libip6t_rt.c revision 65c0621d48e818d75f8c2810e93eb405a6d31406
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_UINT32RC, 35 .flags = XTOPT_INVERT}, 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 = (struct ip6t_rt *)m->data; 105 106 rtinfo->segsleft[1] = 0xFFFFFFFF; 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->invert) 122 rtinfo->invflags |= IP6T_RT_INV_SGS; 123 rtinfo->flags |= IP6T_RT_SGS; 124 break; 125 case O_RT_LEN: 126 if (cb->invert) 127 rtinfo->invflags |= IP6T_RT_INV_LEN; 128 rtinfo->flags |= IP6T_RT_LEN; 129 break; 130 case O_RT0RES: 131 if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 || 132 rtinfo->invflags & IP6T_RT_INV_TYP) 133 xtables_error(PARAMETER_PROBLEM, 134 "`--rt-type 0' required before `--rt-0-res'"); 135 rtinfo->flags |= IP6T_RT_RES; 136 break; 137 case O_RT0ADDRS: 138 if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 || 139 rtinfo->invflags & IP6T_RT_INV_TYP) 140 xtables_error(PARAMETER_PROBLEM, 141 "`--rt-type 0' required before `--rt-0-addrs'"); 142 rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs); 143 rtinfo->flags |= IP6T_RT_FST; 144 break; 145 case O_RT0NSTRICT: 146 if (!(cb->xflags & F_RT0ADDRS)) 147 xtables_error(PARAMETER_PROBLEM, 148 "`--rt-0-addr ...' required before `--rt-0-not-strict'"); 149 rtinfo->flags |= IP6T_RT_FST_NSTRICT; 150 break; 151 } 152} 153 154static void 155print_nums(const char *name, uint32_t min, uint32_t max, 156 int invert) 157{ 158 const char *inv = invert ? "!" : ""; 159 160 if (min != 0 || max != 0xFFFFFFFF || invert) { 161 printf(" %s", name); 162 if (min == max) { 163 printf(":%s", inv); 164 printf("%u", min); 165 } else { 166 printf("s:%s", inv); 167 printf("%u",min); 168 printf(":"); 169 printf("%u",max); 170 } 171 } 172} 173 174static void 175print_addresses(unsigned int addrnr, struct in6_addr *addrp) 176{ 177 unsigned int i; 178 179 for(i=0; i<addrnr; i++){ 180 printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i]))); 181 } 182} 183 184static void rt_print(const void *ip, const struct xt_entry_match *match, 185 int numeric) 186{ 187 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 188 189 printf(" rt"); 190 if (rtinfo->flags & IP6T_RT_TYP) 191 printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", 192 rtinfo->rt_type); 193 print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1], 194 rtinfo->invflags & IP6T_RT_INV_SGS); 195 if (rtinfo->flags & IP6T_RT_LEN) { 196 printf(" length"); 197 printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : ""); 198 printf("%u", rtinfo->hdrlen); 199 } 200 if (rtinfo->flags & IP6T_RT_RES) printf(" reserved"); 201 if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs"); 202 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 203 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict"); 204 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) 205 printf(" Unknown invflags: 0x%X", 206 rtinfo->invflags & ~IP6T_RT_INV_MASK); 207} 208 209static void rt_save(const void *ip, const struct xt_entry_match *match) 210{ 211 const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; 212 213 if (rtinfo->flags & IP6T_RT_TYP) { 214 printf("%s --rt-type %u", 215 (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "", 216 rtinfo->rt_type); 217 } 218 219 if (!(rtinfo->segsleft[0] == 0 220 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { 221 printf("%s --rt-segsleft ", 222 (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : ""); 223 if (rtinfo->segsleft[0] 224 != rtinfo->segsleft[1]) 225 printf("%u:%u", 226 rtinfo->segsleft[0], 227 rtinfo->segsleft[1]); 228 else 229 printf("%u", 230 rtinfo->segsleft[0]); 231 } 232 233 if (rtinfo->flags & IP6T_RT_LEN) { 234 printf("%s --rt-len %u", 235 (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "", 236 rtinfo->hdrlen); 237 } 238 239 if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res"); 240 if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs"); 241 print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); 242 if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict"); 243 244} 245 246static struct xtables_match rt_mt6_reg = { 247 .name = "rt", 248 .version = XTABLES_VERSION, 249 .family = NFPROTO_IPV6, 250 .size = XT_ALIGN(sizeof(struct ip6t_rt)), 251 .userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)), 252 .help = rt_help, 253 .init = rt_init, 254 .x6_parse = rt_parse, 255 .print = rt_print, 256 .save = rt_save, 257 .x6_options = rt_opts, 258}; 259 260void 261_init(void) 262{ 263 xtables_register_match(&rt_mt6_reg); 264} 265