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