PageRenderTime 37ms CodeModel.GetById 16ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/net/netfilter/ipset/ip_set_hash_ip.c

http://github.com/mirrors/linux
C | 321 lines | 250 code | 57 blank | 14 comment | 37 complexity | 8a693d38726aaf20c110acc56b29e58a 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:ip 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#include <net/tcp.h>
 16
 17#include <linux/netfilter.h>
 18#include <linux/netfilter/ipset/pfxlen.h>
 19#include <linux/netfilter/ipset/ip_set.h>
 20#include <linux/netfilter/ipset/ip_set_hash.h>
 21
 22#define IPSET_TYPE_REV_MIN	0
 23/*				1	   Counters support */
 24/*				2	   Comments support */
 25/*				3	   Forceadd support */
 26#define IPSET_TYPE_REV_MAX	4	/* skbinfo support  */
 27
 28MODULE_LICENSE("GPL");
 29MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 30IP_SET_MODULE_DESC("hash:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 31MODULE_ALIAS("ip_set_hash:ip");
 32
 33/* Type specific function prefix */
 34#define HTYPE		hash_ip
 35#define IP_SET_HASH_WITH_NETMASK
 36
 37/* IPv4 variant */
 38
 39/* Member elements */
 40struct hash_ip4_elem {
 41	/* Zero valued IP addresses cannot be stored */
 42	__be32 ip;
 43};
 44
 45/* Common functions */
 46
 47static bool
 48hash_ip4_data_equal(const struct hash_ip4_elem *e1,
 49		    const struct hash_ip4_elem *e2,
 50		    u32 *multi)
 51{
 52	return e1->ip == e2->ip;
 53}
 54
 55static bool
 56hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *e)
 57{
 58	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, e->ip))
 59		goto nla_put_failure;
 60	return false;
 61
 62nla_put_failure:
 63	return true;
 64}
 65
 66static void
 67hash_ip4_data_next(struct hash_ip4_elem *next, const struct hash_ip4_elem *e)
 68{
 69	next->ip = e->ip;
 70}
 71
 72#define MTYPE		hash_ip4
 73#define HOST_MASK	32
 74#include "ip_set_hash_gen.h"
 75
 76static int
 77hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
 78	      const struct xt_action_param *par,
 79	      enum ipset_adt adt, struct ip_set_adt_opt *opt)
 80{
 81	const struct hash_ip4 *h = set->data;
 82	ipset_adtfn adtfn = set->variant->adt[adt];
 83	struct hash_ip4_elem e = { 0 };
 84	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 85	__be32 ip;
 86
 87	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
 88	ip &= ip_set_netmask(h->netmask);
 89	if (ip == 0)
 90		return -EINVAL;
 91
 92	e.ip = ip;
 93	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 94}
 95
 96static int
 97hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
 98	      enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 99{
100	const struct hash_ip4 *h = set->data;
101	ipset_adtfn adtfn = set->variant->adt[adt];
102	struct hash_ip4_elem e = { 0 };
103	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
104	u32 ip = 0, ip_to = 0, hosts;
105	int ret = 0;
106
107	if (tb[IPSET_ATTR_LINENO])
108		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
109
110	if (unlikely(!tb[IPSET_ATTR_IP]))
111		return -IPSET_ERR_PROTOCOL;
112
113	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
114	if (ret)
115		return ret;
116
117	ret = ip_set_get_extensions(set, tb, &ext);
118	if (ret)
119		return ret;
120
121	ip &= ip_set_hostmask(h->netmask);
122	e.ip = htonl(ip);
123	if (e.ip == 0)
124		return -IPSET_ERR_HASH_ELEM;
125
126	if (adt == IPSET_TEST)
127		return adtfn(set, &e, &ext, &ext, flags);
128
129	ip_to = ip;
130	if (tb[IPSET_ATTR_IP_TO]) {
131		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
132		if (ret)
133			return ret;
134		if (ip > ip_to)
135			swap(ip, ip_to);
136	} else if (tb[IPSET_ATTR_CIDR]) {
137		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
138
139		if (!cidr || cidr > HOST_MASK)
140			return -IPSET_ERR_INVALID_CIDR;
141		ip_set_mask_from_to(ip, ip_to, cidr);
142	}
143
144	hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
145
146	if (retried) {
147		ip = ntohl(h->next.ip);
148		e.ip = htonl(ip);
149	}
150	for (; ip <= ip_to;) {
151		ret = adtfn(set, &e, &ext, &ext, flags);
152		if (ret && !ip_set_eexist(ret, flags))
153			return ret;
154
155		ip += hosts;
156		e.ip = htonl(ip);
157		if (e.ip == 0)
158			return 0;
159
160		ret = 0;
161	}
162	return ret;
163}
164
165/* IPv6 variant */
166
167/* Member elements */
168struct hash_ip6_elem {
169	union nf_inet_addr ip;
170};
171
172/* Common functions */
173
174static bool
175hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
176		    const struct hash_ip6_elem *ip2,
177		    u32 *multi)
178{
179	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6);
180}
181
182static void
183hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix)
184{
185	ip6_netmask(ip, prefix);
186}
187
188static bool
189hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e)
190{
191	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6))
192		goto nla_put_failure;
193	return false;
194
195nla_put_failure:
196	return true;
197}
198
199static void
200hash_ip6_data_next(struct hash_ip6_elem *next, const struct hash_ip6_elem *e)
201{
202}
203
204#undef MTYPE
205#undef HOST_MASK
206
207#define MTYPE		hash_ip6
208#define HOST_MASK	128
209
210#define IP_SET_EMIT_CREATE
211#include "ip_set_hash_gen.h"
212
213static int
214hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
215	      const struct xt_action_param *par,
216	      enum ipset_adt adt, struct ip_set_adt_opt *opt)
217{
218	const struct hash_ip6 *h = set->data;
219	ipset_adtfn adtfn = set->variant->adt[adt];
220	struct hash_ip6_elem e = { { .all = { 0 } } };
221	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
222
223	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
224	hash_ip6_netmask(&e.ip, h->netmask);
225	if (ipv6_addr_any(&e.ip.in6))
226		return -EINVAL;
227
228	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
229}
230
231static int
232hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
233	      enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
234{
235	const struct hash_ip6 *h = set->data;
236	ipset_adtfn adtfn = set->variant->adt[adt];
237	struct hash_ip6_elem e = { { .all = { 0 } } };
238	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
239	int ret;
240
241	if (tb[IPSET_ATTR_LINENO])
242		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
243
244	if (unlikely(!tb[IPSET_ATTR_IP]))
245		return -IPSET_ERR_PROTOCOL;
246	if (unlikely(tb[IPSET_ATTR_IP_TO]))
247		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
248	if (unlikely(tb[IPSET_ATTR_CIDR])) {
249		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
250
251		if (cidr != HOST_MASK)
252			return -IPSET_ERR_INVALID_CIDR;
253	}
254
255	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
256	if (ret)
257		return ret;
258
259	ret = ip_set_get_extensions(set, tb, &ext);
260	if (ret)
261		return ret;
262
263	hash_ip6_netmask(&e.ip, h->netmask);
264	if (ipv6_addr_any(&e.ip.in6))
265		return -IPSET_ERR_HASH_ELEM;
266
267	ret = adtfn(set, &e, &ext, &ext, flags);
268
269	return ip_set_eexist(ret, flags) ? 0 : ret;
270}
271
272static struct ip_set_type hash_ip_type __read_mostly = {
273	.name		= "hash:ip",
274	.protocol	= IPSET_PROTOCOL,
275	.features	= IPSET_TYPE_IP,
276	.dimension	= IPSET_DIM_ONE,
277	.family		= NFPROTO_UNSPEC,
278	.revision_min	= IPSET_TYPE_REV_MIN,
279	.revision_max	= IPSET_TYPE_REV_MAX,
280	.create		= hash_ip_create,
281	.create_policy	= {
282		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
283		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
284		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 },
285		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
286		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
287		[IPSET_ATTR_NETMASK]	= { .type = NLA_U8  },
288		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
289	},
290	.adt_policy	= {
291		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
292		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
293		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
294		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
295		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
296		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
297		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
298		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING,
299					    .len  = IPSET_MAX_COMMENT_SIZE },
300		[IPSET_ATTR_SKBMARK]	= { .type = NLA_U64 },
301		[IPSET_ATTR_SKBPRIO]	= { .type = NLA_U32 },
302		[IPSET_ATTR_SKBQUEUE]	= { .type = NLA_U16 },
303	},
304	.me		= THIS_MODULE,
305};
306
307static int __init
308hash_ip_init(void)
309{
310	return ip_set_type_register(&hash_ip_type);
311}
312
313static void __exit
314hash_ip_fini(void)
315{
316	rcu_barrier();
317	ip_set_type_unregister(&hash_ip_type);
318}
319
320module_init(hash_ip_init);
321module_exit(hash_ip_fini);