VirtualBox

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

Last change on this file since 45869 was 45367, checked in by vboxsync, 12 years ago

Main: a couple of whitespace fixes

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