blob: 2a91416530a4f1cebda0268394e694d316e53a7b [file] [log] [blame]
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +00001/* Shared library add-on to iptables to add IP range matching support. */
Jan Engelhardt32b8e612010-07-23 21:16:14 +02002#include <stdbool.h>
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +00003#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
8
Thomas Jarosch240eee62008-10-23 15:40:52 +02009#include <netinet/in.h>
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +000010#include <xtables.h>
11#include <linux/netfilter.h>
12#include <linux/netfilter/xt_iprange.h>
Jan Engelhardt350661a2010-01-31 22:42:52 +010013
14struct ipt_iprange {
15 /* Inclusive: network order. */
16 __be32 min_ip, max_ip;
17};
18
19struct ipt_iprange_info {
20 struct ipt_iprange src;
21 struct ipt_iprange dst;
22
23 /* Flags from above */
Jan Engelhardt7ac40522011-01-07 12:34:04 +010024 uint8_t flags;
Jan Engelhardt350661a2010-01-31 22:42:52 +010025};
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000026
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +000027enum {
28 F_SRCIP = 1 << 0,
29 F_DSTIP = 1 << 1,
30};
31
Jan Engelhardt41daaa02008-01-20 13:42:43 +000032static void iprange_mt_help(void)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000033{
34 printf(
Jan Engelhardt41daaa02008-01-20 13:42:43 +000035"iprange match options:\n"
Jan Engelhardta10a12a2009-09-18 09:59:26 +020036"[!] --src-range ip[-ip] Match source IP in the specified range\n"
37"[!] --dst-range ip[-ip] Match destination IP in the specified range\n");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000038}
39
Jan Engelhardt41daaa02008-01-20 13:42:43 +000040static const struct option iprange_mt_opts[] = {
41 {.name = "src-range", .has_arg = true, .val = '1'},
42 {.name = "dst-range", .has_arg = true, .val = '2'},
Jan Engelhardt32b8e612010-07-23 21:16:14 +020043 XT_GETOPT_TABLEEND,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000044};
45
Jan Engelhardt648a7ba2009-09-18 13:01:05 +020046static void
47iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range,
48 uint8_t family, const char *optname)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000049{
Jan Engelhardt7fa73292009-09-18 13:07:09 +020050 const char *spec[2] = {from, to};
Jan Engelhardta10a12a2009-09-18 09:59:26 +020051 struct in6_addr *ia6;
52 struct in_addr *ia4;
Jan Engelhardt7fa73292009-09-18 13:07:09 +020053 unsigned int i;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000054
Jan Engelhardta10a12a2009-09-18 09:59:26 +020055 memset(range, 0, sizeof(union nf_inet_addr) * 2);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000056
Jan Engelhardta10a12a2009-09-18 09:59:26 +020057 if (family == NFPROTO_IPV6) {
Jan Engelhardt7fa73292009-09-18 13:07:09 +020058 for (i = 0; i < ARRAY_SIZE(spec); ++i) {
59 ia6 = xtables_numeric_to_ip6addr(spec[i]);
60 if (ia6 == NULL)
61 xtables_param_act(XTF_BAD_VALUE, "iprange",
62 optname, spec[i]);
63 range[i].in6 = *ia6;
64 }
Jan Engelhardt41daaa02008-01-20 13:42:43 +000065 } else {
Jan Engelhardt7fa73292009-09-18 13:07:09 +020066 for (i = 0; i < ARRAY_SIZE(spec); ++i) {
67 ia4 = xtables_numeric_to_ipaddr(spec[i]);
68 if (ia4 == NULL)
69 xtables_param_act(XTF_BAD_VALUE, "iprange",
70 optname, spec[i]);
71 range[i].in = *ia4;
72 }
Jan Engelhardt41daaa02008-01-20 13:42:43 +000073 }
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000074}
75
Jan Engelhardt648a7ba2009-09-18 13:01:05 +020076static void iprange_parse_range(char *arg, union nf_inet_addr *range,
Jan Engelhardt7ac40522011-01-07 12:34:04 +010077 uint8_t family, const char *optname)
Jan Engelhardt648a7ba2009-09-18 13:01:05 +020078{
79 char *dash;
80
81 dash = strchr(arg, '-');
82 if (dash == NULL) {
83 iprange_parse_spec(arg, arg, range, family, optname);
84 return;
85 }
86
87 *dash = '\0';
88 iprange_parse_spec(arg, dash + 1, range, family, optname);
89 if (memcmp(&range[0], &range[1], sizeof(*range)) > 0)
90 fprintf(stderr, "xt_iprange: range %s-%s is reversed and "
91 "will never match\n", arg, dash + 1);
92}
93
Jan Engelhardt59d16402007-10-04 16:28:39 +000094static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
95 const void *entry, struct xt_entry_match **match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000096{
97 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
Jan Engelhardta10a12a2009-09-18 09:59:26 +020098 union nf_inet_addr range[2];
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000099
100 switch (c) {
101 case '1':
102 if (*flags & IPRANGE_SRC)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100103 xtables_error(PARAMETER_PROBLEM,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000104 "iprange match: Only use --src-range ONCE!");
105 *flags |= IPRANGE_SRC;
106
107 info->flags |= IPRANGE_SRC;
Jan Engelhardtbf971282009-11-03 19:55:11 +0100108 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000109 if (invert)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000110 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200111 iprange_parse_range(optarg, range, NFPROTO_IPV4, "--src-range");
Vincent Bernatada4ff62010-04-21 14:48:26 +0200112 info->src.min_ip = range[0].ip;
113 info->src.max_ip = range[1].ip;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000114 break;
115
116 case '2':
117 if (*flags & IPRANGE_DST)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100118 xtables_error(PARAMETER_PROBLEM,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000119 "iprange match: Only use --dst-range ONCE!");
120 *flags |= IPRANGE_DST;
121
122 info->flags |= IPRANGE_DST;
Jan Engelhardtbf971282009-11-03 19:55:11 +0100123 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000124 if (invert)
125 info->flags |= IPRANGE_DST_INV;
126
Vincent Bernatada4ff62010-04-21 14:48:26 +0200127 iprange_parse_range(optarg, range, NFPROTO_IPV4, "--dst-range");
128 info->dst.min_ip = range[0].ip;
129 info->dst.max_ip = range[1].ip;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000130 break;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000131 }
132 return 1;
133}
134
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000135static int
136iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
137 const void *entry, struct xt_entry_match **match)
138{
139 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000140
141 switch (c) {
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200142 case '1': /* --src-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200143 iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV4,
144 "--src-range");
Jan Engelhardt6a0cd582008-06-13 17:59:29 +0200145 info->flags |= IPRANGE_SRC;
146 if (invert)
147 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000148 *flags |= F_SRCIP;
149 return true;
150
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200151 case '2': /* --dst-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200152 iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV4,
153 "--dst-range");
Jan Engelhardt6a0cd582008-06-13 17:59:29 +0200154 info->flags |= IPRANGE_DST;
155 if (invert)
156 info->flags |= IPRANGE_DST_INV;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000157 *flags |= F_DSTIP;
158 return true;
159 }
160 return false;
161}
162
163static int
164iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
165 const void *entry, struct xt_entry_match **match)
166{
167 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000168
169 switch (c) {
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200170 case '1': /* --src-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200171 iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV6,
172 "--src-range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000173 info->flags |= IPRANGE_SRC;
174 if (invert)
175 info->flags |= IPRANGE_SRC_INV;
176 *flags |= F_SRCIP;
177 return true;
178
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200179 case '2': /* --dst-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200180 iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV6,
181 "--dst-range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000182 info->flags |= IPRANGE_DST;
183 if (invert)
184 info->flags |= IPRANGE_DST_INV;
185 *flags |= F_DSTIP;
186 return true;
187 }
188 return false;
189}
190
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000191static void iprange_mt_check(unsigned int flags)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000192{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000193 if (flags == 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100194 xtables_error(PARAMETER_PROBLEM,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000195 "iprange match: You must specify `--src-range' or `--dst-range'");
196}
197
198static void
199print_iprange(const struct ipt_iprange *range)
200{
201 const unsigned char *byte_min, *byte_max;
202
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000203 byte_min = (const unsigned char *)&range->min_ip;
204 byte_max = (const unsigned char *)&range->max_ip;
Jan Engelhardt73866352010-12-18 02:04:59 +0100205 printf(" %u.%u.%u.%u-%u.%u.%u.%u",
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000206 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
207 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
208}
209
Jan Engelhardt59d16402007-10-04 16:28:39 +0000210static void iprange_print(const void *ip, const struct xt_entry_match *match,
211 int numeric)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000212{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000213 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000214
215 if (info->flags & IPRANGE_SRC) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100216 printf(" source IP range");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000217 if (info->flags & IPRANGE_SRC_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100218 printf(" !");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000219 print_iprange(&info->src);
220 }
221 if (info->flags & IPRANGE_DST) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100222 printf(" destination IP range");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000223 if (info->flags & IPRANGE_DST_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100224 printf(" !");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000225 print_iprange(&info->dst);
226 }
227}
228
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000229static void
230iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
231 int numeric)
232{
233 const struct xt_iprange_mtinfo *info = (const void *)match->data;
234
235 if (info->flags & IPRANGE_SRC) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100236 printf(" source IP range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000237 if (info->flags & IPRANGE_SRC_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100238 printf(" !");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000239 /*
240 * ipaddr_to_numeric() uses a static buffer, so cannot
241 * combine the printf() calls.
242 */
Jan Engelhardt73866352010-12-18 02:04:59 +0100243 printf(" %s", xtables_ipaddr_to_numeric(&info->src_min.in));
244 printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000245 }
246 if (info->flags & IPRANGE_DST) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100247 printf(" destination IP range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000248 if (info->flags & IPRANGE_DST_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100249 printf(" !");
250 printf(" %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
251 printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000252 }
253}
254
255static void
256iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
257 int numeric)
258{
259 const struct xt_iprange_mtinfo *info = (const void *)match->data;
260
261 if (info->flags & IPRANGE_SRC) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100262 printf(" source IP range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000263 if (info->flags & IPRANGE_SRC_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100264 printf(" !");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000265 /*
266 * ipaddr_to_numeric() uses a static buffer, so cannot
267 * combine the printf() calls.
268 */
Jan Engelhardt73866352010-12-18 02:04:59 +0100269 printf(" %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
270 printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000271 }
272 if (info->flags & IPRANGE_DST) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100273 printf(" destination IP range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000274 if (info->flags & IPRANGE_DST_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100275 printf(" !");
276 printf(" %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
277 printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000278 }
279}
280
Jan Engelhardt59d16402007-10-04 16:28:39 +0000281static void iprange_save(const void *ip, const struct xt_entry_match *match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000282{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000283 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000284
285 if (info->flags & IPRANGE_SRC) {
286 if (info->flags & IPRANGE_SRC_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100287 printf(" !");
288 printf(" --src-range");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000289 print_iprange(&info->src);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000290 }
291 if (info->flags & IPRANGE_DST) {
292 if (info->flags & IPRANGE_DST_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100293 printf(" !");
294 printf(" --dst-range");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000295 print_iprange(&info->dst);
296 }
297}
298
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000299static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
300{
301 const struct xt_iprange_mtinfo *info = (const void *)match->data;
302
303 if (info->flags & IPRANGE_SRC) {
304 if (info->flags & IPRANGE_SRC_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100305 printf(" !");
306 printf(" --src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in));
307 printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000308 }
309 if (info->flags & IPRANGE_DST) {
310 if (info->flags & IPRANGE_DST_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100311 printf(" !");
312 printf(" --dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
313 printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000314 }
315}
316
317static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
318{
319 const struct xt_iprange_mtinfo *info = (const void *)match->data;
320
321 if (info->flags & IPRANGE_SRC) {
322 if (info->flags & IPRANGE_SRC_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100323 printf(" !");
324 printf(" --src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
325 printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000326 }
327 if (info->flags & IPRANGE_DST) {
328 if (info->flags & IPRANGE_DST_INV)
Jan Engelhardt73866352010-12-18 02:04:59 +0100329 printf(" !");
330 printf(" --dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
331 printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000332 }
333}
334
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200335static struct xtables_match iprange_mt_reg[] = {
336 {
337 .version = XTABLES_VERSION,
338 .name = "iprange",
339 .revision = 0,
340 .family = NFPROTO_IPV4,
341 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)),
342 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
343 .help = iprange_mt_help,
344 .parse = iprange_parse,
345 .final_check = iprange_mt_check,
346 .print = iprange_print,
347 .save = iprange_save,
348 .extra_opts = iprange_mt_opts,
349 },
350 {
351 .version = XTABLES_VERSION,
352 .name = "iprange",
353 .revision = 1,
354 .family = NFPROTO_IPV4,
355 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
356 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
357 .help = iprange_mt_help,
358 .parse = iprange_mt4_parse,
359 .final_check = iprange_mt_check,
360 .print = iprange_mt4_print,
361 .save = iprange_mt4_save,
362 .extra_opts = iprange_mt_opts,
363 },
364 {
365 .version = XTABLES_VERSION,
366 .name = "iprange",
367 .revision = 1,
368 .family = NFPROTO_IPV6,
369 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
370 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
371 .help = iprange_mt_help,
372 .parse = iprange_mt6_parse,
373 .final_check = iprange_mt_check,
374 .print = iprange_mt6_print,
375 .save = iprange_mt6_save,
376 .extra_opts = iprange_mt_opts,
377 },
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000378};
379
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000380void _init(void)
381{
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200382 xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000383}