libip6t_rt.c revision a42041665a9d5d08d52a5f1a27916743fbb2736c
1/* Shared library add-on to ip6tables to add Routing header support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <errno.h>
8#include <ip6tables.h>
9#include <linux/netfilter_ipv6/ip6t_rt.h>
10
11/* Function which prints out usage message. */
12static void
13help(void)
14{
15	printf(
16"RT v%s options:\n"
17" --rt-type [!] type            match the type\n"
18" --rt-segsleft [!] num[:num]   match the Segments Left field (range)\n"
19" --rt-len [!] length           total length of this header\n"
20" --rt-0-res                    check the reserved filed, too (type 0)\n"
21" --rt-0-addrs                  Type=0 addresses (list) - NOT SUPPORTED, yet\n",
22NETFILTER_VERSION);
23}
24
25static struct option opts[] = {
26	{ "rt-type", 1, 0, '1' },
27	{ "rt-segsleft", 1, 0, '2' },
28	{ "rt-len", 1, 0, '3' },
29	{ "rt-0-res", 0, 0, '4' },
30	{ "rt-0-addrs", 0, 0, '5' },
31	{0}
32};
33
34static u_int32_t
35parse_rt_num(const char *idstr, const char *typestr)
36{
37	unsigned long int id;
38	char* ep;
39
40	id =  strtoul(idstr,&ep,0) ;
41
42	if ( idstr == ep ) {
43		exit_error(PARAMETER_PROBLEM,
44			   "RT no valid digits in %s `%s'", typestr, idstr);
45	}
46	if ( id == ULONG_MAX  && errno == ERANGE ) {
47		exit_error(PARAMETER_PROBLEM,
48			   "%s `%s' specified too big: would overflow",
49			   typestr, idstr);
50	}
51	if ( *idstr != '\0'  && *ep != '\0' ) {
52		exit_error(PARAMETER_PROBLEM,
53			   "RT error parsing %s `%s'", typestr, idstr);
54	}
55	return (u_int32_t) id;
56}
57
58static void
59parse_rt_segsleft(const char *idstring, u_int32_t *ids)
60{
61	char *buffer;
62	char *cp;
63
64	buffer = strdup(idstring);
65	if ((cp = strchr(buffer, ':')) == NULL)
66		ids[0] = ids[1] = parse_rt_num(buffer,"segsleft");
67	else {
68		*cp = '\0';
69		cp++;
70
71		ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0;
72		ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF;
73	}
74	free(buffer);
75}
76
77/* Initialize the match. */
78static void
79init(struct ip6t_entry_match *m, unsigned int *nfcache)
80{
81	struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
82
83	rtinfo->rt_type = 0x0L;
84	rtinfo->segsleft[0] = 0x0L;
85	rtinfo->segsleft[1] = 0xFFFFFFFF;
86	rtinfo->hdrlen = 0;
87	rtinfo->flags = 0;
88	rtinfo->invflags = 0;
89}
90
91/* Function which parses command options; returns true if it
92   ate an option */
93static int
94parse(int c, char **argv, int invert, unsigned int *flags,
95      const struct ip6t_entry *entry,
96      unsigned int *nfcache,
97      struct ip6t_entry_match **match)
98{
99	struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data;
100
101	switch (c) {
102	case '1':
103		if (*flags & IP6T_RT_TYP)
104			exit_error(PARAMETER_PROBLEM,
105				   "Only one `--rt-type' allowed");
106		check_inverse(optarg, &invert, &optind, 0);
107		rtinfo->rt_type = parse_rt_num(argv[optind-1], "type");
108		if (invert)
109			rtinfo->invflags |= IP6T_RT_INV_TYP;
110		rtinfo->flags |= IP6T_RT_TYP;
111		*flags |= IP6T_RT_TYP;
112		break;
113	case '2':
114		if (*flags & IP6T_RT_SGS)
115			exit_error(PARAMETER_PROBLEM,
116				   "Only one `--rt-segsleft' allowed");
117		check_inverse(optarg, &invert, &optind, 0);
118		parse_rt_segsleft(argv[optind-1], rtinfo->segsleft);
119		if (invert)
120			rtinfo->invflags |= IP6T_RT_INV_SGS;
121		rtinfo->flags |= IP6T_RT_SGS;
122		*flags |= IP6T_RT_SGS;
123		break;
124	case '3':
125		if (*flags & IP6T_RT_LEN)
126			exit_error(PARAMETER_PROBLEM,
127				   "Only one `--rt-len' allowed");
128		check_inverse(optarg, &invert, &optind, 0);
129		rtinfo->hdrlen = parse_rt_num(argv[optind-1], "length");
130		if (invert)
131			rtinfo->invflags |= IP6T_RT_INV_LEN;
132		rtinfo->flags |= IP6T_RT_LEN;
133		*flags |= IP6T_RT_LEN;
134		break;
135	case '4':
136		if (*flags & IP6T_RT_RES)
137			exit_error(PARAMETER_PROBLEM,
138				   "Only one `--rt-0-res' allowed");
139		if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
140			exit_error(PARAMETER_PROBLEM,
141				   "`--rt-type 0' required before `--rt-0-res'");
142		rtinfo->flags |= IP6T_RT_RES;
143		*flags |= IP6T_RT_RES;
144		break;
145	case '5':
146		if (*flags & IP6T_RT_FST)
147			exit_error(PARAMETER_PROBLEM,
148				   "Only one `--rt-0-addrs' allowed");
149		if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
150			exit_error(PARAMETER_PROBLEM,
151				   "`--rt-type 0' required before `--rt-0-res'");
152		/* TODO: implement it! */
153		exit_error(PARAMETER_PROBLEM,
154			" `--rt-0-addrs' not supported, yet");
155		rtinfo->flags |= IP6T_RT_FST;
156		*flags |= IP6T_RT_FST;
157		break;
158	default:
159		return 0;
160	}
161
162	return 1;
163}
164
165/* Final check; we don't care. */
166static void
167final_check(unsigned int flags)
168{
169}
170
171static void
172print_nums(const char *name, u_int32_t min, u_int32_t max,
173	    int invert)
174{
175	const char *inv = invert ? "!" : "";
176
177	if (min != 0 || max != 0xFFFFFFFF || invert) {
178		printf("%s", name);
179		if (min == max) {
180			printf(":%s", inv);
181			printf("%u", min);
182		} else {
183			printf("s:%s", inv);
184			printf("%u",min);
185			printf(":");
186			printf("%u",max);
187		}
188		printf(" ");
189	}
190}
191
192/* Prints out the union ip6t_matchinfo. */
193static void
194print(const struct ip6t_ip6 *ip,
195      const struct ip6t_entry_match *match, int numeric)
196{
197	const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
198
199	printf("rt ");
200	if (rtinfo->flags & IP6T_RT_TYP)
201	    printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
202		    rtinfo->rt_type);
203	print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
204		    rtinfo->invflags & IP6T_RT_INV_SGS);
205	if (rtinfo->flags & IP6T_RT_LEN) {
206		printf("length");
207		printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
208		printf("%u", rtinfo->hdrlen);
209		printf(" ");
210	}
211	if (rtinfo->flags & IP6T_RT_RES) printf("reserved ");
212	if (rtinfo->flags & IP6T_RT_FST) printf("type0-addrs ");
213	if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
214		printf("Unknown invflags: 0x%X ",
215		       rtinfo->invflags & ~IP6T_RT_INV_MASK);
216}
217
218/* Saves the union ip6t_matchinfo in parsable form to stdout. */
219static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
220{
221	const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
222
223	if (rtinfo->flags & IP6T_RT_TYP) {
224		printf("--rt-type %s%u ",
225			(rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "",
226			rtinfo->rt_type);
227	}
228
229	if (!(rtinfo->segsleft[0] == 0
230	    && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
231		printf("--rt-segsleft %s",
232			(rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : "");
233		if (rtinfo->segsleft[0]
234		    != rtinfo->segsleft[1])
235			printf("%u:%u ",
236			       rtinfo->segsleft[0],
237			       rtinfo->segsleft[1]);
238		else
239			printf("%u ",
240			       rtinfo->segsleft[0]);
241	}
242
243	if (rtinfo->flags & IP6T_RT_LEN) {
244		printf("--rt-len %s%u ",
245			(rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "",
246			rtinfo->hdrlen);
247	}
248
249	if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res ");
250	if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs ");
251
252}
253
254static
255struct ip6tables_match rt
256= { NULL,
257    "rt",
258    NETFILTER_VERSION,
259    IP6T_ALIGN(sizeof(struct ip6t_rt)),
260    IP6T_ALIGN(sizeof(struct ip6t_rt)),
261    &help,
262    &init,
263    &parse,
264    &final_check,
265    &print,
266    &save,
267    opts
268};
269
270void
271_init(void)
272{
273	register_match6(&rt);
274}
275