libxt_iprange.c revision dbe6c3b74ee847707181f1fe28b2975b4a8ab425
1/* Shared library add-on to iptables to add IP range matching support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7 8#include <xtables.h> 9#include <linux/netfilter.h> 10#include <linux/netfilter/xt_iprange.h> 11#include <linux/netfilter_ipv4/ipt_iprange.h> 12 13enum { 14 F_SRCIP = 1 << 0, 15 F_DSTIP = 1 << 1, 16}; 17 18static void iprange_mt_help(void) 19{ 20 printf( 21"iprange match options:\n" 22"[!] --src-range ip-ip Match source IP in the specified range\n" 23"[!] --dst-range ip-ip Match destination IP in the specified range\n" 24"\n"); 25} 26 27static const struct option iprange_mt_opts[] = { 28 {.name = "src-range", .has_arg = true, .val = '1'}, 29 {.name = "dst-range", .has_arg = true, .val = '2'}, 30 { .name = NULL } 31}; 32 33static void 34parse_iprange(char *arg, struct ipt_iprange *range) 35{ 36 char *dash; 37 const struct in_addr *ip; 38 39 dash = strchr(arg, '-'); 40 if (dash != NULL) 41 *dash = '\0'; 42 43 ip = numeric_to_ipaddr(arg); 44 if (!ip) 45 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n", 46 arg); 47 range->min_ip = ip->s_addr; 48 49 if (dash != NULL) { 50 ip = numeric_to_ipaddr(dash+1); 51 if (!ip) 52 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n", 53 dash+1); 54 range->max_ip = ip->s_addr; 55 } else { 56 range->max_ip = range->min_ip; 57 } 58} 59 60static int iprange_parse(int c, char **argv, int invert, unsigned int *flags, 61 const void *entry, struct xt_entry_match **match) 62{ 63 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data; 64 65 switch (c) { 66 case '1': 67 if (*flags & IPRANGE_SRC) 68 exit_error(PARAMETER_PROBLEM, 69 "iprange match: Only use --src-range ONCE!"); 70 *flags |= IPRANGE_SRC; 71 72 info->flags |= IPRANGE_SRC; 73 check_inverse(optarg, &invert, &optind, 0); 74 if (invert) 75 info->flags |= IPRANGE_SRC_INV; 76 parse_iprange(optarg, &info->src); 77 78 break; 79 80 case '2': 81 if (*flags & IPRANGE_DST) 82 exit_error(PARAMETER_PROBLEM, 83 "iprange match: Only use --dst-range ONCE!"); 84 *flags |= IPRANGE_DST; 85 86 info->flags |= IPRANGE_DST; 87 check_inverse(optarg, &invert, &optind, 0); 88 if (invert) 89 info->flags |= IPRANGE_DST_INV; 90 91 parse_iprange(optarg, &info->dst); 92 93 break; 94 95 default: 96 return 0; 97 } 98 return 1; 99} 100 101static int 102iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 103 const void *entry, struct xt_entry_match **match) 104{ 105 struct xt_iprange_mtinfo *info = (void *)(*match)->data; 106 const struct in_addr *ia; 107 char *end; 108 109 switch (c) { 110 case '1': /* --src-ip */ 111 end = strchr(optarg, '-'); 112 if (end == NULL) 113 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg); 114 *end = '\0'; 115 ia = numeric_to_ipaddr(optarg); 116 if (ia == NULL) 117 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg); 118 memcpy(&info->src_min.in, ia, sizeof(*ia)); 119 ia = numeric_to_ipaddr(end+1); 120 if (ia == NULL) 121 param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1); 122 memcpy(&info->src_max.in, ia, sizeof(*ia)); 123 *flags |= F_SRCIP; 124 return true; 125 126 case '2': /* --dst-ip */ 127 end = strchr(optarg, '-'); 128 if (end == NULL) 129 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg); 130 *end = '\0'; 131 ia = numeric_to_ipaddr(optarg); 132 if (ia == NULL) 133 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg); 134 memcpy(&info->dst_min.in, ia, sizeof(*ia)); 135 ia = numeric_to_ipaddr(end + 1); 136 if (ia == NULL) 137 param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1); 138 memcpy(&info->dst_max.in, ia, sizeof(*ia)); 139 *flags |= F_DSTIP; 140 return true; 141 } 142 return false; 143} 144 145static int 146iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 147 const void *entry, struct xt_entry_match **match) 148{ 149 struct xt_iprange_mtinfo *info = (void *)(*match)->data; 150 const struct in6_addr *ia; 151 char *end; 152 153 switch (c) { 154 case '1': /* --src-ip */ 155 end = strchr(optarg, '-'); 156 if (end == NULL) 157 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg); 158 *end = '\0'; 159 ia = numeric_to_ip6addr(optarg); 160 if (ia == NULL) 161 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg); 162 memcpy(&info->src_min.in, ia, sizeof(*ia)); 163 ia = numeric_to_ip6addr(end+1); 164 if (ia == NULL) 165 param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1); 166 memcpy(&info->src_max.in, ia, sizeof(*ia)); 167 info->flags |= IPRANGE_SRC; 168 if (invert) 169 info->flags |= IPRANGE_SRC_INV; 170 *flags |= F_SRCIP; 171 return true; 172 173 case '2': /* --dst-ip */ 174 end = strchr(optarg, '-'); 175 if (end == NULL) 176 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg); 177 *end = '\0'; 178 ia = numeric_to_ip6addr(optarg); 179 if (ia == NULL) 180 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg); 181 memcpy(&info->dst_min.in, ia, sizeof(*ia)); 182 ia = numeric_to_ip6addr(end + 1); 183 if (ia == NULL) 184 param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1); 185 memcpy(&info->dst_max.in, ia, sizeof(*ia)); 186 info->flags |= IPRANGE_DST; 187 if (invert) 188 info->flags |= IPRANGE_DST_INV; 189 *flags |= F_DSTIP; 190 return true; 191 } 192 return false; 193} 194 195static void iprange_mt_check(unsigned int flags) 196{ 197 if (flags == 0) 198 exit_error(PARAMETER_PROBLEM, 199 "iprange match: You must specify `--src-range' or `--dst-range'"); 200} 201 202static void 203print_iprange(const struct ipt_iprange *range) 204{ 205 const unsigned char *byte_min, *byte_max; 206 207 byte_min = (const unsigned char *)&range->min_ip; 208 byte_max = (const unsigned char *)&range->max_ip; 209 printf("%u.%u.%u.%u-%u.%u.%u.%u ", 210 byte_min[0], byte_min[1], byte_min[2], byte_min[3], 211 byte_max[0], byte_max[1], byte_max[2], byte_max[3]); 212} 213 214static void iprange_print(const void *ip, const struct xt_entry_match *match, 215 int numeric) 216{ 217 const struct ipt_iprange_info *info = (const void *)match->data; 218 219 if (info->flags & IPRANGE_SRC) { 220 printf("source IP range "); 221 if (info->flags & IPRANGE_SRC_INV) 222 printf("! "); 223 print_iprange(&info->src); 224 } 225 if (info->flags & IPRANGE_DST) { 226 printf("destination IP range "); 227 if (info->flags & IPRANGE_DST_INV) 228 printf("! "); 229 print_iprange(&info->dst); 230 } 231} 232 233static void 234iprange_mt4_print(const void *ip, const struct xt_entry_match *match, 235 int numeric) 236{ 237 const struct xt_iprange_mtinfo *info = (const void *)match->data; 238 239 if (info->flags & IPRANGE_SRC) { 240 printf("source IP range "); 241 if (info->flags & IPRANGE_SRC_INV) 242 printf("! "); 243 /* 244 * ipaddr_to_numeric() uses a static buffer, so cannot 245 * combine the printf() calls. 246 */ 247 printf("%s", ipaddr_to_numeric(&info->src_min.in)); 248 printf("-%s ", ipaddr_to_numeric(&info->src_max.in)); 249 } 250 if (info->flags & IPRANGE_DST) { 251 printf("destination IP range "); 252 if (info->flags & IPRANGE_DST_INV) 253 printf("! "); 254 printf("%s", ipaddr_to_numeric(&info->dst_min.in)); 255 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in)); 256 } 257} 258 259static void 260iprange_mt6_print(const void *ip, const struct xt_entry_match *match, 261 int numeric) 262{ 263 const struct xt_iprange_mtinfo *info = (const void *)match->data; 264 265 if (info->flags & IPRANGE_SRC) { 266 printf("source IP range "); 267 if (info->flags & IPRANGE_SRC_INV) 268 printf("! "); 269 /* 270 * ipaddr_to_numeric() uses a static buffer, so cannot 271 * combine the printf() calls. 272 */ 273 printf("%s", ip6addr_to_numeric(&info->src_min.in6)); 274 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6)); 275 } 276 if (info->flags & IPRANGE_DST) { 277 printf("destination IP range "); 278 if (info->flags & IPRANGE_DST_INV) 279 printf("! "); 280 printf("%s", ip6addr_to_numeric(&info->dst_min.in6)); 281 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6)); 282 } 283} 284 285static void iprange_save(const void *ip, const struct xt_entry_match *match) 286{ 287 const struct ipt_iprange_info *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 "); 293 print_iprange(&info->src); 294 if (info->flags & IPRANGE_DST) 295 fputc(' ', stdout); 296 } 297 if (info->flags & IPRANGE_DST) { 298 if (info->flags & IPRANGE_DST_INV) 299 printf("! "); 300 printf("--dst-range "); 301 print_iprange(&info->dst); 302 } 303} 304 305static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match) 306{ 307 const struct xt_iprange_mtinfo *info = (const void *)match->data; 308 309 if (info->flags & IPRANGE_SRC) { 310 if (info->flags & IPRANGE_SRC_INV) 311 printf("! "); 312 printf("--src-range %s", ipaddr_to_numeric(&info->src_min.in)); 313 printf("-%s ", ipaddr_to_numeric(&info->src_max.in)); 314 } 315 if (info->flags & IPRANGE_DST) { 316 if (info->flags & IPRANGE_DST_INV) 317 printf("! "); 318 printf("--dst-range %s", ipaddr_to_numeric(&info->dst_min.in)); 319 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in)); 320 } 321} 322 323static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match) 324{ 325 const struct xt_iprange_mtinfo *info = (const void *)match->data; 326 327 if (info->flags & IPRANGE_SRC) { 328 if (info->flags & IPRANGE_SRC_INV) 329 printf("! "); 330 printf("--src-range %s", ip6addr_to_numeric(&info->src_min.in6)); 331 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6)); 332 } 333 if (info->flags & IPRANGE_DST) { 334 if (info->flags & IPRANGE_DST_INV) 335 printf("! "); 336 printf("--dst-range %s", ip6addr_to_numeric(&info->dst_min.in6)); 337 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6)); 338 } 339} 340 341static struct xtables_match iprange_match = { 342 .version = IPTABLES_VERSION, 343 .name = "iprange", 344 .revision = 0, 345 .family = AF_INET, 346 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)), 347 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)), 348 .help = iprange_mt_help, 349 .parse = iprange_parse, 350 .final_check = iprange_mt_check, 351 .print = iprange_print, 352 .save = iprange_save, 353 .extra_opts = iprange_mt_opts, 354}; 355 356static struct xtables_match iprange_mt_reg = { 357 .version = IPTABLES_VERSION, 358 .name = "iprange", 359 .revision = 1, 360 .family = AF_INET, 361 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 362 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 363 .help = iprange_mt_help, 364 .parse = iprange_mt4_parse, 365 .final_check = iprange_mt_check, 366 .print = iprange_mt4_print, 367 .save = iprange_mt4_save, 368 .extra_opts = iprange_mt_opts, 369}; 370 371static struct xtables_match iprange_mt6_reg = { 372 .version = IPTABLES_VERSION, 373 .name = "iprange", 374 .revision = 1, 375 .family = AF_INET6, 376 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 377 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 378 .help = iprange_mt_help, 379 .parse = iprange_mt6_parse, 380 .final_check = iprange_mt_check, 381 .print = iprange_mt6_print, 382 .save = iprange_mt6_save, 383 .extra_opts = iprange_mt_opts, 384}; 385 386void _init(void) 387{ 388 xtables_register_match(&iprange_match); 389 xtables_register_match(&iprange_mt_reg); 390 xtables_register_match(&iprange_mt6_reg); 391} 392