VirtualBox

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

Last change on this file since 92489 was 87925, checked in by vboxsync, 4 years ago

VBoxIntnetPcap: Fix timestamps. bugref:9959.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.4 KB
Line 
1/* $Id: VBoxIntnetPcap.cpp 87925 2021-03-02 20:12:02Z vboxsync $ */
2/** @file
3 * VBoxIntnetPcap - packet capture for VirtualBox internal networks
4 */
5
6/*
7 * Copyright (C) 2021 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#include "IntNetIf.h"
19#include "Pcap.h"
20
21#include <iprt/buildconfig.h>
22#include <iprt/file.h>
23#include <iprt/getopt.h>
24#include <iprt/message.h>
25#include <iprt/process.h>
26#include <iprt/stream.h>
27
28#include <iprt/cpp/ministring.h>
29
30#include <VBox/version.h>
31
32void captureFrame(void *pvUser, void *pvFrame, uint32_t cbFrame);
33void captureGSO(void *pvUser, PCPDMNETWORKGSO pcGso, uint32_t cbFrame);
34void checkCaptureLimit();
35
36IntNetIf g_net;
37PRTSTREAM g_pStrmOut;
38uint64_t g_StartNanoTS;
39bool g_fPacketBuffered;
40uint64_t g_u64Count;
41size_t g_cbSnapLen;
42
43
44RTGETOPTDEF g_aGetOptDef[] =
45{
46 { "--count", 'c', RTGETOPT_REQ_UINT64 },
47 { "--network", 'i', RTGETOPT_REQ_STRING },
48 { "--snaplen", 's', RTGETOPT_REQ_UINT32 },
49 { "--packet-buffered", 'U', RTGETOPT_REQ_NOTHING },
50 { "--write", 'w', RTGETOPT_REQ_STRING },
51};
52
53
54int
55main(int argc, char *argv[])
56{
57 int rc;
58
59 RTCString strNetworkName;
60 RTCString strPcapFile;
61
62 rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
63 if (RT_FAILURE(rc))
64 return RTMsgInitFailure(rc);
65
66 RTGETOPTSTATE State;
67 rc = RTGetOptInit(&State, argc, argv,
68 g_aGetOptDef, RT_ELEMENTS(g_aGetOptDef),
69 1, 0);
70
71 int ch;
72 RTGETOPTUNION Val;
73 while ((ch = RTGetOpt(&State, &Val)) != 0)
74 {
75 switch (ch)
76 {
77 case 'c': /* --count */
78 if (g_u64Count != 0)
79 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
80 "multiple --count options");
81 if (Val.u64 == 0)
82 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
83 "--count must be greater than zero");
84 g_u64Count = Val.u64;
85 break;
86
87 case 'i': /* --network */
88 if (strNetworkName.isNotEmpty())
89 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
90 "multiple --network options");
91 if (Val.psz[0] == '\0')
92 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
93 "empty --network option");
94 strNetworkName = Val.psz;
95 break;
96
97 case 's': /* --snaplen */
98 if (g_cbSnapLen != 0)
99 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
100 "multiple --snaplen options");
101 if (Val.u32 == 0)
102 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
103 "--snaplen must be greater than zero");
104 g_cbSnapLen = Val.u32;
105 break;
106
107 case 'U': /* --packet-buffered */
108 g_fPacketBuffered = true;
109 break;
110
111 case 'w': /* --write */
112 if (strPcapFile.isNotEmpty())
113 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
114 "multiple --write options");
115 if (Val.psz[0] == '\0')
116 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
117 "empty --write option");
118 strPcapFile = Val.psz;
119 break;
120
121
122 /*
123 * Standard options recognized by RTGetOpt()
124 */
125 case 'V': /* --version */
126 RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision());
127 return RTEXITCODE_SUCCESS;
128
129 case 'h': /* --help */
130 RTPrintf("%s Version %sr%u\n"
131 "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
132 "All rights reserved.\n"
133 "\n"
134 "Usage: %s <options>\n"
135 "\n"
136 "Options:\n",
137 RTProcShortName(), RTBldCfgVersion(), RTBldCfgRevision(),
138 RTProcShortName());
139 for (size_t i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
140 RTPrintf(" -%c, %s\n",
141 g_aGetOptDef[i].iShort, g_aGetOptDef[i].pszLong);
142 return RTEXITCODE_SUCCESS;
143
144 case VINF_GETOPT_NOT_OPTION:
145 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
146 "unexpected non-option argument");
147
148 default:
149 return RTGetOptPrintError(ch, &Val);
150 }
151 }
152
153 if (strNetworkName.isEmpty())
154 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
155 "missing --network option");
156
157 if (strPcapFile.isEmpty())
158 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
159 "missing --write option");
160
161 if (g_cbSnapLen == 0)
162 g_cbSnapLen = 0xffff;
163
164
165 if (strPcapFile == "-")
166 {
167 g_pStrmOut = g_pStdOut;
168 }
169 else
170 {
171 rc = RTStrmOpen(strPcapFile.c_str(), "wb", &g_pStrmOut);
172 if (RT_FAILURE(rc))
173 return RTMsgErrorExit(RTEXITCODE_FAILURE,
174 "%s: %Rrf", strPcapFile.c_str(), rc);
175 }
176
177 g_net.setInputCallback(captureFrame, NULL);
178 g_net.setInputGSOCallback(captureGSO, NULL);
179
180 /*
181 * NB: There's currently no way to prevent an intnet from being
182 * created when one doesn't exist, so there's no way to catch a
183 * typo... beware.
184 */
185 rc = g_net.init(strNetworkName);
186 if (RT_FAILURE(rc))
187 return RTMsgErrorExit(RTEXITCODE_FAILURE,
188 "%s: %Rrf", strNetworkName.c_str(), rc);
189
190 rc = g_net.ifSetPromiscuous();
191 if (RT_FAILURE(rc))
192 return RTMsgErrorExit(RTEXITCODE_FAILURE,
193 "%s: failed to set promiscuous mode: %Rrf",
194 strNetworkName.c_str(), rc);
195
196 g_StartNanoTS = RTTimeNanoTS();
197 rc = PcapStreamHdr(g_pStrmOut, g_StartNanoTS);
198 if (RT_FAILURE(rc))
199 return RTMsgErrorExit(RTEXITCODE_FAILURE,
200 "write: %Rrf", rc);
201 if (g_fPacketBuffered)
202 RTStrmFlush(g_pStrmOut);
203
204 g_net.ifPump();
205 RTStrmClose(g_pStrmOut);
206
207 return RTEXITCODE_SUCCESS;
208}
209
210
211void
212checkCaptureLimit()
213{
214 if (g_u64Count > 0)
215 {
216 if (g_u64Count-- == 1)
217 g_net.ifAbort();
218 }
219}
220
221
222void
223captureFrame(void *pvUser, void *pvFrame, uint32_t cbFrame)
224{
225 int rc;
226
227 RT_NOREF(pvUser);
228
229 rc = PcapStreamFrame(g_pStrmOut, g_StartNanoTS,
230 pvFrame, cbFrame, g_cbSnapLen);
231 if (RT_FAILURE(rc)) {
232 RTMsgError("write: %Rrf", rc);
233 g_net.ifAbort();
234 }
235
236 if (g_fPacketBuffered)
237 RTStrmFlush(g_pStrmOut);
238
239 checkCaptureLimit();
240}
241
242
243void
244captureGSO(void *pvUser, PCPDMNETWORKGSO pcGso, uint32_t cbFrame)
245{
246 RT_NOREF(pvUser);
247 RT_NOREF(pcGso, cbFrame);
248
249 checkCaptureLimit();
250}
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