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