Mercurial > hg > toybox
comparison toys/pending/ifconfig.c @ 1128:9eaec92e3713 draft
Ifconfig cleanup.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 26 Nov 2013 19:35:22 -0600 |
parents | e0a8cbb1a5e3 |
children |
comparison
equal
deleted
inserted
replaced
1127:e0a8cbb1a5e3 | 1128:9eaec92e3713 |
---|---|
36 | 36 |
37 GLOBALS( | 37 GLOBALS( |
38 int sockfd; | 38 int sockfd; |
39 ) | 39 ) |
40 | 40 |
41 typedef struct sockaddr_with_len { | |
42 union { | |
43 struct sockaddr sock; | |
44 struct sockaddr_in sock_in; | |
45 struct sockaddr_in6 sock_in6; | |
46 } sock_u; | |
47 } sockaddr_with_len; | |
48 | |
49 //for ipv6 add/del | 41 //for ipv6 add/del |
50 struct ifreq_inet6 { | 42 struct ifreq_inet6 { |
51 struct in6_addr ifrinte6_addr; | 43 struct in6_addr ifrinte6_addr; |
52 uint32_t ifrinet6_prefixlen; | 44 uint32_t ifrinet6_prefixlen; |
53 int ifrinet6_ifindex; | 45 int ifrinet6_ifindex; |
54 }; | 46 }; |
55 | 47 |
56 /* | 48 // Convert hostname to binary address for AF_INET or AF_INET6 |
57 * use to get the socket address with the given host ip. | 49 void get_addrinfo(char *host, sa_family_t af, void *addr) |
58 */ | |
59 sockaddr_with_len *get_sockaddr(char *host, int port, sa_family_t af) | |
60 { | 50 { |
61 sockaddr_with_len *swl = NULL; | 51 struct addrinfo hints, *result, *rp = 0; |
62 in_port_t port_num = htons(port); | 52 int status, len; |
63 struct addrinfo hints, *result, *rp; | 53 char *from; |
64 int status; | |
65 char *s; | |
66 | |
67 if (!strncmp(host, "local:", 6)) { | |
68 struct sockaddr_un *sockun; | |
69 | |
70 swl = xzalloc(sizeof(struct sockaddr_with_len)); | |
71 swl->sock_u.sock.sa_family = AF_UNIX; | |
72 sockun = (struct sockaddr_un *)&swl->sock_u.sock; | |
73 xstrncpy(sockun->sun_path, host + 6, sizeof(sockun->sun_path)); | |
74 | |
75 return swl; | |
76 } | |
77 | |
78 // [ipv6]:port or exactly one : | |
79 | |
80 if (*host == '[') { | |
81 host++; | |
82 s = strchr(host, ']'); | |
83 if (s && !s[1]) s = 0; | |
84 else { | |
85 if (!s || s[1] != ':') error_exit("bad address '%s'", host-1); | |
86 s++; | |
87 } | |
88 } else { | |
89 s = strrchr(host, ':'); | |
90 if (strchr(host, ':') != s) s = 0; | |
91 } | |
92 | |
93 if (s++) { | |
94 char *ss; | |
95 unsigned long p = strtoul(s, &ss, 0); | |
96 if (*ss || p > 65535) error_exit("bad port '%s'", s); | |
97 port = p; | |
98 } | |
99 | 54 |
100 memset(&hints, 0 , sizeof(struct addrinfo)); | 55 memset(&hints, 0 , sizeof(struct addrinfo)); |
101 hints.ai_family = af; | 56 hints.ai_family = af; |
102 hints.ai_socktype = SOCK_STREAM; | 57 hints.ai_socktype = SOCK_STREAM; |
103 | 58 |
104 status = getaddrinfo(host, NULL, &hints, &result); | 59 status = getaddrinfo(host, NULL, &hints, &result); |
105 if (status) error_exit("bad address '%s' : %s", host, gai_strerror(status)); | 60 if (!status) |
106 | 61 for (rp = result; rp; rp = rp->ai_next) |
107 for (rp = result; rp; rp = rp->ai_next) { | 62 if (rp->ai_family == af) break; |
108 if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) { | 63 if (!rp) error_exit("bad address '%s' : %s", host, gai_strerror(status)); |
109 swl = xmalloc(sizeof(struct sockaddr_with_len)); | 64 |
110 memcpy(&swl->sock_u.sock, rp->ai_addr, rp->ai_addrlen); | 65 // You'd think ipv4 and ipv6 would ahve some basic compatability, but no. |
111 break; | 66 len = 4; |
112 } | 67 from = ((char *)rp->ai_addr->sa_data) + 2; |
113 } | 68 if (af == AF_INET6) { |
69 len = 16; | |
70 from += 4; | |
71 } | |
72 memcpy(addr, from, len); | |
114 freeaddrinfo(result); | 73 freeaddrinfo(result); |
115 if (!rp) error_exit("bad host name"); | |
116 | |
117 if(swl->sock_u.sock.sa_family == AF_INET) | |
118 swl->sock_u.sock_in.sin_port = port_num; | |
119 else if(swl->sock_u.sock.sa_family == AF_INET6) | |
120 swl->sock_u.sock_in6.sin6_port = port_num; | |
121 | |
122 return swl; | |
123 } | |
124 | |
125 static void set_address(char *host_name, struct ifreq *ifre, int request) | |
126 { | |
127 struct sockaddr_in *sock_in = (struct sockaddr_in *)&ifre->ifr_addr; | |
128 sockaddr_with_len *swl = NULL; | |
129 | |
130 memset(sock_in, 0, sizeof(struct sockaddr_in)); | |
131 sock_in->sin_family = AF_INET; | |
132 | |
133 //Default 0.0.0.0 | |
134 if(strcmp(host_name, "default") == 0) sock_in->sin_addr.s_addr = INADDR_ANY; | |
135 else { | |
136 swl = get_sockaddr(host_name, 0, AF_INET); | |
137 sock_in->sin_addr = swl->sock_u.sock_in.sin_addr; | |
138 free(swl); | |
139 } | |
140 xioctl(TT.sockfd, request, ifre); | |
141 } | 74 } |
142 | 75 |
143 static void display_ifconfig(char *name, int always, unsigned long long val[]) | 76 static void display_ifconfig(char *name, int always, unsigned long long val[]) |
144 { | 77 { |
145 struct ifreq ifre; | 78 struct ifreq ifre; |
272 if (!ifre.ifr_metric) ifre.ifr_metric = 1; | 205 if (!ifre.ifr_metric) ifre.ifr_metric = 1; |
273 xprintf(" Metric:%d", ifre.ifr_metric); | 206 xprintf(" Metric:%d", ifre.ifr_metric); |
274 | 207 |
275 // non-virtual interface | 208 // non-virtual interface |
276 | 209 |
277 if(val) { | 210 if (val) { |
278 char *label[] = {"RX bytes", "RX packets", "errors", "dropped", "overruns", | 211 char *label[] = {"RX bytes", "RX packets", "errors", "dropped", "overruns", |
279 "frame", 0, 0, "TX bytes", "TX packets", "errors", "dropped", "overruns", | 212 "frame", 0, 0, "TX bytes", "TX packets", "errors", "dropped", "overruns", |
280 "collisions", "carrier", 0, "txqueuelen"}; | 213 "collisions", "carrier", 0, "txqueuelen"}; |
281 signed char order[] = {-1, 1, 2, 3, 4, 5, -1, 9, 10, 11, 12, 14, -1, | 214 signed char order[] = {-1, 1, 2, 3, 4, 5, -1, 9, 10, 11, 12, 14, -1, |
282 13, 16, -1, 0, 8}; | 215 13, 16, -1, 0, 8}; |
343 sl = xmalloc(sizeof(*sl)+strlen(name)+1); | 276 sl = xmalloc(sizeof(*sl)+strlen(name)+1); |
344 strcpy(sl->str, name); | 277 strcpy(sl->str, name); |
345 sl->next = ifaces; | 278 sl->next = ifaces; |
346 ifaces = sl; | 279 ifaces = sl; |
347 | 280 |
348 display_ifconfig(name, toys.optflags & FLAG_a, val); | 281 display_ifconfig(sl->str, toys.optflags & FLAG_a, val); |
349 } | 282 } |
350 } | 283 } |
351 fclose(fp); | 284 fclose(fp); |
352 | 285 |
353 if (iface_name) display_ifconfig(iface_name, 1, 0); | 286 if (iface_name) display_ifconfig(iface_name, 1, 0); |
388 { | 321 { |
389 char **argv = toys.optargs; | 322 char **argv = toys.optargs; |
390 struct ifreq ifre; | 323 struct ifreq ifre; |
391 int i; | 324 int i; |
392 | 325 |
393 if(*argv && (strcmp(*argv, "--help") == 0)) show_help(); | |
394 | |
395 TT.sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); | 326 TT.sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); |
396 if(toys.optc < 2) { | 327 if(toys.optc < 2) { |
397 show_iface(*argv); | 328 show_iface(*argv); |
398 return; | 329 return; |
399 } | 330 } |
402 memset(&ifre, 0, sizeof(struct ifreq)); | 333 memset(&ifre, 0, sizeof(struct ifreq)); |
403 xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ); | 334 xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ); |
404 | 335 |
405 // Perform operations on interface | 336 // Perform operations on interface |
406 while(*++argv) { | 337 while(*++argv) { |
338 // Table of known operations | |
407 struct argh { | 339 struct argh { |
408 char *name; | 340 char *name; |
409 int on, off; // set, clear | 341 int on, off; // set, clear |
410 } try[] = { | 342 } try[] = { |
343 {0, IFF_UP|IFF_RUNNING, SIOCSIFADDR}, | |
411 {"up", IFF_UP|IFF_RUNNING, 0}, | 344 {"up", IFF_UP|IFF_RUNNING, 0}, |
412 {"down", 0, IFF_UP}, | 345 {"down", 0, IFF_UP}, |
413 {"arp", 0, IFF_NOARP}, | 346 {"arp", 0, IFF_NOARP}, |
414 {"trailers", 0, IFF_NOTRAILERS}, | 347 {"trailers", 0, IFF_NOTRAILERS}, |
415 {"promisc", IFF_PROMISC, 0}, | 348 {"promisc", IFF_PROMISC, 0}, |
434 char *s = *argv; | 367 char *s = *argv; |
435 int rev = (*s == '-'); | 368 int rev = (*s == '-'); |
436 | 369 |
437 s += rev; | 370 s += rev; |
438 | 371 |
439 for (i = 0; i < sizeof(try)/sizeof(*try); i++) { | 372 // "set hardware address" is oddball enough to special case |
373 if (!strcmp(*argv, "hw")) { | |
374 char *hw_addr, *ptr, *p; | |
375 struct sockaddr *sock = &ifre.ifr_hwaddr; | |
376 int count = 6; | |
377 | |
378 ptr = p = (char *)sock->sa_data; | |
379 memset(sock, 0, sizeof(struct sockaddr)); | |
380 if (!argv[1]) { | |
381 if (!strcmp("ether", *++argv)) sock->sa_family = ARPHRD_ETHER; | |
382 else if (!strcmp("infiniband", *argv)) { | |
383 sock->sa_family = ARPHRD_INFINIBAND; | |
384 count = 20; | |
385 p = ptr = toybuf; | |
386 } | |
387 } | |
388 if (!sock->sa_family || !argv[1]) { | |
389 toys.exithelp++; | |
390 error_exit("bad hw '%s'", *argv); | |
391 } | |
392 hw_addr = *++argv; | |
393 | |
394 // Parse and verify address. | |
395 while (*hw_addr && (p-ptr) < count) { | |
396 int val, len = 0; | |
397 | |
398 if (*hw_addr == ':') hw_addr++; | |
399 sscanf(hw_addr, "%2x%n", &val, &len); | |
400 if (len != 2) break; | |
401 hw_addr += len; | |
402 *p++ = val; | |
403 } | |
404 | |
405 if ((p-ptr) != count || *hw_addr) | |
406 error_exit("bad hw-addr '%s'", hw_addr ? hw_addr : ""); | |
407 | |
408 // the linux kernel's "struct sockaddr" (include/linux/socket.h in the | |
409 // kernel source) only has 14 bytes of sa_data, and an infiniband address | |
410 // is 20. So if we go through the ioctl, the kernel will truncate | |
411 // infiniband addresses, meaning we have to go through sysfs instead. | |
412 if (sock->sa_family == ARPHRD_INFINIBAND && !strchr(ifre.ifr_name, '/')) { | |
413 int fd; | |
414 | |
415 sprintf(toybuf, "/sys/class/net/%s/address", ifre.ifr_name); | |
416 fd = xopen(toybuf, O_RDWR); | |
417 xwrite(fd, *argv, strlen(*argv)); | |
418 close(fd); | |
419 } else xioctl(TT.sockfd, SIOCSIFHWADDR, &ifre); | |
420 continue; | |
421 | |
422 // Add/remove ipv6 address to interface | |
423 | |
424 } else if (!strcmp(*argv, "add") || !strcmp(*argv, "del")) { | |
425 struct ifreq_inet6 { | |
426 struct in6_addr addr; | |
427 unsigned prefix; | |
428 int index; | |
429 } ifre6; | |
430 int plen = 128, fd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); | |
431 char *prefix; | |
432 | |
433 if (!argv[1]) { | |
434 toys.exithelp++; | |
435 error_exit(*argv); | |
436 } | |
437 | |
438 prefix = strchr(argv[1], '/'); | |
439 if (prefix) { | |
440 plen = atolx_range(prefix+1, 0, 128); | |
441 *prefix = 0; | |
442 } | |
443 | |
444 get_addrinfo(argv[1], AF_INET6, &ifre6.addr); | |
445 xioctl(fd6, SIOCGIFINDEX, &ifre); | |
446 ifre6.index = ifre.ifr_ifindex; | |
447 ifre6.prefix = plen; | |
448 xioctl(fd6, **(argv++)=='a' ? SIOCSIFADDR : SIOCDIFADDR, &ifre6); | |
449 | |
450 close(fd6); | |
451 continue; | |
452 // Iterate through table to find/perform operation | |
453 } else for (i = 0; i < sizeof(try)/sizeof(*try); i++) { | |
440 struct argh *t = try+i; | 454 struct argh *t = try+i; |
441 int on = t->on, off = t->off; | 455 int on = t->on, off = t->off; |
442 | 456 |
443 if (strcmp(t->name, s)) continue; | 457 if (!t->name) { |
458 if (isdigit(**argv) || !strcmp(*argv, "default")) argv--; | |
459 else continue; | |
460 } else if (strcmp(t->name, s)) continue; | |
444 | 461 |
445 // Is this an SIOCSI entry? | 462 // Is this an SIOCSI entry? |
446 if ((off|0xff) == 0x89ff) { | 463 if ((off|0xff) == 0x89ff) { |
447 if (!rev) { | 464 if (!rev) { |
448 if (!*++argv) show_help(); | 465 if (!*++argv) show_help(); |
454 if (off == SIOCSIFMAP) xioctl(TT.sockfd, SIOCGIFMAP, &ifre); | 471 if (off == SIOCSIFMAP) xioctl(TT.sockfd, SIOCGIFMAP, &ifre); |
455 on = -on; | 472 on = -on; |
456 poke((on>>16) + (char *)&ifre, l, on&15); | 473 poke((on>>16) + (char *)&ifre, l, on&15); |
457 xioctl(TT.sockfd, off, &ifre); | 474 xioctl(TT.sockfd, off, &ifre); |
458 break; | 475 break; |
459 } else set_address(*argv, &ifre, off); | 476 } else if (t->name || !strchr(ifre.ifr_name, ':')) { |
477 struct sockaddr_in *si = (struct sockaddr_in *)&ifre.ifr_addr; | |
478 | |
479 si->sin_family = AF_INET; | |
480 | |
481 if (!strcmp(*argv, "default")) si->sin_addr.s_addr = INADDR_ANY; | |
482 else get_addrinfo(*argv, AF_INET, &si->sin_addr); | |
483 xioctl(TT.sockfd, off, &ifre); | |
484 } | |
460 } | 485 } |
461 off = 0; | 486 off = 0; |
462 } | 487 } |
463 | 488 |
464 // Set flags | 489 // Set flags |
469 xioctl(TT.sockfd, SIOCSIFFLAGS, &ifre); | 494 xioctl(TT.sockfd, SIOCSIFFLAGS, &ifre); |
470 } | 495 } |
471 | 496 |
472 break; | 497 break; |
473 } | 498 } |
474 if (i != sizeof(try)/sizeof(*try)) continue; | 499 if (i == sizeof(try)/sizeof(*try)) { |
475 | |
476 if (!strcmp(*argv, "hw")) { | |
477 char *hw_addr, *ptr, *p; | |
478 struct sockaddr *sock = &ifre.ifr_hwaddr; | |
479 int count = 6; | |
480 | |
481 if (!*++argv) show_help(); | |
482 | |
483 memset(sock, 0, sizeof(struct sockaddr)); | |
484 if (!strcmp("ether", *argv)) sock->sa_family = ARPHRD_ETHER; | |
485 else if (!strcmp("infiniband", *argv)) { | |
486 sock->sa_family = ARPHRD_INFINIBAND; | |
487 count = 20; | |
488 } else { | |
489 toys.exithelp++; | |
490 error_exit("bad hw '%s'", *argv); | |
491 } | |
492 hw_addr = *++argv; | |
493 | |
494 ptr = p = (char *) sock->sa_data; | |
495 | |
496 while (*hw_addr && (p-ptr) < count) { | |
497 int val, len = 0; | |
498 | |
499 if (*hw_addr == ':') hw_addr++; | |
500 sscanf(hw_addr, "%2x%n", &val, &len); | |
501 if (len != 2) break; | |
502 hw_addr += len; | |
503 *p++ = val; | |
504 } | |
505 | |
506 if ((p-ptr) != count || *hw_addr) | |
507 error_exit("bad hw-addr '%s'", hw_addr ? hw_addr : ""); | |
508 xioctl(TT.sockfd, SIOCSIFHWADDR, &ifre); | |
509 | |
510 // Add/remove ipv6 address to interface | |
511 | |
512 } else if (!strcmp(*argv, "add") || !strcmp(*argv, "del")) { | |
513 sockaddr_with_len *swl = NULL; | |
514 struct ifreq_inet6 ifre6; | |
515 char *prefix; | |
516 int plen = 0, sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); | |
517 | |
518 if (!argv[1]) show_help(); | |
519 | |
520 prefix = strchr(argv[1], '/'); | |
521 if (prefix) { | |
522 plen = get_int_value(prefix + 1, 0, 128); | |
523 *prefix = 0; | |
524 } | |
525 swl = get_sockaddr(argv[1], 0, AF_INET6); | |
526 ifre6.ifrinte6_addr = swl->sock_u.sock_in6.sin6_addr; | |
527 xioctl(sockfd6, SIOCGIFINDEX, &ifre); | |
528 ifre6.ifrinet6_ifindex = ifre.ifr_ifindex; | |
529 ifre6.ifrinet6_prefixlen = plen; | |
530 xioctl(sockfd6, **argv=='a' ? SIOCSIFADDR : SIOCDIFADDR, &ifre6); | |
531 | |
532 free(swl); | |
533 close(sockfd6); | |
534 | |
535 argv++; | |
536 } else if (isdigit(**argv) || !strcmp(*argv, "default")) { | |
537 set_address(*argv, &ifre, SIOCSIFADDR); | |
538 //if the interface name is not an alias; set the flag and continue. | |
539 if(!strchr(ifre.ifr_name, ':')) { | |
540 xioctl(TT.sockfd, SIOCGIFFLAGS, &ifre); | |
541 ifre.ifr_flags |= IFF_UP|IFF_RUNNING; | |
542 xioctl(TT.sockfd, SIOCSIFFLAGS, &ifre); | |
543 } | |
544 | |
545 } else { | |
546 errno = EINVAL; | |
547 toys.exithelp++; | 500 toys.exithelp++; |
548 error_exit("bad argument '%s'", *argv); | 501 error_exit("bad argument '%s'", *argv); |
549 } | 502 } |
550 } | 503 } |
551 close(TT.sockfd); | 504 close(TT.sockfd); |