libip6t_rt.c revision bbe83862a5e1baf15f7c923352d4afdf59bc70e2
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 17static 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", 27IP6T_RT_HOPS); 28} 29 30static 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 40static u_int32_t 41parse_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 64static void 65parse_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 83static char * 84addr_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 90static struct in6_addr * 91numeric_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 ≈ 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 107static int 108parse_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 138static 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 151static 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 232static void 233print_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 253static void 254print_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 263static 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 289static 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 326static 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 340void 341_init(void) 342{ 343 xtables_register_match(&rt_mt6_reg); 344} 345