blob: 3e4bffdc1cc01e7385e76be6d7ee9cdad8a0af18 [file] [log] [blame]
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +02001/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +01002 *
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>
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010015#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>
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010023#include <linux/netfilter/ipset/ip_set_hash.h>
24
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +020025#define IPSET_TYPE_REV_MIN 0
26/* 1 Range as input support for IPv4 added */
27/* 2 nomatch flag support added */
Oliver Smithfda75c62013-09-22 20:56:31 +020028/* 3 Counters support added */
Josh Hunt07cf8f52014-02-28 22:14:57 -050029/* 4 Comments support added */
Anton Danilovaf331412014-08-28 10:11:29 +040030/* 5 Forceadd support added */
31#define IPSET_TYPE_REV_MAX 6 /* skbinfo mapping support added */
Jozsef Kadlecsik10111a62012-09-21 21:59:32 +020032
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010033MODULE_LICENSE("GPL");
34MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +020035IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010036MODULE_ALIAS("ip_set_hash:net");
37
38/* Type specific function prefix */
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +020039#define HTYPE hash_net
40#define IP_SET_HASH_WITH_NETS
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010041
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +020042/* IPv4 variant */
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010043
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +020044/* Member elements */
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010045struct hash_net4_elem {
46 __be32 ip;
47 u16 padding0;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +010048 u8 nomatch;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010049 u8 cidr;
50};
51
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +020052/* Common functions */
53
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010054static inline bool
55hash_net4_data_equal(const struct hash_net4_elem *ip1,
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +020056 const struct hash_net4_elem *ip2,
57 u32 *multi)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010058{
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +010059 return ip1->ip == ip2->ip &&
60 ip1->cidr == ip2->cidr;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010061}
62
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +020063static inline int
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +020064hash_net4_do_data_match(const struct hash_net4_elem *elem)
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +010065{
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +020066 return elem->nomatch ? -ENOTEMPTY : 1;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010067}
68
69static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +020070hash_net4_data_set_flags(struct hash_net4_elem *elem, u32 flags)
71{
72 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
73}
74
75static inline void
76hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
77{
78 swap(*flags, elem->nomatch);
79}
80
81static inline void
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010082hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
83{
84 elem->ip &= ip_set_netmask(cidr);
85 elem->cidr = cidr;
86}
87
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010088static bool
89hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
90{
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +010091 u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
92
David S. Miller7cf78992012-04-01 19:54:46 -040093 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
94 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
95 (flags &&
96 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
97 goto nla_put_failure;
Sergey Popovich728a7e62015-05-02 19:28:15 +020098 return false;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +010099
100nla_put_failure:
Sergey Popovich728a7e62015-05-02 19:28:15 +0200101 return true;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100102}
103
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200104static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200105hash_net4_data_next(struct hash_net4_elem *next,
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200106 const struct hash_net4_elem *d)
107{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200108 next->ip = d->ip;
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200109}
110
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200111#define MTYPE hash_net4
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200112#define HOST_MASK 32
113#include "ip_set_hash_gen.h"
114
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100115static int
116hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
Jozsef Kadlecsikb66554c2011-06-16 18:56:47 +0200117 const struct xt_action_param *par,
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200118 enum ipset_adt adt, struct ip_set_adt_opt *opt)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100119{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200120 const struct hash_net *h = set->data;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100121 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200122 struct hash_net4_elem e = {
Jozsef Kadlecsikf690cba2015-06-12 22:11:00 +0200123 .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
Jozsef Kadlecsik9b03a5e2011-06-16 18:58:20 +0200124 };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200125 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100126
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200127 if (e.cidr == 0)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100128 return -EINVAL;
129 if (adt == IPSET_TEST)
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200130 e.cidr = HOST_MASK;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100131
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200132 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
133 e.ip &= ip_set_netmask(e.cidr);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100134
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200135 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100136}
137
138static int
139hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200140 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100141{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200142 const struct hash_net *h = set->data;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100143 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200144 struct hash_net4_elem e = { .cidr = HOST_MASK };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200145 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
Jozsef Kadlecsik20b2fab2013-05-01 18:47:32 +0200146 u32 ip = 0, ip_to = 0, last;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100147 int ret;
148
Sergey Popovicha212e082015-06-12 21:26:43 +0200149 if (tb[IPSET_ATTR_LINENO])
150 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
151
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100152 if (unlikely(!tb[IPSET_ATTR_IP] ||
Sergey Popovich7dd37bc2015-06-12 21:14:09 +0200153 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100154 return -IPSET_ERR_PROTOCOL;
155
Sergey Popovich8e55d2e2015-05-02 19:28:07 +0200156 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
157 if (ret)
158 return ret;
159
160 ret = ip_set_get_extensions(set, tb, &ext);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100161 if (ret)
162 return ret;
163
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200164 if (tb[IPSET_ATTR_CIDR]) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200165 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
166 if (!e.cidr || e.cidr > HOST_MASK)
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200167 return -IPSET_ERR_INVALID_CIDR;
168 }
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100169
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200170 if (tb[IPSET_ATTR_CADT_FLAGS]) {
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100171 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
Jozsef Kadlecsikca0f6a52015-06-13 19:45:33 +0200172
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100173 if (cadt_flags & IPSET_FLAG_NOMATCH)
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200174 flags |= (IPSET_FLAG_NOMATCH << 16);
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100175 }
176
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200177 if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200178 e.ip = htonl(ip & ip_set_hostmask(e.cidr));
179 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsikca0f6a52015-06-13 19:45:33 +0200180 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200181 ip_set_eexist(ret, flags) ? 0 : ret;
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200182 }
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100183
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200184 ip_to = ip;
185 if (tb[IPSET_ATTR_IP_TO]) {
186 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
187 if (ret)
188 return ret;
189 if (ip_to < ip)
190 swap(ip, ip_to);
191 if (ip + UINT_MAX == ip_to)
192 return -IPSET_ERR_HASH_RANGE;
193 }
194 if (retried)
Jozsef Kadlecsik6e27c9b2012-09-21 21:44:58 +0200195 ip = ntohl(h->next.ip);
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200196 while (!after(ip, ip_to)) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200197 e.ip = htonl(ip);
198 last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
199 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200200 if (ret && !ip_set_eexist(ret, flags))
201 return ret;
Jozsef Kadlecsikca0f6a52015-06-13 19:45:33 +0200202
203 ret = 0;
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200204 ip = last + 1;
205 }
206 return ret;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100207}
208
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200209/* IPv6 variant */
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100210
211struct hash_net6_elem {
212 union nf_inet_addr ip;
213 u16 padding0;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100214 u8 nomatch;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100215 u8 cidr;
216};
217
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200218/* Common functions */
219
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100220static inline bool
221hash_net6_data_equal(const struct hash_net6_elem *ip1,
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200222 const struct hash_net6_elem *ip2,
223 u32 *multi)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100224{
YOSHIFUJI Hideaki / 吉藤英明29e3b162013-01-29 12:49:03 +0000225 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100226 ip1->cidr == ip2->cidr;
227}
228
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200229static inline int
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200230hash_net6_do_data_match(const struct hash_net6_elem *elem)
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100231{
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200232 return elem->nomatch ? -ENOTEMPTY : 1;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100233}
234
235static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200236hash_net6_data_set_flags(struct hash_net6_elem *elem, u32 flags)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100237{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200238 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
239}
240
241static inline void
242hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
243{
244 swap(*flags, elem->nomatch);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100245}
246
247static inline void
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100248hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
249{
250 ip6_netmask(&elem->ip, cidr);
251 elem->cidr = cidr;
252}
253
254static bool
255hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
256{
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100257 u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
258
David S. Miller7cf78992012-04-01 19:54:46 -0400259 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
260 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
261 (flags &&
262 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
263 goto nla_put_failure;
Sergey Popovich728a7e62015-05-02 19:28:15 +0200264 return false;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100265
266nla_put_failure:
Sergey Popovich728a7e62015-05-02 19:28:15 +0200267 return true;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100268}
269
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200270static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200271hash_net6_data_next(struct hash_net4_elem *next,
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200272 const struct hash_net6_elem *d)
273{
274}
275
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200276#undef MTYPE
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200277#undef HOST_MASK
278
279#define MTYPE hash_net6
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200280#define HOST_MASK 128
281#define IP_SET_EMIT_CREATE
282#include "ip_set_hash_gen.h"
283
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100284static int
285hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
Jozsef Kadlecsikb66554c2011-06-16 18:56:47 +0200286 const struct xt_action_param *par,
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200287 enum ipset_adt adt, struct ip_set_adt_opt *opt)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100288{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200289 const struct hash_net *h = set->data;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100290 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200291 struct hash_net6_elem e = {
Jozsef Kadlecsikf690cba2015-06-12 22:11:00 +0200292 .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
Jozsef Kadlecsik9b03a5e2011-06-16 18:58:20 +0200293 };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200294 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100295
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200296 if (e.cidr == 0)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100297 return -EINVAL;
298 if (adt == IPSET_TEST)
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200299 e.cidr = HOST_MASK;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100300
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200301 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
302 ip6_netmask(&e.ip, e.cidr);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100303
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200304 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100305}
306
307static int
308hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200309 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100310{
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100311 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200312 struct hash_net6_elem e = { .cidr = HOST_MASK };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200313 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100314 int ret;
315
Sergey Popovicha212e082015-06-12 21:26:43 +0200316 if (tb[IPSET_ATTR_LINENO])
317 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
318
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100319 if (unlikely(!tb[IPSET_ATTR_IP] ||
Sergey Popovich7dd37bc2015-06-12 21:14:09 +0200320 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100321 return -IPSET_ERR_PROTOCOL;
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200322 if (unlikely(tb[IPSET_ATTR_IP_TO]))
323 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100324
Sergey Popovich8e55d2e2015-05-02 19:28:07 +0200325 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
326 if (ret)
327 return ret;
328
329 ret = ip_set_get_extensions(set, tb, &ext);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100330 if (ret)
331 return ret;
332
Sergey Popovichaff22752015-06-12 21:30:57 +0200333 if (tb[IPSET_ATTR_CIDR]) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200334 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
Sergey Popovichaff22752015-06-12 21:30:57 +0200335 if (!e.cidr || e.cidr > HOST_MASK)
336 return -IPSET_ERR_INVALID_CIDR;
337 }
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100338
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200339 ip6_netmask(&e.ip, e.cidr);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100340
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200341 if (tb[IPSET_ATTR_CADT_FLAGS]) {
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100342 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
Jozsef Kadlecsikca0f6a52015-06-13 19:45:33 +0200343
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100344 if (cadt_flags & IPSET_FLAG_NOMATCH)
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200345 flags |= (IPSET_FLAG_NOMATCH << 16);
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100346 }
347
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200348 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100349
Jozsef Kadlecsik0f1799b2013-09-16 20:04:53 +0200350 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200351 ip_set_eexist(ret, flags) ? 0 : ret;
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100352}
353
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100354static struct ip_set_type hash_net_type __read_mostly = {
355 .name = "hash:net",
356 .protocol = IPSET_PROTOCOL,
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200357 .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100358 .dimension = IPSET_DIM_ONE,
Jan Engelhardtc15f1c82012-02-14 00:24:10 +0100359 .family = NFPROTO_UNSPEC,
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +0200360 .revision_min = IPSET_TYPE_REV_MIN,
361 .revision_max = IPSET_TYPE_REV_MAX,
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100362 .create = hash_net_create,
363 .create_policy = {
364 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
365 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
366 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
367 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
368 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200369 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100370 },
371 .adt_policy = {
372 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
Jozsef Kadlecsikd0d9e0a2011-06-16 18:52:41 +0200373 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100374 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
375 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100376 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
Jozsef Kadlecsik00d71b22013-04-08 23:11:02 +0200377 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
378 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
Sergey Popovich03726182015-05-02 19:28:16 +0200379 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING,
380 .len = IPSET_MAX_COMMENT_SIZE },
Anton Danilovaf331412014-08-28 10:11:29 +0400381 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
382 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
383 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100384 },
385 .me = THIS_MODULE,
386};
387
388static int __init
389hash_net_init(void)
390{
391 return ip_set_type_register(&hash_net_type);
392}
393
394static void __exit
395hash_net_fini(void)
396{
Jozsef Kadlecsik18f84d42015-06-13 17:29:56 +0200397 rcu_barrier();
Jozsef Kadlecsikb3837022011-02-01 15:52:54 +0100398 ip_set_type_unregister(&hash_net_type);
399}
400
401module_init(hash_net_init);
402module_exit(hash_net_fini);