2 * xt_quota2 - enhanced xt_quota that can count upwards and in packets
3 * as a minimal accounting match.
4 * by Jan Engelhardt <jengelh@medozas.de>, 2008
6 * Originally based on xt_quota.c:
7 * netfilter module to enforce network quotas
8 * Sam Johnston <samj@samj.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License; either
12 * version 2 of the License, as published by the Free Software Foundation.
14 #include <linux/list.h>
15 #include <linux/module.h>
16 #include <linux/proc_fs.h>
17 #include <linux/skbuff.h>
18 #include <linux/spinlock.h>
19 #include <asm/atomic.h>
20 #include <net/netlink.h>
22 #include <linux/netfilter/x_tables.h>
23 #include <linux/netfilter/xt_quota2.h>
24 #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
25 #include <linux/netfilter_ipv4/ipt_ULOG.h>
29 * @lock: lock to protect quota writers from each other
31 struct xt_quota_counter
{
34 struct list_head list
;
36 char name
[sizeof(((struct xt_quota_mtinfo2
*)NULL
)->name
)];
37 struct proc_dir_entry
*procfs_entry
;
40 #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
41 /* Harald's favorite number +1 :D From ipt_ULOG.C */
42 static int qlog_nl_event
= 112;
43 module_param_named(event_num
, qlog_nl_event
, uint
, S_IRUGO
| S_IWUSR
);
44 MODULE_PARM_DESC(event_num
,
45 "Event number for NETLINK_NFLOG message. 0 disables log."
46 "111 is what ipt_ULOG uses.");
47 static struct sock
*nflognl
;
50 static LIST_HEAD(counter_list
);
51 static DEFINE_SPINLOCK(counter_list_lock
);
53 static struct proc_dir_entry
*proc_xt_quota
;
54 static unsigned int quota_list_perms
= S_IRUGO
| S_IWUSR
;
55 static unsigned int quota_list_uid
= 0;
56 static unsigned int quota_list_gid
= 0;
57 module_param_named(perms
, quota_list_perms
, uint
, S_IRUGO
| S_IWUSR
);
58 module_param_named(uid
, quota_list_uid
, uint
, S_IRUGO
| S_IWUSR
);
59 module_param_named(gid
, quota_list_gid
, uint
, S_IRUGO
| S_IWUSR
);
62 #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
63 static void quota2_log(unsigned int hooknum
,
64 const struct sk_buff
*skb
,
65 const struct net_device
*in
,
66 const struct net_device
*out
,
69 ulog_packet_msg_t
*pm
;
70 struct sk_buff
*log_skb
;
77 size
= NLMSG_SPACE(sizeof(*pm
));
78 size
= max(size
, (size_t)NLMSG_GOODSIZE
);
79 log_skb
= alloc_skb(size
, GFP_ATOMIC
);
81 pr_err("xt_quota2: cannot alloc skb for logging\n");
85 nlh
= nlmsg_put(log_skb
, /*pid*/0, /*seq*/0, qlog_nl_event
,
88 pr_err("xt_quota2: nlmsg_put failed\n");
93 if (skb
->tstamp
.tv64
== 0)
94 __net_timestamp((struct sk_buff
*)skb
);
98 strlcpy(pm
->prefix
, prefix
, sizeof(pm
->prefix
));
100 *(pm
->prefix
) = '\0';
102 strlcpy(pm
->indev_name
, in
->name
, sizeof(pm
->indev_name
));
104 pm
->indev_name
[0] = '\0';
107 strlcpy(pm
->outdev_name
, out
->name
, sizeof(pm
->outdev_name
));
109 pm
->outdev_name
[0] = '\0';
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
);
116 static void quota2_log(unsigned int hooknum
,
117 const struct sk_buff
*skb
,
118 const struct net_device
*in
,
119 const struct net_device
*out
,
123 #endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
125 static ssize_t
quota_proc_read(struct file
*file
, char __user
*buf
,
126 size_t size
, loff_t
*ppos
)
128 struct xt_quota_counter
*e
= PDE_DATA(file_inode(file
));
132 spin_lock_bh(&e
->lock
);
133 tmp_size
= scnprintf(tmp
, sizeof(tmp
), "%llu\n", e
->quota
);
134 spin_unlock_bh(&e
->lock
);
135 return simple_read_from_buffer(buf
, size
, ppos
, tmp
, tmp_size
);
138 static ssize_t
quota_proc_write(struct file
*file
, const char __user
*input
,
139 size_t size
, loff_t
*ppos
)
141 struct xt_quota_counter
*e
= PDE_DATA(file_inode(file
));
142 char buf
[sizeof("18446744073709551616")];
144 if (size
> sizeof(buf
))
146 if (copy_from_user(buf
, input
, size
) != 0)
148 buf
[sizeof(buf
)-1] = '\0';
150 spin_lock_bh(&e
->lock
);
151 e
->quota
= simple_strtoull(buf
, NULL
, 0);
152 spin_unlock_bh(&e
->lock
);
156 static const struct file_operations q2_counter_fops
= {
157 .read
= quota_proc_read
,
158 .write
= quota_proc_write
,
159 .llseek
= default_llseek
,
162 static struct xt_quota_counter
*
163 q2_new_counter(const struct xt_quota_mtinfo2
*q
, bool anon
)
165 struct xt_quota_counter
*e
;
168 /* Do not need all the procfs things for anonymous counters. */
169 size
= anon
? offsetof(typeof(*e
), list
) : sizeof(*e
);
170 e
= kmalloc(size
, GFP_KERNEL
);
175 spin_lock_init(&e
->lock
);
177 INIT_LIST_HEAD(&e
->list
);
178 atomic_set(&e
->ref
, 1);
179 strlcpy(e
->name
, q
->name
, sizeof(e
->name
));
185 * q2_get_counter - get ref to counter or create new
186 * @name: name of counter
188 static struct xt_quota_counter
*
189 q2_get_counter(const struct xt_quota_mtinfo2
*q
)
191 struct proc_dir_entry
*p
;
192 struct xt_quota_counter
*e
= NULL
;
193 struct xt_quota_counter
*new_e
;
195 if (*q
->name
== '\0')
196 return q2_new_counter(q
, true);
198 /* No need to hold a lock while getting a new counter */
199 new_e
= q2_new_counter(q
, false);
203 spin_lock_bh(&counter_list_lock
);
204 list_for_each_entry(e
, &counter_list
, list
)
205 if (strcmp(e
->name
, q
->name
) == 0) {
207 spin_unlock_bh(&counter_list_lock
);
209 pr_debug("xt_quota2: old counter name=%s", e
->name
);
213 pr_debug("xt_quota2: new_counter name=%s", e
->name
);
214 list_add_tail(&e
->list
, &counter_list
);
215 /* The entry having a refcount of 1 is not directly destructible.
216 * This func has not yet returned the new entry, thus iptables
217 * has not references for destroying this entry.
218 * For another rule to try to destroy it, it would 1st need for this
219 * func* to be re-invoked, acquire a new ref for the same named quota.
220 * Nobody will access the e->procfs_entry either.
221 * So release the lock. */
222 spin_unlock_bh(&counter_list_lock
);
224 /* create_proc_entry() is not spin_lock happy */
225 p
= e
->procfs_entry
= proc_create_data(e
->name
, quota_list_perms
,
226 proc_xt_quota
, &q2_counter_fops
, e
);
228 if (IS_ERR_OR_NULL(p
)) {
229 spin_lock_bh(&counter_list_lock
);
231 spin_unlock_bh(&counter_list_lock
);
234 proc_set_user(p
, quota_list_uid
, quota_list_gid
);
242 static int quota_mt2_check(const struct xt_mtchk_param
*par
)
244 struct xt_quota_mtinfo2
*q
= par
->matchinfo
;
246 pr_debug("xt_quota2: check() flags=0x%04x", q
->flags
);
248 if (q
->flags
& ~XT_QUOTA_MASK
)
251 q
->name
[sizeof(q
->name
)-1] = '\0';
252 if (*q
->name
== '.' || strchr(q
->name
, '/') != NULL
) {
253 printk(KERN_ERR
"xt_quota.3: illegal name\n");
257 q
->master
= q2_get_counter(q
);
258 if (q
->master
== NULL
) {
259 printk(KERN_ERR
"xt_quota.3: memory alloc failure\n");
266 static void quota_mt2_destroy(const struct xt_mtdtor_param
*par
)
268 struct xt_quota_mtinfo2
*q
= par
->matchinfo
;
269 struct xt_quota_counter
*e
= q
->master
;
271 if (*q
->name
== '\0') {
276 spin_lock_bh(&counter_list_lock
);
277 if (!atomic_dec_and_test(&e
->ref
)) {
278 spin_unlock_bh(&counter_list_lock
);
283 remove_proc_entry(e
->name
, proc_xt_quota
);
284 spin_unlock_bh(&counter_list_lock
);
289 quota_mt2(const struct sk_buff
*skb
, struct xt_action_param
*par
)
291 struct xt_quota_mtinfo2
*q
= (void *)par
->matchinfo
;
292 struct xt_quota_counter
*e
= q
->master
;
293 bool ret
= q
->flags
& XT_QUOTA_INVERT
;
295 spin_lock_bh(&e
->lock
);
296 if (q
->flags
& XT_QUOTA_GROW
) {
298 * While no_change is pointless in "grow" mode, we will
299 * implement it here simply to have a consistent behavior.
301 if (!(q
->flags
& XT_QUOTA_NO_CHANGE
)) {
302 e
->quota
+= (q
->flags
& XT_QUOTA_PACKET
) ? 1 : skb
->len
;
306 if (e
->quota
>= skb
->len
) {
307 if (!(q
->flags
& XT_QUOTA_NO_CHANGE
))
308 e
->quota
-= (q
->flags
& XT_QUOTA_PACKET
) ? 1 : skb
->len
;
311 /* We are transitioning, log that fact. */
313 quota2_log(par
->hooknum
,
319 /* we do not allow even small packets from now on */
323 spin_unlock_bh(&e
->lock
);
327 static struct xt_match quota_mt2_reg
[] __read_mostly
= {
331 .family
= NFPROTO_IPV4
,
332 .checkentry
= quota_mt2_check
,
334 .destroy
= quota_mt2_destroy
,
335 .matchsize
= sizeof(struct xt_quota_mtinfo2
),
341 .family
= NFPROTO_IPV6
,
342 .checkentry
= quota_mt2_check
,
344 .destroy
= quota_mt2_destroy
,
345 .matchsize
= sizeof(struct xt_quota_mtinfo2
),
350 static int __init
quota_mt2_init(void)
353 pr_debug("xt_quota2: init()");
355 #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
356 nflognl
= netlink_kernel_create(&init_net
, NETLINK_NFLOG
, NULL
);
361 proc_xt_quota
= proc_mkdir("xt_quota", init_net
.proc_net
);
362 if (proc_xt_quota
== NULL
)
365 ret
= xt_register_matches(quota_mt2_reg
, ARRAY_SIZE(quota_mt2_reg
));
367 remove_proc_entry("xt_quota", init_net
.proc_net
);
368 pr_debug("xt_quota2: init() %d", ret
);
372 static void __exit
quota_mt2_exit(void)
374 xt_unregister_matches(quota_mt2_reg
, ARRAY_SIZE(quota_mt2_reg
));
375 remove_proc_entry("xt_quota", init_net
.proc_net
);
378 module_init(quota_mt2_init
);
379 module_exit(quota_mt2_exit
);
380 MODULE_DESCRIPTION("Xtables: countdown quota match; up counter");
381 MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
382 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
383 MODULE_LICENSE("GPL");
384 MODULE_ALIAS("ipt_quota2");
385 MODULE_ALIAS("ip6t_quota2");