VirtualBox

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

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

pdmifs.h: yet another batch of refactored interface ID code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.8 KB
Line 
1/* $Id: DrvNetSniffer.cpp 25981 2010-01-22 18:42:01Z 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.virtualbox.org. 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 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONNECTOR, &pThis->INetworkConnector);
263 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKPORT, &pThis->INetworkPort);
264 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
265 return NULL;
266}
267
268
269/**
270 * Detach a driver instance.
271 *
272 * @param pDrvIns The driver instance.
273 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
274 */
275static DECLCALLBACK(void) drvNetSnifferDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
276{
277 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
278
279 LogFlow(("drvNetSnifferDetach: pDrvIns: %p, fFlags: %u\n", pDrvIns, fFlags));
280
281 pThis->pConnector = NULL;
282}
283
284
285/**
286 * Attach a driver instance.
287 *
288 * @returns VBox status code.
289 * @param pDrvIns The driver instance.
290 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
291 */
292static DECLCALLBACK(int) drvNetSnifferAttach(PPDMDRVINS pDrvIns, uint32_t fFlags)
293{
294 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
295
296 LogFlow(("drvNetSnifferAttach: pDrvIns: %p, fFlags: %u\n", pDrvIns, fFlags));
297
298 /*
299 * Query the network connector interface.
300 */
301 PPDMIBASE pBaseDown;
302 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBaseDown);
303 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
304 pThis->pConnector = NULL;
305 else if (RT_SUCCESS(rc))
306 {
307 pThis->pConnector = PDMIBASE_QUERY_INTERFACE(pBaseDown, PDMINETWORKCONNECTOR);
308 if (!pThis->pConnector)
309 {
310 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
311 return VERR_PDM_MISSING_INTERFACE_BELOW;
312 }
313 }
314 else
315 {
316 AssertMsgFailed(("Failed to attach to driver below! rc=%Rrc\n", rc));
317 return rc;
318 }
319
320 return VINF_SUCCESS;
321}
322
323
324/**
325 * Destruct a driver instance.
326 *
327 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
328 * resources can be freed correctly.
329 *
330 * @param pDrvIns The driver instance data.
331 */
332static DECLCALLBACK(void) drvNetSnifferDestruct(PPDMDRVINS pDrvIns)
333{
334 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
335
336 if (RTCritSectIsInitialized(&pThis->Lock))
337 RTCritSectDelete(&pThis->Lock);
338
339 if (pThis->File != NIL_RTFILE)
340 {
341 RTFileClose(pThis->File);
342 pThis->File = NIL_RTFILE;
343 }
344}
345
346
347/**
348 * Construct a NAT network transport driver instance.
349 *
350 * @copydoc FNPDMDRVCONSTRUCT
351 */
352static DECLCALLBACK(int) drvNetSnifferConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
353{
354 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
355 LogFlow(("drvNetSnifferConstruct:\n"));
356
357 /*
358 * Validate the config.
359 */
360 if (!CFGMR3AreValuesValid(pCfgHandle, "File\0"))
361 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
362
363 if (CFGMR3GetFirstChild(pCfgHandle))
364 LogRel(("NetSniffer: Found child config entries -- are you trying to redirect ports?\n"));
365
366 /*
367 * Init the static parts.
368 */
369 pThis->pDrvIns = pDrvIns;
370 pThis->File = NIL_RTFILE;
371 /* The pcap file *must* start at time offset 0,0. */
372 pThis->StartNanoTS = RTTimeNanoTS() - RTTimeProgramNanoTS();
373 /* IBase */
374 pDrvIns->IBase.pfnQueryInterface = drvNetSnifferQueryInterface;
375 /* INetworkConnector */
376 pThis->INetworkConnector.pfnSend = drvNetSnifferSend;
377 pThis->INetworkConnector.pfnSetPromiscuousMode = drvNetSnifferSetPromiscuousMode;
378 pThis->INetworkConnector.pfnNotifyLinkChanged = drvNetSnifferNotifyLinkChanged;
379 /* INetworkPort */
380 pThis->INetworkPort.pfnWaitReceiveAvail = drvNetSnifferWaitReceiveAvail;
381 pThis->INetworkPort.pfnReceive = drvNetSnifferReceive;
382 /* INetworkConfig */
383 pThis->INetworkConfig.pfnGetMac = drvNetSnifferGetMac;
384 pThis->INetworkConfig.pfnGetLinkState = drvNetSnifferGetLinkState;
385 pThis->INetworkConfig.pfnSetLinkState = drvNetSnifferSetLinkState;
386
387 /*
388 * Get the filename.
389 */
390 int rc = CFGMR3QueryString(pCfgHandle, "File", pThis->szFilename, sizeof(pThis->szFilename));
391 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
392 {
393 if (pDrvIns->iInstance > 0)
394 RTStrPrintf(pThis->szFilename, sizeof(pThis->szFilename), "./VBox-%x-%u.pcap", RTProcSelf(), pDrvIns->iInstance);
395 else
396 RTStrPrintf(pThis->szFilename, sizeof(pThis->szFilename), "./VBox-%x.pcap", RTProcSelf());
397 }
398
399 else if (RT_FAILURE(rc))
400 {
401 AssertMsgFailed(("Failed to query \"File\", rc=%Rrc.\n", rc));
402 return rc;
403 }
404
405 /*
406 * Query the network port interface.
407 */
408 pThis->pPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKPORT);
409 if (!pThis->pPort)
410 {
411 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
412 return VERR_PDM_MISSING_INTERFACE_ABOVE;
413 }
414
415 /*
416 * Query the network config interface.
417 */
418 pThis->pConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
419 if (!pThis->pConfig)
420 {
421 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
422 return VERR_PDM_MISSING_INTERFACE_ABOVE;
423 }
424
425 /*
426 * Query the network connector interface.
427 */
428 PPDMIBASE pBaseDown;
429 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBaseDown);
430 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
431 pThis->pConnector = NULL;
432 else if (RT_SUCCESS(rc))
433 {
434 pThis->pConnector = PDMIBASE_QUERY_INTERFACE(pBaseDown, PDMINETWORKCONNECTOR);
435 if (!pThis->pConnector)
436 {
437 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
438 return VERR_PDM_MISSING_INTERFACE_BELOW;
439 }
440 }
441 else
442 {
443 AssertMsgFailed(("Failed to attach to driver below! rc=%Rrc\n", rc));
444 return rc;
445 }
446
447 /*
448 * Create the lock.
449 */
450 rc = RTCritSectInit(&pThis->Lock);
451 if (RT_FAILURE(rc))
452 return rc;
453
454 /*
455 * Open output file / pipe.
456 */
457 rc = RTFileOpen(&pThis->File, pThis->szFilename,
458 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
459 if (RT_FAILURE(rc))
460 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
461 N_("Netsniffer cannot open '%s' for writing. The directory must exist and it must be writable for the current user"), pThis->szFilename);
462
463 /*
464 * Write pcap header.
465 * Some time is done since capturing pThis->StartNanoTS so capture the current time again.
466 */
467 PcapFileHdr(pThis->File, RTTimeNanoTS());
468
469 return VINF_SUCCESS;
470}
471
472
473
474/**
475 * Network sniffer filter driver registration record.
476 */
477const PDMDRVREG g_DrvNetSniffer =
478{
479 /* u32Version */
480 PDM_DRVREG_VERSION,
481 /* szDriverName */
482 "NetSniffer",
483 /* szRCMod */
484 "",
485 /* szR0Mod */
486 "",
487 /* pszDescription */
488 "Network Sniffer Filter Driver",
489 /* fFlags */
490 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
491 /* fClass. */
492 PDM_DRVREG_CLASS_NETWORK,
493 /* cMaxInstances */
494 UINT32_MAX,
495 /* cbInstance */
496 sizeof(DRVNETSNIFFER),
497 /* pfnConstruct */
498 drvNetSnifferConstruct,
499 /* pfnDestruct */
500 drvNetSnifferDestruct,
501 /* pfnRelocate */
502 NULL,
503 /* pfnIOCtl */
504 NULL,
505 /* pfnPowerOn */
506 NULL,
507 /* pfnReset */
508 NULL,
509 /* pfnSuspend */
510 NULL,
511 /* pfnResume */
512 NULL,
513 /* pfnAttach */
514 drvNetSnifferAttach,
515 /* pfnDetach */
516 drvNetSnifferDetach,
517 /* pfnPowerOff */
518 NULL,
519 /* pfnSoftReset */
520 NULL,
521 /* u32EndVersion */
522 PDM_DRVREG_VERSION
523};
524
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