]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/ipset/ip_set_hash_netnet.c
Merge remote-tracking branch 'wireless-next/master'
[karo-tx-linux.git] / net / netfilter / ipset / ip_set_hash_netnet.c
1 /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2  * Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 /* Kernel module implementing an IP set type: the hash:net type */
10
11 #include <linux/jhash.h>
12 #include <linux/module.h>
13 #include <linux/ip.h>
14 #include <linux/skbuff.h>
15 #include <linux/errno.h>
16 #include <linux/random.h>
17 #include <net/ip.h>
18 #include <net/ipv6.h>
19 #include <net/netlink.h>
20
21 #include <linux/netfilter.h>
22 #include <linux/netfilter/ipset/pfxlen.h>
23 #include <linux/netfilter/ipset/ip_set.h>
24 #include <linux/netfilter/ipset/ip_set_hash.h>
25
26 #define IPSET_TYPE_REV_MIN      0
27 #define IPSET_TYPE_REV_MAX      0
28
29 MODULE_LICENSE("GPL");
30 MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
31 IP_SET_MODULE_DESC("hash:net,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
32 MODULE_ALIAS("ip_set_hash:net,net");
33
34 /* Type specific function prefix */
35 #define HTYPE           hash_netnet
36 #define IP_SET_HASH_WITH_NETS
37 #define IPSET_NET_COUNT 2
38
39 /* IPv4 variants */
40
41 /* Member elements  */
42 struct hash_netnet4_elem {
43         union {
44                 __be32 ip[2];
45                 __be64 ipcmp;
46         };
47         u8 nomatch;
48         union {
49                 u8 cidr[2];
50                 u16 ccmp;
51         };
52 };
53
54 /* Common functions */
55
56 static inline bool
57 hash_netnet4_data_equal(const struct hash_netnet4_elem *ip1,
58                      const struct hash_netnet4_elem *ip2,
59                      u32 *multi)
60 {
61         return ip1->ipcmp == ip2->ipcmp &&
62                ip2->ccmp == ip2->ccmp;
63 }
64
65 static inline int
66 hash_netnet4_do_data_match(const struct hash_netnet4_elem *elem)
67 {
68         return elem->nomatch ? -ENOTEMPTY : 1;
69 }
70
71 static inline void
72 hash_netnet4_data_set_flags(struct hash_netnet4_elem *elem, u32 flags)
73 {
74         elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
75 }
76
77 static inline void
78 hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags)
79 {
80         swap(*flags, elem->nomatch);
81 }
82
83 static inline void
84 hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem,
85                           struct hash_netnet4_elem *orig)
86 {
87         elem->ip[1] = orig->ip[1];
88 }
89
90 static inline void
91 hash_netnet4_data_netmask(struct hash_netnet4_elem *elem, u8 cidr, bool inner)
92 {
93         if (inner) {
94                 elem->ip[1] &= ip_set_netmask(cidr);
95                 elem->cidr[1] = cidr;
96         } else {
97                 elem->ip[0] &= ip_set_netmask(cidr);
98                 elem->cidr[0] = cidr;
99         }
100 }
101
102 static bool
103 hash_netnet4_data_list(struct sk_buff *skb,
104                     const struct hash_netnet4_elem *data)
105 {
106         u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
107
108         if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
109             nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
110             nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
111             nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
112             (flags &&
113              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
114                 goto nla_put_failure;
115         return 0;
116
117 nla_put_failure:
118         return 1;
119 }
120
121 static inline void
122 hash_netnet4_data_next(struct hash_netnet4_elem *next,
123                     const struct hash_netnet4_elem *d)
124 {
125         next->ipcmp = d->ipcmp;
126 }
127
128 #define MTYPE           hash_netnet4
129 #define PF              4
130 #define HOST_MASK       32
131 #include "ip_set_hash_gen.h"
132
133 static int
134 hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
135                const struct xt_action_param *par,
136                enum ipset_adt adt, struct ip_set_adt_opt *opt)
137 {
138         const struct hash_netnet *h = set->data;
139         ipset_adtfn adtfn = set->variant->adt[adt];
140         struct hash_netnet4_elem e = {
141                 .cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
142                 .cidr[1] = h->nets[0].cidr[1] ? h->nets[0].cidr[1] : HOST_MASK,
143         };
144         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
145
146         if (adt == IPSET_TEST)
147                 e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK;
148
149         ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
150         ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]);
151         e.ip[0] &= ip_set_netmask(e.cidr[0]);
152         e.ip[1] &= ip_set_netmask(e.cidr[1]);
153
154         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
155 }
156
157 static int
158 hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
159                enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
160 {
161         const struct hash_netnet *h = set->data;
162         ipset_adtfn adtfn = set->variant->adt[adt];
163         struct hash_netnet4_elem e = { .cidr[0] = HOST_MASK,
164                                        .cidr[1] = HOST_MASK };
165         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
166         u32 ip = 0, ip_to = 0, last;
167         u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
168         u8 cidr, cidr2;
169         int ret;
170
171         if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
172                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
173                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
174                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
175                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
176                 return -IPSET_ERR_PROTOCOL;
177
178         if (tb[IPSET_ATTR_LINENO])
179                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
180
181         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
182               ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) ||
183               ip_set_get_extensions(set, tb, &ext);
184         if (ret)
185                 return ret;
186
187         if (tb[IPSET_ATTR_CIDR]) {
188                 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
189                 if (!cidr || cidr > HOST_MASK)
190                         return -IPSET_ERR_INVALID_CIDR;
191                 e.cidr[0] = cidr;
192         }
193
194         if (tb[IPSET_ATTR_CIDR2]) {
195                 cidr2 = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
196                 if (!cidr2 || cidr2 > HOST_MASK)
197                         return -IPSET_ERR_INVALID_CIDR;
198                 e.cidr[1] = cidr2;
199         }
200
201         if (tb[IPSET_ATTR_CADT_FLAGS]) {
202                 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
203                 if (cadt_flags & IPSET_FLAG_NOMATCH)
204                         flags |= (IPSET_FLAG_NOMATCH << 16);
205         }
206
207         if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] &&
208                                    tb[IPSET_ATTR_IP2_TO])) {
209                 e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
210                 e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1]));
211                 ret = adtfn(set, &e, &ext, &ext, flags);
212                 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
213                        ip_set_eexist(ret, flags) ? 0 : ret;
214         }
215
216         ip_to = ip;
217         if (tb[IPSET_ATTR_IP_TO]) {
218                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
219                 if (ret)
220                         return ret;
221                 if (ip_to < ip)
222                         swap(ip, ip_to);
223                 if (ip + UINT_MAX == ip_to)
224                         return -IPSET_ERR_HASH_RANGE;
225         }
226
227         ip2_to = ip2_from;
228         if (tb[IPSET_ATTR_IP2_TO]) {
229                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
230                 if (ret)
231                         return ret;
232                 if (ip2_to < ip2_from)
233                         swap(ip2_from, ip2_to);
234                 if (ip2_from + UINT_MAX == ip2_to)
235                         return -IPSET_ERR_HASH_RANGE;
236
237         }
238
239         if (retried)
240                 ip = ntohl(h->next.ip[0]);
241
242         while (!after(ip, ip_to)) {
243                 e.ip[0] = htonl(ip);
244                 last = ip_set_range_to_cidr(ip, ip_to, &cidr);
245                 e.cidr[0] = cidr;
246                 ip2 = (retried &&
247                        ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
248                                                    : ip2_from;
249                 while (!after(ip2, ip2_to)) {
250                         e.ip[1] = htonl(ip2);
251                         last2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr2);
252                         e.cidr[1] = cidr2;
253                         ret = adtfn(set, &e, &ext, &ext, flags);
254                         if (ret && !ip_set_eexist(ret, flags))
255                                 return ret;
256                         else
257                                 ret = 0;
258                         ip2 = last2 + 1;
259                 }
260                 ip = last + 1;
261         }
262         return ret;
263 }
264
265 /* IPv6 variants */
266
267 struct hash_netnet6_elem {
268         union nf_inet_addr ip[2];
269         u8 nomatch;
270         union {
271                 u8 cidr[2];
272                 u16 ccmp;
273         };
274 };
275
276 /* Common functions */
277
278 static inline bool
279 hash_netnet6_data_equal(const struct hash_netnet6_elem *ip1,
280                      const struct hash_netnet6_elem *ip2,
281                      u32 *multi)
282 {
283         return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
284                ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
285                ip1->ccmp == ip2->ccmp;
286 }
287
288 static inline int
289 hash_netnet6_do_data_match(const struct hash_netnet6_elem *elem)
290 {
291         return elem->nomatch ? -ENOTEMPTY : 1;
292 }
293
294 static inline void
295 hash_netnet6_data_set_flags(struct hash_netnet6_elem *elem, u32 flags)
296 {
297         elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
298 }
299
300 static inline void
301 hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags)
302 {
303         swap(*flags, elem->nomatch);
304 }
305
306 static inline void
307 hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem,
308                           struct hash_netnet6_elem *orig)
309 {
310         elem->ip[1] = orig->ip[1];
311 }
312
313 static inline void
314 hash_netnet6_data_netmask(struct hash_netnet6_elem *elem, u8 cidr, bool inner)
315 {
316         if (inner) {
317                 ip6_netmask(&elem->ip[1], cidr);
318                 elem->cidr[1] = cidr;
319         } else {
320                 ip6_netmask(&elem->ip[0], cidr);
321                 elem->cidr[0] = cidr;
322         }
323 }
324
325 static bool
326 hash_netnet6_data_list(struct sk_buff *skb,
327                     const struct hash_netnet6_elem *data)
328 {
329         u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
330
331         if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
332             nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
333             nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
334             nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
335             (flags &&
336              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
337                 goto nla_put_failure;
338         return 0;
339
340 nla_put_failure:
341         return 1;
342 }
343
344 static inline void
345 hash_netnet6_data_next(struct hash_netnet4_elem *next,
346                     const struct hash_netnet6_elem *d)
347 {
348 }
349
350 #undef MTYPE
351 #undef PF
352 #undef HOST_MASK
353
354 #define MTYPE           hash_netnet6
355 #define PF              6
356 #define HOST_MASK       128
357 #define IP_SET_EMIT_CREATE
358 #include "ip_set_hash_gen.h"
359
360 static int
361 hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
362                const struct xt_action_param *par,
363                enum ipset_adt adt, struct ip_set_adt_opt *opt)
364 {
365         const struct hash_netnet *h = set->data;
366         ipset_adtfn adtfn = set->variant->adt[adt];
367         struct hash_netnet6_elem e = {
368                 .cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
369                 .cidr[1] = h->nets[0].cidr[1] ? h->nets[0].cidr[1] : HOST_MASK
370         };
371         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
372
373         if (adt == IPSET_TEST)
374                 e.ccmp = (HOST_MASK << (sizeof(u8)*8)) | HOST_MASK;
375
376         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
377         ip6addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1].in6);
378         ip6_netmask(&e.ip[0], e.cidr[0]);
379         ip6_netmask(&e.ip[1], e.cidr[1]);
380
381         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
382 }
383
384 static int
385 hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[],
386                enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
387 {
388         ipset_adtfn adtfn = set->variant->adt[adt];
389         struct hash_netnet6_elem e = { .cidr[0] = HOST_MASK,
390                                        .cidr[1] = HOST_MASK };
391         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
392         int ret;
393
394         if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
395                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
396                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
397                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
398                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
399                 return -IPSET_ERR_PROTOCOL;
400         if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO]))
401                 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
402
403         if (tb[IPSET_ATTR_LINENO])
404                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
405
406         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
407               ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) ||
408               ip_set_get_extensions(set, tb, &ext);
409         if (ret)
410                 return ret;
411
412         if (tb[IPSET_ATTR_CIDR])
413                 e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
414
415         if (tb[IPSET_ATTR_CIDR2])
416                 e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
417
418         if (!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] ||
419             e.cidr[1] > HOST_MASK)
420                 return -IPSET_ERR_INVALID_CIDR;
421
422         ip6_netmask(&e.ip[0], e.cidr[0]);
423         ip6_netmask(&e.ip[1], e.cidr[1]);
424
425         if (tb[IPSET_ATTR_CADT_FLAGS]) {
426                 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
427                 if (cadt_flags & IPSET_FLAG_NOMATCH)
428                         flags |= (IPSET_FLAG_NOMATCH << 16);
429         }
430
431         ret = adtfn(set, &e, &ext, &ext, flags);
432
433         return ip_set_enomatch(ret, flags, adt, set) ? -ret :
434                ip_set_eexist(ret, flags) ? 0 : ret;
435 }
436
437 static struct ip_set_type hash_netnet_type __read_mostly = {
438         .name           = "hash:net,net",
439         .protocol       = IPSET_PROTOCOL,
440         .features       = IPSET_TYPE_IP | IPSET_TYPE_IP2 | IPSET_TYPE_NOMATCH,
441         .dimension      = IPSET_DIM_TWO,
442         .family         = NFPROTO_UNSPEC,
443         .revision_min   = IPSET_TYPE_REV_MIN,
444         .revision_max   = IPSET_TYPE_REV_MAX,
445         .create         = hash_netnet_create,
446         .create_policy  = {
447                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
448                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
449                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
450                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
451                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
452                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
453         },
454         .adt_policy     = {
455                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
456                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
457                 [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
458                 [IPSET_ATTR_IP2_TO]     = { .type = NLA_NESTED },
459                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
460                 [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
461                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
462                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
463                 [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
464                 [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
465                 [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING },
466         },
467         .me             = THIS_MODULE,
468 };
469
470 static int __init
471 hash_netnet_init(void)
472 {
473         return ip_set_type_register(&hash_netnet_type);
474 }
475
476 static void __exit
477 hash_netnet_fini(void)
478 {
479         ip_set_type_unregister(&hash_netnet_type);
480 }
481
482 module_init(hash_netnet_init);
483 module_exit(hash_netnet_fini);