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