VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvNetSniffer.cpp@ 559

最後變更 在這個檔案從559是 559,由 vboxsync 提交於 18 年 前

Added INetworkConnector callback for sending multiple packets

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 15.7 KB
 
1/** @file
2 *
3 * VBox network devices:
4 * Network sniffer filter driver
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.alldomusa.eu.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_NAT
28#include <VBox/pdm.h>
29#include <VBox/cfgm.h>
30#include <VBox/mm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/assert.h>
35#include <iprt/file.h>
36#include <iprt/process.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39#include <iprt/critsect.h>
40#include <VBox/param.h>
41
42#include <string.h>
43
44#include "Builtins.h"
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50/**
51 * Block driver instance data.
52 */
53typedef struct DRVNETSNIFFER
54{
55 /** The network interface. */
56 PDMINETWORKCONNECTOR INetworkConnector;
57 /** The network interface. */
58 PDMINETWORKPORT INetworkPort;
59 /** The port we're attached to. */
60 PPDMINETWORKPORT pPort;
61 /** The connector that's attached to us. */
62 PPDMINETWORKCONNECTOR pConnector;
63 /** The filename. */
64 char szFilename[RTPATH_MAX];
65 /** The filehandle. */
66 RTFILE File;
67 /** The lock serializing the file access. */
68 RTCRITSECT Lock;
69 /** Pointer to the driver instance. */
70 PPDMDRVINS pDrvIns;
71
72} DRVNETSNIFFER, *PDRVNETSNIFFER;
73
74/** Converts a pointer to NAT::INetworkConnector to a PDRVNETSNIFFER. */
75#define PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConnector)) )
76
77/** Converts a pointer to NAT::INetworkPort to a PDRVNETSNIFFER. */
78#define PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkPort)) )
79
80
81/* "libpcap" magic */
82#define PCAP_MAGIC 0xa1b2c3d4
83
84/* "libpcap" file header (minus magic number). */
85struct pcap_hdr
86{
87 uint16_t version_major; /* major version number = 2 */
88 uint16_t version_minor; /* minor version number = 4 */
89 int32_t thiszone; /* GMT to local correction = 0 */
90 uint32_t sigfigs; /* accuracy of timestamps = 0 */
91 uint32_t snaplen; /* max length of captured packets, in octets = 0xffff */
92 uint32_t network; /* data link type = 01 */
93};
94
95/* "libpcap" record header. */
96struct pcaprec_hdr
97{
98 uint32_t ts_sec; /* timestamp seconds */
99 uint32_t ts_usec; /* timestamp microseconds */
100 uint32_t incl_len; /* number of octets of packet saved in file */
101 uint32_t orig_len; /* actual length of packet */
102};
103
104
105
106/**
107 * Send data to the network.
108 *
109 * @returns VBox status code.
110 * @param pInterface Pointer to the interface structure containing the called function pointer.
111 * @param pvBuf Data to send.
112 * @param cb Number of bytes to send.
113 * @thread EMT
114 */
115static DECLCALLBACK(int) drvNetSnifferSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
116{
117 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
118
119 /* output to sniffer */
120 struct pcaprec_hdr Hdr;
121 uint64_t u64TS = RTTimeProgramNanoTS();
122 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
123 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
124 Hdr.incl_len = cb;
125 Hdr.orig_len = cb;
126 RTCritSectEnter(&pData->Lock);
127 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
128 RTFileWrite(pData->File, pvBuf, cb, NULL);
129 RTCritSectLeave(&pData->Lock);
130
131 /* pass down */
132 if (pData->pConnector)
133 {
134 int rc = pData->pConnector->pfnSend(pData->pConnector, pvBuf, cb);
135#if 0
136 RTCritSectEnter(&pData->Lock);
137 u64TS = RTTimeProgramNanoTS();
138 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
139 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
140 Hdr.incl_len = 0;
141 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
142 RTCritSectLeave(&pData->Lock);
143#endif
144 return rc;
145 }
146 return VINF_SUCCESS;
147}
148
149
150/**
151 * Send multiple data packets to the network.
152 *
153 * @returns VBox status code.
154 * @param pInterface Pointer to the interface structure containing the called function pointer.
155 * @param cPackets Number of packets
156 * @param paPacket Packet description array
157 * @thread EMT
158 */
159static DECLCALLBACK(int) drvNetSnifferSendEx(PPDMINETWORKCONNECTOR pInterface, uint32_t cPackets, PPDMINETWORKPACKET paPacket)
160{
161 int rc = VERR_INVALID_PARAMETER;
162
163 for (uint32_t i=0;i<cPackets;i++)
164 {
165 rc = drvNetSnifferSend(pInterface, paPacket[i].pvBuf, paPacket[i].cb);
166 if (VBOX_FAILURE(rc))
167 break;
168 }
169 return rc;
170}
171
172
173/**
174 * Set promiscuous mode.
175 *
176 * This is called when the promiscuous mode is set. This means that there doesn't have
177 * to be a mode change when it's called.
178 *
179 * @param pInterface Pointer to the interface structure containing the called function pointer.
180 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
181 * @thread EMT
182 */
183static DECLCALLBACK(void) drvNetSnifferSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
184{
185 LogFlow(("drvNetSnifferSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
186 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
187 if (pData->pConnector)
188 pData->pConnector->pfnSetPromiscuousMode(pData->pConnector, fPromiscuous);
189}
190
191
192/**
193 * Notification on link status changes.
194 *
195 * @param pInterface Pointer to the interface structure containing the called function pointer.
196 * @param enmLinkState The new link state.
197 * @thread EMT
198 */
199static DECLCALLBACK(void) drvNetSnifferNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
200{
201 LogFlow(("drvNetSnifferNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
202 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
203 if (pData->pConnector)
204 pData->pConnector->pfnNotifyLinkChanged(pData->pConnector, enmLinkState);
205}
206
207
208/**
209 * More receive buffer has become available.
210 *
211 * This is called when the NIC frees up receive buffers.
212 *
213 * @param pInterface Pointer to the interface structure containing the called function pointer.
214 * @thread EMT
215 */
216static DECLCALLBACK(void) drvNetSnifferNotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
217{
218 LogFlow(("drvNetSnifferNotifyCanReceive:\n"));
219 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
220 if (pData->pConnector)
221 pData->pConnector->pfnNotifyCanReceive(pData->pConnector);
222}
223
224
225/**
226 * Check how much data the device/driver can receive data now.
227 * This must be called before the pfnRecieve() method is called.
228 *
229 * @returns Number of bytes the device can receive now.
230 * @param pInterface Pointer to the interface structure containing the called function pointer.
231 * @thread EMT
232 */
233static DECLCALLBACK(size_t) drvNetSnifferCanReceive(PPDMINETWORKPORT pInterface)
234{
235 PDRVNETSNIFFER pData = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
236 return pData->pPort->pfnCanReceive(pData->pPort);
237}
238
239
240/**
241 * Receive data from the network.
242 *
243 * @returns VBox status code.
244 * @param pInterface Pointer to the interface structure containing the called function pointer.
245 * @param pvBuf The available data.
246 * @param cb Number of bytes available in the buffer.
247 * @thread EMT
248 */
249static DECLCALLBACK(int) drvNetSnifferReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
250{
251 PDRVNETSNIFFER pData = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
252
253 /* output to sniffer */
254 struct pcaprec_hdr Hdr;
255 uint64_t u64TS = RTTimeProgramNanoTS();
256 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
257 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
258 Hdr.incl_len = cb;
259 Hdr.orig_len = cb;
260 RTCritSectEnter(&pData->Lock);
261 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
262 RTFileWrite(pData->File, pvBuf, cb, NULL);
263 RTCritSectLeave(&pData->Lock);
264
265 /* pass up */
266 int rc = pData->pPort->pfnReceive(pData->pPort, pvBuf, cb);
267#if 0
268 RTCritSectEnter(&pData->Lock);
269 u64TS = RTTimeProgramNanoTS();
270 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
271 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
272 Hdr.incl_len = 0;
273 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
274 RTCritSectLeave(&pData->Lock);
275#endif
276 return rc;
277}
278
279/**
280 * Queries an interface to the driver.
281 *
282 * @returns Pointer to interface.
283 * @returns NULL if the interface was not supported by the driver.
284 * @param pInterface Pointer to this interface structure.
285 * @param enmInterface The requested interface identification.
286 * @thread Any thread.
287 */
288static DECLCALLBACK(void *) drvNetSnifferQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
289{
290 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
291 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
292 switch (enmInterface)
293 {
294 case PDMINTERFACE_BASE:
295 return &pDrvIns->IBase;
296 case PDMINTERFACE_NETWORK_CONNECTOR:
297 return &pData->INetworkConnector;
298 case PDMINTERFACE_NETWORK_PORT:
299 return &pData->INetworkPort;
300 default:
301 return NULL;
302 }
303}
304
305
306/**
307 * Destruct a driver instance.
308 *
309 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
310 * resources can be freed correctly.
311 *
312 * @param pDrvIns The driver instance data.
313 */
314static DECLCALLBACK(void) drvNetSnifferDestruct(PPDMDRVINS pDrvIns)
315{
316 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
317
318 if (RTCritSectIsInitialized(&pData->Lock))
319 RTCritSectDelete(&pData->Lock);
320
321 if (pData->File != NIL_RTFILE)
322 {
323 RTFileClose(pData->File);
324 pData->File = NIL_RTFILE;
325 }
326}
327
328
329/**
330 * Construct a NAT network transport driver instance.
331 *
332 * @returns VBox status.
333 * @param pDrvIns The driver instance data.
334 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
335 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
336 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
337 * iInstance it's expected to be used a bit in this function.
338 */
339static DECLCALLBACK(int) drvNetSnifferConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
340{
341 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
342 LogFlow(("drvNetSnifferConstruct:\n"));
343
344 /*
345 * Validate the config.
346 */
347 if (!CFGMR3AreValuesValid(pCfgHandle, "File\0"))
348 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
349
350 /*
351 * Init the static parts.
352 */
353 pData->pDrvIns = pDrvIns;
354 pData->File = NIL_RTFILE;
355 /* IBase */
356 pDrvIns->IBase.pfnQueryInterface = drvNetSnifferQueryInterface;
357 /* INetworkConnector */
358 pData->INetworkConnector.pfnSend = drvNetSnifferSend;
359 pData->INetworkConnector.pfnSendEx = drvNetSnifferSendEx;
360 pData->INetworkConnector.pfnSetPromiscuousMode = drvNetSnifferSetPromiscuousMode;
361 pData->INetworkConnector.pfnNotifyLinkChanged = drvNetSnifferNotifyLinkChanged;
362 pData->INetworkConnector.pfnNotifyCanReceive = drvNetSnifferNotifyCanReceive;
363 /* INetworkPort */
364 pData->INetworkPort.pfnCanReceive = drvNetSnifferCanReceive;
365 pData->INetworkPort.pfnReceive = drvNetSnifferReceive;
366
367 /*
368 * Get the filename.
369 */
370 int rc = CFGMR3QueryString(pCfgHandle, "File", pData->szFilename, sizeof(pData->szFilename));
371 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
372 RTStrPrintf(pData->szFilename, sizeof(pData->szFilename), "./VBox-%x.pcap", RTProcSelf());
373 else if (VBOX_FAILURE(rc))
374 {
375 AssertMsgFailed(("Failed to query \"File\", rc=%Vrc.\n", rc));
376 return rc;
377 }
378
379 /*
380 * Query the network port interface.
381 */
382 pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
383 if (!pData->pPort)
384 {
385 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
386 return VERR_PDM_MISSING_INTERFACE_ABOVE;
387 }
388
389 /*
390 * Query the network connector interface.
391 */
392 PPDMIBASE pBaseDown;
393 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseDown);
394 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
395 pData->pConnector = NULL;
396 else if (VBOX_SUCCESS(rc))
397 {
398 pData->pConnector = (PPDMINETWORKCONNECTOR)pBaseDown->pfnQueryInterface(pBaseDown, PDMINTERFACE_NETWORK_CONNECTOR);
399 if (!pData->pConnector)
400 {
401 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
402 return VERR_PDM_MISSING_INTERFACE_BELOW;
403 }
404 }
405 else
406 {
407 AssertMsgFailed(("Failed to attach to driver below! rc=%Vrc\n", rc));
408 return rc;
409 }
410
411 /*
412 * Create the lock.
413 */
414 rc = RTCritSectInit(&pData->Lock);
415 if (VBOX_FAILURE(rc))
416 return rc;
417
418 /*
419 * Open output file / pipe.
420 */
421 rc = RTFileOpen(&pData->File, pData->szFilename,
422 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
423 if (VBOX_FAILURE(rc))
424 {
425 AssertMsgFailed(("Failed to create file '%s' for writing. rc=%Vrc\n", pData->szFilename, rc));
426 return rc;
427 }
428
429 /*
430 * Write pcap header.
431 */
432 struct
433 {
434 uint32_t u32Magic;
435 struct pcap_hdr pcap;
436#ifdef LOG_ENABLED
437 pcaprec_hdr rec;
438 } Hdr = { PCAP_MAGIC, { 2, 4, 0, 0, 0xffff, 1 }, { 0, 1, 0, 60} }; /* force ethereal to start at 0.000000. */
439#else
440 } Hdr = { PCAP_MAGIC, { 2, 4, 0, 0, 0xffff, 1 } }; /* this is just to make it happy, not to be correct. */
441#endif
442 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
443
444 return VINF_SUCCESS;
445}
446
447
448
449/**
450 * Network sniffer filter driver registration record.
451 */
452const PDMDRVREG g_DrvNetSniffer =
453{
454 /* u32Version */
455 PDM_DRVREG_VERSION,
456 /* szDriverName */
457 "NetSniffer",
458 /* pszDescription */
459 "Network Sniffer Filter Driver",
460 /* fFlags */
461 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
462 /* fClass. */
463 PDM_DRVREG_CLASS_NETWORK,
464 /* cMaxInstances */
465 1,
466 /* cbInstance */
467 sizeof(DRVNETSNIFFER),
468 /* pfnConstruct */
469 drvNetSnifferConstruct,
470 /* pfnDestruct */
471 drvNetSnifferDestruct,
472 /* pfnIOCtl */
473 NULL,
474 /* pfnPowerOn */
475 NULL,
476 /* pfnReset */
477 NULL,
478 /* pfnSuspend */
479 NULL,
480 /* pfnResume */
481 NULL,
482 /* pfnDetach */
483 NULL,
484 /* pfnPowerOff */
485 NULL
486};
487
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette