VirtualBox

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

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

The Big Sun Rebranding Header Change

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