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