VirtualBox

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

Last change on this file since 400 was 1, checked in by vboxsync, 55 years ago

import

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