VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxIntnetPcap/VBoxIntnetPcap.cpp@ 96402

Last change on this file since 96402 was 96402, checked in by vboxsync, 2 years ago

/Config.kmk and many other places: Change VBOX_VENDOR to the official copyright holder text, needs follow-up changes and equivalent adjustments elsewhere.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.7 KB
Line 
1/* $Id: VBoxIntnetPcap.cpp 96402 2022-08-22 15:27:17Z vboxsync $ */
2/** @file
3 * VBoxIntnetPcap - packet capture for VirtualBox internal networks
4 */
5
6/*
7 * Copyright (C) 2021-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "IntNetIf.h"
23#include "Pcap.h"
24
25#include <iprt/buildconfig.h>
26#include <iprt/file.h>
27#include <iprt/getopt.h>
28#include <iprt/message.h>
29#include <iprt/process.h>
30#include <iprt/stream.h>
31
32#include <iprt/cpp/ministring.h>
33
34#include <VBox/version.h>
35
36
37/*********************************************************************************************************************************
38* Internal Functions *
39*********************************************************************************************************************************/
40static DECLCALLBACK(void) captureFrame(void *pvUser, void *pvFrame, uint32_t cbFrame);
41static DECLCALLBACK(void) captureGSO(void *pvUser, PCPDMNETWORKGSO pcGso, uint32_t cbFrame);
42
43
44/*********************************************************************************************************************************
45* Global Variables *
46*********************************************************************************************************************************/
47static IntNetIf g_net;
48static PRTSTREAM g_pStrmOut;
49static uint64_t g_StartNanoTS;
50static bool g_fPacketBuffered;
51static uint64_t g_cCountDown;
52static size_t g_cbSnapLen = 0xffff;
53
54static const RTGETOPTDEF g_aGetOptDef[] =
55{
56 { "--count", 'c', RTGETOPT_REQ_UINT64 },
57 { "--network", 'i', RTGETOPT_REQ_STRING },
58 { "--snaplen", 's', RTGETOPT_REQ_UINT32 },
59 { "--packet-buffered", 'U', RTGETOPT_REQ_NOTHING },
60 { "--write", 'w', RTGETOPT_REQ_STRING },
61};
62
63
64int
65main(int argc, char *argv[])
66{
67 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
68 if (RT_FAILURE(rc))
69 return RTMsgInitFailure(rc);
70
71 /*
72 * Parse options
73 */
74 RTGETOPTSTATE State;
75 rc = RTGetOptInit(&State, argc, argv, g_aGetOptDef, RT_ELEMENTS(g_aGetOptDef), 1, 0);
76 AssertRC(rc);
77
78 const char *pszNetworkName = NULL;
79 const char *pszPcapFile = NULL;
80
81 int ch;
82 RTGETOPTUNION Val;
83 while ((ch = RTGetOpt(&State, &Val)) != 0)
84 {
85 switch (ch)
86 {
87 case 'c': /* --count */
88 if (Val.u64 == 0)
89 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--count must be greater than zero");
90 g_cCountDown = Val.u64;
91 break;
92
93 case 'i': /* --network */
94 if (Val.psz[0] == '\0')
95 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "empty --network option");
96 pszNetworkName = Val.psz;
97 break;
98
99 case 's': /* --snaplen */
100 if (Val.u32 == 0)
101 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--snaplen must be greater than zero");
102 g_cbSnapLen = Val.u32;
103 break;
104
105 case 'U': /* --packet-buffered */
106 g_fPacketBuffered = true;
107 break;
108
109 case 'w': /* --write */
110 if (Val.psz[0] == '\0')
111 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "empty --write option");
112 pszPcapFile = Val.psz;
113 break;
114
115
116 /*
117 * Standard options recognized by RTGetOpt()
118 */
119 case 'V': /* --version */
120 RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision());
121 return RTEXITCODE_SUCCESS;
122
123 case 'h': /* --help */
124 RTPrintf("%s Version %sr%u\n"
125 "Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
126 "\n"
127 "Usage: %s <options>\n"
128 "\n"
129 "Options:\n",
130 RTProcShortName(), RTBldCfgVersion(), RTBldCfgRevision(),
131 RTProcShortName());
132 for (size_t i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
133 RTPrintf(" -%c, %s\n",
134 g_aGetOptDef[i].iShort, g_aGetOptDef[i].pszLong);
135 return RTEXITCODE_SUCCESS;
136
137 default:
138 case VINF_GETOPT_NOT_OPTION:
139 return RTGetOptPrintError(ch, &Val);
140 }
141 }
142 if (!pszNetworkName)
143 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No network specified. Please use the --network option");
144 if (!pszPcapFile)
145 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No output file specified. Please use the --write option");
146
147 /*
148 * Open the output file.
149 */
150 if (strcmp(pszPcapFile, "-") == 0)
151 g_pStrmOut = g_pStdOut;
152 else
153 {
154 rc = RTStrmOpen(pszPcapFile, "wb", &g_pStrmOut);
155 if (RT_FAILURE(rc))
156 return RTMsgErrorExitFailure("%s: %Rrf", pszPcapFile, rc);
157 }
158
159 /*
160 * Configure the snooper.
161 */
162 g_net.setInputCallback(captureFrame, NULL);
163 g_net.setInputGSOCallback(captureGSO, NULL);
164
165 /*
166 * NB: There's currently no way to prevent an intnet from being
167 * created when one doesn't exist, so there's no way to catch a
168 * typo... beware.
169 */
170 rc = g_net.init(pszNetworkName);
171 if (RT_FAILURE(rc))
172 return RTMsgErrorExitFailure("%s: %Rrf", pszNetworkName, rc);
173
174 rc = g_net.ifSetPromiscuous();
175 if (RT_FAILURE(rc))
176 return RTMsgErrorExitFailure("%s: failed to set promiscuous mode: %Rrf", pszNetworkName, rc);
177
178 /*
179 * Snoop traffic.
180 */
181 g_StartNanoTS = RTTimeNanoTS();
182 rc = PcapStreamHdr(g_pStrmOut, g_StartNanoTS);
183 if (RT_FAILURE(rc))
184 return RTMsgErrorExitFailure("write: %Rrf", rc);
185 if (g_fPacketBuffered)
186 RTStrmFlush(g_pStrmOut);
187
188 g_net.ifPump();
189
190 RTEXITCODE rcExit = RT_SUCCESS(RTStrmError(g_pStrmOut)) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
191 rc = RTStrmClose(g_pStrmOut);
192 if (RT_FAILURE(rc))
193 rcExit = RTMsgErrorExitFailure("close: %Rrf", rc);
194 return rcExit;
195}
196
197
198static void checkCaptureLimit(void)
199{
200 if (g_cCountDown > 0)
201 {
202 if (g_cCountDown-- == 1)
203 g_net.ifAbort();
204 }
205}
206
207
208static DECLCALLBACK(void) captureFrame(void *pvUser, void *pvFrame, uint32_t cbFrame)
209{
210 RT_NOREF(pvUser);
211
212 int rc = PcapStreamFrame(g_pStrmOut, g_StartNanoTS, pvFrame, cbFrame, g_cbSnapLen);
213 if (RT_FAILURE(rc))
214 {
215 RTMsgError("write: %Rrf", rc);
216 g_net.ifAbort();
217 }
218
219 if (g_fPacketBuffered)
220 RTStrmFlush(g_pStrmOut);
221
222 checkCaptureLimit();
223}
224
225
226static DECLCALLBACK(void) captureGSO(void *pvUser, PCPDMNETWORKGSO pcGso, uint32_t cbFrame)
227{
228 RT_NOREF(pvUser, pcGso, cbFrame);
229
230 checkCaptureLimit();
231}
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