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,mark 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	   Forceadd support */
24/*				2	   skbinfo support */
25#define IPSET_TYPE_REV_MAX	3	/* bucketsize, initval support  */
26
27MODULE_LICENSE("GPL");
28MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>");
29IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
30MODULE_ALIAS("ip_set_hash:ip,mark");
31
32/* Type specific function prefix */
33#define HTYPE		hash_ipmark
34#define IP_SET_HASH_WITH_MARKMASK
35
36/* IPv4 variant */
37
38/* Member elements */
39struct hash_ipmark4_elem {
40	__be32 ip;
41	__u32 mark;
42};
43
44/* Common functions */
45
46static bool
47hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1,
48			const struct hash_ipmark4_elem *ip2,
49			u32 *multi)
50{
51	return ip1->ip == ip2->ip &&
52	       ip1->mark == ip2->mark;
53}
54
55static bool
56hash_ipmark4_data_list(struct sk_buff *skb,
57		       const struct hash_ipmark4_elem *data)
58{
59	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
60	    nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
61		goto nla_put_failure;
62	return false;
63
64nla_put_failure:
65	return true;
66}
67
68static void
69hash_ipmark4_data_next(struct hash_ipmark4_elem *next,
70		       const struct hash_ipmark4_elem *d)
71{
72	next->ip = d->ip;
73}
74
75#define MTYPE		hash_ipmark4
76#define HOST_MASK	32
77#include "ip_set_hash_gen.h"
78
79static int
80hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb,
81		  const struct xt_action_param *par,
82		  enum ipset_adt adt, struct ip_set_adt_opt *opt)
83{
84	const struct hash_ipmark4 *h = set->data;
85	ipset_adtfn adtfn = set->variant->adt[adt];
86	struct hash_ipmark4_elem e = { };
87	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
88
89	e.mark = skb->mark;
90	e.mark &= h->markmask;
91
92	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
93	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
94}
95
96static int
97hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
98		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
99{
100	struct hash_ipmark4 *h = set->data;
101	ipset_adtfn adtfn = set->variant->adt[adt];
102	struct hash_ipmark4_elem e = { };
103	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
104	u32 ip, ip_to = 0, i = 0;
105	int ret;
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		     !ip_set_attr_netorder(tb, IPSET_ATTR_MARK)))
112		return -IPSET_ERR_PROTOCOL;
113
114	ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip);
115	if (ret)
116		return ret;
117
118	ret = ip_set_get_extensions(set, tb, &ext);
119	if (ret)
120		return ret;
121
122	e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK]));
123	e.mark &= h->markmask;
124	if (e.mark == 0 && e.ip == 0)
125		return -IPSET_ERR_HASH_ELEM;
126
127	if (adt == IPSET_TEST ||
128	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) {
129		ret = adtfn(set, &e, &ext, &ext, flags);
130		return ip_set_eexist(ret, flags) ? 0 : ret;
131	}
132
133	ip_to = ip = ntohl(e.ip);
134	if (tb[IPSET_ATTR_IP_TO]) {
135		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
136		if (ret)
137			return ret;
138		if (ip > ip_to) {
139			if (e.mark == 0 && ip_to == 0)
140				return -IPSET_ERR_HASH_ELEM;
141			swap(ip, ip_to);
142		}
143	} else if (tb[IPSET_ATTR_CIDR]) {
144		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
145
146		if (!cidr || cidr > HOST_MASK)
147			return -IPSET_ERR_INVALID_CIDR;
148		ip_set_mask_from_to(ip, ip_to, cidr);
149	}
150
151	if (retried)
152		ip = ntohl(h->next.ip);
153	for (; ip <= ip_to; ip++, i++) {
154		e.ip = htonl(ip);
155		if (i > IPSET_MAX_RANGE) {
156			hash_ipmark4_data_next(&h->next, &e);
157			return -ERANGE;
158		}
159		ret = adtfn(set, &e, &ext, &ext, flags);
160
161		if (ret && !ip_set_eexist(ret, flags))
162			return ret;
163
164		ret = 0;
165	}
166	return ret;
167}
168
169/* IPv6 variant */
170
171struct hash_ipmark6_elem {
172	union nf_inet_addr ip;
173	__u32 mark;
174};
175
176/* Common functions */
177
178static bool
179hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1,
180			const struct hash_ipmark6_elem *ip2,
181			u32 *multi)
182{
183	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
184	       ip1->mark == ip2->mark;
185}
186
187static bool
188hash_ipmark6_data_list(struct sk_buff *skb,
189		       const struct hash_ipmark6_elem *data)
190{
191	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
192	    nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
193		goto nla_put_failure;
194	return false;
195
196nla_put_failure:
197	return true;
198}
199
200static void
201hash_ipmark6_data_next(struct hash_ipmark6_elem *next,
202		       const struct hash_ipmark6_elem *d)
203{
204}
205
206#undef MTYPE
207#undef HOST_MASK
208
209#define MTYPE		hash_ipmark6
210#define HOST_MASK	128
211#define IP_SET_EMIT_CREATE
212#include "ip_set_hash_gen.h"
213
214static int
215hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb,
216		  const struct xt_action_param *par,
217		  enum ipset_adt adt, struct ip_set_adt_opt *opt)
218{
219	const struct hash_ipmark6 *h = set->data;
220	ipset_adtfn adtfn = set->variant->adt[adt];
221	struct hash_ipmark6_elem e = { };
222	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
223
224	e.mark = skb->mark;
225	e.mark &= h->markmask;
226
227	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
228	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
229}
230
231static int
232hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[],
233		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
234{
235	const struct hash_ipmark6 *h = set->data;
236	ipset_adtfn adtfn = set->variant->adt[adt];
237	struct hash_ipmark6_elem e = { };
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		     !ip_set_attr_netorder(tb, IPSET_ATTR_MARK)))
246		return -IPSET_ERR_PROTOCOL;
247	if (unlikely(tb[IPSET_ATTR_IP_TO]))
248		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
249	if (unlikely(tb[IPSET_ATTR_CIDR])) {
250		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
251
252		if (cidr != HOST_MASK)
253			return -IPSET_ERR_INVALID_CIDR;
254	}
255
256	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
257	if (ret)
258		return ret;
259
260	ret = ip_set_get_extensions(set, tb, &ext);
261	if (ret)
262		return ret;
263
264	e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK]));
265	e.mark &= h->markmask;
266
267	if (adt == IPSET_TEST) {
268		ret = adtfn(set, &e, &ext, &ext, flags);
269		return ip_set_eexist(ret, flags) ? 0 : ret;
270	}
271
272	ret = adtfn(set, &e, &ext, &ext, flags);
273	if (ret && !ip_set_eexist(ret, flags))
274		return ret;
275
276	return 0;
277}
278
279static struct ip_set_type hash_ipmark_type __read_mostly = {
280	.name		= "hash:ip,mark",
281	.protocol	= IPSET_PROTOCOL,
282	.features	= IPSET_TYPE_IP | IPSET_TYPE_MARK,
283	.dimension	= IPSET_DIM_TWO,
284	.family		= NFPROTO_UNSPEC,
285	.revision_min	= IPSET_TYPE_REV_MIN,
286	.revision_max	= IPSET_TYPE_REV_MAX,
287	.create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE,
288	.create		= hash_ipmark_create,
289	.create_policy	= {
290		[IPSET_ATTR_MARKMASK]	= { .type = NLA_U32 },
291		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
292		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
293		[IPSET_ATTR_INITVAL]	= { .type = NLA_U32 },
294		[IPSET_ATTR_BUCKETSIZE]	= { .type = NLA_U8 },
295		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
296		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
297		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
298	},
299	.adt_policy	= {
300		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
301		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
302		[IPSET_ATTR_MARK]	= { .type = NLA_U32 },
303		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
304		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
305		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
306		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
307		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
308		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING,
309					    .len  = IPSET_MAX_COMMENT_SIZE },
310		[IPSET_ATTR_SKBMARK]	= { .type = NLA_U64 },
311		[IPSET_ATTR_SKBPRIO]	= { .type = NLA_U32 },
312		[IPSET_ATTR_SKBQUEUE]	= { .type = NLA_U16 },
313	},
314	.me		= THIS_MODULE,
315};
316
317static int __init
318hash_ipmark_init(void)
319{
320	return ip_set_type_register(&hash_ipmark_type);
321}
322
323static void __exit
324hash_ipmark_fini(void)
325{
326	rcu_barrier();
327	ip_set_type_unregister(&hash_ipmark_type);
328}
329
330module_init(hash_ipmark_init);
331module_exit(hash_ipmark_fini);
332