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