blob: 036f1011a753e21f6ab190a8b2cd3169df5248d6 [file] [log] [blame]
András Kis-Szabóa4204162002-04-24 09:35:01 +00001/* 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>
András Kis-Szabófce86992002-04-29 13:48:46 +00009/*#include <linux/in6.h>*/
András Kis-Szabóa4204162002-04-24 09:35:01 +000010#include <linux/netfilter_ipv6/ip6t_rt.h>
András Kis-Szabófce86992002-04-29 13:48:46 +000011#include <sys/types.h>
12#include <sys/socket.h>
13#include <arpa/inet.h>
András Kis-Szabóa4204162002-04-24 09:35:01 +000014
András Kis-Szabófce86992002-04-29 13:48:46 +000015/*#define DEBUG 1*/
16
András Kis-Szabóa4204162002-04-24 09:35:01 +000017/* Function which prints out usage message. */
18static void
19help(void)
20{
21 printf(
22"RT v%s 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 filed, too (type 0)\n"
András Kis-Szabófce86992002-04-29 13:48:46 +000027" --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",
Harald Welte80fe35d2002-05-29 13:08:15 +000029IPTABLES_VERSION, IP6T_RT_HOPS);
András Kis-Szabóa4204162002-04-24 09:35:01 +000030}
31
Jan Engelhardt661f1122007-07-30 14:46:51 +000032static const struct option opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000033 { "rt-type", 1, NULL, '1' },
34 { "rt-segsleft", 1, NULL, '2' },
35 { "rt-len", 1, NULL, '3' },
36 { "rt-0-res", 0, NULL, '4' },
37 { "rt-0-addrs", 1, NULL, '5' },
38 { "rt-0-not-strict", 0, NULL, '6' },
39 { }
András Kis-Szabóa4204162002-04-24 09:35:01 +000040};
41
42static u_int32_t
43parse_rt_num(const char *idstr, const char *typestr)
44{
45 unsigned long int id;
46 char* ep;
47
48 id = strtoul(idstr,&ep,0) ;
49
50 if ( idstr == ep ) {
51 exit_error(PARAMETER_PROBLEM,
52 "RT no valid digits in %s `%s'", typestr, idstr);
53 }
54 if ( id == ULONG_MAX && errno == ERANGE ) {
55 exit_error(PARAMETER_PROBLEM,
56 "%s `%s' specified too big: would overflow",
57 typestr, idstr);
58 }
59 if ( *idstr != '\0' && *ep != '\0' ) {
60 exit_error(PARAMETER_PROBLEM,
61 "RT error parsing %s `%s'", typestr, idstr);
62 }
63 return (u_int32_t) id;
64}
65
66static void
67parse_rt_segsleft(const char *idstring, u_int32_t *ids)
68{
69 char *buffer;
70 char *cp;
71
72 buffer = strdup(idstring);
73 if ((cp = strchr(buffer, ':')) == NULL)
74 ids[0] = ids[1] = parse_rt_num(buffer,"segsleft");
75 else {
76 *cp = '\0';
77 cp++;
78
79 ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0;
80 ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF;
81 }
82 free(buffer);
83}
84
András Kis-Szabófce86992002-04-29 13:48:46 +000085static char *
86addr_to_numeric(const struct in6_addr *addrp)
87{
88 static char buf[50+1];
89 return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
90}
91
92static struct in6_addr *
93numeric_to_addr(const char *num)
94{
95 static struct in6_addr ap;
96 int err;
97
98 if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
99 return &ap;
100#ifdef DEBUG
101 fprintf(stderr, "\nnumeric2addr: %d\n", err);
102#endif
103 exit_error(PARAMETER_PROBLEM, "bad address: %s", num);
104
105 return (struct in6_addr *)NULL;
106}
107
108
109static int
110parse_addresses(const char *addrstr, struct in6_addr *addrp)
111{
112 char *buffer, *cp, *next;
113 unsigned int i;
114
115 buffer = strdup(addrstr);
116 if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
117
118 for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
119 {
120 next=strchr(cp, ',');
121 if (next) *next++='\0';
122 memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
123#if DEBUG
124 printf("addr str: %s\n", cp);
125 printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
126 printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
127#endif
128 }
129 if (cp) exit_error(PARAMETER_PROBLEM, "too many addresses specified");
130
131 free(buffer);
132
133#if DEBUG
134 printf("addr nr: %d\n", i);
135#endif
136
137 return i;
138}
139
András Kis-Szabóa4204162002-04-24 09:35:01 +0000140/* Initialize the match. */
141static void
Peter Rileyea146a92007-09-02 13:09:07 +0000142init(struct xt_entry_match *m)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000143{
144 struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
145
146 rtinfo->rt_type = 0x0L;
147 rtinfo->segsleft[0] = 0x0L;
148 rtinfo->segsleft[1] = 0xFFFFFFFF;
149 rtinfo->hdrlen = 0;
150 rtinfo->flags = 0;
151 rtinfo->invflags = 0;
András Kis-Szabófce86992002-04-29 13:48:46 +0000152 rtinfo->addrnr = 0;
András Kis-Szabóa4204162002-04-24 09:35:01 +0000153}
154
155/* Function which parses command options; returns true if it
156 ate an option */
157static int
158parse(int c, char **argv, int invert, unsigned int *flags,
Yasuyuki KOZAKAIa620c612007-07-24 06:03:45 +0000159 const void *entry,
Yasuyuki KOZAKAIb85256b2007-07-24 05:58:56 +0000160 struct xt_entry_match **match)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000161{
162 struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data;
163
164 switch (c) {
165 case '1':
166 if (*flags & IP6T_RT_TYP)
167 exit_error(PARAMETER_PROBLEM,
168 "Only one `--rt-type' allowed");
169 check_inverse(optarg, &invert, &optind, 0);
170 rtinfo->rt_type = parse_rt_num(argv[optind-1], "type");
171 if (invert)
172 rtinfo->invflags |= IP6T_RT_INV_TYP;
173 rtinfo->flags |= IP6T_RT_TYP;
174 *flags |= IP6T_RT_TYP;
175 break;
176 case '2':
177 if (*flags & IP6T_RT_SGS)
178 exit_error(PARAMETER_PROBLEM,
179 "Only one `--rt-segsleft' allowed");
180 check_inverse(optarg, &invert, &optind, 0);
181 parse_rt_segsleft(argv[optind-1], rtinfo->segsleft);
182 if (invert)
183 rtinfo->invflags |= IP6T_RT_INV_SGS;
184 rtinfo->flags |= IP6T_RT_SGS;
185 *flags |= IP6T_RT_SGS;
186 break;
187 case '3':
188 if (*flags & IP6T_RT_LEN)
189 exit_error(PARAMETER_PROBLEM,
190 "Only one `--rt-len' allowed");
191 check_inverse(optarg, &invert, &optind, 0);
192 rtinfo->hdrlen = parse_rt_num(argv[optind-1], "length");
193 if (invert)
194 rtinfo->invflags |= IP6T_RT_INV_LEN;
195 rtinfo->flags |= IP6T_RT_LEN;
196 *flags |= IP6T_RT_LEN;
197 break;
198 case '4':
199 if (*flags & IP6T_RT_RES)
200 exit_error(PARAMETER_PROBLEM,
201 "Only one `--rt-0-res' allowed");
202 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
203 exit_error(PARAMETER_PROBLEM,
204 "`--rt-type 0' required before `--rt-0-res'");
205 rtinfo->flags |= IP6T_RT_RES;
206 *flags |= IP6T_RT_RES;
207 break;
208 case '5':
209 if (*flags & IP6T_RT_FST)
210 exit_error(PARAMETER_PROBLEM,
211 "Only one `--rt-0-addrs' allowed");
212 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
213 exit_error(PARAMETER_PROBLEM,
András Kis-Szabófce86992002-04-29 13:48:46 +0000214 "`--rt-type 0' required before `--rt-0-addrs'");
215 check_inverse(optarg, &invert, &optind, 0);
216 if (invert)
217 exit_error(PARAMETER_PROBLEM,
218 " '!' not allowed with `--rt-0-addrs'");
219 rtinfo->addrnr = parse_addresses(argv[optind-1], rtinfo->addrs);
András Kis-Szabóa4204162002-04-24 09:35:01 +0000220 rtinfo->flags |= IP6T_RT_FST;
221 *flags |= IP6T_RT_FST;
222 break;
András Kis-Szabófce86992002-04-29 13:48:46 +0000223 case '6':
224 if (*flags & IP6T_RT_FST_NSTRICT)
225 exit_error(PARAMETER_PROBLEM,
226 "Only one `--rt-0-not-strict' allowed");
227 if ( !(*flags & IP6T_RT_FST) )
228 exit_error(PARAMETER_PROBLEM,
229 "`--rt-0-addr ...' required before `--rt-0-not-strict'");
230 rtinfo->flags |= IP6T_RT_FST_NSTRICT;
231 *flags |= IP6T_RT_FST_NSTRICT;
232 break;
András Kis-Szabóa4204162002-04-24 09:35:01 +0000233 default:
234 return 0;
235 }
236
237 return 1;
238}
239
András Kis-Szabóa4204162002-04-24 09:35:01 +0000240static void
241print_nums(const char *name, u_int32_t min, u_int32_t max,
242 int invert)
243{
244 const char *inv = invert ? "!" : "";
245
246 if (min != 0 || max != 0xFFFFFFFF || invert) {
247 printf("%s", name);
248 if (min == max) {
249 printf(":%s", inv);
250 printf("%u", min);
251 } else {
252 printf("s:%s", inv);
253 printf("%u",min);
254 printf(":");
255 printf("%u",max);
256 }
257 printf(" ");
258 }
259}
260
András Kis-Szabófce86992002-04-29 13:48:46 +0000261static void
262print_addresses(int addrnr, struct in6_addr *addrp)
263{
264 unsigned int i;
265
266 for(i=0; i<addrnr; i++){
267 printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' ');
268 }
269}
270
András Kis-Szabóa4204162002-04-24 09:35:01 +0000271/* Prints out the union ip6t_matchinfo. */
272static void
Yasuyuki KOZAKAIa620c612007-07-24 06:03:45 +0000273print(const void *ip,
Yasuyuki KOZAKAIb85256b2007-07-24 05:58:56 +0000274 const struct xt_entry_match *match, int numeric)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000275{
276 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
277
278 printf("rt ");
279 if (rtinfo->flags & IP6T_RT_TYP)
280 printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
281 rtinfo->rt_type);
282 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
283 rtinfo->invflags & IP6T_RT_INV_SGS);
284 if (rtinfo->flags & IP6T_RT_LEN) {
285 printf("length");
286 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
287 printf("%u", rtinfo->hdrlen);
288 printf(" ");
289 }
290 if (rtinfo->flags & IP6T_RT_RES) printf("reserved ");
András Kis-Szabófce86992002-04-29 13:48:46 +0000291 if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs ");
Fabrice MARIEae31bb62002-06-14 07:38:16 +0000292 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
András Kis-Szabófce86992002-04-29 13:48:46 +0000293 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict ");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000294 if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
295 printf("Unknown invflags: 0x%X ",
296 rtinfo->invflags & ~IP6T_RT_INV_MASK);
297}
298
299/* Saves the union ip6t_matchinfo in parsable form to stdout. */
Yasuyuki KOZAKAIa620c612007-07-24 06:03:45 +0000300static void save(const void *ip, const struct xt_entry_match *match)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000301{
302 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
303
304 if (rtinfo->flags & IP6T_RT_TYP) {
305 printf("--rt-type %s%u ",
306 (rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "",
307 rtinfo->rt_type);
308 }
309
310 if (!(rtinfo->segsleft[0] == 0
311 && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
312 printf("--rt-segsleft %s",
313 (rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : "");
314 if (rtinfo->segsleft[0]
315 != rtinfo->segsleft[1])
316 printf("%u:%u ",
317 rtinfo->segsleft[0],
318 rtinfo->segsleft[1]);
319 else
320 printf("%u ",
321 rtinfo->segsleft[0]);
322 }
323
324 if (rtinfo->flags & IP6T_RT_LEN) {
325 printf("--rt-len %s%u ",
326 (rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "",
327 rtinfo->hdrlen);
328 }
329
330 if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res ");
331 if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs ");
Fabrice MARIEae31bb62002-06-14 07:38:16 +0000332 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
András Kis-Szabófce86992002-04-29 13:48:46 +0000333 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict ");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000334
335}
336
Harald Welte02aa7332005-02-01 15:38:20 +0000337static struct ip6tables_match rt = {
338 .name = "rt",
339 .version = IPTABLES_VERSION,
340 .size = IP6T_ALIGN(sizeof(struct ip6t_rt)),
341 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_rt)),
342 .help = &help,
343 .init = &init,
344 .parse = &parse,
Harald Welte02aa7332005-02-01 15:38:20 +0000345 .print = &print,
346 .save = &save,
347 .extra_opts = opts,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000348};
349
350void
351_init(void)
352{
353 register_match6(&rt);
354}