1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  *
5  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6  *
7  * Changes:
8  *
9  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
10  * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
11  * Phil Karn <karn@ka9q.ampr.org>       990408: "pmtudisc" flag
12  */
13 
14 #include <netinet/ip.h>
15 #include <net/if.h>
16 #include <net/if_arp.h>
17 #include <asm/types.h>
18 
19 #ifndef __constant_htons
20 #define __constant_htons htons
21 #endif
22 
23 // FYI: #define SIOCDEVPRIVATE 0x89F0
24 
25 /* From linux/if_tunnel.h. #including it proved troublesome
26  * (redefiniton errors due to name collisions in linux/ and net[inet]/) */
27 #define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
28 #define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
29 #define SIOCDELTUNNEL   (SIOCDEVPRIVATE + 2)
30 #define SIOCCHGTUNNEL   (SIOCDEVPRIVATE + 3)
31 //#define SIOCGETPRL      (SIOCDEVPRIVATE + 4)
32 //#define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
33 //#define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
34 //#define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
35 #define GRE_CSUM        __constant_htons(0x8000)
36 //#define GRE_ROUTING     __constant_htons(0x4000)
37 #define GRE_KEY         __constant_htons(0x2000)
38 #define GRE_SEQ         __constant_htons(0x1000)
39 //#define GRE_STRICT      __constant_htons(0x0800)
40 //#define GRE_REC         __constant_htons(0x0700)
41 //#define GRE_FLAGS       __constant_htons(0x00F8)
42 //#define GRE_VERSION     __constant_htons(0x0007)
43 struct ip_tunnel_parm {
44 	char            name[IFNAMSIZ];
45 	int             link;
46 	uint16_t        i_flags;
47 	uint16_t        o_flags;
48 	uint32_t        i_key;
49 	uint32_t        o_key;
50 	struct iphdr    iph;
51 };
52 /* SIT-mode i_flags */
53 //#define SIT_ISATAP 0x0001
54 //struct ip_tunnel_prl {
55 //	uint32_t          addr;
56 //	uint16_t          flags;
57 //	uint16_t          __reserved;
58 //	uint32_t          datalen;
59 //	uint32_t          __reserved2;
60 //	/* data follows */
61 //};
62 ///* PRL flags */
63 //#define PRL_DEFAULT 0x0001
64 
65 #include "ip_common.h"  /* #include "libbb.h" is inside */
66 #include "rt_names.h"
67 #include "utils.h"
68 
69 
70 /* Dies on error */
do_ioctl_get_ifindex(char * dev)71 static int do_ioctl_get_ifindex(char *dev)
72 {
73 	struct ifreq ifr;
74 	int fd;
75 
76 	strncpy_IFNAMSIZ(ifr.ifr_name, dev);
77 	fd = xsocket(AF_INET, SOCK_DGRAM, 0);
78 	xioctl(fd, SIOCGIFINDEX, &ifr);
79 	close(fd);
80 	return ifr.ifr_ifindex;
81 }
82 
do_ioctl_get_iftype(char * dev)83 static int do_ioctl_get_iftype(char *dev)
84 {
85 	struct ifreq ifr;
86 	int fd;
87 	int err;
88 
89 	strncpy_IFNAMSIZ(ifr.ifr_name, dev);
90 	fd = xsocket(AF_INET, SOCK_DGRAM, 0);
91 	err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr);
92 	close(fd);
93 	return err ? -1 : ifr.ifr_addr.sa_family;
94 }
95 
do_ioctl_get_ifname(int idx)96 static char *do_ioctl_get_ifname(int idx)
97 {
98 	struct ifreq ifr;
99 	int fd;
100 	int err;
101 
102 	ifr.ifr_ifindex = idx;
103 	fd = xsocket(AF_INET, SOCK_DGRAM, 0);
104 	err = ioctl_or_warn(fd, SIOCGIFNAME, &ifr);
105 	close(fd);
106 	return err ? NULL : xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name));
107 }
108 
do_get_ioctl(const char * basedev,struct ip_tunnel_parm * p)109 static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
110 {
111 	struct ifreq ifr;
112 	int fd;
113 	int err;
114 
115 	strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
116 	ifr.ifr_ifru.ifru_data = (void*)p;
117 	fd = xsocket(AF_INET, SOCK_DGRAM, 0);
118 	err = ioctl_or_warn(fd, SIOCGETTUNNEL, &ifr);
119 	close(fd);
120 	return err;
121 }
122 
123 /* Dies on error, otherwise returns 0 */
do_add_ioctl(int cmd,const char * basedev,struct ip_tunnel_parm * p)124 static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
125 {
126 	struct ifreq ifr;
127 	int fd;
128 
129 	if (cmd == SIOCCHGTUNNEL && p->name[0]) {
130 		strncpy_IFNAMSIZ(ifr.ifr_name, p->name);
131 	} else {
132 		strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
133 	}
134 	ifr.ifr_ifru.ifru_data = (void*)p;
135 	fd = xsocket(AF_INET, SOCK_DGRAM, 0);
136 #if ENABLE_IOCTL_HEX2STR_ERROR
137 	/* #define magic will turn ioctl# into string */
138 	if (cmd == SIOCCHGTUNNEL)
139 		xioctl(fd, SIOCCHGTUNNEL, &ifr);
140 	else
141 		xioctl(fd, SIOCADDTUNNEL, &ifr);
142 #else
143 	xioctl(fd, cmd, &ifr);
144 #endif
145 	close(fd);
146 	return 0;
147 }
148 
149 /* Dies on error, otherwise returns 0 */
do_del_ioctl(const char * basedev,struct ip_tunnel_parm * p)150 static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
151 {
152 	struct ifreq ifr;
153 	int fd;
154 
155 	if (p->name[0]) {
156 		strncpy_IFNAMSIZ(ifr.ifr_name, p->name);
157 	} else {
158 		strncpy_IFNAMSIZ(ifr.ifr_name, basedev);
159 	}
160 	ifr.ifr_ifru.ifru_data = (void*)p;
161 	fd = xsocket(AF_INET, SOCK_DGRAM, 0);
162 	xioctl(fd, SIOCDELTUNNEL, &ifr);
163 	close(fd);
164 	return 0;
165 }
166 
167 /* Dies on error */
parse_args(char ** argv,int cmd,struct ip_tunnel_parm * p)168 static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p)
169 {
170 	static const char keywords[] ALIGN1 =
171 		"mode\0""ipip\0""ip/ip\0""gre\0""gre/ip\0""sit\0""ipv6/ip\0"
172 		"key\0""ikey\0""okey\0""seq\0""iseq\0""oseq\0"
173 		"csum\0""icsum\0""ocsum\0""nopmtudisc\0""pmtudisc\0"
174 		"remote\0""any\0""local\0""dev\0"
175 		"ttl\0""inherit\0""tos\0""dsfield\0"
176 		"name\0";
177 	enum {
178 		ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip,
179 		ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq,
180 		ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc,
181 		ARG_remote, ARG_any, ARG_local, ARG_dev,
182 		ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield,
183 		ARG_name
184 	};
185 	int count = 0;
186 	char medium[IFNAMSIZ];
187 	int key;
188 
189 	memset(p, 0, sizeof(*p));
190 	medium[0] = '\0';
191 
192 	p->iph.version = 4;
193 	p->iph.ihl = 5;
194 #ifndef IP_DF
195 #define IP_DF 0x4000  /* Flag: "Don't Fragment" */
196 #endif
197 	p->iph.frag_off = htons(IP_DF);
198 
199 	while (*argv) {
200 		key = index_in_strings(keywords, *argv);
201 		if (key == ARG_mode) {
202 			NEXT_ARG();
203 			key = index_in_strings(keywords, *argv);
204 			if (key == ARG_ipip ||
205 			    key == ARG_ip_ip
206 			) {
207 				if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
208 					bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
209 				}
210 				p->iph.protocol = IPPROTO_IPIP;
211 			} else if (key == ARG_gre ||
212 				   key == ARG_gre_ip
213 			) {
214 				if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
215 					bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
216 				}
217 				p->iph.protocol = IPPROTO_GRE;
218 			} else if (key == ARG_sit ||
219 				   key == ARG_ip6_ip
220 			) {
221 				if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
222 					bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
223 				}
224 				p->iph.protocol = IPPROTO_IPV6;
225 			} else {
226 				bb_error_msg_and_die("%s tunnel mode", "can't guess");
227 			}
228 		} else if (key == ARG_key) {
229 			unsigned uval;
230 			NEXT_ARG();
231 			p->i_flags |= GRE_KEY;
232 			p->o_flags |= GRE_KEY;
233 			if (strchr(*argv, '.'))
234 				p->i_key = p->o_key = get_addr32(*argv);
235 			else {
236 				uval = get_unsigned(*argv, "key");
237 				p->i_key = p->o_key = htonl(uval);
238 			}
239 		} else if (key == ARG_ikey) {
240 			unsigned uval;
241 			NEXT_ARG();
242 			p->i_flags |= GRE_KEY;
243 			if (strchr(*argv, '.'))
244 				p->o_key = get_addr32(*argv);
245 			else {
246 				uval = get_unsigned(*argv, "ikey");
247 				p->i_key = htonl(uval);
248 			}
249 		} else if (key == ARG_okey) {
250 			unsigned uval;
251 			NEXT_ARG();
252 			p->o_flags |= GRE_KEY;
253 			if (strchr(*argv, '.'))
254 				p->o_key = get_addr32(*argv);
255 			else {
256 				uval = get_unsigned(*argv, "okey");
257 				p->o_key = htonl(uval);
258 			}
259 		} else if (key == ARG_seq) {
260 			p->i_flags |= GRE_SEQ;
261 			p->o_flags |= GRE_SEQ;
262 		} else if (key == ARG_iseq) {
263 			p->i_flags |= GRE_SEQ;
264 		} else if (key == ARG_oseq) {
265 			p->o_flags |= GRE_SEQ;
266 		} else if (key == ARG_csum) {
267 			p->i_flags |= GRE_CSUM;
268 			p->o_flags |= GRE_CSUM;
269 		} else if (key == ARG_icsum) {
270 			p->i_flags |= GRE_CSUM;
271 		} else if (key == ARG_ocsum) {
272 			p->o_flags |= GRE_CSUM;
273 		} else if (key == ARG_nopmtudisc) {
274 			p->iph.frag_off = 0;
275 		} else if (key == ARG_pmtudisc) {
276 			p->iph.frag_off = htons(IP_DF);
277 		} else if (key == ARG_remote) {
278 			NEXT_ARG();
279 			key = index_in_strings(keywords, *argv);
280 			if (key != ARG_any)
281 				p->iph.daddr = get_addr32(*argv);
282 		} else if (key == ARG_local) {
283 			NEXT_ARG();
284 			key = index_in_strings(keywords, *argv);
285 			if (key != ARG_any)
286 				p->iph.saddr = get_addr32(*argv);
287 		} else if (key == ARG_dev) {
288 			NEXT_ARG();
289 			strncpy_IFNAMSIZ(medium, *argv);
290 		} else if (key == ARG_ttl) {
291 			unsigned uval;
292 			NEXT_ARG();
293 			key = index_in_strings(keywords, *argv);
294 			if (key != ARG_inherit) {
295 				uval = get_unsigned(*argv, "TTL");
296 				if (uval > 255)
297 					invarg_1_to_2(*argv, "TTL");
298 				p->iph.ttl = uval;
299 			}
300 		} else if (key == ARG_tos ||
301 			   key == ARG_dsfield
302 		) {
303 			uint32_t uval;
304 			NEXT_ARG();
305 			key = index_in_strings(keywords, *argv);
306 			if (key != ARG_inherit) {
307 				if (rtnl_dsfield_a2n(&uval, *argv))
308 					invarg_1_to_2(*argv, "TOS");
309 				p->iph.tos = uval;
310 			} else
311 				p->iph.tos = 1;
312 		} else {
313 			if (key == ARG_name) {
314 				NEXT_ARG();
315 			}
316 			if (p->name[0])
317 				duparg2("name", *argv);
318 			strncpy_IFNAMSIZ(p->name, *argv);
319 			if (cmd == SIOCCHGTUNNEL && count == 0) {
320 				struct ip_tunnel_parm old_p;
321 				memset(&old_p, 0, sizeof(old_p));
322 				if (do_get_ioctl(*argv, &old_p))
323 					exit(EXIT_FAILURE);
324 				*p = old_p;
325 			}
326 		}
327 		count++;
328 		argv++;
329 	}
330 
331 	if (p->iph.protocol == 0) {
332 		if (memcmp(p->name, "gre", 3) == 0)
333 			p->iph.protocol = IPPROTO_GRE;
334 		else if (memcmp(p->name, "ipip", 4) == 0)
335 			p->iph.protocol = IPPROTO_IPIP;
336 		else if (memcmp(p->name, "sit", 3) == 0)
337 			p->iph.protocol = IPPROTO_IPV6;
338 	}
339 
340 	if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
341 		if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
342 			bb_error_msg_and_die("keys are not allowed with ipip and sit");
343 		}
344 	}
345 
346 	if (medium[0]) {
347 		p->link = do_ioctl_get_ifindex(medium);
348 	}
349 
350 	if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
351 		p->i_key = p->iph.daddr;
352 		p->i_flags |= GRE_KEY;
353 	}
354 	if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
355 		p->o_key = p->iph.daddr;
356 		p->o_flags |= GRE_KEY;
357 	}
358 	if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
359 		bb_error_msg_and_die("broadcast tunnel requires a source address");
360 	}
361 }
362 
363 /* Return value becomes exitcode. It's okay to not return at all */
do_add(int cmd,char ** argv)364 static int do_add(int cmd, char **argv)
365 {
366 	struct ip_tunnel_parm p;
367 
368 	parse_args(argv, cmd, &p);
369 
370 	if (p.iph.ttl && p.iph.frag_off == 0) {
371 		bb_error_msg_and_die("ttl != 0 and noptmudisc are incompatible");
372 	}
373 
374 	switch (p.iph.protocol) {
375 	case IPPROTO_IPIP:
376 		return do_add_ioctl(cmd, "tunl0", &p);
377 	case IPPROTO_GRE:
378 		return do_add_ioctl(cmd, "gre0", &p);
379 	case IPPROTO_IPV6:
380 		return do_add_ioctl(cmd, "sit0", &p);
381 	default:
382 		bb_error_msg_and_die("can't determine tunnel mode (ipip, gre or sit)");
383 	}
384 }
385 
386 /* Return value becomes exitcode. It's okay to not return at all */
do_del(char ** argv)387 static int do_del(char **argv)
388 {
389 	struct ip_tunnel_parm p;
390 
391 	parse_args(argv, SIOCDELTUNNEL, &p);
392 
393 	switch (p.iph.protocol) {
394 	case IPPROTO_IPIP:
395 		return do_del_ioctl("tunl0", &p);
396 	case IPPROTO_GRE:
397 		return do_del_ioctl("gre0", &p);
398 	case IPPROTO_IPV6:
399 		return do_del_ioctl("sit0", &p);
400 	default:
401 		return do_del_ioctl(p.name, &p);
402 	}
403 }
404 
print_tunnel(struct ip_tunnel_parm * p)405 static void print_tunnel(struct ip_tunnel_parm *p)
406 {
407 	char s3[INET_ADDRSTRLEN];
408 	char s4[INET_ADDRSTRLEN];
409 
410 	printf("%s: %s/ip  remote %s  local %s ",
411 		p->name,
412 		p->iph.protocol == IPPROTO_IPIP ? "ip" :
413 			p->iph.protocol == IPPROTO_GRE ? "gre" :
414 			p->iph.protocol == IPPROTO_IPV6 ? "ipv6" :
415 			"unknown",
416 		p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr) : "any",
417 		p->iph.saddr ? format_host(AF_INET, 4, &p->iph.saddr) : "any"
418 	);
419 	if (p->link) {
420 		char *n = do_ioctl_get_ifname(p->link);
421 		if (n) {
422 			printf(" dev %s ", n);
423 			free(n);
424 		}
425 	}
426 	if (p->iph.ttl)
427 		printf(" ttl %d ", p->iph.ttl);
428 	else
429 		printf(" ttl inherit ");
430 	if (p->iph.tos) {
431 		printf(" tos");
432 		if (p->iph.tos & 1)
433 			printf(" inherit");
434 		if (p->iph.tos & ~1)
435 			printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
436 				rtnl_dsfield_n2a(p->iph.tos & ~1));
437 	}
438 	if (!(p->iph.frag_off & htons(IP_DF)))
439 		printf(" nopmtudisc");
440 
441 	inet_ntop(AF_INET, &p->i_key, s3, sizeof(s3));
442 	inet_ntop(AF_INET, &p->o_key, s4, sizeof(s4));
443 	if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key)
444 		printf(" key %s", s3);
445 	else {
446 		if (p->i_flags & GRE_KEY)
447 			printf(" ikey %s ", s3);
448 		if (p->o_flags & GRE_KEY)
449 			printf(" okey %s ", s4);
450 	}
451 
452 	if (p->i_flags & GRE_SEQ)
453 		printf("%c  Drop packets out of sequence.\n", _SL_);
454 	if (p->i_flags & GRE_CSUM)
455 		printf("%c  Checksum in received packet is required.", _SL_);
456 	if (p->o_flags & GRE_SEQ)
457 		printf("%c  Sequence packets on output.", _SL_);
458 	if (p->o_flags & GRE_CSUM)
459 		printf("%c  Checksum output packets.", _SL_);
460 }
461 
do_tunnels_list(struct ip_tunnel_parm * p)462 static void do_tunnels_list(struct ip_tunnel_parm *p)
463 {
464 	char name[IFNAMSIZ];
465 	unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
466 		rx_fifo, rx_frame,
467 		tx_bytes, tx_packets, tx_errs, tx_drops,
468 		tx_fifo, tx_colls, tx_carrier, rx_multi;
469 	int type;
470 	struct ip_tunnel_parm p1;
471 	char buf[512];
472 	FILE *fp = fopen_or_warn("/proc/net/dev", "r");
473 
474 	if (fp == NULL) {
475 		return;
476 	}
477 	/* skip headers */
478 	fgets(buf, sizeof(buf), fp);
479 	fgets(buf, sizeof(buf), fp);
480 
481 	while (fgets(buf, sizeof(buf), fp) != NULL) {
482 		char *ptr;
483 
484 		/*buf[sizeof(buf) - 1] = 0; - fgets is safe anyway */
485 		ptr = strchr(buf, ':');
486 		if (ptr == NULL ||
487 		    (*ptr++ = 0, sscanf(buf, "%s", name) != 1)
488 		) {
489 			bb_error_msg("wrong format of /proc/net/dev");
490 			return;
491 		}
492 		if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
493 			   &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
494 			   &rx_fifo, &rx_frame, &rx_multi,
495 			   &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
496 			   &tx_fifo, &tx_colls, &tx_carrier) != 14)
497 			continue;
498 		if (p->name[0] && strcmp(p->name, name))
499 			continue;
500 		type = do_ioctl_get_iftype(name);
501 		if (type == -1) {
502 			bb_error_msg("can't get type of [%s]", name);
503 			continue;
504 		}
505 		if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
506 			continue;
507 		memset(&p1, 0, sizeof(p1));
508 		if (do_get_ioctl(name, &p1))
509 			continue;
510 		if ((p->link && p1.link != p->link) ||
511 		    (p->name[0] && strcmp(p1.name, p->name)) ||
512 		    (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
513 		    (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
514 		    (p->i_key && p1.i_key != p->i_key)
515 		) {
516 			continue;
517 		}
518 		print_tunnel(&p1);
519 		bb_putchar('\n');
520 	}
521 }
522 
523 /* Return value becomes exitcode. It's okay to not return at all */
do_show(char ** argv)524 static int do_show(char **argv)
525 {
526 	int err;
527 	struct ip_tunnel_parm p;
528 
529 	parse_args(argv, SIOCGETTUNNEL, &p);
530 
531 	switch (p.iph.protocol) {
532 	case IPPROTO_IPIP:
533 		err = do_get_ioctl(p.name[0] ? p.name : "tunl0", &p);
534 		break;
535 	case IPPROTO_GRE:
536 		err = do_get_ioctl(p.name[0] ? p.name : "gre0", &p);
537 		break;
538 	case IPPROTO_IPV6:
539 		err = do_get_ioctl(p.name[0] ? p.name : "sit0", &p);
540 		break;
541 	default:
542 		do_tunnels_list(&p);
543 		return 0;
544 	}
545 	if (err)
546 		return -1;
547 
548 	print_tunnel(&p);
549 	bb_putchar('\n');
550 	return 0;
551 }
552 
553 /* Return value becomes exitcode. It's okay to not return at all */
do_iptunnel(char ** argv)554 int FAST_FUNC do_iptunnel(char **argv)
555 {
556 	static const char keywords[] ALIGN1 =
557 		"add\0""change\0""delete\0""show\0""list\0""lst\0";
558 	enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst };
559 
560 	if (*argv) {
561 		int key = index_in_substrings(keywords, *argv);
562 		if (key < 0)
563 			invarg_1_to_2(*argv, applet_name);
564 		argv++;
565 		if (key == ARG_add)
566 			return do_add(SIOCADDTUNNEL, argv);
567 		if (key == ARG_change)
568 			return do_add(SIOCCHGTUNNEL, argv);
569 		if (key == ARG_del)
570 			return do_del(argv);
571 	}
572 	return do_show(argv);
573 }
574