• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
iprange_mt_help(void)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
iprange_parse_spec(const char * from,const char * to,union nf_inet_addr * range,uint8_t family,const char * optname)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 
iprange_parse_range(const char * oarg,union nf_inet_addr * range,uint8_t family,const char * optname)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 
iprange_parse(struct xt_option_call * cb)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 
iprange_mt_parse(struct xt_option_call * cb,uint8_t nfproto)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 
iprange_mt4_parse(struct xt_option_call * cb)147 static void iprange_mt4_parse(struct xt_option_call *cb)
148 {
149 	iprange_mt_parse(cb, NFPROTO_IPV4);
150 }
151 
iprange_mt6_parse(struct xt_option_call * cb)152 static void iprange_mt6_parse(struct xt_option_call *cb)
153 {
154 	iprange_mt_parse(cb, NFPROTO_IPV6);
155 }
156 
iprange_mt_check(struct xt_fcheck_call * cb)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
print_iprange(const struct ipt_iprange * range)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 
iprange_print(const void * ip,const struct xt_entry_match * match,int numeric)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
iprange_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)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
iprange_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)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 
iprange_save(const void * ip,const struct xt_entry_match * match)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 
iprange_mt4_save(const void * ip,const struct xt_entry_match * match)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 
iprange_mt6_save(const void * ip,const struct xt_entry_match * match)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
print_iprange_xlate(const struct ipt_iprange * range,struct xt_xlate * xl)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 
iprange_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)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 
iprange_mt4_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)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 
iprange_mt6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)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 
_init(void)439 void _init(void)
440 {
441 	xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
442 }
443