PageRenderTime 42ms CodeModel.GetById 17ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

/net/netfilter/ipset/ip_set_hash_ipport.c

http://github.com/mirrors/linux
C | 388 lines | 311 code | 64 blank | 13 comment | 64 complexity | 9580f41e841502491e270aa981209b95 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,port 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_getport.h>
 21#include <linux/netfilter/ipset/ip_set_hash.h>
 22
 23#define IPSET_TYPE_REV_MIN	0
 24/*				1    SCTP and UDPLITE support added */
 25/*				2    Counters support added */
 26/*				3    Comments support added */
 27/*				4    Forceadd support added */
 28#define IPSET_TYPE_REV_MAX	5 /* skbinfo support added */
 29
 30MODULE_LICENSE("GPL");
 31MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 32IP_SET_MODULE_DESC("hash:ip,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 33MODULE_ALIAS("ip_set_hash:ip,port");
 34
 35/* Type specific function prefix */
 36#define HTYPE		hash_ipport
 37
 38/* IPv4 variant */
 39
 40/* Member elements */
 41struct hash_ipport4_elem {
 42	__be32 ip;
 43	__be16 port;
 44	u8 proto;
 45	u8 padding;
 46};
 47
 48/* Common functions */
 49
 50static bool
 51hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
 52			const struct hash_ipport4_elem *ip2,
 53			u32 *multi)
 54{
 55	return ip1->ip == ip2->ip &&
 56	       ip1->port == ip2->port &&
 57	       ip1->proto == ip2->proto;
 58}
 59
 60static bool
 61hash_ipport4_data_list(struct sk_buff *skb,
 62		       const struct hash_ipport4_elem *data)
 63{
 64	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
 65	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
 66	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
 67		goto nla_put_failure;
 68	return false;
 69
 70nla_put_failure:
 71	return true;
 72}
 73
 74static void
 75hash_ipport4_data_next(struct hash_ipport4_elem *next,
 76		       const struct hash_ipport4_elem *d)
 77{
 78	next->ip = d->ip;
 79	next->port = d->port;
 80}
 81
 82#define MTYPE		hash_ipport4
 83#define HOST_MASK	32
 84#include "ip_set_hash_gen.h"
 85
 86static int
 87hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
 88		  const struct xt_action_param *par,
 89		  enum ipset_adt adt, struct ip_set_adt_opt *opt)
 90{
 91	ipset_adtfn adtfn = set->variant->adt[adt];
 92	struct hash_ipport4_elem e = { .ip = 0 };
 93	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 94
 95	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 96				 &e.port, &e.proto))
 97		return -EINVAL;
 98
 99	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
100	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
101}
102
103static int
104hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
105		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
106{
107	const struct hash_ipport4 *h = set->data;
108	ipset_adtfn adtfn = set->variant->adt[adt];
109	struct hash_ipport4_elem e = { .ip = 0 };
110	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
111	u32 ip, ip_to = 0, p = 0, port, port_to;
112	bool with_ports = false;
113	int ret;
114
115	if (tb[IPSET_ATTR_LINENO])
116		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
117
118	if (unlikely(!tb[IPSET_ATTR_IP] ||
119		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
120		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
121		return -IPSET_ERR_PROTOCOL;
122
123	ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip);
124	if (ret)
125		return ret;
126
127	ret = ip_set_get_extensions(set, tb, &ext);
128	if (ret)
129		return ret;
130
131	e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
132
133	if (tb[IPSET_ATTR_PROTO]) {
134		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
135		with_ports = ip_set_proto_with_ports(e.proto);
136
137		if (e.proto == 0)
138			return -IPSET_ERR_INVALID_PROTO;
139	} else {
140		return -IPSET_ERR_MISSING_PROTO;
141	}
142
143	if (!(with_ports || e.proto == IPPROTO_ICMP))
144		e.port = 0;
145
146	if (adt == IPSET_TEST ||
147	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
148	      tb[IPSET_ATTR_PORT_TO])) {
149		ret = adtfn(set, &e, &ext, &ext, flags);
150		return ip_set_eexist(ret, flags) ? 0 : ret;
151	}
152
153	ip_to = ip = ntohl(e.ip);
154	if (tb[IPSET_ATTR_IP_TO]) {
155		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
156		if (ret)
157			return ret;
158		if (ip > ip_to)
159			swap(ip, ip_to);
160	} else if (tb[IPSET_ATTR_CIDR]) {
161		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
162
163		if (!cidr || cidr > HOST_MASK)
164			return -IPSET_ERR_INVALID_CIDR;
165		ip_set_mask_from_to(ip, ip_to, cidr);
166	}
167
168	port_to = port = ntohs(e.port);
169	if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
170		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
171		if (port > port_to)
172			swap(port, port_to);
173	}
174
175	if (retried)
176		ip = ntohl(h->next.ip);
177	for (; ip <= ip_to; ip++) {
178		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
179						       : port;
180		for (; p <= port_to; p++) {
181			e.ip = htonl(ip);
182			e.port = htons(p);
183			ret = adtfn(set, &e, &ext, &ext, flags);
184
185			if (ret && !ip_set_eexist(ret, flags))
186				return ret;
187
188			ret = 0;
189		}
190	}
191	return ret;
192}
193
194/* IPv6 variant */
195
196struct hash_ipport6_elem {
197	union nf_inet_addr ip;
198	__be16 port;
199	u8 proto;
200	u8 padding;
201};
202
203/* Common functions */
204
205static bool
206hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
207			const struct hash_ipport6_elem *ip2,
208			u32 *multi)
209{
210	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
211	       ip1->port == ip2->port &&
212	       ip1->proto == ip2->proto;
213}
214
215static bool
216hash_ipport6_data_list(struct sk_buff *skb,
217		       const struct hash_ipport6_elem *data)
218{
219	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
220	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
221	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
222		goto nla_put_failure;
223	return false;
224
225nla_put_failure:
226	return true;
227}
228
229static void
230hash_ipport6_data_next(struct hash_ipport6_elem *next,
231		       const struct hash_ipport6_elem *d)
232{
233	next->port = d->port;
234}
235
236#undef MTYPE
237#undef HOST_MASK
238
239#define MTYPE		hash_ipport6
240#define HOST_MASK	128
241#define IP_SET_EMIT_CREATE
242#include "ip_set_hash_gen.h"
243
244static int
245hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
246		  const struct xt_action_param *par,
247		  enum ipset_adt adt, struct ip_set_adt_opt *opt)
248{
249	ipset_adtfn adtfn = set->variant->adt[adt];
250	struct hash_ipport6_elem e = { .ip = { .all = { 0 } } };
251	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
252
253	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
254				 &e.port, &e.proto))
255		return -EINVAL;
256
257	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
258	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
259}
260
261static int
262hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
263		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
264{
265	const struct hash_ipport6 *h = set->data;
266	ipset_adtfn adtfn = set->variant->adt[adt];
267	struct hash_ipport6_elem e = { .ip = { .all = { 0 } } };
268	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
269	u32 port, port_to;
270	bool with_ports = false;
271	int ret;
272
273	if (tb[IPSET_ATTR_LINENO])
274		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
275
276	if (unlikely(!tb[IPSET_ATTR_IP] ||
277		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
278		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
279		return -IPSET_ERR_PROTOCOL;
280	if (unlikely(tb[IPSET_ATTR_IP_TO]))
281		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
282	if (unlikely(tb[IPSET_ATTR_CIDR])) {
283		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
284
285		if (cidr != HOST_MASK)
286			return -IPSET_ERR_INVALID_CIDR;
287	}
288
289	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
290	if (ret)
291		return ret;
292
293	ret = ip_set_get_extensions(set, tb, &ext);
294	if (ret)
295		return ret;
296
297	e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
298
299	if (tb[IPSET_ATTR_PROTO]) {
300		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
301		with_ports = ip_set_proto_with_ports(e.proto);
302
303		if (e.proto == 0)
304			return -IPSET_ERR_INVALID_PROTO;
305	} else {
306		return -IPSET_ERR_MISSING_PROTO;
307	}
308
309	if (!(with_ports || e.proto == IPPROTO_ICMPV6))
310		e.port = 0;
311
312	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
313		ret = adtfn(set, &e, &ext, &ext, flags);
314		return ip_set_eexist(ret, flags) ? 0 : ret;
315	}
316
317	port = ntohs(e.port);
318	port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
319	if (port > port_to)
320		swap(port, port_to);
321
322	if (retried)
323		port = ntohs(h->next.port);
324	for (; port <= port_to; port++) {
325		e.port = htons(port);
326		ret = adtfn(set, &e, &ext, &ext, flags);
327
328		if (ret && !ip_set_eexist(ret, flags))
329			return ret;
330
331		ret = 0;
332	}
333	return ret;
334}
335
336static struct ip_set_type hash_ipport_type __read_mostly = {
337	.name		= "hash:ip,port",
338	.protocol	= IPSET_PROTOCOL,
339	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT,
340	.dimension	= IPSET_DIM_TWO,
341	.family		= NFPROTO_UNSPEC,
342	.revision_min	= IPSET_TYPE_REV_MIN,
343	.revision_max	= IPSET_TYPE_REV_MAX,
344	.create		= hash_ipport_create,
345	.create_policy	= {
346		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
347		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
348		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 },
349		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
350		[IPSET_ATTR_PROTO]	= { .type = NLA_U8 },
351		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
352		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
353	},
354	.adt_policy	= {
355		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
356		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
357		[IPSET_ATTR_PORT]	= { .type = NLA_U16 },
358		[IPSET_ATTR_PORT_TO]	= { .type = NLA_U16 },
359		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
360		[IPSET_ATTR_PROTO]	= { .type = NLA_U8 },
361		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
362		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
363		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
364		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
365		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING,
366					    .len  = IPSET_MAX_COMMENT_SIZE },
367		[IPSET_ATTR_SKBMARK]	= { .type = NLA_U64 },
368		[IPSET_ATTR_SKBPRIO]	= { .type = NLA_U32 },
369		[IPSET_ATTR_SKBQUEUE]	= { .type = NLA_U16 },
370	},
371	.me		= THIS_MODULE,
372};
373
374static int __init
375hash_ipport_init(void)
376{
377	return ip_set_type_register(&hash_ipport_type);
378}
379
380static void __exit
381hash_ipport_fini(void)
382{
383	rcu_barrier();
384	ip_set_type_unregister(&hash_ipport_type);
385}
386
387module_init(hash_ipport_init);
388module_exit(hash_ipport_fini);