VirtualBox

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

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

pdmnetif.h & users: sketched out a new interface that is intended to be similar to the ring-0 and raw-mode context interfaces (working on driver allocated buffers during xmit).

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