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