xref: /aosp_15_r20/external/iptables/extensions/libxt_iprange.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
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 = xtables_strdup(oarg);
77 	char *dash;
78 
79 	dash = strchr(arg, '-');
80 	if (dash == NULL) {
81 		iprange_parse_spec(arg, arg, range, family, optname);
82 		free(arg);
83 		return;
84 	}
85 
86 	*dash = '\0';
87 	iprange_parse_spec(arg, dash + 1, range, family, optname);
88 	if (memcmp(&range[0], &range[1], sizeof(*range)) > 0)
89 		fprintf(stderr, "xt_iprange: range %s-%s is reversed and "
90 			"will never match\n", arg, dash + 1);
91 	free(arg);
92 }
93 
iprange_parse(struct xt_option_call * cb)94 static void iprange_parse(struct xt_option_call *cb)
95 {
96 	struct ipt_iprange_info *info = cb->data;
97 	union nf_inet_addr range[2];
98 
99 	xtables_option_parse(cb);
100 	switch (cb->entry->id) {
101 	case O_SRC_RANGE:
102 		info->flags |= IPRANGE_SRC;
103 		if (cb->invert)
104 			info->flags |= IPRANGE_SRC_INV;
105 		iprange_parse_range(cb->arg, range,
106 				    NFPROTO_IPV4, "--src-range");
107 		info->src.min_ip = range[0].ip;
108 		info->src.max_ip = range[1].ip;
109 		break;
110 	case O_DST_RANGE:
111 		info->flags |= IPRANGE_DST;
112 		if (cb->invert)
113 			info->flags |= IPRANGE_DST_INV;
114 		iprange_parse_range(cb->arg, range,
115 				    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 
iprange_mt_parse(struct xt_option_call * cb,uint8_t nfproto)122 static 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 
iprange_mt4_parse(struct xt_option_call * cb)145 static void iprange_mt4_parse(struct xt_option_call *cb)
146 {
147 	iprange_mt_parse(cb, NFPROTO_IPV4);
148 }
149 
iprange_mt6_parse(struct xt_option_call * cb)150 static void iprange_mt6_parse(struct xt_option_call *cb)
151 {
152 	iprange_mt_parse(cb, NFPROTO_IPV6);
153 }
154 
iprange_mt_check(struct xt_fcheck_call * cb)155 static 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 
162 static void
print_iprange(const struct ipt_iprange * range)163 print_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 
iprange_print(const void * ip,const struct xt_entry_match * match,int numeric)174 static 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 
193 static void
iprange_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)194 iprange_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 
219 static void
iprange_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)220 iprange_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 
iprange_save(const void * ip,const struct xt_entry_match * match)245 static 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 
iprange_mt4_save(const void * ip,const struct xt_entry_match * match)263 static 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",
271 		       xtables_ipaddr_to_numeric(&info->src_min.in));
272 		printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
273 	}
274 	if (info->flags & IPRANGE_DST) {
275 		if (info->flags & IPRANGE_DST_INV)
276 			printf(" !");
277 		printf(" --dst-range %s",
278 		       xtables_ipaddr_to_numeric(&info->dst_min.in));
279 		printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
280 	}
281 }
282 
iprange_mt6_save(const void * ip,const struct xt_entry_match * match)283 static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
284 {
285 	const struct xt_iprange_mtinfo *info = (const void *)match->data;
286 
287 	if (info->flags & IPRANGE_SRC) {
288 		if (info->flags & IPRANGE_SRC_INV)
289 			printf(" !");
290 		printf(" --src-range %s",
291 		       xtables_ip6addr_to_numeric(&info->src_min.in6));
292 		printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
293 	}
294 	if (info->flags & IPRANGE_DST) {
295 		if (info->flags & IPRANGE_DST_INV)
296 			printf(" !");
297 		printf(" --dst-range %s",
298 		       xtables_ip6addr_to_numeric(&info->dst_min.in6));
299 		printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
300 	}
301 }
302 
303 static void
print_iprange_xlate(const struct ipt_iprange * range,struct xt_xlate * xl)304 print_iprange_xlate(const struct ipt_iprange *range,
305 		    struct xt_xlate *xl)
306 {
307 	const unsigned char *byte_min, *byte_max;
308 
309 	byte_min = (const unsigned char *)&range->min_ip;
310 	byte_max = (const unsigned char *)&range->max_ip;
311 	xt_xlate_add(xl, " %u.%u.%u.%u-%u.%u.%u.%u ",
312 		   byte_min[0], byte_min[1], byte_min[2], byte_min[3],
313 		   byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
314 }
315 
iprange_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)316 static int iprange_xlate(struct xt_xlate *xl,
317 			 const struct xt_xlate_mt_params *params)
318 {
319 	const struct ipt_iprange_info *info = (const void *)params->match->data;
320 
321 	if (info->flags & IPRANGE_SRC) {
322 		xt_xlate_add(xl, "ip saddr%s",
323 			     info->flags & IPRANGE_SRC_INV ? " !=" : "");
324 		print_iprange_xlate(&info->src, xl);
325 	}
326 	if (info->flags & IPRANGE_DST) {
327 		xt_xlate_add(xl, "ip daddr%s",
328 			     info->flags & IPRANGE_DST_INV ? " !=" : "");
329 		print_iprange_xlate(&info->dst, xl);
330 	}
331 
332 	return 1;
333 }
334 
iprange_mt4_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)335 static int iprange_mt4_xlate(struct xt_xlate *xl,
336 			     const struct xt_xlate_mt_params *params)
337 {
338 	const struct xt_iprange_mtinfo *info =
339 		(const void *)params->match->data;
340 
341 	if (info->flags & IPRANGE_SRC) {
342 		xt_xlate_add(xl, "ip saddr%s %s",
343 			     info->flags & IPRANGE_SRC_INV ? " !=" : "",
344 			     xtables_ipaddr_to_numeric(&info->src_min.in));
345 		xt_xlate_add(xl, "-%s",
346 			     xtables_ipaddr_to_numeric(&info->src_max.in));
347 	}
348 	if (info->flags & IPRANGE_DST) {
349 		xt_xlate_add(xl, "ip daddr%s %s",
350 			     info->flags & IPRANGE_DST_INV ? " !=" : "",
351 			     xtables_ipaddr_to_numeric(&info->dst_min.in));
352 		xt_xlate_add(xl, "-%s",
353 			     xtables_ipaddr_to_numeric(&info->dst_max.in));
354 	}
355 
356 	return 1;
357 }
358 
iprange_mt6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)359 static int iprange_mt6_xlate(struct xt_xlate *xl,
360 			     const struct xt_xlate_mt_params *params)
361 {
362 	const struct xt_iprange_mtinfo *info =
363 		(const void *)params->match->data;
364 
365 	if (info->flags & IPRANGE_SRC) {
366 		xt_xlate_add(xl, "ip6 saddr%s %s",
367 			     info->flags & IPRANGE_SRC_INV ? " !=" : "",
368 			     xtables_ip6addr_to_numeric(&info->src_min.in6));
369 		xt_xlate_add(xl, "-%s",
370 			     xtables_ip6addr_to_numeric(&info->src_max.in6));
371 	}
372 	if (info->flags & IPRANGE_DST) {
373 		xt_xlate_add(xl, "ip6 daddr%s %s",
374 			     info->flags & IPRANGE_DST_INV ? " !=" : "",
375 			     xtables_ip6addr_to_numeric(&info->dst_min.in6));
376 		xt_xlate_add(xl, "-%s",
377 			     xtables_ip6addr_to_numeric(&info->dst_max.in6));
378 	}
379 
380 	return 1;
381 }
382 
383 static struct xtables_match iprange_mt_reg[] = {
384 	{
385 		.version       = XTABLES_VERSION,
386 		.name          = "iprange",
387 		.revision      = 0,
388 		.family        = NFPROTO_IPV4,
389 		.size          = XT_ALIGN(sizeof(struct ipt_iprange_info)),
390 		.userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
391 		.help          = iprange_mt_help,
392 		.x6_parse      = iprange_parse,
393 		.x6_fcheck     = iprange_mt_check,
394 		.print         = iprange_print,
395 		.save          = iprange_save,
396 		.x6_options    = iprange_mt_opts,
397 		.xlate	       = iprange_xlate,
398 	},
399 	{
400 		.version       = XTABLES_VERSION,
401 		.name          = "iprange",
402 		.revision      = 1,
403 		.family        = NFPROTO_IPV4,
404 		.size          = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
405 		.userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
406 		.help          = iprange_mt_help,
407 		.x6_parse      = iprange_mt4_parse,
408 		.x6_fcheck     = iprange_mt_check,
409 		.print         = iprange_mt4_print,
410 		.save          = iprange_mt4_save,
411 		.x6_options    = iprange_mt_opts,
412 		.xlate	       = iprange_mt4_xlate,
413 	},
414 	{
415 		.version       = XTABLES_VERSION,
416 		.name          = "iprange",
417 		.revision      = 1,
418 		.family        = NFPROTO_IPV6,
419 		.size          = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
420 		.userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
421 		.help          = iprange_mt_help,
422 		.x6_parse      = iprange_mt6_parse,
423 		.x6_fcheck     = iprange_mt_check,
424 		.print         = iprange_mt6_print,
425 		.save          = iprange_mt6_save,
426 		.x6_options    = iprange_mt_opts,
427 		.xlate	       = iprange_mt6_xlate,
428 	},
429 };
430 
_init(void)431 void _init(void)
432 {
433 	xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
434 }
435