blob: a3e2c0fdbb7da0a40f6e86896b05a2f2d76f5dbb [file] [log] [blame]
Eric Andersenec455952001-02-14 08:11:27 +00001/* 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 *
Eric Andersencbe31da2001-02-20 06:14:08 +000018 * $Id: ifconfig.c,v 1.3 2001/02/20 06:14:07 andersen Exp $
Eric Andersenec455952001-02-14 08:11:27 +000019 *
20 */
21
Eric Andersenec455952001-02-14 08:11:27 +000022#include <stdio.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <string.h> // strcmp and friends
26#include <ctype.h> // isdigit and friends
Eric Andersencbe31da2001-02-20 06:14:08 +000027#include <sys/types.h>
Eric Andersenec455952001-02-14 08:11:27 +000028#include <sys/socket.h>
29#include <sys/ioctl.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <net/if.h>
33#include <net/if_arp.h>
34#include <linux/if_ether.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000035#include "busybox.h"
Eric Andersenec455952001-02-14 08:11:27 +000036
37static 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. */
44static int
45set_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. */
65static int
66clr_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
86static int
87INET_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. */
106static int
107in_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
175int 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) {
Eric Andersen67991cf2001-02-14 21:23:06 +0000186 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000187 }
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)
Eric Andersen67991cf2001-02-14 21:23:06 +0000272 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000273 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)
Eric Andersen67991cf2001-02-14 21:23:06 +0000283 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000284 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)
Eric Andersen67991cf2001-02-14 21:23:06 +0000295 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000296 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)
Eric Andersen67991cf2001-02-14 21:23:06 +0000309 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000310 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)
Eric Andersen67991cf2001-02-14 21:23:06 +0000347 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000348 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)
Eric Andersen67991cf2001-02-14 21:23:06 +0000366 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000367 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)) {
Eric Andersen67991cf2001-02-14 21:23:06 +0000412 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000413 }
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) {
Eric Andersen67991cf2001-02-14 21:23:06 +0000441 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000442 }
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