1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99#include "libbb.h"
100#include "inet_common.h"
101#include <net/if.h>
102#include <net/if_arp.h>
103#include <netinet/in.h>
104#ifdef HAVE_NET_ETHERNET_H
105# include <net/ethernet.h>
106#endif
107
108#if ENABLE_FEATURE_IFCONFIG_SLIP
109# include <linux/if_slip.h>
110#endif
111
112
113#define QUESTIONABLE_ALIAS_CASE
114
115
116
117#ifndef SIOCSIFTXQLEN
118# define SIOCSIFTXQLEN 0x8943
119# define SIOCGIFTXQLEN 0x8942
120#endif
121
122
123#ifndef ifr_qlen
124# define ifr_qlen ifr_ifru.ifru_mtu
125#endif
126
127#ifndef IFF_DYNAMIC
128# define IFF_DYNAMIC 0x8000
129#endif
130
131#if ENABLE_FEATURE_IPV6
132struct in6_ifreq {
133 struct in6_addr ifr6_addr;
134 uint32_t ifr6_prefixlen;
135 int ifr6_ifindex;
136};
137#endif
138
139
140
141
142
143
144#define N_CLR 0x01
145#define M_CLR 0x02
146#define N_SET 0x04
147#define M_SET 0x08
148#define N_ARG 0x10
149#define M_ARG 0x20
150
151#define M_MASK (M_CLR | M_SET | M_ARG)
152#define N_MASK (N_CLR | N_SET | N_ARG)
153#define SET_MASK (N_SET | M_SET)
154#define CLR_MASK (N_CLR | M_CLR)
155#define SET_CLR_MASK (SET_MASK | CLR_MASK)
156#define ARG_MASK (M_ARG | N_ARG)
157
158
159
160
161
162
163
164
165
166
167
168
169#define A_CAST_TYPE 0x03
170
171
172
173
174
175
176
177#define A_MAP_TYPE 0x0C
178#define A_ARG_REQ 0x10
179#define A_NETMASK 0x20
180#define A_SET_AFTER 0x40
181#define A_COLON_CHK 0x80
182#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
183#define A_HOSTNAME 0x100
184#define A_BROADCAST 0x200
185#else
186#define A_HOSTNAME 0
187#define A_BROADCAST 0
188#endif
189
190
191
192
193#define A_CAST_CHAR_PTR 0x01
194#define A_CAST_RESOLVE 0x01
195#define A_CAST_HOST_COPY 0x02
196#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY
197#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE)
198
199
200
201
202#define A_MAP_ULONG 0x04
203#define A_MAP_USHORT 0x08
204#define A_MAP_UCHAR 0x0C
205
206
207
208
209
210#define ARG_METRIC (A_ARG_REQ )
211#define ARG_MTU (A_ARG_REQ )
212#define ARG_TXQUEUELEN (A_ARG_REQ )
213#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG)
214#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_ULONG)
215#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR)
216#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
217#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
218#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_BROADCAST)
219#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
220#define ARG_POINTOPOINT (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
221#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
222#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
223#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK | A_HOSTNAME)
224#define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
225
226
227struct arg1opt {
228 const char *name;
229 unsigned short selector;
230 unsigned short ifr_offset;
231};
232
233struct options {
234 const char *name;
235#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
236 const unsigned int flags:6;
237 const unsigned int arg_flags:10;
238#else
239 const unsigned char flags;
240 const unsigned char arg_flags;
241#endif
242 const unsigned short selector;
243};
244
245#define ifreq_offsetof(x) offsetof(struct ifreq, x)
246
247
248
249
250
251static const struct arg1opt Arg1Opt[] = {
252 { "SIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric) },
253 { "SIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu) },
254 { "SIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen) },
255 { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) },
256 { "SIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask) },
257 { "SIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr) },
258#if ENABLE_FEATURE_IFCONFIG_HW
259 { "SIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr) },
260#endif
261 { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) },
262#ifdef SIOCSKEEPALIVE
263 { "SKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data) },
264#endif
265#ifdef SIOCSOUTFILL
266 { "SOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data) },
267#endif
268#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
269 { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start) },
270 { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr) },
271 { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq) },
272#endif
273#if ENABLE_FEATURE_IPV6
274 { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) },
275 { "DIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr) },
276#endif
277
278 { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) },
279};
280
281static const struct options OptArray[] = {
282 { "metric", N_ARG, ARG_METRIC, 0 },
283 { "mtu", N_ARG, ARG_MTU, 0 },
284 { "txqueuelen", N_ARG, ARG_TXQUEUELEN, 0 },
285 { "dstaddr", N_ARG, ARG_DSTADDR, 0 },
286 { "netmask", N_ARG, ARG_NETMASK, 0 },
287 { "broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST },
288#if ENABLE_FEATURE_IFCONFIG_HW
289 { "hw", N_ARG, ARG_HW, 0 },
290#endif
291 { "pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT },
292#ifdef SIOCSKEEPALIVE
293 { "keepalive", N_ARG, ARG_KEEPALIVE, 0 },
294#endif
295#ifdef SIOCSOUTFILL
296 { "outfill", N_ARG, ARG_OUTFILL, 0 },
297#endif
298#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
299 { "mem_start", N_ARG, ARG_MEM_START, 0 },
300 { "io_addr", N_ARG, ARG_IO_ADDR, 0 },
301 { "irq", N_ARG, ARG_IRQ, 0 },
302#endif
303#if ENABLE_FEATURE_IPV6
304 { "add", N_ARG, ARG_ADD_DEL, 0 },
305 { "del", N_ARG, ARG_ADD_DEL, 0 },
306#endif
307 { "arp", N_CLR | M_SET, 0, IFF_NOARP },
308 { "trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS },
309 { "promisc", N_SET | M_CLR, 0, IFF_PROMISC },
310 { "multicast", N_SET | M_CLR, 0, IFF_MULTICAST },
311 { "allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI },
312 { "dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC },
313 { "up", N_SET, 0, (IFF_UP | IFF_RUNNING) },
314 { "down", N_CLR, 0, IFF_UP },
315 { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING) }
316};
317
318int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
319int ifconfig_main(int argc UNUSED_PARAM, char **argv)
320{
321 struct ifreq ifr;
322 struct sockaddr_in sai;
323#if ENABLE_FEATURE_IFCONFIG_HW
324 struct sockaddr sa;
325#endif
326 const struct arg1opt *a1op;
327 const struct options *op;
328 int sockfd;
329 int selector;
330#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
331 unsigned int mask;
332 unsigned int did_flags;
333 unsigned int sai_hostname, sai_netmask;
334#else
335 unsigned char mask;
336 unsigned char did_flags;
337#endif
338 char *p;
339
340 const char *host = NULL;
341 IF_FEATURE_IFCONFIG_STATUS(char *show_all_param;)
342
343 did_flags = 0;
344#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
345 sai_hostname = 0;
346 sai_netmask = 0;
347#endif
348
349
350 ++argv;
351
352#if ENABLE_FEATURE_IFCONFIG_STATUS
353 show_all_param = NULL;
354 if (argv[0] && argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2]) {
355 ++argv;
356 show_all_param = IFNAME_SHOW_DOWNED_TOO;
357 }
358#endif
359
360 if (!argv[0] || !argv[1]) {
361#if ENABLE_FEATURE_IFCONFIG_STATUS
362 return display_interfaces(argv[0] ? argv[0] : show_all_param);
363#else
364 bb_error_msg_and_die("no support for status display");
365#endif
366 }
367
368
369 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0);
370
371
372 strncpy_IFNAMSIZ(ifr.ifr_name, *argv);
373
374
375 while (*++argv != NULL) {
376 p = *argv;
377 mask = N_MASK;
378 if (*p == '-') {
379 ++p;
380 mask = M_MASK;
381 }
382 for (op = OptArray; op->name; op++) {
383 if (strcmp(p, op->name) == 0) {
384 mask &= op->flags;
385 if (mask)
386 goto FOUND_ARG;
387
388
389 bb_error_msg_and_die("bad: '%s'", p-1);
390 }
391 }
392
393
394 a1op = Arg1Opt + ARRAY_SIZE(Arg1Opt) - 1;
395 mask = op->arg_flags;
396 goto HOSTNAME;
397
398 FOUND_ARG:
399 if (mask & ARG_MASK) {
400 mask = op->arg_flags;
401 if (mask & A_NETMASK & did_flags)
402 bb_show_usage();
403 a1op = Arg1Opt + (op - OptArray);
404 if (*++argv == NULL) {
405 if (mask & A_ARG_REQ)
406 bb_show_usage();
407 --argv;
408 mask &= A_SET_AFTER;
409 } else {
410 HOSTNAME:
411 did_flags |= (mask & (A_NETMASK|A_HOSTNAME));
412 if (mask & A_CAST_HOST_COPY) {
413#if ENABLE_FEATURE_IFCONFIG_HW
414 if (mask & A_CAST_RESOLVE) {
415#endif
416 host = *argv;
417 if (strcmp(host, "inet") == 0)
418 continue;
419 sai.sin_family = AF_INET;
420 sai.sin_port = 0;
421 if (strcmp(host, "default") == 0) {
422
423 sai.sin_addr.s_addr = INADDR_ANY;
424 }
425#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
426 else if ((host[0] == '+' && !host[1])
427 && (mask & A_BROADCAST)
428 && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)
429 ) {
430
431 sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask);
432 }
433#endif
434 else {
435 len_and_sockaddr *lsa;
436#if ENABLE_FEATURE_IPV6
437 char *prefix;
438 int prefix_len = 0;
439 prefix = strchr(host, '/');
440 if (prefix) {
441 prefix_len = xatou_range(prefix + 1, 0, 128);
442 *prefix = '\0';
443 }
444 resolve:
445#endif
446 lsa = xhost2sockaddr(host, 0);
447#if ENABLE_FEATURE_IPV6
448 if (lsa->u.sa.sa_family != AF_INET6 && prefix) {
449
450
451
452 *prefix = '/';
453 goto resolve;
454 }
455 if (lsa->u.sa.sa_family == AF_INET6) {
456 int sockfd6;
457 struct in6_ifreq ifr6;
458
459 sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0);
460 xioctl(sockfd6, SIOCGIFINDEX, &ifr);
461 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
462 ifr6.ifr6_prefixlen = prefix_len;
463 memcpy(&ifr6.ifr6_addr,
464 &lsa->u.sin6.sin6_addr,
465 sizeof(struct in6_addr));
466 ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "SIOC%s", a1op->name);
467 if (ENABLE_FEATURE_CLEAN_UP)
468 free(lsa);
469 continue;
470 }
471#endif
472 sai.sin_addr = lsa->u.sin.sin_addr;
473 if (ENABLE_FEATURE_CLEAN_UP)
474 free(lsa);
475 }
476#if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS
477 if (mask & A_HOSTNAME)
478 sai_hostname = sai.sin_addr.s_addr;
479 if (mask & A_NETMASK)
480 sai_netmask = sai.sin_addr.s_addr;
481#endif
482 p = (char *) &sai;
483#if ENABLE_FEATURE_IFCONFIG_HW
484 } else {
485
486 smalluint hw_class = index_in_substrings("ether\0"
487 IF_FEATURE_HWIB("infiniband\0"), *argv) + 1;
488 if (!hw_class || !*++argv)
489 bb_show_usage();
490 host = *argv;
491 if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa))
492 bb_error_msg_and_die("invalid hw-addr %s", host);
493 p = (char *) &sa;
494 }
495#endif
496 memcpy( ((char *)&ifr) + a1op->ifr_offset,
497 p, sizeof(struct sockaddr));
498 } else {
499
500 unsigned long i = strtoul(*argv, NULL, 0);
501 p = ((char *)&ifr) + a1op->ifr_offset;
502#if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
503 if (mask & A_MAP_TYPE) {
504 xioctl(sockfd, SIOCGIFMAP, &ifr);
505 if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR)
506 *(unsigned char *) p = i;
507 else if (mask & A_MAP_USHORT)
508 *(unsigned short *) p = i;
509 else
510 *(unsigned long *) p = i;
511 } else
512#endif
513 if (mask & A_CAST_CHAR_PTR)
514 *(caddr_t *) p = (caddr_t) i;
515 else
516 *(int *) p = i;
517 }
518
519 ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "SIOC%s", a1op->name);
520#ifdef QUESTIONABLE_ALIAS_CASE
521 if (mask & A_COLON_CHK) {
522
523
524
525
526
527
528
529 char *ptr;
530 short int found_colon = 0;
531 for (ptr = ifr.ifr_name; *ptr; ptr++)
532 if (*ptr == ':')
533 found_colon++;
534 if (found_colon && ptr[-1] == '-')
535 continue;
536 }
537#endif
538 }
539 if (!(mask & A_SET_AFTER))
540 continue;
541 mask = N_SET;
542 }
543
544 xioctl(sockfd, SIOCGIFFLAGS, &ifr);
545 selector = op->selector;
546 if (mask & SET_MASK)
547 ifr.ifr_flags |= selector;
548 else
549 ifr.ifr_flags &= ~selector;
550 xioctl(sockfd, SIOCSIFFLAGS, &ifr);
551 }
552
553 if (ENABLE_FEATURE_CLEAN_UP)
554 close(sockfd);
555 return 0;
556}
557