]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - net/netfilter/ipset/ip_set_hash_ipmark.c
netfilter: ipset: Preprocessor directices cleanup
[mirror_ubuntu-jammy-kernel.git] / net / netfilter / ipset / ip_set_hash_ipmark.c
CommitLineData
3b02b56c
VD
1/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2 * Copyright (C) 2013 Smoothwall Ltd. <vytas.dauksa@smoothwall.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9/* Kernel module implementing an IP set type: the hash:ip,mark type */
10
11#include <linux/jhash.h>
12#include <linux/module.h>
13#include <linux/ip.h>
14#include <linux/skbuff.h>
15#include <linux/errno.h>
16#include <linux/random.h>
17#include <net/ip.h>
18#include <net/ipv6.h>
19#include <net/netlink.h>
20#include <net/tcp.h>
21
22#include <linux/netfilter.h>
23#include <linux/netfilter/ipset/pfxlen.h>
24#include <linux/netfilter/ipset/ip_set.h>
25#include <linux/netfilter/ipset/ip_set_hash.h>
26
27#define IPSET_TYPE_REV_MIN 0
af331419
AD
28/* 1 Forceadd support */
29#define IPSET_TYPE_REV_MAX 2 /* skbinfo support */
3b02b56c
VD
30
31MODULE_LICENSE("GPL");
32MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>");
33IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
34MODULE_ALIAS("ip_set_hash:ip,mark");
35
36/* Type specific function prefix */
37#define HTYPE hash_ipmark
4d0e5c07 38#define IP_SET_HASH_WITH_MARKMASK
3b02b56c
VD
39
40/* IPv4 variant */
41
42/* Member elements */
43struct hash_ipmark4_elem {
44 __be32 ip;
45 __u32 mark;
46};
47
48/* Common functions */
49
50static inline bool
51hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1,
52 const struct hash_ipmark4_elem *ip2,
53 u32 *multi)
54{
55 return ip1->ip == ip2->ip &&
56 ip1->mark == ip2->mark;
57}
58
59static bool
60hash_ipmark4_data_list(struct sk_buff *skb,
61 const struct hash_ipmark4_elem *data)
62{
63 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
64 nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
65 goto nla_put_failure;
66 return 0;
67
68nla_put_failure:
69 return 1;
70}
71
72static inline void
73hash_ipmark4_data_next(struct hash_ipmark4_elem *next,
74 const struct hash_ipmark4_elem *d)
75{
76 next->ip = d->ip;
77}
78
79#define MTYPE hash_ipmark4
3b02b56c
VD
80#define HOST_MASK 32
81#define HKEY_DATALEN sizeof(struct hash_ipmark4_elem)
82#include "ip_set_hash_gen.h"
83
84static int
85hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb,
86 const struct xt_action_param *par,
87 enum ipset_adt adt, struct ip_set_adt_opt *opt)
88{
4d0e5c07 89 const struct hash_ipmark *h = set->data;
3b02b56c
VD
90 ipset_adtfn adtfn = set->variant->adt[adt];
91 struct hash_ipmark4_elem e = { };
92 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
93
94 e.mark = skb->mark;
4d0e5c07 95 e.mark &= h->markmask;
3b02b56c
VD
96
97 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
98 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
99}
100
101static int
102hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
103 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
104{
105 const struct hash_ipmark *h = set->data;
106 ipset_adtfn adtfn = set->variant->adt[adt];
107 struct hash_ipmark4_elem e = { };
108 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
109 u32 ip, ip_to = 0;
110 int ret;
111
112 if (unlikely(!tb[IPSET_ATTR_IP] ||
113 !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) ||
114 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
115 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
af331419
AD
116 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
117 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
118 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
119 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
3b02b56c
VD
120 return -IPSET_ERR_PROTOCOL;
121
122 if (tb[IPSET_ATTR_LINENO])
123 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
124
125 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
126 ip_set_get_extensions(set, tb, &ext);
127 if (ret)
128 return ret;
129
2006aa4a 130 e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK]));
4d0e5c07 131 e.mark &= h->markmask;
3b02b56c
VD
132
133 if (adt == IPSET_TEST ||
134 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) {
135 ret = adtfn(set, &e, &ext, &ext, flags);
136 return ip_set_eexist(ret, flags) ? 0 : ret;
137 }
138
139 ip_to = ip = ntohl(e.ip);
140 if (tb[IPSET_ATTR_IP_TO]) {
141 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
142 if (ret)
143 return ret;
144 if (ip > ip_to)
145 swap(ip, ip_to);
146 } else if (tb[IPSET_ATTR_CIDR]) {
147 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
148
149 if (!cidr || cidr > 32)
150 return -IPSET_ERR_INVALID_CIDR;
151 ip_set_mask_from_to(ip, ip_to, cidr);
152 }
153
154 if (retried)
155 ip = ntohl(h->next.ip);
156 for (; !before(ip_to, ip); ip++) {
157 e.ip = htonl(ip);
158 ret = adtfn(set, &e, &ext, &ext, flags);
159
160 if (ret && !ip_set_eexist(ret, flags))
161 return ret;
162 else
163 ret = 0;
164 }
165 return ret;
166}
167
168/* IPv6 variant */
169
170struct hash_ipmark6_elem {
171 union nf_inet_addr ip;
172 __u32 mark;
173};
174
175/* Common functions */
176
177static inline bool
178hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1,
179 const struct hash_ipmark6_elem *ip2,
180 u32 *multi)
181{
182 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
183 ip1->mark == ip2->mark;
184}
185
186static bool
187hash_ipmark6_data_list(struct sk_buff *skb,
188 const struct hash_ipmark6_elem *data)
189{
190 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
191 nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
192 goto nla_put_failure;
193 return 0;
194
195nla_put_failure:
196 return 1;
197}
198
199static inline void
200hash_ipmark6_data_next(struct hash_ipmark4_elem *next,
201 const struct hash_ipmark6_elem *d)
202{
203}
204
205#undef MTYPE
3b02b56c
VD
206#undef HOST_MASK
207#undef HKEY_DATALEN
208
209#define MTYPE hash_ipmark6
3b02b56c
VD
210#define HOST_MASK 128
211#define HKEY_DATALEN sizeof(struct hash_ipmark6_elem)
212#define IP_SET_EMIT_CREATE
213#include "ip_set_hash_gen.h"
214
215
216static int
217hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb,
218 const struct xt_action_param *par,
219 enum ipset_adt adt, struct ip_set_adt_opt *opt)
220{
4d0e5c07 221 const struct hash_ipmark *h = set->data;
3b02b56c
VD
222 ipset_adtfn adtfn = set->variant->adt[adt];
223 struct hash_ipmark6_elem e = { };
224 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
225
226 e.mark = skb->mark;
4d0e5c07 227 e.mark &= h->markmask;
3b02b56c
VD
228
229 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
230 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
231}
232
233static int
234hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[],
235 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
236{
4d0e5c07 237 const struct hash_ipmark *h = set->data;
3b02b56c
VD
238 ipset_adtfn adtfn = set->variant->adt[adt];
239 struct hash_ipmark6_elem e = { };
240 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
241 int ret;
242
243 if (unlikely(!tb[IPSET_ATTR_IP] ||
244 !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) ||
245 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
246 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
247 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
af331419
AD
248 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
249 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
250 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) ||
3b02b56c
VD
251 tb[IPSET_ATTR_IP_TO] ||
252 tb[IPSET_ATTR_CIDR]))
253 return -IPSET_ERR_PROTOCOL;
254
255 if (tb[IPSET_ATTR_LINENO])
256 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
257
258 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
259 ip_set_get_extensions(set, tb, &ext);
260 if (ret)
261 return ret;
262
2006aa4a 263 e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK]));
4d0e5c07 264 e.mark &= h->markmask;
3b02b56c
VD
265
266 if (adt == IPSET_TEST) {
267 ret = adtfn(set, &e, &ext, &ext, flags);
268 return ip_set_eexist(ret, flags) ? 0 : ret;
269 }
270
271 ret = adtfn(set, &e, &ext, &ext, flags);
272 if (ret && !ip_set_eexist(ret, flags))
273 return ret;
274 else
275 ret = 0;
276
277 return ret;
278}
279
280static struct ip_set_type hash_ipmark_type __read_mostly = {
281 .name = "hash:ip,mark",
282 .protocol = IPSET_PROTOCOL,
283 .features = IPSET_TYPE_IP | IPSET_TYPE_MARK,
284 .dimension = IPSET_DIM_TWO,
285 .family = NFPROTO_UNSPEC,
286 .revision_min = IPSET_TYPE_REV_MIN,
287 .revision_max = IPSET_TYPE_REV_MAX,
288 .create = hash_ipmark_create,
289 .create_policy = {
4d0e5c07 290 [IPSET_ATTR_MARKMASK] = { .type = NLA_U32 },
3b02b56c
VD
291 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
292 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
293 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
294 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
295 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
296 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
297 },
298 .adt_policy = {
299 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
300 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
301 [IPSET_ATTR_MARK] = { .type = NLA_U32 },
302 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
303 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
304 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
305 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
306 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
307 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
af331419
AD
308 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
309 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
310 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
3b02b56c
VD
311 },
312 .me = THIS_MODULE,
313};
314
315static int __init
316hash_ipmark_init(void)
317{
318 return ip_set_type_register(&hash_ipmark_type);
319}
320
321static void __exit
322hash_ipmark_fini(void)
323{
324 ip_set_type_unregister(&hash_ipmark_type);
325}
326
327module_init(hash_ipmark_init);
328module_exit(hash_ipmark_fini);