VirtualBox

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

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

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

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