blob: 2a50a96056bea63e2bf7bf5d194ad565ae37c99e [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 Andersenf15d4da2001-03-06 00:48:59 +000018 * $Id: ifconfig.c,v 1.4 2001/03/06 00:48:59 andersen Exp $
19 *
20 * Majorly hacked up by Larry Doolittle <ldoolitt@recycle.lbl.gov>
Eric Andersenec455952001-02-14 08:11:27 +000021 *
22 */
23
Eric Andersenf15d4da2001-03-06 00:48:59 +000024#include "busybox.h"
25#include <sys/types.h>
Eric Andersenec455952001-02-14 08:11:27 +000026#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <string.h> // strcmp and friends
30#include <ctype.h> // isdigit and friends
31#include <sys/socket.h>
32#include <sys/ioctl.h>
33#include <netinet/in.h>
34#include <arpa/inet.h>
35#include <net/if.h>
36#include <net/if_arp.h>
37#include <linux/if_ether.h>
38
39static int sockfd; /* socket fd we use to manipulate stuff with */
40
Eric Andersenf15d4da2001-03-06 00:48:59 +000041#define TESTME 0
42#if TESTME
43#define ioctl test_ioctl
44char *saddr_to_a(struct sockaddr *s)
45{
46 if (s->sa_family == ARPHRD_ETHER) {
47 static char hw[18];
48 sprintf(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
49 s->sa_data[0], s->sa_data[1], s->sa_data[2],
50 s->sa_data[3], s->sa_data[4], s->sa_data[5]);
51 return hw;
52 } else if (s->sa_family == AF_INET) {
53 struct sockaddr_in *ss = (struct sockaddr_in *) s;
54 return inet_ntoa(ss->sin_addr);
55 } else {
56 return NULL;
57 }
58}
59
60int test_ioctl(int __fd, unsigned long int __request, void *param)
61{
62 struct ifreq *i=(struct ifreq *)param;
63 printf("ioctl fd=%d, request=%ld\n", __fd, __request);
64
65 switch(__request) {
66 case SIOCGIFFLAGS: printf(" SIOCGIFFLAGS\n"); i->ifr_flags = 0; break;
67 case SIOCSIFFLAGS: printf(" SIOCSIFFLAGS, %x\n", i->ifr_flags); break;
68 case SIOCSIFMETRIC: printf(" SIOCSIFMETRIC, %d\n", i->ifr_metric); break;
69 case SIOCSIFMTU: printf(" SIOCSIFMTU, %d\n", i->ifr_mtu); break;
70 case SIOCSIFBRDADDR: printf(" SIOCSIFBRDADDR, %s\n", saddr_to_a(&(i->ifr_broadaddr))); break;
71 case SIOCSIFDSTADDR: printf(" SIOCSIFDSTADDR, %s\n", saddr_to_a(&(i->ifr_dstaddr ))); break;
72 case SIOCSIFNETMASK: printf(" SIOCSIFNETMASK, %s\n", saddr_to_a(&(i->ifr_netmask ))); break;
73 case SIOCSIFADDR: printf(" SIOCSIFADDR, %s\n", saddr_to_a(&(i->ifr_addr ))); break;
74 case SIOCSIFHWADDR: printf(" SIOCSIFHWADDR, %s\n", saddr_to_a(&(i->ifr_hwaddr ))); break; /* broken */
75 default:
76 }
77 return 0;
78}
79#endif
80
81
Eric Andersenec455952001-02-14 08:11:27 +000082/* print usage and exit */
83
84#define _(x) x
85
86/* Set a certain interface flag. */
87static int
88set_flag(char *ifname, short flag)
89{
90 struct ifreq ifr;
91
92 strcpy(ifr.ifr_name, ifname);
93 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
94 perror("SIOCGIFFLAGS");
Eric Andersenf15d4da2001-03-06 00:48:59 +000095 return -1;
Eric Andersenec455952001-02-14 08:11:27 +000096 }
97 strcpy(ifr.ifr_name, ifname);
98 ifr.ifr_flags |= flag;
99 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
100 perror("SIOCSIFFLAGS");
101 return -1;
102 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000103 return 0;
Eric Andersenec455952001-02-14 08:11:27 +0000104}
105
106
107/* Clear a certain interface flag. */
108static int
109clr_flag(char *ifname, short flag)
110{
111 struct ifreq ifr;
112
113 strcpy(ifr.ifr_name, ifname);
114 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
115 perror("SIOCGIFFLAGS");
116 return -1;
117 }
118 strcpy(ifr.ifr_name, ifname);
119 ifr.ifr_flags &= ~flag;
120 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
121 perror("SIOCSIFFLAGS");
122 return -1;
123 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000124 return 0;
Eric Andersenec455952001-02-14 08:11:27 +0000125}
126
Eric Andersenf15d4da2001-03-06 00:48:59 +0000127/* which element in struct ifreq to frob */
128enum frob {
129 L_METRIC,
130 L_MTU,
131 L_DATA,
132 L_BROAD,
133 L_DEST,
134 L_MASK,
135 L_HWAD,
136};
137
138
139struct flag_map {
140 char *name;
141 enum frob frob;
142 int flag;
143 int sflag;
144 int action;
145};
146
147/* action:
148 * 2 set
149 * 4 clear
150 * 6 set/clear
151 * 8 clear/set
152 * 10 numeric
153 * 12 address
154 * 14 address/clear
155 */
156const static struct flag_map flag_table[] = {
157 {"arp", 0, IFF_NOARP, 0, 6},
158 {"trailers", 0, IFF_NOTRAILERS, 0, 6},
159 {"promisc", 0, IFF_PROMISC, 0, 8},
160 {"multicast", 0, IFF_MULTICAST, 0, 8},
161 {"allmulti", 0, IFF_ALLMULTI, 0, 8},
162 {"up", 0, (IFF_UP | IFF_RUNNING), 0, 2},
163 {"down", 0, IFF_UP, 0, 4},
164 {"metric", L_METRIC, 0, SIOCSIFMETRIC, 10},
165 {"mtu", L_MTU, 0, SIOCSIFMTU, 10},
166#ifdef SIOCSKEEPALIVE
167 {"keepalive", L_DATA, 0, SIOCSKEEPALIVE, 10},
168#endif
169#ifdef SIOCSOUTFILL
170 {"outfill", L_DATA, 0, SIOCSOUTFILL, 10},
171#endif
172 {"broadcast", L_BROAD, IFF_BROADCAST, SIOCSIFBRDADDR, 14},
173 {"dstaddr", L_DEST, 0, SIOCSIFDSTADDR, 12},
174 {"netmask", L_MASK, 0, SIOCSIFNETMASK, 12},
175 {"pointopoint", L_DEST, IFF_POINTOPOINT, SIOCSIFDSTADDR, 14},
176 {"hw", L_HWAD, 0, SIOCSIFHWADDR, 14},
177};
178
179
Eric Andersenec455952001-02-14 08:11:27 +0000180/* resolve XXX.YYY.ZZZ.QQQ -> binary */
181
182static int
183INET_resolve(char *name, struct sockaddr_in *sin)
184{
185 sin->sin_family = AF_INET;
186 sin->sin_port = 0;
187
188 /* Default is special, meaning 0.0.0.0. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000189 if (strcmp(name, "default")==0) {
Eric Andersenec455952001-02-14 08:11:27 +0000190 sin->sin_addr.s_addr = INADDR_ANY;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000191 return 1;
Eric Andersenec455952001-02-14 08:11:27 +0000192 }
193 /* Look to see if it's a dotted quad. */
194 if (inet_aton(name, &sin->sin_addr)) {
195 return 0;
196 }
197 /* guess not.. */
Eric Andersenf15d4da2001-03-06 00:48:59 +0000198 errno = EINVAL;
Eric Andersenec455952001-02-14 08:11:27 +0000199 return -1;
200}
201
202/* Input an Ethernet address and convert to binary. */
203static int
204in_ether(char *bufp, struct sockaddr *sap)
205{
206 unsigned char *ptr;
207 char c, *orig;
208 int i;
209 unsigned val;
210
211 sap->sa_family = ARPHRD_ETHER;
212 ptr = sap->sa_data;
213
214 i = 0;
215 orig = bufp;
216 while ((*bufp != '\0') && (i < ETH_ALEN)) {
217 val = 0;
218 c = *bufp++;
219 if (isdigit(c))
220 val = c - '0';
221 else if (c >= 'a' && c <= 'f')
222 val = c - 'a' + 10;
223 else if (c >= 'A' && c <= 'F')
224 val = c - 'A' + 10;
225 else {
226#ifdef DEBUG
Eric Andersenf15d4da2001-03-06 00:48:59 +0000227 error_msg(
228 _("in_ether(%s): invalid ether address!"),
Eric Andersenec455952001-02-14 08:11:27 +0000229 orig);
230#endif
231 errno = EINVAL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000232 return -1;
Eric Andersenec455952001-02-14 08:11:27 +0000233 }
234 val <<= 4;
235 c = *bufp;
236 if (isdigit(c))
237 val |= c - '0';
238 else if (c >= 'a' && c <= 'f')
239 val |= c - 'a' + 10;
240 else if (c >= 'A' && c <= 'F')
241 val |= c - 'A' + 10;
242 else if (c == ':' || c == 0)
243 val >>= 4;
244 else {
245#ifdef DEBUG
Eric Andersenf15d4da2001-03-06 00:48:59 +0000246 error_msg(
247 _("in_ether(%s): invalid ether address!"),
Eric Andersenec455952001-02-14 08:11:27 +0000248 orig);
249#endif
250 errno = EINVAL;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000251 return -1;
Eric Andersenec455952001-02-14 08:11:27 +0000252 }
253 if (c != 0)
254 bufp++;
255 *ptr++ = (unsigned char) (val & 0377);
256 i++;
257
Eric Andersenf15d4da2001-03-06 00:48:59 +0000258 /* optional colon already handled, don't swallow a second */
Eric Andersenec455952001-02-14 08:11:27 +0000259 }
260
261 if(i != ETH_ALEN) {
262 errno = EINVAL;
263 return -1;
264 }
265
266 return 0;
267}
Eric Andersenf15d4da2001-03-06 00:48:59 +0000268
269#ifdef BB_FEATURE_IFCONFIG_STATUS
270extern int display_interfaces(void);
271#else
272int display_interfaces(void)
273{
274 show_usage();
275}
276#endif
Eric Andersenec455952001-02-14 08:11:27 +0000277
278int ifconfig_main(int argc, char **argv)
279{
280 struct ifreq ifr;
281 struct sockaddr_in sa;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000282 char **spp, *cmd;
Eric Andersenec455952001-02-14 08:11:27 +0000283 int goterr = 0;
Eric Andersenf15d4da2001-03-06 00:48:59 +0000284 int r;
285 /* int didnetmask = 0; special case input error detection no longer implemented */
Eric Andersenec455952001-02-14 08:11:27 +0000286 char host[128];
Eric Andersenf15d4da2001-03-06 00:48:59 +0000287 const struct flag_map *ft;
288 int i, sense;
289 int a, ecode;
290 struct sockaddr *d;
Eric Andersenec455952001-02-14 08:11:27 +0000291
292 if(argc < 2) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000293 return(display_interfaces());
Eric Andersenec455952001-02-14 08:11:27 +0000294 }
295
296 /* Create a channel to the NET kernel. */
297 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000298 perror_msg_and_die("socket");
Eric Andersenec455952001-02-14 08:11:27 +0000299 }
300
301 /* skip argv[0] */
302
303 argc--;
304 argv++;
305
306 spp = argv;
307
308 /* get interface name */
309
310 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
311
312 /* Process the remaining arguments. */
313 while (*spp != (char *) NULL) {
Eric Andersenf15d4da2001-03-06 00:48:59 +0000314 cmd = *spp;
315 sense=0;
316 if (*cmd=='-') {
317 sense=1;
318 cmd++;
Eric Andersenec455952001-02-14 08:11:27 +0000319 }
Eric Andersenf15d4da2001-03-06 00:48:59 +0000320 ft = NULL;
321 for (i=0; i<(sizeof(flag_table)/sizeof(struct flag_map)); i++) {
322 if (strcmp(cmd, flag_table[i].name)==0) {
323 ft=flag_table+i;
324 spp++;
325 break;
326 }
327 }
328 if (ft) {
329 switch (ft->action+sense) {
330 case 4:
331 case 7:
332 case 8:
333 case 15:
334 goterr |= clr_flag(ifr.ifr_name, ft->flag);
335 break;
336 case 2:
337 case 6:
338 case 9:
339 goterr |= set_flag(ifr.ifr_name, ft->flag);
340 break;
341 case 10:
342 if (*spp == NULL)
343 show_usage();
344 a = atoi(*spp++);
345 switch (ft->frob) {
346 case L_METRIC: ifr.ifr_metric = a; break;
347 case L_MTU: ifr.ifr_mtu = a; break;
348 case L_DATA: ifr.ifr_data = (caddr_t) a; break;
349 default: error_msg_and_die("bugaboo");
350 }
351
352 if (ioctl(sockfd, ft->sflag, &ifr) < 0) {
353 perror(ft->name); /* imperfect */
354 goterr++;
355 }
356 break;
357 case 12:
358 case 14:
359 if (ft->action+sense==10 && *spp == NULL) {
360 show_usage();
361 break;
362 }
363 if (*spp != NULL) {
364 safe_strncpy(host, *spp, (sizeof host));
365 spp++;
366 if (ft->frob == L_HWAD) {
367 ecode = in_ether(host, &ifr.ifr_hwaddr);
368 } else {
369 switch (ft->frob) {
370 case L_BROAD: d = &ifr.ifr_broadaddr; break;
371 case L_DEST: d = &ifr.ifr_dstaddr; break;
372 case L_MASK: d = &ifr.ifr_netmask; break;
373 default: error_msg_and_die("bugaboo");
374 }
375 ecode = INET_resolve(host, (struct sockaddr_in *) d);
376 }
377 if (ecode < 0 || ioctl(sockfd, ft->sflag, &ifr) < 0) {
378 perror(ft->name); /* imperfect */
379 goterr++;
380 }
381 }
382 if (ft->flag != 0) {
383 goterr |= set_flag(ifr.ifr_name, ft->flag);
384 }
385 break;
386 default:
387 show_usage();
388 } /* end of switch */
Eric Andersenec455952001-02-14 08:11:27 +0000389 continue;
390 }
391
Eric Andersenec455952001-02-14 08:11:27 +0000392 /* If the next argument is a valid hostname, assume OK. */
393 safe_strncpy(host, *spp, (sizeof host));
394
395 if (INET_resolve(host, &sa) < 0) {
Eric Andersen67991cf2001-02-14 21:23:06 +0000396 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000397 }
398 memcpy((char *) &ifr.ifr_addr,
399 (char *) &sa, sizeof(struct sockaddr));
400
401 r = ioctl(sockfd, SIOCSIFADDR, &ifr);
402
403 if (r < 0) {
404 perror("SIOCSIFADDR");
405 goterr++;
406 }
407
408 /*
409 * Don't do the set_flag() if the address is an alias with a - at the
410 * end, since it's deleted already! - Roman
411 *
412 * Should really use regex.h here, not sure though how well it'll go
413 * with the cross-platform support etc.
414 */
415 {
416 char *ptr;
417 short int found_colon = 0;
418 for (ptr = ifr.ifr_name; *ptr; ptr++ )
419 if (*ptr == ':') found_colon++;
420
421 if (!(found_colon && *(ptr - 1) == '-'))
422 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
423 }
424
425 spp++;
426
427 } /* end of while-loop */
428
Eric Andersenf15d4da2001-03-06 00:48:59 +0000429 return goterr;
Eric Andersenec455952001-02-14 08:11:27 +0000430}
431