VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/adpctl/VBoxNetAdpCtl.cpp@ 67954

Last change on this file since 67954 was 67757, checked in by vboxsync, 7 years ago

AdpCtl: bugref:8866: play safe and use snprintf()

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.8 KB
Line 
1/* $Id: VBoxNetAdpCtl.cpp 67757 2017-07-03 13:52:33Z vboxsync $ */
2/** @file
3 * Apps - VBoxAdpCtl, Configuration tool for vboxnetX adapters.
4 */
5
6/*
7 * Copyright (C) 2009-2016 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#include <list>
24#include <errno.h>
25#include <stdio.h>
26#include <stdarg.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <sys/wait.h>
31#include <sys/ioctl.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#ifdef RT_OS_LINUX
35# include <net/if.h>
36# include <linux/types.h>
37/* Older versions of ethtool.h rely on these: */
38typedef unsigned long long u64;
39typedef __uint32_t u32;
40typedef __uint16_t u16;
41typedef __uint8_t u8;
42# include <limits.h> /* for INT_MAX */
43# include <linux/ethtool.h>
44# include <linux/sockios.h>
45#endif
46#ifdef RT_OS_SOLARIS
47# include <sys/ioccom.h>
48#endif
49
50#define NOREF(x) (void)x
51
52/** @todo Error codes must be moved to some header file */
53#define ADPCTLERR_BAD_NAME 2
54#define ADPCTLERR_NO_CTL_DEV 3
55#define ADPCTLERR_IOCTL_FAILED 4
56#define ADPCTLERR_SOCKET_FAILED 5
57
58/** @todo These are duplicates from src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h */
59#define VBOXNETADP_CTL_DEV_NAME "/dev/vboxnetctl"
60#define VBOXNETADP_MAX_INSTANCES 128
61#define VBOXNETADP_NAME "vboxnet"
62#define VBOXNETADP_MAX_NAME_LEN 32
63#define VBOXNETADP_CTL_ADD _IOWR('v', 1, VBOXNETADPREQ)
64#define VBOXNETADP_CTL_REMOVE _IOW('v', 2, VBOXNETADPREQ)
65typedef struct VBoxNetAdpReq
66{
67 char szName[VBOXNETADP_MAX_NAME_LEN];
68} VBOXNETADPREQ;
69typedef VBOXNETADPREQ *PVBOXNETADPREQ;
70
71#define VBOXADPCTL_IFCONFIG_PATH1 "/sbin/ifconfig"
72#define VBOXADPCTL_IFCONFIG_PATH2 "/bin/ifconfig"
73
74
75static void showUsage(void)
76{
77 fprintf(stderr, "Usage: VBoxNetAdpCtl <adapter> <address> ([netmask <address>] | remove)\n");
78 fprintf(stderr, " | VBoxNetAdpCtl [<adapter>] add\n");
79 fprintf(stderr, " | VBoxNetAdpCtl <adapter> remove\n");
80}
81
82
83/*
84 * A wrapper on standard list that provides '<<' operator for adding several list members in a single
85 * line dynamically. For example: "CmdList(arg1) << arg2 << arg3" produces a list with three members.
86 */
87class CmdList
88{
89public:
90 /** Creates an empty list. */
91 CmdList() {};
92 /** Creates a list with a single member. */
93 CmdList(const char *pcszCommand) { m_list.push_back(pcszCommand); };
94 /** Provides access to the underlying standard list. */
95 const std::list<const char *>& getList(void) const { return m_list; };
96 /** Adds a member to the list. */
97 CmdList& operator<<(const char *pcszArgument);
98private:
99 std::list<const char *>m_list;
100};
101
102CmdList& CmdList::operator<<(const char *pcszArgument)
103{
104 m_list.push_back(pcszArgument);
105 return *this;
106}
107
108/** Simple helper to distinguish IPv4 and IPv6 addresses. */
109inline bool isAddrV6(const char *pcszAddress)
110{
111 return !!(strchr(pcszAddress, ':'));
112}
113
114
115/*********************************************************************************************************************************
116* Generic address commands. *
117*********************************************************************************************************************************/
118
119/**
120 * The base class for all address manipulation commands. While being an abstract class,
121 * it provides a generic implementation of 'set' and 'remove' methods, which rely on
122 * pure virtual methods like 'addV4' and 'removeV4' to perform actual command execution.
123 */
124class AddressCommand
125{
126public:
127 AddressCommand() : m_pszPath(0) {};
128 virtual ~AddressCommand() {};
129
130 /** returns true if underlying command (executable) is present in the system. */
131 bool isAvailable(void)
132 { struct stat s; return (!stat(m_pszPath, &s) && S_ISREG(s.st_mode)); };
133
134 /*
135 * Someday we may want to support several IP addresses per adapter, but for now we
136 * have 'set' method only, which replaces all addresses with the one specifed.
137 *
138 * virtual int add(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0;
139 */
140 /** replace existing address(es) */
141 virtual int set(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0);
142 /** remove address */
143 virtual int remove(const char *pcszAdapter, const char *pcszAddress);
144protected:
145 /** IPv4-specific handler used by generic implementation of 'set' method if 'setV4' is not supported. */
146 virtual int addV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0;
147 /** IPv6-specific handler used by generic implementation of 'set' method. */
148 virtual int addV6(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0;
149 /** IPv4-specific handler used by generic implementation of 'set' method. */
150 virtual int setV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0) = 0;
151 /** IPv4-specific handler used by generic implementation of 'remove' method. */
152 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress) = 0;
153 /** IPv6-specific handler used by generic implementation of 'remove' method. */
154 virtual int removeV6(const char *pcszAdapter, const char *pcszAddress) = 0;
155 /** Composes the argument list of command that obtains all addresses assigned to the adapter. */
156 virtual CmdList getShowCommand(const char *pcszAdapter) const = 0;
157
158 /** Prepares an array of C strings needed for 'exec' call. */
159 char * const * allocArgv(const CmdList& commandList);
160 /** Hides process creation details. To be used in derived classes. */
161 int execute(CmdList& commandList);
162
163 /** A path to executable command. */
164 const char *m_pszPath;
165private:
166 /** Removes all previously asssigned addresses of a particular protocol family. */
167 int removeAddresses(const char *pcszAdapter, const char *pcszFamily);
168};
169
170/*
171 * A generic implementation of 'ifconfig' command for all platforms.
172 */
173class CmdIfconfig : public AddressCommand
174{
175public:
176 CmdIfconfig()
177 {
178 struct stat s;
179 if ( !stat(VBOXADPCTL_IFCONFIG_PATH1, &s)
180 && S_ISREG(s.st_mode))
181 m_pszPath = (char*)VBOXADPCTL_IFCONFIG_PATH1;
182 else
183 m_pszPath = (char*)VBOXADPCTL_IFCONFIG_PATH2;
184 };
185
186protected:
187 /** Returns platform-specific subcommand to add an address. */
188 virtual const char *addCmdArg(void) const = 0;
189 /** Returns platform-specific subcommand to remove an address. */
190 virtual const char *delCmdArg(void) const = 0;
191 virtual CmdList getShowCommand(const char *pcszAdapter) const
192 { return CmdList(pcszAdapter); };
193 virtual int addV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
194 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); NOREF(pcszNetmask); };
195 virtual int addV6(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
196 {
197 return execute(CmdList(pcszAdapter) << "inet6" << addCmdArg() << pcszAddress);
198 NOREF(pcszNetmask);
199 };
200 virtual int setV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
201 {
202 if (!pcszNetmask)
203 return execute(CmdList(pcszAdapter) << pcszAddress);
204 return execute(CmdList(pcszAdapter) << pcszAddress << "netmask" << pcszNetmask);
205 };
206 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress)
207 { return execute(CmdList(pcszAdapter) << delCmdArg() << pcszAddress); };
208 virtual int removeV6(const char *pcszAdapter, const char *pcszAddress)
209 { return execute(CmdList(pcszAdapter) << "inet6" << delCmdArg() << pcszAddress); };
210};
211
212
213/*********************************************************************************************************************************
214* Platform-specific commands *
215*********************************************************************************************************************************/
216
217class CmdIfconfigLinux : public CmdIfconfig
218{
219protected:
220 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress)
221 { return execute(CmdList(pcszAdapter) << "0.0.0.0"); NOREF(pcszAddress); };
222 virtual const char *addCmdArg(void) const { return "add"; };
223 virtual const char *delCmdArg(void) const { return "del"; };
224};
225
226class CmdIfconfigDarwin : public CmdIfconfig
227{
228protected:
229 virtual const char *addCmdArg(void) const { return "add"; };
230 virtual const char *delCmdArg(void) const { return "delete"; };
231};
232
233class CmdIfconfigSolaris : public CmdIfconfig
234{
235public:
236 virtual int set(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
237 {
238 const char *pcszFamily = isAddrV6(pcszAddress) ? "inet6" : "inet";
239 if (execute(CmdList(pcszAdapter) << pcszFamily))
240 execute(CmdList(pcszAdapter) << pcszFamily << "plumb" << "up");
241 return CmdIfconfig::set(pcszAdapter, pcszAddress, pcszNetmask);
242 };
243protected:
244 /* We can umplumb IPv4 interfaces only! */
245 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress)
246 {
247 int rc = CmdIfconfig::removeV4(pcszAdapter, pcszAddress);
248 execute(CmdList(pcszAdapter) << "inet" << "unplumb");
249 return rc;
250 };
251 virtual const char *addCmdArg(void) const { return "addif"; };
252 virtual const char *delCmdArg(void) const { return "removeif"; };
253};
254
255
256/*
257 * Linux-specific implementation of 'ip' command, as other platforms do not support it.
258 */
259class CmdIpLinux : public AddressCommand
260{
261public:
262 CmdIpLinux() { pszBuffer = 0; m_pszPath = "/sbin/ip"; };
263 virtual ~CmdIpLinux() { delete pszBuffer; };
264 /**
265 * IPv4 and IPv6 syntax is the same, so we override `remove` instead of implementing
266 * family-specific commands. It would be easier to use the same body in both
267 * 'removeV4' and 'removeV6', so we override 'remove' to illustrate how to do common
268 * implementation.
269 */
270 virtual int remove(const char *pcszAdapter, const char *pcszAddress)
271 { return execute(CmdList("addr") << "del" << pcszAddress << "dev" << pcszAdapter); };
272protected:
273 virtual int addV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
274 {
275 return execute(CmdList("addr") << "add" << combine(pcszAddress, pcszNetmask) <<
276 "dev" << pcszAdapter);
277 };
278 virtual int addV6(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
279 {
280 return execute(CmdList("addr") << "add" << pcszAddress << "dev" << pcszAdapter);
281 NOREF(pcszNetmask);
282 };
283 /**
284 * Our command does not support 'replacing' addresses. Reporting this fact to generic implementation
285 * of 'set' causes it to remove all assigned addresses, then 'add' the new one.
286 */
287 virtual int setV4(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask = 0)
288 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); NOREF(pcszNetmask); };
289 /** We use family-agnostic command syntax. See 'remove' above. */
290 virtual int removeV4(const char *pcszAdapter, const char *pcszAddress)
291 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); };
292 /** We use family-agnostic command syntax. See 'remove' above. */
293 virtual int removeV6(const char *pcszAdapter, const char *pcszAddress)
294 { return ENOTSUP; NOREF(pcszAdapter); NOREF(pcszAddress); };
295 virtual CmdList getShowCommand(const char *pcszAdapter) const
296 { return CmdList("addr") << "show" << "dev" << pcszAdapter; };
297private:
298 /** Converts address and network mask into a single string in CIDR notation (like 192.168.1.1/24) */
299 const char *combine(const char *pcszAddress, const char *pcszNetmask);
300
301 char *pszBuffer;
302};
303
304const char * CmdIpLinux::combine(const char *pcszAddress, const char *pcszNetmask)
305{
306 delete pszBuffer;
307 if (pcszNetmask)
308 {
309 unsigned cBits = 0;
310 unsigned m[4];
311 if (sscanf(pcszNetmask, "%u.%u.%u.%u", &m[0], &m[1], &m[2], &m[3]) == 4)
312 {
313 for (int i = 0; i < 4 && m[i]; ++i)
314 {
315 int mask = m[i];
316 while (mask & 0x80)
317 {
318 cBits++;
319 mask <<= 1;
320 }
321 }
322 const size_t cbBuf = strlen(pcszAddress) + 4;
323 pszBuffer = new char[cbBuf]; // '/xx\0'
324 snprintf(pszBuffer, cbBuf, "%s/%u", pcszAddress, cBits);
325 return pszBuffer;
326 }
327 }
328 return pcszAddress;
329}
330
331
332
333/*********************************************************************************************************************************
334* Generic address command implementations *
335*********************************************************************************************************************************/
336
337int AddressCommand::set(const char *pcszAdapter, const char *pcszAddress, const char *pcszNetmask)
338{
339 if (isAddrV6(pcszAddress))
340 {
341 removeAddresses(pcszAdapter, "inet6");
342 return addV6(pcszAdapter, pcszAddress, pcszNetmask);
343 }
344 int rc = setV4(pcszAdapter, pcszAddress, pcszNetmask);
345 if (rc == ENOTSUP)
346 {
347 removeAddresses(pcszAdapter, "inet");
348 rc = addV4(pcszAdapter, pcszAddress, pcszNetmask);
349 }
350 return rc;
351}
352
353int AddressCommand::remove(const char *pcszAdapter, const char *pcszAddress)
354{
355 if (isAddrV6(pcszAddress))
356 return removeV6(pcszAdapter, pcszAddress);
357 return removeV4(pcszAdapter, pcszAddress);
358}
359
360/*
361 * Allocate an array of exec arguments. In addition to arguments provided
362 * we need to include the full path to the executable as well as "terminating"
363 * null pointer marking the end of the array.
364 */
365char * const * AddressCommand::allocArgv(const CmdList& list)
366{
367 int i = 0;
368 std::list<const char *>::const_iterator it;
369 const char **argv = (const char **)calloc(list.getList().size() + 2, sizeof(const char *));
370 if (argv)
371 {
372 argv[i++] = m_pszPath;
373 for (it = list.getList().begin(); it != list.getList().end(); ++it)
374 argv[i++] = *it;
375 argv[i++] = NULL;
376 }
377 return (char * const*)argv;
378}
379
380int AddressCommand::execute(CmdList& list)
381{
382 char * const pEnv[] = { (char*)"LC_ALL=C", NULL };
383 char * const* argv = allocArgv(list);
384 if (argv == NULL)
385 return EXIT_FAILURE;
386
387 int rc = EXIT_SUCCESS;
388 pid_t childPid = fork();
389 switch (childPid)
390 {
391 case -1: /* Something went wrong. */
392 perror("fork() failed");
393 rc = EXIT_FAILURE;
394 break;
395 case 0: /* Child process. */
396 if (execve(argv[0], argv, pEnv) == -1)
397 rc = EXIT_FAILURE;
398 break;
399 default: /* Parent process. */
400 waitpid(childPid, &rc, 0);
401 break;
402 }
403
404 free((void*)argv);
405 return rc;
406}
407
408#define MAX_ADDRESSES 128
409#define MAX_ADDRLEN 64
410
411int AddressCommand::removeAddresses(const char *pcszAdapter, const char *pcszFamily)
412{
413 char szBuf[1024];
414 char aszAddresses[MAX_ADDRESSES][MAX_ADDRLEN];
415 int rc = EXIT_SUCCESS;
416 int fds[2];
417 char * const * argv = allocArgv(getShowCommand(pcszAdapter));
418 char * const envp[] = { (char*)"LC_ALL=C", NULL };
419
420 memset(aszAddresses, 0, sizeof(aszAddresses));
421
422 rc = pipe(fds);
423 if (rc < 0)
424 return errno;
425
426 pid_t pid = fork();
427 if (pid < 0)
428 return errno;
429
430 if (pid == 0)
431 {
432 /* child */
433 close(fds[0]);
434 close(STDOUT_FILENO);
435 rc = dup2(fds[1], STDOUT_FILENO);
436 if (rc >= 0)
437 if (execve(argv[0], argv, envp) == -1)
438 return errno;
439 return rc;
440 }
441
442 /* parent */
443 close(fds[1]);
444 FILE *fp = fdopen(fds[0], "r");
445 if (!fp)
446 return false;
447
448 int cAddrs;
449 for (cAddrs = 0; cAddrs < MAX_ADDRESSES && fgets(szBuf, sizeof(szBuf), fp);)
450 {
451 int cbSkipWS = strspn(szBuf, " \t");
452 char *pszWord = strtok(szBuf + cbSkipWS, " ");
453 /* We are concerned with particular family address lines only. */
454 if (!pszWord || strcmp(pszWord, pcszFamily))
455 continue;
456
457 pszWord = strtok(NULL, " ");
458
459 /* Skip "addr:" word if present. */
460 if (pszWord && !strcmp(pszWord, "addr:"))
461 pszWord = strtok(NULL, " ");
462
463 /* Skip link-local address lines. */
464 if (!pszWord || !strncmp(pszWord, "fe80", 4))
465 continue;
466 strncpy(aszAddresses[cAddrs++], pszWord, MAX_ADDRLEN-1);
467 }
468 fclose(fp);
469
470 for (int i = 0; i < cAddrs && rc == EXIT_SUCCESS; i++)
471 rc = remove(pcszAdapter, aszAddresses[i]);
472
473 return rc;
474}
475
476
477/*********************************************************************************************************************************
478* Adapter creation/removal implementations *
479*********************************************************************************************************************************/
480
481/*
482 * A generic implementation of adapter creation/removal ioctl calls.
483 */
484class Adapter
485{
486public:
487 int add(char *pszNameInOut);
488 int remove(const char *pcszName);
489 int checkName(const char *pcszNameIn, char *pszNameOut, size_t cbNameOut);
490protected:
491 virtual int doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq);
492};
493
494/*
495 * Solaris does not support dynamic creation/removal of adapters.
496 */
497class AdapterSolaris : public Adapter
498{
499protected:
500 virtual int doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq)
501 { return 1 /*ENOTSUP*/; NOREF(iCmd); NOREF(pReq); };
502};
503
504#if defined(RT_OS_LINUX)
505/*
506 * Linux implementation provides a 'workaround' to obtain adapter speed.
507 */
508class AdapterLinux : public Adapter
509{
510public:
511 int getSpeed(const char *pszName, unsigned *puSpeed);
512};
513
514int AdapterLinux::getSpeed(const char *pszName, unsigned *puSpeed)
515{
516 struct ifreq IfReq;
517 struct ethtool_value EthToolVal;
518 struct ethtool_cmd EthToolReq;
519 int fd = socket(AF_INET, SOCK_DGRAM, 0);
520 if (fd < 0)
521 {
522 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link "
523 "speed for %s: ", pszName);
524 perror("VBoxNetAdpCtl: failed to open control socket");
525 return ADPCTLERR_SOCKET_FAILED;
526 }
527 /* Get link status first. */
528 memset(&EthToolVal, 0, sizeof(EthToolVal));
529 memset(&IfReq, 0, sizeof(IfReq));
530 snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszName);
531
532 EthToolVal.cmd = ETHTOOL_GLINK;
533 IfReq.ifr_data = (caddr_t)&EthToolVal;
534 int rc = ioctl(fd, SIOCETHTOOL, &IfReq);
535 if (rc == 0)
536 {
537 if (EthToolVal.data)
538 {
539 memset(&IfReq, 0, sizeof(IfReq));
540 snprintf(IfReq.ifr_name, sizeof(IfReq.ifr_name), "%s", pszName);
541 EthToolReq.cmd = ETHTOOL_GSET;
542 IfReq.ifr_data = (caddr_t)&EthToolReq;
543 rc = ioctl(fd, SIOCETHTOOL, &IfReq);
544 if (rc == 0)
545 {
546 *puSpeed = EthToolReq.speed;
547 }
548 else
549 {
550 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link "
551 "speed for %s: ", pszName);
552 perror("VBoxNetAdpCtl: ioctl failed");
553 rc = ADPCTLERR_IOCTL_FAILED;
554 }
555 }
556 else
557 *puSpeed = 0;
558 }
559 else
560 {
561 fprintf(stderr, "VBoxNetAdpCtl: Error while retrieving link "
562 "status for %s: ", pszName);
563 perror("VBoxNetAdpCtl: ioctl failed");
564 rc = ADPCTLERR_IOCTL_FAILED;
565 }
566
567 close(fd);
568 return rc;
569}
570#endif /* defined(RT_OS_LINUX) */
571
572int Adapter::add(char *pszName /* in/out */)
573{
574 VBOXNETADPREQ Req;
575 memset(&Req, '\0', sizeof(Req));
576 snprintf(Req.szName, sizeof(Req.szName), "%s", pszName);
577 int rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req);
578 if (rc == 0)
579 strncpy(pszName, Req.szName, VBOXNETADP_MAX_NAME_LEN);
580 return rc;
581}
582
583int Adapter::remove(const char *pcszName)
584{
585 VBOXNETADPREQ Req;
586 memset(&Req, '\0', sizeof(Req));
587 snprintf(Req.szName, sizeof(Req.szName), "%s", pcszName);
588 return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req);
589}
590
591int Adapter::checkName(const char *pcszNameIn, char *pszNameOut, size_t cbNameOut)
592{
593 int iAdapterIndex = -1;
594
595 if ( strlen(pcszNameIn) >= VBOXNETADP_MAX_NAME_LEN
596 || sscanf(pcszNameIn, "vboxnet%d", &iAdapterIndex) != 1
597 || iAdapterIndex < 0 || iAdapterIndex >= VBOXNETADP_MAX_INSTANCES )
598 {
599 fprintf(stderr, "VBoxNetAdpCtl: Setting configuration for '%s' is not supported.\n", pcszNameIn);
600 return ADPCTLERR_BAD_NAME;
601 }
602 snprintf(pszNameOut, cbNameOut, "vboxnet%d", iAdapterIndex);
603 if (strcmp(pszNameOut, pcszNameIn))
604 {
605 fprintf(stderr, "VBoxNetAdpCtl: Invalid adapter name '%s'.\n", pcszNameIn);
606 return ADPCTLERR_BAD_NAME;
607 }
608
609 return 0;
610}
611
612int Adapter::doIOCtl(unsigned long iCmd, VBOXNETADPREQ *pReq)
613{
614 int fd = open(VBOXNETADP_CTL_DEV_NAME, O_RDWR);
615 if (fd == -1)
616 {
617 fprintf(stderr, "VBoxNetAdpCtl: Error while %s %s: ",
618 iCmd == VBOXNETADP_CTL_REMOVE ? "removing" : "adding",
619 pReq->szName[0] ? pReq->szName : "new interface");
620 perror("failed to open " VBOXNETADP_CTL_DEV_NAME);
621 return ADPCTLERR_NO_CTL_DEV;
622 }
623
624 int rc = ioctl(fd, iCmd, pReq);
625 if (rc == -1)
626 {
627 fprintf(stderr, "VBoxNetAdpCtl: Error while %s %s: ",
628 iCmd == VBOXNETADP_CTL_REMOVE ? "removing" : "adding",
629 pReq->szName[0] ? pReq->szName : "new interface");
630 perror("VBoxNetAdpCtl: ioctl failed for " VBOXNETADP_CTL_DEV_NAME);
631 rc = ADPCTLERR_IOCTL_FAILED;
632 }
633
634 close(fd);
635
636 return rc;
637}
638
639/*********************************************************************************************************************************
640* Main logic, argument parsing, etc. *
641*********************************************************************************************************************************/
642
643#if defined(RT_OS_LINUX)
644static CmdIfconfigLinux g_ifconfig;
645static AdapterLinux g_adapter;
646#elif defined(RT_OS_SOLARIS)
647static CmdIfconfigSolaris g_ifconfig;
648static AdapterSolaris g_adapter;
649#else
650static CmdIfconfigDarwin g_ifconfig;
651static Adapter g_adapter;
652#endif
653
654static AddressCommand& chooseAddressCommand()
655{
656#if defined(RT_OS_LINUX)
657 static CmdIpLinux g_ip;
658 if (g_ip.isAvailable())
659 return g_ip;
660#endif
661 return g_ifconfig;
662}
663
664int main(int argc, char *argv[])
665{
666 char szAdapterName[VBOXNETADP_MAX_NAME_LEN];
667 int rc = EXIT_SUCCESS;
668
669 AddressCommand& cmd = chooseAddressCommand();
670
671 if (argc < 2)
672 {
673 fprintf(stderr, "Insufficient number of arguments\n\n");
674 showUsage();
675 return 1;
676 }
677 else if (argc == 2 && !strcmp("add", argv[1]))
678 {
679 /* Create a new interface */
680 *szAdapterName = '\0';
681 rc = g_adapter.add(szAdapterName);
682 if (rc == 0)
683 puts(szAdapterName);
684 return rc;
685 }
686#ifdef RT_OS_LINUX
687 else if (argc == 3 && !strcmp("speed", argv[2]))
688 {
689 /*
690 * This ugly hack is needed for retrieving the link speed on
691 * pre-2.6.33 kernels (see @bugref{6345}).
692 */
693 if (strlen(argv[1]) >= IFNAMSIZ)
694 {
695 showUsage();
696 return -1;
697 }
698 unsigned uSpeed = 0;
699 rc = g_adapter.getSpeed(argv[1], &uSpeed);
700 if (!rc)
701 printf("%u", uSpeed);
702 return rc;
703 }
704#endif
705
706 rc = g_adapter.checkName(argv[1], szAdapterName, sizeof(szAdapterName));
707 if (rc)
708 return rc;
709
710 switch (argc)
711 {
712 case 5:
713 {
714 /* Add a netmask to existing interface */
715 if (strcmp("netmask", argv[3]))
716 {
717 fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
718 showUsage();
719 return 1;
720 }
721 rc = cmd.set(argv[1], argv[2], argv[4]);
722 break;
723 }
724
725 case 4:
726 {
727 /* Remove a single address from existing interface */
728 if (strcmp("remove", argv[3]))
729 {
730 fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
731 showUsage();
732 return 1;
733 }
734 rc = cmd.remove(argv[1], argv[2]);
735 break;
736 }
737
738 case 3:
739 {
740 if (strcmp("remove", argv[2]) == 0)
741 {
742 /* Remove an existing interface */
743 rc = g_adapter.remove(argv[1]);
744 }
745 else if (strcmp("add", argv[2]) == 0)
746 {
747 /* Create an interface with given name */
748 rc = g_adapter.add(szAdapterName);
749 if (rc == 0)
750 puts(szAdapterName);
751 }
752 else
753 rc = cmd.set(argv[1], argv[2]);
754 break;
755 }
756
757 default:
758 fprintf(stderr, "Invalid number of arguments.\n\n");
759 showUsage();
760 return 1;
761 }
762
763 return rc;
764}
765
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use