VirtualBox

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

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

netsniffer: implemented missing config interface allow to sniffing NAT-bound network cards

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 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.virtualbox.org. 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 "Builtins.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * Block driver instance data.
47 */
48typedef struct DRVNETSNIFFER
49{
50 /** The network interface. */
51 PDMINETWORKCONNECTOR INetworkConnector;
52 /** The network interface. */
53 PDMINETWORKPORT INetworkPort;
54 /** The network config interface. */
55 PDMINETWORKCONFIG INetworkConfig;
56 /** The port we're attached to. */
57 PPDMINETWORKPORT pPort;
58 /** The config port interface we're attached to. */
59 PPDMINETWORKCONFIG pConfig;
60 /** The connector that's attached to us. */
61 PPDMINETWORKCONNECTOR pConnector;
62 /** The filename. */
63 char szFilename[RTPATH_MAX];
64 /** The filehandle. */
65 RTFILE File;
66 /** The lock serializing the file access. */
67 RTCRITSECT Lock;
68 /** Pointer to the driver instance. */
69 PPDMDRVINS pDrvIns;
70
71} DRVNETSNIFFER, *PDRVNETSNIFFER;
72
73/** Converts a pointer to NAT::INetworkConnector to a PDRVNETSNIFFER. */
74#define PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConnector)) )
75
76/** Converts a pointer to NAT::INetworkPort to a PDRVNETSNIFFER. */
77#define PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkPort)) )
78
79/** Converts a pointer to NAT::INetworkConfig to a PDRVNETSNIFFER. */
80#define PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface) ( (PDRVNETSNIFFER)((uintptr_t)pInterface - RT_OFFSETOF(DRVNETSNIFFER, INetworkConfig)) )
81
82
83/* "libpcap" magic */
84#define PCAP_MAGIC 0xa1b2c3d4
85
86/* "libpcap" file header (minus magic number). */
87struct pcap_hdr
88{
89 uint16_t version_major; /* major version number = 2 */
90 uint16_t version_minor; /* minor version number = 4 */
91 int32_t thiszone; /* GMT to local correction = 0 */
92 uint32_t sigfigs; /* accuracy of timestamps = 0 */
93 uint32_t snaplen; /* max length of captured packets, in octets = 0xffff */
94 uint32_t network; /* data link type = 01 */
95};
96
97/* "libpcap" record header. */
98struct pcaprec_hdr
99{
100 uint32_t ts_sec; /* timestamp seconds */
101 uint32_t ts_usec; /* timestamp microseconds */
102 uint32_t incl_len; /* number of octets of packet saved in file */
103 uint32_t orig_len; /* actual length of packet */
104};
105
106struct pcaprec_hdr_init
107{
108 uint32_t u32Magic;
109 struct pcap_hdr pcap;
110#ifdef LOG_ENABLED
111 pcaprec_hdr rec;
112#endif
113};
114
115
116/**
117 * Send data to the network.
118 *
119 * @returns VBox status code.
120 * @param pInterface Pointer to the interface structure containing the called function pointer.
121 * @param pvBuf Data to send.
122 * @param cb Number of bytes to send.
123 * @thread EMT
124 */
125static DECLCALLBACK(int) drvNetSnifferSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
126{
127 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
128
129 /* output to sniffer */
130 struct pcaprec_hdr Hdr;
131 uint64_t u64TS = RTTimeProgramNanoTS();
132 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
133 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
134 Hdr.incl_len = cb;
135 Hdr.orig_len = cb;
136 RTCritSectEnter(&pData->Lock);
137 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
138 RTFileWrite(pData->File, pvBuf, cb, NULL);
139 RTCritSectLeave(&pData->Lock);
140
141 /* pass down */
142 if (pData->pConnector)
143 {
144 int rc = pData->pConnector->pfnSend(pData->pConnector, pvBuf, cb);
145#if 0
146 RTCritSectEnter(&pData->Lock);
147 u64TS = RTTimeProgramNanoTS();
148 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
149 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
150 Hdr.incl_len = 0;
151 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
152 RTCritSectLeave(&pData->Lock);
153#endif
154 return rc;
155 }
156 return VINF_SUCCESS;
157}
158
159
160/**
161 * Set promiscuous mode.
162 *
163 * This is called when the promiscuous mode is set. This means that there doesn't have
164 * to be a mode change when it's called.
165 *
166 * @param pInterface Pointer to the interface structure containing the called function pointer.
167 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
168 * @thread EMT
169 */
170static DECLCALLBACK(void) drvNetSnifferSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
171{
172 LogFlow(("drvNetSnifferSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
173 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
174 if (pData->pConnector)
175 pData->pConnector->pfnSetPromiscuousMode(pData->pConnector, fPromiscuous);
176}
177
178
179/**
180 * Notification on link status changes.
181 *
182 * @param pInterface Pointer to the interface structure containing the called function pointer.
183 * @param enmLinkState The new link state.
184 * @thread EMT
185 */
186static DECLCALLBACK(void) drvNetSnifferNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
187{
188 LogFlow(("drvNetSnifferNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
189 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
190 if (pData->pConnector)
191 pData->pConnector->pfnNotifyLinkChanged(pData->pConnector, enmLinkState);
192}
193
194
195/**
196 * Check how much data the device/driver can receive data now.
197 * This must be called before the pfnRecieve() method is called.
198 *
199 * @returns Number of bytes the device can receive now.
200 * @param pInterface Pointer to the interface structure containing the called function pointer.
201 * @thread EMT
202 */
203static DECLCALLBACK(int) drvNetSnifferWaitReceiveAvail(PPDMINETWORKPORT pInterface, unsigned cMillies)
204{
205 PDRVNETSNIFFER pData = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
206 return pData->pPort->pfnWaitReceiveAvail(pData->pPort, cMillies);
207}
208
209
210/**
211 * Receive data from the network.
212 *
213 * @returns VBox status code.
214 * @param pInterface Pointer to the interface structure containing the called function pointer.
215 * @param pvBuf The available data.
216 * @param cb Number of bytes available in the buffer.
217 * @thread EMT
218 */
219static DECLCALLBACK(int) drvNetSnifferReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
220{
221 PDRVNETSNIFFER pData = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
222
223 /* output to sniffer */
224 struct pcaprec_hdr Hdr;
225 uint64_t u64TS = RTTimeProgramNanoTS();
226 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
227 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
228 Hdr.incl_len = cb;
229 Hdr.orig_len = cb;
230 RTCritSectEnter(&pData->Lock);
231 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
232 RTFileWrite(pData->File, pvBuf, cb, NULL);
233 RTCritSectLeave(&pData->Lock);
234
235 /* pass up */
236 int rc = pData->pPort->pfnReceive(pData->pPort, pvBuf, cb);
237#if 0
238 RTCritSectEnter(&pData->Lock);
239 u64TS = RTTimeProgramNanoTS();
240 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
241 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
242 Hdr.incl_len = 0;
243 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
244 RTCritSectLeave(&pData->Lock);
245#endif
246 return rc;
247}
248
249
250/**
251 * Gets the current Media Access Control (MAC) address.
252 *
253 * @returns VBox status code.
254 * @param pInterface Pointer to the interface structure containing the called function pointer.
255 * @param pMac Where to store the MAC address.
256 * @thread EMT
257 */
258static DECLCALLBACK(int) drvNetSnifferGetMac(PPDMINETWORKCONFIG pInterface, PPDMMAC pMac)
259{
260 PDRVNETSNIFFER pData = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
261 return pData->pConfig->pfnGetMac(pData->pConfig, pMac);
262}
263
264/**
265 * Gets the new link state.
266 *
267 * @returns The current link state.
268 * @param pInterface Pointer to the interface structure containing the called function pointer.
269 * @thread EMT
270 */
271static DECLCALLBACK(PDMNETWORKLINKSTATE) drvNetSnifferGetLinkState(PPDMINETWORKCONFIG pInterface)
272{
273 PDRVNETSNIFFER pData = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
274 return pData->pConfig->pfnGetLinkState(pData->pConfig);
275}
276
277/**
278 * Sets the new link state.
279 *
280 * @returns VBox status code.
281 * @param pInterface Pointer to the interface structure containing the called function pointer.
282 * @param enmState The new link state
283 * @thread EMT
284 */
285static DECLCALLBACK(int) drvNetSnifferSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
286{
287 PDRVNETSNIFFER pData = PDMINETWORKCONFIG_2_DRVNETSNIFFER(pInterface);
288 return pData->pConfig->pfnSetLinkState(pData->pConfig, enmState);
289}
290
291
292/**
293 * Queries an interface to the driver.
294 *
295 * @returns Pointer to interface.
296 * @returns NULL if the interface was not supported by the driver.
297 * @param pInterface Pointer to this interface structure.
298 * @param enmInterface The requested interface identification.
299 * @thread Any thread.
300 */
301static DECLCALLBACK(void *) drvNetSnifferQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
302{
303 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
304 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
305 switch (enmInterface)
306 {
307 case PDMINTERFACE_BASE:
308 return &pDrvIns->IBase;
309 case PDMINTERFACE_NETWORK_CONNECTOR:
310 return &pData->INetworkConnector;
311 case PDMINTERFACE_NETWORK_PORT:
312 return &pData->INetworkPort;
313 case PDMINTERFACE_NETWORK_CONFIG:
314 return &pData->INetworkConfig;
315 default:
316 return NULL;
317 }
318}
319
320
321/**
322 * Destruct a driver instance.
323 *
324 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
325 * resources can be freed correctly.
326 *
327 * @param pDrvIns The driver instance data.
328 */
329static DECLCALLBACK(void) drvNetSnifferDestruct(PPDMDRVINS pDrvIns)
330{
331 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
332
333 if (RTCritSectIsInitialized(&pData->Lock))
334 RTCritSectDelete(&pData->Lock);
335
336 if (pData->File != NIL_RTFILE)
337 {
338 RTFileClose(pData->File);
339 pData->File = NIL_RTFILE;
340 }
341}
342
343
344/**
345 * Construct a NAT network transport driver instance.
346 *
347 * @returns VBox status.
348 * @param pDrvIns The driver instance data.
349 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
350 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
351 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
352 * iInstance it's expected to be used a bit in this function.
353 */
354static DECLCALLBACK(int) drvNetSnifferConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
355{
356 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
357 LogFlow(("drvNetSnifferConstruct:\n"));
358
359 /*
360 * Validate the config.
361 */
362 if (!CFGMR3AreValuesValid(pCfgHandle, "File\0"))
363 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
364
365 /*
366 * Init the static parts.
367 */
368 pData->pDrvIns = pDrvIns;
369 pData->File = NIL_RTFILE;
370 /* IBase */
371 pDrvIns->IBase.pfnQueryInterface = drvNetSnifferQueryInterface;
372 /* INetworkConnector */
373 pData->INetworkConnector.pfnSend = drvNetSnifferSend;
374 pData->INetworkConnector.pfnSetPromiscuousMode = drvNetSnifferSetPromiscuousMode;
375 pData->INetworkConnector.pfnNotifyLinkChanged = drvNetSnifferNotifyLinkChanged;
376 /* INetworkPort */
377 pData->INetworkPort.pfnWaitReceiveAvail = drvNetSnifferWaitReceiveAvail;
378 pData->INetworkPort.pfnReceive = drvNetSnifferReceive;
379 /* INetworkConfig */
380 pData->INetworkConfig.pfnGetMac = drvNetSnifferGetMac;
381 pData->INetworkConfig.pfnGetLinkState = drvNetSnifferGetLinkState;
382 pData->INetworkConfig.pfnSetLinkState = drvNetSnifferSetLinkState;
383
384 /*
385 * Get the filename.
386 */
387 int rc = CFGMR3QueryString(pCfgHandle, "File", pData->szFilename, sizeof(pData->szFilename));
388 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
389 RTStrPrintf(pData->szFilename, sizeof(pData->szFilename), "./VBox-%x.pcap", RTProcSelf());
390 else if (VBOX_FAILURE(rc))
391 {
392 AssertMsgFailed(("Failed to query \"File\", rc=%Vrc.\n", rc));
393 return rc;
394 }
395
396 /*
397 * Query the network port interface.
398 */
399 pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
400 if (!pData->pPort)
401 {
402 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
403 return VERR_PDM_MISSING_INTERFACE_ABOVE;
404 }
405
406 /*
407 * Query the network config interface.
408 */
409 pData->pConfig = (PPDMINETWORKCONFIG)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_CONFIG);
410 if (!pData->pConfig)
411 {
412 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
413 return VERR_PDM_MISSING_INTERFACE_ABOVE;
414 }
415
416 /*
417 * Query the network connector interface.
418 */
419 PPDMIBASE pBaseDown;
420 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseDown);
421 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
422 pData->pConnector = NULL;
423 else if (VBOX_SUCCESS(rc))
424 {
425 pData->pConnector = (PPDMINETWORKCONNECTOR)pBaseDown->pfnQueryInterface(pBaseDown, PDMINTERFACE_NETWORK_CONNECTOR);
426 if (!pData->pConnector)
427 {
428 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
429 return VERR_PDM_MISSING_INTERFACE_BELOW;
430 }
431 }
432 else
433 {
434 AssertMsgFailed(("Failed to attach to driver below! rc=%Vrc\n", rc));
435 return rc;
436 }
437
438 /*
439 * Create the lock.
440 */
441 rc = RTCritSectInit(&pData->Lock);
442 if (VBOX_FAILURE(rc))
443 return rc;
444
445 /*
446 * Open output file / pipe.
447 */
448 rc = RTFileOpen(&pData->File, pData->szFilename,
449 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
450 if (VBOX_FAILURE(rc))
451 {
452 AssertMsgFailed(("Failed to create file '%s' for writing. rc=%Vrc\n", pData->szFilename, rc));
453 return rc;
454 }
455
456 /*
457 * Write pcap header.
458 */
459#ifdef LOG_ENABLED
460 pcaprec_hdr_init Hdr =
461 {
462 PCAP_MAGIC,
463 { 2, 4, 0, 0, 0xffff, 1 },
464 { 0, 1, 0, 60}
465 }; /* force ethereal to start at 0.000000. */
466#else
467 pcaprec_hdr_init Hdr =
468 {
469 PCAP_MAGIC,
470 { 2, 4, 0, 0, 0xffff, 1 }
471 }; /* this is just to make it happy, not to be correct. */
472#endif
473
474 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
475
476 return VINF_SUCCESS;
477}
478
479
480
481/**
482 * Network sniffer filter driver registration record.
483 */
484const PDMDRVREG g_DrvNetSniffer =
485{
486 /* u32Version */
487 PDM_DRVREG_VERSION,
488 /* szDriverName */
489 "NetSniffer",
490 /* pszDescription */
491 "Network Sniffer Filter Driver",
492 /* fFlags */
493 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
494 /* fClass. */
495 PDM_DRVREG_CLASS_NETWORK,
496 /* cMaxInstances */
497 1,
498 /* cbInstance */
499 sizeof(DRVNETSNIFFER),
500 /* pfnConstruct */
501 drvNetSnifferConstruct,
502 /* pfnDestruct */
503 drvNetSnifferDestruct,
504 /* pfnIOCtl */
505 NULL,
506 /* pfnPowerOn */
507 NULL,
508 /* pfnReset */
509 NULL,
510 /* pfnSuspend */
511 NULL,
512 /* pfnResume */
513 NULL,
514 /* pfnDetach */
515 NULL,
516 /* pfnPowerOff */
517 NULL
518};
519
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