Commit | Line | Data |
---|---|---|
a7b4f989 JK |
1 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> |
2 | * Patrick Schaaf <bof@bof.de> | |
3 | * Martin Josefsson <gandalf@wlug.westbo.se> | |
075e64c0 | 4 | * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> |
a7b4f989 JK |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
a8201414 DH |
10 | #ifndef _IP_SET_H |
11 | #define _IP_SET_H | |
a7b4f989 | 12 | |
ae8ded1c JE |
13 | #include <linux/ip.h> |
14 | #include <linux/ipv6.h> | |
15 | #include <linux/netlink.h> | |
16 | #include <linux/netfilter.h> | |
17 | #include <linux/netfilter/x_tables.h> | |
10111a6e | 18 | #include <linux/stringify.h> |
ae8ded1c JE |
19 | #include <linux/vmalloc.h> |
20 | #include <net/netlink.h> | |
a8201414 | 21 | #include <uapi/linux/netfilter/ipset/ip_set.h> |
ae8ded1c | 22 | |
10111a6e JK |
23 | #define _IP_SET_MODULE_DESC(a, b, c) \ |
24 | MODULE_DESCRIPTION(a " type of IP sets, revisions " b "-" c) | |
25 | #define IP_SET_MODULE_DESC(a, b, c) \ | |
26 | _IP_SET_MODULE_DESC(a, __stringify(b), __stringify(c)) | |
27 | ||
a7b4f989 JK |
28 | /* Set features */ |
29 | enum ip_set_feature { | |
30 | IPSET_TYPE_IP_FLAG = 0, | |
31 | IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), | |
32 | IPSET_TYPE_PORT_FLAG = 1, | |
33 | IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), | |
34 | IPSET_TYPE_MAC_FLAG = 2, | |
35 | IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), | |
36 | IPSET_TYPE_IP2_FLAG = 3, | |
37 | IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), | |
38 | IPSET_TYPE_NAME_FLAG = 4, | |
39 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), | |
e385357a JK |
40 | IPSET_TYPE_IFACE_FLAG = 5, |
41 | IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG), | |
3e0304a5 JK |
42 | IPSET_TYPE_NOMATCH_FLAG = 6, |
43 | IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG), | |
a7b4f989 JK |
44 | /* Strictly speaking not a feature, but a flag for dumping: |
45 | * this settype must be dumped last */ | |
46 | IPSET_DUMP_LAST_FLAG = 7, | |
47 | IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), | |
48 | }; | |
49 | ||
075e64c0 JK |
50 | /* Set extensions */ |
51 | enum ip_set_extension { | |
52 | IPSET_EXT_NONE = 0, | |
53 | IPSET_EXT_BIT_TIMEOUT = 1, | |
54 | IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT), | |
34d666d4 JK |
55 | IPSET_EXT_BIT_COUNTER = 2, |
56 | IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), | |
075e64c0 JK |
57 | }; |
58 | ||
59 | /* Extension offsets */ | |
60 | enum ip_set_offset { | |
61 | IPSET_OFFSET_TIMEOUT = 0, | |
34d666d4 | 62 | IPSET_OFFSET_COUNTER, |
075e64c0 JK |
63 | IPSET_OFFSET_MAX, |
64 | }; | |
65 | ||
66 | #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) | |
34d666d4 | 67 | #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) |
075e64c0 JK |
68 | |
69 | struct ip_set_ext { | |
70 | unsigned long timeout; | |
34d666d4 JK |
71 | u64 packets; |
72 | u64 bytes; | |
075e64c0 JK |
73 | }; |
74 | ||
a7b4f989 JK |
75 | struct ip_set; |
76 | ||
5416219e | 77 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, |
075e64c0 | 78 | const struct ip_set_ext *ext, |
6e01781d | 79 | struct ip_set_ext *mext, u32 cmdflags); |
a7b4f989 | 80 | |
ac8cc925 JK |
81 | /* Kernel API function options */ |
82 | struct ip_set_adt_opt { | |
83 | u8 family; /* Actual protocol family */ | |
84 | u8 dim; /* Dimension of match/target */ | |
85 | u8 flags; /* Direction and negation flags */ | |
86 | u32 cmdflags; /* Command-like flags */ | |
075e64c0 | 87 | struct ip_set_ext ext; /* Extensions */ |
ac8cc925 JK |
88 | }; |
89 | ||
a7b4f989 JK |
90 | /* Set type, variant-specific part */ |
91 | struct ip_set_type_variant { | |
92 | /* Kernelspace: test/add/del entries | |
93 | * returns negative error code, | |
94 | * zero for no match/success to add/delete | |
95 | * positive for matching element */ | |
3ace95c0 | 96 | int (*kadt)(struct ip_set *set, const struct sk_buff *skb, |
b66554cf | 97 | const struct xt_action_param *par, |
075e64c0 | 98 | enum ipset_adt adt, struct ip_set_adt_opt *opt); |
a7b4f989 JK |
99 | |
100 | /* Userspace: test/add/del entries | |
101 | * returns negative error code, | |
102 | * zero for no match/success to add/delete | |
103 | * positive for matching element */ | |
104 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], | |
3d14b171 | 105 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); |
a7b4f989 JK |
106 | |
107 | /* Low level add/del/test functions */ | |
108 | ipset_adtfn adt[IPSET_ADT_MAX]; | |
109 | ||
110 | /* When adding entries and set is full, try to resize the set */ | |
111 | int (*resize)(struct ip_set *set, bool retried); | |
112 | /* Destroy the set */ | |
113 | void (*destroy)(struct ip_set *set); | |
114 | /* Flush the elements */ | |
115 | void (*flush)(struct ip_set *set); | |
116 | /* Expire entries before listing */ | |
117 | void (*expire)(struct ip_set *set); | |
118 | /* List set header data */ | |
119 | int (*head)(struct ip_set *set, struct sk_buff *skb); | |
120 | /* List elements */ | |
121 | int (*list)(const struct ip_set *set, struct sk_buff *skb, | |
122 | struct netlink_callback *cb); | |
123 | ||
124 | /* Return true if "b" set is the same as "a" | |
125 | * according to the create set parameters */ | |
126 | bool (*same_set)(const struct ip_set *a, const struct ip_set *b); | |
127 | }; | |
128 | ||
129 | /* The core set type structure */ | |
130 | struct ip_set_type { | |
131 | struct list_head list; | |
132 | ||
133 | /* Typename */ | |
134 | char name[IPSET_MAXNAMELEN]; | |
135 | /* Protocol version */ | |
136 | u8 protocol; | |
137 | /* Set features to control swapping */ | |
138 | u8 features; | |
139 | /* Set type dimension */ | |
140 | u8 dimension; | |
c15f1c83 JE |
141 | /* |
142 | * Supported family: may be NFPROTO_UNSPEC for both | |
143 | * NFPROTO_IPV4/NFPROTO_IPV6. | |
144 | */ | |
a7b4f989 | 145 | u8 family; |
f1e00b39 JK |
146 | /* Type revisions */ |
147 | u8 revision_min, revision_max; | |
a7b4f989 JK |
148 | |
149 | /* Create set */ | |
150 | int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); | |
151 | ||
152 | /* Attribute policies */ | |
153 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; | |
154 | const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1]; | |
155 | ||
156 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ | |
157 | struct module *me; | |
158 | }; | |
159 | ||
160 | /* register and unregister set type */ | |
161 | extern int ip_set_type_register(struct ip_set_type *set_type); | |
162 | extern void ip_set_type_unregister(struct ip_set_type *set_type); | |
163 | ||
164 | /* A generic IP set */ | |
165 | struct ip_set { | |
166 | /* The name of the set */ | |
167 | char name[IPSET_MAXNAMELEN]; | |
168 | /* Lock protecting the set data */ | |
169 | rwlock_t lock; | |
170 | /* References to the set */ | |
2f9f28b2 | 171 | u32 ref; |
a7b4f989 JK |
172 | /* The core set type */ |
173 | struct ip_set_type *type; | |
174 | /* The type variant doing the real job */ | |
175 | const struct ip_set_type_variant *variant; | |
176 | /* The actual INET family of the set */ | |
177 | u8 family; | |
f1e00b39 JK |
178 | /* The type revision */ |
179 | u8 revision; | |
075e64c0 JK |
180 | /* Extensions */ |
181 | u8 extensions; | |
a7b4f989 JK |
182 | /* The type specific data */ |
183 | void *data; | |
184 | }; | |
185 | ||
34d666d4 JK |
186 | struct ip_set_counter { |
187 | atomic64_t bytes; | |
188 | atomic64_t packets; | |
189 | }; | |
190 | ||
191 | static inline void | |
192 | ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter) | |
193 | { | |
194 | atomic64_add((long long)bytes, &(counter)->bytes); | |
195 | } | |
196 | ||
197 | static inline void | |
198 | ip_set_add_packets(u64 packets, struct ip_set_counter *counter) | |
199 | { | |
200 | atomic64_add((long long)packets, &(counter)->packets); | |
201 | } | |
202 | ||
203 | static inline u64 | |
204 | ip_set_get_bytes(const struct ip_set_counter *counter) | |
205 | { | |
206 | return (u64)atomic64_read(&(counter)->bytes); | |
207 | } | |
208 | ||
209 | static inline u64 | |
210 | ip_set_get_packets(const struct ip_set_counter *counter) | |
211 | { | |
212 | return (u64)atomic64_read(&(counter)->packets); | |
213 | } | |
214 | ||
215 | static inline void | |
216 | ip_set_update_counter(struct ip_set_counter *counter, | |
217 | const struct ip_set_ext *ext, | |
218 | struct ip_set_ext *mext, u32 flags) | |
219 | { | |
6e01781d JK |
220 | if (ext->packets != ULLONG_MAX && |
221 | !(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) { | |
34d666d4 JK |
222 | ip_set_add_bytes(ext->bytes, counter); |
223 | ip_set_add_packets(ext->packets, counter); | |
224 | } | |
6e01781d JK |
225 | if (flags & IPSET_FLAG_MATCH_COUNTERS) { |
226 | mext->packets = ip_set_get_packets(counter); | |
227 | mext->bytes = ip_set_get_bytes(counter); | |
228 | } | |
34d666d4 JK |
229 | } |
230 | ||
231 | static inline bool | |
232 | ip_set_put_counter(struct sk_buff *skb, struct ip_set_counter *counter) | |
233 | { | |
234 | return nla_put_net64(skb, IPSET_ATTR_BYTES, | |
235 | cpu_to_be64(ip_set_get_bytes(counter))) || | |
236 | nla_put_net64(skb, IPSET_ATTR_PACKETS, | |
237 | cpu_to_be64(ip_set_get_packets(counter))); | |
238 | } | |
239 | ||
240 | static inline void | |
241 | ip_set_init_counter(struct ip_set_counter *counter, | |
242 | const struct ip_set_ext *ext) | |
243 | { | |
244 | if (ext->bytes != ULLONG_MAX) | |
245 | atomic64_set(&(counter)->bytes, (long long)(ext->bytes)); | |
246 | if (ext->packets != ULLONG_MAX) | |
247 | atomic64_set(&(counter)->packets, (long long)(ext->packets)); | |
248 | } | |
249 | ||
a7b4f989 JK |
250 | /* register and unregister set references */ |
251 | extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); | |
252 | extern void ip_set_put_byindex(ip_set_id_t index); | |
15b4d93f | 253 | extern const char *ip_set_name_byindex(ip_set_id_t index); |
a7b4f989 JK |
254 | extern ip_set_id_t ip_set_nfnl_get(const char *name); |
255 | extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); | |
256 | extern void ip_set_nfnl_put(ip_set_id_t index); | |
257 | ||
258 | /* API for iptables set match, and SET target */ | |
ac8cc925 | 259 | |
a7b4f989 | 260 | extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, |
b66554cf | 261 | const struct xt_action_param *par, |
075e64c0 | 262 | struct ip_set_adt_opt *opt); |
a7b4f989 | 263 | extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, |
b66554cf | 264 | const struct xt_action_param *par, |
075e64c0 | 265 | struct ip_set_adt_opt *opt); |
a7b4f989 | 266 | extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, |
b66554cf | 267 | const struct xt_action_param *par, |
075e64c0 | 268 | struct ip_set_adt_opt *opt); |
a7b4f989 JK |
269 | |
270 | /* Utility functions */ | |
15b4d93f | 271 | extern void *ip_set_alloc(size_t size); |
a7b4f989 JK |
272 | extern void ip_set_free(void *members); |
273 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); | |
274 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); | |
075e64c0 JK |
275 | extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], |
276 | struct ip_set_ext *ext); | |
a7b4f989 JK |
277 | |
278 | static inline int | |
279 | ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) | |
280 | { | |
281 | __be32 ip; | |
282 | int ret = ip_set_get_ipaddr4(nla, &ip); | |
15b4d93f | 283 | |
a7b4f989 JK |
284 | if (ret) |
285 | return ret; | |
286 | *ipaddr = ntohl(ip); | |
287 | return 0; | |
288 | } | |
289 | ||
290 | /* Ignore IPSET_ERR_EXIST errors if asked to do so? */ | |
291 | static inline bool | |
292 | ip_set_eexist(int ret, u32 flags) | |
293 | { | |
294 | return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); | |
295 | } | |
296 | ||
43c56e59 JK |
297 | /* Match elements marked with nomatch */ |
298 | static inline bool | |
0f1799ba | 299 | ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt, struct ip_set *set) |
43c56e59 JK |
300 | { |
301 | return adt == IPSET_TEST && | |
0f1799ba JK |
302 | (set->type->features & IPSET_TYPE_NOMATCH) && |
303 | ((flags >> 16) & IPSET_FLAG_NOMATCH) && | |
304 | (ret > 0 || ret == -ENOTEMPTY); | |
43c56e59 JK |
305 | } |
306 | ||
a7b4f989 JK |
307 | /* Check the NLA_F_NET_BYTEORDER flag */ |
308 | static inline bool | |
309 | ip_set_attr_netorder(struct nlattr *tb[], int type) | |
310 | { | |
311 | return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER); | |
312 | } | |
313 | ||
314 | static inline bool | |
315 | ip_set_optattr_netorder(struct nlattr *tb[], int type) | |
316 | { | |
317 | return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER); | |
318 | } | |
319 | ||
320 | /* Useful converters */ | |
321 | static inline u32 | |
322 | ip_set_get_h32(const struct nlattr *attr) | |
323 | { | |
324 | return ntohl(nla_get_be32(attr)); | |
325 | } | |
326 | ||
327 | static inline u16 | |
328 | ip_set_get_h16(const struct nlattr *attr) | |
329 | { | |
330 | return ntohs(nla_get_be16(attr)); | |
331 | } | |
332 | ||
333 | #define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED) | |
334 | #define ipset_nest_end(skb, start) nla_nest_end(skb, start) | |
335 | ||
7cf7899d DM |
336 | static inline int nla_put_ipaddr4(struct sk_buff *skb, int type, __be32 ipaddr) |
337 | { | |
338 | struct nlattr *__nested = ipset_nest_start(skb, type); | |
339 | int ret; | |
340 | ||
341 | if (!__nested) | |
342 | return -EMSGSIZE; | |
343 | ret = nla_put_net32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); | |
344 | if (!ret) | |
345 | ipset_nest_end(skb, __nested); | |
346 | return ret; | |
347 | } | |
348 | ||
3ace95c0 JK |
349 | static inline int nla_put_ipaddr6(struct sk_buff *skb, int type, |
350 | const struct in6_addr *ipaddrptr) | |
7cf7899d DM |
351 | { |
352 | struct nlattr *__nested = ipset_nest_start(skb, type); | |
353 | int ret; | |
354 | ||
355 | if (!__nested) | |
356 | return -EMSGSIZE; | |
357 | ret = nla_put(skb, IPSET_ATTR_IPADDR_IPV6, | |
358 | sizeof(struct in6_addr), ipaddrptr); | |
359 | if (!ret) | |
360 | ipset_nest_end(skb, __nested); | |
361 | return ret; | |
362 | } | |
a7b4f989 JK |
363 | |
364 | /* Get address from skbuff */ | |
365 | static inline __be32 | |
366 | ip4addr(const struct sk_buff *skb, bool src) | |
367 | { | |
368 | return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; | |
369 | } | |
370 | ||
371 | static inline void | |
372 | ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr) | |
373 | { | |
374 | *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; | |
375 | } | |
376 | ||
377 | static inline void | |
378 | ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) | |
379 | { | |
380 | memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, | |
381 | sizeof(*addr)); | |
382 | } | |
383 | ||
384 | /* Calculate the bytes required to store the inclusive range of a-b */ | |
385 | static inline int | |
386 | bitmap_bytes(u32 a, u32 b) | |
387 | { | |
388 | return 4 * ((((b - a + 8) / 8) + 3) / 4); | |
389 | } | |
390 | ||
075e64c0 JK |
391 | #include <linux/netfilter/ipset/ip_set_timeout.h> |
392 | ||
34d666d4 JK |
393 | #define IP_SET_INIT_KEXT(skb, opt, map) \ |
394 | { .bytes = (skb)->len, .packets = 1, \ | |
395 | .timeout = ip_set_adt_opt_timeout(opt, map) } | |
075e64c0 | 396 | |
34d666d4 JK |
397 | #define IP_SET_INIT_UEXT(map) \ |
398 | { .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \ | |
399 | .timeout = (map)->timeout } | |
075e64c0 | 400 | |
a7b4f989 | 401 | #endif /*_IP_SET_H */ |