Fork for IVI and add .changes file
[profile/ivi/iptables.git] / extensions / libip6t_rt.c
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 <xtables.h>
9 /*#include <linux/in6.h>*/
10 #include <linux/netfilter_ipv6/ip6t_rt.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <arpa/inet.h>
14
15 /*#define DEBUG 1*/
16
17 static void rt_help(void)
18 {
19         printf(
20 "rt match options:\n"
21 "[!] --rt-type type             match the type\n"
22 "[!] --rt-segsleft num[:num]    match the Segments Left field (range)\n"
23 "[!] --rt-len length            total length of this header\n"
24 " --rt-0-res                    check the reserved filed, too (type 0)\n"
25 " --rt-0-addrs ADDR[,ADDR...]   Type=0 addresses (list, max: %d)\n"
26 " --rt-0-not-strict             List of Type=0 addresses not a strict list\n",
27 IP6T_RT_HOPS);
28 }
29
30 static const struct option rt_opts[] = {
31         { "rt-type", 1, NULL, '1' },
32         { "rt-segsleft", 1, NULL, '2' },
33         { "rt-len", 1, NULL, '3' },
34         { "rt-0-res", 0, NULL, '4' },
35         { "rt-0-addrs", 1, NULL, '5' },
36         { "rt-0-not-strict", 0, NULL, '6' },
37         { .name = NULL }
38 };
39
40 static u_int32_t
41 parse_rt_num(const char *idstr, const char *typestr)
42 {
43         unsigned long int id;
44         char* ep;
45
46         id =  strtoul(idstr,&ep,0) ;
47
48         if ( idstr == ep ) {
49                 xtables_error(PARAMETER_PROBLEM,
50                            "RT no valid digits in %s `%s'", typestr, idstr);
51         }
52         if ( id == ULONG_MAX  && errno == ERANGE ) {
53                 xtables_error(PARAMETER_PROBLEM,
54                            "%s `%s' specified too big: would overflow",
55                            typestr, idstr);
56         }       
57         if ( *idstr != '\0'  && *ep != '\0' ) {
58                 xtables_error(PARAMETER_PROBLEM,
59                            "RT error parsing %s `%s'", typestr, idstr);
60         }
61         return id;
62 }
63
64 static void
65 parse_rt_segsleft(const char *idstring, u_int32_t *ids)
66 {
67         char *buffer;
68         char *cp;
69
70         buffer = strdup(idstring);
71         if ((cp = strchr(buffer, ':')) == NULL)
72                 ids[0] = ids[1] = parse_rt_num(buffer,"segsleft");
73         else {
74                 *cp = '\0';
75                 cp++;
76
77                 ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0;
78                 ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF;
79         }
80         free(buffer);
81 }
82
83 static char *
84 addr_to_numeric(const struct in6_addr *addrp)
85 {
86         static char buf[50+1];
87         return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
88 }
89
90 static struct in6_addr *
91 numeric_to_addr(const char *num)
92 {
93         static struct in6_addr ap;
94         int err;
95
96         if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
97                 return &ap;
98 #ifdef DEBUG
99         fprintf(stderr, "\nnumeric2addr: %d\n", err);
100 #endif
101         xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
102
103         return (struct in6_addr *)NULL;
104 }
105
106
107 static int
108 parse_addresses(const char *addrstr, struct in6_addr *addrp)
109 {
110         char *buffer, *cp, *next;
111         unsigned int i;
112         
113         buffer = strdup(addrstr);
114         if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
115                         
116         for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
117         {
118                 next=strchr(cp, ',');
119                 if (next) *next++='\0';
120                 memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
121 #if DEBUG
122                 printf("addr str: %s\n", cp);
123                 printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
124                 printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
125 #endif
126         }
127         if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
128
129         free(buffer);
130
131 #if DEBUG
132         printf("addr nr: %d\n", i);
133 #endif
134
135         return i;
136 }
137
138 static void rt_init(struct xt_entry_match *m)
139 {
140         struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
141
142         rtinfo->rt_type = 0x0L;
143         rtinfo->segsleft[0] = 0x0L;
144         rtinfo->segsleft[1] = 0xFFFFFFFF;
145         rtinfo->hdrlen = 0;
146         rtinfo->flags = 0;
147         rtinfo->invflags = 0;
148         rtinfo->addrnr = 0;
149 }
150
151 static int rt_parse(int c, char **argv, int invert, unsigned int *flags,
152                     const void *entry, struct xt_entry_match **match)
153 {
154         struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data;
155
156         switch (c) {
157         case '1':
158                 if (*flags & IP6T_RT_TYP)
159                         xtables_error(PARAMETER_PROBLEM,
160                                    "Only one `--rt-type' allowed");
161                 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
162                 rtinfo->rt_type = parse_rt_num(optarg, "type");
163                 if (invert)
164                         rtinfo->invflags |= IP6T_RT_INV_TYP;
165                 rtinfo->flags |= IP6T_RT_TYP;
166                 *flags |= IP6T_RT_TYP;
167                 break;
168         case '2':
169                 if (*flags & IP6T_RT_SGS)
170                         xtables_error(PARAMETER_PROBLEM,
171                                    "Only one `--rt-segsleft' allowed");
172                 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
173                 parse_rt_segsleft(optarg, rtinfo->segsleft);
174                 if (invert)
175                         rtinfo->invflags |= IP6T_RT_INV_SGS;
176                 rtinfo->flags |= IP6T_RT_SGS;
177                 *flags |= IP6T_RT_SGS;
178                 break;
179         case '3':
180                 if (*flags & IP6T_RT_LEN)
181                         xtables_error(PARAMETER_PROBLEM,
182                                    "Only one `--rt-len' allowed");
183                 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
184                 rtinfo->hdrlen = parse_rt_num(optarg, "length");
185                 if (invert)
186                         rtinfo->invflags |= IP6T_RT_INV_LEN;
187                 rtinfo->flags |= IP6T_RT_LEN;
188                 *flags |= IP6T_RT_LEN;
189                 break;
190         case '4':
191                 if (*flags & IP6T_RT_RES)
192                         xtables_error(PARAMETER_PROBLEM,
193                                    "Only one `--rt-0-res' allowed");
194                 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
195                         xtables_error(PARAMETER_PROBLEM,
196                                    "`--rt-type 0' required before `--rt-0-res'");
197                 rtinfo->flags |= IP6T_RT_RES;
198                 *flags |= IP6T_RT_RES;
199                 break;
200         case '5':
201                 if (*flags & IP6T_RT_FST)
202                         xtables_error(PARAMETER_PROBLEM,
203                                    "Only one `--rt-0-addrs' allowed");
204                 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
205                         xtables_error(PARAMETER_PROBLEM,
206                                    "`--rt-type 0' required before `--rt-0-addrs'");
207                 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
208                 if (invert)
209                         xtables_error(PARAMETER_PROBLEM,
210                                    " '!' not allowed with `--rt-0-addrs'");
211                 rtinfo->addrnr = parse_addresses(optarg, rtinfo->addrs);
212                 rtinfo->flags |= IP6T_RT_FST;
213                 *flags |= IP6T_RT_FST;
214                 break;
215         case '6':
216                 if (*flags & IP6T_RT_FST_NSTRICT)
217                         xtables_error(PARAMETER_PROBLEM,
218                                    "Only one `--rt-0-not-strict' allowed");
219                 if ( !(*flags & IP6T_RT_FST) )
220                         xtables_error(PARAMETER_PROBLEM,
221                                    "`--rt-0-addr ...' required before `--rt-0-not-strict'");
222                 rtinfo->flags |= IP6T_RT_FST_NSTRICT;
223                 *flags |= IP6T_RT_FST_NSTRICT;
224                 break;
225         default:
226                 return 0;
227         }
228
229         return 1;
230 }
231
232 static void
233 print_nums(const char *name, u_int32_t min, u_int32_t max,
234             int invert)
235 {
236         const char *inv = invert ? "!" : "";
237
238         if (min != 0 || max != 0xFFFFFFFF || invert) {
239                 printf("%s", name);
240                 if (min == max) {
241                         printf(":%s", inv);
242                         printf("%u", min);
243                 } else {
244                         printf("s:%s", inv);
245                         printf("%u",min);
246                         printf(":");
247                         printf("%u",max);
248                 }
249                 printf(" ");
250         }
251 }
252
253 static void
254 print_addresses(unsigned int addrnr, struct in6_addr *addrp)
255 {
256         unsigned int i;
257
258         for(i=0; i<addrnr; i++){
259                 printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' ');
260         }
261 }
262
263 static void rt_print(const void *ip, const struct xt_entry_match *match,
264                      int numeric)
265 {
266         const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
267
268         printf("rt ");
269         if (rtinfo->flags & IP6T_RT_TYP)
270             printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
271                     rtinfo->rt_type);
272         print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
273                     rtinfo->invflags & IP6T_RT_INV_SGS);
274         if (rtinfo->flags & IP6T_RT_LEN) {
275                 printf("length");
276                 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
277                 printf("%u", rtinfo->hdrlen);
278                 printf(" ");
279         }
280         if (rtinfo->flags & IP6T_RT_RES) printf("reserved ");
281         if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs ");
282         print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
283         if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict ");
284         if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
285                 printf("Unknown invflags: 0x%X ",
286                        rtinfo->invflags & ~IP6T_RT_INV_MASK);
287 }
288
289 static void rt_save(const void *ip, const struct xt_entry_match *match)
290 {
291         const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
292
293         if (rtinfo->flags & IP6T_RT_TYP) {
294                 printf("%s--rt-type %u ", 
295                         (rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "", 
296                         rtinfo->rt_type);
297         }
298
299         if (!(rtinfo->segsleft[0] == 0
300             && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
301                 printf("%s--rt-segsleft ",
302                         (rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : "");
303                 if (rtinfo->segsleft[0]
304                     != rtinfo->segsleft[1])
305                         printf("%u:%u ",
306                                rtinfo->segsleft[0],
307                                rtinfo->segsleft[1]);
308                 else
309                         printf("%u ",
310                                rtinfo->segsleft[0]);
311         }
312
313         if (rtinfo->flags & IP6T_RT_LEN) {
314                 printf("%s--rt-len %u ",
315                         (rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "", 
316                         rtinfo->hdrlen);
317         }
318
319         if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res ");
320         if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs ");
321         print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
322         if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict ");
323
324 }
325
326 static struct xtables_match rt_mt6_reg = {
327         .name           = "rt",
328         .version        = XTABLES_VERSION,
329         .family         = NFPROTO_IPV6,
330         .size           = XT_ALIGN(sizeof(struct ip6t_rt)),
331         .userspacesize  = XT_ALIGN(sizeof(struct ip6t_rt)),
332         .help           = rt_help,
333         .init           = rt_init,
334         .parse          = rt_parse,
335         .print          = rt_print,
336         .save           = rt_save,
337         .extra_opts     = rt_opts,
338 };
339
340 void
341 _init(void)
342 {
343         xtables_register_match(&rt_mt6_reg);
344 }