/** @copydoc VBOXSERVICE::pfnPreInit */ static DECLCALLBACK(int) VBoxServiceTimeSyncPreInit(void) { #ifdef VBOX_WITH_GUEST_PROPS /** @todo Merge this function with VBoxServiceTimeSyncOption() to generalize * the "command line args override guest property values" behavior. */ /* * Read the service options from the VM's guest properties. * Note that these options can be overridden by the command line options later. */ uint32_t uGuestPropSvcClientID; int rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID); if (RT_FAILURE(rc)) { if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */ { VBoxServiceVerbose(0, "VMInfo: Guest property service is not available, skipping\n"); rc = VINF_SUCCESS; } else VBoxServiceError("Failed to connect to the guest property service! Error: %Rrc\n", rc); } else { rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-interval", &g_TimeSyncInterval, 50, UINT32_MAX - 1); if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-min-adjust", &g_TimeSyncMinAdjust, 0, 3600000); } if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-latency-factor", &g_TimeSyncLatencyFactor, 1, 1024); } if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-max-latency", &g_TimeSyncMaxLatency, 1, 3600000); } if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", &g_TimeSyncSetThreshold, 0, 7*24*60*60*1000 /* a week */); } if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { char *pszValue; rc = VBoxServiceReadProp(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-start", &pszValue, NULL /* ppszFlags */, NULL /* puTimestamp */); if (RT_SUCCESS(rc)) { g_fTimeSyncSetNext = true; RTStrFree(pszValue); } } if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { uint32_t value; rc = VBoxServiceReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-on-restore", &value, 1, 1); if (RT_SUCCESS(rc)) g_fTimeSyncSetOnRestore = !!value; } VbglR3GuestPropDisconnect(uGuestPropSvcClientID); } if (rc == VERR_NOT_FOUND) /* If a value is not found, don't be sad! */ rc = VINF_SUCCESS; return rc; #else /* Nothing to do here yet. */ return VINF_SUCCESS; #endif }
/** * Provide information about the guest network. */ static int vboxserviceVMInfoWriteNetwork(void) { int rc = VINF_SUCCESS; uint32_t cIfacesReport = 0; char szPropPath[256]; #ifdef RT_OS_WINDOWS IP_ADAPTER_INFO *pAdpInfo = NULL; # ifndef TARGET_NT4 ULONG cbAdpInfo = sizeof(*pAdpInfo); pAdpInfo = (IP_ADAPTER_INFO *)RTMemAlloc(cbAdpInfo); if (!pAdpInfo) { VBoxServiceError("VMInfo/Network: Failed to allocate IP_ADAPTER_INFO\n"); return VERR_NO_MEMORY; } DWORD dwRet = GetAdaptersInfo(pAdpInfo, &cbAdpInfo); if (dwRet == ERROR_BUFFER_OVERFLOW) { IP_ADAPTER_INFO *pAdpInfoNew = (IP_ADAPTER_INFO*)RTMemRealloc(pAdpInfo, cbAdpInfo); if (pAdpInfoNew) { pAdpInfo = pAdpInfoNew; dwRet = GetAdaptersInfo(pAdpInfo, &cbAdpInfo); } } else if (dwRet == ERROR_NO_DATA) { VBoxServiceVerbose(3, "VMInfo/Network: No network adapters available\n"); /* If no network adapters available / present in the * system we pretend success to not bail out too early. */ dwRet = ERROR_SUCCESS; } if (dwRet != ERROR_SUCCESS) { if (pAdpInfo) RTMemFree(pAdpInfo); VBoxServiceError("VMInfo/Network: Failed to get adapter info: Error %d\n", dwRet); return RTErrConvertFromWin32(dwRet); } # endif /* !TARGET_NT4 */ SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); if (sd == SOCKET_ERROR) /* Socket invalid. */ { int wsaErr = WSAGetLastError(); /* Don't complain/bail out with an error if network stack is not up; can happen * on NT4 due to start up when not connected shares dialogs pop up. */ if (WSAENETDOWN == wsaErr) { VBoxServiceVerbose(0, "VMInfo/Network: Network is not up yet.\n"); wsaErr = VINF_SUCCESS; } else VBoxServiceError("VMInfo/Network: Failed to get a socket: Error %d\n", wsaErr); if (pAdpInfo) RTMemFree(pAdpInfo); return RTErrConvertFromWin32(wsaErr); } INTERFACE_INFO InterfaceList[20] = {0}; unsigned long nBytesReturned = 0; if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { VBoxServiceError("VMInfo/Network: Failed to WSAIoctl() on socket: Error: %d\n", WSAGetLastError()); if (pAdpInfo) RTMemFree(pAdpInfo); return RTErrConvertFromWin32(WSAGetLastError()); } int cIfacesSystem = nBytesReturned / sizeof(INTERFACE_INFO); /** @todo Use GetAdaptersInfo() and GetAdapterAddresses (IPv4 + IPv6) for more information. */ for (int i = 0; i < cIfacesSystem; ++i) { sockaddr_in *pAddress; u_long nFlags = 0; if (InterfaceList[i].iiFlags & IFF_LOOPBACK) /* Skip loopback device. */ continue; nFlags = InterfaceList[i].iiFlags; pAddress = (sockaddr_in *)&(InterfaceList[i].iiAddress); Assert(pAddress); char szIp[32]; RTStrPrintf(szIp, sizeof(szIp), "%s", inet_ntoa(pAddress->sin_addr)); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/IP", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szIp); pAddress = (sockaddr_in *) & (InterfaceList[i].iiBroadcastAddress); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Broadcast", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr)); pAddress = (sockaddr_in *)&(InterfaceList[i].iiNetmask); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Netmask", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr)); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/Status", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, nFlags & IFF_UP ? "Up" : "Down"); # ifndef TARGET_NT4 IP_ADAPTER_INFO *pAdp; for (pAdp = pAdpInfo; pAdp; pAdp = pAdp->Next) if (!strcmp(pAdp->IpAddressList.IpAddress.String, szIp)) break; RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/MAC", cIfacesReport); if (pAdp) { char szMac[32]; RTStrPrintf(szMac, sizeof(szMac), "%02X%02X%02X%02X%02X%02X", pAdp->Address[0], pAdp->Address[1], pAdp->Address[2], pAdp->Address[3], pAdp->Address[4], pAdp->Address[5]); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szMac); } else VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, NULL); # endif /* !TARGET_NT4 */ cIfacesReport++; } if (pAdpInfo) RTMemFree(pAdpInfo); if (sd >= 0) closesocket(sd); #elif defined(RT_OS_FREEBSD) struct ifaddrs *pIfHead = NULL; /* Get all available interfaces */ rc = getifaddrs(&pIfHead); if (rc < 0) { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to get all interfaces: Error %Rrc\n"); return rc; } /* Loop through all interfaces and set the data. */ for (struct ifaddrs *pIfCurr = pIfHead; pIfCurr; pIfCurr = pIfCurr->ifa_next) { /* * Only AF_INET and no loopback interfaces * @todo: IPv6 interfaces */ if ( pIfCurr->ifa_addr->sa_family == AF_INET && !(pIfCurr->ifa_flags & IFF_LOOPBACK)) { char szInetAddr[NI_MAXHOST]; memset(szInetAddr, 0, NI_MAXHOST); getnameinfo(pIfCurr->ifa_addr, sizeof(struct sockaddr_in), szInetAddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/IP", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szInetAddr); memset(szInetAddr, 0, NI_MAXHOST); getnameinfo(pIfCurr->ifa_broadaddr, sizeof(struct sockaddr_in), szInetAddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Broadcast", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szInetAddr); memset(szInetAddr, 0, NI_MAXHOST); getnameinfo(pIfCurr->ifa_netmask, sizeof(struct sockaddr_in), szInetAddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Netmask", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szInetAddr); /* Search for the AF_LINK interface of the current AF_INET one and get the mac. */ for (struct ifaddrs *pIfLinkCurr = pIfHead; pIfLinkCurr; pIfLinkCurr = pIfLinkCurr->ifa_next) { if ( pIfLinkCurr->ifa_addr->sa_family == AF_LINK && !strcmp(pIfCurr->ifa_name, pIfLinkCurr->ifa_name)) { char szMac[32]; uint8_t *pu8Mac = NULL; struct sockaddr_dl *pLinkAddress = (struct sockaddr_dl *)pIfLinkCurr->ifa_addr; AssertPtr(pLinkAddress); pu8Mac = (uint8_t *)LLADDR(pLinkAddress); RTStrPrintf(szMac, sizeof(szMac), "%02X%02X%02X%02X%02X%02X", pu8Mac[0], pu8Mac[1], pu8Mac[2], pu8Mac[3], pu8Mac[4], pu8Mac[5]); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/MAC", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szMac); break; } } RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/Status", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, pIfCurr->ifa_flags & IFF_UP ? "Up" : "Down"); cIfacesReport++; } } /* Free allocated resources. */ freeifaddrs(pIfHead); #else /* !RT_OS_WINDOWS && !RT_OS_FREEBSD */ int sd = socket(AF_INET, SOCK_DGRAM, 0); if (sd < 0) { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to get a socket: Error %Rrc\n", rc); return rc; } ifconf ifcfg; char buffer[1024] = {0}; ifcfg.ifc_len = sizeof(buffer); ifcfg.ifc_buf = buffer; if (ioctl(sd, SIOCGIFCONF, &ifcfg) < 0) { close(sd); rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to ioctl(SIOCGIFCONF) on socket: Error %Rrc\n", rc); return rc; } ifreq* ifrequest = ifcfg.ifc_req; int cIfacesSystem = ifcfg.ifc_len / sizeof(ifreq); for (int i = 0; i < cIfacesSystem; ++i) { sockaddr_in *pAddress; if (ioctl(sd, SIOCGIFFLAGS, &ifrequest[i]) < 0) { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to ioctl(SIOCGIFFLAGS) on socket: Error %Rrc\n", rc); break; } if (ifrequest[i].ifr_flags & IFF_LOOPBACK) /* Skip the loopback device. */ continue; bool fIfUp = !!(ifrequest[i].ifr_flags & IFF_UP); pAddress = ((sockaddr_in *)&ifrequest[i].ifr_addr); Assert(pAddress); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/IP", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr)); if (ioctl(sd, SIOCGIFBRDADDR, &ifrequest[i]) < 0) { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to ioctl(SIOCGIFBRDADDR) on socket: Error %Rrc\n", rc); break; } pAddress = (sockaddr_in *)&ifrequest[i].ifr_broadaddr; RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Broadcast", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr)); if (ioctl(sd, SIOCGIFNETMASK, &ifrequest[i]) < 0) { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to ioctl(SIOCGIFNETMASK) on socket: Error %Rrc\n", rc); break; } # if defined(RT_OS_OS2) || defined(RT_OS_SOLARIS) pAddress = (sockaddr_in *)&ifrequest[i].ifr_addr; # else pAddress = (sockaddr_in *)&ifrequest[i].ifr_netmask; # endif RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/V4/Netmask", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr)); # if defined(RT_OS_SOLARIS) /* * "ifreq" is obsolete on Solaris. We use the recommended "lifreq". * We might fail if the interface has not been assigned an IP address. * That doesn't matter; as long as it's plumbed we can pick it up. * But, if it has not acquired an IP address we cannot obtain it's MAC * address this way, so we just use all zeros there. */ RTMAC IfMac; RT_ZERO(IfMac); struct lifreq IfReq; RT_ZERO(IfReq); AssertCompile(sizeof(IfReq.lifr_name) >= sizeof(ifrequest[i].ifr_name)); strncpy(IfReq.lifr_name, ifrequest[i].ifr_name, sizeof(ifrequest[i].ifr_name)); if (ioctl(sd, SIOCGLIFADDR, &IfReq) >= 0) { struct arpreq ArpReq; RT_ZERO(ArpReq); memcpy(&ArpReq.arp_pa, &IfReq.lifr_addr, sizeof(struct sockaddr_in)); if (ioctl(sd, SIOCGARP, &ArpReq) >= 0) memcpy(&IfMac, ArpReq.arp_ha.sa_data, sizeof(IfMac)); else { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: failed to ioctl(SIOCGARP) on socket: Error %Rrc\n", rc); break; } } else { VBoxServiceVerbose(2, "VMInfo/Network: Interface %d has no assigned IP address, skipping ...\n", i); continue; } # else # ifndef RT_OS_OS2 /** @todo port this to OS/2 */ if (ioctl(sd, SIOCGIFHWADDR, &ifrequest[i]) < 0) { rc = RTErrConvertFromErrno(errno); VBoxServiceError("VMInfo/Network: Failed to ioctl(SIOCGIFHWADDR) on socket: Error %Rrc\n", rc); break; } # endif # endif # ifndef RT_OS_OS2 /** @todo port this to OS/2 */ char szMac[32]; # if defined(RT_OS_SOLARIS) uint8_t *pu8Mac = IfMac.au8; # else uint8_t *pu8Mac = (uint8_t*)&ifrequest[i].ifr_hwaddr.sa_data[0]; /* @todo see above */ # endif RTStrPrintf(szMac, sizeof(szMac), "%02X%02X%02X%02X%02X%02X", pu8Mac[0], pu8Mac[1], pu8Mac[2], pu8Mac[3], pu8Mac[4], pu8Mac[5]); RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/MAC", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szMac); # endif /* !OS/2*/ RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%u/Status", cIfacesReport); VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, fIfUp ? "Up" : "Down"); cIfacesReport++; } /* For all interfaces */ close(sd); if (RT_FAILURE(rc)) VBoxServiceError("VMInfo/Network: Network enumeration for interface %u failed with error %Rrc\n", cIfacesReport, rc); #endif /* !RT_OS_WINDOWS */ #if 0 /* Zapping not enabled yet, needs more testing first. */ /* * Zap all stale network interface data if the former (saved) network ifaces count * is bigger than the current one. */ /* Get former count. */ uint32_t cIfacesReportOld; rc = VBoxServiceReadPropUInt32(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/Net/Count", &cIfacesReportOld, 0 /* Min */, UINT32_MAX /* Max */); if ( RT_SUCCESS(rc) && cIfacesReportOld > cIfacesReport) /* Are some ifaces not around anymore? */ { VBoxServiceVerbose(3, "VMInfo/Network: Stale interface data detected (%u old vs. %u current)\n", cIfacesReportOld, cIfacesReport); uint32_t uIfaceDeleteIdx = cIfacesReport; do { VBoxServiceVerbose(3, "VMInfo/Network: Deleting stale data of interface %d ...\n", uIfaceDeleteIdx); rc = VBoxServicePropCacheUpdateByPath(&g_VMInfoPropCache, NULL /* Value, delete */, 0 /* Flags */, "/VirtualBox/GuestInfo/Net/%u", uIfaceDeleteIdx++); } while (RT_SUCCESS(rc)); } else if ( RT_FAILURE(rc) && rc != VERR_NOT_FOUND) { VBoxServiceError("VMInfo/Network: Failed retrieving old network interfaces count with error %Rrc\n", rc); } #endif /* * This property is a beacon which is _always_ written, even if the network configuration * does not change. If this property is missing, the host assumes that all other GuestInfo * properties are no longer valid. */ VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/Net/Count", "%d", cIfacesReport); /* Don't fail here; just report everything we got. */ return VINF_SUCCESS; }