VirtualBox

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

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

spaces. dropped #include <string.h>

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