Mercurial > hg > toybox
comparison toys/pending/ifconfig.c @ 905:e875b03e1fcc
Yet more ifconfig cleanup. (As described on the mailing list [CLEANUP] thread.)
author | Rob Landley <rob@landley.net> |
---|---|
date | Sun, 19 May 2013 00:48:19 -0500 |
parents | f6db08574875 |
children | ce0a9368b82f |
comparison
equal
deleted
inserted
replaced
904:44abb9cac9d7 | 905:e875b03e1fcc |
---|---|
60 unsigned long long val[16]; | 60 unsigned long long val[16]; |
61 }; | 61 }; |
62 | 62 |
63 #define IO_MAP_INDEX 0x100 | 63 #define IO_MAP_INDEX 0x100 |
64 | 64 |
65 //from kernel header ipv6.h | |
66 #define IPV6_ADDR_ANY 0x0000U | |
67 #define IPV6_ADDR_LOOPBACK 0x0010U | |
68 #define IPV6_ADDR_LINKLOCAL 0x0020U | |
69 #define IPV6_ADDR_SITELOCAL 0x0040U | |
70 #define IPV6_ADDR_COMPATv4 0x0080U | |
71 | |
72 //for the param settings. | 65 //for the param settings. |
73 | 66 |
74 //for ipv6 add/del | 67 //for ipv6 add/del |
75 struct ifreq_inet6 { | 68 struct ifreq_inet6 { |
76 struct in6_addr ifrinte6_addr; | 69 struct in6_addr ifrinte6_addr; |
91 #ifndef INFINIBAND_ALEN | 84 #ifndef INFINIBAND_ALEN |
92 # define INFINIBAND_ALEN 20 | 85 # define INFINIBAND_ALEN 20 |
93 #endif | 86 #endif |
94 | 87 |
95 /* | 88 /* |
96 * verify the host is local unix path. | |
97 * if so, set the swl input param accordingly. | |
98 */ | |
99 static int is_host_unix(char *host, sockaddr_with_len **swl) | |
100 { | |
101 if (strncmp(host, "local:", 6) == 0) { | |
102 struct sockaddr_un *sockun; | |
103 | |
104 *swl = xzalloc(sizeof(struct sockaddr_with_len)); | |
105 (*swl)->socklen = sizeof(struct sockaddr_un); | |
106 (*swl)->sock_u.sock.sa_family = AF_UNIX; | |
107 sockun = (struct sockaddr_un *)&(*swl)->sock_u.sock; | |
108 xstrncpy(sockun->sun_path, host + 6, sizeof(sockun->sun_path)); | |
109 return 1; | |
110 } | |
111 return 0; | |
112 } | |
113 | |
114 /* | |
115 * used to converts string into int and validate the input str for invalid int value or out-of-range. | |
116 */ | |
117 unsigned get_strtou(char *str, char **endp, int base) | |
118 { | |
119 unsigned long uli; | |
120 char *endptr; | |
121 | |
122 if(!isalnum(str[0])) { | |
123 errno = ERANGE; | |
124 return UINT_MAX; | |
125 } | |
126 errno = 0; | |
127 uli = strtoul(str, &endptr, base); | |
128 if(uli > UINT_MAX) { | |
129 errno = ERANGE; | |
130 return UINT_MAX; | |
131 } | |
132 | |
133 if(endp) *endp = endptr; | |
134 if(endptr[0]) { | |
135 if(isalnum(endptr[0]) || errno) { //"123abc" or out-of-range | |
136 errno = ERANGE; | |
137 return UINT_MAX; | |
138 } | |
139 errno = EINVAL; | |
140 } | |
141 return uli; | |
142 } | |
143 | |
144 | |
145 | |
146 /* | |
147 * validate the input param (host) for valid ipv6 ip and extract port number (if there). | |
148 */ | |
149 static void get_host_and_port(char **host, int *port) | |
150 { | |
151 char *ch_ptr; | |
152 char *org_host = *host; | |
153 if (*host[0] == '[') { | |
154 (*host)++; | |
155 ch_ptr = strchr(*host, ']'); | |
156 if (!ch_ptr || (ch_ptr[1] != ':' && ch_ptr[1] != '\0')) | |
157 error_exit("bad address '%s'", org_host); | |
158 } else { | |
159 ch_ptr = strrchr(*host, ':'); | |
160 //There is more than one ':' like "::1" | |
161 if(ch_ptr && strchr(*host, ':') != ch_ptr) ch_ptr = NULL; | |
162 } | |
163 if (ch_ptr) { //pointer to ":" or "]:" | |
164 int size = ch_ptr - (*host) + 1; | |
165 xstrncpy(*host, *host, size); | |
166 if (*ch_ptr != ':') { | |
167 ch_ptr++; //skip ']' | |
168 //[nn] without port | |
169 if (!*ch_ptr) return; | |
170 } | |
171 ch_ptr++; //skip ':' to get the port number. | |
172 *port = get_strtou(ch_ptr, NULL, 10); | |
173 if (errno || (unsigned)*port > 65535) error_exit("bad port '%s'", org_host); | |
174 } | |
175 } | |
176 | |
177 /* | |
178 * used to extract the address info from the given host ip | 89 * used to extract the address info from the given host ip |
179 * and update the swl param accordingly. | 90 * and update the swl param accordingly. |
180 */ | 91 */ |
181 static int get_socket_stream(char *host, sa_family_t af, sockaddr_with_len **swl) | 92 static int get_socket_stream(char *host, sa_family_t af, sockaddr_with_len **swl) |
182 { | 93 { |
207 */ | 118 */ |
208 sockaddr_with_len *get_sockaddr(char *host, int port, sa_family_t af) | 119 sockaddr_with_len *get_sockaddr(char *host, int port, sa_family_t af) |
209 { | 120 { |
210 sockaddr_with_len *swl = NULL; | 121 sockaddr_with_len *swl = NULL; |
211 in_port_t port_num = htons(port); | 122 in_port_t port_num = htons(port); |
212 | 123 char *s; |
213 if(is_host_unix(host, &swl) && swl) return swl; | 124 |
214 | 125 if (!strncmp(host, "local:", 6)) { |
215 //[IPV6_ip]:port_num | 126 struct sockaddr_un *sockun; |
216 if(host[0] == '[' || strrchr(host, ':')) get_host_and_port((char **)&host, &port); | 127 |
128 swl = xzalloc(sizeof(struct sockaddr_with_len)); | |
129 swl->socklen = sizeof(struct sockaddr_un); | |
130 swl->sock_u.sock.sa_family = AF_UNIX; | |
131 sockun = (struct sockaddr_un *)&swl->sock_u.sock; | |
132 xstrncpy(sockun->sun_path, host + 6, sizeof(sockun->sun_path)); | |
133 | |
134 return swl; | |
135 } | |
136 | |
137 // [ipv6]:port or exactly one : | |
138 | |
139 if (*host == '[') { | |
140 host++; | |
141 s = strchr(host, ']'); | |
142 if (s && !s[1]) s = 0; | |
143 else { | |
144 if (!s || s[1] != ':') error_exit("bad address '%s'", host-1); | |
145 s++; | |
146 } | |
147 } else { | |
148 s = strrchr(host, ':'); | |
149 if (s && strchr(host, ':') != s) s = 0; | |
150 } | |
151 | |
152 if (s++) { | |
153 char *ss; | |
154 unsigned long p = strtoul(s, &ss, 0); | |
155 if (*ss || p > 65535) error_exit("bad port '%s'", s); | |
156 port = p; | |
157 } | |
217 | 158 |
218 if (get_socket_stream(host, af, &swl)) return NULL; | 159 if (get_socket_stream(host, af, &swl)) return NULL; |
219 | 160 |
220 if(swl->sock_u.sock.sa_family == AF_INET) | 161 if(swl->sock_u.sock.sa_family == AF_INET) |
221 swl->sock_u.sock_in.sin_port = port_num; | 162 swl->sock_u.sock_in.sin_port = port_num; |
256 struct sockaddr_un *sockun = (void*)sock; | 197 struct sockaddr_un *sockun = (void*)sock; |
257 return xmsprintf("local:%.*s", (int) sizeof(sockun->sun_path), sockun->sun_path); | 198 return xmsprintf("local:%.*s", (int) sizeof(sockun->sun_path), sockun->sun_path); |
258 } else return NULL; | 199 } else return NULL; |
259 } | 200 } |
260 | 201 |
261 static void set_flags(int sockfd, struct ifreq *ifre, int set_flag, int reset_flag) | 202 static void set_flags(int sockfd, struct ifreq *ifre, int set_flag, |
203 int reset_flag) | |
262 { | 204 { |
263 xioctl(sockfd, SIOCGIFFLAGS, ifre); | 205 xioctl(sockfd, SIOCGIFFLAGS, ifre); |
264 ifre->ifr_flags = (ifre->ifr_flags & (~reset_flag)) | set_flag; | 206 ifre->ifr_flags &= ~reset_flag; |
207 ifre->ifr_flags |= set_flag; | |
265 xioctl(sockfd, SIOCSIFFLAGS, ifre); | 208 xioctl(sockfd, SIOCSIFFLAGS, ifre); |
266 } | |
267 | |
268 static void set_mtu(int sockfd, struct ifreq *ifre, char *mtu) | |
269 { | |
270 ifre->ifr_mtu = strtoul(mtu, NULL, 0); | |
271 xioctl(sockfd, SIOCSIFMTU, ifre); | |
272 } | 209 } |
273 | 210 |
274 static void set_metric(int sockfd, struct ifreq *ifre, char *metric) | 211 static void set_metric(int sockfd, struct ifreq *ifre, char *metric) |
275 { | 212 { |
276 ifre->ifr_metric = strtoul(metric, NULL, 0); | 213 ifre->ifr_metric = strtoul(metric, NULL, 0); |
309 | 246 |
310 xioctl(sockfd6, request, &ifre6); | 247 xioctl(sockfd6, request, &ifre6); |
311 free(swl); | 248 free(swl); |
312 } | 249 } |
313 | 250 |
314 static void set_address(int sockfd, char *host_name, struct ifreq *ifre, int request, char *req_name) | 251 static void set_address(int sockfd, char *host_name, struct ifreq *ifre, int request) |
315 { | 252 { |
316 struct sockaddr_in sock_in; | 253 struct sockaddr_in sock_in; |
317 sockaddr_with_len *swl = NULL; | 254 sockaddr_with_len *swl = NULL; |
318 sock_in.sin_family = AF_INET; | 255 sock_in.sin_family = AF_INET; |
319 sock_in.sin_port = 0; | 256 sock_in.sin_port = 0; |
533 } | 470 } |
534 ipv6_addr[i+1] = '\0'; | 471 ipv6_addr[i+1] = '\0'; |
535 if(inet_pton(AF_INET6, ipv6_addr, (struct sockaddr *) &sock_in6.sin6_addr) > 0) { | 472 if(inet_pton(AF_INET6, ipv6_addr, (struct sockaddr *) &sock_in6.sin6_addr) > 0) { |
536 sock_in6.sin6_family = AF_INET6; | 473 sock_in6.sin6_family = AF_INET6; |
537 if(inet_ntop(AF_INET6, &sock_in6.sin6_addr, toybuf, BUFSIZ)) { | 474 if(inet_ntop(AF_INET6, &sock_in6.sin6_addr, toybuf, BUFSIZ)) { |
538 xprintf("%10sinet6 addr: %s/%d Scope:", " ", toybuf, plen); | 475 char *names[] = {"Global","Host","Link","Site","Compat"}, |
539 if(scope == IPV6_ADDR_ANY) xprintf(" Global"); | 476 *name = "Unknown"; |
540 else if(scope == IPV6_ADDR_LOOPBACK) xprintf(" Host"); | 477 int j; |
541 else if(scope == IPV6_ADDR_LINKLOCAL) xprintf(" Link"); | 478 |
542 else if(scope == IPV6_ADDR_SITELOCAL) xprintf(" Site"); | 479 for (j=0; j < sizeof(names)/sizeof(*names); j++) |
543 else if(scope == IPV6_ADDR_COMPATv4) xprintf(" Compat"); | 480 if (scope == (!!j)<<(j+3)) name = names[j]; |
544 else xprintf("Unknown"); | 481 xprintf("%10cinet6 addr: %s/%d Scope: %s\n", ' ', toybuf, plen, name); |
545 xputc('\n'); | |
546 } | 482 } |
547 } | 483 } |
548 } | 484 } |
549 } | 485 } |
550 fclose(fp); | 486 fclose(fp); |
754 memset(&ifre, 0, sizeof(struct ifreq)); | 690 memset(&ifre, 0, sizeof(struct ifreq)); |
755 xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ); | 691 xstrncpy(ifre.ifr_name, *argv, IFNAMSIZ); |
756 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); | 692 sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); |
757 | 693 |
758 while(*++argv) { | 694 while(*++argv) { |
759 struct { | 695 struct argh { |
760 char *name; | 696 char *name; |
761 int flags[2]; // set, clear | 697 int flags[2], addr; // set, clear |
762 } try[] = { | 698 } try[] = { |
763 {"up", {IFF_UP|IFF_RUNNING, 0}}, | 699 {"up", {IFF_UP|IFF_RUNNING, 0}, 0}, |
764 {"down", {0, IFF_UP}}, | 700 {"down", {0, IFF_UP}, 0}, |
765 {"arp", {0, IFF_NOARP}}, | 701 {"arp", {0, IFF_NOARP}, 0}, |
766 {"trailers", {0, IFF_NOTRAILERS}}, | 702 {"trailers", {0, IFF_NOTRAILERS}, 0}, |
767 {"promisc", {IFF_PROMISC, 0}}, | 703 {"promisc", {IFF_PROMISC, 0}, 0}, |
768 {"allmulti", {IFF_ALLMULTI, 0}}, | 704 {"allmulti", {IFF_ALLMULTI, 0}, 0}, |
769 {"multicast", {IFF_MULTICAST, 0}}, | 705 {"multicast", {IFF_MULTICAST, 0}, 0}, |
770 {"dynamic", {IFF_DYNAMIC, 0}} | 706 {"dynamic", {IFF_DYNAMIC, 0}, 0}, |
707 {"pointopoint", {IFF_POINTOPOINT, 0}, SIOCSIFDSTADDR}, // 8918 | |
708 {"broadcast", {IFF_BROADCAST, 0}, SIOCSIFBRDADDR}, //891a | |
709 {"netmask", {0, 0}, SIOCSIFNETMASK}, | |
710 {"dstaddr", {0, 0}, SIOCSIFDSTADDR} | |
771 }; | 711 }; |
772 char *s = *argv; | 712 char *s = *argv; |
773 int rev = (*s == '-'); | 713 int rev = (*s == '-'); |
774 | 714 |
775 s += rev; | 715 s += rev; |
776 | 716 |
777 for (i = 0; i < sizeof(try)/sizeof(*try); i++) { | 717 for (i = 0; i < sizeof(try)/sizeof(*try); i++) { |
778 if (strcmp(try[i].name, s)) continue; | 718 struct argh *t = try+i; |
779 | 719 |
780 xioctl(sockfd, SIOCGIFFLAGS, &ifre); | 720 if (strcmp(t->name, s)) continue; |
781 ifre.ifr_flags &= ~try[i].flags[rev^1]; | 721 |
782 ifre.ifr_flags |= try[i].flags[rev]; | 722 if (!rev && t->addr) { |
783 | 723 if (!*++argv) show_help(); |
784 xioctl(sockfd, SIOCSIFFLAGS, &ifre); | 724 set_address(sockfd, *argv, &ifre, t->addr); |
725 } | |
726 if (t->flags[0] || t->flags[1]) { | |
727 xioctl(sockfd, SIOCGIFFLAGS, &ifre); | |
728 ifre.ifr_flags &= ~t->flags[rev^1]; | |
729 ifre.ifr_flags |= t->flags[rev]; | |
730 xioctl(sockfd, SIOCSIFFLAGS, &ifre); | |
731 } | |
732 | |
785 break; | 733 break; |
786 } | 734 } |
787 if (i != sizeof(try)/sizeof(*try)) continue; | 735 if (i != sizeof(try)/sizeof(*try)) continue; |
788 | 736 |
789 if (!strcmp(*argv, "-pointopoint")) | 737 if (!strcmp(*argv, "hw")) { |
790 set_flags(sockfd, &ifre, 0, IFF_POINTOPOINT); | |
791 /*value setup */ | |
792 else if (!strcmp(*argv, "pointopoint")) { | |
793 if (!*++argv) show_help(); | |
794 set_address(sockfd, *argv, &ifre, SIOCSIFDSTADDR, "SIOCSIFDSTADDR"); | |
795 set_flags(sockfd, &ifre, IFF_POINTOPOINT, 0); | |
796 } else if (!strcmp(*argv, "netmask")) { | |
797 if (!*++argv) show_help(); | |
798 set_address(sockfd, *argv, &ifre, SIOCSIFNETMASK, "SIOCSIFNETMASK"); | |
799 } else if (!strcmp(*argv, "-broadcast")) { | |
800 set_flags(sockfd, &ifre, 0, IFF_BROADCAST); | |
801 } else if (!strcmp(*argv, "broadcast")) { | |
802 if (!*++argv) show_help(); | |
803 set_address(sockfd, *argv, &ifre, SIOCSIFBRDADDR, "SIOCSIFBRDADDR"); | |
804 set_flags(sockfd, &ifre, IFF_BROADCAST, 0); | |
805 } else if (!strcmp(*argv, "dstaddr")) { | |
806 if (!*++argv) show_help(); | |
807 set_address(sockfd, *argv, &ifre, SIOCSIFDSTADDR, "SIOCSIFDSTADDR"); | |
808 } else if (!strcmp(*argv, "hw")) { | |
809 if (!*++argv) show_help(); | 738 if (!*++argv) show_help(); |
810 set_hw_address(sockfd, &argv, &ifre, SIOCSIFHWADDR, "SIOCSIFHWADDR"); | 739 set_hw_address(sockfd, &argv, &ifre, SIOCSIFHWADDR, "SIOCSIFHWADDR"); |
740 | |
811 } else if (!strcmp(*argv, "mtu")) { | 741 } else if (!strcmp(*argv, "mtu")) { |
812 if (!*++argv) show_help(); | 742 if (!*++argv) show_help(); |
813 set_mtu(sockfd, &ifre, *argv); | 743 ifre.ifr_mtu = strtoul(*argv, NULL, 0); |
814 } else if (!strcmp(*argv, "metric")) { | 744 xioctl(sockfd, SIOCSIFMTU, &ifre); |
815 if (!*++argv) show_help(); | |
816 set_metric(sockfd, &ifre, *argv); | |
817 } else if (!strcmp(*argv, "txqueuelen")) { | |
818 if (!*++argv) show_help(); | |
819 set_qlen(sockfd, &ifre, *argv); | |
820 } else if (!strcmp(*argv, "keepalive")) { | 745 } else if (!strcmp(*argv, "keepalive")) { |
821 if (!*++argv) show_help(); | 746 if (!*++argv) show_help(); |
822 ifre.ifr_data = (void *)strtoul(*argv, 0, 0); | 747 ifre.ifr_data = (void *)strtoul(*argv, 0, 0); |
823 xioctl(sockfd, SIOCSKEEPALIVE, &ifre); | 748 xioctl(sockfd, SIOCSKEEPALIVE, &ifre); |
824 } else if (!strcmp(*argv, "outfill")) { | 749 } else if (!strcmp(*argv, "outfill")) { |
825 if (!*++argv) show_help(); | 750 if (!*++argv) show_help(); |
826 ifre.ifr_data = (void *)strtoul(*argv, 0, 0); | 751 ifre.ifr_data = (void *)strtoul(*argv, 0, 0); |
827 xioctl(sockfd, SIOCSOUTFILL, &ifre); | 752 xioctl(sockfd, SIOCSOUTFILL, &ifre); |
753 | |
754 | |
755 | |
756 } else if (!strcmp(*argv, "metric")) { | |
757 if (!*++argv) show_help(); | |
758 set_metric(sockfd, &ifre, *argv); | |
759 } else if (!strcmp(*argv, "txqueuelen")) { | |
760 if (!*++argv) show_help(); | |
761 set_qlen(sockfd, &ifre, *argv); | |
828 } else if (!strcmp(*argv, "add")) { | 762 } else if (!strcmp(*argv, "add")) { |
829 if (!*++argv) show_help(); | 763 if (!*++argv) show_help(); |
830 set_ipv6_addr(sockfd, &ifre, *argv, SIOCSIFADDR, "SIOCSIFADDR"); | 764 set_ipv6_addr(sockfd, &ifre, *argv, SIOCSIFADDR, "SIOCSIFADDR"); |
831 } else if (!strcmp(*argv, "del")) { | 765 } else if (!strcmp(*argv, "del")) { |
832 if (!*++argv) show_help(); | 766 if (!*++argv) show_help(); |
838 if (!*++argv) show_help(); | 772 if (!*++argv) show_help(); |
839 set_ioaddr(sockfd, &ifre, *argv, SIOCSIFMAP, "SIOCSIFMAP"); | 773 set_ioaddr(sockfd, &ifre, *argv, SIOCSIFMAP, "SIOCSIFMAP"); |
840 } else if (!strcmp(*argv, "irq")) { | 774 } else if (!strcmp(*argv, "irq")) { |
841 if (!*++argv) show_help(); | 775 if (!*++argv) show_help(); |
842 set_irq(sockfd, &ifre, *argv, SIOCSIFMAP, "SIOCSIFMAP"); | 776 set_irq(sockfd, &ifre, *argv, SIOCSIFMAP, "SIOCSIFMAP"); |
777 | |
778 | |
843 } else { | 779 } else { |
844 if (isdigit(**argv) || !strcmp(*argv, "default")) { | 780 if (isdigit(**argv) || !strcmp(*argv, "default")) { |
845 char *iface_name = ifre.ifr_name; | 781 set_address(sockfd, *argv, &ifre, SIOCSIFADDR); |
846 short int is_colon = 0; | |
847 set_address(sockfd, *argv, &ifre, SIOCSIFADDR, "SIOCSIFADDR"); | |
848 while (*iface_name) { | |
849 if (*iface_name == ':') { | |
850 is_colon = 1; | |
851 break; | |
852 } | |
853 iface_name++; | |
854 } | |
855 //if the interface name is not an alias; set the flag and continue. | 782 //if the interface name is not an alias; set the flag and continue. |
856 if(!is_colon) set_flags(sockfd, &ifre, IFF_UP | IFF_RUNNING, 0); | 783 if(!strchr(ifre.ifr_name, ':')) |
784 set_flags(sockfd, &ifre, IFF_UP | IFF_RUNNING, 0); | |
857 } else if (!strcmp(*argv, "inet") || !strcmp(*argv, "inet6")) continue; | 785 } else if (!strcmp(*argv, "inet") || !strcmp(*argv, "inet6")) continue; |
858 else { | 786 else { |
859 errno = EINVAL; | 787 errno = EINVAL; |
860 toys.exithelp++; | 788 toys.exithelp++; |
861 error_exit("bad argument"); | 789 error_exit("bad argument"); |