1 #include <stdint.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <xtables.h> 6 #include <linux/netfilter.h> 7 #include <linux/netfilter/xt_iprange.h> 8 9 struct ipt_iprange { 10 /* Inclusive: network order. */ 11 __be32 min_ip, max_ip; 12 }; 13 14 struct ipt_iprange_info { 15 struct ipt_iprange src; 16 struct ipt_iprange dst; 17 18 /* Flags from above */ 19 uint8_t flags; 20 }; 21 22 enum { 23 O_SRC_RANGE = 0, 24 O_DST_RANGE, 25 }; 26 27 static void iprange_mt_help(void) 28 { 29 printf( 30 "iprange match options:\n" 31 "[!] --src-range ip[-ip] Match source IP in the specified range\n" 32 "[!] --dst-range ip[-ip] Match destination IP in the specified range\n"); 33 } 34 35 static const struct xt_option_entry iprange_mt_opts[] = { 36 {.name = "src-range", .id = O_SRC_RANGE, .type = XTTYPE_STRING, 37 .flags = XTOPT_INVERT}, 38 {.name = "dst-range", .id = O_DST_RANGE, .type = XTTYPE_STRING, 39 .flags = XTOPT_INVERT}, 40 XTOPT_TABLEEND, 41 }; 42 43 static void 44 iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range, 45 uint8_t family, const char *optname) 46 { 47 const char *spec[2] = {from, to}; 48 struct in6_addr *ia6; 49 struct in_addr *ia4; 50 unsigned int i; 51 52 memset(range, 0, sizeof(union nf_inet_addr) * 2); 53 54 if (family == NFPROTO_IPV6) { 55 for (i = 0; i < ARRAY_SIZE(spec); ++i) { 56 ia6 = xtables_numeric_to_ip6addr(spec[i]); 57 if (ia6 == NULL) 58 xtables_param_act(XTF_BAD_VALUE, "iprange", 59 optname, spec[i]); 60 range[i].in6 = *ia6; 61 } 62 } else { 63 for (i = 0; i < ARRAY_SIZE(spec); ++i) { 64 ia4 = xtables_numeric_to_ipaddr(spec[i]); 65 if (ia4 == NULL) 66 xtables_param_act(XTF_BAD_VALUE, "iprange", 67 optname, spec[i]); 68 range[i].in = *ia4; 69 } 70 } 71 } 72 73 static void iprange_parse_range(const char *oarg, union nf_inet_addr *range, 74 uint8_t family, const char *optname) 75 { 76 char *arg = strdup(oarg); 77 char *dash; 78 79 if (arg == NULL) 80 xtables_error(RESOURCE_PROBLEM, "strdup"); 81 dash = strchr(arg, '-'); 82 if (dash == NULL) { 83 iprange_parse_spec(arg, arg, range, family, optname); 84 free(arg); 85 return; 86 } 87 88 *dash = '\0'; 89 iprange_parse_spec(arg, dash + 1, range, family, optname); 90 if (memcmp(&range[0], &range[1], sizeof(*range)) > 0) 91 fprintf(stderr, "xt_iprange: range %s-%s is reversed and " 92 "will never match\n", arg, dash + 1); 93 free(arg); 94 } 95 96 static void iprange_parse(struct xt_option_call *cb) 97 { 98 struct ipt_iprange_info *info = cb->data; 99 union nf_inet_addr range[2]; 100 101 xtables_option_parse(cb); 102 switch (cb->entry->id) { 103 case O_SRC_RANGE: 104 info->flags |= IPRANGE_SRC; 105 if (cb->invert) 106 info->flags |= IPRANGE_SRC_INV; 107 iprange_parse_range(cb->arg, range, 108 NFPROTO_IPV4, "--src-range"); 109 info->src.min_ip = range[0].ip; 110 info->src.max_ip = range[1].ip; 111 break; 112 case O_DST_RANGE: 113 info->flags |= IPRANGE_DST; 114 if (cb->invert) 115 info->flags |= IPRANGE_DST_INV; 116 iprange_parse_range(cb->arg, range, 117 NFPROTO_IPV4, "--dst-range"); 118 info->dst.min_ip = range[0].ip; 119 info->dst.max_ip = range[1].ip; 120 break; 121 } 122 } 123 124 static void iprange_mt_parse(struct xt_option_call *cb, uint8_t nfproto) 125 { 126 struct xt_iprange_mtinfo *info = cb->data; 127 128 xtables_option_parse(cb); 129 switch (cb->entry->id) { 130 case O_SRC_RANGE: 131 iprange_parse_range(cb->arg, &info->src_min, nfproto, 132 "--src-range"); 133 info->flags |= IPRANGE_SRC; 134 if (cb->invert) 135 info->flags |= IPRANGE_SRC_INV; 136 break; 137 case O_DST_RANGE: 138 iprange_parse_range(cb->arg, &info->dst_min, nfproto, 139 "--dst-range"); 140 info->flags |= IPRANGE_DST; 141 if (cb->invert) 142 info->flags |= IPRANGE_DST_INV; 143 break; 144 } 145 } 146 147 static void iprange_mt4_parse(struct xt_option_call *cb) 148 { 149 iprange_mt_parse(cb, NFPROTO_IPV4); 150 } 151 152 static void iprange_mt6_parse(struct xt_option_call *cb) 153 { 154 iprange_mt_parse(cb, NFPROTO_IPV6); 155 } 156 157 static void iprange_mt_check(struct xt_fcheck_call *cb) 158 { 159 if (cb->xflags == 0) 160 xtables_error(PARAMETER_PROBLEM, 161 "iprange match: You must specify `--src-range' or `--dst-range'"); 162 } 163 164 static void 165 print_iprange(const struct ipt_iprange *range) 166 { 167 const unsigned char *byte_min, *byte_max; 168 169 byte_min = (const unsigned char *)&range->min_ip; 170 byte_max = (const unsigned char *)&range->max_ip; 171 printf(" %u.%u.%u.%u-%u.%u.%u.%u", 172 byte_min[0], byte_min[1], byte_min[2], byte_min[3], 173 byte_max[0], byte_max[1], byte_max[2], byte_max[3]); 174 } 175 176 static void iprange_print(const void *ip, const struct xt_entry_match *match, 177 int numeric) 178 { 179 const struct ipt_iprange_info *info = (const void *)match->data; 180 181 if (info->flags & IPRANGE_SRC) { 182 printf(" source IP range"); 183 if (info->flags & IPRANGE_SRC_INV) 184 printf(" !"); 185 print_iprange(&info->src); 186 } 187 if (info->flags & IPRANGE_DST) { 188 printf(" destination IP range"); 189 if (info->flags & IPRANGE_DST_INV) 190 printf(" !"); 191 print_iprange(&info->dst); 192 } 193 } 194 195 static void 196 iprange_mt4_print(const void *ip, const struct xt_entry_match *match, 197 int numeric) 198 { 199 const struct xt_iprange_mtinfo *info = (const void *)match->data; 200 201 if (info->flags & IPRANGE_SRC) { 202 printf(" source IP range"); 203 if (info->flags & IPRANGE_SRC_INV) 204 printf(" !"); 205 /* 206 * ipaddr_to_numeric() uses a static buffer, so cannot 207 * combine the printf() calls. 208 */ 209 printf(" %s", xtables_ipaddr_to_numeric(&info->src_min.in)); 210 printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); 211 } 212 if (info->flags & IPRANGE_DST) { 213 printf(" destination IP range"); 214 if (info->flags & IPRANGE_DST_INV) 215 printf(" !"); 216 printf(" %s", xtables_ipaddr_to_numeric(&info->dst_min.in)); 217 printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in)); 218 } 219 } 220 221 static void 222 iprange_mt6_print(const void *ip, const struct xt_entry_match *match, 223 int numeric) 224 { 225 const struct xt_iprange_mtinfo *info = (const void *)match->data; 226 227 if (info->flags & IPRANGE_SRC) { 228 printf(" source IP range"); 229 if (info->flags & IPRANGE_SRC_INV) 230 printf(" !"); 231 /* 232 * ipaddr_to_numeric() uses a static buffer, so cannot 233 * combine the printf() calls. 234 */ 235 printf(" %s", xtables_ip6addr_to_numeric(&info->src_min.in6)); 236 printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); 237 } 238 if (info->flags & IPRANGE_DST) { 239 printf(" destination IP range"); 240 if (info->flags & IPRANGE_DST_INV) 241 printf(" !"); 242 printf(" %s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); 243 printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6)); 244 } 245 } 246 247 static void iprange_save(const void *ip, const struct xt_entry_match *match) 248 { 249 const struct ipt_iprange_info *info = (const void *)match->data; 250 251 if (info->flags & IPRANGE_SRC) { 252 if (info->flags & IPRANGE_SRC_INV) 253 printf(" !"); 254 printf(" --src-range"); 255 print_iprange(&info->src); 256 } 257 if (info->flags & IPRANGE_DST) { 258 if (info->flags & IPRANGE_DST_INV) 259 printf(" !"); 260 printf(" --dst-range"); 261 print_iprange(&info->dst); 262 } 263 } 264 265 static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match) 266 { 267 const struct xt_iprange_mtinfo *info = (const void *)match->data; 268 269 if (info->flags & IPRANGE_SRC) { 270 if (info->flags & IPRANGE_SRC_INV) 271 printf(" !"); 272 printf(" --src-range %s", 273 xtables_ipaddr_to_numeric(&info->src_min.in)); 274 printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); 275 } 276 if (info->flags & IPRANGE_DST) { 277 if (info->flags & IPRANGE_DST_INV) 278 printf(" !"); 279 printf(" --dst-range %s", 280 xtables_ipaddr_to_numeric(&info->dst_min.in)); 281 printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in)); 282 } 283 } 284 285 static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match) 286 { 287 const struct xt_iprange_mtinfo *info = (const void *)match->data; 288 289 if (info->flags & IPRANGE_SRC) { 290 if (info->flags & IPRANGE_SRC_INV) 291 printf(" !"); 292 printf(" --src-range %s", 293 xtables_ip6addr_to_numeric(&info->src_min.in6)); 294 printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); 295 } 296 if (info->flags & IPRANGE_DST) { 297 if (info->flags & IPRANGE_DST_INV) 298 printf(" !"); 299 printf(" --dst-range %s", 300 xtables_ip6addr_to_numeric(&info->dst_min.in6)); 301 printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6)); 302 } 303 } 304 305 static void 306 print_iprange_xlate(const struct ipt_iprange *range, 307 struct xt_xlate *xl) 308 { 309 const unsigned char *byte_min, *byte_max; 310 311 byte_min = (const unsigned char *)&range->min_ip; 312 byte_max = (const unsigned char *)&range->max_ip; 313 xt_xlate_add(xl, " %u.%u.%u.%u-%u.%u.%u.%u ", 314 byte_min[0], byte_min[1], byte_min[2], byte_min[3], 315 byte_max[0], byte_max[1], byte_max[2], byte_max[3]); 316 } 317 318 static int iprange_xlate(struct xt_xlate *xl, 319 const struct xt_xlate_mt_params *params) 320 { 321 const struct ipt_iprange_info *info = (const void *)params->match->data; 322 char *space = ""; 323 324 if (info->flags & IPRANGE_SRC) { 325 xt_xlate_add(xl, "ip saddr%s", 326 info->flags & IPRANGE_SRC_INV ? " !=" : ""); 327 print_iprange_xlate(&info->src, xl); 328 space = " "; 329 } 330 if (info->flags & IPRANGE_DST) { 331 xt_xlate_add(xl, "%sip daddr%s", space, 332 info->flags & IPRANGE_DST_INV ? " !=" : ""); 333 print_iprange_xlate(&info->dst, xl); 334 } 335 336 return 1; 337 } 338 339 static int iprange_mt4_xlate(struct xt_xlate *xl, 340 const struct xt_xlate_mt_params *params) 341 { 342 const struct xt_iprange_mtinfo *info = 343 (const void *)params->match->data; 344 char *space = ""; 345 346 if (info->flags & IPRANGE_SRC) { 347 xt_xlate_add(xl, "ip saddr%s %s", 348 info->flags & IPRANGE_SRC_INV ? " !=" : "", 349 xtables_ipaddr_to_numeric(&info->src_min.in)); 350 xt_xlate_add(xl, "-%s", 351 xtables_ipaddr_to_numeric(&info->src_max.in)); 352 space = " "; 353 } 354 if (info->flags & IPRANGE_DST) { 355 xt_xlate_add(xl, "%sip daddr%s %s", space, 356 info->flags & IPRANGE_DST_INV ? " !=" : "", 357 xtables_ipaddr_to_numeric(&info->dst_min.in)); 358 xt_xlate_add(xl, "-%s", 359 xtables_ipaddr_to_numeric(&info->dst_max.in)); 360 } 361 362 return 1; 363 } 364 365 static int iprange_mt6_xlate(struct xt_xlate *xl, 366 const struct xt_xlate_mt_params *params) 367 { 368 const struct xt_iprange_mtinfo *info = 369 (const void *)params->match->data; 370 char *space = ""; 371 372 if (info->flags & IPRANGE_SRC) { 373 xt_xlate_add(xl, "ip6 saddr%s %s", 374 info->flags & IPRANGE_SRC_INV ? " !=" : "", 375 xtables_ip6addr_to_numeric(&info->src_min.in6)); 376 xt_xlate_add(xl, "-%s", 377 xtables_ip6addr_to_numeric(&info->src_max.in6)); 378 space = " "; 379 } 380 if (info->flags & IPRANGE_DST) { 381 xt_xlate_add(xl, "%sip6 daddr%s %s", space, 382 info->flags & IPRANGE_DST_INV ? " !=" : "", 383 xtables_ip6addr_to_numeric(&info->dst_min.in6)); 384 xt_xlate_add(xl, "-%s", 385 xtables_ip6addr_to_numeric(&info->dst_max.in6)); 386 } 387 388 return 1; 389 } 390 391 static struct xtables_match iprange_mt_reg[] = { 392 { 393 .version = XTABLES_VERSION, 394 .name = "iprange", 395 .revision = 0, 396 .family = NFPROTO_IPV4, 397 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)), 398 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)), 399 .help = iprange_mt_help, 400 .x6_parse = iprange_parse, 401 .x6_fcheck = iprange_mt_check, 402 .print = iprange_print, 403 .save = iprange_save, 404 .x6_options = iprange_mt_opts, 405 .xlate = iprange_xlate, 406 }, 407 { 408 .version = XTABLES_VERSION, 409 .name = "iprange", 410 .revision = 1, 411 .family = NFPROTO_IPV4, 412 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 413 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 414 .help = iprange_mt_help, 415 .x6_parse = iprange_mt4_parse, 416 .x6_fcheck = iprange_mt_check, 417 .print = iprange_mt4_print, 418 .save = iprange_mt4_save, 419 .x6_options = iprange_mt_opts, 420 .xlate = iprange_mt4_xlate, 421 }, 422 { 423 .version = XTABLES_VERSION, 424 .name = "iprange", 425 .revision = 1, 426 .family = NFPROTO_IPV6, 427 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 428 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 429 .help = iprange_mt_help, 430 .x6_parse = iprange_mt6_parse, 431 .x6_fcheck = iprange_mt_check, 432 .print = iprange_mt6_print, 433 .save = iprange_mt6_save, 434 .x6_options = iprange_mt_opts, 435 .xlate = iprange_mt6_xlate, 436 }, 437 }; 438 439 void _init(void) 440 { 441 xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 442 } 443