VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp@ 36986

Last change on this file since 36986 was 35693, checked in by vboxsync, 14 years ago

Main/NetIf: Third attempt to fix VBoxSVC crash when listing host interfaces with no default route (#5491)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1/* $Id: NetIf-darwin.cpp 35693 2011-01-24 17:27:05Z vboxsync $ */
2/** @file
3 * Main - NetIfList, Darwin implementation.
4 */
5
6/*
7 * Copyright (C) 2008 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/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23/*
24 * Deal with conflicts first.
25 * PVM - BSD mess, that FreeBSD has correct a long time ago.
26 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
27 */
28#include <iprt/types.h>
29#include <sys/param.h>
30#undef PVM
31
32#define LOG_GROUP LOG_GROUP_MAIN
33
34#include <iprt/err.h>
35#include <iprt/alloc.h>
36
37#include <string.h>
38#include <sys/socket.h>
39#include <sys/ioctl.h>
40#include <sys/sysctl.h>
41#include <netinet/in.h>
42#include <net/if.h>
43#include <net/if_dl.h>
44#include <net/if_types.h>
45#include <net/route.h>
46#include <ifaddrs.h>
47#include <errno.h>
48#include <unistd.h>
49#include <list>
50
51#include "HostNetworkInterfaceImpl.h"
52#include "netif.h"
53#include "iokit.h"
54#include "Logging.h"
55
56#if 0
57int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
58{
59 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
60 if (sock < 0)
61 {
62 Log(("NetIfList: socket() -> %d\n", errno));
63 return NULL;
64 }
65 struct ifaddrs *IfAddrs, *pAddr;
66 int rc = getifaddrs(&IfAddrs);
67 if (rc)
68 {
69 close(sock);
70 Log(("NetIfList: getifaddrs() -> %d\n", rc));
71 return VERR_INTERNAL_ERROR;
72 }
73
74 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
75 while (pEtherNICs)
76 {
77 size_t cbNameLen = strlen(pEtherNICs->szName) + 1;
78 PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
79 pNew->MACAddress = pEtherNICs->Mac;
80 pNew->enmMediumType = NETIF_T_ETHERNET;
81 pNew->Uuid = pEtherNICs->Uuid;
82 Assert(sizeof(pNew->szShortName) > sizeof(pEtherNICs->szBSDName));
83 memcpy(pNew->szShortName, pEtherNICs->szBSDName, sizeof(pEtherNICs->szBSDName));
84 pNew->szShortName[sizeof(pEtherNICs->szBSDName)] = '\0';
85 memcpy(pNew->szName, pEtherNICs->szName, cbNameLen);
86
87 struct ifreq IfReq;
88 strcpy(IfReq.ifr_name, pNew->szShortName);
89 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
90 {
91 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
92 pNew->enmStatus = NETIF_S_UNKNOWN;
93 }
94 else
95 pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
96
97 for (pAddr = IfAddrs; pAddr != NULL; pAddr = pAddr->ifa_next)
98 {
99 if (strcmp(pNew->szShortName, pAddr->ifa_name))
100 continue;
101
102 struct sockaddr_in *pIPAddr, *pIPNetMask;
103 struct sockaddr_in6 *pIPv6Addr, *pIPv6NetMask;
104
105 switch (pAddr->ifa_addr->sa_family)
106 {
107 case AF_INET:
108 if (pNew->IPAddress.u)
109 break;
110 pIPAddr = (struct sockaddr_in *)pAddr->ifa_addr;
111 Assert(sizeof(pNew->IPAddress) == sizeof(pIPAddr->sin_addr));
112 pNew->IPAddress.u = pIPAddr->sin_addr.s_addr;
113 pIPNetMask = (struct sockaddr_in *)pAddr->ifa_netmask;
114 Assert(pIPNetMask->sin_family == AF_INET);
115 Assert(sizeof(pNew->IPNetMask) == sizeof(pIPNetMask->sin_addr));
116 pNew->IPNetMask.u = pIPNetMask->sin_addr.s_addr;
117 break;
118 case AF_INET6:
119 if (pNew->IPv6Address.s.Lo || pNew->IPv6Address.s.Hi)
120 break;
121 pIPv6Addr = (struct sockaddr_in6 *)pAddr->ifa_addr;
122 Assert(sizeof(pNew->IPv6Address) == sizeof(pIPv6Addr->sin6_addr));
123 memcpy(pNew->IPv6Address.au8,
124 pIPv6Addr->sin6_addr.__u6_addr.__u6_addr8,
125 sizeof(pNew->IPv6Address));
126 pIPv6NetMask = (struct sockaddr_in6 *)pAddr->ifa_netmask;
127 Assert(pIPv6NetMask->sin6_family == AF_INET6);
128 Assert(sizeof(pNew->IPv6NetMask) == sizeof(pIPv6NetMask->sin6_addr));
129 memcpy(pNew->IPv6NetMask.au8,
130 pIPv6NetMask->sin6_addr.__u6_addr.__u6_addr8,
131 sizeof(pNew->IPv6NetMask));
132 break;
133 }
134 }
135
136 ComObjPtr<HostNetworkInterface> IfObj;
137 IfObj.createObject();
138 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), HostNetworkInterfaceType_Bridged, pNew)))
139 list.push_back(IfObj);
140 RTMemFree(pNew);
141
142 /* next, free current */
143 void *pvFree = pEtherNICs;
144 pEtherNICs = pEtherNICs->pNext;
145 RTMemFree(pvFree);
146 }
147
148 freeifaddrs(IfAddrs);
149 close(sock);
150 return VINF_SUCCESS;
151}
152#else
153
154#define ROUNDUP(a) \
155 (((a) & (sizeof(u_long) - 1)) ? (1 + ((a) | (sizeof(u_long) - 1))) : (a))
156#define ADVANCE(x, n) (x += (n)->sa_len ? ROUNDUP((n)->sa_len) : sizeof(u_long))
157
158void extractAddresses(int iAddrMask, caddr_t cp, caddr_t cplim, struct sockaddr **pAddresses)
159{
160 struct sockaddr *sa;
161
162 for (int i = 0; i < RTAX_MAX && cp < cplim; i++) {
163 if (iAddrMask & (1 << i))
164 {
165 sa = (struct sockaddr *)cp;
166
167 pAddresses[i] = sa;
168
169 ADVANCE(cp, sa);
170 }
171 else
172 pAddresses[i] = NULL;
173 }
174}
175
176void extractAddressesToNetInfo(int iAddrMask, caddr_t cp, caddr_t cplim, PNETIFINFO pInfo)
177{
178 struct sockaddr *addresses[RTAX_MAX];
179
180 extractAddresses(iAddrMask, cp, cplim, addresses);
181 switch (addresses[RTAX_IFA]->sa_family)
182 {
183 case AF_INET:
184 if (!pInfo->IPAddress.u)
185 {
186 pInfo->IPAddress.u = ((struct sockaddr_in *)addresses[RTAX_IFA])->sin_addr.s_addr;
187 pInfo->IPNetMask.u = ((struct sockaddr_in *)addresses[RTAX_NETMASK])->sin_addr.s_addr;
188 }
189 break;
190 case AF_INET6:
191 if (!pInfo->IPv6Address.s.Lo && !pInfo->IPv6Address.s.Hi)
192 {
193 memcpy(pInfo->IPv6Address.au8,
194 ((struct sockaddr_in6 *)addresses[RTAX_IFA])->sin6_addr.__u6_addr.__u6_addr8,
195 sizeof(pInfo->IPv6Address));
196 memcpy(pInfo->IPv6NetMask.au8,
197 ((struct sockaddr_in6 *)addresses[RTAX_NETMASK])->sin6_addr.__u6_addr.__u6_addr8,
198 sizeof(pInfo->IPv6NetMask));
199 }
200 break;
201 default:
202 Log(("NetIfList: Unsupported address family: %u\n", addresses[RTAX_IFA]->sa_family));
203 break;
204 }
205}
206
207static int getDefaultIfaceIndex(unsigned short *pu16Index)
208{
209 size_t cbNeeded;
210 char *pBuf, *pNext;
211 int aiMib[6];
212 struct sockaddr *addresses[RTAX_MAX];
213
214 aiMib[0] = CTL_NET;
215 aiMib[1] = PF_ROUTE;
216 aiMib[2] = 0;
217 aiMib[3] = PF_INET; /* address family */
218 aiMib[4] = NET_RT_DUMP;
219 aiMib[5] = 0;
220
221 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
222 {
223 Log(("getDefaultIfaceIndex: Failed to get estimate for list size (errno=%d).\n", errno));
224 return RTErrConvertFromErrno(errno);
225 }
226 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
227 return VERR_NO_MEMORY;
228 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
229 {
230 free(pBuf);
231 Log(("getDefaultIfaceIndex: Failed to retrieve interface table (errno=%d).\n", errno));
232 return RTErrConvertFromErrno(errno);
233 }
234
235 char *pEnd = pBuf + cbNeeded;
236 struct rt_msghdr *pRtMsg;
237 for (pNext = pBuf; pNext < pEnd; pNext += pRtMsg->rtm_msglen)
238 {
239 pRtMsg = (struct rt_msghdr *)pNext;
240
241 if (pRtMsg->rtm_type != RTM_GET)
242 {
243 Log(("getDefaultIfaceIndex: Got message %u while expecting %u.\n",
244 pRtMsg->rtm_type, RTM_GET));
245 //rc = VERR_INTERNAL_ERROR;
246 continue;
247 }
248 if ((char*)(pRtMsg + 1) < pEnd)
249 {
250 /* Extract addresses from the message. */
251 extractAddresses(pRtMsg->rtm_addrs, (char *)(pRtMsg + 1),
252 pRtMsg->rtm_msglen + 1 + (char *)pRtMsg, addresses);
253 if ((pRtMsg->rtm_addrs & RTA_DST)
254 && (pRtMsg->rtm_addrs & RTA_NETMASK))
255 {
256 if (addresses[RTAX_DST]->sa_family != AF_INET)
257 continue;
258 struct sockaddr_in *addr = (struct sockaddr_in *)addresses[RTAX_DST];
259 struct sockaddr_in *mask = (struct sockaddr_in *)addresses[RTAX_NETMASK];
260 if ((addr->sin_addr.s_addr == INADDR_ANY) &&
261 mask &&
262 (ntohl(mask->sin_addr.s_addr) == 0L ||
263 mask->sin_len == 0))
264 {
265 *pu16Index = pRtMsg->rtm_index;
266 free(pBuf);
267 return VINF_SUCCESS;
268 }
269 }
270 }
271 }
272 free(pBuf);
273 return 0; /* Failed to find default interface, take the first one in the list. */
274}
275
276int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
277{
278 int rc = VINF_SUCCESS;
279 size_t cbNeeded;
280 char *pBuf, *pNext;
281 int aiMib[6];
282 unsigned short u16DefaultIface = 0; /* initialized to shut up gcc */
283
284 /* Get the index of the interface associated with default route. */
285 rc = getDefaultIfaceIndex(&u16DefaultIface);
286 if (RT_FAILURE(rc))
287 return rc;
288
289 aiMib[0] = CTL_NET;
290 aiMib[1] = PF_ROUTE;
291 aiMib[2] = 0;
292 aiMib[3] = 0; /* address family */
293 aiMib[4] = NET_RT_IFLIST;
294 aiMib[5] = 0;
295
296 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
297 {
298 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
299 return RTErrConvertFromErrno(errno);
300 }
301 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
302 return VERR_NO_MEMORY;
303 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
304 {
305 free(pBuf);
306 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
307 return RTErrConvertFromErrno(errno);
308 }
309
310 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
311 if (sock < 0)
312 {
313 free(pBuf);
314 Log(("NetIfList: socket() -> %d\n", errno));
315 return RTErrConvertFromErrno(errno);
316 }
317
318 PDARWINETHERNIC pNIC;
319 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
320
321 char *pEnd = pBuf + cbNeeded;
322 for (pNext = pBuf; pNext < pEnd;)
323 {
324 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
325
326 if (pIfMsg->ifm_type != RTM_IFINFO)
327 {
328 Log(("NetIfList: Got message %u while expecting %u.\n",
329 pIfMsg->ifm_type, RTM_IFINFO));
330 rc = VERR_INTERNAL_ERROR;
331 break;
332 }
333 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
334
335 size_t cbNameLen = pSdl->sdl_nlen + 1;
336 Assert(pSdl->sdl_nlen < sizeof(pNIC->szBSDName));
337 for (pNIC = pEtherNICs; pNIC; pNIC = pNIC->pNext)
338 if ( !strncmp(pSdl->sdl_data, pNIC->szBSDName, pSdl->sdl_nlen)
339 && pNIC->szBSDName[pSdl->sdl_nlen] == '\0')
340 {
341 cbNameLen = strlen(pNIC->szName) + 1;
342 break;
343 }
344 PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
345 if (!pNew)
346 {
347 rc = VERR_NO_MEMORY;
348 break;
349 }
350 memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8));
351 pNew->enmMediumType = NETIF_T_ETHERNET;
352 Assert(sizeof(pNew->szShortName) > pSdl->sdl_nlen);
353 memcpy(pNew->szShortName, pSdl->sdl_data, RT_MIN(pSdl->sdl_nlen, sizeof(pNew->szShortName) - 1));
354
355 /*
356 * If we found the adapter in the list returned by
357 * DarwinGetEthernetControllers() copy the name and UUID from there.
358 */
359 if (pNIC)
360 {
361 memcpy(pNew->szName, pNIC->szName, cbNameLen);
362 pNew->Uuid = pNIC->Uuid;
363 }
364 else
365 {
366 memcpy(pNew->szName, pSdl->sdl_data, pSdl->sdl_nlen);
367 /* Generate UUID from name and MAC address. */
368 RTUUID uuid;
369 RTUuidClear(&uuid);
370 memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
371 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
372 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
373 memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node));
374 pNew->Uuid = uuid;
375 }
376
377 pNext += pIfMsg->ifm_msglen;
378 while (pNext < pEnd)
379 {
380 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
381
382 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
383 break;
384 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
385 (char *)(pIfAddrMsg + 1),
386 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
387 pNew);
388 pNext += pIfAddrMsg->ifam_msglen;
389 }
390
391 if (pSdl->sdl_type == IFT_ETHER)
392 {
393 struct ifreq IfReq;
394 strcpy(IfReq.ifr_name, pNew->szShortName);
395 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
396 {
397 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
398 pNew->enmStatus = NETIF_S_UNKNOWN;
399 }
400 else
401 pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
402
403 HostNetworkInterfaceType_T enmType;
404 if (strncmp("vboxnet", pNew->szName, 7))
405 enmType = HostNetworkInterfaceType_Bridged;
406 else
407 enmType = HostNetworkInterfaceType_HostOnly;
408
409 ComObjPtr<HostNetworkInterface> IfObj;
410 IfObj.createObject();
411 if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew)))
412 /* Make sure the default interface gets to the beginning. */
413 if (pIfMsg->ifm_index == u16DefaultIface)
414 list.push_front(IfObj);
415 else
416 list.push_back(IfObj);
417 }
418 RTMemFree(pNew);
419 }
420 for (pNIC = pEtherNICs; pNIC;)
421 {
422 void *pvFree = pNIC;
423 pNIC = pNIC->pNext;
424 RTMemFree(pvFree);
425 }
426 close(sock);
427 free(pBuf);
428 return rc;
429}
430
431int NetIfGetConfigByName(PNETIFINFO pInfo)
432{
433 int rc = VINF_SUCCESS;
434 size_t cbNeeded;
435 char *pBuf, *pNext;
436 int aiMib[6];
437
438 aiMib[0] = CTL_NET;
439 aiMib[1] = PF_ROUTE;
440 aiMib[2] = 0;
441 aiMib[3] = 0; /* address family */
442 aiMib[4] = NET_RT_IFLIST;
443 aiMib[5] = 0;
444
445 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
446 {
447 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
448 return RTErrConvertFromErrno(errno);
449 }
450 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
451 return VERR_NO_MEMORY;
452 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
453 {
454 free(pBuf);
455 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
456 return RTErrConvertFromErrno(errno);
457 }
458
459 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
460 if (sock < 0)
461 {
462 free(pBuf);
463 Log(("NetIfList: socket() -> %d\n", errno));
464 return RTErrConvertFromErrno(errno);
465 }
466
467 char *pEnd = pBuf + cbNeeded;
468 for (pNext = pBuf; pNext < pEnd;)
469 {
470 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
471
472 if (pIfMsg->ifm_type != RTM_IFINFO)
473 {
474 Log(("NetIfList: Got message %u while expecting %u.\n",
475 pIfMsg->ifm_type, RTM_IFINFO));
476 rc = VERR_INTERNAL_ERROR;
477 break;
478 }
479 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
480
481 bool fSkip = !!strncmp(pInfo->szShortName, pSdl->sdl_data, pSdl->sdl_nlen)
482 || pInfo->szShortName[pSdl->sdl_nlen] != '\0';
483
484 pNext += pIfMsg->ifm_msglen;
485 while (pNext < pEnd)
486 {
487 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
488
489 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
490 break;
491 if (!fSkip)
492 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
493 (char *)(pIfAddrMsg + 1),
494 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
495 pInfo);
496 pNext += pIfAddrMsg->ifam_msglen;
497 }
498
499 if (!fSkip && pSdl->sdl_type == IFT_ETHER)
500 {
501 size_t cbNameLen = pSdl->sdl_nlen + 1;
502 memcpy(pInfo->MACAddress.au8, LLADDR(pSdl), sizeof(pInfo->MACAddress.au8));
503 pInfo->enmMediumType = NETIF_T_ETHERNET;
504 /* Generate UUID from name and MAC address. */
505 RTUUID uuid;
506 RTUuidClear(&uuid);
507 memcpy(&uuid, pInfo->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
508 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
509 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
510 memcpy(uuid.Gen.au8Node, pInfo->MACAddress.au8, sizeof(uuid.Gen.au8Node));
511 pInfo->Uuid = uuid;
512
513 struct ifreq IfReq;
514 strcpy(IfReq.ifr_name, pInfo->szShortName);
515 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
516 {
517 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
518 pInfo->enmStatus = NETIF_S_UNKNOWN;
519 }
520 else
521 pInfo->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
522
523 return VINF_SUCCESS;
524 }
525 }
526 close(sock);
527 free(pBuf);
528 return rc;
529}
530
531#endif
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