PageRenderTime 52ms CodeModel.GetById 17ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/net/netfilter/ipset/ip_set_hash_net.c

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