static bool removeAddresses(char *pszAdapterName) { char szBuf[1024]; char aszAddresses[MAX_ADDRESSES][MAX_ADDRLEN]; int rc; int fds[2]; char * const argv[] = { g_pszIfConfig, pszAdapterName, NULL }; char * const envp[] = { (char*)"LC_ALL=C", NULL }; memset(aszAddresses, 0, sizeof(aszAddresses)); rc = pipe(fds); if (rc < 0) return false; pid_t pid = fork(); if (pid < 0) return false; if (pid == 0) { /* child */ close(fds[0]); close(STDOUT_FILENO); rc = dup2(fds[1], STDOUT_FILENO); if (rc >= 0) execve(argv[0], argv, envp); return false; } /* parent */ close(fds[1]); FILE *fp = fdopen(fds[0], "r"); if (!fp) return false; int cAddrs; for (cAddrs = 0; cAddrs < MAX_ADDRESSES && fgets(szBuf, sizeof(szBuf), fp);) { int cbSkipWS = strspn(szBuf, " \t"); char *pszWord = strtok(szBuf + cbSkipWS, " "); /* We are concerned with IPv6 address lines only. */ if (!pszWord || strcmp(pszWord, "inet6")) continue; #ifdef RT_OS_LINUX pszWord = strtok(NULL, " "); /* Skip "addr:". */ if (!pszWord || strcmp(pszWord, "addr:")) continue; #endif pszWord = strtok(NULL, " "); /* Skip link-local addresses. */ if (!pszWord || !strncmp(pszWord, "fe80", 4)) continue; strncpy(aszAddresses[cAddrs++], pszWord, MAX_ADDRLEN-1); } fclose(fp); for (int i = 0; i < cAddrs; i++) { if (executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, aszAddresses[i]) != EXIT_SUCCESS) return false; } return true; }
int main(int argc, char *argv[]) { char szAdapterName[VBOXNETADP_MAX_NAME_LEN]; char *pszAdapterName = NULL; const char *pszAddress = NULL; const char *pszNetworkMask = NULL; const char *pszOption = NULL; int rc = EXIT_SUCCESS; bool fRemove = false; VBOXNETADPREQ Req; setPathIfConfig(); switch (argc) { case 5: { /* Add a netmask to existing interface */ if (strcmp("netmask", argv[3])) { fprintf(stderr, "Invalid argument: %s\n\n", argv[3]); showUsage(); return 1; } pszOption = "netmask"; pszNetworkMask = argv[4]; pszAdapterName = argv[1]; pszAddress = argv[2]; break; } case 4: { /* Remove a single address from existing interface */ if (strcmp("remove", argv[3])) { fprintf(stderr, "Invalid argument: %s\n\n", argv[3]); showUsage(); return 1; } fRemove = true; pszAdapterName = argv[1]; pszAddress = argv[2]; break; } case 3: { pszAdapterName = argv[1]; memset(&Req, '\0', sizeof(Req)); #ifdef RT_OS_LINUX if (strcmp("speed", argv[2]) == 0) { /* * This ugly hack is needed for retrieving the link speed on * pre-2.6.33 kernels (see @bugref{6345}). */ if (strlen(pszAdapterName) >= IFNAMSIZ) { showUsage(); return -1; } struct ifreq IfReq; struct ethtool_value EthToolVal; struct ethtool_cmd EthToolReq; int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " "speed for %s: ", pszAdapterName); perror("VBoxNetAdpCtl: failed to open control socket"); return ADPCTLERR_SOCKET_FAILED; } /* Get link status first. */ memset(&EthToolVal, 0, sizeof(EthToolVal)); memset(&IfReq, 0, sizeof(IfReq)); snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszAdapterName); EthToolVal.cmd = ETHTOOL_GLINK; IfReq.ifr_data = (caddr_t)&EthToolVal; rc = ioctl(fd, SIOCETHTOOL, &IfReq); if (rc == 0) { if (EthToolVal.data) { memset(&IfReq, 0, sizeof(IfReq)); snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszAdapterName); EthToolReq.cmd = ETHTOOL_GSET; IfReq.ifr_data = (caddr_t)&EthToolReq; rc = ioctl(fd, SIOCETHTOOL, &IfReq); if (rc == 0) { printf("%u", EthToolReq.speed); } else { fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " "speed for %s: ", pszAdapterName); perror("VBoxNetAdpCtl: ioctl failed"); rc = ADPCTLERR_IOCTL_FAILED; } } else printf("0"); } else { fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link " "status for %s: ", pszAdapterName); perror("VBoxNetAdpCtl: ioctl failed"); rc = ADPCTLERR_IOCTL_FAILED; } close(fd); return rc; } #endif rc = checkAdapterName(pszAdapterName, szAdapterName); if (rc) return rc; snprintf(Req.szName, sizeof(Req.szName), "%s", szAdapterName); pszAddress = argv[2]; if (strcmp("remove", pszAddress) == 0) { /* Remove an existing interface */ #ifdef RT_OS_SOLARIS return 1; #else return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req); #endif } else if (strcmp("add", pszAddress) == 0) { /* Create an interface with given name */ #ifdef RT_OS_SOLARIS return 1; #else rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req); if (rc == 0) puts(Req.szName); #endif return rc; } break; } case 2: { /* Create a new interface */ if (strcmp("add", argv[1]) == 0) { #ifdef RT_OS_SOLARIS return 1; #else memset(&Req, '\0', sizeof(Req)); rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req); if (rc == 0) puts(Req.szName); #endif return rc; } /* Fall through */ } default: fprintf(stderr, "Invalid number of arguments.\n\n"); /* Fall through */ case 1: showUsage(); return 1; } rc = checkAdapterName(pszAdapterName, szAdapterName); if (rc) return rc; pszAdapterName = szAdapterName; if (fRemove) { if (strchr(pszAddress, ':')) rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, pszAddress); else { #if defined(RT_OS_LINUX) rc = executeIfconfig(pszAdapterName, "0.0.0.0"); #else rc = executeIfconfig(pszAdapterName, VBOXADPCTL_DEL_CMD, pszAddress); #endif #ifdef RT_OS_SOLARIS /* On Solaris we can unplumb the ipv4 interface */ executeIfconfig(pszAdapterName, "inet", "unplumb"); #endif } } else { /* We are setting/replacing address. */ if (strchr(pszAddress, ':')) { #ifdef RT_OS_SOLARIS /* On Solaris we need to plumb the interface first if it's not already plumbed. */ if (executeIfconfig(pszAdapterName, "inet6") != 0) executeIfconfig(pszAdapterName, "inet6", "plumb", "up"); #endif /* * Before we set IPv6 address we'd like to remove * all previously assigned addresses except the * self-assigned one. */ if (!removeAddresses(pszAdapterName)) rc = EXIT_FAILURE; else rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_ADD_CMD, pszAddress, pszOption, pszNetworkMask); } else { #ifdef RT_OS_SOLARIS /* On Solaris we need to plumb the interface first if it's not already plumbed. */ if (executeIfconfig(pszAdapterName, "inet") != 0) executeIfconfig(pszAdapterName, "plumb", "up"); #endif rc = executeIfconfig(pszAdapterName, pszAddress, pszOption, pszNetworkMask); } } return rc; }
int main(int argc, char *argv[]) { char szAdapterName[VBOXNETADP_MAX_NAME_LEN]; char *pszAdapterName = NULL; const char *pszAddress = NULL; const char *pszNetworkMask = NULL; const char *pszOption = NULL; int rc = EXIT_SUCCESS; bool fRemove = false; VBOXNETADPREQ Req; switch (argc) { case 5: { /* Add a netmask to existing interface */ if (strcmp("netmask", argv[3])) { fprintf(stderr, "Invalid argument: %s\n\n", argv[3]); showUsage(); return 1; } pszOption = "netmask"; pszNetworkMask = argv[4]; pszAdapterName = argv[1]; pszAddress = argv[2]; break; } case 4: { /* Remove a single address from existing interface */ if (strcmp("remove", argv[3])) { fprintf(stderr, "Invalid argument: %s\n\n", argv[3]); showUsage(); return 1; } fRemove = true; pszAdapterName = argv[1]; pszAddress = argv[2]; break; } case 3: { pszAdapterName = argv[1]; memset(&Req, '\0', sizeof(Req)); rc = checkAdapterName(pszAdapterName, szAdapterName); if (rc) return rc; snprintf(Req.szName, sizeof(Req.szName), "%s", szAdapterName); pszAddress = argv[2]; if (strcmp("remove", pszAddress) == 0) { /* Remove an existing interface */ #ifdef RT_OS_SOLARIS return 1; #else return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req); #endif } else if (strcmp("add", pszAddress) == 0) { /* Create an interface with given name */ #ifdef RT_OS_SOLARIS return 1; #else rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req); if (rc == 0) puts(Req.szName); #endif return rc; } break; } case 2: { /* Create a new interface */ if (strcmp("add", argv[1]) == 0) { #ifdef RT_OS_SOLARIS return 1; #else memset(&Req, '\0', sizeof(Req)); rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req); if (rc == 0) puts(Req.szName); #endif return rc; } /* Fall through */ } default: fprintf(stderr, "Invalid number of arguments.\n\n"); /* Fall through */ case 1: showUsage(); return 1; } rc = checkAdapterName(pszAdapterName, szAdapterName); if (rc) return rc; pszAdapterName = szAdapterName; if (fRemove) { if (strchr(pszAddress, ':')) rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, pszAddress); else { #if defined(RT_OS_LINUX) rc = executeIfconfig(pszAdapterName, "0.0.0.0"); #else rc = executeIfconfig(pszAdapterName, VBOXADPCTL_DEL_CMD, pszAddress); #endif #ifdef RT_OS_SOLARIS /* On Solaris we can unplumb the ipv4 interface */ executeIfconfig(pszAdapterName, "inet", "unplumb"); #endif } } else { /* We are setting/replacing address. */ if (strchr(pszAddress, ':')) { #ifdef RT_OS_SOLARIS /* On Solaris we need to plumb the interface first if it's not already plumbed. */ if (executeIfconfig(pszAdapterName, "inet6") != 0) executeIfconfig(pszAdapterName, "inet6", "plumb", "up"); #endif /* * Before we set IPv6 address we'd like to remove * all previously assigned addresses except the * self-assigned one. */ if (!removeAddresses(pszAdapterName)) rc = EXIT_FAILURE; else rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_ADD_CMD, pszAddress, pszOption, pszNetworkMask); } else { #ifdef RT_OS_SOLARIS /* On Solaris we need to plumb the interface first if it's not already plumbed. */ if (executeIfconfig(pszAdapterName, "inet") != 0) executeIfconfig(pszAdapterName, "plumb", "up"); #endif rc = executeIfconfig(pszAdapterName, pszAddress, pszOption, pszNetworkMask); } } return rc; }