libip6t_rt.c revision a42041665a9d5d08d52a5f1a27916743fbb2736c
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/netfilter_ipv6/ip6t_rt.h> 10 11/* Function which prints out usage message. */ 12static void 13help(void) 14{ 15 printf( 16"RT v%s options:\n" 17" --rt-type [!] type match the type\n" 18" --rt-segsleft [!] num[:num] match the Segments Left field (range)\n" 19" --rt-len [!] length total length of this header\n" 20" --rt-0-res check the reserved filed, too (type 0)\n" 21" --rt-0-addrs Type=0 addresses (list) - NOT SUPPORTED, yet\n", 22NETFILTER_VERSION); 23} 24 25static struct option opts[] = { 26 { "rt-type", 1, 0, '1' }, 27 { "rt-segsleft", 1, 0, '2' }, 28 { "rt-len", 1, 0, '3' }, 29 { "rt-0-res", 0, 0, '4' }, 30 { "rt-0-addrs", 0, 0, '5' }, 31 {0} 32}; 33 34static u_int32_t 35parse_rt_num(const char *idstr, const char *typestr) 36{ 37 unsigned long int id; 38 char* ep; 39 40 id = strtoul(idstr,&ep,0) ; 41 42 if ( idstr == ep ) { 43 exit_error(PARAMETER_PROBLEM, 44 "RT no valid digits in %s `%s'", typestr, idstr); 45 } 46 if ( id == ULONG_MAX && errno == ERANGE ) { 47 exit_error(PARAMETER_PROBLEM, 48 "%s `%s' specified too big: would overflow", 49 typestr, idstr); 50 } 51 if ( *idstr != '\0' && *ep != '\0' ) { 52 exit_error(PARAMETER_PROBLEM, 53 "RT error parsing %s `%s'", typestr, idstr); 54 } 55 return (u_int32_t) id; 56} 57 58static void 59parse_rt_segsleft(const char *idstring, u_int32_t *ids) 60{ 61 char *buffer; 62 char *cp; 63 64 buffer = strdup(idstring); 65 if ((cp = strchr(buffer, ':')) == NULL) 66 ids[0] = ids[1] = parse_rt_num(buffer,"segsleft"); 67 else { 68 *cp = '\0'; 69 cp++; 70 71 ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0; 72 ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF; 73 } 74 free(buffer); 75} 76 77/* Initialize the match. */ 78static void 79init(struct ip6t_entry_match *m, unsigned int *nfcache) 80{ 81 struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data; 82 83 rtinfo->rt_type = 0x0L; 84 rtinfo->segsleft[0] = 0x0L; 85 rtinfo->segsleft[1] = 0xFFFFFFFF; 86 rtinfo->hdrlen = 0; 87 rtinfo->flags = 0; 88 rtinfo->invflags = 0; 89} 90 91/* Function which parses command options; returns true if it 92 ate an option */ 93static int 94parse(int c, char **argv, int invert, unsigned int *flags, 95 const struct ip6t_entry *entry, 96 unsigned int *nfcache, 97 struct ip6t_entry_match **match) 98{ 99 struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data; 100 101 switch (c) { 102 case '1': 103 if (*flags & IP6T_RT_TYP) 104 exit_error(PARAMETER_PROBLEM, 105 "Only one `--rt-type' allowed"); 106 check_inverse(optarg, &invert, &optind, 0); 107 rtinfo->rt_type = parse_rt_num(argv[optind-1], "type"); 108 if (invert) 109 rtinfo->invflags |= IP6T_RT_INV_TYP; 110 rtinfo->flags |= IP6T_RT_TYP; 111 *flags |= IP6T_RT_TYP; 112 break; 113 case '2': 114 if (*flags & IP6T_RT_SGS) 115 exit_error(PARAMETER_PROBLEM, 116 "Only one `--rt-segsleft' allowed"); 117 check_inverse(optarg, &invert, &optind, 0); 118 parse_rt_segsleft(argv[optind-1], rtinfo->segsleft); 119 if (invert) 120 rtinfo->invflags |= IP6T_RT_INV_SGS; 121 rtinfo->flags |= IP6T_RT_SGS; 122 *flags |= IP6T_RT_SGS; 123 break; 124 case '3': 125 if (*flags & IP6T_RT_LEN) 126 exit_error(PARAMETER_PROBLEM, 127 "Only one `--rt-len' allowed"); 128 check_inverse(optarg, &invert, &optind, 0); 129 rtinfo->hdrlen = parse_rt_num(argv[optind-1], "length"); 130 if (invert) 131 rtinfo->invflags |= IP6T_RT_INV_LEN; 132 rtinfo->flags |= IP6T_RT_LEN; 133 *flags |= IP6T_RT_LEN; 134 break; 135 case '4': 136 if (*flags & IP6T_RT_RES) 137 exit_error(PARAMETER_PROBLEM, 138 "Only one `--rt-0-res' allowed"); 139 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) 140 exit_error(PARAMETER_PROBLEM, 141 "`--rt-type 0' required before `--rt-0-res'"); 142 rtinfo->flags |= IP6T_RT_RES; 143 *flags |= IP6T_RT_RES; 144 break; 145 case '5': 146 if (*flags & IP6T_RT_FST) 147 exit_error(PARAMETER_PROBLEM, 148 "Only one `--rt-0-addrs' allowed"); 149 if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) 150 exit_error(PARAMETER_PROBLEM, 151 "`--rt-type 0' required before `--rt-0-res'"); 152 /* TODO: implement it! */ 153 exit_error(PARAMETER_PROBLEM, 154 " `--rt-0-addrs' not supported, yet"); 155 rtinfo->flags |= IP6T_RT_FST; 156 *flags |= IP6T_RT_FST; 157 break; 158 default: 159 return 0; 160 } 161 162 return 1; 163} 164 165/* Final check; we don't care. */ 166static void 167final_check(unsigned int flags) 168{ 169} 170 171static void 172print_nums(const char *name, u_int32_t min, u_int32_t max, 173 int invert) 174{ 175 const char *inv = invert ? "!" : ""; 176 177 if (min != 0 || max != 0xFFFFFFFF || invert) { 178 printf("%s", name); 179 if (min == max) { 180 printf(":%s", inv); 181 printf("%u", min); 182 } else { 183 printf("s:%s", inv); 184 printf("%u",min); 185 printf(":"); 186 printf("%u",max); 187 } 188 printf(" "); 189 } 190} 191 192/* Prints out the union ip6t_matchinfo. */ 193static void 194print(const struct ip6t_ip6 *ip, 195 const struct ip6t_entry_match *match, int numeric) 196{ 197 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 198 199 printf("rt "); 200 if (rtinfo->flags & IP6T_RT_TYP) 201 printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", 202 rtinfo->rt_type); 203 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1], 204 rtinfo->invflags & IP6T_RT_INV_SGS); 205 if (rtinfo->flags & IP6T_RT_LEN) { 206 printf("length"); 207 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : ""); 208 printf("%u", rtinfo->hdrlen); 209 printf(" "); 210 } 211 if (rtinfo->flags & IP6T_RT_RES) printf("reserved "); 212 if (rtinfo->flags & IP6T_RT_FST) printf("type0-addrs "); 213 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) 214 printf("Unknown invflags: 0x%X ", 215 rtinfo->invflags & ~IP6T_RT_INV_MASK); 216} 217 218/* Saves the union ip6t_matchinfo in parsable form to stdout. */ 219static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) 220{ 221 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 222 223 if (rtinfo->flags & IP6T_RT_TYP) { 224 printf("--rt-type %s%u ", 225 (rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "", 226 rtinfo->rt_type); 227 } 228 229 if (!(rtinfo->segsleft[0] == 0 230 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { 231 printf("--rt-segsleft %s", 232 (rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : ""); 233 if (rtinfo->segsleft[0] 234 != rtinfo->segsleft[1]) 235 printf("%u:%u ", 236 rtinfo->segsleft[0], 237 rtinfo->segsleft[1]); 238 else 239 printf("%u ", 240 rtinfo->segsleft[0]); 241 } 242 243 if (rtinfo->flags & IP6T_RT_LEN) { 244 printf("--rt-len %s%u ", 245 (rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "", 246 rtinfo->hdrlen); 247 } 248 249 if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res "); 250 if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs "); 251 252} 253 254static 255struct ip6tables_match rt 256= { NULL, 257 "rt", 258 NETFILTER_VERSION, 259 IP6T_ALIGN(sizeof(struct ip6t_rt)), 260 IP6T_ALIGN(sizeof(struct ip6t_rt)), 261 &help, 262 &init, 263 &parse, 264 &final_check, 265 &print, 266 &save, 267 opts 268}; 269 270void 271_init(void) 272{ 273 register_match6(&rt); 274} 275