VirtualBox

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

Last change on this file since 2981 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 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
102
103
104/**
105 * Send data to the network.
106 *
107 * @returns VBox status code.
108 * @param pInterface Pointer to the interface structure containing the called function pointer.
109 * @param pvBuf Data to send.
110 * @param cb Number of bytes to send.
111 * @thread EMT
112 */
113static DECLCALLBACK(int) drvNetSnifferSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
114{
115 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
116
117 /* output to sniffer */
118 struct pcaprec_hdr Hdr;
119 uint64_t u64TS = RTTimeProgramNanoTS();
120 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
121 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
122 Hdr.incl_len = cb;
123 Hdr.orig_len = cb;
124 RTCritSectEnter(&pData->Lock);
125 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
126 RTFileWrite(pData->File, pvBuf, cb, NULL);
127 RTCritSectLeave(&pData->Lock);
128
129 /* pass down */
130 if (pData->pConnector)
131 {
132 int rc = pData->pConnector->pfnSend(pData->pConnector, pvBuf, cb);
133#if 0
134 RTCritSectEnter(&pData->Lock);
135 u64TS = RTTimeProgramNanoTS();
136 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
137 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
138 Hdr.incl_len = 0;
139 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
140 RTCritSectLeave(&pData->Lock);
141#endif
142 return rc;
143 }
144 return VINF_SUCCESS;
145}
146
147
148/**
149 * Set promiscuous mode.
150 *
151 * This is called when the promiscuous mode is set. This means that there doesn't have
152 * to be a mode change when it's called.
153 *
154 * @param pInterface Pointer to the interface structure containing the called function pointer.
155 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
156 * @thread EMT
157 */
158static DECLCALLBACK(void) drvNetSnifferSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
159{
160 LogFlow(("drvNetSnifferSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
161 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
162 if (pData->pConnector)
163 pData->pConnector->pfnSetPromiscuousMode(pData->pConnector, fPromiscuous);
164}
165
166
167/**
168 * Notification on link status changes.
169 *
170 * @param pInterface Pointer to the interface structure containing the called function pointer.
171 * @param enmLinkState The new link state.
172 * @thread EMT
173 */
174static DECLCALLBACK(void) drvNetSnifferNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
175{
176 LogFlow(("drvNetSnifferNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
177 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
178 if (pData->pConnector)
179 pData->pConnector->pfnNotifyLinkChanged(pData->pConnector, enmLinkState);
180}
181
182
183/**
184 * More receive buffer has become available.
185 *
186 * This is called when the NIC frees up receive buffers.
187 *
188 * @param pInterface Pointer to the interface structure containing the called function pointer.
189 * @thread EMT
190 */
191static DECLCALLBACK(void) drvNetSnifferNotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
192{
193 LogFlow(("drvNetSnifferNotifyCanReceive:\n"));
194 PDRVNETSNIFFER pData = PDMINETWORKCONNECTOR_2_DRVNETSNIFFER(pInterface);
195 if (pData->pConnector)
196 pData->pConnector->pfnNotifyCanReceive(pData->pConnector);
197}
198
199
200/**
201 * Check how much data the device/driver can receive data now.
202 * This must be called before the pfnRecieve() method is called.
203 *
204 * @returns Number of bytes the device can receive now.
205 * @param pInterface Pointer to the interface structure containing the called function pointer.
206 * @thread EMT
207 */
208static DECLCALLBACK(size_t) drvNetSnifferCanReceive(PPDMINETWORKPORT pInterface)
209{
210 PDRVNETSNIFFER pData = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
211 return pData->pPort->pfnCanReceive(pData->pPort);
212}
213
214
215/**
216 * Receive data from the network.
217 *
218 * @returns VBox status code.
219 * @param pInterface Pointer to the interface structure containing the called function pointer.
220 * @param pvBuf The available data.
221 * @param cb Number of bytes available in the buffer.
222 * @thread EMT
223 */
224static DECLCALLBACK(int) drvNetSnifferReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
225{
226 PDRVNETSNIFFER pData = PDMINETWORKPORT_2_DRVNETSNIFFER(pInterface);
227
228 /* output to sniffer */
229 struct pcaprec_hdr Hdr;
230 uint64_t u64TS = RTTimeProgramNanoTS();
231 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
232 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
233 Hdr.incl_len = cb;
234 Hdr.orig_len = cb;
235 RTCritSectEnter(&pData->Lock);
236 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
237 RTFileWrite(pData->File, pvBuf, cb, NULL);
238 RTCritSectLeave(&pData->Lock);
239
240 /* pass up */
241 int rc = pData->pPort->pfnReceive(pData->pPort, pvBuf, cb);
242#if 0
243 RTCritSectEnter(&pData->Lock);
244 u64TS = RTTimeProgramNanoTS();
245 Hdr.ts_sec = (uint32_t)(u64TS / 1000000000);
246 Hdr.ts_usec = (uint32_t)((u64TS / 1000) % 1000000);
247 Hdr.incl_len = 0;
248 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
249 RTCritSectLeave(&pData->Lock);
250#endif
251 return rc;
252}
253
254/**
255 * Queries an interface to the driver.
256 *
257 * @returns Pointer to interface.
258 * @returns NULL if the interface was not supported by the driver.
259 * @param pInterface Pointer to this interface structure.
260 * @param enmInterface The requested interface identification.
261 * @thread Any thread.
262 */
263static DECLCALLBACK(void *) drvNetSnifferQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
264{
265 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
266 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
267 switch (enmInterface)
268 {
269 case PDMINTERFACE_BASE:
270 return &pDrvIns->IBase;
271 case PDMINTERFACE_NETWORK_CONNECTOR:
272 return &pData->INetworkConnector;
273 case PDMINTERFACE_NETWORK_PORT:
274 return &pData->INetworkPort;
275 default:
276 return NULL;
277 }
278}
279
280
281/**
282 * Destruct a driver instance.
283 *
284 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
285 * resources can be freed correctly.
286 *
287 * @param pDrvIns The driver instance data.
288 */
289static DECLCALLBACK(void) drvNetSnifferDestruct(PPDMDRVINS pDrvIns)
290{
291 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
292
293 if (RTCritSectIsInitialized(&pData->Lock))
294 RTCritSectDelete(&pData->Lock);
295
296 if (pData->File != NIL_RTFILE)
297 {
298 RTFileClose(pData->File);
299 pData->File = NIL_RTFILE;
300 }
301}
302
303
304/**
305 * Construct a NAT network transport driver instance.
306 *
307 * @returns VBox status.
308 * @param pDrvIns The driver instance data.
309 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
310 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
311 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
312 * iInstance it's expected to be used a bit in this function.
313 */
314static DECLCALLBACK(int) drvNetSnifferConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
315{
316 PDRVNETSNIFFER pData = PDMINS2DATA(pDrvIns, PDRVNETSNIFFER);
317 LogFlow(("drvNetSnifferConstruct:\n"));
318
319 /*
320 * Validate the config.
321 */
322 if (!CFGMR3AreValuesValid(pCfgHandle, "File\0"))
323 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
324
325 /*
326 * Init the static parts.
327 */
328 pData->pDrvIns = pDrvIns;
329 pData->File = NIL_RTFILE;
330 /* IBase */
331 pDrvIns->IBase.pfnQueryInterface = drvNetSnifferQueryInterface;
332 /* INetworkConnector */
333 pData->INetworkConnector.pfnSend = drvNetSnifferSend;
334 pData->INetworkConnector.pfnSetPromiscuousMode = drvNetSnifferSetPromiscuousMode;
335 pData->INetworkConnector.pfnNotifyLinkChanged = drvNetSnifferNotifyLinkChanged;
336 pData->INetworkConnector.pfnNotifyCanReceive = drvNetSnifferNotifyCanReceive;
337 /* INetworkPort */
338 pData->INetworkPort.pfnCanReceive = drvNetSnifferCanReceive;
339 pData->INetworkPort.pfnReceive = drvNetSnifferReceive;
340
341 /*
342 * Get the filename.
343 */
344 int rc = CFGMR3QueryString(pCfgHandle, "File", pData->szFilename, sizeof(pData->szFilename));
345 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
346 RTStrPrintf(pData->szFilename, sizeof(pData->szFilename), "./VBox-%x.pcap", RTProcSelf());
347 else if (VBOX_FAILURE(rc))
348 {
349 AssertMsgFailed(("Failed to query \"File\", rc=%Vrc.\n", rc));
350 return rc;
351 }
352
353 /*
354 * Query the network port interface.
355 */
356 pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
357 if (!pData->pPort)
358 {
359 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
360 return VERR_PDM_MISSING_INTERFACE_ABOVE;
361 }
362
363 /*
364 * Query the network connector interface.
365 */
366 PPDMIBASE pBaseDown;
367 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseDown);
368 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
369 pData->pConnector = NULL;
370 else if (VBOX_SUCCESS(rc))
371 {
372 pData->pConnector = (PPDMINETWORKCONNECTOR)pBaseDown->pfnQueryInterface(pBaseDown, PDMINTERFACE_NETWORK_CONNECTOR);
373 if (!pData->pConnector)
374 {
375 AssertMsgFailed(("Configuration error: the driver below didn't export the network connector interface!\n"));
376 return VERR_PDM_MISSING_INTERFACE_BELOW;
377 }
378 }
379 else
380 {
381 AssertMsgFailed(("Failed to attach to driver below! rc=%Vrc\n", rc));
382 return rc;
383 }
384
385 /*
386 * Create the lock.
387 */
388 rc = RTCritSectInit(&pData->Lock);
389 if (VBOX_FAILURE(rc))
390 return rc;
391
392 /*
393 * Open output file / pipe.
394 */
395 rc = RTFileOpen(&pData->File, pData->szFilename,
396 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
397 if (VBOX_FAILURE(rc))
398 {
399 AssertMsgFailed(("Failed to create file '%s' for writing. rc=%Vrc\n", pData->szFilename, rc));
400 return rc;
401 }
402
403 /*
404 * Write pcap header.
405 */
406 struct
407 {
408 uint32_t u32Magic;
409 struct pcap_hdr pcap;
410#ifdef LOG_ENABLED
411 pcaprec_hdr rec;
412 } Hdr = { PCAP_MAGIC, { 2, 4, 0, 0, 0xffff, 1 }, { 0, 1, 0, 60} }; /* force ethereal to start at 0.000000. */
413#else
414 } Hdr = { PCAP_MAGIC, { 2, 4, 0, 0, 0xffff, 1 } }; /* this is just to make it happy, not to be correct. */
415#endif
416 RTFileWrite(pData->File, &Hdr, sizeof(Hdr), NULL);
417
418 return VINF_SUCCESS;
419}
420
421
422
423/**
424 * Network sniffer filter driver registration record.
425 */
426const PDMDRVREG g_DrvNetSniffer =
427{
428 /* u32Version */
429 PDM_DRVREG_VERSION,
430 /* szDriverName */
431 "NetSniffer",
432 /* pszDescription */
433 "Network Sniffer Filter Driver",
434 /* fFlags */
435 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
436 /* fClass. */
437 PDM_DRVREG_CLASS_NETWORK,
438 /* cMaxInstances */
439 1,
440 /* cbInstance */
441 sizeof(DRVNETSNIFFER),
442 /* pfnConstruct */
443 drvNetSnifferConstruct,
444 /* pfnDestruct */
445 drvNetSnifferDestruct,
446 /* pfnIOCtl */
447 NULL,
448 /* pfnPowerOn */
449 NULL,
450 /* pfnReset */
451 NULL,
452 /* pfnSuspend */
453 NULL,
454 /* pfnResume */
455 NULL,
456 /* pfnDetach */
457 NULL,
458 /* pfnPowerOff */
459 NULL
460};
461
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