VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/generic/NetIf-generic.cpp@ 91769

Last change on this file since 91769 was 91769, checked in by vboxsync, 3 years ago

VBoxNetAdp: (bugref:10077) More administrative control over network ranges

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/* $Id: NetIf-generic.cpp 91769 2021-10-15 19:24:43Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Generic NetIf implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2020 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 <VBox/err.h>
19#include <VBox/log.h>
20#include <iprt/process.h>
21#include <iprt/env.h>
22#include <iprt/path.h>
23#include <iprt/param.h>
24#include <sys/ioctl.h>
25#include <netinet/in.h>
26#include <net/if.h>
27#include <errno.h>
28#include <unistd.h>
29
30#if defined(RT_OS_SOLARIS)
31# include <sys/sockio.h>
32#endif
33
34#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN)
35# include <cstdio>
36#endif
37
38#include "HostNetworkInterfaceImpl.h"
39#include "ProgressImpl.h"
40#include "VirtualBoxImpl.h"
41#include "VBoxNls.h"
42#include "Global.h"
43#include "netif.h"
44
45#define VBOXNETADPCTL_NAME "VBoxNetAdpCtl"
46
47DECLARE_TRANSLATION_CONTEXT(NetIfGeneric);
48
49
50static int NetIfAdpCtl(const char * pcszIfName, const char *pszAddr, const char *pszOption, const char *pszMask)
51{
52 const char *args[] = { NULL, pcszIfName, pszAddr, pszOption, pszMask, NULL };
53
54 char szAdpCtl[RTPATH_MAX];
55 int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME));
56 if (RT_FAILURE(rc))
57 {
58 LogRel(("NetIfAdpCtl: failed to get program path, rc=%Rrc.\n", rc));
59 return rc;
60 }
61 strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME);
62 args[0] = szAdpCtl;
63 if (!RTPathExists(szAdpCtl))
64 {
65 LogRel(("NetIfAdpCtl: path %s does not exist. Failed to run " VBOXNETADPCTL_NAME " helper.\n",
66 szAdpCtl));
67 return VERR_FILE_NOT_FOUND;
68 }
69
70 RTPROCESS pid;
71 rc = RTProcCreate(szAdpCtl, args, RTENV_DEFAULT, 0, &pid);
72 if (RT_SUCCESS(rc))
73 {
74 RTPROCSTATUS Status;
75 rc = RTProcWait(pid, 0, &Status);
76 if (RT_SUCCESS(rc))
77 {
78 if ( Status.iStatus == 0
79 && Status.enmReason == RTPROCEXITREASON_NORMAL)
80 return VINF_SUCCESS;
81 LogRel(("NetIfAdpCtl: failed to create process for %s: iStats=%d enmReason=%d\n",
82 szAdpCtl, Status.iStatus, Status.enmReason));
83 rc = -Status.iStatus;
84 }
85 }
86 else
87 LogRel(("NetIfAdpCtl: failed to create process for %s: %Rrc\n", szAdpCtl, rc));
88 return rc;
89}
90
91static int NetIfAdpCtl(HostNetworkInterface * pIf, const char *pszAddr, const char *pszOption, const char *pszMask)
92{
93 Bstr interfaceName;
94 pIf->COMGETTER(Name)(interfaceName.asOutParam());
95 Utf8Str strName(interfaceName);
96 return NetIfAdpCtl(strName.c_str(), pszAddr, pszOption, pszMask);
97}
98
99int NetIfAdpCtlOut(const char * pcszName, const char * pcszCmd, char *pszBuffer, size_t cBufSize)
100{
101 char szAdpCtl[RTPATH_MAX];
102 int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " ") - strlen(pcszCmd));
103 if (RT_FAILURE(rc))
104 {
105 LogRel(("NetIfAdpCtlOut: Failed to get program path, rc=%Rrc\n", rc));
106 return VERR_INVALID_PARAMETER;
107 }
108 strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME " ");
109 if (pcszName && strlen(pcszName) <= RTPATH_MAX - strlen(szAdpCtl) - 1 - strlen(pcszCmd))
110 {
111 strcat(szAdpCtl, pcszName);
112 strcat(szAdpCtl, " ");
113 strcat(szAdpCtl, pcszCmd);
114 }
115 else
116 {
117 LogRel(("NetIfAdpCtlOut: Command line is too long: %s%s %s\n", szAdpCtl, pcszName, pcszCmd));
118 return VERR_INVALID_PARAMETER;
119 }
120 if (strlen(szAdpCtl) < RTPATH_MAX - sizeof(" 2>&1"))
121 strcat(szAdpCtl, " 2>&1");
122 FILE *fp = popen(szAdpCtl, "r");
123 if (fp)
124 {
125 if (fgets(pszBuffer, (int)cBufSize, fp))
126 {
127 if (!strncmp(VBOXNETADPCTL_NAME ":", pszBuffer, sizeof(VBOXNETADPCTL_NAME)))
128 {
129 LogRel(("NetIfAdpCtlOut: %s", pszBuffer));
130 rc = VERR_INTERNAL_ERROR;
131 }
132 }
133 else
134 {
135 LogRel(("NetIfAdpCtlOut: No output from " VBOXNETADPCTL_NAME));
136 rc = VERR_INTERNAL_ERROR;
137 }
138 pclose(fp);
139 }
140 return rc;
141}
142
143int NetIfEnableStaticIpConfig(VirtualBox * /* vBox */, HostNetworkInterface * pIf, ULONG aOldIp, ULONG aNewIp, ULONG aMask)
144{
145 const char *pszOption, *pszMask;
146 char szAddress[16]; /* 4*3 + 3*1 + 1 */
147 char szNetMask[16]; /* 4*3 + 3*1 + 1 */
148 uint8_t *pu8Addr = (uint8_t *)&aNewIp;
149 uint8_t *pu8Mask = (uint8_t *)&aMask;
150 if (aNewIp == 0)
151 {
152 pu8Addr = (uint8_t *)&aOldIp;
153 pszOption = "remove";
154 pszMask = NULL;
155 }
156 else
157 {
158 pszOption = "netmask";
159 pszMask = szNetMask;
160 RTStrPrintf(szNetMask, sizeof(szNetMask), "%d.%d.%d.%d",
161 pu8Mask[0], pu8Mask[1], pu8Mask[2], pu8Mask[3]);
162 }
163 RTStrPrintf(szAddress, sizeof(szAddress), "%d.%d.%d.%d",
164 pu8Addr[0], pu8Addr[1], pu8Addr[2], pu8Addr[3]);
165 return NetIfAdpCtl(pIf, szAddress, pszOption, pszMask);
166}
167
168int NetIfEnableStaticIpConfigV6(VirtualBox * /* vBox */, HostNetworkInterface * pIf, const Utf8Str &aOldIPV6Address,
169 const Utf8Str &aIPV6Address, ULONG aIPV6MaskPrefixLength)
170{
171 char szAddress[5*8 + 1 + 5 + 1];
172 if (aIPV6Address.length())
173 {
174 RTStrPrintf(szAddress, sizeof(szAddress), "%s/%d",
175 aIPV6Address.c_str(), aIPV6MaskPrefixLength);
176 return NetIfAdpCtl(pIf, szAddress, NULL, NULL);
177 }
178 else
179 {
180 RTStrPrintf(szAddress, sizeof(szAddress), "%s",
181 aOldIPV6Address.c_str());
182 return NetIfAdpCtl(pIf, szAddress, "remove", NULL);
183 }
184}
185
186int NetIfEnableDynamicIpConfig(VirtualBox * /* vBox */, HostNetworkInterface * /* pIf */)
187{
188 return VERR_NOT_IMPLEMENTED;
189}
190
191
192int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVirtualBox,
193 IHostNetworkInterface **aHostNetworkInterface,
194 IProgress **aProgress,
195 const char *pcszName)
196{
197#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
198 /* create a progress object */
199 ComObjPtr<Progress> progress;
200 HRESULT hrc = progress.createObject();
201 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
202
203 /* Note vrc and hrc are competing about tracking the error state here. */
204 int vrc = VINF_SUCCESS;
205 ComPtr<IHost> host;
206 hrc = pVirtualBox->COMGETTER(Host)(host.asOutParam());
207 if (SUCCEEDED(hrc))
208 {
209 hrc = progress->init(pVirtualBox, host,
210 NetIfGeneric::tr("Creating host only network interface"),
211 FALSE /* aCancelable */);
212 if (SUCCEEDED(hrc))
213 {
214 progress.queryInterfaceTo(aProgress);
215
216 char szAdpCtl[RTPATH_MAX];
217 vrc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " add"));
218 if (RT_FAILURE(vrc))
219 {
220 progress->i_notifyComplete(E_FAIL,
221 COM_IIDOF(IHostNetworkInterface),
222 HostNetworkInterface::getStaticComponentName(),
223 NetIfGeneric::tr("Failed to get program path, vrc=%Rrc\n"), vrc);
224 return vrc;
225 }
226 strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME " ");
227 if (pcszName && strlen(pcszName) <= RTPATH_MAX - strlen(szAdpCtl) - sizeof(" add"))
228 {
229 strcat(szAdpCtl, pcszName);
230 strcat(szAdpCtl, " add");
231 }
232 else
233 strcat(szAdpCtl, "add");
234 if (strlen(szAdpCtl) < RTPATH_MAX - sizeof(" 2>&1"))
235 strcat(szAdpCtl, " 2>&1");
236
237 FILE *fp = popen(szAdpCtl, "r");
238 if (fp)
239 {
240 char szBuf[128]; /* We are not interested in long error messages. */
241 if (fgets(szBuf, sizeof(szBuf), fp))
242 {
243 /* Remove trailing new line characters. */
244 char *pLast = szBuf + strlen(szBuf) - 1;
245 if (pLast >= szBuf && *pLast == '\n')
246 *pLast = 0;
247
248 if (!strncmp(VBOXNETADPCTL_NAME ":", szBuf, sizeof(VBOXNETADPCTL_NAME)))
249 {
250 progress->i_notifyComplete(E_FAIL,
251 COM_IIDOF(IHostNetworkInterface),
252 HostNetworkInterface::getStaticComponentName(),
253 "%s", szBuf);
254 pclose(fp);
255 return Global::vboxStatusCodeFromCOM(E_FAIL);
256 }
257
258 size_t cbNameLen = strlen(szBuf) + 1;
259 PNETIFINFO pInfo = (PNETIFINFO)RTMemAllocZ(RT_UOFFSETOF_DYN(NETIFINFO, szName[cbNameLen]));
260 if (!pInfo)
261 vrc = VERR_NO_MEMORY;
262 else
263 {
264 strcpy(pInfo->szShortName, szBuf);
265 strcpy(pInfo->szName, szBuf);
266 vrc = NetIfGetConfigByName(pInfo);
267 if (RT_FAILURE(vrc))
268 {
269 progress->i_notifyComplete(E_FAIL,
270 COM_IIDOF(IHostNetworkInterface),
271 HostNetworkInterface::getStaticComponentName(),
272 NetIfGeneric::tr("Failed to get config info for %s (as reported by 'VBoxNetAdpCtl add')\n"),
273 szBuf);
274 }
275 else
276 {
277 Utf8Str IfName(szBuf);
278 /* create a new uninitialized host interface object */
279 ComObjPtr<HostNetworkInterface> iface;
280 iface.createObject();
281 iface->init(IfName, HostNetworkInterfaceType_HostOnly, pInfo);
282 iface->i_setVirtualBox(pVirtualBox);
283 iface.queryInterfaceTo(aHostNetworkInterface);
284 }
285 RTMemFree(pInfo);
286 }
287 if ((vrc = pclose(fp)) != 0)
288 {
289 progress->i_notifyComplete(E_FAIL,
290 COM_IIDOF(IHostNetworkInterface),
291 HostNetworkInterface::getStaticComponentName(),
292 NetIfGeneric::tr("Failed to execute '%s' - exit status: %d"), szAdpCtl, vrc);
293 vrc = VERR_INTERNAL_ERROR;
294 }
295 }
296 else
297 {
298 /* Failed to add an interface */
299 progress->i_notifyComplete(E_FAIL,
300 COM_IIDOF(IHostNetworkInterface),
301 HostNetworkInterface::getStaticComponentName(),
302 NetIfGeneric::tr("Failed to execute '%s' (errno %d). Check permissions!"),
303 szAdpCtl, errno);
304 pclose(fp);
305 vrc = VERR_PERMISSION_DENIED;
306 }
307 }
308 else
309 {
310 vrc = RTErrConvertFromErrno(errno);
311 progress->i_notifyComplete(E_FAIL,
312 COM_IIDOF(IHostNetworkInterface),
313 HostNetworkInterface::getStaticComponentName(),
314 NetIfGeneric::tr("Failed to execute '%s' (errno %d / %Rrc). Check permissions!"),
315 szAdpCtl, errno, vrc);
316 }
317 if (RT_SUCCESS(vrc))
318 progress->i_notifyComplete(S_OK);
319 else
320 hrc = E_FAIL;
321 }
322 }
323
324 return RT_FAILURE(vrc) ? vrc : SUCCEEDED(hrc) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc);
325
326#else
327 NOREF(pVirtualBox);
328 NOREF(aHostNetworkInterface);
329 NOREF(aProgress);
330 NOREF(pcszName);
331 return VERR_NOT_IMPLEMENTED;
332#endif
333}
334
335int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVirtualBox, const Guid &aId,
336 IProgress **aProgress)
337{
338#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
339 /* create a progress object */
340 ComObjPtr<Progress> progress;
341 HRESULT hrc = progress.createObject();
342 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
343
344 ComPtr<IHost> host;
345 int vrc = VINF_SUCCESS;
346 hrc = pVirtualBox->COMGETTER(Host)(host.asOutParam());
347 if (SUCCEEDED(hrc))
348 {
349 ComPtr<IHostNetworkInterface> iface;
350 if (FAILED(host->FindHostNetworkInterfaceById(aId.toUtf16().raw(), iface.asOutParam())))
351 return VERR_INVALID_PARAMETER;
352
353 Bstr ifname;
354 iface->COMGETTER(Name)(ifname.asOutParam());
355 if (ifname.isEmpty())
356 return VERR_INTERNAL_ERROR;
357 Utf8Str strIfName(ifname);
358
359 hrc = progress->init(pVirtualBox, host, NetIfGeneric::tr("Removing host network interface"), FALSE /* aCancelable */);
360 if (SUCCEEDED(hrc))
361 {
362 progress.queryInterfaceTo(aProgress);
363 vrc = NetIfAdpCtl(strIfName.c_str(), "remove", NULL, NULL);
364 if (RT_FAILURE(vrc))
365 progress->i_notifyComplete(E_FAIL,
366 COM_IIDOF(IHostNetworkInterface),
367 HostNetworkInterface::getStaticComponentName(),
368 NetIfGeneric::tr("Failed to execute 'VBoxNetAdpCtl %s remove' (%Rrc)"),
369 strIfName.c_str(), vrc);
370 else
371 progress->i_notifyComplete(S_OK);
372 }
373 else
374 vrc = Global::vboxStatusCodeFromCOM(hrc);
375 }
376 else
377 vrc = Global::vboxStatusCodeFromCOM(hrc);
378 return vrc;
379#else
380 NOREF(pVirtualBox);
381 NOREF(aId);
382 NOREF(aProgress);
383 return VERR_NOT_IMPLEMENTED;
384#endif
385}
386
387int NetIfGetConfig(HostNetworkInterface * /* pIf */, NETIFINFO *)
388{
389 return VERR_NOT_IMPLEMENTED;
390}
391
392int NetIfDhcpRediscover(VirtualBox * /* pVBox */, HostNetworkInterface * /* pIf */)
393{
394 return VERR_NOT_IMPLEMENTED;
395}
396
397/**
398 * Obtain the current state of the interface.
399 *
400 * @returns VBox status code.
401 *
402 * @param pcszIfName Interface name.
403 * @param penmState Where to store the retrieved state.
404 */
405int NetIfGetState(const char *pcszIfName, NETIFSTATUS *penmState)
406{
407 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
408 if (sock < 0)
409 return VERR_OUT_OF_RESOURCES;
410 struct ifreq Req;
411 RT_ZERO(Req);
412 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
413 if (ioctl(sock, SIOCGIFFLAGS, &Req) < 0)
414 {
415 Log(("NetIfGetState: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
416 *penmState = NETIF_S_UNKNOWN;
417 }
418 else
419 *penmState = (Req.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
420 close(sock);
421 return VINF_SUCCESS;
422}
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