1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <xtables.h> 5#include <linux/netfilter_ipv6/ip6t_rt.h> 6#include <arpa/inet.h> 7 8enum { 9 O_RT_TYPE = 0, 10 O_RT_SEGSLEFT, 11 O_RT_LEN, 12 O_RT0RES, 13 O_RT0ADDRS, 14 O_RT0NSTRICT, 15 F_RT_TYPE = 1 << O_RT_TYPE, 16 F_RT0ADDRS = 1 << O_RT0ADDRS, 17}; 18 19static void rt_help(void) 20{ 21 printf( 22"rt match 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 field 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", 29IP6T_RT_HOPS); 30} 31 32#define s struct ip6t_rt 33static const struct xt_option_entry rt_opts[] = { 34 {.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32, 35 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)}, 36 {.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC, 37 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)}, 38 {.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32, 39 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)}, 40 {.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE}, 41 {.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING}, 42 {.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE}, 43 XTOPT_TABLEEND, 44}; 45#undef s 46 47static const char * 48addr_to_numeric(const struct in6_addr *addrp) 49{ 50 static char buf[50+1]; 51 return inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); 52} 53 54static struct in6_addr * 55numeric_to_addr(const char *num) 56{ 57 static struct in6_addr ap; 58 int err; 59 60 if ((err=inet_pton(AF_INET6, num, &ap)) == 1) 61 return ≈ 62#ifdef DEBUG 63 fprintf(stderr, "\nnumeric2addr: %d\n", err); 64#endif 65 xtables_error(PARAMETER_PROBLEM, "bad address: %s", num); 66 67 return (struct in6_addr *)NULL; 68} 69 70 71static int 72parse_addresses(const char *addrstr, struct in6_addr *addrp) 73{ 74 char *buffer, *cp, *next; 75 unsigned int i; 76 77 buffer = strdup(addrstr); 78 if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed"); 79 80 for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++) 81 { 82 next=strchr(cp, ','); 83 if (next) *next++='\0'; 84 memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr)); 85#if DEBUG 86 printf("addr str: %s\n", cp); 87 printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp)))); 88 printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i]))); 89#endif 90 } 91 if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified"); 92 93 free(buffer); 94 95#if DEBUG 96 printf("addr nr: %d\n", i); 97#endif 98 99 return i; 100} 101 102static void rt_init(struct xt_entry_match *m) 103{ 104 struct ip6t_rt *rtinfo = (void *)m->data; 105 106 rtinfo->segsleft[1] = ~0U; 107} 108 109static void rt_parse(struct xt_option_call *cb) 110{ 111 struct ip6t_rt *rtinfo = cb->data; 112 113 xtables_option_parse(cb); 114 switch (cb->entry->id) { 115 case O_RT_TYPE: 116 if (cb->invert) 117 rtinfo->invflags |= IP6T_RT_INV_TYP; 118 rtinfo->flags |= IP6T_RT_TYP; 119 break; 120 case O_RT_SEGSLEFT: 121 if (cb->nvals == 1) 122 rtinfo->segsleft[1] = rtinfo->segsleft[0]; 123 if (cb->invert) 124 rtinfo->invflags |= IP6T_RT_INV_SGS; 125 rtinfo->flags |= IP6T_RT_SGS; 126 break; 127 case O_RT_LEN: 128 if (cb->invert) 129 rtinfo->invflags |= IP6T_RT_INV_LEN; 130 rtinfo->flags |= IP6T_RT_LEN; 131 break; 132 case O_RT0RES: 133 if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 || 134 rtinfo->invflags & IP6T_RT_INV_TYP) 135 xtables_error(PARAMETER_PROBLEM, 136 "`--rt-type 0' required before `--rt-0-res'"); 137 rtinfo->flags |= IP6T_RT_RES; 138 break; 139 case O_RT0ADDRS: 140 if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 || 141 rtinfo->invflags & IP6T_RT_INV_TYP) 142 xtables_error(PARAMETER_PROBLEM, 143 "`--rt-type 0' required before `--rt-0-addrs'"); 144 rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs); 145 rtinfo->flags |= IP6T_RT_FST; 146 break; 147 case O_RT0NSTRICT: 148 if (!(cb->xflags & F_RT0ADDRS)) 149 xtables_error(PARAMETER_PROBLEM, 150 "`--rt-0-addr ...' required before `--rt-0-not-strict'"); 151 rtinfo->flags |= IP6T_RT_FST_NSTRICT; 152 break; 153 } 154} 155 156static void 157print_nums(const char *name, uint32_t min, uint32_t max, 158 int invert) 159{ 160 const char *inv = invert ? "!" : ""; 161 162 if (min != 0 || max != 0xFFFFFFFF || invert) { 163 printf(" %s", name); 164 if (min == max) { 165 printf(":%s", inv); 166 printf("%u", min); 167 } else { 168 printf("s:%s", inv); 169 printf("%u",min); 170 printf(":"); 171 printf("%u",max); 172 } 173 } 174} 175 176static void 177print_addresses(unsigned int addrnr, struct in6_addr *addrp) 178{ 179 unsigned int i; 180 181 for(i=0; i<addrnr; i++){ 182 printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i]))); 183 } 184} 185 186static void rt_print(const void *ip, const struct xt_entry_match *match, 187 int numeric) 188{ 189 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 190 191 printf(" rt"); 192 if (rtinfo->flags & IP6T_RT_TYP) 193 printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", 194 rtinfo->rt_type); 195 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1], 196 rtinfo->invflags & IP6T_RT_INV_SGS); 197 if (rtinfo->flags & IP6T_RT_LEN) { 198 printf(" length"); 199 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : ""); 200 printf("%u", rtinfo->hdrlen); 201 } 202 if (rtinfo->flags & IP6T_RT_RES) printf(" reserved"); 203 if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs"); 204 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 205 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict"); 206 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) 207 printf(" Unknown invflags: 0x%X", 208 rtinfo->invflags & ~IP6T_RT_INV_MASK); 209} 210 211static void rt_save(const void *ip, const struct xt_entry_match *match) 212{ 213 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 214 215 if (rtinfo->flags & IP6T_RT_TYP) { 216 printf("%s --rt-type %u", 217 (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "", 218 rtinfo->rt_type); 219 } 220 221 if (!(rtinfo->segsleft[0] == 0 222 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { 223 printf("%s --rt-segsleft ", 224 (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : ""); 225 if (rtinfo->segsleft[0] 226 != rtinfo->segsleft[1]) 227 printf("%u:%u", 228 rtinfo->segsleft[0], 229 rtinfo->segsleft[1]); 230 else 231 printf("%u", 232 rtinfo->segsleft[0]); 233 } 234 235 if (rtinfo->flags & IP6T_RT_LEN) { 236 printf("%s --rt-len %u", 237 (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "", 238 rtinfo->hdrlen); 239 } 240 241 if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res"); 242 if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs"); 243 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 244 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict"); 245 246} 247 248static int rt_xlate(struct xt_xlate *xl, 249 const struct xt_xlate_mt_params *params) 250{ 251 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)params->match->data; 252 char *space = ""; 253 254 if (rtinfo->flags & IP6T_RT_TYP) { 255 xt_xlate_add(xl, "rt type%s %u", 256 (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !=" : "", 257 rtinfo->rt_type); 258 space = " "; 259 } 260 261 if (!(rtinfo->segsleft[0] == 0 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { 262 xt_xlate_add(xl, "%srt seg-left%s ", space, 263 (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !=" : ""); 264 265 if (rtinfo->segsleft[0] != rtinfo->segsleft[1]) 266 xt_xlate_add(xl, "%u-%u", rtinfo->segsleft[0], 267 rtinfo->segsleft[1]); 268 else 269 xt_xlate_add(xl, "%u", rtinfo->segsleft[0]); 270 space = " "; 271 } 272 273 if (rtinfo->flags & IP6T_RT_LEN) { 274 xt_xlate_add(xl, "%srt hdrlength%s %u", space, 275 (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !=" : "", 276 rtinfo->hdrlen); 277 } 278 279 if (rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST | IP6T_RT_FST_NSTRICT)) 280 return 0; 281 282 return 1; 283} 284 285static struct xtables_match rt_mt6_reg = { 286 .name = "rt", 287 .version = XTABLES_VERSION, 288 .family = NFPROTO_IPV6, 289 .size = XT_ALIGN(sizeof(struct ip6t_rt)), 290 .userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)), 291 .help = rt_help, 292 .init = rt_init, 293 .x6_parse = rt_parse, 294 .print = rt_print, 295 .save = rt_save, 296 .x6_options = rt_opts, 297 .xlate = rt_xlate, 298}; 299 300void 301_init(void) 302{ 303 xtables_register_match(&rt_mt6_reg); 304} 305