All of lore.kernel.org
 help / color / mirror / Atom feed
From: diegows <diegows@linux.org.ar>
To: netfilter-devel@lists.netfilter.org, samj@samj.net,
	linux-net@vger.kernel.org
Subject: quota.patch
Date: Tue, 08 Apr 2003 12:42:56 -0300	[thread overview]
Message-ID: <3E92EE00.7040703@linux.org.ar> (raw)

[-- Attachment #1: Type: text/plain, Size: 208 bytes --]

This is a modified quota match writing by Sam j. I add quota per ip and 
quota per connection (this is not very useful i think now...). Please 
try this and send  to me any comments and suggestions.

Thanks.

[-- Attachment #2: quota.patch --]
[-- Type: text/plain, Size: 12620 bytes --]

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 (&quota_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), &quota) < 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 (&quota_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 (&quota_lock);
+  if (q->invert == 1)
+    return 1;
+  return 0;
+
+quota:
+  spin_unlock_bh (&quota_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 (&quota_match);
+}
+
+static void __exit
+fini (void)
+{
+  ipt_unregister_match (&quota_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 (&quota_lock);
+
+  if (q->mode == QUOTA)
+    {
+      if (q->quota >= datalen)
+	{
+	  /* we can affor
+	     d this one */
+	  q->quota -= datalen;
+	  spin_unlock_bh (&quota_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), &quota) < 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 (&quota_lock);
+	      return 0;
+	    }
+	  spin_unlock_bh (&quota_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 (&quota_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 (&quota_match);
+}
+
+static void __exit
+fini (void)
+{
+  ipt_unregister_match (&quota_match);
+}
+
+module_init (init);
+module_exit (fini);

[-- Attachment #3: quota.patch.config.in --]
[-- Type: text/plain, Size: 174 bytes --]

  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

[-- Attachment #4: quota.patch.configure.help --]
[-- Type: text/plain, Size: 262 bytes --]

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'.


[-- Attachment #5: quota.patch.help --]
[-- Type: text/plain, Size: 477 bytes --]

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


[-- Attachment #6: quota.patch.makefile --]
[-- Type: text/plain, Size: 94 bytes --]

obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o

             reply	other threads:[~2003-04-08 15:42 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-04-08 15:42 diegows [this message]
2003-04-11  9:17 ` quota.patch Jozsef Kadlecsik
2003-04-11 13:32   ` quota.patch diegows
  -- strict thread matches above, loose matches on Subject: below --
2003-04-08 16:15 quota.patch diegows

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3E92EE00.7040703@linux.org.ar \
    --to=diegows@linux.org.ar \
    --cc=linux-net@vger.kernel.org \
    --cc=netfilter-devel@lists.netfilter.org \
    --cc=samj@samj.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.