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