/** @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
}
Ejemplo n.º 2
0
/**
 * 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;
}