libip6t_rt.c revision 65c0621d48e818d75f8c2810e93eb405a6d31406
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <xtables.h>
5#include <linux/netfilter_ipv6/ip6t_rt.h>
6#include <arpa/inet.h>
7
8enum {
9	O_RT_TYPE = 0,
10	O_RT_SEGSLEFT,
11	O_RT_LEN,
12	O_RT0RES,
13	O_RT0ADDRS,
14	O_RT0NSTRICT,
15	F_RT_TYPE  = 1 << O_RT_TYPE,
16	F_RT0ADDRS = 1 << O_RT0ADDRS,
17};
18
19static void rt_help(void)
20{
21	printf(
22"rt match options:\n"
23"[!] --rt-type type             match the type\n"
24"[!] --rt-segsleft num[:num]    match the Segments Left field (range)\n"
25"[!] --rt-len length            total length of this header\n"
26" --rt-0-res                    check the reserved field too (type 0)\n"
27" --rt-0-addrs ADDR[,ADDR...]   Type=0 addresses (list, max: %d)\n"
28" --rt-0-not-strict             List of Type=0 addresses not a strict list\n",
29IP6T_RT_HOPS);
30}
31
32#define s struct ip6t_rt
33static const struct xt_option_entry rt_opts[] = {
34	{.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32RC,
35	 .flags = XTOPT_INVERT},
36	{.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC,
37	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)},
38	{.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32,
39	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
40	{.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE},
41	{.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING},
42	{.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE},
43	XTOPT_TABLEEND,
44};
45#undef s
46
47static const char *
48addr_to_numeric(const struct in6_addr *addrp)
49{
50	static char buf[50+1];
51	return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
52}
53
54static struct in6_addr *
55numeric_to_addr(const char *num)
56{
57	static struct in6_addr ap;
58	int err;
59
60	if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
61		return &ap;
62#ifdef DEBUG
63	fprintf(stderr, "\nnumeric2addr: %d\n", err);
64#endif
65	xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
66
67	return (struct in6_addr *)NULL;
68}
69
70
71static int
72parse_addresses(const char *addrstr, struct in6_addr *addrp)
73{
74        char *buffer, *cp, *next;
75        unsigned int i;
76
77	buffer = strdup(addrstr);
78	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
79
80        for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
81        {
82                next=strchr(cp, ',');
83                if (next) *next++='\0';
84		memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
85#if DEBUG
86		printf("addr str: %s\n", cp);
87		printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
88		printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
89#endif
90	}
91	if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
92
93	free(buffer);
94
95#if DEBUG
96	printf("addr nr: %d\n", i);
97#endif
98
99	return i;
100}
101
102static void rt_init(struct xt_entry_match *m)
103{
104	struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
105
106	rtinfo->segsleft[1] = 0xFFFFFFFF;
107}
108
109static void rt_parse(struct xt_option_call *cb)
110{
111	struct ip6t_rt *rtinfo = cb->data;
112
113	xtables_option_parse(cb);
114	switch (cb->entry->id) {
115	case O_RT_TYPE:
116		if (cb->invert)
117			rtinfo->invflags |= IP6T_RT_INV_TYP;
118		rtinfo->flags |= IP6T_RT_TYP;
119		break;
120	case O_RT_SEGSLEFT:
121		if (cb->invert)
122			rtinfo->invflags |= IP6T_RT_INV_SGS;
123		rtinfo->flags |= IP6T_RT_SGS;
124		break;
125	case O_RT_LEN:
126		if (cb->invert)
127			rtinfo->invflags |= IP6T_RT_INV_LEN;
128		rtinfo->flags |= IP6T_RT_LEN;
129		break;
130	case O_RT0RES:
131		if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
132		    rtinfo->invflags & IP6T_RT_INV_TYP)
133			xtables_error(PARAMETER_PROBLEM,
134				   "`--rt-type 0' required before `--rt-0-res'");
135		rtinfo->flags |= IP6T_RT_RES;
136		break;
137	case O_RT0ADDRS:
138		if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
139		    rtinfo->invflags & IP6T_RT_INV_TYP)
140			xtables_error(PARAMETER_PROBLEM,
141				   "`--rt-type 0' required before `--rt-0-addrs'");
142		rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs);
143		rtinfo->flags |= IP6T_RT_FST;
144		break;
145	case O_RT0NSTRICT:
146		if (!(cb->xflags & F_RT0ADDRS))
147			xtables_error(PARAMETER_PROBLEM,
148				   "`--rt-0-addr ...' required before `--rt-0-not-strict'");
149		rtinfo->flags |= IP6T_RT_FST_NSTRICT;
150		break;
151	}
152}
153
154static void
155print_nums(const char *name, uint32_t min, uint32_t max,
156	    int invert)
157{
158	const char *inv = invert ? "!" : "";
159
160	if (min != 0 || max != 0xFFFFFFFF || invert) {
161		printf(" %s", name);
162		if (min == max) {
163			printf(":%s", inv);
164			printf("%u", min);
165		} else {
166			printf("s:%s", inv);
167			printf("%u",min);
168			printf(":");
169			printf("%u",max);
170		}
171	}
172}
173
174static void
175print_addresses(unsigned int addrnr, struct in6_addr *addrp)
176{
177	unsigned int i;
178
179	for(i=0; i<addrnr; i++){
180		printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i])));
181	}
182}
183
184static void rt_print(const void *ip, const struct xt_entry_match *match,
185                     int numeric)
186{
187	const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
188
189	printf(" rt");
190	if (rtinfo->flags & IP6T_RT_TYP)
191	    printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
192		    rtinfo->rt_type);
193	print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
194		    rtinfo->invflags & IP6T_RT_INV_SGS);
195	if (rtinfo->flags & IP6T_RT_LEN) {
196		printf(" length");
197		printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
198		printf("%u", rtinfo->hdrlen);
199	}
200	if (rtinfo->flags & IP6T_RT_RES) printf(" reserved");
201	if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs");
202	print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
203	if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict");
204	if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
205		printf(" Unknown invflags: 0x%X",
206		       rtinfo->invflags & ~IP6T_RT_INV_MASK);
207}
208
209static void rt_save(const void *ip, const struct xt_entry_match *match)
210{
211	const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
212
213	if (rtinfo->flags & IP6T_RT_TYP) {
214		printf("%s --rt-type %u",
215			(rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "",
216			rtinfo->rt_type);
217	}
218
219	if (!(rtinfo->segsleft[0] == 0
220	    && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
221		printf("%s --rt-segsleft ",
222			(rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
223		if (rtinfo->segsleft[0]
224		    != rtinfo->segsleft[1])
225			printf("%u:%u",
226			       rtinfo->segsleft[0],
227			       rtinfo->segsleft[1]);
228		else
229			printf("%u",
230			       rtinfo->segsleft[0]);
231	}
232
233	if (rtinfo->flags & IP6T_RT_LEN) {
234		printf("%s --rt-len %u",
235			(rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "",
236			rtinfo->hdrlen);
237	}
238
239	if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res");
240	if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs");
241	print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
242	if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict");
243
244}
245
246static struct xtables_match rt_mt6_reg = {
247	.name		= "rt",
248	.version	= XTABLES_VERSION,
249	.family		= NFPROTO_IPV6,
250	.size		= XT_ALIGN(sizeof(struct ip6t_rt)),
251	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_rt)),
252	.help		= rt_help,
253	.init		= rt_init,
254	.x6_parse	= rt_parse,
255	.print		= rt_print,
256	.save		= rt_save,
257	.x6_options	= rt_opts,
258};
259
260void
261_init(void)
262{
263	xtables_register_match(&rt_mt6_reg);
264}
265