• 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, 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 
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", 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 
iprange_mt6_save(const void * ip,const struct xt_entry_match * match)281 static 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 
299 static 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 
_init(void)344 void _init(void)
345 {
346 	xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
347 }
348