summaryrefslogtreecommitdiff
path: root/networking/libiproute/iptunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/libiproute/iptunnel.c')
-rw-r--r--networking/libiproute/iptunnel.c121
1 files changed, 50 insertions, 71 deletions
diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c
index e2e75fce0..52a50993d 100644
--- a/networking/libiproute/iptunnel.c
+++ b/networking/libiproute/iptunnel.c
@@ -18,9 +18,6 @@
18#include <sys/socket.h> 18#include <sys/socket.h>
19#include <sys/ioctl.h> 19#include <sys/ioctl.h>
20 20
21#include <string.h>
22#include <unistd.h>
23
24#include <netinet/ip.h> 21#include <netinet/ip.h>
25 22
26#include <net/if.h> 23#include <net/if.h>
@@ -37,6 +34,7 @@
37#include "ip_common.h" 34#include "ip_common.h"
38 35
39 36
37/* Dies on error */
40static int do_ioctl_get_ifindex(char *dev) 38static int do_ioctl_get_ifindex(char *dev)
41{ 39{
42 struct ifreq ifr; 40 struct ifreq ifr;
@@ -45,8 +43,7 @@ static int do_ioctl_get_ifindex(char *dev)
45 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 43 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
46 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 44 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
47 if (ioctl(fd, SIOCGIFINDEX, &ifr)) { 45 if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
48 bb_perror_msg("ioctl"); 46 bb_perror_msg_and_die("SIOCGIFINDEX");
49 return 0;
50 } 47 }
51 close(fd); 48 close(fd);
52 return ifr.ifr_ifindex; 49 return ifr.ifr_ifindex;
@@ -60,31 +57,28 @@ static int do_ioctl_get_iftype(char *dev)
60 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 57 strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
61 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 58 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
62 if (ioctl(fd, SIOCGIFHWADDR, &ifr)) { 59 if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {
63 bb_perror_msg("ioctl"); 60 bb_perror_msg("SIOCGIFHWADDR");
64 return -1; 61 return -1;
65 } 62 }
66 close(fd); 63 close(fd);
67 return ifr.ifr_addr.sa_family; 64 return ifr.ifr_addr.sa_family;
68} 65}
69 66
70
71static char *do_ioctl_get_ifname(int idx) 67static char *do_ioctl_get_ifname(int idx)
72{ 68{
73 static struct ifreq ifr; 69 struct ifreq ifr;
74 int fd; 70 int fd;
75 71
76 ifr.ifr_ifindex = idx; 72 ifr.ifr_ifindex = idx;
77 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 73 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
78 if (ioctl(fd, SIOCGIFNAME, &ifr)) { 74 if (ioctl(fd, SIOCGIFNAME, &ifr)) {
79 bb_perror_msg("ioctl"); 75 bb_perror_msg("SIOCGIFNAME");
80 return NULL; 76 return NULL;
81 } 77 }
82 close(fd); 78 close(fd);
83 return ifr.ifr_name; 79 return xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name));
84} 80}
85 81
86
87
88static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p) 82static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
89{ 83{
90 struct ifreq ifr; 84 struct ifreq ifr;
@@ -96,17 +90,17 @@ static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
96 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 90 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
97 err = ioctl(fd, SIOCGETTUNNEL, &ifr); 91 err = ioctl(fd, SIOCGETTUNNEL, &ifr);
98 if (err) { 92 if (err) {
99 bb_perror_msg("ioctl"); 93 bb_perror_msg("SIOCGETTUNNEL");
100 } 94 }
101 close(fd); 95 close(fd);
102 return err; 96 return err;
103} 97}
104 98
99/* Dies on error, otherwise returns 0 */
105static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p) 100static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
106{ 101{
107 struct ifreq ifr; 102 struct ifreq ifr;
108 int fd; 103 int fd;
109 int err;
110 104
111 if (cmd == SIOCCHGTUNNEL && p->name[0]) { 105 if (cmd == SIOCCHGTUNNEL && p->name[0]) {
112 strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); 106 strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
@@ -115,19 +109,18 @@ static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
115 } 109 }
116 ifr.ifr_ifru.ifru_data = (void*)p; 110 ifr.ifr_ifru.ifru_data = (void*)p;
117 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 111 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
118 err = ioctl(fd, cmd, &ifr); 112 if (ioctl(fd, cmd, &ifr)) {
119 if (err) { 113 bb_perror_msg_and_die("ioctl");
120 bb_perror_msg("ioctl");
121 } 114 }
122 close(fd); 115 close(fd);
123 return err; 116 return 0;
124} 117}
125 118
119/* Dies on error, otherwise returns 0 */
126static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p) 120static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
127{ 121{
128 struct ifreq ifr; 122 struct ifreq ifr;
129 int fd; 123 int fd;
130 int err;
131 124
132 if (p->name[0]) { 125 if (p->name[0]) {
133 strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); 126 strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
@@ -136,15 +129,15 @@ static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
136 } 129 }
137 ifr.ifr_ifru.ifru_data = (void*)p; 130 ifr.ifr_ifru.ifru_data = (void*)p;
138 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 131 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
139 err = ioctl(fd, SIOCDELTUNNEL, &ifr); 132 if (ioctl(fd, SIOCDELTUNNEL, &ifr)) {
140 if (err) { 133 bb_perror_msg_and_die("SIOCDELTUNNEL");
141 bb_perror_msg("ioctl");
142 } 134 }
143 close(fd); 135 close(fd);
144 return err; 136 return 0;
145} 137}
146 138
147static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) 139/* Dies on error */
140static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
148{ 141{
149 int count = 0; 142 int count = 0;
150 char medium[IFNAMSIZ]; 143 char medium[IFNAMSIZ];
@@ -164,27 +157,23 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
164 if (strcmp(*argv, "ipip") == 0 || 157 if (strcmp(*argv, "ipip") == 0 ||
165 strcmp(*argv, "ip/ip") == 0) { 158 strcmp(*argv, "ip/ip") == 0) {
166 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { 159 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
167 bb_error_msg("you managed to ask for more than one tunnel mode"); 160 bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
168 exit(-1);
169 } 161 }
170 p->iph.protocol = IPPROTO_IPIP; 162 p->iph.protocol = IPPROTO_IPIP;
171 } else if (strcmp(*argv, "gre") == 0 || 163 } else if (strcmp(*argv, "gre") == 0 ||
172 strcmp(*argv, "gre/ip") == 0) { 164 strcmp(*argv, "gre/ip") == 0) {
173 if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { 165 if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
174 bb_error_msg("you managed to ask for more than one tunnel mode"); 166 bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
175 exit(-1);
176 } 167 }
177 p->iph.protocol = IPPROTO_GRE; 168 p->iph.protocol = IPPROTO_GRE;
178 } else if (strcmp(*argv, "sit") == 0 || 169 } else if (strcmp(*argv, "sit") == 0 ||
179 strcmp(*argv, "ipv6/ip") == 0) { 170 strcmp(*argv, "ipv6/ip") == 0) {
180 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { 171 if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
181 bb_error_msg("you managed to ask for more than one tunnel mode"); 172 bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
182 exit(-1);
183 } 173 }
184 p->iph.protocol = IPPROTO_IPV6; 174 p->iph.protocol = IPPROTO_IPV6;
185 } else { 175 } else {
186 bb_error_msg("cannot guess tunnel mode"); 176 bb_error_msg_and_die("cannot guess tunnel mode");
187 exit(-1);
188 } 177 }
189 } else if (strcmp(*argv, "key") == 0) { 178 } else if (strcmp(*argv, "key") == 0) {
190 unsigned uval; 179 unsigned uval;
@@ -195,8 +184,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
195 p->i_key = p->o_key = get_addr32(*argv); 184 p->i_key = p->o_key = get_addr32(*argv);
196 else { 185 else {
197 if (get_unsigned(&uval, *argv, 0)<0) { 186 if (get_unsigned(&uval, *argv, 0)<0) {
198 bb_error_msg("invalid value of \"key\""); 187 bb_error_msg_and_die("invalid value of \"key\"");
199 exit(-1);
200 } 188 }
201 p->i_key = p->o_key = htonl(uval); 189 p->i_key = p->o_key = htonl(uval);
202 } 190 }
@@ -208,8 +196,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
208 p->o_key = get_addr32(*argv); 196 p->o_key = get_addr32(*argv);
209 else { 197 else {
210 if (get_unsigned(&uval, *argv, 0)<0) { 198 if (get_unsigned(&uval, *argv, 0)<0) {
211 bb_error_msg("invalid value of \"ikey\""); 199 bb_error_msg_and_die("invalid value of \"ikey\"");
212 exit(-1);
213 } 200 }
214 p->i_key = htonl(uval); 201 p->i_key = htonl(uval);
215 } 202 }
@@ -221,8 +208,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
221 p->o_key = get_addr32(*argv); 208 p->o_key = get_addr32(*argv);
222 else { 209 else {
223 if (get_unsigned(&uval, *argv, 0)<0) { 210 if (get_unsigned(&uval, *argv, 0)<0) {
224 bb_error_msg("invalid value of \"okey\""); 211 bb_error_msg_and_die("invalid value of \"okey\"");
225 exit(-1);
226 } 212 }
227 p->o_key = htonl(uval); 213 p->o_key = htonl(uval);
228 } 214 }
@@ -286,15 +272,15 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
286 struct ip_tunnel_parm old_p; 272 struct ip_tunnel_parm old_p;
287 memset(&old_p, 0, sizeof(old_p)); 273 memset(&old_p, 0, sizeof(old_p));
288 if (do_get_ioctl(*argv, &old_p)) 274 if (do_get_ioctl(*argv, &old_p))
289 return -1; 275 exit(1);
290 *p = old_p; 276 *p = old_p;
291 } 277 }
292 } 278 }
293 count++; 279 count++;
294 argc--; argv++; 280 argc--;
281 argv++;
295 } 282 }
296 283
297
298 if (p->iph.protocol == 0) { 284 if (p->iph.protocol == 0) {
299 if (memcmp(p->name, "gre", 3) == 0) 285 if (memcmp(p->name, "gre", 3) == 0)
300 p->iph.protocol = IPPROTO_GRE; 286 p->iph.protocol = IPPROTO_GRE;
@@ -306,15 +292,12 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
306 292
307 if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { 293 if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
308 if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { 294 if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
309 bb_error_msg("keys are not allowed with ipip and sit"); 295 bb_error_msg_and_die("keys are not allowed with ipip and sit");
310 return -1;
311 } 296 }
312 } 297 }
313 298
314 if (medium[0]) { 299 if (medium[0]) {
315 p->link = do_ioctl_get_ifindex(medium); 300 p->link = do_ioctl_get_ifindex(medium);
316 if (p->link == 0)
317 return -1;
318 } 301 }
319 302
320 if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { 303 if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
@@ -326,23 +309,20 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
326 p->o_flags |= GRE_KEY; 309 p->o_flags |= GRE_KEY;
327 } 310 }
328 if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { 311 if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
329 bb_error_msg("broadcast tunnel requires a source address"); 312 bb_error_msg_and_die("broadcast tunnel requires a source address");
330 return -1;
331 } 313 }
332 return 0;
333} 314}
334 315
335 316
317/* Return value becomes exitcode. It's okay to not return at all */
336static int do_add(int cmd, int argc, char **argv) 318static int do_add(int cmd, int argc, char **argv)
337{ 319{
338 struct ip_tunnel_parm p; 320 struct ip_tunnel_parm p;
339 321
340 if (parse_args(argc, argv, cmd, &p) < 0) 322 parse_args(argc, argv, cmd, &p);
341 return -1;
342 323
343 if (p.iph.ttl && p.iph.frag_off == 0) { 324 if (p.iph.ttl && p.iph.frag_off == 0) {
344 bb_error_msg("ttl != 0 and noptmudisc are incompatible"); 325 bb_error_msg_and_die("ttl != 0 and noptmudisc are incompatible");
345 return -1;
346 } 326 }
347 327
348 switch (p.iph.protocol) { 328 switch (p.iph.protocol) {
@@ -353,18 +333,16 @@ static int do_add(int cmd, int argc, char **argv)
353 case IPPROTO_IPV6: 333 case IPPROTO_IPV6:
354 return do_add_ioctl(cmd, "sit0", &p); 334 return do_add_ioctl(cmd, "sit0", &p);
355 default: 335 default:
356 bb_error_msg("cannot determine tunnel mode (ipip, gre or sit)"); 336 bb_error_msg_and_die("cannot determine tunnel mode (ipip, gre or sit)");
357 return -1;
358 } 337 }
359 return -1;
360} 338}
361 339
340/* Return value becomes exitcode. It's okay to not return at all */
362static int do_del(int argc, char **argv) 341static int do_del(int argc, char **argv)
363{ 342{
364 struct ip_tunnel_parm p; 343 struct ip_tunnel_parm p;
365 344
366 if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0) 345 parse_args(argc, argv, SIOCDELTUNNEL, &p);
367 return -1;
368 346
369 switch (p.iph.protocol) { 347 switch (p.iph.protocol) {
370 case IPPROTO_IPIP: 348 case IPPROTO_IPIP:
@@ -376,7 +354,6 @@ static int do_del(int argc, char **argv)
376 default: 354 default:
377 return do_del_ioctl(p.name, &p); 355 return do_del_ioctl(p.name, &p);
378 } 356 }
379 return -1;
380} 357}
381 358
382static void print_tunnel(struct ip_tunnel_parm *p) 359static void print_tunnel(struct ip_tunnel_parm *p)
@@ -399,8 +376,10 @@ static void print_tunnel(struct ip_tunnel_parm *p)
399 p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any"); 376 p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any");
400 if (p->link) { 377 if (p->link) {
401 char *n = do_ioctl_get_ifname(p->link); 378 char *n = do_ioctl_get_ifname(p->link);
402 if (n) 379 if (n) {
403 printf(" dev %s ", n); 380 printf(" dev %s ", n);
381 free(n);
382 }
404 } 383 }
405 if (p->iph.ttl) 384 if (p->iph.ttl)
406 printf(" ttl %d ", p->iph.ttl); 385 printf(" ttl %d ", p->iph.ttl);
@@ -428,16 +407,16 @@ static void print_tunnel(struct ip_tunnel_parm *p)
428 } 407 }
429 408
430 if (p->i_flags & GRE_SEQ) 409 if (p->i_flags & GRE_SEQ)
431 printf("%s Drop packets out of sequence.\n", _SL_); 410 printf("%c Drop packets out of sequence.\n", _SL_);
432 if (p->i_flags & GRE_CSUM) 411 if (p->i_flags & GRE_CSUM)
433 printf("%s Checksum in received packet is required.", _SL_); 412 printf("%c Checksum in received packet is required.", _SL_);
434 if (p->o_flags & GRE_SEQ) 413 if (p->o_flags & GRE_SEQ)
435 printf("%s Sequence packets on output.", _SL_); 414 printf("%c Sequence packets on output.", _SL_);
436 if (p->o_flags & GRE_CSUM) 415 if (p->o_flags & GRE_CSUM)
437 printf("%s Checksum output packets.", _SL_); 416 printf("%c Checksum output packets.", _SL_);
438} 417}
439 418
440static int do_tunnels_list(struct ip_tunnel_parm *p) 419static void do_tunnels_list(struct ip_tunnel_parm *p)
441{ 420{
442 char name[IFNAMSIZ]; 421 char name[IFNAMSIZ];
443 unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, 422 unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
@@ -450,8 +429,8 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
450 FILE *fp = fopen("/proc/net/dev", "r"); 429 FILE *fp = fopen("/proc/net/dev", "r");
451 430
452 if (fp == NULL) { 431 if (fp == NULL) {
453 perror("fopen"); 432 bb_perror_msg("fopen");
454 return -1; 433 return;
455 } 434 }
456 435
457 fgets(buf, sizeof(buf), fp); 436 fgets(buf, sizeof(buf), fp);
@@ -465,7 +444,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
465 if (ptr == NULL || 444 if (ptr == NULL ||
466 (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { 445 (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
467 bb_error_msg("wrong format of /proc/net/dev. Sorry"); 446 bb_error_msg("wrong format of /proc/net/dev. Sorry");
468 return -1; 447 return;
469 } 448 }
470 if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", 449 if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
471 &rx_bytes, &rx_packets, &rx_errs, &rx_drops, 450 &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
@@ -477,7 +456,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
477 continue; 456 continue;
478 type = do_ioctl_get_iftype(name); 457 type = do_ioctl_get_iftype(name);
479 if (type == -1) { 458 if (type == -1) {
480 bb_error_msg("failed to get type of [%s]", name); 459 bb_error_msg("cannot get type of [%s]", name);
481 continue; 460 continue;
482 } 461 }
483 if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) 462 if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
@@ -494,16 +473,15 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
494 print_tunnel(&p1); 473 print_tunnel(&p1);
495 puts(""); 474 puts("");
496 } 475 }
497 return 0;
498} 476}
499 477
478/* Return value becomes exitcode. It's okay to not return at all */
500static int do_show(int argc, char **argv) 479static int do_show(int argc, char **argv)
501{ 480{
502 int err; 481 int err;
503 struct ip_tunnel_parm p; 482 struct ip_tunnel_parm p;
504 483
505 if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) 484 parse_args(argc, argv, SIOCGETTUNNEL, &p);
506 return -1;
507 485
508 switch (p.iph.protocol) { 486 switch (p.iph.protocol) {
509 case IPPROTO_IPIP: 487 case IPPROTO_IPIP:
@@ -527,6 +505,7 @@ static int do_show(int argc, char **argv)
527 return 0; 505 return 0;
528} 506}
529 507
508/* Return value becomes exitcode. It's okay to not return at all */
530int do_iptunnel(int argc, char **argv) 509int do_iptunnel(int argc, char **argv)
531{ 510{
532 if (argc > 0) { 511 if (argc > 0) {