blob: 51b35f8a2718c5fa60e2e5decb3e74c5390b0f7c [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
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +00008#include <xtables.h>
9#include <linux/netfilter.h>
10#include <linux/netfilter/xt_iprange.h>
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000011#include <linux/netfilter_ipv4/ipt_iprange.h>
12
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +000013enum {
14 F_SRCIP = 1 << 0,
15 F_DSTIP = 1 << 1,
16};
17
Jan Engelhardt41daaa02008-01-20 13:42:43 +000018static void iprange_mt_help(void)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000019{
20 printf(
Jan Engelhardt41daaa02008-01-20 13:42:43 +000021"iprange match options:\n"
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000022"[!] --src-range ip-ip Match source IP in the specified range\n"
23"[!] --dst-range ip-ip Match destination IP in the specified range\n"
Jan Engelhardt41daaa02008-01-20 13:42:43 +000024"\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
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000033static void
34parse_iprange(char *arg, struct ipt_iprange *range)
35{
36 char *dash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000037 const struct in_addr *ip;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000038
39 dash = strchr(arg, '-');
Jan Engelhardt41daaa02008-01-20 13:42:43 +000040 if (dash != NULL)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000041 *dash = '\0';
Jan Engelhardt41daaa02008-01-20 13:42:43 +000042
Jan Engelhardtbd943842008-01-20 13:38:08 +000043 ip = numeric_to_ipaddr(arg);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000044 if (ip != NULL)
45 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000046 arg);
47 range->min_ip = ip->s_addr;
48
Jan Engelhardt41daaa02008-01-20 13:42:43 +000049 if (dash != NULL) {
Jan Engelhardtbd943842008-01-20 13:38:08 +000050 ip = numeric_to_ipaddr(dash+1);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000051 if (ip != NULL)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000052 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
53 dash+1);
54 range->max_ip = ip->s_addr;
Jan Engelhardt41daaa02008-01-20 13:42:43 +000055 } else {
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000056 range->max_ip = range->min_ip;
Jan Engelhardt41daaa02008-01-20 13:42:43 +000057 }
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000058}
59
Jan Engelhardt59d16402007-10-04 16:28:39 +000060static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
61 const void *entry, struct xt_entry_match **match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000062{
63 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
64
65 switch (c) {
66 case '1':
67 if (*flags & IPRANGE_SRC)
68 exit_error(PARAMETER_PROBLEM,
69 "iprange match: Only use --src-range ONCE!");
70 *flags |= IPRANGE_SRC;
71
72 info->flags |= IPRANGE_SRC;
73 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000074 if (invert)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000075 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardt41daaa02008-01-20 13:42:43 +000076 parse_iprange(optarg, &info->src);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000077
78 break;
79
80 case '2':
81 if (*flags & IPRANGE_DST)
82 exit_error(PARAMETER_PROBLEM,
83 "iprange match: Only use --dst-range ONCE!");
84 *flags |= IPRANGE_DST;
85
86 info->flags |= IPRANGE_DST;
87 check_inverse(optarg, &invert, &optind, 0);
88 if (invert)
89 info->flags |= IPRANGE_DST_INV;
90
Jan Engelhardt41daaa02008-01-20 13:42:43 +000091 parse_iprange(optarg, &info->dst);
Nicolas Boulianeb9c6ec12004-07-12 07:16:54 +000092
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000093 break;
94
95 default:
96 return 0;
97 }
98 return 1;
99}
100
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000101static int
102iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
103 const void *entry, struct xt_entry_match **match)
104{
105 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
106 const struct in_addr *ia;
107 char *end;
108
109 switch (c) {
110 case '1': /* --src-ip */
111 end = strchr(optarg, '-');
112 if (end == NULL)
113 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
114 *end = '\0';
115 ia = numeric_to_ipaddr(optarg);
116 if (ia == NULL)
117 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
118 memcpy(&info->src_min.in, ia, sizeof(*ia));
119 ia = numeric_to_ipaddr(end+1);
120 if (ia == NULL)
121 param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1);
122 memcpy(&info->src_max.in, ia, sizeof(*ia));
123 *flags |= F_SRCIP;
124 return true;
125
126 case '2': /* --dst-ip */
127 end = strchr(optarg, '-');
128 if (end == NULL)
129 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
130 *end = '\0';
131 ia = numeric_to_ipaddr(optarg);
132 if (ia == NULL)
133 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
134 memcpy(&info->dst_min.in, ia, sizeof(*ia));
135 ia = numeric_to_ipaddr(end + 1);
136 if (ia == NULL)
137 param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1);
138 memcpy(&info->dst_max.in, ia, sizeof(*ia));
139 *flags |= F_DSTIP;
140 return true;
141 }
142 return false;
143}
144
145static int
146iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
147 const void *entry, struct xt_entry_match **match)
148{
149 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
150 const struct in6_addr *ia;
151 char *end;
152
153 switch (c) {
154 case '1': /* --src-ip */
155 end = strchr(optarg, '-');
156 if (end == NULL)
157 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
158 *end = '\0';
159 ia = numeric_to_ip6addr(optarg);
160 if (ia == NULL)
161 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
162 memcpy(&info->src_min.in, ia, sizeof(*ia));
163 ia = numeric_to_ip6addr(end+1);
164 if (ia == NULL)
165 param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1);
166 memcpy(&info->src_max.in, ia, sizeof(*ia));
167 info->flags |= IPRANGE_SRC;
168 if (invert)
169 info->flags |= IPRANGE_SRC_INV;
170 *flags |= F_SRCIP;
171 return true;
172
173 case '2': /* --dst-ip */
174 end = strchr(optarg, '-');
175 if (end == NULL)
176 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
177 *end = '\0';
178 ia = numeric_to_ip6addr(optarg);
179 if (ia == NULL)
180 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
181 memcpy(&info->dst_min.in, ia, sizeof(*ia));
182 ia = numeric_to_ip6addr(end + 1);
183 if (ia == NULL)
184 param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1);
185 memcpy(&info->dst_max.in, ia, sizeof(*ia));
186 info->flags |= IPRANGE_DST;
187 if (invert)
188 info->flags |= IPRANGE_DST_INV;
189 *flags |= F_DSTIP;
190 return true;
191 }
192 return false;
193}
194
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000195static void iprange_mt_check(unsigned int flags)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000196{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000197 if (flags == 0)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000198 exit_error(PARAMETER_PROBLEM,
199 "iprange match: You must specify `--src-range' or `--dst-range'");
200}
201
202static void
203print_iprange(const struct ipt_iprange *range)
204{
205 const unsigned char *byte_min, *byte_max;
206
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000207 byte_min = (const unsigned char *)&range->min_ip;
208 byte_max = (const unsigned char *)&range->max_ip;
209 printf("%u.%u.%u.%u-%u.%u.%u.%u ",
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000210 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
211 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
212}
213
Jan Engelhardt59d16402007-10-04 16:28:39 +0000214static void iprange_print(const void *ip, const struct xt_entry_match *match,
215 int numeric)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000216{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000217 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000218
219 if (info->flags & IPRANGE_SRC) {
220 printf("source IP range ");
221 if (info->flags & IPRANGE_SRC_INV)
222 printf("! ");
223 print_iprange(&info->src);
224 }
225 if (info->flags & IPRANGE_DST) {
226 printf("destination IP range ");
227 if (info->flags & IPRANGE_DST_INV)
228 printf("! ");
229 print_iprange(&info->dst);
230 }
231}
232
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000233static void
234iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
235 int numeric)
236{
237 const struct xt_iprange_mtinfo *info = (const void *)match->data;
238
239 if (info->flags & IPRANGE_SRC) {
240 printf("source IP range ");
241 if (info->flags & IPRANGE_SRC_INV)
242 printf("! ");
243 /*
244 * ipaddr_to_numeric() uses a static buffer, so cannot
245 * combine the printf() calls.
246 */
247 printf("%s", ipaddr_to_numeric(&info->src_min.in));
248 printf("-%s ", ipaddr_to_numeric(&info->src_max.in));
249 }
250 if (info->flags & IPRANGE_DST) {
251 printf("destination IP range ");
252 if (info->flags & IPRANGE_DST_INV)
253 printf("! ");
254 printf("%s", ipaddr_to_numeric(&info->dst_min.in));
255 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in));
256 }
257}
258
259static void
260iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
261 int numeric)
262{
263 const struct xt_iprange_mtinfo *info = (const void *)match->data;
264
265 if (info->flags & IPRANGE_SRC) {
266 printf("source IP range ");
267 if (info->flags & IPRANGE_SRC_INV)
268 printf("! ");
269 /*
270 * ipaddr_to_numeric() uses a static buffer, so cannot
271 * combine the printf() calls.
272 */
273 printf("%s", ip6addr_to_numeric(&info->src_min.in6));
274 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6));
275 }
276 if (info->flags & IPRANGE_DST) {
277 printf("destination IP range ");
278 if (info->flags & IPRANGE_DST_INV)
279 printf("! ");
280 printf("%s", ip6addr_to_numeric(&info->dst_min.in6));
281 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6));
282 }
283}
284
Jan Engelhardt59d16402007-10-04 16:28:39 +0000285static void iprange_save(const void *ip, const struct xt_entry_match *match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000286{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000287 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000288
289 if (info->flags & IPRANGE_SRC) {
290 if (info->flags & IPRANGE_SRC_INV)
291 printf("! ");
292 printf("--src-range ");
293 print_iprange(&info->src);
294 if (info->flags & IPRANGE_DST)
295 fputc(' ', stdout);
296 }
297 if (info->flags & IPRANGE_DST) {
298 if (info->flags & IPRANGE_DST_INV)
299 printf("! ");
300 printf("--dst-range ");
301 print_iprange(&info->dst);
302 }
303}
304
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000305static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
306{
307 const struct xt_iprange_mtinfo *info = (const void *)match->data;
308
309 if (info->flags & IPRANGE_SRC) {
310 if (info->flags & IPRANGE_SRC_INV)
311 printf("! ");
312 printf("--src-range %s", ipaddr_to_numeric(&info->src_min.in));
313 printf("-%s ", ipaddr_to_numeric(&info->src_max.in));
314 }
315 if (info->flags & IPRANGE_DST) {
316 if (info->flags & IPRANGE_DST_INV)
317 printf("! ");
318 printf("--dst-range %s", ipaddr_to_numeric(&info->dst_min.in));
319 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in));
320 }
321}
322
323static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
324{
325 const struct xt_iprange_mtinfo *info = (const void *)match->data;
326
327 if (info->flags & IPRANGE_SRC) {
328 if (info->flags & IPRANGE_SRC_INV)
329 printf("! ");
330 printf("--src-range %s", ip6addr_to_numeric(&info->src_min.in6));
331 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6));
332 }
333 if (info->flags & IPRANGE_DST) {
334 if (info->flags & IPRANGE_DST_INV)
335 printf("! ");
336 printf("--dst-range %s", ip6addr_to_numeric(&info->dst_min.in6));
337 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6));
338 }
339}
340
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000341static struct xtables_match iprange_match = {
342 .version = IPTABLES_VERSION,
343 .name = "iprange",
344 .revision = 0,
345 .family = AF_INET,
346 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)),
347 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
348 .help = iprange_mt_help,
349 .parse = iprange_parse,
350 .final_check = iprange_mt_check,
351 .print = iprange_print,
352 .save = iprange_save,
353 .extra_opts = iprange_mt_opts,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000354};
355
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000356static struct xtables_match iprange_mt_reg = {
357 .version = IPTABLES_VERSION,
358 .name = "iprange",
359 .revision = 1,
360 .family = AF_INET,
361 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
362 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
363 .help = iprange_mt_help,
364 .parse = iprange_mt4_parse,
365 .final_check = iprange_mt_check,
366 .print = iprange_mt4_print,
367 .save = iprange_mt4_save,
368 .extra_opts = iprange_mt_opts,
369};
370
371static struct xtables_match iprange_mt6_reg = {
372 .version = IPTABLES_VERSION,
373 .name = "iprange",
374 .revision = 1,
375 .family = AF_INET6,
376 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
377 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
378 .help = iprange_mt_help,
379 .parse = iprange_mt6_parse,
380 .final_check = iprange_mt_check,
381 .print = iprange_mt6_print,
382 .save = iprange_mt6_save,
383 .extra_opts = iprange_mt_opts,
384};
385
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000386void _init(void)
387{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000388 xtables_register_match(&iprange_match);
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000389 xtables_register_match(&iprange_mt_reg);
390 xtables_register_match(&iprange_mt6_reg);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000391}