VirtualBox

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

Last change on this file since 22375 was 22375, checked in by vboxsync, 16 years ago

NetSniffer: do not erase the dump file even if network attachment is changed

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