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