VirtualBox

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

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

pdmifs.h: Moved the network interfaces to a separate header called pdmnetifs.h.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
Line 
1/* $Id: DrvNetSniffer.cpp 26300 2010-02-05 16:02:55Z 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 PDMINETWORKCONNECTOR
51 * @implements PDMINETWORKPORT
52 * @implements PDMINETWORKCONFIG
53 */
54typedef struct DRVNETSNIFFER
55{
56 /** The network interface. */
57 PDMINETWORKCONNECTOR INetworkConnector;
58 /** The network interface. */
59 PDMINETWORKPORT INetworkPort;
60 /** The network config interface. */
61 PDMINETWORKCONFIG INetworkConfig;
62 /** The port we're attached to. */
63 PPDMINETWORKPORT pPort;
64 /** The config port interface we're attached to. */
65 PPDMINETWORKCONFIG pConfig;
66 /** The connector that's attached to us. */
67 PPDMINETWORKCONNECTOR pConnector;
68 /** The filename. */
69 char szFilename[RTPATH_MAX];
70 /** The filehandle. */
71 RTFILE File;
72 /** The lock serializing the file access. */
73 RTCRITSECT Lock;
74 /** The NanoTS delta we pass to the pcap writers. */
75 uint64_t StartNanoTS;
76 /** Pointer to the driver instance. */
77 PPDMDRVINS pDrvIns;
78
79} DRVNETSNIFFER, *PDRVNETSNIFFER;
80
81/** Converts a pointer to NAT::INetworkConnector to a PDRVNETSNIFFER. */
82#define PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConnector)) )
83
84/** Converts a pointer to NAT::INetworkPort to a PDRVNETSNIFFER. */
85#define PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkPort)) )
86
87/** Converts a pointer to NAT::INetworkConfig to a PDRVNETSNIFFER. */
88#define PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConfig)) )
89
90
91
92/**
93 * Send data to the network.
94 *
95 * @returns VBox status code.
96 * @param pInterface Pointer to the interface structure containing the called function pointer.
97 * @param pvBuf Data to send.
98 * @param cb Number of bytes to send.
99 * @thread EMT
100 */
101static DECLCALLBACK(int) drvNetSnifferSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
102{
103 PDRVNETSNIFFER pThis = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
104
105 /* output to sniffer */
106 RTCritSectEnter(&pThis->Lock);
107 PcapFileFrame(pThis->File, pThis->StartNanoTS, pvBuf, cb, cb);
108 RTCritSectLeave(&pThis->Lock);
109
110 /* pass down */
111 if (pThis->pConnector)
112 {
113 int rc = pThis->pConnector->pfnSend(pThis->pConnector, pvBuf, cb);
114#if 0
115 RTCritSectEnter(&pThis->Lock);
116 u64TS = RTTimeProgramNanoTS();
117 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
118 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
119 Hdr.incl_len = 0;
120 RTFileWrite(pThis->File, &Hdr, sizeof(Hdr), NULL);
121 RTCritSectLeave(&pThis->Lock);
122#endif
123 return rc;
124 }
125 return VINF_SUCCESS;
126}
127
128
129/**
130 * Set promiscuous mode.
131 *
132 * This is called when the promiscuous mode is set. This means that there doesn't have
133 * to be a mode change when it's called.
134 *
135 * @param pInterface Pointer to the interface structure containing the called function pointer.
136 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
137 * @thread EMT
138 */
139static DECLCALLBACK(void) drvNetSnifferSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
140{
141 LogFlow(("drvNetSnifferSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
142 PDRVNETSNIFFER pThis = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
143 if (pThis->pConnector)
144 pThis->pConnector->pfnSetPromiscuousMode(pThis->pConnector, fPromiscuous);
145}
146
147
148/**
149 * Notification on link status changes.
150 *
151 * @param pInterface Pointer to the interface structure containing the called function pointer.
152 * @param enmLinkState The new link state.
153 * @thread EMT
154 */
155static DECLCALLBACK(void) drvNetSnifferNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
156{
157 LogFlow(("drvNetSnifferNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
158 PDRVNETSNIFFER pThis = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
159 if (pThis->pConnector)
160 pThis->pConnector->pfnNotifyLinkChanged(pThis->pConnector, enmLinkState);
161}
162
163
164/**
165 * Check how much data the device/driver can receive data now.
166 * This must be called before the pfnRecieve() method is called.
167 *
168 * @returns Number of bytes the device can receive now.
169 * @param pInterface Pointer to the interface structure containing the called function pointer.
170 * @thread EMT
171 */
172static DECLCALLBACK(int) drvNetSnifferWaitReceiveAvail(PPDMINETWORKPORT pInterface, RTMSINTERVAL cMillies)
173{
174 PDRVNETSNIFFER pThis = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
175 return pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, cMillies);
176}
177
178
179/**
180 * Receive data from the network.
181 *
182 * @returns VBox status code.
183 * @param pInterface Pointer to the interface structure containing the called function pointer.
184 * @param pvBuf The available data.
185 * @param cb Number of bytes available in the buffer.
186 * @thread EMT
187 */
188static DECLCALLBACK(int) drvNetSnifferReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
189{
190 PDRVNETSNIFFER pThis = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
191
192 /* output to sniffer */
193 RTCritSectEnter(&pThis->Lock);
194 PcapFileFrame(pThis->File, pThis->StartNanoTS, pvBuf, cb, cb);
195 RTCritSectLeave(&pThis->Lock);
196
197 /* pass up */
198 int rc = pThis->pPort->pfnReceive(pThis->pPort, pvBuf, cb);
199#if 0
200 RTCritSectEnter(&pThis->Lock);
201 u64TS = RTTimeProgramNanoTS();
202 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
203 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
204 Hdr.incl_len = 0;
205 RTFileWrite(pThis->File, &Hdr, sizeof(Hdr), NULL);
206 RTCritSectLeave(&pThis->Lock);
207#endif
208 return rc;
209}
210
211
212/**
213 * Gets the current Media Access Control (MAC) address.
214 *
215 * @returns VBox status code.
216 * @param pInterface Pointer to the interface structure containing the called function pointer.
217 * @param pMac Where to store the MAC address.
218 * @thread EMT
219 */
220static DECLCALLBACK(int) drvNetSnifferGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
221{
222 PDRVNETSNIFFER pThis = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
223 return pThis->pConfig->pfnGetMac(pThis->pConfig, pMac);
224}
225
226/**
227 * Gets the new link state.
228 *
229 * @returns The current link state.
230 * @param pInterface Pointer to the interface structure containing the called function pointer.
231 * @thread EMT
232 */
233static DECLCALLBACK(PDMNETWORKLINKSTATE) drvNetSnifferGetLinkState(PPDMINETWORKCONFIG pInterface)
234{
235 PDRVNETSNIFFER pThis = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
236 return pThis->pConfig->pfnGetLinkState(pThis->pConfig);
237}
238
239/**
240 * Sets the new link state.
241 *
242 * @returns VBox status code.
243 * @param pInterface Pointer to the interface structure containing the called function pointer.
244 * @param enmState The new link state
245 * @thread EMT
246 */
247static DECLCALLBACK(int) drvNetSnifferSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
248{
249 PDRVNETSNIFFER pThis = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
250 return pThis->pConfig->pfnSetLinkState(pThis->pConfig, enmState);
251}
252
253
254/**
255 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
256 */
257static DECLCALLBACK(void *) drvNetSnifferQueryInterface(PPDMIBASE pInterface, const char *pszIID)
258{
259 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
260 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
261 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &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 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
336
337 if (RTCritSectIsInitialized(&pThis->Lock))
338 RTCritSectDelete(&pThis->Lock);
339
340 if (pThis->File != NIL_RTFILE)
341 {
342 RTFileClose(pThis->File);
343 pThis->File = NIL_RTFILE;
344 }
345}
346
347
348/**
349 * Construct a NAT network transport driver instance.
350 *
351 * @copydoc FNPDMDRVCONSTRUCT
352 */
353static DECLCALLBACK(int) drvNetSnifferConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
354{
355 PDRVNETSNIFFER pThis = PDMINS_2_DATA(pDrvIns, PDRVNETSNIFFER);
356 LogFlow(("drvNetSnifferConstruct:\n"));
357 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
358
359 /*
360 * Validate the config.
361 */
362 if (!CFGMR3AreValuesValid(pCfg, "File\0"))
363 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
364
365 if (CFGMR3GetFirstChild(pCfg))
366 LogRel(("NetSniffer: Found child config entries -- are you trying to redirect ports?\n"));
367
368 /*
369 * Init the static parts.
370 */
371 pThis->pDrvIns = pDrvIns;
372 pThis->File = NIL_RTFILE;
373 /* The pcap file *must* start at time offset 0,0. */
374 pThis->StartNanoTS = RTTimeNanoTS() - RTTimeProgramNanoTS();
375 /* IBase */
376 pDrvIns->IBase.pfnQueryInterface = drvNetSnifferQueryInterface;
377 /* INetworkConnector */
378 pThis->INetworkConnector.pfnSend = drvNetSnifferSend;
379 pThis->INetworkConnector.pfnSetPromiscuousMode = drvNetSnifferSetPromiscuousMode;
380 pThis->INetworkConnector.pfnNotifyLinkChanged = drvNetSnifferNotifyLinkChanged;
381 /* INetworkPort */
382 pThis->INetworkPort.pfnWaitReceiveAvail = drvNetSnifferWaitReceiveAvail;
383 pThis->INetworkPort.pfnReceive = drvNetSnifferReceive;
384 /* INetworkConfig */
385 pThis->INetworkConfig.pfnGetMac = drvNetSnifferGetMac;
386 pThis->INetworkConfig.pfnGetLinkState = drvNetSnifferGetLinkState;
387 pThis->INetworkConfig.pfnSetLinkState = drvNetSnifferSetLinkState;
388
389 /*
390 * Get the filename.
391 */
392 int rc = CFGMR3QueryString(pCfg, "File", pThis->szFilename, sizeof(pThis->szFilename));
393 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
394 {
395 if (pDrvIns->iInstance > 0)
396 RTStrPrintf(pThis->szFilename, sizeof(pThis->szFilename), "./VBox-%x-%u.pcap", RTProcSelf(), pDrvIns->iInstance);
397 else
398 RTStrPrintf(pThis->szFilename, sizeof(pThis->szFilename), "./VBox-%x.pcap", RTProcSelf());
399 }
400
401 else if (RT_FAILURE(rc))
402 {
403 AssertMsgFailed(("Failed to query \"File\", rc=%Rrc.\n", rc));
404 return rc;
405 }
406
407 /*
408 * Query the network port interface.
409 */
410 pThis->pPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKPORT);
411 if (!pThis->pPort)
412 {
413 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
414 return VERR_PDM_MISSING_INTERFACE_ABOVE;
415 }
416
417 /*
418 * Query the network config interface.
419 */
420 pThis->pConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
421 if (!pThis->pConfig)
422 {
423 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
424 return VERR_PDM_MISSING_INTERFACE_ABOVE;
425 }
426
427 /*
428 * Query the network connector interface.
429 */
430 PPDMIBASE pBaseDown;
431 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBaseDown);
432 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
433 pThis->pConnector = NULL;
434 else if (RT_SUCCESS(rc))
435 {
436 pThis->pConnector = PDMIBASE_QUERY_INTERFACE(pBaseDown, PDMINETWORKCONNECTOR);
437 if (!pThis->pConnector)
438 {
439 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
440 return VERR_PDM_MISSING_INTERFACE_BELOW;
441 }
442 }
443 else
444 {
445 AssertMsgFailed(("Failed to attach to driver below! rc=%Rrc\n", rc));
446 return rc;
447 }
448
449 /*
450 * Create the lock.
451 */
452 rc = RTCritSectInit(&pThis->Lock);
453 if (RT_FAILURE(rc))
454 return rc;
455
456 /*
457 * Open output file / pipe.
458 */
459 rc = RTFileOpen(&pThis->File, pThis->szFilename,
460 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
461 if (RT_FAILURE(rc))
462 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
463 N_("Netsniffer cannot open '%s' for writing. The directory must exist and it must be writable for the current user"), pThis->szFilename);
464
465 /*
466 * Write pcap header.
467 * Some time is done since capturing pThis->StartNanoTS so capture the current time again.
468 */
469 PcapFileHdr(pThis->File, RTTimeNanoTS());
470
471 return VINF_SUCCESS;
472}
473
474
475
476/**
477 * Network sniffer filter driver registration record.
478 */
479const PDMDRVREG g_DrvNetSniffer =
480{
481 /* u32Version */
482 PDM_DRVREG_VERSION,
483 /* szName */
484 "NetSniffer",
485 /* szRCMod */
486 "",
487 /* szR0Mod */
488 "",
489 /* pszDescription */
490 "Network Sniffer Filter Driver",
491 /* fFlags */
492 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
493 /* fClass. */
494 PDM_DRVREG_CLASS_NETWORK,
495 /* cMaxInstances */
496 UINT32_MAX,
497 /* cbInstance */
498 sizeof(DRVNETSNIFFER),
499 /* pfnConstruct */
500 drvNetSnifferConstruct,
501 /* pfnDestruct */
502 drvNetSnifferDestruct,
503 /* pfnRelocate */
504 NULL,
505 /* pfnIOCtl */
506 NULL,
507 /* pfnPowerOn */
508 NULL,
509 /* pfnReset */
510 NULL,
511 /* pfnSuspend */
512 NULL,
513 /* pfnResume */
514 NULL,
515 /* pfnAttach */
516 drvNetSnifferAttach,
517 /* pfnDetach */
518 drvNetSnifferDetach,
519 /* pfnPowerOff */
520 NULL,
521 /* pfnSoftReset */
522 NULL,
523 /* u32EndVersion */
524 PDM_DRVREG_VERSION
525};
526
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