VBoxNetAdpCtl.cpp revision 613e5cf233371122e87263c07af8f122a17d0224
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/* $Id$ */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * Apps - VBoxAdpCtl, Configuration tool for vboxnetX adapters.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2009 Sun Microsystems, Inc.
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync *
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * available from http://www.virtualbox.org. This file is free software;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * additional information or have any questions.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync* Header Files *
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync*******************************************************************************/
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync#include <assert.h>
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#include <stdio.h>
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#include <stdlib.h>
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#include <string.h>
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#include <unistd.h>
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync#include <sys/wait.h>
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#include <sys/ioctl.h>
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#include <sys/ioccom.h>
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync#include <fcntl.h>
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync/* @todo Error codes must be moved to some header file */
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync#define ADPCTLERR_NO_CTL_DEV 3
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync#define ADPCTLERR_IOCTL_FAILED 4
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync/* @todo These are duplicates from src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h */
f85630691753e2acd5099c3079b3e6d40c049a62vboxsync#define VBOXNETADP_CTL_DEV_NAME "/dev/vboxnetctl"
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync#define VBOXNETADP_NAME "vboxnet"
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define VBOXNETADP_MAX_NAME_LEN 32
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define VBOXNETADP_CTL_ADD _IOR('v', 1, VBOXNETADPREQ)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define VBOXNETADP_CTL_REMOVE _IOW('v', 2, VBOXNETADPREQ)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsynctypedef struct VBoxNetAdpReq
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync{
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync char szName[VBOXNETADP_MAX_NAME_LEN];
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync} VBOXNETADPREQ;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsynctypedef VBOXNETADPREQ *PVBOXNETADPREQ;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define VBOXADPCTL_IFCONFIG_PATH "/sbin/ifconfig"
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#ifdef RT_OS_LINUX
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define VBOXADPCTL_DEL_CMD "del"
b34f0f200ed0778053a2a1d93381c2c6b60cb2d5vboxsync#else
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync#define VBOXADPCTL_DEL_CMD "delete"
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync#endif
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsyncstatic void showUsage(void)
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync{
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync fprintf(stderr, "Usage: VBoxNetAdpCtl <adapter> <address> ([netmask <address>] | remove)\n");
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync fprintf(stderr, " | VBoxNetAdpCtl add\n");
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync fprintf(stderr, " | VBoxNetAdpCtl <adapter> remove\n");
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync}
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsyncstatic int executeIfconfig(const char *pcszAdapterName, const char *pcszArg1,
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync const char *pcszArg2 = NULL,
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync const char *pcszArg3 = NULL,
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync const char *pcszArg4 = NULL,
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync const char *pcszArg5 = NULL)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync{
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync const char * const argv[] =
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync {
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync VBOXADPCTL_IFCONFIG_PATH,
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync pcszAdapterName,
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pcszArg1, /* [address family] */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pcszArg2, /* address */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pcszArg3, /* ['netmask'] */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pcszArg4, /* [network mask] */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pcszArg5, /* [network mask] */
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync NULL /* terminator */
6a767f9e41ad3ab67a2d0a376ae0a9404a283626vboxsync };
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync int rc = EXIT_SUCCESS;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pid_t childPid = fork();
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync switch (childPid)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync {
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync case -1: /* Something went wrong. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync perror("fork() failed");
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync rc = EXIT_FAILURE;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync break;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync case 0: /* Child process. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync if (execv(VBOXADPCTL_IFCONFIG_PATH, (char * const*)argv) == -1)
9c11b89c71ca727d975c39f2719063501ddcd03dvboxsync rc = EXIT_FAILURE;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync break;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync default: /* Parent process. */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync waitpid(childPid, &rc, 0);
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync break;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync }
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync return rc;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync}
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#define MAX_ADDRESSES 128
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync#define MAX_ADDRLEN 64
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsyncstatic bool removeAddresses(const char *pszAdapterName)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync{
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync char szCmd[1024], szBuf[1024];
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync char aszAddresses[MAX_ADDRESSES][MAX_ADDRLEN];
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync memset(aszAddresses, 0, sizeof(aszAddresses));
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync snprintf(szCmd, sizeof(szCmd), VBOXADPCTL_IFCONFIG_PATH " %s", pszAdapterName);
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync FILE *fp = popen(szCmd, "r");
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync if (!fp)
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync return false;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync int cAddrs;
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync for (cAddrs = 0; cAddrs < MAX_ADDRESSES && fgets(szBuf, sizeof(szBuf), fp);)
ad81f667a6be22bee5e7628bf8cfb849723734c6vboxsync {
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync int cbSkipWS = strspn(szBuf, " \t");
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync#if 0 /* Don't use this! assert() breaks the mac build. Use IPRT or be a rectangular building thing. */
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync assert(cbSkipWS < 20);
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync#endif
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync char *pszWord = strtok(szBuf + cbSkipWS, " ");
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync /* We are concerned with IPv6 address lines only. */
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync if (!pszWord || strcmp(pszWord, "inet6"))
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync continue;
94ba6c16473d2e164a603f75a976fd187d54ce3bvboxsync#ifdef RT_OS_LINUX
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pszWord = strtok(NULL, " ");
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync /* Skip "addr:". */
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync if (!pszWord || strcmp(pszWord, "addr:"))
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync continue;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync#endif
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync pszWord = strtok(NULL, " ");
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync /* Skip link-local addresses. */
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync if (!pszWord || !strncmp(pszWord, "fe80", 4))
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync continue;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync strncpy(aszAddresses[cAddrs++], pszWord, MAX_ADDRLEN-1);
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync }
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync pclose(fp);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync for (int i = 0; i < cAddrs; i++)
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync {
ad81f667a6be22bee5e7628bf8cfb849723734c6vboxsync if (executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, aszAddresses[i]) != EXIT_SUCCESS)
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync return false;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync }
7f857bf87e6836b7359e38b75ef7408dd2886c7cvboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync return true;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync}
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncint doIOCtl(unsigned long uCmd, void *pData)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync{
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync int fd = open(VBOXNETADP_CTL_DEV_NAME, O_RDWR);
f85630691753e2acd5099c3079b3e6d40c049a62vboxsync if (fd == -1)
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync {
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync perror("VBoxNetAdpCtl: failed to open " VBOXNETADP_CTL_DEV_NAME);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync return ADPCTLERR_NO_CTL_DEV;
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync }
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync int rc = ioctl(fd, uCmd, pData);
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync if (rc == -1)
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync {
1d398d1aa90bdac2b68d4f434283746c5838a96dvboxsync perror("VBoxNetAdpCtl: ioctl failed for " VBOXNETADP_CTL_DEV_NAME);
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync rc = ADPCTLERR_IOCTL_FAILED;
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync }
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync close(fd);
94ba6c16473d2e164a603f75a976fd187d54ce3bvboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync return rc;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync}
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsyncint main(int argc, char *argv[])
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync{
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync const char *pszAdapterName;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync const char *pszAddress;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync const char *pszNetworkMask = NULL;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync const char *pszOption = NULL;
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync int rc = EXIT_SUCCESS;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync bool fRemove = false;
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync VBOXNETADPREQ Req;
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync switch (argc)
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync {
72c49feb12a449819b130e1b2255fb785e7c9fb1vboxsync case 5:
1d398d1aa90bdac2b68d4f434283746c5838a96dvboxsync if (strcmp("netmask", argv[3]))
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync {
fc0e1701814ea969173fadb20fef6833b04fb2bcvboxsync fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
3667b9956dd95cfba687d4dc23dabb9a49c1feadvboxsync showUsage();
7f857bf87e6836b7359e38b75ef7408dd2886c7cvboxsync return 1;
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync }
29bdc01040c07a3dd482a94a2cb8f0a90f8587a7vboxsync pszOption = "netmask";
pszNetworkMask = argv[4];
pszAdapterName = argv[1];
pszAddress = argv[2];
break;
case 4:
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];
pszAddress = argv[2];
if (strcmp("remove", pszAddress) == 0)
{
strncpy(Req.szName, pszAdapterName, sizeof(Req.szName));
return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req);
}
break;
case 2:
if (strcmp("add", argv[1]) == 0)
{
rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req);
if (rc == 0)
puts(Req.szName);
return rc;
}
/* Fall through */
default:
fprintf(stderr, "Invalid number of arguments.\n\n");
/* Fall through */
case 1:
showUsage();
return 1;
}
if (strncmp("vboxnet", pszAdapterName, 7))
{
fprintf(stderr, "Setting configuration for %s is not supported.\n", pszAdapterName);
return 2;
}
if (fRemove)
{
if (strchr(pszAddress, ':'))
rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, pszAddress);
else
{
#ifdef RT_OS_LINUX
rc = executeIfconfig(pszAdapterName, "0.0.0.0");
#else
rc = executeIfconfig(pszAdapterName, "delete", pszAddress);
#endif
}
}
else
{
/* We are setting/replacing address. */
if (strchr(pszAddress, ':'))
{
/*
* 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", "add", pszAddress, pszOption, pszNetworkMask);
}
else
rc = executeIfconfig(pszAdapterName, pszAddress, pszOption, pszNetworkMask);
}
return rc;
}