VirtualBox

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

Last change on this file since 25966 was 25966, checked in by vboxsync, 15 years ago

PDMIBASE refactoring; use UUID as interface IDs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: DrvNetSniffer.cpp 25966 2010-01-22 11:15:43Z vboxsync $ */
2/** @file
3 * DrvNetSniffer - Network sniffer filter driver.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_DRV_NAT
27#include <VBox/pdmdrv.h>
28
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include <iprt/critsect.h>
32#include <iprt/file.h>
33#include <iprt/process.h>
34#include <iprt/string.h>
35#include <iprt/time.h>
36#include <iprt/uuid.h>
37#include <VBox/param.h>
38
39#include "Pcap.h"
40#include "Builtins.h"
41
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46/**
47 * Block driver instance data.
48 *
49 * @implements PDMINETWORKCONNECTOR
50 * @implements PDMINETWORKPORT
51 * @implements PDMINETWORKCONFIG
52 */
53typedef struct DRVNETSNIFFER
54{
55 /** The network interface. */
56 PDMINETWORKCONNECTOR INetworkConnector;
57 /** The network interface. */
58 PDMINETWORKPORT INetworkPort;
59 /** The network config interface. */
60 PDMINETWORKCONFIG INetworkConfig;
61 /** The port we're attached to. */
62 PPDMINETWORKPORT pPort;
63 /** The config port interface we're attached to. */
64 PPDMINETWORKCONFIG pConfig;
65 /** The connector that's attached to us. */
66 PPDMINETWORKCONNECTOR pConnector;
67 /** The filename. */
68 char szFilename[RTPATH_MAX];
69 /** The filehandle. */
70 RTFILE File;
71 /** The lock serializing the file access. */
72 RTCRITSECT Lock;
73 /** The NanoTS delta we pass to the pcap writers. */
74 uint64_t StartNanoTS;
75 /** Pointer to the driver instance. */
76 PPDMDRVINS pDrvIns;
77
78} DRVNETSNIFFER, *PDRVNETSNIFFER;
79
80/** Converts a pointer to NAT::INetworkConnector to a PDRVNETSNIFFER. */
81#define PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConnector)) )
82
83/** Converts a pointer to NAT::INetworkPort to a PDRVNETSNIFFER. */
84#define PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkPort)) )
85
86/** Converts a pointer to NAT::INetworkConfig to a PDRVNETSNIFFER. */
87#define PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConfig)) )
88
89
90
91/**
92 * Send data to the network.
93 *
94 * @returns VBox status code.
95 * @param pInterface Pointer to the interface structure containing the called function pointer.
96 * @param pvBuf Data to send.
97 * @param cb Number of bytes to send.
98 * @thread EMT
99 */
100static DECLCALLBACK(int) drvNetSnifferSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
101{
102 PDRVNETSNIFFER pThis = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
103
104 /* output to sniffer */
105 RTCritSectEnter(&pThis->Lock);
106 PcapFileFrame(pThis->File, pThis->StartNanoTS, pvBuf, cb, cb);
107 RTCritSectLeave(&pThis->Lock);
108
109 /* pass down */
110 if (pThis->pConnector)
111 {
112 int rc = pThis->pConnector->pfnSend(pThis->pConnector, pvBuf, cb);
113#if 0
114 RTCritSectEnter(&pThis->Lock);
115 u64TS = RTTimeProgramNanoTS();
116 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
117 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
118 Hdr.incl_len = 0;
119 RTFileWrite(pThis->File, &Hdr, sizeof(Hdr), NULL);
120 RTCritSectLeave(&pThis->Lock);
121#endif
122 return rc;
123 }
124 return VINF_SUCCESS;
125}
126
127
128/**
129 * Set promiscuous mode.
130 *
131 * This is called when the promiscuous mode is set. This means that there doesn't have
132 * to be a mode change when it's called.
133 *
134 * @param pInterface Pointer to the interface structure containing the called function pointer.
135 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
136 * @thread EMT
137 */
138static DECLCALLBACK(void) drvNetSnifferSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
139{
140 LogFlow(("drvNetSnifferSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
141 PDRVNETSNIFFER pThis = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
142 if (pThis->pConnector)
143 pThis->pConnector->pfnSetPromiscuousMode(pThis->pConnector, fPromiscuous);
144}
145
146
147/**
148 * Notification on link status changes.
149 *
150 * @param pInterface Pointer to the interface structure containing the called function pointer.
151 * @param enmLinkState The new link state.
152 * @thread EMT
153 */
154static DECLCALLBACK(void) drvNetSnifferNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
155{
156 LogFlow(("drvNetSnifferNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
157 PDRVNETSNIFFER pThis = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
158 if (pThis->pConnector)
159 pThis->pConnector->pfnNotifyLinkChanged(pThis->pConnector, enmLinkState);
160}
161
162
163/**
164 * Check how much data the device/driver can receive data now.
165 * This must be called before the pfnRecieve() method is called.
166 *
167 * @returns Number of bytes the device can receive now.
168 * @param pInterface Pointer to the interface structure containing the called function pointer.
169 * @thread EMT
170 */
171static DECLCALLBACK(int) drvNetSnifferWaitReceiveAvail(PPDMINETWORKPORT pInterface, RTMSINTERVAL cMillies)
172{
173 PDRVNETSNIFFER pThis = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
174 return pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, cMillies);
175}
176
177
178/**
179 * Receive data from the network.
180 *
181 * @returns VBox status code.
182 * @param pInterface Pointer to the interface structure containing the called function pointer.
183 * @param pvBuf The available data.
184 * @param cb Number of bytes available in the buffer.
185 * @thread EMT
186 */
187static DECLCALLBACK(int) drvNetSnifferReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
188{
189 PDRVNETSNIFFER pThis = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
190
191 /* output to sniffer */
192 RTCritSectEnter(&pThis->Lock);
193 PcapFileFrame(pThis->File, pThis->StartNanoTS, pvBuf, cb, cb);
194 RTCritSectLeave(&pThis->Lock);
195
196 /* pass up */
197 int rc = pThis->pPort->pfnReceive(pThis->pPort, pvBuf, cb);
198#if 0
199 RTCritSectEnter(&pThis->Lock);
200 u64TS = RTTimeProgramNanoTS();
201 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
202 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
203 Hdr.incl_len = 0;
204 RTFileWrite(pThis->File, &Hdr, sizeof(Hdr), NULL);
205 RTCritSectLeave(&pThis->Lock);
206#endif
207 return rc;
208}
209
210
211/**
212 * Gets the current Media Access Control (MAC) address.
213 *
214 * @returns VBox status code.
215 * @param pInterface Pointer to the interface structure containing the called function pointer.
216 * @param pMac Where to store the MAC address.
217 * @thread EMT
218 */
219static DECLCALLBACK(int) drvNetSnifferGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
220{
221 PDRVNETSNIFFER pThis = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
222 return pThis->pConfig->pfnGetMac(pThis->pConfig, pMac);
223}
224
225/**
226 * Gets the new link state.
227 *
228 * @returns The current link state.
229 * @param pInterface Pointer to the interface structure containing the called function pointer.
230 * @thread EMT
231 */
232static DECLCALLBACK(PDMNETWORKLINKSTATE) drvNetSnifferGetLinkState(PPDMINETWORKCONFIG pInterface)
233{
234 PDRVNETSNIFFER pThis = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
235 return pThis->pConfig->pfnGetLinkState(pThis->pConfig);
236}
237
238/**
239 * Sets the new link state.
240 *
241 * @returns VBox status code.
242 * @param pInterface Pointer to the interface structure containing the called function pointer.
243 * @param enmState The new link state
244 * @thread EMT
245 */
246static DECLCALLBACK(int) drvNetSnifferSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
247{
248 PDRVNETSNIFFER pThis = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
249 return pThis->pConfig->pfnSetLinkState(pThis->pConfig, enmState);
250}
251
252
253/**
254 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
255 */
256static DECLCALLBACK(void *) drvNetSnifferQueryInterface(PPDMIBASE pInterface, const char *pszIID)
257{
258 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
259 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
260 if (RTUuidCompare2Strs(pszIID, PDMIBASE_IID) == 0)
261 return &pDrvIns->IBase;
262 if (RTUuidCompare2Strs(pszIID, PDMINTERFACE_NETWORK_CONNECTOR) == 0)
263 return &pThis->INetworkConnector;
264 if (RTUuidCompare2Strs(pszIID, PDMINTERFACE_NETWORK_PORT) == 0)
265 return &pThis->INetworkPort;
266 if (RTUuidCompare2Strs(pszIID, PDMINTERFACE_NETWORK_CONFIG) == 0)
267 return &pThis->INetworkConfig;
268 return NULL;
269}
270
271
272/**
273 * Detach a driver instance.
274 *
275 * @param pDrvIns The driver instance.
276 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
277 */
278static DECLCALLBACK(void) drvNetSnifferDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
279{
280 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
281
282 LogFlow(("drvNetSnifferDetach: pDrvIns: %p, fFlags: %u\n", pDrvIns, fFlags));
283
284 pThis->pConnector = NULL;
285}
286
287
288/**
289 * Attach a driver instance.
290 *
291 * @returns VBox status code.
292 * @param pDrvIns The driver instance.
293 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
294 */
295static DECLCALLBACK(int) drvNetSnifferAttach(PPDMDRVINS pDrvIns, uint32_t fFlags)
296{
297 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
298
299 LogFlow(("drvNetSnifferAttach: pDrvIns: %p, fFlags: %u\n", pDrvIns, fFlags));
300
301 /*
302 * Query the network connector interface.
303 */
304 PPDMIBASE pBaseDown;
305 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBaseDown);
306 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
307 pThis->pConnector = NULL;
308 else if (RT_SUCCESS(rc))
309 {
310 pThis->pConnector = (PPDMINETWORKCONNECTOR)pBaseDown->pfnQueryInterface(pBaseDown, PDMINTERFACE_NETWORK_CONNECTOR);
311 if (!pThis->pConnector)
312 {
313 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
314 return VERR_PDM_MISSING_INTERFACE_BELOW;
315 }
316 }
317 else
318 {
319 AssertMsgFailed(("Failed to attach to driver below! rc=%Rrc\n", rc));
320 return rc;
321 }
322
323 return VINF_SUCCESS;
324}
325
326
327/**
328 * Destruct a driver instance.
329 *
330 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
331 * resources can be freed correctly.
332 *
333 * @param pDrvIns The driver instance data.
334 */
335static DECLCALLBACK(void) drvNetSnifferDestruct(PPDMDRVINS pDrvIns)
336{
337 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
338
339 if (RTCritSectIsInitialized(&pThis->Lock))
340 RTCritSectDelete(&pThis->Lock);
341
342 if (pThis->File != NIL_RTFILE)
343 {
344 RTFileClose(pThis->File);
345 pThis->File = NIL_RTFILE;
346 }
347}
348
349
350/**
351 * Construct a NAT network transport driver instance.
352 *
353 * @copydoc FNPDMDRVCONSTRUCT
354 */
355static DECLCALLBACK(int) drvNetSnifferConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
356{
357 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
358 LogFlow(("drvNetSnifferConstruct:\n"));
359
360 /*
361 * Validate the config.
362 */
363 if (!CFGMR3AreValuesValid(pCfgHandle, "File\0"))
364 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
365
366 if (CFGMR3GetFirstChild(pCfgHandle))
367 LogRel(("NetSniffer: Found child config entries -- are you trying to redirect ports?\n"));
368
369 /*
370 * Init the static parts.
371 */
372 pThis->pDrvIns = pDrvIns;
373 pThis->File = NIL_RTFILE;
374 /* The pcap file *must* start at time offset 0,0. */
375 pThis->StartNanoTS = RTTimeNanoTS() - RTTimeProgramNanoTS();
376 /* IBase */
377 pDrvIns->IBase.pfnQueryInterface = drvNetSnifferQueryInterface;
378 /* INetworkConnector */
379 pThis->INetworkConnector.pfnSend = drvNetSnifferSend;
380 pThis->INetworkConnector.pfnSetPromiscuousMode = drvNetSnifferSetPromiscuousMode;
381 pThis->INetworkConnector.pfnNotifyLinkChanged = drvNetSnifferNotifyLinkChanged;
382 /* INetworkPort */
383 pThis->INetworkPort.pfnWaitReceiveAvail = drvNetSnifferWaitReceiveAvail;
384 pThis->INetworkPort.pfnReceive = drvNetSnifferReceive;
385 /* INetworkConfig */
386 pThis->INetworkConfig.pfnGetMac = drvNetSnifferGetMac;
387 pThis->INetworkConfig.pfnGetLinkState = drvNetSnifferGetLinkState;
388 pThis->INetworkConfig.pfnSetLinkState = drvNetSnifferSetLinkState;
389
390 /*
391 * Get the filename.
392 */
393 int rc = CFGMR3QueryString(pCfgHandle, "File", pThis->szFilename, sizeof(pThis->szFilename));
394 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
395 {
396 if (pDrvIns->iInstance > 0)
397 RTStrPrintf(pThis->szFilename, sizeof(pThis->szFilename), "./VBox-%x-%u.pcap", RTProcSelf(), pDrvIns->iInstance);
398 else
399 RTStrPrintf(pThis->szFilename, sizeof(pThis->szFilename), "./VBox-%x.pcap", RTProcSelf());
400 }
401
402 else if (RT_FAILURE(rc))
403 {
404 AssertMsgFailed(("Failed to query \"File\", rc=%Rrc.\n", rc));
405 return rc;
406 }
407
408 /*
409 * Query the network port interface.
410 */
411 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
412 if (!pThis->pPort)
413 {
414 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
415 return VERR_PDM_MISSING_INTERFACE_ABOVE;
416 }
417
418 /*
419 * Query the network config interface.
420 */
421 pThis->pConfig = (PPDMINETWORKCONFIG)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_CONFIG);
422 if (!pThis->pConfig)
423 {
424 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
425 return VERR_PDM_MISSING_INTERFACE_ABOVE;
426 }
427
428 /*
429 * Query the network connector interface.
430 */
431 PPDMIBASE pBaseDown;
432 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBaseDown);
433 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
434 pThis->pConnector = NULL;
435 else if (RT_SUCCESS(rc))
436 {
437 pThis->pConnector = (PPDMINETWORKCONNECTOR)pBaseDown->pfnQueryInterface(pBaseDown, PDMINTERFACE_NETWORK_CONNECTOR);
438 if (!pThis->pConnector)
439 {
440 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
441 return VERR_PDM_MISSING_INTERFACE_BELOW;
442 }
443 }
444 else
445 {
446 AssertMsgFailed(("Failed to attach to driver below! rc=%Rrc\n", rc));
447 return rc;
448 }
449
450 /*
451 * Create the lock.
452 */
453 rc = RTCritSectInit(&pThis->Lock);
454 if (RT_FAILURE(rc))
455 return rc;
456
457 /*
458 * Open output file / pipe.
459 */
460 rc = RTFileOpen(&pThis->File, pThis->szFilename,
461 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
462 if (RT_FAILURE(rc))
463 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
464 N_("Netsniffer cannot open '%s' for writing. The directory must exist and it must be writable for the current user"), pThis->szFilename);
465
466 /*
467 * Write pcap header.
468 * Some time is done since capturing pThis->StartNanoTS so capture the current time again.
469 */
470 PcapFileHdr(pThis->File, RTTimeNanoTS());
471
472 return VINF_SUCCESS;
473}
474
475
476
477/**
478 * Network sniffer filter driver registration record.
479 */
480const PDMDRVREG g_DrvNetSniffer =
481{
482 /* u32Version */
483 PDM_DRVREG_VERSION,
484 /* szDriverName */
485 "NetSniffer",
486 /* szRCMod */
487 "",
488 /* szR0Mod */
489 "",
490 /* pszDescription */
491 "Network Sniffer Filter Driver",
492 /* fFlags */
493 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
494 /* fClass. */
495 PDM_DRVREG_CLASS_NETWORK,
496 /* cMaxInstances */
497 UINT32_MAX,
498 /* cbInstance */
499 sizeof(DRVNETSNIFFER),
500 /* pfnConstruct */
501 drvNetSnifferConstruct,
502 /* pfnDestruct */
503 drvNetSnifferDestruct,
504 /* pfnRelocate */
505 NULL,
506 /* pfnIOCtl */
507 NULL,
508 /* pfnPowerOn */
509 NULL,
510 /* pfnReset */
511 NULL,
512 /* pfnSuspend */
513 NULL,
514 /* pfnResume */
515 NULL,
516 /* pfnAttach */
517 drvNetSnifferAttach,
518 /* pfnDetach */
519 drvNetSnifferDetach,
520 /* pfnPowerOff */
521 NULL,
522 /* pfnSoftReset */
523 NULL,
524 /* u32EndVersion */
525 PDM_DRVREG_VERSION
526};
527
Note: See TracBrowser for help on using the repository browser.

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