aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>2013-09-22 14:56:30 -0400
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2013-09-30 15:33:28 -0400
commit68b63f08d22f23161c43cd2417104aa213ff877f (patch)
tree33271d9a7e9670cbc4506901c21ff87154f6bf3a
parentea53ac5b630e813aec20c7cdcfe511daca70dee4 (diff)
netfilter: ipset: Support comments for ipset entries in the core.
This adds the core support for having comments on ipset entries. The comments are stored as standard null-terminated strings in dynamically allocated memory after being passed to the kernel. As a result of this, code has been added to the generic destroy function to iterate all extensions and call that extension's destroy task if the set has that extension activated, and if such a task is defined. Signed-off-by: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa> Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r--include/linux/netfilter/ipset/ip_set.h51
-rw-r--r--include/linux/netfilter/ipset/ip_set_comment.h57
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set.h8
-rw-r--r--net/netfilter/ipset/ip_set_core.c14
4 files changed, 121 insertions, 9 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index 6372ee224fe8..407f84df6a47 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -53,6 +53,8 @@ enum ip_set_extension {
53 IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT), 53 IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT),
54 IPSET_EXT_BIT_COUNTER = 1, 54 IPSET_EXT_BIT_COUNTER = 1,
55 IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), 55 IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER),
56 IPSET_EXT_BIT_COMMENT = 2,
57 IPSET_EXT_COMMENT = (1 << IPSET_EXT_BIT_COMMENT),
56 /* Mark set with an extension which needs to call destroy */ 58 /* Mark set with an extension which needs to call destroy */
57 IPSET_EXT_BIT_DESTROY = 7, 59 IPSET_EXT_BIT_DESTROY = 7,
58 IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY), 60 IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY),
@@ -60,11 +62,13 @@ enum ip_set_extension {
60 62
61#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) 63#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT)
62#define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) 64#define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER)
65#define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT)
63 66
64/* Extension id, in size order */ 67/* Extension id, in size order */
65enum ip_set_ext_id { 68enum ip_set_ext_id {
66 IPSET_EXT_ID_COUNTER = 0, 69 IPSET_EXT_ID_COUNTER = 0,
67 IPSET_EXT_ID_TIMEOUT, 70 IPSET_EXT_ID_TIMEOUT,
71 IPSET_EXT_ID_COMMENT,
68 IPSET_EXT_ID_MAX, 72 IPSET_EXT_ID_MAX,
69}; 73};
70 74
@@ -85,6 +89,7 @@ struct ip_set_ext {
85 u64 packets; 89 u64 packets;
86 u64 bytes; 90 u64 bytes;
87 u32 timeout; 91 u32 timeout;
92 char *comment;
88}; 93};
89 94
90struct ip_set_counter { 95struct ip_set_counter {
@@ -92,20 +97,19 @@ struct ip_set_counter {
92 atomic64_t packets; 97 atomic64_t packets;
93}; 98};
94 99
95struct ip_set; 100struct ip_set_comment {
101 char *str;
102};
96 103
97static inline void 104struct ip_set;
98ip_set_ext_destroy(struct ip_set *set, void *data)
99{
100 /* Check that the extension is enabled for the set and
101 * call it's destroy function for its extension part in data.
102 */
103}
104 105
105#define ext_timeout(e, s) \ 106#define ext_timeout(e, s) \
106(unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT]) 107(unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT])
107#define ext_counter(e, s) \ 108#define ext_counter(e, s) \
108(struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER]) 109(struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER])
110#define ext_comment(e, s) \
111(struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT])
112
109 113
110typedef int (*ipset_adtfn)(struct ip_set *set, void *value, 114typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
111 const struct ip_set_ext *ext, 115 const struct ip_set_ext *ext,
@@ -223,6 +227,36 @@ struct ip_set {
223}; 227};
224 228
225static inline void 229static inline void
230ip_set_ext_destroy(struct ip_set *set, void *data)
231{
232 /* Check that the extension is enabled for the set and
233 * call it's destroy function for its extension part in data.
234 */
235 if (SET_WITH_COMMENT(set))
236 ip_set_extensions[IPSET_EXT_ID_COMMENT].destroy(
237 ext_comment(data, set));
238}
239
240static inline int
241ip_set_put_flags(struct sk_buff *skb, struct ip_set *set)
242{
243 u32 cadt_flags = 0;
244
245 if (SET_WITH_TIMEOUT(set))
246 if (unlikely(nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
247 htonl(set->timeout))))
248 return -EMSGSIZE;
249 if (SET_WITH_COUNTER(set))
250 cadt_flags |= IPSET_FLAG_WITH_COUNTERS;
251 if (SET_WITH_COMMENT(set))
252 cadt_flags |= IPSET_FLAG_WITH_COMMENT;
253
254 if (!cadt_flags)
255 return 0;
256 return nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(cadt_flags));
257}
258
259static inline void
226ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter) 260ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter)
227{ 261{
228 atomic64_add((long long)bytes, &(counter)->bytes); 262 atomic64_add((long long)bytes, &(counter)->bytes);
@@ -425,6 +459,7 @@ bitmap_bytes(u32 a, u32 b)
425} 459}
426 460
427#include <linux/netfilter/ipset/ip_set_timeout.h> 461#include <linux/netfilter/ipset/ip_set_timeout.h>
462#include <linux/netfilter/ipset/ip_set_comment.h>
428 463
429#define IP_SET_INIT_KEXT(skb, opt, set) \ 464#define IP_SET_INIT_KEXT(skb, opt, set) \
430 { .bytes = (skb)->len, .packets = 1, \ 465 { .bytes = (skb)->len, .packets = 1, \
diff --git a/include/linux/netfilter/ipset/ip_set_comment.h b/include/linux/netfilter/ipset/ip_set_comment.h
new file mode 100644
index 000000000000..21217ea008d7
--- /dev/null
+++ b/include/linux/netfilter/ipset/ip_set_comment.h
@@ -0,0 +1,57 @@
1#ifndef _IP_SET_COMMENT_H
2#define _IP_SET_COMMENT_H
3
4/* Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
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 */
10
11#ifdef __KERNEL__
12
13static inline char*
14ip_set_comment_uget(struct nlattr *tb)
15{
16 return nla_data(tb);
17}
18
19static inline void
20ip_set_init_comment(struct ip_set_comment *comment,
21 const struct ip_set_ext *ext)
22{
23 size_t len = ext->comment ? strlen(ext->comment) : 0;
24
25 if (unlikely(comment->str)) {
26 kfree(comment->str);
27 comment->str = NULL;
28 }
29 if (!len)
30 return;
31 if (unlikely(len > IPSET_MAX_COMMENT_SIZE))
32 len = IPSET_MAX_COMMENT_SIZE;
33 comment->str = kzalloc(len + 1, GFP_ATOMIC);
34 if (unlikely(!comment->str))
35 return;
36 strlcpy(comment->str, ext->comment, len + 1);
37}
38
39static inline int
40ip_set_put_comment(struct sk_buff *skb, struct ip_set_comment *comment)
41{
42 if (!comment->str)
43 return 0;
44 return nla_put_string(skb, IPSET_ATTR_COMMENT, comment->str);
45}
46
47static inline void
48ip_set_comment_free(struct ip_set_comment *comment)
49{
50 if (unlikely(!comment->str))
51 return;
52 kfree(comment->str);
53 comment->str = NULL;
54}
55
56#endif
57#endif
diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h
index 2b61ac44dcc1..25d3b2f79c02 100644
--- a/include/uapi/linux/netfilter/ipset/ip_set.h
+++ b/include/uapi/linux/netfilter/ipset/ip_set.h
@@ -10,12 +10,14 @@
10#ifndef _UAPI_IP_SET_H 10#ifndef _UAPI_IP_SET_H
11#define _UAPI_IP_SET_H 11#define _UAPI_IP_SET_H
12 12
13
14#include <linux/types.h> 13#include <linux/types.h>
15 14
16/* The protocol version */ 15/* The protocol version */
17#define IPSET_PROTOCOL 6 16#define IPSET_PROTOCOL 6
18 17
18/* The maximum permissible comment length we will accept over netlink */
19#define IPSET_MAX_COMMENT_SIZE 255
20
19/* The max length of strings including NUL: set and type identifiers */ 21/* The max length of strings including NUL: set and type identifiers */
20#define IPSET_MAXNAMELEN 32 22#define IPSET_MAXNAMELEN 32
21 23
@@ -110,6 +112,7 @@ enum {
110 IPSET_ATTR_IFACE, 112 IPSET_ATTR_IFACE,
111 IPSET_ATTR_BYTES, 113 IPSET_ATTR_BYTES,
112 IPSET_ATTR_PACKETS, 114 IPSET_ATTR_PACKETS,
115 IPSET_ATTR_COMMENT,
113 __IPSET_ATTR_ADT_MAX, 116 __IPSET_ATTR_ADT_MAX,
114}; 117};
115#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) 118#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -140,6 +143,7 @@ enum ipset_errno {
140 IPSET_ERR_IPADDR_IPV4, 143 IPSET_ERR_IPADDR_IPV4,
141 IPSET_ERR_IPADDR_IPV6, 144 IPSET_ERR_IPADDR_IPV6,
142 IPSET_ERR_COUNTER, 145 IPSET_ERR_COUNTER,
146 IPSET_ERR_COMMENT,
143 147
144 /* Type specific error codes */ 148 /* Type specific error codes */
145 IPSET_ERR_TYPE_SPECIFIC = 4352, 149 IPSET_ERR_TYPE_SPECIFIC = 4352,
@@ -176,6 +180,8 @@ enum ipset_cadt_flags {
176 IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH), 180 IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
177 IPSET_FLAG_BIT_WITH_COUNTERS = 3, 181 IPSET_FLAG_BIT_WITH_COUNTERS = 3,
178 IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS), 182 IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
183 IPSET_FLAG_BIT_WITH_COMMENT = 4,
184 IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT),
179 IPSET_FLAG_CADT_MAX = 15, 185 IPSET_FLAG_CADT_MAX = 15,
180}; 186};
181 187
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index f35afed3814f..3bf9a3d29dff 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -315,6 +315,7 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
315} 315}
316EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); 316EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
317 317
318typedef void (*destroyer)(void *);
318/* ipset data extension types, in size order */ 319/* ipset data extension types, in size order */
319 320
320const struct ip_set_ext_type ip_set_extensions[] = { 321const struct ip_set_ext_type ip_set_extensions[] = {
@@ -329,6 +330,13 @@ const struct ip_set_ext_type ip_set_extensions[] = {
329 .len = sizeof(unsigned long), 330 .len = sizeof(unsigned long),
330 .align = __alignof__(unsigned long), 331 .align = __alignof__(unsigned long),
331 }, 332 },
333 [IPSET_EXT_ID_COMMENT] = {
334 .type = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY,
335 .flag = IPSET_FLAG_WITH_COMMENT,
336 .len = sizeof(struct ip_set_comment),
337 .align = __alignof__(struct ip_set_comment),
338 .destroy = (destroyer) ip_set_comment_free,
339 },
332}; 340};
333EXPORT_SYMBOL_GPL(ip_set_extensions); 341EXPORT_SYMBOL_GPL(ip_set_extensions);
334 342
@@ -380,6 +388,12 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
380 ext->packets = be64_to_cpu(nla_get_be64( 388 ext->packets = be64_to_cpu(nla_get_be64(
381 tb[IPSET_ATTR_PACKETS])); 389 tb[IPSET_ATTR_PACKETS]));
382 } 390 }
391 if (tb[IPSET_ATTR_COMMENT]) {
392 if (!(set->extensions & IPSET_EXT_COMMENT))
393 return -IPSET_ERR_COMMENT;
394 ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]);
395 }
396
383 return 0; 397 return 0;
384} 398}
385EXPORT_SYMBOL_GPL(ip_set_get_extensions); 399EXPORT_SYMBOL_GPL(ip_set_get_extensions);