VirtualBox

source: vbox/trunk/src/apps/adpctl/VBoxNetAdpCtl.cpp@ 25275

Last change on this file since 25275 was 24854, checked in by vboxsync, 15 years ago

gcc warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/* $Id: VBoxNetAdpCtl.cpp 24854 2009-11-22 17:08:06Z vboxsync $ */
2/** @file
3 * Apps - VBoxAdpCtl, Configuration tool for vboxnetX adapters.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <sys/wait.h>
32#include <sys/ioctl.h>
33#include <fcntl.h>
34#ifdef RT_OS_SOLARIS
35# include <sys/ioccom.h>
36#endif
37
38/** @todo Error codes must be moved to some header file */
39#define ADPCTLERR_BAD_NAME 2
40#define ADPCTLERR_NO_CTL_DEV 3
41#define ADPCTLERR_IOCTL_FAILED 4
42
43/** @todo These are duplicates from src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h */
44#define VBOXNETADP_CTL_DEV_NAME "/dev/vboxnetctl"
45#define VBOXNETADP_NAME "vboxnet"
46#define VBOXNETADP_MAX_NAME_LEN 32
47#define VBOXNETADP_CTL_ADD _IOR('v', 1, VBOXNETADPREQ)
48#define VBOXNETADP_CTL_REMOVE _IOW('v', 2, VBOXNETADPREQ)
49typedef struct VBoxNetAdpReq
50{
51 char szName[VBOXNETADP_MAX_NAME_LEN];
52} VBOXNETADPREQ;
53typedef VBOXNETADPREQ *PVBOXNETADPREQ;
54
55
56#define VBOXADPCTL_IFCONFIG_PATH "/sbin/ifconfig"
57
58#ifdef RT_OS_LINUX
59#define VBOXADPCTL_DEL_CMD "del"
60#else
61#define VBOXADPCTL_DEL_CMD "delete"
62#endif
63
64static void showUsage(void)
65{
66 fprintf(stderr, "Usage: VBoxNetAdpCtl <adapter> <address> ([netmask <address>] | remove)\n");
67 fprintf(stderr, " | VBoxNetAdpCtl add\n");
68 fprintf(stderr, " | VBoxNetAdpCtl <adapter> remove\n");
69}
70
71static int executeIfconfig(const char *pcszAdapterName, const char *pcszArg1,
72 const char *pcszArg2 = NULL,
73 const char *pcszArg3 = NULL,
74 const char *pcszArg4 = NULL,
75 const char *pcszArg5 = NULL)
76{
77 const char * const argv[] =
78 {
79 VBOXADPCTL_IFCONFIG_PATH,
80 pcszAdapterName,
81 pcszArg1, /* [address family] */
82 pcszArg2, /* address */
83 pcszArg3, /* ['netmask'] */
84 pcszArg4, /* [network mask] */
85 pcszArg5, /* [network mask] */
86 NULL /* terminator */
87 };
88 char * const envp[] = { (char*)"LC_ALL=C", NULL };
89 int rc = EXIT_SUCCESS;
90 pid_t childPid = fork();
91 switch (childPid)
92 {
93 case -1: /* Something went wrong. */
94 perror("fork() failed");
95 rc = EXIT_FAILURE;
96 break;
97 case 0: /* Child process. */
98 if (execve(VBOXADPCTL_IFCONFIG_PATH, (char * const*)argv, envp) == -1)
99 rc = EXIT_FAILURE;
100 break;
101 default: /* Parent process. */
102 waitpid(childPid, &rc, 0);
103 break;
104 }
105
106 return rc;
107}
108
109#define MAX_ADDRESSES 128
110#define MAX_ADDRLEN 64
111
112static bool removeAddresses(char *pszAdapterName)
113{
114 char szBuf[1024];
115 char aszAddresses[MAX_ADDRESSES][MAX_ADDRLEN];
116 int rc;
117 int fds[2];
118 char * const argv[] = { (char*)VBOXADPCTL_IFCONFIG_PATH, pszAdapterName, NULL };
119 char * const envp[] = { (char*)"LC_ALL=C", NULL };
120
121 memset(aszAddresses, 0, sizeof(aszAddresses));
122
123 rc = pipe(fds);
124 if (rc < 0)
125 return false;
126
127 pid_t pid = fork();
128 if (pid < 0)
129 return false;
130
131 if (pid == 0)
132 {
133 /* child */
134 close(fds[0]);
135 close(STDOUT_FILENO);
136 rc = dup2(fds[1], STDOUT_FILENO);
137 if (rc >= 0)
138 execve(VBOXADPCTL_IFCONFIG_PATH, argv, envp);
139 return false;
140 }
141
142 /* parent */
143 close(fds[1]);
144 FILE *fp = fdopen(fds[0], "r");
145 if (!fp)
146 return false;
147
148 int cAddrs;
149 for (cAddrs = 0; cAddrs < MAX_ADDRESSES && fgets(szBuf, sizeof(szBuf), fp);)
150 {
151 int cbSkipWS = strspn(szBuf, " \t");
152 char *pszWord = strtok(szBuf + cbSkipWS, " ");
153 /* We are concerned with IPv6 address lines only. */
154 if (!pszWord || strcmp(pszWord, "inet6"))
155 continue;
156#ifdef RT_OS_LINUX
157 pszWord = strtok(NULL, " ");
158 /* Skip "addr:". */
159 if (!pszWord || strcmp(pszWord, "addr:"))
160 continue;
161#endif
162 pszWord = strtok(NULL, " ");
163 /* Skip link-local addresses. */
164 if (!pszWord || !strncmp(pszWord, "fe80", 4))
165 continue;
166 strncpy(aszAddresses[cAddrs++], pszWord, MAX_ADDRLEN-1);
167 }
168 fclose(fp);
169
170 for (int i = 0; i < cAddrs; i++)
171 {
172 if (executeIfconfig(pszAdapterName, "inet6",
173 VBOXADPCTL_DEL_CMD, aszAddresses[i]) != EXIT_SUCCESS)
174 return false;
175 }
176
177 return true;
178}
179
180int doIOCtl(unsigned long uCmd, void *pData)
181{
182 int fd = open(VBOXNETADP_CTL_DEV_NAME, O_RDWR);
183 if (fd == -1)
184 {
185 perror("VBoxNetAdpCtl: failed to open " VBOXNETADP_CTL_DEV_NAME);
186 return ADPCTLERR_NO_CTL_DEV;
187 }
188
189 int rc = ioctl(fd, uCmd, pData);
190 if (rc == -1)
191 {
192 perror("VBoxNetAdpCtl: ioctl failed for " VBOXNETADP_CTL_DEV_NAME);
193 rc = ADPCTLERR_IOCTL_FAILED;
194 }
195
196 close(fd);
197
198 return rc;
199}
200
201int checkAdapterName(const char *pcszNameIn, char *pszNameOut)
202{
203 int iAdapterIndex = -1;
204
205 if ( strlen(pcszNameIn) >= VBOXNETADP_MAX_NAME_LEN
206 || sscanf(pcszNameIn, "vboxnet%d", &iAdapterIndex) != 1
207 || iAdapterIndex < 0 || iAdapterIndex > 99 )
208 {
209 fprintf(stderr, "Setting configuration for %s is not supported.\n", pcszNameIn);
210 return ADPCTLERR_BAD_NAME;
211 }
212 sprintf(pszNameOut, "vboxnet%d", iAdapterIndex);
213 if (strcmp(pszNameOut, pcszNameIn))
214 {
215 fprintf(stderr, "Invalid adapter name %s.\n", pcszNameIn);
216 return ADPCTLERR_BAD_NAME;
217 }
218
219 return 0;
220}
221
222int main(int argc, char *argv[])
223
224{
225 char szAdapterName[VBOXNETADP_MAX_NAME_LEN];
226 char *pszAdapterName;
227 const char *pszAddress;
228 const char *pszNetworkMask = NULL;
229 const char *pszOption = NULL;
230 int rc = EXIT_SUCCESS;
231 bool fRemove = false;
232 VBOXNETADPREQ Req;
233
234 switch (argc)
235 {
236 case 5:
237 if (strcmp("netmask", argv[3]))
238 {
239 fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
240 showUsage();
241 return 1;
242 }
243 pszOption = "netmask";
244 pszNetworkMask = argv[4];
245 pszAdapterName = argv[1];
246 pszAddress = argv[2];
247 break;
248 case 4:
249 if (strcmp("remove", argv[3]))
250 {
251 fprintf(stderr, "Invalid argument: %s\n\n", argv[3]);
252 showUsage();
253 return 1;
254 }
255 fRemove = true;
256 pszAdapterName = argv[1];
257 pszAddress = argv[2];
258 break;
259 case 3:
260 pszAdapterName = argv[1];
261 pszAddress = argv[2];
262 if (strcmp("remove", pszAddress) == 0)
263 {
264 rc = checkAdapterName(pszAdapterName, szAdapterName);
265 if (rc)
266 return rc;
267 memset(&Req, '\0', sizeof(Req));
268 snprintf(Req.szName, sizeof(Req.szName), "%s", szAdapterName);
269 return doIOCtl(VBOXNETADP_CTL_REMOVE, &Req);
270 }
271 break;
272 case 2:
273 if (strcmp("add", argv[1]) == 0)
274 {
275 memset(&Req, '\0', sizeof(Req));
276 rc = doIOCtl(VBOXNETADP_CTL_ADD, &Req);
277 if (rc == 0)
278 puts(Req.szName);
279 return rc;
280 }
281 /* Fall through */
282 default:
283 fprintf(stderr, "Invalid number of arguments.\n\n");
284 /* Fall through */
285 case 1:
286 showUsage();
287 return 1;
288 }
289
290 rc = checkAdapterName(pszAdapterName, szAdapterName);
291 if (rc)
292 return rc;
293
294 pszAdapterName = szAdapterName;
295
296 if (fRemove)
297 {
298 if (strchr(pszAddress, ':'))
299 rc = executeIfconfig(pszAdapterName, "inet6", VBOXADPCTL_DEL_CMD, pszAddress);
300 else
301 {
302#ifdef RT_OS_LINUX
303 rc = executeIfconfig(pszAdapterName, "0.0.0.0");
304#else
305 rc = executeIfconfig(pszAdapterName, "delete", pszAddress);
306#endif
307 }
308 }
309 else
310 {
311 /* We are setting/replacing address. */
312 if (strchr(pszAddress, ':'))
313 {
314 /*
315 * Before we set IPv6 address we'd like to remove
316 * all previously assigned addresses except the
317 * self-assigned one.
318 */
319 if (!removeAddresses(pszAdapterName))
320 rc = EXIT_FAILURE;
321 else
322 rc = executeIfconfig(pszAdapterName, "inet6", "add", pszAddress, pszOption, pszNetworkMask);
323 }
324 else
325 rc = executeIfconfig(pszAdapterName, pszAddress, pszOption, pszNetworkMask);
326 }
327 return rc;
328}
329
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use