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