VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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