VirtualBox

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

Last change on this file since 3460 was 3196, checked in by vboxsync, 18 years ago

worked around annoying gcc warning

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