aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJP Abgrall2011-07-12 14:02:59 -0500
committerArve Hjønnevåg2013-02-19 19:53:34 -0600
commit955caa36b865ded4754a7107ee2d627e38472fb2 (patch)
tree9f637458ebe3f384e5d908e6c357a9c5d181d356 /net
parentf6cd614292d5e6f2c4b7b3747c25b189955de778 (diff)
downloadkernel-common-955caa36b865ded4754a7107ee2d627e38472fb2.tar.gz
kernel-common-955caa36b865ded4754a7107ee2d627e38472fb2.tar.xz
kernel-common-955caa36b865ded4754a7107ee2d627e38472fb2.zip
netfilter: fixup the quota2, and enable.
The xt_quota2 came from http://sourceforge.net/projects/xtables-addons/develop It needed tweaking for it to compile within the kernel tree. Fixed kmalloc() and create_proc_entry() invocations within a non-interruptible context. Removed useless copying of current quota back to the iptable's struct matchinfo: - those are per CPU: they will change randomly based on which cpu gets to update the value. - they prevent matching a rule: e.g. -A chain -m quota2 --name q1 --quota 123 can't be followed by -D chain -m quota2 --name q1 --quota 123 as the 123 will be compared to the struct matchinfo's quota member. Use the NETLINK NETLINK_NFLOG family to log a single message when the quota limit is reached. It uses the same packet type as ipt_ULOG, but - never copies skb data, - uses 112 as the event number (ULOG's +1) It doesn't log if the module param "event_num" is 0. Change-Id: I021d3b743db3b22158cc49acb5c94d905b501492 Signed-off-by: JP Abgrall <jpa@google.com>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/Kconfig24
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/xt_quota2.c154
3 files changed, 156 insertions, 23 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index a3da13036d1..bf5c7c9efb8 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -1128,6 +1128,30 @@ config NETFILTER_XT_MATCH_QUOTA
1128 If you want to compile it as a module, say M here and read 1128 If you want to compile it as a module, say M here and read
1129 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. 1129 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
1130 1130
1131config NETFILTER_XT_MATCH_QUOTA2
1132 tristate '"quota2" match support'
1133 depends on NETFILTER_ADVANCED
1134 help
1135 This option adds a `quota2' match, which allows to match on a
1136 byte counter correctly and not per CPU.
1137 It allows naming the quotas.
1138 This is based on http://xtables-addons.git.sourceforge.net
1139
1140 If you want to compile it as a module, say M here and read
1141 <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
1142
1143config NETFILTER_XT_MATCH_QUOTA2_LOG
1144 bool '"quota2" Netfilter LOG support'
1145 depends on NETFILTER_XT_MATCH_QUOTA2
1146 depends on IP_NF_TARGET_ULOG=n # not yes, not module, just no
1147 default n
1148 help
1149 This option allows `quota2' to log ONCE when a quota limit
1150 is passed. It logs via NETLINK using the NETLINK_NFLOG family.
1151 It logs similarly to how ipt_ULOG would without data.
1152
1153 If unsure, say `N'.
1154
1131config NETFILTER_XT_MATCH_RATEEST 1155config NETFILTER_XT_MATCH_RATEEST
1132 tristate '"rateest" match support' 1156 tristate '"rateest" match support'
1133 depends on NETFILTER_ADVANCED 1157 depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 71ed5f82093..115b4fe9044 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -126,6 +126,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
126obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o 126obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
127obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid_print.o xt_qtaguid.o 127obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid_print.o xt_qtaguid.o
128obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o 128obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
129obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA2) += xt_quota2.o
129obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o 130obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o
130obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o 131obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
131obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o 132obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o
diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c
index 4857008f1eb..aace7292853 100644
--- a/net/netfilter/xt_quota2.c
+++ b/net/netfilter/xt_quota2.c
@@ -12,14 +12,18 @@
12 * version 2 of the License, as published by the Free Software Foundation. 12 * version 2 of the License, as published by the Free Software Foundation.
13 */ 13 */
14#include <linux/list.h> 14#include <linux/list.h>
15#include <linux/module.h>
15#include <linux/proc_fs.h> 16#include <linux/proc_fs.h>
16#include <linux/skbuff.h> 17#include <linux/skbuff.h>
17#include <linux/spinlock.h> 18#include <linux/spinlock.h>
18#include <asm/atomic.h> 19#include <asm/atomic.h>
20#include <net/netlink.h>
19 21
20#include <linux/netfilter/x_tables.h> 22#include <linux/netfilter/x_tables.h>
21#include "xt_quota2.h" 23#include <linux/netfilter/xt_quota2.h>
22#include "compat_xtables.h" 24#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
25#include <linux/netfilter_ipv4/ipt_ULOG.h>
26#endif
23 27
24/** 28/**
25 * @lock: lock to protect quota writers from each other 29 * @lock: lock to protect quota writers from each other
@@ -33,6 +37,16 @@ struct xt_quota_counter {
33 struct proc_dir_entry *procfs_entry; 37 struct proc_dir_entry *procfs_entry;
34}; 38};
35 39
40#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
41/* Harald's favorite number +1 :D From ipt_ULOG.C */
42static int qlog_nl_event = 112;
43module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
44MODULE_PARM_DESC(event_num,
45 "Event number for NETLINK_NFLOG message. 0 disables log."
46 "111 is what ipt_ULOG uses.");
47static struct sock *nflognl;
48#endif
49
36static LIST_HEAD(counter_list); 50static LIST_HEAD(counter_list);
37static DEFINE_SPINLOCK(counter_list_lock); 51static DEFINE_SPINLOCK(counter_list_lock);
38 52
@@ -44,6 +58,70 @@ module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
44module_param_named(uid, quota_list_uid, uint, S_IRUGO | S_IWUSR); 58module_param_named(uid, quota_list_uid, uint, S_IRUGO | S_IWUSR);
45module_param_named(gid, quota_list_gid, uint, S_IRUGO | S_IWUSR); 59module_param_named(gid, quota_list_gid, uint, S_IRUGO | S_IWUSR);
46 60
61
62#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
63static void quota2_log(unsigned int hooknum,
64 const struct sk_buff *skb,
65 const struct net_device *in,
66 const struct net_device *out,
67 const char *prefix)
68{
69 ulog_packet_msg_t *pm;
70 struct sk_buff *log_skb;
71 size_t size;
72 struct nlmsghdr *nlh;
73
74 if (!qlog_nl_event)
75 return;
76
77 size = NLMSG_SPACE(sizeof(*pm));
78 size = max(size, (size_t)NLMSG_GOODSIZE);
79 log_skb = alloc_skb(size, GFP_ATOMIC);
80 if (!log_skb) {
81 pr_err("xt_quota2: cannot alloc skb for logging\n");
82 return;
83 }
84
85 nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
86 sizeof(*pm), 0);
87 if (!nlh) {
88 pr_err("xt_quota2: nlmsg_put failed\n");
89 kfree_skb(log_skb);
90 return;
91 }
92 pm = nlmsg_data(nlh);
93 if (skb->tstamp.tv64 == 0)
94 __net_timestamp((struct sk_buff *)skb);
95 pm->data_len = 0;
96 pm->hook = hooknum;
97 if (prefix != NULL)
98 strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
99 else
100 *(pm->prefix) = '\0';
101 if (in)
102 strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
103 else
104 pm->indev_name[0] = '\0';
105
106 if (out)
107 strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
108 else
109 pm->outdev_name[0] = '\0';
110
111 NETLINK_CB(log_skb).dst_group = 1;
112 pr_debug("throwing 1 packets to netlink group 1\n");
113 netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
114}
115#else
116static void quota2_log(unsigned int hooknum,
117 const struct sk_buff *skb,
118 const struct net_device *in,
119 const struct net_device *out,
120 const char *prefix)
121{
122}
123#endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
124
47static int quota_proc_read(char *page, char **start, off_t offset, 125static int quota_proc_read(char *page, char **start, off_t offset,
48 int count, int *eof, void *data) 126 int count, int *eof, void *data)
49{ 127{
@@ -91,7 +169,7 @@ q2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon)
91 if (!anon) { 169 if (!anon) {
92 INIT_LIST_HEAD(&e->list); 170 INIT_LIST_HEAD(&e->list);
93 atomic_set(&e->ref, 1); 171 atomic_set(&e->ref, 1);
94 strncpy(e->name, q->name, sizeof(e->name)); 172 strlcpy(e->name, q->name, sizeof(e->name));
95 } 173 }
96 return e; 174 return e;
97} 175}
@@ -104,42 +182,56 @@ static struct xt_quota_counter *
104q2_get_counter(const struct xt_quota_mtinfo2 *q) 182q2_get_counter(const struct xt_quota_mtinfo2 *q)
105{ 183{
106 struct proc_dir_entry *p; 184 struct proc_dir_entry *p;
107 struct xt_quota_counter *e; 185 struct xt_quota_counter *e = NULL;
186 struct xt_quota_counter *new_e;
108 187
109 if (*q->name == '\0') 188 if (*q->name == '\0')
110 return q2_new_counter(q, true); 189 return q2_new_counter(q, true);
111 190
191 /* No need to hold a lock while getting a new counter */
192 new_e = q2_new_counter(q, false);
193 if (new_e == NULL)
194 goto out;
195
112 spin_lock_bh(&counter_list_lock); 196 spin_lock_bh(&counter_list_lock);
113 list_for_each_entry(e, &counter_list, list) 197 list_for_each_entry(e, &counter_list, list)
114 if (strcmp(e->name, q->name) == 0) { 198 if (strcmp(e->name, q->name) == 0) {
115 atomic_inc(&e->ref); 199 atomic_inc(&e->ref);
116 spin_unlock_bh(&counter_list_lock); 200 spin_unlock_bh(&counter_list_lock);
201 kfree(new_e);
202 pr_debug("xt_quota2: old counter name=%s", e->name);
117 return e; 203 return e;
118 } 204 }
205 e = new_e;
206 pr_debug("xt_quota2: new_counter name=%s", e->name);
207 list_add_tail(&e->list, &counter_list);
208 /* The entry having a refcount of 1 is not directly destructible.
209 * This func has not yet returned the new entry, thus iptables
210 * has not references for destroying this entry.
211 * For another rule to try to destroy it, it would 1st need for this
212 * func* to be re-invoked, acquire a new ref for the same named quota.
213 * Nobody will access the e->procfs_entry either.
214 * So release the lock. */
215 spin_unlock_bh(&counter_list_lock);
119 216
120 e = q2_new_counter(q, false); 217 /* create_proc_entry() is not spin_lock happy */
121 if (e == NULL)
122 goto out;
123
124 p = e->procfs_entry = create_proc_entry(e->name, quota_list_perms, 218 p = e->procfs_entry = create_proc_entry(e->name, quota_list_perms,
125 proc_xt_quota); 219 proc_xt_quota);
126 if (p == NULL || IS_ERR(p))
127 goto out;
128 220
129#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29) 221 if (IS_ERR_OR_NULL(p)) {
130 p->owner = THIS_MODULE; 222 spin_lock_bh(&counter_list_lock);
131#endif 223 list_del(&e->list);
224 spin_unlock_bh(&counter_list_lock);
225 goto out;
226 }
132 p->data = e; 227 p->data = e;
133 p->read_proc = quota_proc_read; 228 p->read_proc = quota_proc_read;
134 p->write_proc = quota_proc_write; 229 p->write_proc = quota_proc_write;
135 p->uid = quota_list_uid; 230 p->uid = quota_list_uid;
136 p->gid = quota_list_gid; 231 p->gid = quota_list_gid;
137 list_add_tail(&e->list, &counter_list);
138 spin_unlock_bh(&counter_list_lock);
139 return e; 232 return e;
140 233
141 out: 234 out:
142 spin_unlock_bh(&counter_list_lock);
143 kfree(e); 235 kfree(e);
144 return NULL; 236 return NULL;
145} 237}
@@ -148,6 +240,8 @@ static int quota_mt2_check(const struct xt_mtchk_param *par)
148{ 240{
149 struct xt_quota_mtinfo2 *q = par->matchinfo; 241 struct xt_quota_mtinfo2 *q = par->matchinfo;
150 242
243 pr_debug("xt_quota2: check() flags=0x%04x", q->flags);
244
151 if (q->flags & ~XT_QUOTA_MASK) 245 if (q->flags & ~XT_QUOTA_MASK)
152 return -EINVAL; 246 return -EINVAL;
153 247
@@ -203,7 +297,6 @@ quota_mt2(const struct sk_buff *skb, struct xt_action_param *par)
203 */ 297 */
204 if (!(q->flags & XT_QUOTA_NO_CHANGE)) { 298 if (!(q->flags & XT_QUOTA_NO_CHANGE)) {
205 e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len; 299 e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
206 q->quota = e->quota;
207 } 300 }
208 ret = true; 301 ret = true;
209 } else { 302 } else {
@@ -212,10 +305,17 @@ quota_mt2(const struct sk_buff *skb, struct xt_action_param *par)
212 e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len; 305 e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
213 ret = !ret; 306 ret = !ret;
214 } else { 307 } else {
308 /* We are transitioning, log that fact. */
309 if (e->quota) {
310 quota2_log(par->hooknum,
311 skb,
312 par->in,
313 par->out,
314 q->name);
315 }
215 /* we do not allow even small packets from now on */ 316 /* we do not allow even small packets from now on */
216 e->quota = 0; 317 e->quota = 0;
217 } 318 }
218 q->quota = e->quota;
219 } 319 }
220 spin_unlock_bh(&e->lock); 320 spin_unlock_bh(&e->lock);
221 return ret; 321 return ret;
@@ -228,7 +328,7 @@ static struct xt_match quota_mt2_reg[] __read_mostly = {
228 .family = NFPROTO_IPV4, 328 .family = NFPROTO_IPV4,
229 .checkentry = quota_mt2_check, 329 .checkentry = quota_mt2_check,
230 .match = quota_mt2, 330 .match = quota_mt2,
231 .destroy = quota_mt2_destroy, 331 .destroy = quota_mt2_destroy,
232 .matchsize = sizeof(struct xt_quota_mtinfo2), 332 .matchsize = sizeof(struct xt_quota_mtinfo2),
233 .me = THIS_MODULE, 333 .me = THIS_MODULE,
234 }, 334 },
@@ -238,7 +338,7 @@ static struct xt_match quota_mt2_reg[] __read_mostly = {
238 .family = NFPROTO_IPV6, 338 .family = NFPROTO_IPV6,
239 .checkentry = quota_mt2_check, 339 .checkentry = quota_mt2_check,
240 .match = quota_mt2, 340 .match = quota_mt2,
241 .destroy = quota_mt2_destroy, 341 .destroy = quota_mt2_destroy,
242 .matchsize = sizeof(struct xt_quota_mtinfo2), 342 .matchsize = sizeof(struct xt_quota_mtinfo2),
243 .me = THIS_MODULE, 343 .me = THIS_MODULE,
244 }, 344 },
@@ -247,21 +347,29 @@ static struct xt_match quota_mt2_reg[] __read_mostly = {
247static int __init quota_mt2_init(void) 347static int __init quota_mt2_init(void)
248{ 348{
249 int ret; 349 int ret;
350 pr_debug("xt_quota2: init()");
351
352#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
353 nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
354 if (!nflognl)
355 return -ENOMEM;
356#endif
250 357
251 proc_xt_quota = proc_mkdir("xt_quota", init_net__proc_net); 358 proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
252 if (proc_xt_quota == NULL) 359 if (proc_xt_quota == NULL)
253 return -EACCES; 360 return -EACCES;
254 361
255 ret = xt_register_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg)); 362 ret = xt_register_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
256 if (ret < 0) 363 if (ret < 0)
257 remove_proc_entry("xt_quota", init_net__proc_net); 364 remove_proc_entry("xt_quota", init_net.proc_net);
365 pr_debug("xt_quota2: init() %d", ret);
258 return ret; 366 return ret;
259} 367}
260 368
261static void __exit quota_mt2_exit(void) 369static void __exit quota_mt2_exit(void)
262{ 370{
263 xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg)); 371 xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
264 remove_proc_entry("xt_quota", init_net__proc_net); 372 remove_proc_entry("xt_quota", init_net.proc_net);
265} 373}
266 374
267module_init(quota_mt2_init); 375module_init(quota_mt2_init);