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