libxt_iprange.c revision 240eee607ab7e5bb9f671b7ceba40e2940182f61
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 <netinet/in.h> 9#include <xtables.h> 10#include <linux/netfilter.h> 11#include <linux/netfilter/xt_iprange.h> 12#include <linux/netfilter_ipv4/ipt_iprange.h> 13 14enum { 15 F_SRCIP = 1 << 0, 16 F_DSTIP = 1 << 1, 17}; 18 19static void iprange_mt_help(void) 20{ 21 printf( 22"iprange match options:\n" 23"[!] --src-range ip-ip Match source IP in the specified range\n" 24"[!] --dst-range ip-ip Match destination IP in the specified range\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-range */ 111 end = strchr(optarg, '-'); 112 if (end == NULL) 113 param_act(P_BAD_VALUE, "iprange", "--src-range", optarg); 114 *end = '\0'; 115 ia = numeric_to_ipaddr(optarg); 116 if (ia == NULL) 117 param_act(P_BAD_VALUE, "iprange", "--src-range", 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-range", end + 1); 122 memcpy(&info->src_max.in, ia, sizeof(*ia)); 123 info->flags |= IPRANGE_SRC; 124 if (invert) 125 info->flags |= IPRANGE_SRC_INV; 126 *flags |= F_SRCIP; 127 return true; 128 129 case '2': /* --dst-range */ 130 end = strchr(optarg, '-'); 131 if (end == NULL) 132 param_act(P_BAD_VALUE, "iprange", "--dst-range", optarg); 133 *end = '\0'; 134 ia = numeric_to_ipaddr(optarg); 135 if (ia == NULL) 136 param_act(P_BAD_VALUE, "iprange", "--dst-range", optarg); 137 memcpy(&info->dst_min.in, ia, sizeof(*ia)); 138 ia = numeric_to_ipaddr(end + 1); 139 if (ia == NULL) 140 param_act(P_BAD_VALUE, "iprange", "--dst-range", end + 1); 141 memcpy(&info->dst_max.in, ia, sizeof(*ia)); 142 info->flags |= IPRANGE_DST; 143 if (invert) 144 info->flags |= IPRANGE_DST_INV; 145 *flags |= F_DSTIP; 146 return true; 147 } 148 return false; 149} 150 151static int 152iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 153 const void *entry, struct xt_entry_match **match) 154{ 155 struct xt_iprange_mtinfo *info = (void *)(*match)->data; 156 const struct in6_addr *ia; 157 char *end; 158 159 switch (c) { 160 case '1': /* --src-range */ 161 end = strchr(optarg, '-'); 162 if (end == NULL) 163 param_act(P_BAD_VALUE, "iprange", "--src-range", optarg); 164 *end = '\0'; 165 ia = numeric_to_ip6addr(optarg); 166 if (ia == NULL) 167 param_act(P_BAD_VALUE, "iprange", "--src-range", optarg); 168 memcpy(&info->src_min.in, ia, sizeof(*ia)); 169 ia = numeric_to_ip6addr(end+1); 170 if (ia == NULL) 171 param_act(P_BAD_VALUE, "iprange", "--src-range", end + 1); 172 memcpy(&info->src_max.in, ia, sizeof(*ia)); 173 info->flags |= IPRANGE_SRC; 174 if (invert) 175 info->flags |= IPRANGE_SRC_INV; 176 *flags |= F_SRCIP; 177 return true; 178 179 case '2': /* --dst-range */ 180 end = strchr(optarg, '-'); 181 if (end == NULL) 182 param_act(P_BAD_VALUE, "iprange", "--dst-range", optarg); 183 *end = '\0'; 184 ia = numeric_to_ip6addr(optarg); 185 if (ia == NULL) 186 param_act(P_BAD_VALUE, "iprange", "--dst-range", optarg); 187 memcpy(&info->dst_min.in, ia, sizeof(*ia)); 188 ia = numeric_to_ip6addr(end + 1); 189 if (ia == NULL) 190 param_act(P_BAD_VALUE, "iprange", "--dst-range", end + 1); 191 memcpy(&info->dst_max.in, ia, sizeof(*ia)); 192 info->flags |= IPRANGE_DST; 193 if (invert) 194 info->flags |= IPRANGE_DST_INV; 195 *flags |= F_DSTIP; 196 return true; 197 } 198 return false; 199} 200 201static void iprange_mt_check(unsigned int flags) 202{ 203 if (flags == 0) 204 exit_error(PARAMETER_PROBLEM, 205 "iprange match: You must specify `--src-range' or `--dst-range'"); 206} 207 208static void 209print_iprange(const struct ipt_iprange *range) 210{ 211 const unsigned char *byte_min, *byte_max; 212 213 byte_min = (const unsigned char *)&range->min_ip; 214 byte_max = (const unsigned char *)&range->max_ip; 215 printf("%u.%u.%u.%u-%u.%u.%u.%u ", 216 byte_min[0], byte_min[1], byte_min[2], byte_min[3], 217 byte_max[0], byte_max[1], byte_max[2], byte_max[3]); 218} 219 220static void iprange_print(const void *ip, const struct xt_entry_match *match, 221 int numeric) 222{ 223 const struct ipt_iprange_info *info = (const void *)match->data; 224 225 if (info->flags & IPRANGE_SRC) { 226 printf("source IP range "); 227 if (info->flags & IPRANGE_SRC_INV) 228 printf("! "); 229 print_iprange(&info->src); 230 } 231 if (info->flags & IPRANGE_DST) { 232 printf("destination IP range "); 233 if (info->flags & IPRANGE_DST_INV) 234 printf("! "); 235 print_iprange(&info->dst); 236 } 237} 238 239static void 240iprange_mt4_print(const void *ip, const struct xt_entry_match *match, 241 int numeric) 242{ 243 const struct xt_iprange_mtinfo *info = (const void *)match->data; 244 245 if (info->flags & IPRANGE_SRC) { 246 printf("source IP range "); 247 if (info->flags & IPRANGE_SRC_INV) 248 printf("! "); 249 /* 250 * ipaddr_to_numeric() uses a static buffer, so cannot 251 * combine the printf() calls. 252 */ 253 printf("%s", ipaddr_to_numeric(&info->src_min.in)); 254 printf("-%s ", ipaddr_to_numeric(&info->src_max.in)); 255 } 256 if (info->flags & IPRANGE_DST) { 257 printf("destination IP range "); 258 if (info->flags & IPRANGE_DST_INV) 259 printf("! "); 260 printf("%s", ipaddr_to_numeric(&info->dst_min.in)); 261 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in)); 262 } 263} 264 265static void 266iprange_mt6_print(const void *ip, const struct xt_entry_match *match, 267 int numeric) 268{ 269 const struct xt_iprange_mtinfo *info = (const void *)match->data; 270 271 if (info->flags & IPRANGE_SRC) { 272 printf("source IP range "); 273 if (info->flags & IPRANGE_SRC_INV) 274 printf("! "); 275 /* 276 * ipaddr_to_numeric() uses a static buffer, so cannot 277 * combine the printf() calls. 278 */ 279 printf("%s", ip6addr_to_numeric(&info->src_min.in6)); 280 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6)); 281 } 282 if (info->flags & IPRANGE_DST) { 283 printf("destination IP range "); 284 if (info->flags & IPRANGE_DST_INV) 285 printf("! "); 286 printf("%s", ip6addr_to_numeric(&info->dst_min.in6)); 287 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6)); 288 } 289} 290 291static void iprange_save(const void *ip, const struct xt_entry_match *match) 292{ 293 const struct ipt_iprange_info *info = (const void *)match->data; 294 295 if (info->flags & IPRANGE_SRC) { 296 if (info->flags & IPRANGE_SRC_INV) 297 printf("! "); 298 printf("--src-range "); 299 print_iprange(&info->src); 300 if (info->flags & IPRANGE_DST) 301 fputc(' ', stdout); 302 } 303 if (info->flags & IPRANGE_DST) { 304 if (info->flags & IPRANGE_DST_INV) 305 printf("! "); 306 printf("--dst-range "); 307 print_iprange(&info->dst); 308 } 309} 310 311static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match) 312{ 313 const struct xt_iprange_mtinfo *info = (const void *)match->data; 314 315 if (info->flags & IPRANGE_SRC) { 316 if (info->flags & IPRANGE_SRC_INV) 317 printf("! "); 318 printf("--src-range %s", ipaddr_to_numeric(&info->src_min.in)); 319 printf("-%s ", ipaddr_to_numeric(&info->src_max.in)); 320 } 321 if (info->flags & IPRANGE_DST) { 322 if (info->flags & IPRANGE_DST_INV) 323 printf("! "); 324 printf("--dst-range %s", ipaddr_to_numeric(&info->dst_min.in)); 325 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in)); 326 } 327} 328 329static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match) 330{ 331 const struct xt_iprange_mtinfo *info = (const void *)match->data; 332 333 if (info->flags & IPRANGE_SRC) { 334 if (info->flags & IPRANGE_SRC_INV) 335 printf("! "); 336 printf("--src-range %s", ip6addr_to_numeric(&info->src_min.in6)); 337 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6)); 338 } 339 if (info->flags & IPRANGE_DST) { 340 if (info->flags & IPRANGE_DST_INV) 341 printf("! "); 342 printf("--dst-range %s", ip6addr_to_numeric(&info->dst_min.in6)); 343 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6)); 344 } 345} 346 347static struct xtables_match iprange_match = { 348 .version = XTABLES_VERSION, 349 .name = "iprange", 350 .revision = 0, 351 .family = AF_INET, 352 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)), 353 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)), 354 .help = iprange_mt_help, 355 .parse = iprange_parse, 356 .final_check = iprange_mt_check, 357 .print = iprange_print, 358 .save = iprange_save, 359 .extra_opts = iprange_mt_opts, 360}; 361 362static struct xtables_match iprange_mt_reg = { 363 .version = XTABLES_VERSION, 364 .name = "iprange", 365 .revision = 1, 366 .family = AF_INET, 367 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 368 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 369 .help = iprange_mt_help, 370 .parse = iprange_mt4_parse, 371 .final_check = iprange_mt_check, 372 .print = iprange_mt4_print, 373 .save = iprange_mt4_save, 374 .extra_opts = iprange_mt_opts, 375}; 376 377static struct xtables_match iprange_mt6_reg = { 378 .version = XTABLES_VERSION, 379 .name = "iprange", 380 .revision = 1, 381 .family = AF_INET6, 382 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 383 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 384 .help = iprange_mt_help, 385 .parse = iprange_mt6_parse, 386 .final_check = iprange_mt_check, 387 .print = iprange_mt6_print, 388 .save = iprange_mt6_save, 389 .extra_opts = iprange_mt_opts, 390}; 391 392void _init(void) 393{ 394 xtables_register_match(&iprange_match); 395 xtables_register_match(&iprange_mt_reg); 396 xtables_register_match(&iprange_mt6_reg); 397} 398