diff options
Diffstat (limited to 'ifconfig.c')
-rw-r--r-- | ifconfig.c | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/ifconfig.c b/ifconfig.c new file mode 100644 index 000000000..2134f8a48 --- /dev/null +++ b/ifconfig.c | |||
@@ -0,0 +1,476 @@ | |||
1 | /* ifconfig | ||
2 | * | ||
3 | * Similar to the standard Unix ifconfig, but with only the necessary | ||
4 | * parts for AF_INET, and without any printing of if info (for now). | ||
5 | * | ||
6 | * Bjorn Wesen, Axis Communications AB | ||
7 | * | ||
8 | * | ||
9 | * Authors of the original ifconfig was: | ||
10 | * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it | ||
13 | * and/or modify it under the terms of the GNU General | ||
14 | * Public License as published by the Free Software | ||
15 | * Foundation; either version 2 of the License, or (at | ||
16 | * your option) any later version. | ||
17 | * | ||
18 | * $Id: ifconfig.c,v 1.1 2001/02/14 08:11:27 andersen Exp $ | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "busybox.h" | ||
23 | #include <sys/types.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <errno.h> | ||
27 | #include <string.h> // strcmp and friends | ||
28 | #include <ctype.h> // isdigit and friends | ||
29 | #include <sys/socket.h> | ||
30 | #include <sys/ioctl.h> | ||
31 | #include <netinet/in.h> | ||
32 | #include <arpa/inet.h> | ||
33 | #include <net/if.h> | ||
34 | #include <net/if_arp.h> | ||
35 | #include <linux/if_ether.h> | ||
36 | |||
37 | static int sockfd; /* socket fd we use to manipulate stuff with */ | ||
38 | |||
39 | /* print usage and exit */ | ||
40 | |||
41 | #define _(x) x | ||
42 | |||
43 | /* Set a certain interface flag. */ | ||
44 | static int | ||
45 | set_flag(char *ifname, short flag) | ||
46 | { | ||
47 | struct ifreq ifr; | ||
48 | |||
49 | strcpy(ifr.ifr_name, ifname); | ||
50 | if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { | ||
51 | perror("SIOCGIFFLAGS"); | ||
52 | return (-1); | ||
53 | } | ||
54 | strcpy(ifr.ifr_name, ifname); | ||
55 | ifr.ifr_flags |= flag; | ||
56 | if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { | ||
57 | perror("SIOCSIFFLAGS"); | ||
58 | return -1; | ||
59 | } | ||
60 | return (0); | ||
61 | } | ||
62 | |||
63 | |||
64 | /* Clear a certain interface flag. */ | ||
65 | static int | ||
66 | clr_flag(char *ifname, short flag) | ||
67 | { | ||
68 | struct ifreq ifr; | ||
69 | |||
70 | strcpy(ifr.ifr_name, ifname); | ||
71 | if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { | ||
72 | perror("SIOCGIFFLAGS"); | ||
73 | return -1; | ||
74 | } | ||
75 | strcpy(ifr.ifr_name, ifname); | ||
76 | ifr.ifr_flags &= ~flag; | ||
77 | if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { | ||
78 | perror("SIOCSIFFLAGS"); | ||
79 | return -1; | ||
80 | } | ||
81 | return (0); | ||
82 | } | ||
83 | |||
84 | /* resolve XXX.YYY.ZZZ.QQQ -> binary */ | ||
85 | |||
86 | static int | ||
87 | INET_resolve(char *name, struct sockaddr_in *sin) | ||
88 | { | ||
89 | sin->sin_family = AF_INET; | ||
90 | sin->sin_port = 0; | ||
91 | |||
92 | /* Default is special, meaning 0.0.0.0. */ | ||
93 | if (!strcmp(name, "default")) { | ||
94 | sin->sin_addr.s_addr = INADDR_ANY; | ||
95 | return (1); | ||
96 | } | ||
97 | /* Look to see if it's a dotted quad. */ | ||
98 | if (inet_aton(name, &sin->sin_addr)) { | ||
99 | return 0; | ||
100 | } | ||
101 | /* guess not.. */ | ||
102 | return -1; | ||
103 | } | ||
104 | |||
105 | /* Input an Ethernet address and convert to binary. */ | ||
106 | static int | ||
107 | in_ether(char *bufp, struct sockaddr *sap) | ||
108 | { | ||
109 | unsigned char *ptr; | ||
110 | char c, *orig; | ||
111 | int i; | ||
112 | unsigned val; | ||
113 | |||
114 | sap->sa_family = ARPHRD_ETHER; | ||
115 | ptr = sap->sa_data; | ||
116 | |||
117 | i = 0; | ||
118 | orig = bufp; | ||
119 | while ((*bufp != '\0') && (i < ETH_ALEN)) { | ||
120 | val = 0; | ||
121 | c = *bufp++; | ||
122 | if (isdigit(c)) | ||
123 | val = c - '0'; | ||
124 | else if (c >= 'a' && c <= 'f') | ||
125 | val = c - 'a' + 10; | ||
126 | else if (c >= 'A' && c <= 'F') | ||
127 | val = c - 'A' + 10; | ||
128 | else { | ||
129 | #ifdef DEBUG | ||
130 | fprintf(stderr, | ||
131 | _("in_ether(%s): invalid ether address!\n"), | ||
132 | orig); | ||
133 | #endif | ||
134 | errno = EINVAL; | ||
135 | return (-1); | ||
136 | } | ||
137 | val <<= 4; | ||
138 | c = *bufp; | ||
139 | if (isdigit(c)) | ||
140 | val |= c - '0'; | ||
141 | else if (c >= 'a' && c <= 'f') | ||
142 | val |= c - 'a' + 10; | ||
143 | else if (c >= 'A' && c <= 'F') | ||
144 | val |= c - 'A' + 10; | ||
145 | else if (c == ':' || c == 0) | ||
146 | val >>= 4; | ||
147 | else { | ||
148 | #ifdef DEBUG | ||
149 | fprintf(stderr, | ||
150 | _("in_ether(%s): invalid ether address!\n"), | ||
151 | orig); | ||
152 | #endif | ||
153 | errno = EINVAL; | ||
154 | return (-1); | ||
155 | } | ||
156 | if (c != 0) | ||
157 | bufp++; | ||
158 | *ptr++ = (unsigned char) (val & 0377); | ||
159 | i++; | ||
160 | |||
161 | /* We might get a semicolon here - not required. */ | ||
162 | if (*bufp == ':') | ||
163 | bufp++; | ||
164 | |||
165 | } | ||
166 | |||
167 | if(i != ETH_ALEN) { | ||
168 | errno = EINVAL; | ||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int ifconfig_main(int argc, char **argv) | ||
176 | { | ||
177 | struct ifreq ifr; | ||
178 | struct sockaddr_in sa; | ||
179 | struct sockaddr sa2; | ||
180 | char **spp; | ||
181 | int goterr = 0; | ||
182 | int r, didnetmask = 0; | ||
183 | char host[128]; | ||
184 | |||
185 | if(argc < 2) { | ||
186 | usage(ifconfig_usage); | ||
187 | } | ||
188 | |||
189 | /* Create a channel to the NET kernel. */ | ||
190 | if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | ||
191 | perror("socket"); | ||
192 | exit(1); | ||
193 | } | ||
194 | |||
195 | /* skip argv[0] */ | ||
196 | |||
197 | argc--; | ||
198 | argv++; | ||
199 | |||
200 | spp = argv; | ||
201 | |||
202 | /* get interface name */ | ||
203 | |||
204 | safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ); | ||
205 | |||
206 | /* Process the remaining arguments. */ | ||
207 | while (*spp != (char *) NULL) { | ||
208 | if (!strcmp(*spp, "arp")) { | ||
209 | goterr |= clr_flag(ifr.ifr_name, IFF_NOARP); | ||
210 | spp++; | ||
211 | continue; | ||
212 | } | ||
213 | if (!strcmp(*spp, "-arp")) { | ||
214 | goterr |= set_flag(ifr.ifr_name, IFF_NOARP); | ||
215 | spp++; | ||
216 | continue; | ||
217 | } | ||
218 | |||
219 | if (!strcmp(*spp, "trailers")) { | ||
220 | goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS); | ||
221 | spp++; | ||
222 | continue; | ||
223 | } | ||
224 | if (!strcmp(*spp, "-trailers")) { | ||
225 | goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS); | ||
226 | spp++; | ||
227 | continue; | ||
228 | } | ||
229 | if (!strcmp(*spp, "promisc")) { | ||
230 | goterr |= set_flag(ifr.ifr_name, IFF_PROMISC); | ||
231 | spp++; | ||
232 | continue; | ||
233 | } | ||
234 | if (!strcmp(*spp, "-promisc")) { | ||
235 | goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC); | ||
236 | spp++; | ||
237 | continue; | ||
238 | } | ||
239 | if (!strcmp(*spp, "multicast")) { | ||
240 | goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST); | ||
241 | spp++; | ||
242 | continue; | ||
243 | } | ||
244 | if (!strcmp(*spp, "-multicast")) { | ||
245 | goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST); | ||
246 | spp++; | ||
247 | continue; | ||
248 | } | ||
249 | if (!strcmp(*spp, "allmulti")) { | ||
250 | goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI); | ||
251 | spp++; | ||
252 | continue; | ||
253 | } | ||
254 | if (!strcmp(*spp, "-allmulti")) { | ||
255 | goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI); | ||
256 | spp++; | ||
257 | continue; | ||
258 | } | ||
259 | if (!strcmp(*spp, "up")) { | ||
260 | goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING)); | ||
261 | spp++; | ||
262 | continue; | ||
263 | } | ||
264 | if (!strcmp(*spp, "down")) { | ||
265 | goterr |= clr_flag(ifr.ifr_name, IFF_UP); | ||
266 | spp++; | ||
267 | continue; | ||
268 | } | ||
269 | |||
270 | if (!strcmp(*spp, "metric")) { | ||
271 | if (*++spp == NULL) | ||
272 | usage(ifconfig_usage); | ||
273 | ifr.ifr_metric = atoi(*spp); | ||
274 | if (ioctl(sockfd, SIOCSIFMETRIC, &ifr) < 0) { | ||
275 | fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno)); | ||
276 | goterr++; | ||
277 | } | ||
278 | spp++; | ||
279 | continue; | ||
280 | } | ||
281 | if (!strcmp(*spp, "mtu")) { | ||
282 | if (*++spp == NULL) | ||
283 | usage(ifconfig_usage); | ||
284 | ifr.ifr_mtu = atoi(*spp); | ||
285 | if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) { | ||
286 | fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno)); | ||
287 | goterr++; | ||
288 | } | ||
289 | spp++; | ||
290 | continue; | ||
291 | } | ||
292 | #ifdef SIOCSKEEPALIVE | ||
293 | if (!strcmp(*spp, "keepalive")) { | ||
294 | if (*++spp == NULL) | ||
295 | usage(ifconfig_usage); | ||
296 | ifr.ifr_data = (caddr_t) atoi(*spp); | ||
297 | if (ioctl(sockfd, SIOCSKEEPALIVE, &ifr) < 0) { | ||
298 | fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno)); | ||
299 | goterr++; | ||
300 | } | ||
301 | spp++; | ||
302 | continue; | ||
303 | } | ||
304 | #endif | ||
305 | |||
306 | #ifdef SIOCSOUTFILL | ||
307 | if (!strcmp(*spp, "outfill")) { | ||
308 | if (*++spp == NULL) | ||
309 | usage(ifconfig_usage); | ||
310 | ifr.ifr_data = (caddr_t) atoi(*spp); | ||
311 | if (ioctl(sockfd, SIOCSOUTFILL, &ifr) < 0) { | ||
312 | fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno)); | ||
313 | goterr++; | ||
314 | } | ||
315 | spp++; | ||
316 | continue; | ||
317 | } | ||
318 | #endif | ||
319 | |||
320 | if (!strcmp(*spp, "-broadcast")) { | ||
321 | goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST); | ||
322 | spp++; | ||
323 | continue; | ||
324 | } | ||
325 | if (!strcmp(*spp, "broadcast")) { | ||
326 | if (*++spp != NULL) { | ||
327 | safe_strncpy(host, *spp, (sizeof host)); | ||
328 | if (INET_resolve(host, &sa) < 0) { | ||
329 | goterr++; | ||
330 | spp++; | ||
331 | continue; | ||
332 | } | ||
333 | memcpy((char *) &ifr.ifr_broadaddr, | ||
334 | (char *) &sa, | ||
335 | sizeof(struct sockaddr)); | ||
336 | if (ioctl(sockfd, SIOCSIFBRDADDR, &ifr) < 0) { | ||
337 | perror("SIOCSIFBRDADDR"); | ||
338 | goterr++; | ||
339 | } | ||
340 | spp++; | ||
341 | } | ||
342 | goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST); | ||
343 | continue; | ||
344 | } | ||
345 | if (!strcmp(*spp, "dstaddr")) { | ||
346 | if (*++spp == NULL) | ||
347 | usage(ifconfig_usage); | ||
348 | safe_strncpy(host, *spp, (sizeof host)); | ||
349 | if (INET_resolve(host, &sa) < 0) { | ||
350 | goterr++; | ||
351 | spp++; | ||
352 | continue; | ||
353 | } | ||
354 | memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa, | ||
355 | sizeof(struct sockaddr)); | ||
356 | if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) { | ||
357 | fprintf(stderr, "SIOCSIFDSTADDR: %s\n", | ||
358 | strerror(errno)); | ||
359 | goterr++; | ||
360 | } | ||
361 | spp++; | ||
362 | continue; | ||
363 | } | ||
364 | if (!strcmp(*spp, "netmask")) { | ||
365 | if (*++spp == NULL || didnetmask) | ||
366 | usage(ifconfig_usage); | ||
367 | safe_strncpy(host, *spp, (sizeof host)); | ||
368 | if (INET_resolve(host, &sa) < 0) { | ||
369 | goterr++; | ||
370 | spp++; | ||
371 | continue; | ||
372 | } | ||
373 | didnetmask++; | ||
374 | memcpy((char *) &ifr.ifr_netmask, (char *) &sa, | ||
375 | sizeof(struct sockaddr)); | ||
376 | if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { | ||
377 | perror("SIOCSIFNETMASK"); | ||
378 | goterr++; | ||
379 | } | ||
380 | spp++; | ||
381 | continue; | ||
382 | } | ||
383 | |||
384 | if (!strcmp(*spp, "-pointopoint")) { | ||
385 | goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT); | ||
386 | spp++; | ||
387 | continue; | ||
388 | } | ||
389 | if (!strcmp(*spp, "pointopoint")) { | ||
390 | if (*(spp + 1) != NULL) { | ||
391 | spp++; | ||
392 | safe_strncpy(host, *spp, (sizeof host)); | ||
393 | if (INET_resolve(host, &sa)) { | ||
394 | goterr++; | ||
395 | spp++; | ||
396 | continue; | ||
397 | } | ||
398 | memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa, | ||
399 | sizeof(struct sockaddr)); | ||
400 | if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) { | ||
401 | perror("SIOCSIFDSTADDR"); | ||
402 | goterr++; | ||
403 | } | ||
404 | } | ||
405 | goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT); | ||
406 | spp++; | ||
407 | continue; | ||
408 | }; | ||
409 | |||
410 | if (!strcmp(*spp, "hw")) { | ||
411 | if (*++spp == NULL || strcmp("ether", *spp)) { | ||
412 | usage(ifconfig_usage); | ||
413 | } | ||
414 | |||
415 | if (*++spp == NULL) { | ||
416 | /* silently ignore it if no address */ | ||
417 | continue; | ||
418 | } | ||
419 | |||
420 | safe_strncpy(host, *spp, (sizeof host)); | ||
421 | if (in_ether(host, &sa2) < 0) { | ||
422 | fprintf(stderr, "invalid hw-addr %s\n", host); | ||
423 | goterr++; | ||
424 | spp++; | ||
425 | continue; | ||
426 | } | ||
427 | memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa2, | ||
428 | sizeof(struct sockaddr)); | ||
429 | if (ioctl(sockfd, SIOCSIFHWADDR, &ifr) < 0) { | ||
430 | perror("SIOCSIFHWADDR"); | ||
431 | goterr++; | ||
432 | } | ||
433 | spp++; | ||
434 | continue; | ||
435 | } | ||
436 | |||
437 | /* If the next argument is a valid hostname, assume OK. */ | ||
438 | safe_strncpy(host, *spp, (sizeof host)); | ||
439 | |||
440 | if (INET_resolve(host, &sa) < 0) { | ||
441 | usage(ifconfig_usage); | ||
442 | } | ||
443 | memcpy((char *) &ifr.ifr_addr, | ||
444 | (char *) &sa, sizeof(struct sockaddr)); | ||
445 | |||
446 | r = ioctl(sockfd, SIOCSIFADDR, &ifr); | ||
447 | |||
448 | if (r < 0) { | ||
449 | perror("SIOCSIFADDR"); | ||
450 | goterr++; | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Don't do the set_flag() if the address is an alias with a - at the | ||
455 | * end, since it's deleted already! - Roman | ||
456 | * | ||
457 | * Should really use regex.h here, not sure though how well it'll go | ||
458 | * with the cross-platform support etc. | ||
459 | */ | ||
460 | { | ||
461 | char *ptr; | ||
462 | short int found_colon = 0; | ||
463 | for (ptr = ifr.ifr_name; *ptr; ptr++ ) | ||
464 | if (*ptr == ':') found_colon++; | ||
465 | |||
466 | if (!(found_colon && *(ptr - 1) == '-')) | ||
467 | goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING)); | ||
468 | } | ||
469 | |||
470 | spp++; | ||
471 | |||
472 | } /* end of while-loop */ | ||
473 | |||
474 | exit(0); | ||
475 | } | ||
476 | |||