blob: 1c57dbd64cf8e9faa2e6350633540fa0b233bc0f [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. */
Jan Engelhardt32b8e612010-07-23 21:16:14 +02002#include <stdbool.h>
András Kis-Szabóa4204162002-04-24 09:35:01 +00003#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
8#include <errno.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01009#include <xtables.h>
András Kis-Szabófce86992002-04-29 13:48:46 +000010/*#include <linux/in6.h>*/
András Kis-Szabóa4204162002-04-24 09:35:01 +000011#include <linux/netfilter_ipv6/ip6t_rt.h>
András Kis-Szabófce86992002-04-29 13:48:46 +000012#include <sys/types.h>
13#include <sys/socket.h>
14#include <arpa/inet.h>
Jan Engelhardtddac6c52008-09-01 14:22:19 +020015
András Kis-Szabófce86992002-04-29 13:48:46 +000016/*#define DEBUG 1*/
17
Jan Engelhardt997045f2007-10-04 16:29:21 +000018static void rt_help(void)
András Kis-Szabóa4204162002-04-24 09:35:01 +000019{
20 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020021"rt match options:\n"
Jan Engelhardt96727922008-08-13 14:42:41 +020022"[!] --rt-type type match the type\n"
23"[!] --rt-segsleft num[:num] match the Segments Left field (range)\n"
24"[!] --rt-len length total length of this header\n"
Jan Engelhardt12a18d62011-02-18 01:45:05 +010025" --rt-0-res check the reserved field too (type 0)\n"
András Kis-Szabófce86992002-04-29 13:48:46 +000026" --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n"
27" --rt-0-not-strict List of Type=0 addresses not a strict list\n",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020028IP6T_RT_HOPS);
András Kis-Szabóa4204162002-04-24 09:35:01 +000029}
30
Jan Engelhardt997045f2007-10-04 16:29:21 +000031static const struct option rt_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020032 {.name = "rt-type", .has_arg = true, .val = '1'},
33 {.name = "rt-segsleft", .has_arg = true, .val = '2'},
34 {.name = "rt-len", .has_arg = true, .val = '3'},
35 {.name = "rt-0-res", .has_arg = false, .val = '4'},
36 {.name = "rt-0-addrs", .has_arg = true, .val = '5'},
37 {.name = "rt-0-not-strict", .has_arg = false, .val = '6'},
38 XT_GETOPT_TABLEEND,
András Kis-Szabóa4204162002-04-24 09:35:01 +000039};
40
Jan Engelhardt7ac40522011-01-07 12:34:04 +010041static uint32_t
András Kis-Szabóa4204162002-04-24 09:35:01 +000042parse_rt_num(const char *idstr, const char *typestr)
43{
44 unsigned long int id;
45 char* ep;
46
47 id = strtoul(idstr,&ep,0) ;
48
49 if ( idstr == ep ) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +010050 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +000051 "RT no valid digits in %s `%s'", typestr, idstr);
52 }
53 if ( id == ULONG_MAX && errno == ERANGE ) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +010054 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +000055 "%s `%s' specified too big: would overflow",
56 typestr, idstr);
57 }
58 if ( *idstr != '\0' && *ep != '\0' ) {
Jan Engelhardt1829ed42009-02-21 03:29:44 +010059 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +000060 "RT error parsing %s `%s'", typestr, idstr);
61 }
Jan Engelhardt213e1852009-01-27 17:24:34 +010062 return id;
András Kis-Szabóa4204162002-04-24 09:35:01 +000063}
64
65static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +010066parse_rt_segsleft(const char *idstring, uint32_t *ids)
András Kis-Szabóa4204162002-04-24 09:35:01 +000067{
68 char *buffer;
69 char *cp;
70
71 buffer = strdup(idstring);
72 if ((cp = strchr(buffer, ':')) == NULL)
73 ids[0] = ids[1] = parse_rt_num(buffer,"segsleft");
74 else {
75 *cp = '\0';
76 cp++;
77
78 ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0;
79 ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF;
80 }
81 free(buffer);
82}
83
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +020084static const char *
András Kis-Szabófce86992002-04-29 13:48:46 +000085addr_to_numeric(const struct in6_addr *addrp)
86{
87 static char buf[50+1];
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +020088 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
András Kis-Szabófce86992002-04-29 13:48:46 +000089}
90
91static struct in6_addr *
92numeric_to_addr(const char *num)
93{
94 static struct in6_addr ap;
95 int err;
96
97 if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
98 return &ap;
99#ifdef DEBUG
100 fprintf(stderr, "\nnumeric2addr: %d\n", err);
101#endif
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100102 xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
András Kis-Szabófce86992002-04-29 13:48:46 +0000103
104 return (struct in6_addr *)NULL;
105}
106
107
108static int
109parse_addresses(const char *addrstr, struct in6_addr *addrp)
110{
111 char *buffer, *cp, *next;
112 unsigned int i;
113
114 buffer = strdup(addrstr);
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100115 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
András Kis-Szabófce86992002-04-29 13:48:46 +0000116
117 for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
118 {
119 next=strchr(cp, ',');
120 if (next) *next++='\0';
121 memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
122#if DEBUG
123 printf("addr str: %s\n", cp);
124 printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
125 printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
126#endif
127 }
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100128 if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
András Kis-Szabófce86992002-04-29 13:48:46 +0000129
130 free(buffer);
131
132#if DEBUG
133 printf("addr nr: %d\n", i);
134#endif
135
136 return i;
137}
138
Jan Engelhardt997045f2007-10-04 16:29:21 +0000139static void rt_init(struct xt_entry_match *m)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000140{
141 struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
142
András Kis-Szabóa4204162002-04-24 09:35:01 +0000143 rtinfo->segsleft[1] = 0xFFFFFFFF;
András Kis-Szabóa4204162002-04-24 09:35:01 +0000144}
145
Jan Engelhardt997045f2007-10-04 16:29:21 +0000146static int rt_parse(int c, char **argv, int invert, unsigned int *flags,
147 const void *entry, struct xt_entry_match **match)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000148{
149 struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data;
150
151 switch (c) {
152 case '1':
153 if (*flags & IP6T_RT_TYP)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100154 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000155 "Only one `--rt-type' allowed");
Jan Engelhardtbf971282009-11-03 19:55:11 +0100156 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200157 rtinfo->rt_type = parse_rt_num(optarg, "type");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000158 if (invert)
159 rtinfo->invflags |= IP6T_RT_INV_TYP;
160 rtinfo->flags |= IP6T_RT_TYP;
161 *flags |= IP6T_RT_TYP;
162 break;
163 case '2':
164 if (*flags & IP6T_RT_SGS)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100165 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000166 "Only one `--rt-segsleft' allowed");
Jan Engelhardtbf971282009-11-03 19:55:11 +0100167 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200168 parse_rt_segsleft(optarg, rtinfo->segsleft);
András Kis-Szabóa4204162002-04-24 09:35:01 +0000169 if (invert)
170 rtinfo->invflags |= IP6T_RT_INV_SGS;
171 rtinfo->flags |= IP6T_RT_SGS;
172 *flags |= IP6T_RT_SGS;
173 break;
174 case '3':
175 if (*flags & IP6T_RT_LEN)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100176 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000177 "Only one `--rt-len' allowed");
Jan Engelhardtbf971282009-11-03 19:55:11 +0100178 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200179 rtinfo->hdrlen = parse_rt_num(optarg, "length");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000180 if (invert)
181 rtinfo->invflags |= IP6T_RT_INV_LEN;
182 rtinfo->flags |= IP6T_RT_LEN;
183 *flags |= IP6T_RT_LEN;
184 break;
185 case '4':
186 if (*flags & IP6T_RT_RES)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100187 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000188 "Only one `--rt-0-res' allowed");
189 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100190 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000191 "`--rt-type 0' required before `--rt-0-res'");
192 rtinfo->flags |= IP6T_RT_RES;
193 *flags |= IP6T_RT_RES;
194 break;
195 case '5':
196 if (*flags & IP6T_RT_FST)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100197 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000198 "Only one `--rt-0-addrs' allowed");
199 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100200 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabófce86992002-04-29 13:48:46 +0000201 "`--rt-type 0' required before `--rt-0-addrs'");
Jan Engelhardtbf971282009-11-03 19:55:11 +0100202 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
András Kis-Szabófce86992002-04-29 13:48:46 +0000203 if (invert)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100204 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabófce86992002-04-29 13:48:46 +0000205 " '!' not allowed with `--rt-0-addrs'");
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200206 rtinfo->addrnr = parse_addresses(optarg, rtinfo->addrs);
András Kis-Szabóa4204162002-04-24 09:35:01 +0000207 rtinfo->flags |= IP6T_RT_FST;
208 *flags |= IP6T_RT_FST;
209 break;
András Kis-Szabófce86992002-04-29 13:48:46 +0000210 case '6':
211 if (*flags & IP6T_RT_FST_NSTRICT)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100212 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabófce86992002-04-29 13:48:46 +0000213 "Only one `--rt-0-not-strict' allowed");
214 if ( !(*flags & IP6T_RT_FST) )
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100215 xtables_error(PARAMETER_PROBLEM,
András Kis-Szabófce86992002-04-29 13:48:46 +0000216 "`--rt-0-addr ...' required before `--rt-0-not-strict'");
217 rtinfo->flags |= IP6T_RT_FST_NSTRICT;
218 *flags |= IP6T_RT_FST_NSTRICT;
219 break;
András Kis-Szabóa4204162002-04-24 09:35:01 +0000220 }
221
222 return 1;
223}
224
András Kis-Szabóa4204162002-04-24 09:35:01 +0000225static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100226print_nums(const char *name, uint32_t min, uint32_t max,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000227 int invert)
228{
229 const char *inv = invert ? "!" : "";
230
231 if (min != 0 || max != 0xFFFFFFFF || invert) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100232 printf(" %s", name);
András Kis-Szabóa4204162002-04-24 09:35:01 +0000233 if (min == max) {
234 printf(":%s", inv);
235 printf("%u", min);
236 } else {
237 printf("s:%s", inv);
238 printf("%u",min);
239 printf(":");
240 printf("%u",max);
241 }
András Kis-Szabóa4204162002-04-24 09:35:01 +0000242 }
243}
244
András Kis-Szabófce86992002-04-29 13:48:46 +0000245static void
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100246print_addresses(unsigned int addrnr, struct in6_addr *addrp)
András Kis-Szabófce86992002-04-29 13:48:46 +0000247{
248 unsigned int i;
249
250 for(i=0; i<addrnr; i++){
Jan Engelhardt73866352010-12-18 02:04:59 +0100251 printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i])));
András Kis-Szabófce86992002-04-29 13:48:46 +0000252 }
253}
254
Jan Engelhardt997045f2007-10-04 16:29:21 +0000255static void rt_print(const void *ip, const struct xt_entry_match *match,
256 int numeric)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000257{
258 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
259
Jan Engelhardt73866352010-12-18 02:04:59 +0100260 printf(" rt");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000261 if (rtinfo->flags & IP6T_RT_TYP)
Jan Engelhardt73866352010-12-18 02:04:59 +0100262 printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
András Kis-Szabóa4204162002-04-24 09:35:01 +0000263 rtinfo->rt_type);
264 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
265 rtinfo->invflags & IP6T_RT_INV_SGS);
266 if (rtinfo->flags & IP6T_RT_LEN) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100267 printf(" length");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000268 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
269 printf("%u", rtinfo->hdrlen);
András Kis-Szabóa4204162002-04-24 09:35:01 +0000270 }
Jan Engelhardt73866352010-12-18 02:04:59 +0100271 if (rtinfo->flags & IP6T_RT_RES) printf(" reserved");
272 if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs");
Fabrice MARIEae31bb62002-06-14 07:38:16 +0000273 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
Jan Engelhardt73866352010-12-18 02:04:59 +0100274 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000275 if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100276 printf(" Unknown invflags: 0x%X",
András Kis-Szabóa4204162002-04-24 09:35:01 +0000277 rtinfo->invflags & ~IP6T_RT_INV_MASK);
278}
279
Jan Engelhardt997045f2007-10-04 16:29:21 +0000280static void rt_save(const void *ip, const struct xt_entry_match *match)
András Kis-Szabóa4204162002-04-24 09:35:01 +0000281{
282 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
283
284 if (rtinfo->flags & IP6T_RT_TYP) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100285 printf("%s --rt-type %u",
286 (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "",
András Kis-Szabóa4204162002-04-24 09:35:01 +0000287 rtinfo->rt_type);
288 }
289
290 if (!(rtinfo->segsleft[0] == 0
291 && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100292 printf("%s --rt-segsleft ",
293 (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000294 if (rtinfo->segsleft[0]
295 != rtinfo->segsleft[1])
Jan Engelhardt73866352010-12-18 02:04:59 +0100296 printf("%u:%u",
András Kis-Szabóa4204162002-04-24 09:35:01 +0000297 rtinfo->segsleft[0],
298 rtinfo->segsleft[1]);
299 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100300 printf("%u",
András Kis-Szabóa4204162002-04-24 09:35:01 +0000301 rtinfo->segsleft[0]);
302 }
303
304 if (rtinfo->flags & IP6T_RT_LEN) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100305 printf("%s --rt-len %u",
306 (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "",
András Kis-Szabóa4204162002-04-24 09:35:01 +0000307 rtinfo->hdrlen);
308 }
309
Jan Engelhardt73866352010-12-18 02:04:59 +0100310 if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res");
311 if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs");
Fabrice MARIEae31bb62002-06-14 07:38:16 +0000312 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
Jan Engelhardt73866352010-12-18 02:04:59 +0100313 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict");
András Kis-Szabóa4204162002-04-24 09:35:01 +0000314
315}
316
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200317static struct xtables_match rt_mt6_reg = {
Harald Welte02aa7332005-02-01 15:38:20 +0000318 .name = "rt",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200319 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100320 .family = NFPROTO_IPV6,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200321 .size = XT_ALIGN(sizeof(struct ip6t_rt)),
322 .userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
Jan Engelhardt997045f2007-10-04 16:29:21 +0000323 .help = rt_help,
324 .init = rt_init,
325 .parse = rt_parse,
326 .print = rt_print,
327 .save = rt_save,
328 .extra_opts = rt_opts,
András Kis-Szabóa4204162002-04-24 09:35:01 +0000329};
330
331void
332_init(void)
333{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200334 xtables_register_match(&rt_mt6_reg);
András Kis-Szabóa4204162002-04-24 09:35:01 +0000335}