VirtualBox

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

Last change on this file since 106579 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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