Thanks.
diff -uNr --exclude=Makefile linux-2.4.20/include/linux/netfilter_ipv4/ipt_quota.h linux-2.4.20-2/include/linux/netfilter_ipv4/ipt_quota.h --- linux-2.4.20/include/linux/netfilter_ipv4/ipt_quota.h Wed Dec 31 21:00:00 1969 +++ linux-2.4.20-2/include/linux/netfilter_ipv4/ipt_quota.h Tue Apr 8 12:11:56 2003 @@ -0,0 +1,37 @@ +#ifndef _IPT_QUOTA_H +#define _IPT_QUOTA_H + +/* print debug info in both kernel/netfilter module & iptable library */ +/* #define DEBUG_IPT_QUOTA */ + +#define QUOTA_HASH_SIZE 1024 + +/* modes */ +#define IPQUOTA 1 /* quota per ip enable */ +#define QUOTA 0 /* general quota */ +#define CONNQUOTA 2 /* quota per connection */ + /**/ struct ipquota_list +{ + u_int32_t conn_index; + u_int64_t quota; + struct ipquota_list *next; +}; + +struct ipt_quota_info +{ + u_int64_t quota; + int mode; + int invert; + struct ipquota_list *quota_hash[QUOTA_HASH_SIZE]; +}; + +#define QUOTA_INDEX(skb, info) (q->mode == CONNQUOTA ? (skb->nh.iph->saddr + \ + skb->nh.iph->daddr + \ + skb->h.th->source + \ + skb->h.th->dest + \ + skb->nh.iph->protocol) : \ + (skb->nh.iph->saddr)) + +#define QUOTA_KEY(conn_index) (conn_index % QUOTA_HASH_SIZE) + +#endif /*_IPT_QUOTA_H*/ diff -uNr --exclude=Makefile linux-2.4.20/include/linux/netfilter_ipv4/ipt_quota.h~ linux-2.4.20-2/include/linux/netfilter_ipv4/ipt_quota.h~ --- linux-2.4.20/include/linux/netfilter_ipv4/ipt_quota.h~ Wed Dec 31 21:00:00 1969 +++ linux-2.4.20-2/include/linux/netfilter_ipv4/ipt_quota.h~ Tue Apr 8 12:11:56 2003 @@ -0,0 +1,37 @@ +#ifndef _IPT_QUOTA_H +#define _IPT_QUOTA_H + +/* print debug info in both kernel/netfilter module & iptable library */ +/* #define DEBUG_IPT_QUOTA */ + +#define QUOTA_HASH_SIZE 1024 + +/* modes */ +#define IPQUOTA 1 /* quota per ip enable */ +#define QUOTA 0 /* general quota */ +#define CONNQUOTA 2 /* quota per connection */ + /**/ struct ipquota_list +{ + u_int32_t conn_index; + u_int64_t quota; + struct ipquota_list *next; +}; + +struct ipt_quota_info +{ + u_int64_t quota; + int mode; + int invert; + struct ipquota_list *quota_hash[QUOTA_HASH_SIZE]; +}; + +#define QUOTA_INDEX(skb, info) (q->mode == CONNQUOTA ? (skb->nh.iph->saddr + \ + skb->nh.iph->daddr + \ + skb->h.th->source + \ + skb->h.th->dest + \ + skb->nh.iph->protocol) : \ + (skb->nh.iph->saddr)) + +#define QUOTA_KEY(conn_index) (conn_index % QUOTA_HASH_SIZE) + +#endif /*_IPT_QUOTA_H*/ diff -uNr --exclude=Makefile linux-2.4.20/net/ipv4/netfilter/ipt_quota.c linux-2.4.20-2/net/ipv4/netfilter/ipt_quota.c --- linux-2.4.20/net/ipv4/netfilter/ipt_quota.c Wed Dec 31 21:00:00 1969 +++ linux-2.4.20-2/net/ipv4/netfilter/ipt_quota.c Tue Apr 8 12:13:10 2003 @@ -0,0 +1,234 @@ +/* + * netfilter module to enforce network quotas + * + * Sam Johnston <samj@samj.net> + * + * 2003/04/02 Diego Woitasen (diegows@linux.org.ar) add quota per ip and quota + * per connection + */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_quota.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> + +MODULE_LICENSE ("GPL"); + +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED; + +static inline int +quota_hash_get (struct ipquota_list **hash, u_int32_t conn_index, + u_int64_t * quota) +{ + + struct ipquota_list *node = hash[QUOTA_KEY (conn_index)]; + + while (node != NULL) + { + if (node->conn_index == conn_index) + { + *quota = node->quota; + return (0); + } + node = node->next; + } + + return (-1); + +} + +static inline int +quota_hash_sum (struct ipquota_list **hash, u_int32_t conn_index, + u_int16_t datalen) +{ + + struct ipquota_list + *node = hash[QUOTA_KEY (conn_index)], *tmp = hash[QUOTA_KEY (conn_index)]; + + while (tmp != NULL) + { + if (tmp->conn_index == conn_index) + { + tmp->quota += datalen; + return (0); + } + tmp = tmp->next; + } + + tmp = kmalloc (sizeof (struct ipquota_list), GFP_KERNEL); + if (!tmp) + { + printk ("quota_hash_sum()->kmalloc fail"); + return (-1); + } + + tmp->conn_index = conn_index; + tmp->quota = datalen; + tmp->next = NULL; + + if (node == NULL) + hash[QUOTA_KEY (conn_index)] = tmp; + else + { + while (node->next != NULL) + node = node->next; + node->next = tmp; + } + + return (0); + +} + +static inline int +quota_hash_reset (struct ipquota_list **hash, u_int32_t conn_index) +{ + + struct ipquota_list *node = hash[QUOTA_KEY (conn_index)]; + + while (node) + { + if (node->conn_index == conn_index) + { + node->quota = 0; + return 0; + } + node = node->next; + } + + return (-1); + +} + +static int +match (const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + u_int64_t quota = 0; + + spin_lock_bh ("a_lock); + + if (q->mode == QUOTA) + { + if (q->quota >= datalen) + { + /* we can affor + d this one */ + q->quota -= datalen; + goto quota; + } + /* so we do not allow even small packets from now on */ + q->quota = 0; + } + else + { + + if (quota_hash_get (q->quota_hash, QUOTA_INDEX (skb, q), "a) < 0 + || quota < q->quota) + { + + if (quota_hash_sum (q->quota_hash, QUOTA_INDEX (skb, q), datalen) + < 0) + { + printk ("quota_hash_sum() error"); + spin_unlock_bh ("a_lock); + return 0; + } + goto quota; + } + } + + if (q->mode == CONNQUOTA) + { + enum ip_conntrack_info ct_state; + + ip_conntrack_get ((struct sk_buff *) skb, &ct_state); + if (ct_state == IP_CT_NEW) + { + quota_hash_reset (q->quota_hash, QUOTA_INDEX (skb, q)); + goto quota; + } + } + +#ifdef DEBUG_IPT_QUOTA + printk ("IPT Quota Failed: max=%llu\n", q->quota); +#endif + + spin_unlock_bh ("a_lock); + if (q->invert == 1) + return 1; + return 0; + +quota: + spin_unlock_bh ("a_lock); +#ifdef DEBUG_IPT_QUOTA + printk ("IPT Quota OK: %llu datlen %d \n", q->quota, datalen); +#endif + if (q->invert == 1) + return 0; + return 1; + +} + +static int +checkentry (const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + /* TODO: spinlocks? sanity checks? */ + if (matchsize != IPT_ALIGN (sizeof (struct ipt_quota_info))) + return 0; + + return 1; +} + +static void +destroy (void *matchinfo, unsigned int size) +{ + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + + int i; + + for (i = 0; i < QUOTA_HASH_SIZE; i++) + { + if (q->quota_hash[i]) + { + struct ipquota_list *tmp1, *tmp2; + tmp1 = q->quota_hash[i]; + + while (tmp1) + { + tmp2 = tmp1; + tmp1 = tmp1->next; + kfree (tmp2); + } + } + + } +} + +static struct ipt_match quota_match + = { {NULL, NULL}, "quota", &match, &checkentry, &destroy, THIS_MODULE }; + +static int __init +init (void) +{ + return ipt_register_match ("a_match); +} + +static void __exit +fini (void) +{ + ipt_unregister_match ("a_match); +} + +module_init (init); +module_exit (fini); diff -uNr --exclude=Makefile linux-2.4.20/net/ipv4/netfilter/ipt_quota.c~ linux-2.4.20-2/net/ipv4/netfilter/ipt_quota.c~ --- linux-2.4.20/net/ipv4/netfilter/ipt_quota.c~ Wed Dec 31 21:00:00 1969 +++ linux-2.4.20-2/net/ipv4/netfilter/ipt_quota.c~ Tue Apr 8 12:11:56 2003 @@ -0,0 +1,241 @@ +/* + * netfilter module to enforce network quotas + * + * Sam Johnston <samj@samj.net> + * + * 2003/04/02 Diego Woitasen (diegows@linux.org.ar) add quota per ip and quota + * per connection + */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_quota.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> + +MODULE_LICENSE ("GPL"); + +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED; + +static inline int +quota_hash_get (struct ipquota_list **hash, u_int32_t conn_index, + u_int64_t * quota) +{ + + struct ipquota_list *node = hash[QUOTA_KEY (conn_index)]; + + while (node != NULL) + { + if (node->conn_index == conn_index) + { + *quota = node->quota; + return (0); + } + node = node->next; + } + + return (-1); + +} + +static inline int +quota_hash_sum (struct ipquota_list **hash, u_int32_t conn_index, + u_int16_t datalen) +{ + + struct ipquota_list + *node = hash[QUOTA_KEY (conn_index)], *tmp = hash[QUOTA_KEY (conn_index)]; + + while (tmp != NULL) + { + if (tmp->conn_index == conn_index) + { + tmp->quota += datalen; + return (0); + } + tmp = tmp->next; + } + + tmp = kmalloc (sizeof (struct ipquota_list), GFP_KERNEL); + if (!tmp) + { + printk ("quota_hash_sum()->kmalloc fail"); + return (-1); + } + + tmp->conn_index = conn_index; + tmp->quota = datalen; + tmp->next = NULL; + + if (node == NULL) + hash[QUOTA_KEY (conn_index)] = tmp; + else + { + while (node->next != NULL) + node = node->next; + node->next = tmp; + } + + return (0); + +} + +static inline int +quota_hash_reset (struct ipquota_list **hash, u_int32_t conn_index) +{ + + struct ipquota_list *node = hash[QUOTA_KEY (conn_index)]; + + while (node) + { + if (node->conn_index == conn_index) + { + node->quota = 0; + return 0; + } + node = node->next; + } + + return (-1); + +} + +static int +match (const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + u_int64_t quota = 0; + + spin_lock_bh ("a_lock); + + if (q->mode == QUOTA) + { + if (q->quota >= datalen) + { + /* we can affor + d this one */ + q->quota -= datalen; + spin_unlock_bh ("a_lock); +#ifdef DEBUG_IPT_QUOTA + printk ("IPT Quota OK: %llu datlen %d \n", q->quota, datalen); +#endif + goto quota; + } + /* so we do not allow even small packets from now on */ + q->quota = 0; + } + else + { + + if (quota_hash_get (q->quota_hash, QUOTA_INDEX (skb, q), "a) < 0 + || quota < q->quota) + { + printk ("quota. quota=%llu, max=%llu", quota, q->quota); + if (quota_hash_sum (q->quota_hash, QUOTA_INDEX (skb, q), datalen) + < 0) + { + printk ("quota_hash_sum() error"); + spin_unlock_bh ("a_lock); + return 0; + } + spin_unlock_bh ("a_lock); +#ifdef DEBUG_IPT_QUOTA + printk ("IPT IP/CONN Quota OK: %llu datlen %d \n", q->quota, + datalen); +#endif + goto quota; + } + } + + + if (q->mode == CONNQUOTA) + { + enum ip_conntrack_info ct_state; + + ip_conntrack_get ((struct sk_buff *)skb, &ct_state); + if (ct_state == IP_CT_NEW) + { + quota_hash_reset (q->quota_hash, QUOTA_INDEX (skb, q)); + goto quota; + } + } + +#ifdef DEBUG_IPT_QUOTA + printk ("IPT Quota Failed: max=%llu\n", q->quota); +#endif + + spin_unlock_bh ("a_lock); + if (q->invert == 1) + return 1; + return 0; + +quota: + if (q->invert == 1) + return 0; + return 1; + + +} + +static int +checkentry (const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + /* TODO: spinlocks? sanity checks? */ + if (matchsize != IPT_ALIGN (sizeof (struct ipt_quota_info))) + return 0; + + return 1; +} + +static void +destroy (void *matchinfo, unsigned int size) +{ + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + + int i; + + for (i = 0; i < QUOTA_HASH_SIZE; i++) + { + if (q->quota_hash[i]) + { + struct ipquota_list *tmp1, *tmp2; + tmp1 = q->quota_hash[i]; + printk ("\ni=%d, tmp1=%p", i, tmp1); + while (tmp1) + { + tmp2 = tmp1; + tmp1 = tmp1->next; + kfree (tmp2); + } + } + + } +} + +static struct ipt_match quota_match + = { {NULL, NULL}, "quota", &match, &checkentry, &destroy, THIS_MODULE }; + +static int __init +init (void) +{ + return ipt_register_match ("a_match); +} + +static void __exit +fini (void) +{ + ipt_unregister_match ("a_match); +} + +module_init (init); +module_exit (fini);
dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $CONFIG_IP_NF_IPTABLES
CONFIG_IP_NF_MATCH_LIMIT quota match support CONFIG_IP_NF_MATCH_QUOTA This match implements network quotas, quota per ip and quota per connection. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'.
Author: Sam Johnston <samj@samj.net> Status: worksforme This option adds CONFIG_IP_NF_MATCH_QUOTA, which implements network quotas by decrementing a byte counter with each packet. Also implements quota per source ip address and quota per connection (Diego Woitasen <diegows@linux.org.ar>) Supported options are: --quota <bytes> The quota in bytes. --ipquota <bytes> The quota per source ip address in bytes --connquota <bytes> The quota per connection in bytes
obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o