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);