Home | History | Annotate | Download | only in extensions
      1 #include <stdint.h>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <stdlib.h>
      5 #include <xtables.h>
      6 #include <linux/netfilter.h>
      7 #include <linux/netfilter/xt_iprange.h>
      8 
      9 struct ipt_iprange {
     10 	/* Inclusive: network order. */
     11 	__be32 min_ip, max_ip;
     12 };
     13 
     14 struct ipt_iprange_info {
     15 	struct ipt_iprange src;
     16 	struct ipt_iprange dst;
     17 
     18 	/* Flags from above */
     19 	uint8_t flags;
     20 };
     21 
     22 enum {
     23 	O_SRC_RANGE = 0,
     24 	O_DST_RANGE,
     25 };
     26 
     27 static void iprange_mt_help(void)
     28 {
     29 	printf(
     30 "iprange match options:\n"
     31 "[!] --src-range ip[-ip]    Match source IP in the specified range\n"
     32 "[!] --dst-range ip[-ip]    Match destination IP in the specified range\n");
     33 }
     34 
     35 static const struct xt_option_entry iprange_mt_opts[] = {
     36 	{.name = "src-range", .id = O_SRC_RANGE, .type = XTTYPE_STRING,
     37 	 .flags = XTOPT_INVERT},
     38 	{.name = "dst-range", .id = O_DST_RANGE, .type = XTTYPE_STRING,
     39 	 .flags = XTOPT_INVERT},
     40 	XTOPT_TABLEEND,
     41 };
     42 
     43 static void
     44 iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range,
     45 		   uint8_t family, const char *optname)
     46 {
     47 	const char *spec[2] = {from, to};
     48 	struct in6_addr *ia6;
     49 	struct in_addr *ia4;
     50 	unsigned int i;
     51 
     52 	memset(range, 0, sizeof(union nf_inet_addr) * 2);
     53 
     54 	if (family == NFPROTO_IPV6) {
     55 		for (i = 0; i < ARRAY_SIZE(spec); ++i) {
     56 			ia6 = xtables_numeric_to_ip6addr(spec[i]);
     57 			if (ia6 == NULL)
     58 				xtables_param_act(XTF_BAD_VALUE, "iprange",
     59 					optname, spec[i]);
     60 			range[i].in6 = *ia6;
     61 		}
     62 	} else {
     63 		for (i = 0; i < ARRAY_SIZE(spec); ++i) {
     64 			ia4 = xtables_numeric_to_ipaddr(spec[i]);
     65 			if (ia4 == NULL)
     66 				xtables_param_act(XTF_BAD_VALUE, "iprange",
     67 					optname, spec[i]);
     68 			range[i].in = *ia4;
     69 		}
     70 	}
     71 }
     72 
     73 static void iprange_parse_range(const char *oarg, union nf_inet_addr *range,
     74 				uint8_t family, const char *optname)
     75 {
     76 	char *arg = strdup(oarg);
     77 	char *dash;
     78 
     79 	if (arg == NULL)
     80 		xtables_error(RESOURCE_PROBLEM, "strdup");
     81 	dash = strchr(arg, '-');
     82 	if (dash == NULL) {
     83 		iprange_parse_spec(arg, arg, range, family, optname);
     84 		free(arg);
     85 		return;
     86 	}
     87 
     88 	*dash = '\0';
     89 	iprange_parse_spec(arg, dash + 1, range, family, optname);
     90 	if (memcmp(&range[0], &range[1], sizeof(*range)) > 0)
     91 		fprintf(stderr, "xt_iprange: range %s-%s is reversed and "
     92 			"will never match\n", arg, dash + 1);
     93 	free(arg);
     94 }
     95 
     96 static void iprange_parse(struct xt_option_call *cb)
     97 {
     98 	struct ipt_iprange_info *info = cb->data;
     99 	union nf_inet_addr range[2];
    100 
    101 	xtables_option_parse(cb);
    102 	switch (cb->entry->id) {
    103 	case O_SRC_RANGE:
    104 		info->flags |= IPRANGE_SRC;
    105 		if (cb->invert)
    106 			info->flags |= IPRANGE_SRC_INV;
    107 		iprange_parse_range(cb->arg, range,
    108 				    NFPROTO_IPV4, "--src-range");
    109 		info->src.min_ip = range[0].ip;
    110 		info->src.max_ip = range[1].ip;
    111 		break;
    112 	case O_DST_RANGE:
    113 		info->flags |= IPRANGE_DST;
    114 		if (cb->invert)
    115 			info->flags |= IPRANGE_DST_INV;
    116 		iprange_parse_range(cb->arg, range,
    117 				    NFPROTO_IPV4, "--dst-range");
    118 		info->dst.min_ip = range[0].ip;
    119 		info->dst.max_ip = range[1].ip;
    120 		break;
    121 	}
    122 }
    123 
    124 static void iprange_mt_parse(struct xt_option_call *cb, uint8_t nfproto)
    125 {
    126 	struct xt_iprange_mtinfo *info = cb->data;
    127 
    128 	xtables_option_parse(cb);
    129 	switch (cb->entry->id) {
    130 	case O_SRC_RANGE:
    131 		iprange_parse_range(cb->arg, &info->src_min, nfproto,
    132 			"--src-range");
    133 		info->flags |= IPRANGE_SRC;
    134 		if (cb->invert)
    135 			info->flags |= IPRANGE_SRC_INV;
    136 		break;
    137 	case O_DST_RANGE:
    138 		iprange_parse_range(cb->arg, &info->dst_min, nfproto,
    139 			"--dst-range");
    140 		info->flags |= IPRANGE_DST;
    141 		if (cb->invert)
    142 			info->flags |= IPRANGE_DST_INV;
    143 		break;
    144 	}
    145 }
    146 
    147 static void iprange_mt4_parse(struct xt_option_call *cb)
    148 {
    149 	iprange_mt_parse(cb, NFPROTO_IPV4);
    150 }
    151 
    152 static void iprange_mt6_parse(struct xt_option_call *cb)
    153 {
    154 	iprange_mt_parse(cb, NFPROTO_IPV6);
    155 }
    156 
    157 static void iprange_mt_check(struct xt_fcheck_call *cb)
    158 {
    159 	if (cb->xflags == 0)
    160 		xtables_error(PARAMETER_PROBLEM,
    161 			   "iprange match: You must specify `--src-range' or `--dst-range'");
    162 }
    163 
    164 static void
    165 print_iprange(const struct ipt_iprange *range)
    166 {
    167 	const unsigned char *byte_min, *byte_max;
    168 
    169 	byte_min = (const unsigned char *)&range->min_ip;
    170 	byte_max = (const unsigned char *)&range->max_ip;
    171 	printf(" %u.%u.%u.%u-%u.%u.%u.%u",
    172 		byte_min[0], byte_min[1], byte_min[2], byte_min[3],
    173 		byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
    174 }
    175 
    176 static void iprange_print(const void *ip, const struct xt_entry_match *match,
    177 			  int numeric)
    178 {
    179 	const struct ipt_iprange_info *info = (const void *)match->data;
    180 
    181 	if (info->flags & IPRANGE_SRC) {
    182 		printf(" source IP range");
    183 		if (info->flags & IPRANGE_SRC_INV)
    184 			printf(" !");
    185 		print_iprange(&info->src);
    186 	}
    187 	if (info->flags & IPRANGE_DST) {
    188 		printf(" destination IP range");
    189 		if (info->flags & IPRANGE_DST_INV)
    190 			printf(" !");
    191 		print_iprange(&info->dst);
    192 	}
    193 }
    194 
    195 static void
    196 iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
    197 		  int numeric)
    198 {
    199 	const struct xt_iprange_mtinfo *info = (const void *)match->data;
    200 
    201 	if (info->flags & IPRANGE_SRC) {
    202 		printf(" source IP range");
    203 		if (info->flags & IPRANGE_SRC_INV)
    204 			printf(" !");
    205 		/*
    206 		 * ipaddr_to_numeric() uses a static buffer, so cannot
    207 		 * combine the printf() calls.
    208 		 */
    209 		printf(" %s", xtables_ipaddr_to_numeric(&info->src_min.in));
    210 		printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
    211 	}
    212 	if (info->flags & IPRANGE_DST) {
    213 		printf(" destination IP range");
    214 		if (info->flags & IPRANGE_DST_INV)
    215 			printf(" !");
    216 		printf(" %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
    217 		printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
    218 	}
    219 }
    220 
    221 static void
    222 iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
    223 		  int numeric)
    224 {
    225 	const struct xt_iprange_mtinfo *info = (const void *)match->data;
    226 
    227 	if (info->flags & IPRANGE_SRC) {
    228 		printf(" source IP range");
    229 		if (info->flags & IPRANGE_SRC_INV)
    230 			printf(" !");
    231 		/*
    232 		 * ipaddr_to_numeric() uses a static buffer, so cannot
    233 		 * combine the printf() calls.
    234 		 */
    235 		printf(" %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
    236 		printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
    237 	}
    238 	if (info->flags & IPRANGE_DST) {
    239 		printf(" destination IP range");
    240 		if (info->flags & IPRANGE_DST_INV)
    241 			printf(" !");
    242 		printf(" %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
    243 		printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
    244 	}
    245 }
    246 
    247 static void iprange_save(const void *ip, const struct xt_entry_match *match)
    248 {
    249 	const struct ipt_iprange_info *info = (const void *)match->data;
    250 
    251 	if (info->flags & IPRANGE_SRC) {
    252 		if (info->flags & IPRANGE_SRC_INV)
    253 			printf(" !");
    254 		printf(" --src-range");
    255 		print_iprange(&info->src);
    256 	}
    257 	if (info->flags & IPRANGE_DST) {
    258 		if (info->flags & IPRANGE_DST_INV)
    259 			printf(" !");
    260 		printf(" --dst-range");
    261 		print_iprange(&info->dst);
    262 	}
    263 }
    264 
    265 static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
    266 {
    267 	const struct xt_iprange_mtinfo *info = (const void *)match->data;
    268 
    269 	if (info->flags & IPRANGE_SRC) {
    270 		if (info->flags & IPRANGE_SRC_INV)
    271 			printf(" !");
    272 		printf(" --src-range %s",
    273 		       xtables_ipaddr_to_numeric(&info->src_min.in));
    274 		printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
    275 	}
    276 	if (info->flags & IPRANGE_DST) {
    277 		if (info->flags & IPRANGE_DST_INV)
    278 			printf(" !");
    279 		printf(" --dst-range %s",
    280 		       xtables_ipaddr_to_numeric(&info->dst_min.in));
    281 		printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
    282 	}
    283 }
    284 
    285 static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
    286 {
    287 	const struct xt_iprange_mtinfo *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 %s",
    293 		       xtables_ip6addr_to_numeric(&info->src_min.in6));
    294 		printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
    295 	}
    296 	if (info->flags & IPRANGE_DST) {
    297 		if (info->flags & IPRANGE_DST_INV)
    298 			printf(" !");
    299 		printf(" --dst-range %s",
    300 		       xtables_ip6addr_to_numeric(&info->dst_min.in6));
    301 		printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
    302 	}
    303 }
    304 
    305 static void
    306 print_iprange_xlate(const struct ipt_iprange *range,
    307 		    struct xt_xlate *xl)
    308 {
    309 	const unsigned char *byte_min, *byte_max;
    310 
    311 	byte_min = (const unsigned char *)&range->min_ip;
    312 	byte_max = (const unsigned char *)&range->max_ip;
    313 	xt_xlate_add(xl, " %u.%u.%u.%u-%u.%u.%u.%u ",
    314 		   byte_min[0], byte_min[1], byte_min[2], byte_min[3],
    315 		   byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
    316 }
    317 
    318 static int iprange_xlate(struct xt_xlate *xl,
    319 			 const struct xt_xlate_mt_params *params)
    320 {
    321 	const struct ipt_iprange_info *info = (const void *)params->match->data;
    322 	char *space = "";
    323 
    324 	if (info->flags & IPRANGE_SRC) {
    325 		xt_xlate_add(xl, "ip saddr%s",
    326 			     info->flags & IPRANGE_SRC_INV ? " !=" : "");
    327 		print_iprange_xlate(&info->src, xl);
    328 		space = " ";
    329 	}
    330 	if (info->flags & IPRANGE_DST) {
    331 		xt_xlate_add(xl, "%sip daddr%s", space,
    332 			     info->flags & IPRANGE_DST_INV ? " !=" : "");
    333 		print_iprange_xlate(&info->dst, xl);
    334 	}
    335 
    336 	return 1;
    337 }
    338 
    339 static int iprange_mt4_xlate(struct xt_xlate *xl,
    340 			     const struct xt_xlate_mt_params *params)
    341 {
    342 	const struct xt_iprange_mtinfo *info =
    343 		(const void *)params->match->data;
    344 	char *space = "";
    345 
    346 	if (info->flags & IPRANGE_SRC) {
    347 		xt_xlate_add(xl, "ip saddr%s %s",
    348 			     info->flags & IPRANGE_SRC_INV ? " !=" : "",
    349 			     xtables_ipaddr_to_numeric(&info->src_min.in));
    350 		xt_xlate_add(xl, "-%s",
    351 			     xtables_ipaddr_to_numeric(&info->src_max.in));
    352 		space = " ";
    353 	}
    354 	if (info->flags & IPRANGE_DST) {
    355 		xt_xlate_add(xl, "%sip daddr%s %s", space,
    356 			     info->flags & IPRANGE_DST_INV ? " !=" : "",
    357 			     xtables_ipaddr_to_numeric(&info->dst_min.in));
    358 		xt_xlate_add(xl, "-%s",
    359 			     xtables_ipaddr_to_numeric(&info->dst_max.in));
    360 	}
    361 
    362 	return 1;
    363 }
    364 
    365 static int iprange_mt6_xlate(struct xt_xlate *xl,
    366 			     const struct xt_xlate_mt_params *params)
    367 {
    368 	const struct xt_iprange_mtinfo *info =
    369 		(const void *)params->match->data;
    370 	char *space = "";
    371 
    372 	if (info->flags & IPRANGE_SRC) {
    373 		xt_xlate_add(xl, "ip6 saddr%s %s",
    374 			     info->flags & IPRANGE_SRC_INV ? " !=" : "",
    375 			     xtables_ip6addr_to_numeric(&info->src_min.in6));
    376 		xt_xlate_add(xl, "-%s",
    377 			     xtables_ip6addr_to_numeric(&info->src_max.in6));
    378 		space = " ";
    379 	}
    380 	if (info->flags & IPRANGE_DST) {
    381 		xt_xlate_add(xl, "%sip6 daddr%s %s", space,
    382 			     info->flags & IPRANGE_DST_INV ? " !=" : "",
    383 			     xtables_ip6addr_to_numeric(&info->dst_min.in6));
    384 		xt_xlate_add(xl, "-%s",
    385 			     xtables_ip6addr_to_numeric(&info->dst_max.in6));
    386 	}
    387 
    388 	return 1;
    389 }
    390 
    391 static struct xtables_match iprange_mt_reg[] = {
    392 	{
    393 		.version       = XTABLES_VERSION,
    394 		.name          = "iprange",
    395 		.revision      = 0,
    396 		.family        = NFPROTO_IPV4,
    397 		.size          = XT_ALIGN(sizeof(struct ipt_iprange_info)),
    398 		.userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
    399 		.help          = iprange_mt_help,
    400 		.x6_parse      = iprange_parse,
    401 		.x6_fcheck     = iprange_mt_check,
    402 		.print         = iprange_print,
    403 		.save          = iprange_save,
    404 		.x6_options    = iprange_mt_opts,
    405 		.xlate	       = iprange_xlate,
    406 	},
    407 	{
    408 		.version       = XTABLES_VERSION,
    409 		.name          = "iprange",
    410 		.revision      = 1,
    411 		.family        = NFPROTO_IPV4,
    412 		.size          = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
    413 		.userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
    414 		.help          = iprange_mt_help,
    415 		.x6_parse      = iprange_mt4_parse,
    416 		.x6_fcheck     = iprange_mt_check,
    417 		.print         = iprange_mt4_print,
    418 		.save          = iprange_mt4_save,
    419 		.x6_options    = iprange_mt_opts,
    420 		.xlate	       = iprange_mt4_xlate,
    421 	},
    422 	{
    423 		.version       = XTABLES_VERSION,
    424 		.name          = "iprange",
    425 		.revision      = 1,
    426 		.family        = NFPROTO_IPV6,
    427 		.size          = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
    428 		.userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
    429 		.help          = iprange_mt_help,
    430 		.x6_parse      = iprange_mt6_parse,
    431 		.x6_fcheck     = iprange_mt_check,
    432 		.print         = iprange_mt6_print,
    433 		.save          = iprange_mt6_save,
    434 		.x6_options    = iprange_mt_opts,
    435 		.xlate	       = iprange_mt6_xlate,
    436 	},
    437 };
    438 
    439 void _init(void)
    440 {
    441 	xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
    442 }
    443