OSDN Git Service

Merge android-4.4.188 (886d085) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / net / netfilter / xt_quota2.c
1 /*
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
5  *
6  * Originally based on xt_quota.c:
7  *      netfilter module to enforce network quotas
8  *      Sam Johnston <samj@samj.net>
9  *
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.
13  */
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 <linux/workqueue.h>
20 #include <asm/atomic.h>
21 #include <net/netlink.h>
22
23 #include <linux/netfilter/x_tables.h>
24 #include <linux/netfilter/xt_quota2.h>
25
26 #define QUOTA2_SYSFS_WORK_MAX_SIZE 64
27 #define QUOTA2_SYSFS_NUM_ENVP 3
28
29 #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
30 /* For compatibility, these definitions are copied from the
31  * deprecated header file <linux/netfilter_ipv4/ipt_ULOG.h> */
32 #define ULOG_MAC_LEN    80
33 #define ULOG_PREFIX_LEN 32
34
35 /* Format of the ULOG packets passed through netlink */
36 typedef struct ulog_packet_msg {
37         unsigned long mark;
38         long timestamp_sec;
39         long timestamp_usec;
40         unsigned int hook;
41         char indev_name[IFNAMSIZ];
42         char outdev_name[IFNAMSIZ];
43         size_t data_len;
44         char prefix[ULOG_PREFIX_LEN];
45         unsigned char mac_len;
46         unsigned char mac[ULOG_MAC_LEN];
47         unsigned char payload[0];
48 } ulog_packet_msg_t;
49 #endif
50
51 /**
52  * @lock:       lock to protect quota writers from each other
53  */
54 struct xt_quota_counter {
55         u_int64_t quota;
56         spinlock_t lock;
57         struct list_head list;
58         atomic_t ref;
59         char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
60         struct proc_dir_entry *procfs_entry;
61         char last_iface[QUOTA2_SYSFS_WORK_MAX_SIZE];
62         char last_prefix[QUOTA2_SYSFS_WORK_MAX_SIZE];
63         struct work_struct work;
64 };
65
66 #define to_quota_counter(x) container_of(x, struct xt_quota_counter, work)
67
68 static struct class *quota_class;
69 static struct device *quota_device;
70 static struct kobject *quota_kobj;
71
72 static LIST_HEAD(counter_list);
73 static DEFINE_SPINLOCK(counter_list_lock);
74
75 static struct proc_dir_entry *proc_xt_quota;
76 static unsigned int quota_list_perms = S_IRUGO | S_IWUSR;
77 static kuid_t quota_list_uid = KUIDT_INIT(0);
78 static kgid_t quota_list_gid = KGIDT_INIT(0);
79 module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
80
81 static void quota2_work(struct work_struct *work)
82 {
83         char alert_msg[QUOTA2_SYSFS_WORK_MAX_SIZE];
84         char iface_name[QUOTA2_SYSFS_WORK_MAX_SIZE];
85         char *envp[QUOTA2_SYSFS_NUM_ENVP] = {alert_msg, iface_name,  NULL};
86         struct xt_quota_counter *counter = to_quota_counter(work);
87
88         snprintf(alert_msg, sizeof(alert_msg), "ALERT_NAME=%s", counter->name);
89         snprintf(iface_name, sizeof(iface_name), "INTERFACE=%s",
90                  counter->last_iface);
91
92         kobject_uevent_env(quota_kobj, KOBJ_CHANGE, envp);
93 }
94
95 static void quota2_log(const struct net_device *in,
96                        const struct net_device *out,
97                        struct  xt_quota_counter *q,
98                        const char *prefix)
99 {
100         if (!prefix)
101                 return;
102
103         strlcpy(q->last_prefix, prefix, QUOTA2_SYSFS_WORK_MAX_SIZE);
104
105         if (in)
106                 strlcpy(q->last_iface, in->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
107         else if (out)
108                 strlcpy(q->last_iface, out->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
109         else
110                 strlcpy(q->last_iface, "UNKNOWN", QUOTA2_SYSFS_WORK_MAX_SIZE);
111
112         schedule_work(&q->work);
113 }
114
115 static ssize_t quota_proc_read(struct file *file, char __user *buf,
116                            size_t size, loff_t *ppos)
117 {
118         struct xt_quota_counter *e = PDE_DATA(file_inode(file));
119         char tmp[24];
120         size_t tmp_size;
121
122         spin_lock_bh(&e->lock);
123         tmp_size = scnprintf(tmp, sizeof(tmp), "%llu\n", e->quota);
124         spin_unlock_bh(&e->lock);
125         return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
126 }
127
128 static ssize_t quota_proc_write(struct file *file, const char __user *input,
129                             size_t size, loff_t *ppos)
130 {
131         struct xt_quota_counter *e = PDE_DATA(file_inode(file));
132         char buf[sizeof("18446744073709551616")];
133
134         if (size > sizeof(buf))
135                 size = sizeof(buf);
136         if (copy_from_user(buf, input, size) != 0)
137                 return -EFAULT;
138         buf[sizeof(buf)-1] = '\0';
139
140         spin_lock_bh(&e->lock);
141         e->quota = simple_strtoull(buf, NULL, 0);
142         spin_unlock_bh(&e->lock);
143         return size;
144 }
145
146 static const struct file_operations q2_counter_fops = {
147         .read           = quota_proc_read,
148         .write          = quota_proc_write,
149         .llseek         = default_llseek,
150 };
151
152 static struct xt_quota_counter *
153 q2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon)
154 {
155         struct xt_quota_counter *e;
156         unsigned int size;
157
158         /* Do not need all the procfs things for anonymous counters. */
159         size = anon ? offsetof(typeof(*e), list) : sizeof(*e);
160         e = kmalloc(size, GFP_KERNEL);
161         if (e == NULL)
162                 return NULL;
163
164         e->quota = q->quota;
165         spin_lock_init(&e->lock);
166         if (!anon) {
167                 INIT_LIST_HEAD(&e->list);
168                 atomic_set(&e->ref, 1);
169                 strlcpy(e->name, q->name, sizeof(e->name));
170                 strlcpy(e->last_prefix, "UNSET", sizeof(e->last_prefix));
171                 strlcpy(e->last_iface, "UNSET", sizeof(e->last_iface));
172                 INIT_WORK(&e->work, quota2_work);
173         }
174         return e;
175 }
176
177 /**
178  * q2_get_counter - get ref to counter or create new
179  * @name:       name of counter
180  */
181 static struct xt_quota_counter *
182 q2_get_counter(const struct xt_quota_mtinfo2 *q)
183 {
184         struct proc_dir_entry *p;
185         struct xt_quota_counter *e = NULL;
186         struct xt_quota_counter *new_e;
187
188         if (*q->name == '\0')
189                 return q2_new_counter(q, true);
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
196         spin_lock_bh(&counter_list_lock);
197         list_for_each_entry(e, &counter_list, list)
198                 if (strcmp(e->name, q->name) == 0) {
199                         atomic_inc(&e->ref);
200                         spin_unlock_bh(&counter_list_lock);
201                         kfree(new_e);
202                         pr_debug("xt_quota2: old counter name=%s", e->name);
203                         return e;
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);
216
217         /* create_proc_entry() is not spin_lock happy */
218         p = e->procfs_entry = proc_create_data(e->name, quota_list_perms,
219                               proc_xt_quota, &q2_counter_fops, e);
220
221         if (IS_ERR_OR_NULL(p)) {
222                 spin_lock_bh(&counter_list_lock);
223                 list_del(&e->list);
224                 spin_unlock_bh(&counter_list_lock);
225                 goto out;
226         }
227         proc_set_user(p, quota_list_uid, quota_list_gid);
228         return e;
229
230  out:
231         kfree(e);
232         return NULL;
233 }
234
235 static int quota_mt2_check(const struct xt_mtchk_param *par)
236 {
237         struct xt_quota_mtinfo2 *q = par->matchinfo;
238
239         pr_debug("xt_quota2: check() flags=0x%04x", q->flags);
240
241         if (q->flags & ~XT_QUOTA_MASK)
242                 return -EINVAL;
243
244         q->name[sizeof(q->name)-1] = '\0';
245         if (*q->name == '.' || strchr(q->name, '/') != NULL) {
246                 printk(KERN_ERR "xt_quota.3: illegal name\n");
247                 return -EINVAL;
248         }
249
250         q->master = q2_get_counter(q);
251         if (q->master == NULL) {
252                 printk(KERN_ERR "xt_quota.3: memory alloc failure\n");
253                 return -ENOMEM;
254         }
255
256         return 0;
257 }
258
259 static void quota_mt2_destroy(const struct xt_mtdtor_param *par)
260 {
261         struct xt_quota_mtinfo2 *q = par->matchinfo;
262         struct xt_quota_counter *e = q->master;
263
264         if (*q->name == '\0') {
265                 kfree(e);
266                 return;
267         }
268
269         spin_lock_bh(&counter_list_lock);
270         if (!atomic_dec_and_test(&e->ref)) {
271                 spin_unlock_bh(&counter_list_lock);
272                 return;
273         }
274
275         list_del(&e->list);
276         remove_proc_entry(e->name, proc_xt_quota);
277         spin_unlock_bh(&counter_list_lock);
278         kfree(e);
279 }
280
281 static bool
282 quota_mt2(const struct sk_buff *skb, struct xt_action_param *par)
283 {
284         struct xt_quota_mtinfo2 *q = (void *)par->matchinfo;
285         struct xt_quota_counter *e = q->master;
286         bool ret = q->flags & XT_QUOTA_INVERT;
287
288         spin_lock_bh(&e->lock);
289         if (q->flags & XT_QUOTA_GROW) {
290                 /*
291                  * While no_change is pointless in "grow" mode, we will
292                  * implement it here simply to have a consistent behavior.
293                  */
294                 if (!(q->flags & XT_QUOTA_NO_CHANGE)) {
295                         e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
296                 }
297                 ret = true;
298         } else {
299                 if (e->quota >= skb->len) {
300                         if (!(q->flags & XT_QUOTA_NO_CHANGE))
301                                 e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
302                         ret = !ret;
303                 } else {
304                         /* We are transitioning, log that fact. */
305                         if (e->quota) {
306                                 quota2_log(par->in, par->out, e, q->name);
307                         }
308                         /* we do not allow even small packets from now on */
309                         e->quota = 0;
310                 }
311         }
312         spin_unlock_bh(&e->lock);
313         return ret;
314 }
315
316 static struct xt_match quota_mt2_reg[] __read_mostly = {
317         {
318                 .name       = "quota2",
319                 .revision   = 3,
320                 .family     = NFPROTO_IPV4,
321                 .checkentry = quota_mt2_check,
322                 .match      = quota_mt2,
323                 .destroy    = quota_mt2_destroy,
324                 .matchsize  = sizeof(struct xt_quota_mtinfo2),
325                 .me         = THIS_MODULE,
326         },
327         {
328                 .name       = "quota2",
329                 .revision   = 3,
330                 .family     = NFPROTO_IPV6,
331                 .checkentry = quota_mt2_check,
332                 .match      = quota_mt2,
333                 .destroy    = quota_mt2_destroy,
334                 .matchsize  = sizeof(struct xt_quota_mtinfo2),
335                 .me         = THIS_MODULE,
336         },
337 };
338
339 static int __init quota_mt2_init(void)
340 {
341         int ret;
342         pr_debug("xt_quota2: init()");
343
344         quota_class = class_create(THIS_MODULE, "xt_quota2");
345         ret = PTR_ERR(quota_class);
346         if (IS_ERR(quota_class)) {
347                 pr_err("xt_quota2: couldn't create class");
348                 class_destroy(quota_class);
349                 return ret;
350         }
351
352         quota_device = device_create(quota_class, NULL, MKDEV(0, 0), NULL,
353                                      "counters");
354         ret = PTR_ERR(quota_device);
355         if (IS_ERR(quota_device)) {
356                 pr_err("xt_quota2: couldn't create device");
357                 device_destroy(quota_class, MKDEV(0, 0));
358                 class_destroy(quota_class);
359                 return ret;
360         }
361
362         quota_kobj = &quota_device->kobj;
363
364         proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
365         if (proc_xt_quota == NULL)
366                 return -EACCES;
367
368         ret = xt_register_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
369         if (ret < 0)
370                 remove_proc_entry("xt_quota", init_net.proc_net);
371         pr_debug("xt_quota2: init() %d", ret);
372         return ret;
373 }
374
375 static void __exit quota_mt2_exit(void)
376 {
377         xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
378         remove_proc_entry("xt_quota", init_net.proc_net);
379         device_destroy(quota_class, MKDEV(0, 0));
380         class_destroy(quota_class);
381 }
382
383 module_init(quota_mt2_init);
384 module_exit(quota_mt2_exit);
385 MODULE_DESCRIPTION("Xtables: countdown quota match; up counter");
386 MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
387 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
388 MODULE_LICENSE("GPL");
389 MODULE_ALIAS("ipt_quota2");
390 MODULE_ALIAS("ip6t_quota2");