libxt_iprange.c revision e37d45ce390c2f5a7f1e64742b9100ecef0def54
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
9struct ipt_iprange {
10	/* Inclusive: network order. */
11	__be32 min_ip, max_ip;
12};
13
14struct ipt_iprange_info {
15	struct ipt_iprange src;
16	struct ipt_iprange dst;
17
18	/* Flags from above */
19	uint8_t flags;
20};
21
22enum {
23	O_SRC_RANGE = 0,
24	O_DST_RANGE,
25};
26
27static 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
35static 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
43static void
44iprange_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
73static 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
96static 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, NFPROTO_IPV4, "--src-range");
108		info->src.min_ip = range[0].ip;
109		info->src.max_ip = range[1].ip;
110		break;
111	case O_DST_RANGE:
112		info->flags |= IPRANGE_DST;
113		if (cb->invert)
114			info->flags |= IPRANGE_DST_INV;
115		iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--dst-range");
116		info->dst.min_ip = range[0].ip;
117		info->dst.max_ip = range[1].ip;
118		break;
119	}
120}
121
122static void iprange_mt_parse(struct xt_option_call *cb, uint8_t nfproto)
123{
124	struct xt_iprange_mtinfo *info = cb->data;
125
126	xtables_option_parse(cb);
127	switch (cb->entry->id) {
128	case O_SRC_RANGE:
129		iprange_parse_range(cb->arg, &info->src_min, nfproto,
130			"--src-range");
131		info->flags |= IPRANGE_SRC;
132		if (cb->invert)
133			info->flags |= IPRANGE_SRC_INV;
134		break;
135	case O_DST_RANGE:
136		iprange_parse_range(cb->arg, &info->dst_min, nfproto,
137			"--dst-range");
138		info->flags |= IPRANGE_DST;
139		if (cb->invert)
140			info->flags |= IPRANGE_DST_INV;
141		break;
142	}
143}
144
145static void iprange_mt4_parse(struct xt_option_call *cb)
146{
147	iprange_mt_parse(cb, NFPROTO_IPV4);
148}
149
150static void iprange_mt6_parse(struct xt_option_call *cb)
151{
152	iprange_mt_parse(cb, NFPROTO_IPV6);
153}
154
155static void iprange_mt_check(struct xt_fcheck_call *cb)
156{
157	if (cb->xflags == 0)
158		xtables_error(PARAMETER_PROBLEM,
159			   "iprange match: You must specify `--src-range' or `--dst-range'");
160}
161
162static void
163print_iprange(const struct ipt_iprange *range)
164{
165	const unsigned char *byte_min, *byte_max;
166
167	byte_min = (const unsigned char *)&range->min_ip;
168	byte_max = (const unsigned char *)&range->max_ip;
169	printf(" %u.%u.%u.%u-%u.%u.%u.%u",
170		byte_min[0], byte_min[1], byte_min[2], byte_min[3],
171		byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
172}
173
174static void iprange_print(const void *ip, const struct xt_entry_match *match,
175                          int numeric)
176{
177	const struct ipt_iprange_info *info = (const void *)match->data;
178
179	if (info->flags & IPRANGE_SRC) {
180		printf(" source IP range");
181		if (info->flags & IPRANGE_SRC_INV)
182			printf(" !");
183		print_iprange(&info->src);
184	}
185	if (info->flags & IPRANGE_DST) {
186		printf(" destination IP range");
187		if (info->flags & IPRANGE_DST_INV)
188			printf(" !");
189		print_iprange(&info->dst);
190	}
191}
192
193static void
194iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
195                  int numeric)
196{
197	const struct xt_iprange_mtinfo *info = (const void *)match->data;
198
199	if (info->flags & IPRANGE_SRC) {
200		printf(" source IP range");
201		if (info->flags & IPRANGE_SRC_INV)
202			printf(" !");
203		/*
204		 * ipaddr_to_numeric() uses a static buffer, so cannot
205		 * combine the printf() calls.
206		 */
207		printf(" %s", xtables_ipaddr_to_numeric(&info->src_min.in));
208		printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
209	}
210	if (info->flags & IPRANGE_DST) {
211		printf(" destination IP range");
212		if (info->flags & IPRANGE_DST_INV)
213			printf(" !");
214		printf(" %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
215		printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
216	}
217}
218
219static void
220iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
221                  int numeric)
222{
223	const struct xt_iprange_mtinfo *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		/*
230		 * ipaddr_to_numeric() uses a static buffer, so cannot
231		 * combine the printf() calls.
232		 */
233		printf(" %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
234		printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
235	}
236	if (info->flags & IPRANGE_DST) {
237		printf(" destination IP range");
238		if (info->flags & IPRANGE_DST_INV)
239			printf(" !");
240		printf(" %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
241		printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
242	}
243}
244
245static void iprange_save(const void *ip, const struct xt_entry_match *match)
246{
247	const struct ipt_iprange_info *info = (const void *)match->data;
248
249	if (info->flags & IPRANGE_SRC) {
250		if (info->flags & IPRANGE_SRC_INV)
251			printf(" !");
252		printf(" --src-range");
253		print_iprange(&info->src);
254	}
255	if (info->flags & IPRANGE_DST) {
256		if (info->flags & IPRANGE_DST_INV)
257			printf(" !");
258		printf(" --dst-range");
259		print_iprange(&info->dst);
260	}
261}
262
263static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
264{
265	const struct xt_iprange_mtinfo *info = (const void *)match->data;
266
267	if (info->flags & IPRANGE_SRC) {
268		if (info->flags & IPRANGE_SRC_INV)
269			printf(" !");
270		printf(" --src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in));
271		printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
272	}
273	if (info->flags & IPRANGE_DST) {
274		if (info->flags & IPRANGE_DST_INV)
275			printf(" !");
276		printf(" --dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
277		printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
278	}
279}
280
281static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
282{
283	const struct xt_iprange_mtinfo *info = (const void *)match->data;
284
285	if (info->flags & IPRANGE_SRC) {
286		if (info->flags & IPRANGE_SRC_INV)
287			printf(" !");
288		printf(" --src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
289		printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
290	}
291	if (info->flags & IPRANGE_DST) {
292		if (info->flags & IPRANGE_DST_INV)
293			printf(" !");
294		printf(" --dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
295		printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
296	}
297}
298
299static struct xtables_match iprange_mt_reg[] = {
300	{
301		.version       = XTABLES_VERSION,
302		.name          = "iprange",
303		.revision      = 0,
304		.family        = NFPROTO_IPV4,
305		.size          = XT_ALIGN(sizeof(struct ipt_iprange_info)),
306		.userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
307		.help          = iprange_mt_help,
308		.x6_parse      = iprange_parse,
309		.x6_fcheck     = iprange_mt_check,
310		.print         = iprange_print,
311		.save          = iprange_save,
312		.x6_options    = iprange_mt_opts,
313	},
314	{
315		.version       = XTABLES_VERSION,
316		.name          = "iprange",
317		.revision      = 1,
318		.family        = NFPROTO_IPV4,
319		.size          = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
320		.userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
321		.help          = iprange_mt_help,
322		.x6_parse      = iprange_mt4_parse,
323		.x6_fcheck     = iprange_mt_check,
324		.print         = iprange_mt4_print,
325		.save          = iprange_mt4_save,
326		.x6_options    = iprange_mt_opts,
327	},
328	{
329		.version       = XTABLES_VERSION,
330		.name          = "iprange",
331		.revision      = 1,
332		.family        = NFPROTO_IPV6,
333		.size          = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
334		.userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
335		.help          = iprange_mt_help,
336		.x6_parse      = iprange_mt6_parse,
337		.x6_fcheck     = iprange_mt_check,
338		.print         = iprange_mt6_print,
339		.save          = iprange_mt6_save,
340		.x6_options    = iprange_mt_opts,
341	},
342};
343
344void _init(void)
345{
346	xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
347}
348