1e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall/*
2e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * xt_quota2 - enhanced xt_quota that can count upwards and in packets
3e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * as a minimal accounting match.
4e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * by Jan Engelhardt <jengelh@medozas.de>, 2008
5e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall *
6e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * Originally based on xt_quota.c:
7e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * 	netfilter module to enforce network quotas
8e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * 	Sam Johnston <samj@samj.net>
9e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall *
10e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall *	This program is free software; you can redistribute it and/or modify
11e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall *	it under the terms of the GNU General Public License; either
12e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall *	version 2 of the License, as published by the Free Software Foundation.
13e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall */
14e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall#include <linux/list.h>
15917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#include <linux/module.h>
16e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall#include <linux/proc_fs.h>
17e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall#include <linux/skbuff.h>
18e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall#include <linux/spinlock.h>
19e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall#include <asm/atomic.h>
20917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#include <net/netlink.h>
21e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
22e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall#include <linux/netfilter/x_tables.h>
23917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#include <linux/netfilter/xt_quota2.h>
24917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
25917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#include <linux/netfilter_ipv4/ipt_ULOG.h>
26917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#endif
27e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
28e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall/**
29e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * @lock:	lock to protect quota writers from each other
30e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall */
31e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstruct xt_quota_counter {
32e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	u_int64_t quota;
33e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spinlock_t lock;
34e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct list_head list;
35e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	atomic_t ref;
36e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
37e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct proc_dir_entry *procfs_entry;
38e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall};
39e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
40917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
41917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall/* Harald's favorite number +1 :D From ipt_ULOG.C */
42917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrallstatic int qlog_nl_event = 112;
43917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrallmodule_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
44917596c2800a52c769d271bccc91b34da7bb59ebJP AbgrallMODULE_PARM_DESC(event_num,
45917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		 "Event number for NETLINK_NFLOG message. 0 disables log."
46917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		 "111 is what ipt_ULOG uses.");
47917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrallstatic struct sock *nflognl;
48917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#endif
49917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
50e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic LIST_HEAD(counter_list);
51e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic DEFINE_SPINLOCK(counter_list_lock);
52e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
53e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic struct proc_dir_entry *proc_xt_quota;
54e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic unsigned int quota_list_perms = S_IRUGO | S_IWUSR;
55f6dc94292c5f911044a6ee7d29398656800d4ca2John Stultzstatic kuid_t quota_list_uid = KUIDT_INIT(0);
56f6dc94292c5f911044a6ee7d29398656800d4ca2John Stultzstatic kgid_t quota_list_gid = KGIDT_INIT(0);
57e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallmodule_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
58917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
59917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
60917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrallstatic void quota2_log(unsigned int hooknum,
61917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const struct sk_buff *skb,
62917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const struct net_device *in,
63917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const struct net_device *out,
64917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const char *prefix)
65917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall{
66917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	ulog_packet_msg_t *pm;
67917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	struct sk_buff *log_skb;
68917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	size_t size;
69917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	struct nlmsghdr *nlh;
70917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
71917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (!qlog_nl_event)
72917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		return;
73917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
74917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	size = NLMSG_SPACE(sizeof(*pm));
75917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	size = max(size, (size_t)NLMSG_GOODSIZE);
76917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	log_skb = alloc_skb(size, GFP_ATOMIC);
77917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (!log_skb) {
78917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		pr_err("xt_quota2: cannot alloc skb for logging\n");
79917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		return;
80917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	}
81917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
82917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
83917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall			sizeof(*pm), 0);
84917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (!nlh) {
85917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		pr_err("xt_quota2: nlmsg_put failed\n");
86917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		kfree_skb(log_skb);
87917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		return;
88917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	}
89917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pm = nlmsg_data(nlh);
90917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (skb->tstamp.tv64 == 0)
91917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		__net_timestamp((struct sk_buff *)skb);
92917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pm->data_len = 0;
93917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pm->hook = hooknum;
94917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (prefix != NULL)
95917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
96917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	else
97917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		*(pm->prefix) = '\0';
98917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (in)
99917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
100917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	else
101917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		pm->indev_name[0] = '\0';
102917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
103917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (out)
104917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
105917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	else
106917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		pm->outdev_name[0] = '\0';
107917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
108917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	NETLINK_CB(log_skb).dst_group = 1;
109917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pr_debug("throwing 1 packets to netlink group 1\n");
110917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
111917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall}
112917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#else
113917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrallstatic void quota2_log(unsigned int hooknum,
114917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const struct sk_buff *skb,
115917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const struct net_device *in,
116917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const struct net_device *out,
117917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		       const char *prefix)
118917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall{
119917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall}
120917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#endif  /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
121917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
122d4b98f8768f1d52afd7c7c3a3579350eb9bdde9cGreg Hackmannstatic ssize_t quota_proc_read(struct file *file, char __user *buf,
1239a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg			   size_t size, loff_t *ppos)
124e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
1259a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	struct xt_quota_counter *e = PDE_DATA(file_inode(file));
1269a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	char tmp[24];
1279a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	size_t tmp_size;
128e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
129e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_lock_bh(&e->lock);
1309a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	tmp_size = scnprintf(tmp, sizeof(tmp), "%llu\n", e->quota);
131e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_unlock_bh(&e->lock);
1329a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
133e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
134e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
135d4b98f8768f1d52afd7c7c3a3579350eb9bdde9cGreg Hackmannstatic ssize_t quota_proc_write(struct file *file, const char __user *input,
1369a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg                            size_t size, loff_t *ppos)
137e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
1389a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	struct xt_quota_counter *e = PDE_DATA(file_inode(file));
139e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	char buf[sizeof("18446744073709551616")];
140e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
141e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (size > sizeof(buf))
142e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		size = sizeof(buf);
143e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (copy_from_user(buf, input, size) != 0)
144e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return -EFAULT;
145e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	buf[sizeof(buf)-1] = '\0';
146e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
147e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_lock_bh(&e->lock);
148e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	e->quota = simple_strtoull(buf, NULL, 0);
149e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_unlock_bh(&e->lock);
150e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return size;
151e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
152e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
1539a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevågstatic const struct file_operations q2_counter_fops = {
1549a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	.read		= quota_proc_read,
1559a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	.write		= quota_proc_write,
1569a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	.llseek		= default_llseek,
1579a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg};
1589a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg
159e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic struct xt_quota_counter *
160e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallq2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon)
161e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
162e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct xt_quota_counter *e;
163e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	unsigned int size;
164e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
165e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	/* Do not need all the procfs things for anonymous counters. */
166e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	size = anon ? offsetof(typeof(*e), list) : sizeof(*e);
167e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	e = kmalloc(size, GFP_KERNEL);
168e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (e == NULL)
169e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return NULL;
170e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
171e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	e->quota = q->quota;
172e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_lock_init(&e->lock);
173e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (!anon) {
174e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		INIT_LIST_HEAD(&e->list);
175e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		atomic_set(&e->ref, 1);
176917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		strlcpy(e->name, q->name, sizeof(e->name));
177e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	}
178e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return e;
179e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
180e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
181e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall/**
182e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * q2_get_counter - get ref to counter or create new
183e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall * @name:	name of counter
184e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall */
185e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic struct xt_quota_counter *
186e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallq2_get_counter(const struct xt_quota_mtinfo2 *q)
187e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
188e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct proc_dir_entry *p;
189917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	struct xt_quota_counter *e = NULL;
190917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	struct xt_quota_counter *new_e;
191e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
192e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (*q->name == '\0')
193e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return q2_new_counter(q, true);
194e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
195917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	/* No need to hold a lock while getting a new counter */
196917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	new_e = q2_new_counter(q, false);
197917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (new_e == NULL)
198917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		goto out;
199917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
200e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_lock_bh(&counter_list_lock);
201e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	list_for_each_entry(e, &counter_list, list)
202e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		if (strcmp(e->name, q->name) == 0) {
203e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			atomic_inc(&e->ref);
204e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			spin_unlock_bh(&counter_list_lock);
205917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall			kfree(new_e);
206917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall			pr_debug("xt_quota2: old counter name=%s", e->name);
207e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			return e;
208e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		}
209917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	e = new_e;
210917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pr_debug("xt_quota2: new_counter name=%s", e->name);
211917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	list_add_tail(&e->list, &counter_list);
212917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	/* The entry having a refcount of 1 is not directly destructible.
213917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	 * This func has not yet returned the new entry, thus iptables
214917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	 * has not references for destroying this entry.
215917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	 * For another rule to try to destroy it, it would 1st need for this
216917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	 * func* to be re-invoked, acquire a new ref for the same named quota.
217917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	 * Nobody will access the e->procfs_entry either.
218917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	 * So release the lock. */
219917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	spin_unlock_bh(&counter_list_lock);
220e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
221917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	/* create_proc_entry() is not spin_lock happy */
2229a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	p = e->procfs_entry = proc_create_data(e->name, quota_list_perms,
2239a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	                      proc_xt_quota, &q2_counter_fops, e);
224e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
225917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (IS_ERR_OR_NULL(p)) {
226917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		spin_lock_bh(&counter_list_lock);
227917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		list_del(&e->list);
228917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		spin_unlock_bh(&counter_list_lock);
229917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		goto out;
230917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	}
2319a4389e02f6cef9f550fc7abb686363aa3e14185Arve Hjønnevåg	proc_set_user(p, quota_list_uid, quota_list_gid);
232e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return e;
233e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
234e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall out:
235e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	kfree(e);
236e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return NULL;
237e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
238e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
239e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic int quota_mt2_check(const struct xt_mtchk_param *par)
240e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
241e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct xt_quota_mtinfo2 *q = par->matchinfo;
242e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
243917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pr_debug("xt_quota2: check() flags=0x%04x", q->flags);
244917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
245e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (q->flags & ~XT_QUOTA_MASK)
246e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return -EINVAL;
247e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
248e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	q->name[sizeof(q->name)-1] = '\0';
249e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (*q->name == '.' || strchr(q->name, '/') != NULL) {
250e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		printk(KERN_ERR "xt_quota.3: illegal name\n");
251e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return -EINVAL;
252e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	}
253e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
254e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	q->master = q2_get_counter(q);
255e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (q->master == NULL) {
256e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		printk(KERN_ERR "xt_quota.3: memory alloc failure\n");
257e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return -ENOMEM;
258e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	}
259e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
260e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return 0;
261e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
262e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
263e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic void quota_mt2_destroy(const struct xt_mtdtor_param *par)
264e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
265e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct xt_quota_mtinfo2 *q = par->matchinfo;
266e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct xt_quota_counter *e = q->master;
267e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
268e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (*q->name == '\0') {
269e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		kfree(e);
270e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return;
271e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	}
272e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
273e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_lock_bh(&counter_list_lock);
274e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (!atomic_dec_and_test(&e->ref)) {
275e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		spin_unlock_bh(&counter_list_lock);
276e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return;
277e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	}
278e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
279e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	list_del(&e->list);
280e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	remove_proc_entry(e->name, proc_xt_quota);
281e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_unlock_bh(&counter_list_lock);
282e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	kfree(e);
283e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
284e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
285e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic bool
286e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallquota_mt2(const struct sk_buff *skb, struct xt_action_param *par)
287e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
288e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct xt_quota_mtinfo2 *q = (void *)par->matchinfo;
289e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	struct xt_quota_counter *e = q->master;
290e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	bool ret = q->flags & XT_QUOTA_INVERT;
291e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
292e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_lock_bh(&e->lock);
293e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (q->flags & XT_QUOTA_GROW) {
294e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		/*
295e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		 * While no_change is pointless in "grow" mode, we will
296e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		 * implement it here simply to have a consistent behavior.
297e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		 */
298e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		if (!(q->flags & XT_QUOTA_NO_CHANGE)) {
299e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
300e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		}
301e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		ret = true;
302e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	} else {
303e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		if (e->quota >= skb->len) {
304e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			if (!(q->flags & XT_QUOTA_NO_CHANGE))
305e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall				e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
306e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			ret = !ret;
307e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		} else {
308917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall			/* We are transitioning, log that fact. */
309917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall			if (e->quota) {
310917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall				quota2_log(par->hooknum,
311917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall					   skb,
312917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall					   par->in,
313917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall					   par->out,
314917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall					   q->name);
315917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall			}
316e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			/* we do not allow even small packets from now on */
317e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall			e->quota = 0;
318e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		}
319e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	}
320e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	spin_unlock_bh(&e->lock);
321e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return ret;
322e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
323e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
324e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic struct xt_match quota_mt2_reg[] __read_mostly = {
325e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	{
326e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.name       = "quota2",
327e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.revision   = 3,
328e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.family     = NFPROTO_IPV4,
329e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.checkentry = quota_mt2_check,
330e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.match      = quota_mt2,
331917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		.destroy    = quota_mt2_destroy,
332e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.matchsize  = sizeof(struct xt_quota_mtinfo2),
333e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.me         = THIS_MODULE,
334e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	},
335e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	{
336e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.name       = "quota2",
337e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.revision   = 3,
338e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.family     = NFPROTO_IPV6,
339e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.checkentry = quota_mt2_check,
340e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.match      = quota_mt2,
341917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		.destroy    = quota_mt2_destroy,
342e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.matchsize  = sizeof(struct xt_quota_mtinfo2),
343e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		.me         = THIS_MODULE,
344e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	},
345e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall};
346e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
347e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic int __init quota_mt2_init(void)
348e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
349e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	int ret;
350917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pr_debug("xt_quota2: init()");
351917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall
352917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
353917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
354917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	if (!nflognl)
355917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		return -ENOMEM;
356917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall#endif
357e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
358917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
359e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (proc_xt_quota == NULL)
360e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall		return -EACCES;
361e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
362e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	ret = xt_register_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
363e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	if (ret < 0)
364917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall		remove_proc_entry("xt_quota", init_net.proc_net);
365917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	pr_debug("xt_quota2: init() %d", ret);
366e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	return ret;
367e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
368e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
369e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallstatic void __exit quota_mt2_exit(void)
370e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall{
371e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall	xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
372917596c2800a52c769d271bccc91b34da7bb59ebJP Abgrall	remove_proc_entry("xt_quota", init_net.proc_net);
373e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall}
374e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrall
375e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallmodule_init(quota_mt2_init);
376e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP Abgrallmodule_exit(quota_mt2_exit);
377e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP AbgrallMODULE_DESCRIPTION("Xtables: countdown quota match; up counter");
378e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP AbgrallMODULE_AUTHOR("Sam Johnston <samj@samj.net>");
379e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP AbgrallMODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
380e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP AbgrallMODULE_LICENSE("GPL");
381e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP AbgrallMODULE_ALIAS("ipt_quota2");
382e78618c4c98e5fe6ed11c21c7a73fd9f8f6936b0JP AbgrallMODULE_ALIAS("ip6t_quota2");
383