]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - net/netfilter/ipset/ip_set_hash_ipportip.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 500
[mirror_ubuntu-hirsute-kernel.git] / net / netfilter / ipset / ip_set_hash_ipportip.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
5d50e1d8 2/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5663bc30
JK
3 */
4
5/* Kernel module implementing an IP set type: the hash:ip,port,ip type */
6
7#include <linux/jhash.h>
8#include <linux/module.h>
9#include <linux/ip.h>
10#include <linux/skbuff.h>
11#include <linux/errno.h>
5663bc30
JK
12#include <linux/random.h>
13#include <net/ip.h>
14#include <net/ipv6.h>
15#include <net/netlink.h>
16#include <net/tcp.h>
17
18#include <linux/netfilter.h>
19#include <linux/netfilter/ipset/pfxlen.h>
20#include <linux/netfilter/ipset/ip_set.h>
5663bc30
JK
21#include <linux/netfilter/ipset/ip_set_getport.h>
22#include <linux/netfilter/ipset/ip_set_hash.h>
23
35b8dcf8
JK
24#define IPSET_TYPE_REV_MIN 0
25/* 1 SCTP and UDPLITE support added */
fda75c6d 26/* 2 Counters support added */
07cf8f5a 27/* 3 Comments support added */
af331419
AD
28/* 4 Forceadd support added */
29#define IPSET_TYPE_REV_MAX 5 /* skbinfo support added */
10111a6e 30
5663bc30
JK
31MODULE_LICENSE("GPL");
32MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
35b8dcf8 33IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
5663bc30
JK
34MODULE_ALIAS("ip_set_hash:ip,port,ip");
35
36/* Type specific function prefix */
5d50e1d8 37#define HTYPE hash_ipportip
5663bc30 38
03c8b234 39/* IPv4 variant */
5663bc30 40
5d50e1d8 41/* Member elements */
5663bc30
JK
42struct hash_ipportip4_elem {
43 __be32 ip;
44 __be32 ip2;
45 __be16 port;
46 u8 proto;
47 u8 padding;
48};
49
5663bc30
JK
50static inline bool
51hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
89dc79b7
JK
52 const struct hash_ipportip4_elem *ip2,
53 u32 *multi)
5663bc30
JK
54{
55 return ip1->ip == ip2->ip &&
56 ip1->ip2 == ip2->ip2 &&
57 ip1->port == ip2->port &&
58 ip1->proto == ip2->proto;
59}
60
5663bc30
JK
61static bool
62hash_ipportip4_data_list(struct sk_buff *skb,
ca0f6a5c 63 const struct hash_ipportip4_elem *data)
5663bc30 64{
7cf7899d
DM
65 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
66 nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
67 nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
68 nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
69 goto nla_put_failure;
728a7e69 70 return false;
5663bc30
JK
71
72nla_put_failure:
728a7e69 73 return true;
5663bc30
JK
74}
75
5d50e1d8
JK
76static inline void
77hash_ipportip4_data_next(struct hash_ipportip4_elem *next,
78 const struct hash_ipportip4_elem *d)
5663bc30 79{
5d50e1d8
JK
80 next->ip = d->ip;
81 next->port = d->port;
5663bc30
JK
82}
83
5d50e1d8
JK
84/* Common functions */
85#define MTYPE hash_ipportip4
5663bc30 86#define HOST_MASK 32
5d50e1d8 87#include "ip_set_hash_gen.h"
3d14b171 88
5663bc30
JK
89static int
90hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
b66554cf 91 const struct xt_action_param *par,
5d50e1d8 92 enum ipset_adt adt, struct ip_set_adt_opt *opt)
5663bc30 93{
5663bc30 94 ipset_adtfn adtfn = set->variant->adt[adt];
94729f8a 95 struct hash_ipportip4_elem e = { .ip = 0 };
ca134ce8 96 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
5663bc30 97
ac8cc925 98 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
5d50e1d8 99 &e.port, &e.proto))
5663bc30
JK
100 return -EINVAL;
101
5d50e1d8
JK
102 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
103 ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
104 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
5663bc30
JK
105}
106
107static int
108hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
3d14b171 109 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
5663bc30 110{
21956ab2 111 const struct hash_ipportip4 *h = set->data;
5663bc30 112 ipset_adtfn adtfn = set->variant->adt[adt];
94729f8a 113 struct hash_ipportip4_elem e = { .ip = 0 };
ca134ce8 114 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
20b2fab4 115 u32 ip, ip_to = 0, p = 0, port, port_to;
5e0c1eb7 116 bool with_ports = false;
5663bc30
JK
117 int ret;
118
a212e08e
SP
119 if (tb[IPSET_ATTR_LINENO])
120 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
121
5663bc30
JK
122 if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
123 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
7dd37bc8 124 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
5663bc30
JK
125 return -IPSET_ERR_PROTOCOL;
126
8e55d2e5
SP
127 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip);
128 if (ret)
129 return ret;
130
131 ret = ip_set_get_extensions(set, tb, &ext);
5663bc30
JK
132 if (ret)
133 return ret;
134
5d50e1d8 135 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &e.ip2);
5663bc30
JK
136 if (ret)
137 return ret;
138
d25472e4 139 e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
5663bc30
JK
140
141 if (tb[IPSET_ATTR_PROTO]) {
5d50e1d8
JK
142 e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
143 with_ports = ip_set_proto_with_ports(e.proto);
5663bc30 144
5d50e1d8 145 if (e.proto == 0)
5663bc30 146 return -IPSET_ERR_INVALID_PROTO;
ca0f6a5c 147 } else {
5663bc30 148 return -IPSET_ERR_MISSING_PROTO;
ca0f6a5c 149 }
5663bc30 150
5d50e1d8
JK
151 if (!(with_ports || e.proto == IPPROTO_ICMP))
152 e.port = 0;
5663bc30
JK
153
154 if (adt == IPSET_TEST ||
5663bc30
JK
155 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
156 tb[IPSET_ATTR_PORT_TO])) {
5d50e1d8 157 ret = adtfn(set, &e, &ext, &ext, flags);
5663bc30
JK
158 return ip_set_eexist(ret, flags) ? 0 : ret;
159 }
160
5d50e1d8 161 ip_to = ip = ntohl(e.ip);
5663bc30
JK
162 if (tb[IPSET_ATTR_IP_TO]) {
163 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
164 if (ret)
165 return ret;
166 if (ip > ip_to)
167 swap(ip, ip_to);
168 } else if (tb[IPSET_ATTR_CIDR]) {
169 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
170
cabfd139 171 if (!cidr || cidr > HOST_MASK)
5663bc30 172 return -IPSET_ERR_INVALID_CIDR;
e6146e86 173 ip_set_mask_from_to(ip, ip_to, cidr);
4fe198e6 174 }
5663bc30 175
5d50e1d8 176 port_to = port = ntohs(e.port);
5e0c1eb7 177 if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
5663bc30
JK
178 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
179 if (port > port_to)
180 swap(port, port_to);
5e0c1eb7 181 }
5663bc30 182
3d14b171 183 if (retried)
6e27c9b4 184 ip = ntohl(h->next.ip);
48596a8d 185 for (; ip <= ip_to; ip++) {
6e27c9b4
JK
186 p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
187 : port;
3d14b171 188 for (; p <= port_to; p++) {
5d50e1d8
JK
189 e.ip = htonl(ip);
190 e.port = htons(p);
191 ret = adtfn(set, &e, &ext, &ext, flags);
5663bc30
JK
192
193 if (ret && !ip_set_eexist(ret, flags))
194 return ret;
ca0f6a5c
JK
195
196 ret = 0;
5663bc30 197 }
3d14b171 198 }
5663bc30
JK
199 return ret;
200}
201
03c8b234 202/* IPv6 variant */
5663bc30
JK
203
204struct hash_ipportip6_elem {
205 union nf_inet_addr ip;
206 union nf_inet_addr ip2;
207 __be16 port;
208 u8 proto;
209 u8 padding;
210};
211
5d50e1d8
JK
212/* Common functions */
213
5663bc30
JK
214static inline bool
215hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
89dc79b7
JK
216 const struct hash_ipportip6_elem *ip2,
217 u32 *multi)
5663bc30 218{
29e3b160
YH
219 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
220 ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) &&
5663bc30
JK
221 ip1->port == ip2->port &&
222 ip1->proto == ip2->proto;
223}
224
5663bc30
JK
225static bool
226hash_ipportip6_data_list(struct sk_buff *skb,
227 const struct hash_ipportip6_elem *data)
228{
7cf7899d
DM
229 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
230 nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
231 nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
232 nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
233 goto nla_put_failure;
728a7e69 234 return false;
5663bc30
JK
235
236nla_put_failure:
728a7e69 237 return true;
5663bc30
JK
238}
239
5d50e1d8 240static inline void
21956ab2 241hash_ipportip6_data_next(struct hash_ipportip6_elem *next,
5d50e1d8 242 const struct hash_ipportip6_elem *d)
5663bc30 243{
5d50e1d8 244 next->port = d->port;
5663bc30
JK
245}
246
5d50e1d8 247#undef MTYPE
5663bc30
JK
248#undef HOST_MASK
249
5d50e1d8 250#define MTYPE hash_ipportip6
5663bc30 251#define HOST_MASK 128
5d50e1d8
JK
252#define IP_SET_EMIT_CREATE
253#include "ip_set_hash_gen.h"
3d14b171 254
5663bc30
JK
255static int
256hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
b66554cf 257 const struct xt_action_param *par,
5d50e1d8 258 enum ipset_adt adt, struct ip_set_adt_opt *opt)
5663bc30 259{
5663bc30 260 ipset_adtfn adtfn = set->variant->adt[adt];
94729f8a 261 struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } };
ca134ce8 262 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
5663bc30 263
ac8cc925 264 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
5d50e1d8 265 &e.port, &e.proto))
5663bc30
JK
266 return -EINVAL;
267
5d50e1d8
JK
268 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
269 ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
270 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
5663bc30
JK
271}
272
273static int
274hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
3d14b171 275 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
5663bc30 276{
21956ab2 277 const struct hash_ipportip6 *h = set->data;
5663bc30 278 ipset_adtfn adtfn = set->variant->adt[adt];
94729f8a 279 struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } };
ca134ce8 280 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
5663bc30 281 u32 port, port_to;
5e0c1eb7 282 bool with_ports = false;
5663bc30
JK
283 int ret;
284
a212e08e
SP
285 if (tb[IPSET_ATTR_LINENO])
286 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
287
5663bc30
JK
288 if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
289 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
2c227f27 290 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
5663bc30 291 return -IPSET_ERR_PROTOCOL;
2c227f27
SP
292 if (unlikely(tb[IPSET_ATTR_IP_TO]))
293 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
294 if (unlikely(tb[IPSET_ATTR_CIDR])) {
295 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
296
297 if (cidr != HOST_MASK)
298 return -IPSET_ERR_INVALID_CIDR;
299 }
5663bc30 300
8e55d2e5
SP
301 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
302 if (ret)
303 return ret;
304
305 ret = ip_set_get_extensions(set, tb, &ext);
5663bc30
JK
306 if (ret)
307 return ret;
308
5d50e1d8 309 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
5663bc30
JK
310 if (ret)
311 return ret;
312
d25472e4 313 e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
5663bc30
JK
314
315 if (tb[IPSET_ATTR_PROTO]) {
5d50e1d8
JK
316 e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
317 with_ports = ip_set_proto_with_ports(e.proto);
5663bc30 318
5d50e1d8 319 if (e.proto == 0)
5663bc30 320 return -IPSET_ERR_INVALID_PROTO;
ca0f6a5c 321 } else {
5663bc30 322 return -IPSET_ERR_MISSING_PROTO;
ca0f6a5c 323 }
5663bc30 324
5d50e1d8
JK
325 if (!(with_ports || e.proto == IPPROTO_ICMPV6))
326 e.port = 0;
5663bc30 327
5e0c1eb7 328 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
5d50e1d8 329 ret = adtfn(set, &e, &ext, &ext, flags);
5663bc30
JK
330 return ip_set_eexist(ret, flags) ? 0 : ret;
331 }
332
5d50e1d8 333 port = ntohs(e.port);
5663bc30
JK
334 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
335 if (port > port_to)
336 swap(port, port_to);
337
3d14b171 338 if (retried)
6e27c9b4 339 port = ntohs(h->next.port);
5663bc30 340 for (; port <= port_to; port++) {
5d50e1d8
JK
341 e.port = htons(port);
342 ret = adtfn(set, &e, &ext, &ext, flags);
5663bc30
JK
343
344 if (ret && !ip_set_eexist(ret, flags))
345 return ret;
ca0f6a5c
JK
346
347 ret = 0;
5663bc30
JK
348 }
349 return ret;
350}
351
5663bc30
JK
352static struct ip_set_type hash_ipportip_type __read_mostly = {
353 .name = "hash:ip,port,ip",
354 .protocol = IPSET_PROTOCOL,
355 .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
356 .dimension = IPSET_DIM_THREE,
c15f1c83 357 .family = NFPROTO_UNSPEC,
35b8dcf8
JK
358 .revision_min = IPSET_TYPE_REV_MIN,
359 .revision_max = IPSET_TYPE_REV_MAX,
5663bc30
JK
360 .create = hash_ipportip_create,
361 .create_policy = {
362 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
363 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
364 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
365 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
366 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
00d71b27 367 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
5663bc30
JK
368 },
369 .adt_policy = {
370 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
371 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
372 [IPSET_ATTR_IP2] = { .type = NLA_NESTED },
373 [IPSET_ATTR_PORT] = { .type = NLA_U16 },
374 [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
375 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
376 [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
377 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
378 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
00d71b27
JK
379 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
380 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
03726186
SP
381 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING,
382 .len = IPSET_MAX_COMMENT_SIZE },
af331419
AD
383 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
384 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
385 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
5663bc30
JK
386 },
387 .me = THIS_MODULE,
388};
389
390static int __init
391hash_ipportip_init(void)
392{
393 return ip_set_type_register(&hash_ipportip_type);
394}
395
396static void __exit
397hash_ipportip_fini(void)
398{
18f84d41 399 rcu_barrier();
5663bc30
JK
400 ip_set_type_unregister(&hash_ipportip_type);
401}
402
403module_init(hash_ipportip_init);
404module_exit(hash_ipportip_fini);