libip6t_rt.c revision ea146a982e26c42f9954f140276f8deeb2edbe98
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 const 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 xt_entry_match *m) 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 void *entry, 160 struct xt_entry_match **match) 161{ 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, 214 "`--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); 220 rtinfo->flags |= IP6T_RT_FST; 221 *flags |= IP6T_RT_FST; 222 break; 223 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; 233 default: 234 return 0; 235 } 236 237 return 1; 238} 239 240/* Final check; we don't care. */ 241static void 242final_check(unsigned int flags) 243{ 244} 245 246static void 247print_nums(const char *name, u_int32_t min, u_int32_t max, 248 int invert) 249{ 250 const char *inv = invert ? "!" : ""; 251 252 if (min != 0 || max != 0xFFFFFFFF || invert) { 253 printf("%s", name); 254 if (min == max) { 255 printf(":%s", inv); 256 printf("%u", min); 257 } else { 258 printf("s:%s", inv); 259 printf("%u",min); 260 printf(":"); 261 printf("%u",max); 262 } 263 printf(" "); 264 } 265} 266 267static void 268print_addresses(int addrnr, struct in6_addr *addrp) 269{ 270 unsigned int i; 271 272 for(i=0; i<addrnr; i++){ 273 printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' '); 274 } 275} 276 277/* Prints out the union ip6t_matchinfo. */ 278static void 279print(const void *ip, 280 const struct xt_entry_match *match, int numeric) 281{ 282 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 283 284 printf("rt "); 285 if (rtinfo->flags & IP6T_RT_TYP) 286 printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", 287 rtinfo->rt_type); 288 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1], 289 rtinfo->invflags & IP6T_RT_INV_SGS); 290 if (rtinfo->flags & IP6T_RT_LEN) { 291 printf("length"); 292 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : ""); 293 printf("%u", rtinfo->hdrlen); 294 printf(" "); 295 } 296 if (rtinfo->flags & IP6T_RT_RES) printf("reserved "); 297 if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs "); 298 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 299 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict "); 300 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) 301 printf("Unknown invflags: 0x%X ", 302 rtinfo->invflags & ~IP6T_RT_INV_MASK); 303} 304 305/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 306static void save(const void *ip, const struct xt_entry_match *match) 307{ 308 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 309 310 if (rtinfo->flags & IP6T_RT_TYP) { 311 printf("--rt-type %s%u ", 312 (rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "", 313 rtinfo->rt_type); 314 } 315 316 if (!(rtinfo->segsleft[0] == 0 317 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { 318 printf("--rt-segsleft %s", 319 (rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : ""); 320 if (rtinfo->segsleft[0] 321 != rtinfo->segsleft[1]) 322 printf("%u:%u ", 323 rtinfo->segsleft[0], 324 rtinfo->segsleft[1]); 325 else 326 printf("%u ", 327 rtinfo->segsleft[0]); 328 } 329 330 if (rtinfo->flags & IP6T_RT_LEN) { 331 printf("--rt-len %s%u ", 332 (rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "", 333 rtinfo->hdrlen); 334 } 335 336 if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res "); 337 if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs "); 338 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 339 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict "); 340 341} 342 343static struct ip6tables_match rt = { 344 .name = "rt", 345 .version = IPTABLES_VERSION, 346 .size = IP6T_ALIGN(sizeof(struct ip6t_rt)), 347 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_rt)), 348 .help = &help, 349 .init = &init, 350 .parse = &parse, 351 .final_check = &final_check, 352 .print = &print, 353 .save = &save, 354 .extra_opts = opts, 355}; 356 357void 358_init(void) 359{ 360 register_match6(&rt); 361} 362