1/*
2 * iptunnel.c	       "ip tunnel"
3 *
4 *		This program is free software; you can redistribute it and/or
5 *		modify it under the terms of the GNU General Public License
6 *		as published by the Free Software Foundation; either version
7 *		2 of the License, or (at your option) any later version.
8 *
9 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <arpa/inet.h>
20#include <sys/ioctl.h>
21#include <net/if.h>
22#include <net/if_arp.h>
23#include <linux/ip.h>
24#include <linux/if_tunnel.h>
25
26#include "rt_names.h"
27#include "utils.h"
28#include "ip_common.h"
29#include "tunnel.h"
30
31static void usage(void) __attribute__((noreturn));
32
33static void usage(void)
34{
35	fprintf(stderr, "Usage: ip tunnel { add | change | del | show | prl | 6rd } [ NAME ]\n");
36	fprintf(stderr, "          [ mode { ipip | gre | sit | isatap | vti } ] [ remote ADDR ] [ local ADDR ]\n");
37	fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
38	fprintf(stderr, "          [ prl-default ADDR ] [ prl-nodefault ADDR ] [ prl-delete ADDR ]\n");
39	fprintf(stderr, "          [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
40	fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
41	fprintf(stderr, "\n");
42	fprintf(stderr, "Where: NAME := STRING\n");
43	fprintf(stderr, "       ADDR := { IP_ADDRESS | any }\n");
44	fprintf(stderr, "       TOS  := { STRING | 00..ff | inherit | inherit/STRING | inherit/00..ff }\n");
45	fprintf(stderr, "       TTL  := { 1..255 | inherit }\n");
46	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
47	exit(-1);
48}
49
50static void set_tunnel_proto(struct ip_tunnel_parm *p, int proto)
51{
52	if (p->iph.protocol && p->iph.protocol != proto) {
53		fprintf(stderr,
54			"You managed to ask for more than one tunnel mode.\n");
55		exit(-1);
56	}
57	p->iph.protocol = proto;
58}
59
60static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
61{
62	int count = 0;
63	const char *medium = NULL;
64	int isatap = 0;
65
66	memset(p, 0, sizeof(*p));
67	p->iph.version = 4;
68	p->iph.ihl = 5;
69#ifndef IP_DF
70#define IP_DF		0x4000		/* Flag: "Don't Fragment"	*/
71#endif
72	p->iph.frag_off = htons(IP_DF);
73
74	while (argc > 0) {
75		if (strcmp(*argv, "mode") == 0) {
76			NEXT_ARG();
77			if (strcmp(*argv, "ipip") == 0 ||
78			    strcmp(*argv, "ip/ip") == 0) {
79				set_tunnel_proto(p, IPPROTO_IPIP);
80			} else if (strcmp(*argv, "gre") == 0 ||
81				   strcmp(*argv, "gre/ip") == 0) {
82				set_tunnel_proto(p, IPPROTO_GRE);
83			} else if (strcmp(*argv, "sit") == 0 ||
84				   strcmp(*argv, "ipv6/ip") == 0) {
85				set_tunnel_proto(p, IPPROTO_IPV6);
86			} else if (strcmp(*argv, "isatap") == 0) {
87				set_tunnel_proto(p, IPPROTO_IPV6);
88				isatap++;
89			} else if (strcmp(*argv, "vti") == 0) {
90				set_tunnel_proto(p, IPPROTO_IPIP);
91				p->i_flags |= VTI_ISVTI;
92			} else {
93				fprintf(stderr,
94					"Unknown tunnel mode \"%s\"\n", *argv);
95				exit(-1);
96			}
97		} else if (strcmp(*argv, "key") == 0) {
98			NEXT_ARG();
99			p->i_flags |= GRE_KEY;
100			p->o_flags |= GRE_KEY;
101			p->i_key = p->o_key = tnl_parse_key("key", *argv);
102		} else if (strcmp(*argv, "ikey") == 0) {
103			NEXT_ARG();
104			p->i_flags |= GRE_KEY;
105			p->i_key = tnl_parse_key("ikey", *argv);
106		} else if (strcmp(*argv, "okey") == 0) {
107			NEXT_ARG();
108			p->o_flags |= GRE_KEY;
109			p->o_key = tnl_parse_key("okey", *argv);
110		} else if (strcmp(*argv, "seq") == 0) {
111			p->i_flags |= GRE_SEQ;
112			p->o_flags |= GRE_SEQ;
113		} else if (strcmp(*argv, "iseq") == 0) {
114			p->i_flags |= GRE_SEQ;
115		} else if (strcmp(*argv, "oseq") == 0) {
116			p->o_flags |= GRE_SEQ;
117		} else if (strcmp(*argv, "csum") == 0) {
118			p->i_flags |= GRE_CSUM;
119			p->o_flags |= GRE_CSUM;
120		} else if (strcmp(*argv, "icsum") == 0) {
121			p->i_flags |= GRE_CSUM;
122		} else if (strcmp(*argv, "ocsum") == 0) {
123			p->o_flags |= GRE_CSUM;
124		} else if (strcmp(*argv, "nopmtudisc") == 0) {
125			p->iph.frag_off = 0;
126		} else if (strcmp(*argv, "pmtudisc") == 0) {
127			p->iph.frag_off = htons(IP_DF);
128		} else if (strcmp(*argv, "remote") == 0) {
129			NEXT_ARG();
130			if (strcmp(*argv, "any"))
131				p->iph.daddr = get_addr32(*argv);
132			else
133				p->iph.daddr = htonl(INADDR_ANY);
134		} else if (strcmp(*argv, "local") == 0) {
135			NEXT_ARG();
136			if (strcmp(*argv, "any"))
137				p->iph.saddr = get_addr32(*argv);
138			else
139				p->iph.saddr = htonl(INADDR_ANY);
140		} else if (strcmp(*argv, "dev") == 0) {
141			NEXT_ARG();
142			medium = *argv;
143		} else if (strcmp(*argv, "ttl") == 0 ||
144			   strcmp(*argv, "hoplimit") == 0 ||
145			   strcmp(*argv, "hlim") == 0) {
146			__u8 uval;
147
148			NEXT_ARG();
149			if (strcmp(*argv, "inherit") != 0) {
150				if (get_u8(&uval, *argv, 0))
151					invarg("invalid TTL\n", *argv);
152				p->iph.ttl = uval;
153			}
154		} else if (strcmp(*argv, "tos") == 0 ||
155			   strcmp(*argv, "tclass") == 0 ||
156			   matches(*argv, "dsfield") == 0) {
157			char *dsfield;
158			__u32 uval;
159
160			NEXT_ARG();
161			dsfield = *argv;
162			strsep(&dsfield, "/");
163			if (strcmp(*argv, "inherit") != 0) {
164				dsfield = *argv;
165				p->iph.tos = 0;
166			} else
167				p->iph.tos = 1;
168			if (dsfield) {
169				if (rtnl_dsfield_a2n(&uval, dsfield))
170					invarg("bad TOS value", *argv);
171				p->iph.tos |= uval;
172			}
173		} else {
174			if (strcmp(*argv, "name") == 0)
175				NEXT_ARG();
176			else if (matches(*argv, "help") == 0)
177				usage();
178
179			if (p->name[0])
180				duparg2("name", *argv);
181			if (get_ifname(p->name, *argv))
182				invarg("\"name\" not a valid ifname", *argv);
183			if (cmd == SIOCCHGTUNNEL && count == 0) {
184				struct ip_tunnel_parm old_p = {};
185
186				if (tnl_get_ioctl(*argv, &old_p))
187					return -1;
188				*p = old_p;
189			}
190		}
191		count++;
192		argc--; argv++;
193	}
194
195
196	if (p->iph.protocol == 0) {
197		if (memcmp(p->name, "gre", 3) == 0)
198			p->iph.protocol = IPPROTO_GRE;
199		else if (memcmp(p->name, "ipip", 4) == 0)
200			p->iph.protocol = IPPROTO_IPIP;
201		else if (memcmp(p->name, "sit", 3) == 0)
202			p->iph.protocol = IPPROTO_IPV6;
203		else if (memcmp(p->name, "isatap", 6) == 0) {
204			p->iph.protocol = IPPROTO_IPV6;
205			isatap++;
206		} else if (memcmp(p->name, "vti", 3) == 0) {
207			p->iph.protocol = IPPROTO_IPIP;
208			p->i_flags |= VTI_ISVTI;
209		}
210	}
211
212	if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
213		if (!(p->i_flags & VTI_ISVTI) &&
214		    (p->iph.protocol != IPPROTO_GRE)) {
215			fprintf(stderr, "Keys are not allowed with ipip and sit tunnels\n");
216			return -1;
217		}
218	}
219
220	if (medium) {
221		p->link = ll_name_to_index(medium);
222		if (p->link == 0) {
223			fprintf(stderr, "Cannot find device \"%s\"\n", medium);
224			return -1;
225		}
226	}
227
228	if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
229		p->i_key = p->iph.daddr;
230		p->i_flags |= GRE_KEY;
231	}
232	if (p->o_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
233		p->o_key = p->iph.daddr;
234		p->o_flags |= GRE_KEY;
235	}
236	if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
237		fprintf(stderr, "A broadcast tunnel requires a source address\n");
238		return -1;
239	}
240	if (isatap)
241		p->i_flags |= SIT_ISATAP;
242
243	return 0;
244}
245
246static const char *tnl_defname(const struct ip_tunnel_parm *p)
247{
248	switch (p->iph.protocol) {
249	case IPPROTO_IPIP:
250		if (p->i_flags & VTI_ISVTI)
251			return "ip_vti0";
252		else
253			return "tunl0";
254	case IPPROTO_GRE:
255		return "gre0";
256	case IPPROTO_IPV6:
257		return "sit0";
258	}
259	return NULL;
260}
261
262static int do_add(int cmd, int argc, char **argv)
263{
264	struct ip_tunnel_parm p;
265	const char *basedev;
266
267	if (parse_args(argc, argv, cmd, &p) < 0)
268		return -1;
269
270	if (p.iph.ttl && p.iph.frag_off == 0) {
271		fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n");
272		return -1;
273	}
274
275	basedev = tnl_defname(&p);
276	if (!basedev) {
277		fprintf(stderr,
278			"cannot determine tunnel mode (ipip, gre, vti or sit)\n");
279		return -1;
280	}
281
282	return tnl_add_ioctl(cmd, basedev, p.name, &p);
283}
284
285static int do_del(int argc, char **argv)
286{
287	struct ip_tunnel_parm p;
288
289	if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
290		return -1;
291
292	return tnl_del_ioctl(tnl_defname(&p) ? : p.name, p.name, &p);
293}
294
295static void print_tunnel(struct ip_tunnel_parm *p)
296{
297	struct ip_tunnel_6rd ip6rd = {};
298	char s1[1024];
299	char s2[1024];
300
301	/* Do not use format_host() for local addr,
302	 * symbolic name will not be useful.
303	 */
304	printf("%s: %s/ip remote %s local %s",
305	       p->name,
306	       tnl_strproto(p->iph.protocol),
307	       p->iph.daddr ? format_host_r(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any",
308	       p->iph.saddr ? rt_addr_n2a_r(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any");
309
310	if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) {
311		struct ip_tunnel_prl prl[16] = {};
312		int i;
313
314		prl[0].datalen = sizeof(prl) - sizeof(prl[0]);
315		prl[0].addr = htonl(INADDR_ANY);
316
317		if (!tnl_prl_ioctl(SIOCGETPRL, p->name, prl))
318			for (i = 1; i < ARRAY_SIZE(prl); i++) {
319				if (prl[i].addr != htonl(INADDR_ANY)) {
320					printf(" %s %s ",
321					       (prl[i].flags & PRL_DEFAULT) ? "pdr" : "pr",
322					       format_host(AF_INET, 4, &prl[i].addr));
323				}
324			}
325	}
326
327	if (p->link) {
328		const char *n = ll_index_to_name(p->link);
329
330		if (n)
331			printf(" dev %s", n);
332	}
333
334	if (p->iph.ttl)
335		printf(" ttl %d", p->iph.ttl);
336	else
337		printf(" ttl inherit");
338
339	if (p->iph.tos) {
340		SPRINT_BUF(b1);
341		printf(" tos");
342		if (p->iph.tos & 1)
343			printf(" inherit");
344		if (p->iph.tos & ~1)
345			printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
346			       rtnl_dsfield_n2a(p->iph.tos & ~1, b1, sizeof(b1)));
347	}
348
349	if (!(p->iph.frag_off & htons(IP_DF)))
350		printf(" nopmtudisc");
351
352	if (p->iph.protocol == IPPROTO_IPV6 && !tnl_ioctl_get_6rd(p->name, &ip6rd) && ip6rd.prefixlen) {
353		printf(" 6rd-prefix %s/%u",
354		       inet_ntop(AF_INET6, &ip6rd.prefix, s1, sizeof(s1)),
355		       ip6rd.prefixlen);
356		if (ip6rd.relay_prefix) {
357			printf(" 6rd-relay_prefix %s/%u",
358			       format_host(AF_INET, 4, &ip6rd.relay_prefix),
359			       ip6rd.relay_prefixlen);
360		}
361	}
362
363	if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key)
364		printf(" key %u", ntohl(p->i_key));
365	else if ((p->i_flags | p->o_flags) & GRE_KEY) {
366		if (p->i_flags & GRE_KEY)
367			printf(" ikey %u", ntohl(p->i_key));
368		if (p->o_flags & GRE_KEY)
369			printf(" okey %u", ntohl(p->o_key));
370	}
371
372	if (p->i_flags & GRE_SEQ)
373		printf("%s  Drop packets out of sequence.", _SL_);
374	if (p->i_flags & GRE_CSUM)
375		printf("%s  Checksum in received packet is required.", _SL_);
376	if (p->o_flags & GRE_SEQ)
377		printf("%s  Sequence packets on output.", _SL_);
378	if (p->o_flags & GRE_CSUM)
379		printf("%s  Checksum output packets.", _SL_);
380}
381
382static int do_tunnels_list(struct ip_tunnel_parm *p)
383{
384	char buf[512];
385	int err = -1;
386	FILE *fp = fopen("/proc/net/dev", "r");
387
388	if (fp == NULL) {
389		perror("fopen");
390		return -1;
391	}
392
393	/* skip header lines */
394	if (!fgets(buf, sizeof(buf), fp) ||
395	    !fgets(buf, sizeof(buf), fp)) {
396		fprintf(stderr, "/proc/net/dev read error\n");
397		goto end;
398	}
399
400	while (fgets(buf, sizeof(buf), fp) != NULL) {
401		char name[IFNAMSIZ];
402		int index, type;
403		struct ip_tunnel_parm p1 = {};
404		char *ptr;
405
406		buf[sizeof(buf) - 1] = 0;
407		ptr = strchr(buf, ':');
408		if (ptr == NULL ||
409		    (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
410			fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
411			goto end;
412		}
413		if (p->name[0] && strcmp(p->name, name))
414			continue;
415		index = ll_name_to_index(name);
416		if (index == 0)
417			continue;
418		type = ll_index_to_type(index);
419		if (type == -1) {
420			fprintf(stderr, "Failed to get type of \"%s\"\n", name);
421			continue;
422		}
423		if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
424			continue;
425		if (tnl_get_ioctl(name, &p1))
426			continue;
427		if ((p->link && p1.link != p->link) ||
428		    (p->name[0] && strcmp(p1.name, p->name)) ||
429		    (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
430		    (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
431		    (p->i_key && p1.i_key != p->i_key))
432			continue;
433		print_tunnel(&p1);
434		if (show_stats)
435			tnl_print_stats(ptr);
436		printf("\n");
437	}
438	err = 0;
439 end:
440	fclose(fp);
441	return err;
442}
443
444static int do_show(int argc, char **argv)
445{
446	struct ip_tunnel_parm p;
447	const char *basedev;
448
449	ll_init_map(&rth);
450	if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
451		return -1;
452
453	basedev = tnl_defname(&p);
454	if (!basedev)
455		return do_tunnels_list(&p);
456
457	if (tnl_get_ioctl(p.name[0] ? p.name : basedev, &p))
458		return -1;
459
460	print_tunnel(&p);
461	printf("\n");
462	return 0;
463}
464
465static int do_prl(int argc, char **argv)
466{
467	struct ip_tunnel_prl p = {};
468	int count = 0;
469	int cmd = 0;
470	const char *medium = NULL;
471
472	while (argc > 0) {
473		if (strcmp(*argv, "prl-default") == 0) {
474			NEXT_ARG();
475			cmd = SIOCADDPRL;
476			p.addr = get_addr32(*argv);
477			p.flags |= PRL_DEFAULT;
478			count++;
479		} else if (strcmp(*argv, "prl-nodefault") == 0) {
480			NEXT_ARG();
481			cmd = SIOCADDPRL;
482			p.addr = get_addr32(*argv);
483			count++;
484		} else if (strcmp(*argv, "prl-delete") == 0) {
485			NEXT_ARG();
486			cmd = SIOCDELPRL;
487			p.addr = get_addr32(*argv);
488			count++;
489		} else if (strcmp(*argv, "dev") == 0) {
490			NEXT_ARG();
491			if (check_ifname(*argv))
492				invarg("\"dev\" not a valid ifname", *argv);
493			medium = *argv;
494		} else {
495			fprintf(stderr,
496				"Invalid PRL parameter \"%s\"\n", *argv);
497			exit(-1);
498		}
499		if (count > 1) {
500			fprintf(stderr,
501				"One PRL entry at a time\n");
502			exit(-1);
503		}
504		argc--; argv++;
505	}
506	if (!medium) {
507		fprintf(stderr, "Must specify device\n");
508		exit(-1);
509	}
510
511	return tnl_prl_ioctl(cmd, medium, &p);
512}
513
514static int do_6rd(int argc, char **argv)
515{
516	struct ip_tunnel_6rd ip6rd = {};
517	int cmd = 0;
518	const char *medium = NULL;
519	inet_prefix prefix;
520
521	while (argc > 0) {
522		if (strcmp(*argv, "6rd-prefix") == 0) {
523			NEXT_ARG();
524			if (get_prefix(&prefix, *argv, AF_INET6))
525				invarg("invalid 6rd_prefix\n", *argv);
526			cmd = SIOCADD6RD;
527			memcpy(&ip6rd.prefix, prefix.data, 16);
528			ip6rd.prefixlen = prefix.bitlen;
529		} else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
530			NEXT_ARG();
531			if (get_prefix(&prefix, *argv, AF_INET))
532				invarg("invalid 6rd-relay_prefix\n", *argv);
533			cmd = SIOCADD6RD;
534			memcpy(&ip6rd.relay_prefix, prefix.data, 4);
535			ip6rd.relay_prefixlen = prefix.bitlen;
536		} else if (strcmp(*argv, "6rd-reset") == 0) {
537			cmd = SIOCDEL6RD;
538		} else if (strcmp(*argv, "dev") == 0) {
539			NEXT_ARG();
540			if (check_ifname(*argv))
541				invarg("\"dev\" not a valid ifname", *argv);
542			medium = *argv;
543		} else {
544			fprintf(stderr,
545				"Invalid 6RD parameter \"%s\"\n", *argv);
546			exit(-1);
547		}
548		argc--; argv++;
549	}
550	if (!medium) {
551		fprintf(stderr, "Must specify device\n");
552		exit(-1);
553	}
554
555	return tnl_6rd_ioctl(cmd, medium, &ip6rd);
556}
557
558static int tunnel_mode_is_ipv6(char *tunnel_mode)
559{
560	static const char * const ipv6_modes[] = {
561		"ipv6/ipv6", "ip6ip6",
562		"vti6",
563		"ip/ipv6", "ipv4/ipv6", "ipip6", "ip4ip6",
564		"ip6gre", "gre/ipv6",
565		"any/ipv6", "any"
566	};
567	int i;
568
569	for (i = 0; i < ARRAY_SIZE(ipv6_modes); i++) {
570		if (strcmp(ipv6_modes[i], tunnel_mode) == 0)
571			return 1;
572	}
573	return 0;
574}
575
576int do_iptunnel(int argc, char **argv)
577{
578	int i;
579
580	for (i = 0; i < argc - 1; i++) {
581		if (strcmp(argv[i], "mode") == 0) {
582			if (tunnel_mode_is_ipv6(argv[i + 1]))
583				preferred_family = AF_INET6;
584			break;
585		}
586	}
587	switch (preferred_family) {
588	case AF_UNSPEC:
589		preferred_family = AF_INET;
590		break;
591	case AF_INET:
592		break;
593	/*
594	 * This is silly enough but we have no easy way to make it
595	 * protocol-independent because of unarranged structure between
596	 * IPv4 and IPv6.
597	 */
598	case AF_INET6:
599		return do_ip6tunnel(argc, argv);
600	default:
601		fprintf(stderr, "Unsupported protocol family: %d\n", preferred_family);
602		exit(-1);
603	}
604
605	if (argc > 0) {
606		if (matches(*argv, "add") == 0)
607			return do_add(SIOCADDTUNNEL, argc - 1, argv + 1);
608		if (matches(*argv, "change") == 0)
609			return do_add(SIOCCHGTUNNEL, argc - 1, argv + 1);
610		if (matches(*argv, "delete") == 0)
611			return do_del(argc - 1, argv + 1);
612		if (matches(*argv, "show") == 0 ||
613		    matches(*argv, "lst") == 0 ||
614		    matches(*argv, "list") == 0)
615			return do_show(argc - 1, argv + 1);
616		if (matches(*argv, "prl") == 0)
617			return do_prl(argc - 1, argv + 1);
618		if (matches(*argv, "6rd") == 0)
619			return do_6rd(argc - 1, argv + 1);
620		if (matches(*argv, "help") == 0)
621			usage();
622	} else
623		return do_show(0, NULL);
624
625	fprintf(stderr, "Command \"%s\" is unknown, try \"ip tunnel help\"\n", *argv);
626	exit(-1);
627}
628