]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - net/netfilter/ipset/ip_set_hash_ip.c
netfilter: ipset: make possible to hash some part of the data element only
[mirror_ubuntu-focal-kernel.git] / net / netfilter / ipset / ip_set_hash_ip.c
CommitLineData
6c027889
JK
1/* Copyright (C) 2003-2011 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:ip 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>
6c027889
JK
15#include <linux/random.h>
16#include <net/ip.h>
17#include <net/ipv6.h>
18#include <net/netlink.h>
19#include <net/tcp.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_timeout.h>
25#include <linux/netfilter/ipset/ip_set_hash.h>
26
27MODULE_LICENSE("GPL");
28MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
29MODULE_DESCRIPTION("hash:ip type of IP sets");
30MODULE_ALIAS("ip_set_hash:ip");
31
32/* Type specific function prefix */
33#define TYPE hash_ip
34
35static bool
36hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
37
38#define hash_ip4_same_set hash_ip_same_set
39#define hash_ip6_same_set hash_ip_same_set
40
41/* The type variant functions: IPv4 */
42
43/* Member elements without timeout */
44struct hash_ip4_elem {
45 __be32 ip;
46};
47
48/* Member elements with timeout support */
49struct hash_ip4_telem {
50 __be32 ip;
51 unsigned long timeout;
52};
53
54static inline bool
55hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
56 const struct hash_ip4_elem *ip2)
57{
58 return ip1->ip == ip2->ip;
59}
60
61static inline bool
62hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
63{
64 return elem->ip == 0;
65}
66
67static inline void
68hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
69{
70 dst->ip = src->ip;
71}
72
73/* Zero valued IP addresses cannot be stored */
74static inline void
75hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
76{
77 elem->ip = 0;
78}
79
80static inline bool
81hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
82{
83 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
84 return 0;
85
86nla_put_failure:
87 return 1;
88}
89
90static bool
91hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
92{
93 const struct hash_ip4_telem *tdata =
94 (const struct hash_ip4_telem *)data;
95
96 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
97 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
98 htonl(ip_set_timeout_get(tdata->timeout)));
99
100 return 0;
101
102nla_put_failure:
103 return 1;
104}
105
106#define IP_SET_HASH_WITH_NETMASK
107#define PF 4
108#define HOST_MASK 32
109#include <linux/netfilter/ipset/ip_set_ahash.h>
110
3d14b171
JK
111static inline void
112hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
113{
114 h->next.ip = ntohl(d->ip);
115}
116
6c027889
JK
117static int
118hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
b66554cf 119 const struct xt_action_param *par,
ac8cc925 120 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
6c027889
JK
121{
122 const struct ip_set_hash *h = set->data;
123 ipset_adtfn adtfn = set->variant->adt[adt];
124 __be32 ip;
125
ac8cc925 126 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
6c027889
JK
127 ip &= ip_set_netmask(h->netmask);
128 if (ip == 0)
129 return -EINVAL;
130
ac8cc925 131 return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
6c027889
JK
132}
133
134static int
135hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
3d14b171 136 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
6c027889
JK
137{
138 const struct ip_set_hash *h = set->data;
139 ipset_adtfn adtfn = set->variant->adt[adt];
140 u32 ip, ip_to, hosts, timeout = h->timeout;
141 __be32 nip;
142 int ret = 0;
143
144 if (unlikely(!tb[IPSET_ATTR_IP] ||
145 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
146 return -IPSET_ERR_PROTOCOL;
147
148 if (tb[IPSET_ATTR_LINENO])
149 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
150
151 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
152 if (ret)
153 return ret;
154
155 ip &= ip_set_hostmask(h->netmask);
156
157 if (tb[IPSET_ATTR_TIMEOUT]) {
158 if (!with_timeout(h->timeout))
159 return -IPSET_ERR_TIMEOUT;
160 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
161 }
162
163 if (adt == IPSET_TEST) {
164 nip = htonl(ip);
165 if (nip == 0)
166 return -IPSET_ERR_HASH_ELEM;
5416219e 167 return adtfn(set, &nip, timeout, flags);
6c027889
JK
168 }
169
170 if (tb[IPSET_ATTR_IP_TO]) {
171 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
172 if (ret)
173 return ret;
174 if (ip > ip_to)
175 swap(ip, ip_to);
176 } else if (tb[IPSET_ATTR_CIDR]) {
177 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
178
179 if (cidr > 32)
180 return -IPSET_ERR_INVALID_CIDR;
e6146e86 181 ip_set_mask_from_to(ip, ip_to, cidr);
6c027889
JK
182 } else
183 ip_to = ip;
184
185 hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
186
3d14b171
JK
187 if (retried)
188 ip = h->next.ip;
6c027889
JK
189 for (; !before(ip_to, ip); ip += hosts) {
190 nip = htonl(ip);
191 if (nip == 0)
192 return -IPSET_ERR_HASH_ELEM;
5416219e 193 ret = adtfn(set, &nip, timeout, flags);
6c027889
JK
194
195 if (ret && !ip_set_eexist(ret, flags))
196 return ret;
197 else
198 ret = 0;
199 }
200 return ret;
201}
202
203static bool
204hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
205{
206 const struct ip_set_hash *x = a->data;
207 const struct ip_set_hash *y = b->data;
208
209 /* Resizing changes htable_bits, so we ignore it */
210 return x->maxelem == y->maxelem &&
211 x->timeout == y->timeout &&
212 x->netmask == y->netmask;
213}
214
215/* The type variant functions: IPv6 */
216
217struct hash_ip6_elem {
218 union nf_inet_addr ip;
219};
220
221struct hash_ip6_telem {
222 union nf_inet_addr ip;
223 unsigned long timeout;
224};
225
226static inline bool
227hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
228 const struct hash_ip6_elem *ip2)
229{
230 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
231}
232
233static inline bool
234hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
235{
236 return ipv6_addr_any(&elem->ip.in6);
237}
238
239static inline void
240hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
241{
242 ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
243}
244
245static inline void
246hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
247{
248 ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
249}
250
251static inline void
252ip6_netmask(union nf_inet_addr *ip, u8 prefix)
253{
254 ip->ip6[0] &= ip_set_netmask6(prefix)[0];
255 ip->ip6[1] &= ip_set_netmask6(prefix)[1];
256 ip->ip6[2] &= ip_set_netmask6(prefix)[2];
257 ip->ip6[3] &= ip_set_netmask6(prefix)[3];
258}
259
260static bool
261hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
262{
263 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
264 return 0;
265
266nla_put_failure:
267 return 1;
268}
269
270static bool
271hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
272{
273 const struct hash_ip6_telem *e =
274 (const struct hash_ip6_telem *)data;
275
276 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
277 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
278 htonl(ip_set_timeout_get(e->timeout)));
279 return 0;
280
281nla_put_failure:
282 return 1;
283}
284
285#undef PF
286#undef HOST_MASK
287
288#define PF 6
289#define HOST_MASK 128
290#include <linux/netfilter/ipset/ip_set_ahash.h>
291
3d14b171
JK
292static inline void
293hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
294{
295}
296
6c027889
JK
297static int
298hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
b66554cf 299 const struct xt_action_param *par,
ac8cc925 300 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
6c027889
JK
301{
302 const struct ip_set_hash *h = set->data;
303 ipset_adtfn adtfn = set->variant->adt[adt];
304 union nf_inet_addr ip;
305
ac8cc925 306 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
6c027889
JK
307 ip6_netmask(&ip, h->netmask);
308 if (ipv6_addr_any(&ip.in6))
309 return -EINVAL;
310
ac8cc925 311 return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
6c027889
JK
312}
313
314static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
315 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
316 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
317 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
318};
319
320static int
321hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
3d14b171 322 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
6c027889
JK
323{
324 const struct ip_set_hash *h = set->data;
325 ipset_adtfn adtfn = set->variant->adt[adt];
326 union nf_inet_addr ip;
327 u32 timeout = h->timeout;
328 int ret;
329
330 if (unlikely(!tb[IPSET_ATTR_IP] ||
331 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
332 tb[IPSET_ATTR_IP_TO] ||
333 tb[IPSET_ATTR_CIDR]))
334 return -IPSET_ERR_PROTOCOL;
335
336 if (tb[IPSET_ATTR_LINENO])
337 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
338
339 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
340 if (ret)
341 return ret;
342
343 ip6_netmask(&ip, h->netmask);
344 if (ipv6_addr_any(&ip.in6))
345 return -IPSET_ERR_HASH_ELEM;
346
347 if (tb[IPSET_ATTR_TIMEOUT]) {
348 if (!with_timeout(h->timeout))
349 return -IPSET_ERR_TIMEOUT;
350 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
351 }
352
5416219e 353 ret = adtfn(set, &ip, timeout, flags);
6c027889
JK
354
355 return ip_set_eexist(ret, flags) ? 0 : ret;
356}
357
358/* Create hash:ip type of sets */
359
360static int
361hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
362{
363 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
364 u8 netmask, hbits;
365 struct ip_set_hash *h;
366
367 if (!(set->family == AF_INET || set->family == AF_INET6))
368 return -IPSET_ERR_INVALID_FAMILY;
369 netmask = set->family == AF_INET ? 32 : 128;
370 pr_debug("Create set %s with family %s\n",
371 set->name, set->family == AF_INET ? "inet" : "inet6");
372
373 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
374 !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
375 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
376 return -IPSET_ERR_PROTOCOL;
377
378 if (tb[IPSET_ATTR_HASHSIZE]) {
379 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
380 if (hashsize < IPSET_MIMINAL_HASHSIZE)
381 hashsize = IPSET_MIMINAL_HASHSIZE;
382 }
383
384 if (tb[IPSET_ATTR_MAXELEM])
385 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
386
387 if (tb[IPSET_ATTR_NETMASK]) {
388 netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
389
390 if ((set->family == AF_INET && netmask > 32) ||
391 (set->family == AF_INET6 && netmask > 128) ||
392 netmask == 0)
393 return -IPSET_ERR_INVALID_NETMASK;
394 }
395
396 h = kzalloc(sizeof(*h), GFP_KERNEL);
397 if (!h)
398 return -ENOMEM;
399
400 h->maxelem = maxelem;
401 h->netmask = netmask;
402 get_random_bytes(&h->initval, sizeof(h->initval));
403 h->timeout = IPSET_NO_TIMEOUT;
404
405 hbits = htable_bits(hashsize);
406 h->table = ip_set_alloc(
407 sizeof(struct htable)
408 + jhash_size(hbits) * sizeof(struct hbucket));
409 if (!h->table) {
410 kfree(h);
411 return -ENOMEM;
412 }
413 h->table->htable_bits = hbits;
414
415 set->data = h;
416
417 if (tb[IPSET_ATTR_TIMEOUT]) {
418 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
419
420 set->variant = set->family == AF_INET
421 ? &hash_ip4_tvariant : &hash_ip6_tvariant;
422
423 if (set->family == AF_INET)
424 hash_ip4_gc_init(set);
425 else
426 hash_ip6_gc_init(set);
427 } else {
428 set->variant = set->family == AF_INET
429 ? &hash_ip4_variant : &hash_ip6_variant;
430 }
431
432 pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
433 set->name, jhash_size(h->table->htable_bits),
434 h->table->htable_bits, h->maxelem, set->data, h->table);
435
436 return 0;
437}
438
439static struct ip_set_type hash_ip_type __read_mostly = {
440 .name = "hash:ip",
441 .protocol = IPSET_PROTOCOL,
442 .features = IPSET_TYPE_IP,
443 .dimension = IPSET_DIM_ONE,
444 .family = AF_UNSPEC,
f1e00b39
JK
445 .revision_min = 0,
446 .revision_max = 0,
6c027889
JK
447 .create = hash_ip_create,
448 .create_policy = {
449 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
450 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
451 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
452 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
453 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
454 [IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
455 },
456 .adt_policy = {
457 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
458 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
459 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
460 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
461 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
462 },
463 .me = THIS_MODULE,
464};
465
466static int __init
467hash_ip_init(void)
468{
469 return ip_set_type_register(&hash_ip_type);
470}
471
472static void __exit
473hash_ip_fini(void)
474{
475 ip_set_type_unregister(&hash_ip_type);
476}
477
478module_init(hash_ip_init);
479module_exit(hash_ip_fini);