libip6t_rt.c revision 4008138e2b5248940265b160fae001d8954fae21
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 <ip6tables.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/* 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" 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", 29IPTABLES_VERSION, IP6T_RT_HOPS); 30} 31 32static struct option opts[] = { 33 { "rt-type", 1, 0, '1' }, 34 { "rt-segsleft", 1, 0, '2' }, 35 { "rt-len", 1, 0, '3' }, 36 { "rt-0-res", 0, 0, '4' }, 37 { "rt-0-addrs", 1, 0, '5' }, 38 { "rt-0-not-strict", 0, 0, '6' }, 39 {0} 40}; 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 85static 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 ≈ 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 140/* Initialize the match. */ 141static void 142init(struct ip6t_entry_match *m, unsigned int *nfcache) 143{ 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; 152 rtinfo->addrnr = 0; 153} 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, 159 const struct ip6t_entry *entry, 160 unsigned int *nfcache, 161 struct ip6t_entry_match **match) 162{ 163 struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data; 164 165 switch (c) { 166 case '1': 167 if (*flags & IP6T_RT_TYP) 168 exit_error(PARAMETER_PROBLEM, 169 "Only one `--rt-type' allowed"); 170 check_inverse(optarg, &invert, &optind, 0); 171 rtinfo->rt_type = parse_rt_num(argv[optind-1], "type"); 172 if (invert) 173 rtinfo->invflags |= IP6T_RT_INV_TYP; 174 rtinfo->flags |= IP6T_RT_TYP; 175 *flags |= IP6T_RT_TYP; 176 break; 177 case '2': 178 if (*flags & IP6T_RT_SGS) 179 exit_error(PARAMETER_PROBLEM, 180 "Only one `--rt-segsleft' allowed"); 181 check_inverse(optarg, &invert, &optind, 0); 182 parse_rt_segsleft(argv[optind-1], rtinfo->segsleft); 183 if (invert) 184 rtinfo->invflags |= IP6T_RT_INV_SGS; 185 rtinfo->flags |= IP6T_RT_SGS; 186 *flags |= IP6T_RT_SGS; 187 break; 188 case '3': 189 if (*flags & IP6T_RT_LEN) 190 exit_error(PARAMETER_PROBLEM, 191 "Only one `--rt-len' allowed"); 192 check_inverse(optarg, &invert, &optind, 0); 193 rtinfo->hdrlen = parse_rt_num(argv[optind-1], "length"); 194 if (invert) 195 rtinfo->invflags |= IP6T_RT_INV_LEN; 196 rtinfo->flags |= IP6T_RT_LEN; 197 *flags |= IP6T_RT_LEN; 198 break; 199 case '4': 200 if (*flags & IP6T_RT_RES) 201 exit_error(PARAMETER_PROBLEM, 202 "Only one `--rt-0-res' allowed"); 203 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) 204 exit_error(PARAMETER_PROBLEM, 205 "`--rt-type 0' required before `--rt-0-res'"); 206 rtinfo->flags |= IP6T_RT_RES; 207 *flags |= IP6T_RT_RES; 208 break; 209 case '5': 210 if (*flags & IP6T_RT_FST) 211 exit_error(PARAMETER_PROBLEM, 212 "Only one `--rt-0-addrs' allowed"); 213 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) 214 exit_error(PARAMETER_PROBLEM, 215 "`--rt-type 0' required before `--rt-0-addrs'"); 216 check_inverse(optarg, &invert, &optind, 0); 217 if (invert) 218 exit_error(PARAMETER_PROBLEM, 219 " '!' not allowed with `--rt-0-addrs'"); 220 rtinfo->addrnr = parse_addresses(argv[optind-1], rtinfo->addrs); 221 rtinfo->flags |= IP6T_RT_FST; 222 *flags |= IP6T_RT_FST; 223 break; 224 case '6': 225 if (*flags & IP6T_RT_FST_NSTRICT) 226 exit_error(PARAMETER_PROBLEM, 227 "Only one `--rt-0-not-strict' allowed"); 228 if ( !(*flags & IP6T_RT_FST) ) 229 exit_error(PARAMETER_PROBLEM, 230 "`--rt-0-addr ...' required before `--rt-0-not-strict'"); 231 rtinfo->flags |= IP6T_RT_FST_NSTRICT; 232 *flags |= IP6T_RT_FST_NSTRICT; 233 break; 234 default: 235 return 0; 236 } 237 238 return 1; 239} 240 241/* Final check; we don't care. */ 242static void 243final_check(unsigned int flags) 244{ 245} 246 247static void 248print_nums(const char *name, u_int32_t min, u_int32_t max, 249 int invert) 250{ 251 const char *inv = invert ? "!" : ""; 252 253 if (min != 0 || max != 0xFFFFFFFF || invert) { 254 printf("%s", name); 255 if (min == max) { 256 printf(":%s", inv); 257 printf("%u", min); 258 } else { 259 printf("s:%s", inv); 260 printf("%u",min); 261 printf(":"); 262 printf("%u",max); 263 } 264 printf(" "); 265 } 266} 267 268static void 269print_addresses(int addrnr, struct in6_addr *addrp) 270{ 271 unsigned int i; 272 273 for(i=0; i<addrnr; i++){ 274 printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' '); 275 } 276} 277 278/* Prints out the union ip6t_matchinfo. */ 279static void 280print(const struct ip6t_ip6 *ip, 281 const struct ip6t_entry_match *match, int numeric) 282{ 283 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 284 285 printf("rt "); 286 if (rtinfo->flags & IP6T_RT_TYP) 287 printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", 288 rtinfo->rt_type); 289 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1], 290 rtinfo->invflags & IP6T_RT_INV_SGS); 291 if (rtinfo->flags & IP6T_RT_LEN) { 292 printf("length"); 293 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : ""); 294 printf("%u", rtinfo->hdrlen); 295 printf(" "); 296 } 297 if (rtinfo->flags & IP6T_RT_RES) printf("reserved "); 298 if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs "); 299 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 300 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict "); 301 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) 302 printf("Unknown invflags: 0x%X ", 303 rtinfo->invflags & ~IP6T_RT_INV_MASK); 304} 305 306/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 307static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 308{ 309 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 310 311 if (rtinfo->flags & IP6T_RT_TYP) { 312 printf("--rt-type %s%u ", 313 (rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "", 314 rtinfo->rt_type); 315 } 316 317 if (!(rtinfo->segsleft[0] == 0 318 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { 319 printf("--rt-segsleft %s", 320 (rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : ""); 321 if (rtinfo->segsleft[0] 322 != rtinfo->segsleft[1]) 323 printf("%u:%u ", 324 rtinfo->segsleft[0], 325 rtinfo->segsleft[1]); 326 else 327 printf("%u ", 328 rtinfo->segsleft[0]); 329 } 330 331 if (rtinfo->flags & IP6T_RT_LEN) { 332 printf("--rt-len %s%u ", 333 (rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "", 334 rtinfo->hdrlen); 335 } 336 337 if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res "); 338 if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs "); 339 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 340 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict "); 341 342} 343 344static struct ip6tables_match rt = { 345 .name = "rt", 346 .version = IPTABLES_VERSION, 347 .size = IP6T_ALIGN(sizeof(struct ip6t_rt)), 348 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_rt)), 349 .help = &help, 350 .init = &init, 351 .parse = &parse, 352 .final_check = &final_check, 353 .print = &print, 354 .save = &save, 355 .extra_opts = opts, 356}; 357 358void 359_init(void) 360{ 361 register_match6(&rt); 362} 363