cleanup
[iptables.git] / trunk / extensions / libxt_iprange.c
1 /* 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
8 #include <xtables.h>
9 #include <linux/netfilter.h>
10 #include <linux/netfilter/xt_iprange.h>
11 #include <linux/netfilter_ipv4/ipt_iprange.h>
12
13 enum {
14         F_SRCIP = 1 << 0,
15         F_DSTIP = 1 << 1,
16 };
17
18 static void iprange_mt_help(void)
19 {
20         printf(
21 "iprange match options:\n"
22 "[!] --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");
24 }
25
26 static const struct option iprange_mt_opts[] = {
27         {.name = "src-range", .has_arg = true, .val = '1'},
28         {.name = "dst-range", .has_arg = true, .val = '2'},
29         { .name = NULL }
30 };
31
32 static void
33 parse_iprange(char *arg, struct ipt_iprange *range)
34 {
35         char *dash;
36         const struct in_addr *ip;
37
38         dash = strchr(arg, '-');
39         if (dash != NULL)
40                 *dash = '\0';
41
42         ip = numeric_to_ipaddr(arg);
43         if (!ip)
44                 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
45                            arg);
46         range->min_ip = ip->s_addr;
47
48         if (dash != NULL) {
49                 ip = numeric_to_ipaddr(dash+1);
50                 if (!ip)
51                         exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
52                                    dash+1);
53                 range->max_ip = ip->s_addr;
54         } else {
55                 range->max_ip = range->min_ip;
56         }
57 }
58
59 static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
60                          const void *entry, struct xt_entry_match **match)
61 {
62         struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
63
64         switch (c) {
65         case '1':
66                 if (*flags & IPRANGE_SRC)
67                         exit_error(PARAMETER_PROBLEM,
68                                    "iprange match: Only use --src-range ONCE!");
69                 *flags |= IPRANGE_SRC;
70
71                 info->flags |= IPRANGE_SRC;
72                 check_inverse(optarg, &invert, &optind, 0);
73                 if (invert)
74                         info->flags |= IPRANGE_SRC_INV;
75                 parse_iprange(optarg, &info->src);
76
77                 break;
78
79         case '2':
80                 if (*flags & IPRANGE_DST)
81                         exit_error(PARAMETER_PROBLEM,
82                                    "iprange match: Only use --dst-range ONCE!");
83                 *flags |= IPRANGE_DST;
84
85                 info->flags |= IPRANGE_DST;
86                 check_inverse(optarg, &invert, &optind, 0);
87                 if (invert)
88                         info->flags |= IPRANGE_DST_INV;
89
90                 parse_iprange(optarg, &info->dst);
91
92                 break;
93
94         default:
95                 return 0;
96         }
97         return 1;
98 }
99
100 static int
101 iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
102                   const void *entry, struct xt_entry_match **match)
103 {
104         struct xt_iprange_mtinfo *info = (void *)(*match)->data;
105         const struct in_addr *ia;
106         char *end;
107
108         switch (c) {
109         case '1': /* --src-ip */
110                 end = strchr(optarg, '-');
111                 if (end == NULL)
112                         param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
113                 *end = '\0';
114                 ia = numeric_to_ipaddr(optarg);
115                 if (ia == NULL)
116                         param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
117                 memcpy(&info->src_min.in, ia, sizeof(*ia));
118                 ia = numeric_to_ipaddr(end+1);
119                 if (ia == NULL)
120                         param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1);
121                 memcpy(&info->src_max.in, ia, sizeof(*ia));
122                 info->flags |= IPRANGE_SRC;
123                 if (invert)
124                         info->flags |= IPRANGE_SRC_INV;
125                 *flags |= F_SRCIP;
126                 return true;
127
128         case '2': /* --dst-ip */
129                 end = strchr(optarg, '-');
130                 if (end == NULL)
131                         param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
132                 *end = '\0';
133                 ia = numeric_to_ipaddr(optarg);
134                 if (ia == NULL)
135                         param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
136                 memcpy(&info->dst_min.in, ia, sizeof(*ia));
137                 ia = numeric_to_ipaddr(end + 1);
138                 if (ia == NULL)
139                         param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1);
140                 memcpy(&info->dst_max.in, ia, sizeof(*ia));
141                 info->flags |= IPRANGE_DST;
142                 if (invert)
143                         info->flags |= IPRANGE_DST_INV;
144                 *flags |= F_DSTIP;
145                 return true;
146         }
147         return false;
148 }
149
150 static int
151 iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
152                   const void *entry, struct xt_entry_match **match)
153 {
154         struct xt_iprange_mtinfo *info = (void *)(*match)->data;
155         const struct in6_addr *ia;
156         char *end;
157
158         switch (c) {
159         case '1': /* --src-ip */
160                 end = strchr(optarg, '-');
161                 if (end == NULL)
162                         param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
163                 *end = '\0';
164                 ia = numeric_to_ip6addr(optarg);
165                 if (ia == NULL)
166                         param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
167                 memcpy(&info->src_min.in, ia, sizeof(*ia));
168                 ia = numeric_to_ip6addr(end+1);
169                 if (ia == NULL)
170                         param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1);
171                 memcpy(&info->src_max.in, ia, sizeof(*ia));
172                 info->flags |= IPRANGE_SRC;
173                 if (invert)
174                         info->flags |= IPRANGE_SRC_INV;
175                 *flags |= F_SRCIP;
176                 return true;
177
178         case '2': /* --dst-ip */
179                 end = strchr(optarg, '-');
180                 if (end == NULL)
181                         param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
182                 *end = '\0';
183                 ia = numeric_to_ip6addr(optarg);
184                 if (ia == NULL)
185                         param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
186                 memcpy(&info->dst_min.in, ia, sizeof(*ia));
187                 ia = numeric_to_ip6addr(end + 1);
188                 if (ia == NULL)
189                         param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1);
190                 memcpy(&info->dst_max.in, ia, sizeof(*ia));
191                 info->flags |= IPRANGE_DST;
192                 if (invert)
193                         info->flags |= IPRANGE_DST_INV;
194                 *flags |= F_DSTIP;
195                 return true;
196         }
197         return false;
198 }
199
200 static void iprange_mt_check(unsigned int flags)
201 {
202         if (flags == 0)
203                 exit_error(PARAMETER_PROBLEM,
204                            "iprange match: You must specify `--src-range' or `--dst-range'");
205 }
206
207 static void
208 print_iprange(const struct ipt_iprange *range)
209 {
210         const unsigned char *byte_min, *byte_max;
211
212         byte_min = (const unsigned char *)&range->min_ip;
213         byte_max = (const unsigned char *)&range->max_ip;
214         printf("%u.%u.%u.%u-%u.%u.%u.%u ",
215                 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
216                 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
217 }
218
219 static void iprange_print(const void *ip, const struct xt_entry_match *match,
220                           int numeric)
221 {
222         const struct ipt_iprange_info *info = (const void *)match->data;
223
224         if (info->flags & IPRANGE_SRC) {
225                 printf("source IP range ");
226                 if (info->flags & IPRANGE_SRC_INV)
227                         printf("! ");
228                 print_iprange(&info->src);
229         }
230         if (info->flags & IPRANGE_DST) {
231                 printf("destination IP range ");
232                 if (info->flags & IPRANGE_DST_INV)
233                         printf("! ");
234                 print_iprange(&info->dst);
235         }
236 }
237
238 static void
239 iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
240                   int numeric)
241 {
242         const struct xt_iprange_mtinfo *info = (const void *)match->data;
243
244         if (info->flags & IPRANGE_SRC) {
245                 printf("source IP range ");
246                 if (info->flags & IPRANGE_SRC_INV)
247                         printf("! ");
248                 /*
249                  * ipaddr_to_numeric() uses a static buffer, so cannot
250                  * combine the printf() calls.
251                  */
252                 printf("%s", ipaddr_to_numeric(&info->src_min.in));
253                 printf("-%s ", ipaddr_to_numeric(&info->src_max.in));
254         }
255         if (info->flags & IPRANGE_DST) {
256                 printf("destination IP range ");
257                 if (info->flags & IPRANGE_DST_INV)
258                         printf("! ");
259                 printf("%s", ipaddr_to_numeric(&info->dst_min.in));
260                 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in));
261         }
262 }
263
264 static void
265 iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
266                   int numeric)
267 {
268         const struct xt_iprange_mtinfo *info = (const void *)match->data;
269
270         if (info->flags & IPRANGE_SRC) {
271                 printf("source IP range ");
272                 if (info->flags & IPRANGE_SRC_INV)
273                         printf("! ");
274                 /*
275                  * ipaddr_to_numeric() uses a static buffer, so cannot
276                  * combine the printf() calls.
277                  */
278                 printf("%s", ip6addr_to_numeric(&info->src_min.in6));
279                 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6));
280         }
281         if (info->flags & IPRANGE_DST) {
282                 printf("destination IP range ");
283                 if (info->flags & IPRANGE_DST_INV)
284                         printf("! ");
285                 printf("%s", ip6addr_to_numeric(&info->dst_min.in6));
286                 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6));
287         }
288 }
289
290 static void iprange_save(const void *ip, const struct xt_entry_match *match)
291 {
292         const struct ipt_iprange_info *info = (const void *)match->data;
293
294         if (info->flags & IPRANGE_SRC) {
295                 if (info->flags & IPRANGE_SRC_INV)
296                         printf("! ");
297                 printf("--src-range ");
298                 print_iprange(&info->src);
299                 if (info->flags & IPRANGE_DST)
300                         fputc(' ', stdout);
301         }
302         if (info->flags & IPRANGE_DST) {
303                 if (info->flags & IPRANGE_DST_INV)
304                         printf("! ");
305                 printf("--dst-range ");
306                 print_iprange(&info->dst);
307         }
308 }
309
310 static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
311 {
312         const struct xt_iprange_mtinfo *info = (const void *)match->data;
313
314         if (info->flags & IPRANGE_SRC) {
315                 if (info->flags & IPRANGE_SRC_INV)
316                         printf("! ");
317                 printf("--src-range %s", ipaddr_to_numeric(&info->src_min.in));
318                 printf("-%s ", ipaddr_to_numeric(&info->src_max.in));
319         }
320         if (info->flags & IPRANGE_DST) {
321                 if (info->flags & IPRANGE_DST_INV)
322                         printf("! ");
323                 printf("--dst-range %s", ipaddr_to_numeric(&info->dst_min.in));
324                 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in));
325         }
326 }
327
328 static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
329 {
330         const struct xt_iprange_mtinfo *info = (const void *)match->data;
331
332         if (info->flags & IPRANGE_SRC) {
333                 if (info->flags & IPRANGE_SRC_INV)
334                         printf("! ");
335                 printf("--src-range %s", ip6addr_to_numeric(&info->src_min.in6));
336                 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6));
337         }
338         if (info->flags & IPRANGE_DST) {
339                 if (info->flags & IPRANGE_DST_INV)
340                         printf("! ");
341                 printf("--dst-range %s", ip6addr_to_numeric(&info->dst_min.in6));
342                 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6));
343         }
344 }
345
346 static struct xtables_match iprange_match = {
347         .version       = XTABLES_VERSION,
348         .name          = "iprange",
349         .revision      = 0,
350         .family        = AF_INET,
351         .size          = XT_ALIGN(sizeof(struct ipt_iprange_info)),
352         .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
353         .help          = iprange_mt_help,
354         .parse         = iprange_parse,
355         .final_check   = iprange_mt_check,
356         .print         = iprange_print,
357         .save          = iprange_save,
358         .extra_opts    = iprange_mt_opts,
359 };
360
361 static struct xtables_match iprange_mt_reg = {
362         .version        = XTABLES_VERSION,
363         .name           = "iprange",
364         .revision       = 1,
365         .family         = AF_INET,
366         .size           = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
367         .userspacesize  = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
368         .help           = iprange_mt_help,
369         .parse          = iprange_mt4_parse,
370         .final_check    = iprange_mt_check,
371         .print          = iprange_mt4_print,
372         .save           = iprange_mt4_save,
373         .extra_opts     = iprange_mt_opts,
374 };
375
376 static struct xtables_match iprange_mt6_reg = {
377         .version        = XTABLES_VERSION,
378         .name           = "iprange",
379         .revision       = 1,
380         .family         = AF_INET6,
381         .size           = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
382         .userspacesize  = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
383         .help           = iprange_mt_help,
384         .parse          = iprange_mt6_parse,
385         .final_check    = iprange_mt_check,
386         .print          = iprange_mt6_print,
387         .save           = iprange_mt6_save,
388         .extra_opts     = iprange_mt_opts,
389 };
390
391 void _init(void)
392 {
393         xtables_register_match(&iprange_match);
394         xtables_register_match(&iprange_mt_reg);
395         xtables_register_match(&iprange_mt6_reg);
396 }