blob: 9e544ea0139cfe9f6f0694e88a40b228b12e2dae [file] [log] [blame]
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +00001/* Shared library add-on to iptables to add IP range matching support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7
Thomas Jarosch240eee62008-10-23 15:40:52 +02008#include <netinet/in.h>
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +00009#include <xtables.h>
10#include <linux/netfilter.h>
11#include <linux/netfilter/xt_iprange.h>
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000012#include <linux/netfilter_ipv4/ipt_iprange.h>
13
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +000014enum {
15 F_SRCIP = 1 << 0,
16 F_DSTIP = 1 << 1,
17};
18
Jan Engelhardt41daaa02008-01-20 13:42:43 +000019static void iprange_mt_help(void)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000020{
21 printf(
Jan Engelhardt41daaa02008-01-20 13:42:43 +000022"iprange match options:\n"
Jan Engelhardta10a12a2009-09-18 09:59:26 +020023"[!] --src-range ip[-ip] Match source IP in the specified range\n"
24"[!] --dst-range ip[-ip] Match destination IP in the specified range\n");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000025}
26
Jan Engelhardt41daaa02008-01-20 13:42:43 +000027static const struct option iprange_mt_opts[] = {
28 {.name = "src-range", .has_arg = true, .val = '1'},
29 {.name = "dst-range", .has_arg = true, .val = '2'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000030 { .name = NULL }
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000031};
32
Jan Engelhardt648a7ba2009-09-18 13:01:05 +020033static void
34iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range,
35 uint8_t family, const char *optname)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000036{
Jan Engelhardt7fa73292009-09-18 13:07:09 +020037 const char *spec[2] = {from, to};
Jan Engelhardta10a12a2009-09-18 09:59:26 +020038 struct in6_addr *ia6;
39 struct in_addr *ia4;
Jan Engelhardt7fa73292009-09-18 13:07:09 +020040 unsigned int i;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000041
Jan Engelhardta10a12a2009-09-18 09:59:26 +020042 memset(range, 0, sizeof(union nf_inet_addr) * 2);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000043
Jan Engelhardta10a12a2009-09-18 09:59:26 +020044 if (family == NFPROTO_IPV6) {
Jan Engelhardt7fa73292009-09-18 13:07:09 +020045 for (i = 0; i < ARRAY_SIZE(spec); ++i) {
46 ia6 = xtables_numeric_to_ip6addr(spec[i]);
47 if (ia6 == NULL)
48 xtables_param_act(XTF_BAD_VALUE, "iprange",
49 optname, spec[i]);
50 range[i].in6 = *ia6;
51 }
Jan Engelhardt41daaa02008-01-20 13:42:43 +000052 } else {
Jan Engelhardt7fa73292009-09-18 13:07:09 +020053 for (i = 0; i < ARRAY_SIZE(spec); ++i) {
54 ia4 = xtables_numeric_to_ipaddr(spec[i]);
55 if (ia4 == NULL)
56 xtables_param_act(XTF_BAD_VALUE, "iprange",
57 optname, spec[i]);
58 range[i].in = *ia4;
59 }
Jan Engelhardt41daaa02008-01-20 13:42:43 +000060 }
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000061}
62
Jan Engelhardt648a7ba2009-09-18 13:01:05 +020063static void iprange_parse_range(char *arg, union nf_inet_addr *range,
64 u_int8_t family, const char *optname)
65{
66 char *dash;
67
68 dash = strchr(arg, '-');
69 if (dash == NULL) {
70 iprange_parse_spec(arg, arg, range, family, optname);
71 return;
72 }
73
74 *dash = '\0';
75 iprange_parse_spec(arg, dash + 1, range, family, optname);
76 if (memcmp(&range[0], &range[1], sizeof(*range)) > 0)
77 fprintf(stderr, "xt_iprange: range %s-%s is reversed and "
78 "will never match\n", arg, dash + 1);
79}
80
Jan Engelhardt59d16402007-10-04 16:28:39 +000081static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
82 const void *entry, struct xt_entry_match **match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000083{
84 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
Jan Engelhardta10a12a2009-09-18 09:59:26 +020085 union nf_inet_addr range[2];
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000086
87 switch (c) {
88 case '1':
89 if (*flags & IPRANGE_SRC)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010090 xtables_error(PARAMETER_PROBLEM,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000091 "iprange match: Only use --src-range ONCE!");
92 *flags |= IPRANGE_SRC;
93
94 info->flags |= IPRANGE_SRC;
Jan Engelhardt0f16c722009-01-30 04:55:38 +010095 xtables_check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000096 if (invert)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000097 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardta10a12a2009-09-18 09:59:26 +020098 iprange_parse_range(optarg, range, NFPROTO_IPV4, "--src-range");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000099
100 break;
101
102 case '2':
103 if (*flags & IPRANGE_DST)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100104 xtables_error(PARAMETER_PROBLEM,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000105 "iprange match: Only use --dst-range ONCE!");
106 *flags |= IPRANGE_DST;
107
108 info->flags |= IPRANGE_DST;
Jan Engelhardt0f16c722009-01-30 04:55:38 +0100109 xtables_check_inverse(optarg, &invert, &optind, 0);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000110 if (invert)
111 info->flags |= IPRANGE_DST_INV;
112
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200113 iprange_parse_range(optarg, range, NFPROTO_IPV4, "--src-range");
Nicolas Boulianeb9c6ec12004-07-12 07:16:54 +0000114
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000115 break;
116
117 default:
118 return 0;
119 }
120 return 1;
121}
122
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000123static int
124iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
125 const void *entry, struct xt_entry_match **match)
126{
127 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000128
129 switch (c) {
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200130 case '1': /* --src-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200131 iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV4,
132 "--src-range");
Jan Engelhardt6a0cd582008-06-13 17:59:29 +0200133 info->flags |= IPRANGE_SRC;
134 if (invert)
135 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000136 *flags |= F_SRCIP;
137 return true;
138
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200139 case '2': /* --dst-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200140 iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV4,
141 "--dst-range");
Jan Engelhardt6a0cd582008-06-13 17:59:29 +0200142 info->flags |= IPRANGE_DST;
143 if (invert)
144 info->flags |= IPRANGE_DST_INV;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000145 *flags |= F_DSTIP;
146 return true;
147 }
148 return false;
149}
150
151static int
152iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
153 const void *entry, struct xt_entry_match **match)
154{
155 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000156
157 switch (c) {
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200158 case '1': /* --src-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200159 iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV6,
160 "--src-range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000161 info->flags |= IPRANGE_SRC;
162 if (invert)
163 info->flags |= IPRANGE_SRC_INV;
164 *flags |= F_SRCIP;
165 return true;
166
Jan Engelhardtbfb7e0b2008-09-01 14:19:03 +0200167 case '2': /* --dst-range */
Jan Engelhardta10a12a2009-09-18 09:59:26 +0200168 iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV6,
169 "--dst-range");
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000170 info->flags |= IPRANGE_DST;
171 if (invert)
172 info->flags |= IPRANGE_DST_INV;
173 *flags |= F_DSTIP;
174 return true;
175 }
176 return false;
177}
178
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000179static void iprange_mt_check(unsigned int flags)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000180{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000181 if (flags == 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100182 xtables_error(PARAMETER_PROBLEM,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000183 "iprange match: You must specify `--src-range' or `--dst-range'");
184}
185
186static void
187print_iprange(const struct ipt_iprange *range)
188{
189 const unsigned char *byte_min, *byte_max;
190
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000191 byte_min = (const unsigned char *)&range->min_ip;
192 byte_max = (const unsigned char *)&range->max_ip;
193 printf("%u.%u.%u.%u-%u.%u.%u.%u ",
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000194 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
195 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
196}
197
Jan Engelhardt59d16402007-10-04 16:28:39 +0000198static void iprange_print(const void *ip, const struct xt_entry_match *match,
199 int numeric)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000200{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000201 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000202
203 if (info->flags & IPRANGE_SRC) {
204 printf("source IP range ");
205 if (info->flags & IPRANGE_SRC_INV)
206 printf("! ");
207 print_iprange(&info->src);
208 }
209 if (info->flags & IPRANGE_DST) {
210 printf("destination IP range ");
211 if (info->flags & IPRANGE_DST_INV)
212 printf("! ");
213 print_iprange(&info->dst);
214 }
215}
216
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000217static void
218iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
219 int numeric)
220{
221 const struct xt_iprange_mtinfo *info = (const void *)match->data;
222
223 if (info->flags & IPRANGE_SRC) {
224 printf("source IP range ");
225 if (info->flags & IPRANGE_SRC_INV)
226 printf("! ");
227 /*
228 * ipaddr_to_numeric() uses a static buffer, so cannot
229 * combine the printf() calls.
230 */
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100231 printf("%s", xtables_ipaddr_to_numeric(&info->src_min.in));
232 printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000233 }
234 if (info->flags & IPRANGE_DST) {
235 printf("destination IP range ");
236 if (info->flags & IPRANGE_DST_INV)
237 printf("! ");
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100238 printf("%s", xtables_ipaddr_to_numeric(&info->dst_min.in));
239 printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000240 }
241}
242
243static void
244iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
245 int numeric)
246{
247 const struct xt_iprange_mtinfo *info = (const void *)match->data;
248
249 if (info->flags & IPRANGE_SRC) {
250 printf("source IP range ");
251 if (info->flags & IPRANGE_SRC_INV)
252 printf("! ");
253 /*
254 * ipaddr_to_numeric() uses a static buffer, so cannot
255 * combine the printf() calls.
256 */
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100257 printf("%s", xtables_ip6addr_to_numeric(&info->src_min.in6));
258 printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000259 }
260 if (info->flags & IPRANGE_DST) {
261 printf("destination IP range ");
262 if (info->flags & IPRANGE_DST_INV)
263 printf("! ");
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100264 printf("%s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
265 printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000266 }
267}
268
Jan Engelhardt59d16402007-10-04 16:28:39 +0000269static void iprange_save(const void *ip, const struct xt_entry_match *match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000270{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000271 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000272
273 if (info->flags & IPRANGE_SRC) {
274 if (info->flags & IPRANGE_SRC_INV)
275 printf("! ");
276 printf("--src-range ");
277 print_iprange(&info->src);
278 if (info->flags & IPRANGE_DST)
279 fputc(' ', stdout);
280 }
281 if (info->flags & IPRANGE_DST) {
282 if (info->flags & IPRANGE_DST_INV)
283 printf("! ");
284 printf("--dst-range ");
285 print_iprange(&info->dst);
286 }
287}
288
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000289static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
290{
291 const struct xt_iprange_mtinfo *info = (const void *)match->data;
292
293 if (info->flags & IPRANGE_SRC) {
294 if (info->flags & IPRANGE_SRC_INV)
295 printf("! ");
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100296 printf("--src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in));
297 printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000298 }
299 if (info->flags & IPRANGE_DST) {
300 if (info->flags & IPRANGE_DST_INV)
301 printf("! ");
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100302 printf("--dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
303 printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000304 }
305}
306
307static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
308{
309 const struct xt_iprange_mtinfo *info = (const void *)match->data;
310
311 if (info->flags & IPRANGE_SRC) {
312 if (info->flags & IPRANGE_SRC_INV)
313 printf("! ");
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100314 printf("--src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
315 printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000316 }
317 if (info->flags & IPRANGE_DST) {
318 if (info->flags & IPRANGE_DST_INV)
319 printf("! ");
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100320 printf("--dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
321 printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000322 }
323}
324
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200325static struct xtables_match iprange_mt_reg[] = {
326 {
327 .version = XTABLES_VERSION,
328 .name = "iprange",
329 .revision = 0,
330 .family = NFPROTO_IPV4,
331 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)),
332 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
333 .help = iprange_mt_help,
334 .parse = iprange_parse,
335 .final_check = iprange_mt_check,
336 .print = iprange_print,
337 .save = iprange_save,
338 .extra_opts = iprange_mt_opts,
339 },
340 {
341 .version = XTABLES_VERSION,
342 .name = "iprange",
343 .revision = 1,
344 .family = NFPROTO_IPV4,
345 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
346 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
347 .help = iprange_mt_help,
348 .parse = iprange_mt4_parse,
349 .final_check = iprange_mt_check,
350 .print = iprange_mt4_print,
351 .save = iprange_mt4_save,
352 .extra_opts = iprange_mt_opts,
353 },
354 {
355 .version = XTABLES_VERSION,
356 .name = "iprange",
357 .revision = 1,
358 .family = NFPROTO_IPV6,
359 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
360 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
361 .help = iprange_mt_help,
362 .parse = iprange_mt6_parse,
363 .final_check = iprange_mt_check,
364 .print = iprange_mt6_print,
365 .save = iprange_mt6_save,
366 .extra_opts = iprange_mt_opts,
367 },
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000368};
369
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000370void _init(void)
371{
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200372 xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000373}