diff -urN -X dontdiff linux-2.4/Documentation/Configure.help linux-2.4.6-ipacct/Documentation/Configure.help
--- linux-2.4/Documentation/Configure.help	Thu Jul  5 15:29:15 2001
+++ linux-2.4.6-ipacct/Documentation/Configure.help	Thu Jul  5 15:43:27 2001
@@ -3108,6 +3108,15 @@
 
   If unsure, say N.

+IP: Per user accounting
+CONFIG_IP_ACCT_USER
+  This program allows you to account the IP traffic on a per user basis.
+  Usually you only want to say Y here if your box will be an IP provider
+  and you want to keep track of your users IP traffic.  This package does
+  not require you to use the default kernel IP accounting.  The data is
+  accessible with "cat /proc/net/ip_acct_user", so you want to say Y to
+  the /proc filesystem, if you say Y here.
+
 # Choice: alphatype
 Alpha system type
 CONFIG_ALPHA_GENERIC
diff -urN -X dontdiff linux-2.4/Makefile linux-2.4.6-ipacct/Makefile
--- linux-2.4/Makefile	Thu Jul  5 15:29:15 2001
+++ linux-2.4.6-ipacct/Makefile	Thu Jul  5 15:43:36 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -pre6
+EXTRAVERSION = -pre6-ipacct

 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) VERSION = 2

diff -urN -X dontdiff linux-2.4/arch/i386/defconfig linux-2.4.6-ipacct/arch/i386/defconfig
--- linux-2.4/arch/i386/defconfig	Thu Jul  5 15:29:15 2001
+++ linux-2.4.6-ipacct/arch/i386/defconfig	Thu Jul  5 15:43:27 2001
@@ -172,6 +172,7 @@
 # CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_IP_ACCT_USER=y
 # CONFIG_VLAN_8021Q is not set

 #
 
diff -urN -X dontdiff linux-2.4.20/include/linux/ip_acct_user.h v2.4.20/include/linux/ip_acct_user.h
--- linux-2.4.20/include/linux/ip_acct_user.h	1970-01-01 02:00:00.000000000 +0200
+++ v2.4.20/include/linux/ip_acct_user.h	2003-05-19 13:47:31.000000000 +0300
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 1994,1995 Lars Fenneberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LINUX_IP_ACCT_USER_H
+#define _LINUX_IP_ACCT_USER_H
+
+#include <linux/types.h>
+
+#define IPAU_VERSION "UserIPAcct: version 0.9b\n"
+
+#define IPAU_NOUSER	(uid_t)(99)  /* thats the uid of nobody on my system */
+#define IPAU_DEF_WEIGHT		1   /* default weight */
+
+#define IPAU_HAS_RESET_BY_RW	1  /* can reset the user counters by open rw */
+#define IPAU_RESET_FREE		4  /* at the forth reset free the structure */
+
+/* see also linux/sockios.h for future collisions */
+
+#define SIOCADDWT	0x89D0		/* Add weight entry    */
+#define SIOCDELWT	0x89D1		/* Del weight entry    */
+#define SIOCRSTUT	0x89D2		/* Reset counter(s)    */
+#define SIOCCTRLU	0x89D3		/* Control user access */
+#define SIOCADDCE	0x89D4		/* Add control entry   */
+#define SIOCDELCE	0x89D5		/* Delete control entry */
+
+/* Magic value "Clear all user ip acct info" for SIOCRSTUT ioctl */
+#define IPAU_CLEAR_ALL -1
+
+/* Flags for SIOCCTRLU ioctl                            */
+#define IPAU_NO_ACCESS  1
+
+/* Max number of connections per user */
+#define IPAU_MAXCONSPERUSER 255
+
+/* structure for argument to SIOCCTRLU ioctl            */
+/* Added remote address - 23/02/1999 Zaheer Merali <zaheer@mirage.co.uk> */
+struct ip_acct_user_ctrl_entry {
+
+  uid_t        uid;
+  int  flags; 
+  unsigned long r_addr;
+       
+};
+
+/* structure for argument to SIOCADDWT, SIOCDELWT ioctl  */
+struct ip_acct_weight_entry {
+
+	unsigned long addr;
+	unsigned long mask;
+	int     weight;
+       
+};
+
+#ifdef __KERNEL__
+
+#define IPAU_HASHMAX		101
+#define IPAU_HASHVAL(i)		((i)%IPAU_HASHMAX)
+
+#ifdef DEBUG
+#define IPAU_MAGIC		0x4701
+#endif
+
+struct ip_acct_user_s {
+
+#ifdef DEBUG
+	int magic;
+#endif
+	uid_t   uid;    /* user who owns the socket     */
+	int     sent;   /* bytes sent for this user     */
+	int     recv;   /* bytes received for this user */
+	int     flags;  /* deny/grant access            */
+	char    reset;  /* counter for memory management*/
+	struct ip_acct_user_s *prev, *succ;
+};
+
+struct  ip_acct_weight_s {
+
+#ifdef DEBUG
+	int magic;
+#endif
+	unsigned long addr;
+	unsigned long mask;
+	int     weight;                 /* Weight of this address */
+                                       /* (0 means ignore)       */ 
+	struct ip_acct_weight_s *succ;
+};
+
+struct ip_acct_weight_list {
+	int default_weight;
+	struct ip_acct_weight_s *head;
+	struct ip_acct_weight_s *tail;
+};
+
+   /* Added 15 Mar 1999 - Zaheer Merali - stuff for IP Control Rules */
+struct ip_acct_control_address_s {
+  
+  /* address */
+  unsigned long addr;
+  /* mask */
+  unsigned long mask;
+  /* policy (accept=1,reject=0)*/
+  int policy;
+  /* previous and next exntries in list - doubly linked list */
+  struct ip_acct_control_address_s *prev, *succ;
+};
+
+struct ip_acct_control_user_s {
+
+  /* default policy (accept=1,reject=0) */
+  int def;
+  /* userid (0 if global as root cannot be limited) */
+  uid_t uid;
+  /* list of remote address rules */
+  struct ip_acct_control_address_s *remote_list;
+  /* list of local address rules */
+  struct ip_acct_control_address_s *local_list;
+};
+
+
+int ip_acct_user_sent(uid_t user, unsigned long daddr, int sent);
+int ip_acct_user_received(uid_t user, unsigned long daddr, int recv);
+int ip_acct_user_allowed(uid_t user, unsigned long daddr);
+int ip_acct_user_get_uinfo(char *buffer, char **start, off_t offset, int length);
+int ip_acct_user_get_winfo(char *buffer, char **start, off_t offset, int length);
+int ip_acct_user_ioctl(unsigned int cmd, void *arg);
+void ip_acct_user_init(void);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_IP_ACCT_USER_H */
+

diff -urN -X dontdiff linux-2.4/net/ipv4/Config.in linux-2.4.6-ipacct/net/ipv4/Config.in
--- linux-2.4/net/ipv4/Config.in	Sat May 26 10:49:55 2001
+++ linux-2.4.6-ipacct/net/ipv4/Config.in	Thu Jul  5 15:43:27 2001
@@ -2,6 +2,7 @@
 # IP configuration
 #
 bool '  IP: multicasting' CONFIG_IP_MULTICAST
+bool '  IP: Per user accounting' CONFIG_IP_ACCT_USER
 bool '  IP: advanced router' CONFIG_IP_ADVANCED_ROUTER
 if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then
    define_bool CONFIG_RTNETLINK y	
diff -urN -X dontdiff linux-2.4/net/ipv4/Makefile linux-2.4.6-ipacct/net/ipv4/Makefile
--- linux-2.4/net/ipv4/Makefile	Fri Dec 29 22:07:24 2000
+++ linux-2.4.6-ipacct/net/ipv4/Makefile	Thu Jul  5 15:43:27 2001
@@ -25,6 +25,7 @@
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_IP_PNP) += ipconfig.o
+obj-$(CONFIG_IP_ACCT_USER) += ip_acct_user.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN -X dontdiff linux-2.4/net/ipv4/af_inet.c linux-2.4.6-ipacct/net/ipv4/af_inet.c
--- linux-2.4/net/ipv4/af_inet.c	Thu Jul  5 15:29:39 2001
+++ linux-2.4.6-ipacct/net/ipv4/af_inet.c	Thu Jul  5 15:43:27 2001
@@ -103,6 +103,9 @@
 #include <net/icmp.h>
 #include <net/ipip.h>
 #include <net/inet_common.h>
+#ifdef CONFIG_IP_ACCT_USER
+#include <linux/ip_acct_user.h>
+#endif
 #ifdef CONFIG_IP_MROUTE
 #include <linux/mroute.h>
 #endif
@@ -860,6 +863,13 @@
 		case SIOCGARP:
 		case SIOCSARP:
 			return(arp_ioctl(cmd,(void *) arg));
+#ifdef CONFIG_IP_ACCT_USER
+		case SIOCADDWT:
+		case SIOCDELWT:
+		case SIOCRSTUT:
+		case SIOCCTRLU:
+			return(ip_acct_user_ioctl(cmd,(void *)arg));
+#endif
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFBRDADDR:
@@ -1153,6 +1163,10 @@
 	 */
 
 	icmp_init(&inet_family_ops);
+
+#ifdef CONFIG_IP_ACCT_USER
+	ip_acct_user_init();
+#endif
 
 	/* I wish inet_add_protocol had no constructor hook...
 	   I had to move IPIP from net/ipv4/protocol.c :-( --ANK

diff -urN -X dontdiff linux-2.4.20/net/ipv4/ip_acct_user.c v2.4.20/net/ipv4/ip_acct_user.c
--- linux-2.4.20/net/ipv4/ip_acct_user.c	1970-01-01 02:00:00.000000000 +0200
+++ v2.4.20/net/ipv4/ip_acct_user.c	2003-05-21 15:57:24.000000000 +0300
@@ -0,0 +1,777 @@
+/* 
+ * Copyright (C) 1994,1995 Lars Fenneberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/segment.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/net.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <linux/ip_acct_user.h>
+#include <asm/uaccess.h>
+#define VERIFY_READ 0
+#undef DEBUG
+
+static struct ip_acct_user_s *user_stat[IPAU_HASHMAX];
+static struct ip_acct_weight_list user_weight_list;
+
+/* static struct ip_acct_control_user_list *user_control_list; */
+/***********************************************************************
+                           Subroutines
+***********************************************************************/
+
+/***********************************************************************
+ used for matching address against weight table
+***********************************************************************/
+
+inline struct ip_acct_weight_s *
+match_addr(struct ip_acct_weight_list *wlist, unsigned long waddr)
+{
+  struct ip_acct_weight_s *p;
+
+  for(p=wlist->head; p!=NULL; p=p->succ) {
+    if (!(((p->addr) ^ waddr) & (p->mask))) break;
+  }
+
+#ifdef DEBUG
+  if ((p!=NULL) && (p->magic != IPAU_MAGIC)) {
+    printk("ipacct: weight list corrupt.\n");
+    p = NULL;
+  }
+#endif
+
+  return p;
+}
+
+/***********************************************************************
+ used for adding address into weight table
+***********************************************************************/
+
+static int
+add_addr(struct ip_acct_weight_list *wlist,
+                      struct ip_acct_weight_entry *wt)
+{
+  struct ip_acct_weight_s *p = wlist->head; 
+
+#ifdef DEBUG
+  printk("ipacct: add addr.\n");
+#endif
+
+  if ((wt->addr) == 0x00000000) {
+    wlist->default_weight = wt->weight;
+    return 0;  
+  }
+
+  cli();
+  while ((p != NULL) && 
+        (((p->addr) != (wt->addr)) ||
+        ((p->mask) != (wt->mask)))) p = p->succ;
+
+#ifdef DEBUG
+  if ((p != NULL) && (p->magic != IPAU_MAGIC))
+  {
+    printk("ipacct: weight list corrupt.\n");
+    p = NULL;
+  }
+#endif
+  
+  if (p != NULL) 
+  {
+    p->weight = wt->weight;
+  }
+  else
+  {
+    if ((p = (struct ip_acct_weight_s *)kmalloc(sizeof(struct ip_acct_weight_s),GFP_KERNEL)) == NULL) return -ENOMEM;
+
+#ifdef DEBUG    
+    p->magic  = IPAU_MAGIC;
+#endif
+
+    p->addr   = wt->addr;
+    p->mask   = wt->mask;
+    p->weight = wt->weight;
+    p->succ   = NULL;
+
+    if (wlist->head == NULL) 
+    {
+       wlist->head = wlist->tail = p;
+    }
+    else
+    {
+       wlist->tail->succ = p;
+       wlist->tail = p;
+    }
+
+  }
+  sti();
+
+  return 0;
+}
+
+
+/***********************************************************************
+ used for deleting address from weight table
+***********************************************************************/
+
+static int
+del_addr(struct ip_acct_weight_list *wlist,
+                      struct ip_acct_weight_entry *wt)
+{
+  struct ip_acct_weight_s *p = wlist->head;
+  struct ip_acct_weight_s *pred = NULL;
+
+
+#ifdef DEBUG
+  printk("ipacct: del addr.\n");
+#endif
+
+  cli();  
+
+  while ((p != NULL) && 
+        (((p->addr) != (wt->addr)) ||
+        ((p->mask) != (wt->mask)))) 
+  {
+    pred = p;
+    p = p->succ;
+  }
+
+#ifdef DEBUG
+  if ((p != NULL) && (p->magic != IPAU_MAGIC))
+  {
+    printk("ipacct: weight list corrupt.\n");
+    p = NULL;
+  }
+#endif
+
+  if (p == NULL) return -EINVAL;
+       
+  if (pred == NULL)
+  {
+    wlist->head = p->succ;
+    if (wlist->head == NULL) wlist->tail = NULL;
+  }
+  else 
+  {
+    pred->succ = p->succ;
+    if (pred->succ == NULL) wlist->tail = pred;
+  }
+
+  sti();
+  kfree(p);
+
+  return 0;
+}
+
+
+/***********************************************************************
+ used for getting one weight from weight table
+***********************************************************************/
+
+inline int
+get_weight(struct ip_acct_weight_list *wlist, unsigned long waddr)
+{
+  struct ip_acct_weight_s *p;
+  int w;
+
+  cli();  
+  if ((p = match_addr(wlist, waddr)) == NULL) w = wlist->default_weight; else w = (p->weight);
+  sti();
+  
+  return w;
+}
+
+/***********************************************************************
+ used for getting the whole weight table
+***********************************************************************/
+ 
+static int
+get_weight_info(struct ip_acct_weight_list *wlist, char *buffer, 
+                      char **start, off_t offset, int length)
+{
+       struct ip_acct_weight_s *p = wlist->head;
+       int len=0;
+       off_t pos=0;
+       off_t begin=0;
+  
+#ifdef DEBUG
+       printk("ipacct: get weight info.\n");
+#endif
+  
+  
+       len+=sprintf(buffer, "addr\t\tmask\t\tweight\n");
+
+       cli();
+       while(p != NULL) 
+       {
+
+         len+=sprintf(buffer+len,"%08lX\t%08lX\t%-5i\n",p->addr,p->mask,p->weight);
+
+         p = p->succ;
+                       
+         pos=begin+len;
+         if(pos<offset)
+         {
+           len=0;
+           begin=pos;
+         }
+         if(pos>offset+length) break;
+       }
+       sti();
+
+       if (pos<=offset+length) {
+
+         len+=sprintf(buffer+len,"%08iX\t%08iX\t%-5i\n",htonl(0x00000000),htonl(0xffffffff),wlist->default_weight);
+
+         pos=begin+len;
+         if(pos<offset)
+         {
+           len=0;
+           begin=pos;
+         }
+       
+       }
+
+       *start=buffer+(offset-begin);
+       len-=(offset-begin);
+       if(len>length)
+               len=length;
+       return len;
+}
+
+/***********************************************************************
+ used to find user in the ip_acct_user_s structure
+hacked a little by Ivo Velichkov
+***********************************************************************/
+ 
+static struct ip_acct_user_s *
+find_user(uid_t user)
+{ 
+
+  struct ip_acct_user_s *p = user_stat[IPAU_HASHVAL(user)];
+
+  while (p!=NULL) {
+    if ( (p->uid)== user ){
+
+#ifdef DEBUG
+      printk ("found user %i with zapis %p\n", user, p);
+#endif
+
+      break;
+    }else{
+      p=p->succ;
+    }
+  }
+
+#ifdef DEBUG
+  if ((p != NULL) && (p->magic != IPAU_MAGIC))
+  {
+    printk("ipacct: user list corrupt.\n");
+    p = NULL;
+  }
+#endif
+
+  return p;
+}
+
+
+/* get_all_entries_of_user added 21/02/1999 - Zaheer Merali <zaheer@mirage.co.uk> *
+ * - returns a pointer to an array of ip_acct_user_s pointers                     *
+ * THE CALLER MUST kfree the returned value                                       */
+
+static struct ip_acct_user_s **
+get_all_entries_of_user(uid_t user, unsigned int *numofusers)
+{
+  struct ip_acct_user_s **p_users;
+  unsigned int userindex=0;
+  struct ip_acct_user_s *p=user_stat[IPAU_HASHVAL(user)];
+  
+  if ((p_users=(struct ip_acct_user_s **)kmalloc(sizeof(struct ip_addr_user_s *)*IPAU_MAXCONSPERUSER,GFP_ATOMIC)) == NULL)
+    return NULL;
+
+  while (p!=NULL && userindex<IPAU_MAXCONSPERUSER) {
+    if ((p!=NULL) && ((p->uid) != user)) p=p->succ;
+    else p_users[userindex++]=p;
+  }
+
+  *numofusers=userindex;
+
+  return p_users;
+}
+
+/***********************************************************************
+ used to create user in the ip_acct_user_s structure
+ hacked a little by Ivo Velichkov removed the raddr
+***********************************************************************/
+
+static struct ip_acct_user_s *create_user(uid_t user)
+{
+    struct ip_acct_user_s *p;
+    int hashval = IPAU_HASHVAL(user);
+
+#ifdef DEBUG
+    printk("ipacct: create user (uid %i).\n",user);
+#endif
+  
+    if ((p = (struct ip_acct_user_s *)kmalloc(sizeof(struct ip_acct_user_s),GFP_ATOMIC)) == NULL) 
+       return NULL;
+    
+#ifdef DEBUG
+    p->magic  = IPAU_MAGIC;
+#endif
+    p->uid    = user;
+    p->reset  = 0;
+    p->prev   = NULL;
+    p->succ   = user_stat[hashval];
+    if (p->succ) p->succ->prev = p;
+    user_stat[hashval] = p; 
+#ifdef DEBUG
+    printk("Created user %i at memory ref %p\n",user,p);
+#endif
+    return p;
+}
+
+/***********************************************************************
+ used to delete user in the ip_acct_user_s structure
+***********************************************************************/
+
+void delete_user(struct ip_acct_user_s *p)
+{
+       int hashval = IPAU_HASHVAL(p->uid);
+       
+       if (p->prev)
+       {
+               p->prev->succ = p->succ;
+               if (p->succ) p->succ->prev = p->prev;
+       }
+       else
+       {
+               user_stat[hashval] = p->succ;
+               if (user_stat[hashval]) user_stat[hashval]->prev = NULL;
+       }
+       kfree(p);
+}
+
+/***********************************************************************
+ used for ctrl access in ipacct. It is not used by kernel!
+***********************************************************************/
+
+static int
+ctrl_access(struct ip_acct_user_ctrl_entry *ct)
+{
+
+  struct ip_acct_user_s *p, *q;
+
+#ifdef DEBUG
+  printk("ipacct: ctrl access (uid %i, flags %x).\n",ct->uid, ct->flags);
+#endif
+
+  if (ct->uid == 0)
+       return -EPERM;          /* even root cannot change the flags */
+                               /* for the root account            */
+
+  cli();
+
+  if (ct->r_addr == 0) {
+
+    if ((p = find_user(ct->uid))) 
+      {
+       p->flags = ct->flags;
+      }
+    else if (ct->flags)
+      {
+       if ((p = create_user(ct->uid)) == NULL) return -ENOMEM;
+       
+       p->sent   = 0;
+       p->recv   = 0;
+       p->flags  = ct->flags;
+
+      }
+  }
+  else {
+    if ((p = find_user(ct->uid)))
+      {
+       p->flags = ct->flags;
+      }
+    else if (ct->flags)
+      {
+       if ((q = find_user(ct->uid)))
+         {
+           // total entry for user exists..
+           if ((p=create_user(ct->uid)) == NULL) return -ENOMEM;
+           p->sent=p->recv=0;
+           p->flags=ct->flags;
+         }
+       else
+         {
+           // create total entry first...
+           if ((q=create_user(ct->uid)) == NULL) return -ENOMEM;
+           q->sent=q->recv=0;
+           q->flags=0;
+         }
+      }
+  }
+
+  sti();
+  
+  return 0;
+}
+
+/***********************************************************************
+ used for reseting counters in ipacct. It is not used by kernel!
+***********************************************************************/
+
+static int
+reset_counter(int uid)
+{
+  struct ip_acct_user_s *p, *succ; 
+  struct ip_acct_user_s **p_users;
+  int numofips;
+  int i,j;
+  int result = 0;
+
+#ifdef DEBUG
+  printk("ipacct: reset counter (uid %i).\n",uid);
+#endif
+
+  if (uid>=0)
+  {
+    cli();
+
+    p_users=get_all_entries_of_user((uid_t)uid,&numofips);
+
+    if (p_users) {
+      for(j=0;j<numofips;j++) {
+       p=p_users[j];
+       
+       if ((p->reset >= IPAU_RESET_FREE) && !(p->flags)) {
+
+         delete_user(p);
+       }
+       else {
+         if (p->sent + p->recv) { 
+           p->sent = p->recv = p->reset = 0;
+         } 
+         else {
+           p->reset++;
+         }
+       }
+    
+      }
+      kfree(p_users);
+    }
+    else result = -EINVAL;
+    sti();
+  } 
+  else
+  {
+    cli();
+    for(i=0;i<IPAU_HASHMAX; i++)
+    {
+      p = user_stat[i];
+      while (p)
+       {
+        succ = p->succ;
+        if ((p->reset >= IPAU_RESET_FREE) && !(p->flags))
+          {
+            
+            delete_user(p);
+          }
+         else
+          {  
+            if (p->sent + p->recv)
+              {
+                p->sent = p->recv = p->reset = 0;
+              }
+            else
+              {
+                p->reset++;
+              }
+          }
+        p = succ;
+       }
+    }
+    sti();
+  }
+  return result;
+}
+
+
+/***********************************************************************
+ used to check wich user is allowed to connect outside
+ hacked a little by Ivo Velichkov removed the raddr
+***********************************************************************/
+
+int
+ip_acct_user_allowed(uid_t user, unsigned long daddr)
+{
+  struct ip_acct_user_s *p, *q;
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+
+  /* check first if user is allowed to connect to that IP */
+  if ( q = find_user(user) ) {
+
+#ifdef DEBUG
+    printk("found user -- %i -- daddr %u flags: %u\n",user, daddr, q->flags);
+#endif
+
+    if ((q->flags & IPAU_NO_ACCESS)) {
+      restore_flags(flags);
+      return 0;
+    }
+  
+  }
+  if ((p = find_user(user)))
+  {
+    if ((p->flags & IPAU_NO_ACCESS) && get_weight(&user_weight_list, daddr))
+    {
+      restore_flags(flags);
+      return 0;
+    }
+  }
+  restore_flags(flags);
+  return 1;
+}
+
+/***********************************************************************
+ used to account the sent packets
+ hacked a little by Ivo Velichkov changed the way info is stored
+***********************************************************************/
+
+int
+ip_acct_user_sent(uid_t user,unsigned long daddr, int sent)
+{
+  struct ip_acct_user_s *p;
+  /* struct ip_acct_user_s *p_ip; */
+  unsigned long flags;
+
+#ifdef DEBUG
+  printk("ipacct: user %i daddr %li sent %i\n",user,daddr,sent);
+#endif
+
+  save_flags(flags);
+  cli();
+
+  if ((p = find_user(user))) 
+  {
+  
+    p->sent += sent*get_weight(&user_weight_list, daddr);
+    
+  }
+  else
+  {
+    if ((p = create_user(user)) == NULL) return -ENOMEM;
+    
+    p->sent   = sent*get_weight(&user_weight_list, daddr);
+    p->recv   = 0;
+    p->flags  = 0;
+
+  }
+  restore_flags(flags);
+
+  return 0;
+}
+
+/***********************************************************************
+ used to account the received packets
+ hacked a little by Ivo Velichkov changed the way info is stored
+***********************************************************************/
+
+int
+ip_acct_user_received(uid_t user, unsigned long daddr, int recv)
+{
+  struct ip_acct_user_s *p;
+  unsigned long flags;
+
+#ifdef DEBUG
+  printk("ipacct: user %i daddr %li recv %i\n",user,daddr,recv);
+#endif
+
+  save_flags(flags);
+  cli();
+  if ((p = find_user(user))) 
+  {
+  
+    p->recv += recv*get_weight(&user_weight_list, daddr);
+
+  }
+  else
+  {
+    if ((p = create_user(user)) == NULL) return -ENOMEM;
+    
+    p->sent   = 0;
+    p->recv   = recv*get_weight(&user_weight_list, daddr);
+    p->flags  = 0;
+
+  }
+  restore_flags(flags);
+
+  return 0;
+}
+
+/***********************************************************************
+ used to display /proc/net/ip_acct_user
+ hacked a little by Ivo Velichkov changed the way info is stored
+***********************************************************************/
+
+int
+ip_acct_user_get_uinfo(char *buffer, char **start, off_t offset, int length)
+{
+       struct ip_acct_user_s *p, *succ;
+       int i;  
+       int len=0;
+       int last_len=0;
+       off_t pos=0;
+       off_t begin=0;
+       unsigned long flags;
+  
+#ifdef DEBUG
+       printk("ipacct: get user info.\n");
+#endif
+  
+       len+=sprintf(buffer, "uid      sent       recv       flags\n");
+
+
+       for(i = 0; i < IPAU_HASHMAX; i++) 
+       {
+               save_flags(flags);
+               cli();
+
+               p = user_stat[i];
+               while(p != NULL) 
+               {
+                       succ = p->succ;
+		       len+=sprintf(buffer+len,"%-8i %-10i %-10i %02X\n",p->uid,p->sent,p->recv,p->flags);
+                       
+                       pos=begin+len;
+                       if(pos<offset)
+                       {
+                               len=0;
+                               begin=pos;
+                       }
+                       else if(pos>offset+length) 
+                       {
+                               len = last_len;
+                               break;          
+                       }
+
+                       last_len = len;
+                       p = succ;
+               }
+               
+               restore_flags(flags);
+       
+               if(pos>offset+length)
+                       break;
+       }
+       *start=buffer+(offset-begin);
+       len-=(offset-begin);
+       if(len>length)
+               len=length;
+       return len;
+} 
+
+/***********************************************************************/
+
+int
+ip_acct_user_get_winfo(char *buffer, char **start, off_t offset, int length)
+{
+       return get_weight_info(&user_weight_list, buffer, start, offset, length);
+} 
+
+
+
+/***********************************************************************
+ used to init the information in proc system
+***********************************************************************/
+
+void 
+ip_acct_user_init(void)
+{
+       int i;
+
+	/* Changed to the 2.4.x calling convention
+		25th June 2001: Chris Crowther <shadow@shad0w.org.uk> */
+	proc_net_create("ip_acct_user",S_IFREG|S_IRUGO|S_IWUSR,ip_acct_user_get_uinfo);
+	proc_net_create("ip_acct_weight",S_IFREG|S_IRUGO|S_IWUSR,ip_acct_user_get_winfo);
+
+       printk(IPAU_VERSION);
+
+       for(i=0; i<IPAU_HASHMAX; i++) user_stat[i] = NULL;
+
+       user_weight_list.head = user_weight_list.tail = NULL;
+       user_weight_list.default_weight = IPAU_DEF_WEIGHT;
+
+       /* initialise control entry struct */
+
+
+}
+
+/***********************************************************************/
+
+int ip_acct_user_ioctl(unsigned int cmd, void *arg)
+{
+       int err;
+       int uid;
+       struct ip_acct_user_ctrl_entry ct;
+       struct ip_acct_weight_entry wt;
+
+       switch(cmd) 
+       {
+               case SIOCADDWT:         /* Add a weight */
+               case SIOCDELWT:         /* Delete a weight */
+                       if (!suser())
+                               return -EPERM;
+                       err=!access_ok(VERIFY_READ, arg, sizeof(struct ip_acct_weight_entry));
+                       if (err)
+                               return err;
+                       copy_from_user(&wt, arg, sizeof(struct ip_acct_weight_entry));
+                       return (cmd == SIOCADDWT) ? add_addr(&user_weight_list, &wt) : del_addr(&user_weight_list, &wt);
+               case SIOCRSTUT:         /* Reset user table */
+                       if (!suser())
+                               return -EPERM;
+                       err=!access_ok(VERIFY_READ, arg, sizeof(int));
+                       if (err)
+                               return err;
+                       copy_from_user(&uid, arg, sizeof(int));
+                       return (reset_counter(uid));
+               case SIOCCTRLU:         /* Ctrl user access */
+                       if (!suser())
+                               return -EPERM;
+                       err=!access_ok(VERIFY_READ, arg, sizeof(struct ip_acct_user_ctrl_entry));
+                       if (err)
+                               return err;
+                       copy_from_user(&ct, arg, sizeof(struct ip_acct_user_ctrl_entry));
+                       return (ctrl_access(&ct));
+       }
+
+       return -EINVAL;
+}
+

diff -urN -X dontdiff linux-2.4/net/ipv4/ip_output.c linux-2.4.6-ipacct/net/ipv4/ip_output.c
--- linux-2.4/net/ipv4/ip_output.c	Thu Jul  5 15:29:39 2001
+++ linux-2.4.6-ipacct/net/ipv4/ip_output.c	Thu Jul  5 15:43:27 2001
@@ -76,6 +76,9 @@
 #include <linux/netfilter_ipv4.h>
 #include <linux/mroute.h>
 #include <linux/netlink.h>
+#ifdef CONFIG_IP_ACCT_USER
+#include <linux/ip_acct_user.h>
+#endif
 
 /*
  *      Shall we try to damage output packets if routing dev changes?
@@ -368,6 +371,14 @@
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto no_route;
 
+#ifdef CONFIG_IP_ACCT_USER
+        /*
+         * IS the user allowed to send
+         */
+        if ((skb->sk) && (skb->sk->socket) && !ip_acct_user_allowed(SOCK_INODE(skb->sk->socket)->i_uid,sk->daddr))
+                return (-EPERM);
+#endif
+
 	/* OK, we know where to send it, allocate and build IP header. */
 	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
 	*((__u16 *)iph)	= htons((4 << 12) | (5 << 8) | (sk->protinfo.af_inet.tos & 0xff));
@@ -379,6 +390,15 @@
 	iph->daddr    = rt->rt_dst;
 	skb->nh.iph   = iph;
 	/* Transport layer set skb->h.foo itself. */
+
+#ifdef CONFIG_IP_ACCT_USER
+        if (sk && sk->socket) {
+          ip_acct_user_sent(SOCK_INODE(sk->socket)->i_uid, iph->daddr,ntohs(iph->tot_len));
+        }  
+        else {
+          ip_acct_user_sent(IPAU_NOUSER, iph->daddr, ntohs(iph->tot_len));
+        }
+#endif
 
 	if(opt && opt->optlen) {
 		iph->ihl += opt->optlen >> 2;
diff -urN -X dontdiff linux-2.4/net/ipv4/raw.c linux-2.4.6-ipacct/net/ipv4/raw.c
--- linux-2.4/net/ipv4/raw.c	Thu Jul  5 15:29:39 2001
+++ linux-2.4.6-ipacct/net/ipv4/raw.c	Thu Jul  5 15:43:27 2001
@@ -64,6 +64,10 @@
 #include <net/raw.h>
 #include <net/inet_common.h>
 #include <net/checksum.h>
+#ifdef CONFIG_IP_ACCT_USER
+#include <linux/ip_acct_user.h>
+#endif
+
 
 struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
 rwlock_t raw_v4_lock = RW_LOCK_UNLOCKED;
@@ -237,6 +241,10 @@
 		kfree_skb(skb);
 		return NET_RX_DROP;
 	}
+
+#ifdef CONFIG_IP_ACCT_USER
+        if (sk->socket) ip_acct_user_received(SOCK_INODE(skb->sk->socket)->i_uid, skb->nh.iph->saddr, ntohs(skb->nh.iph->tot_len));
+#endif
 
 	IP_INC_STATS(IpInDelivers);
 	return NET_RX_SUCCESS;
diff -urN -X dontdiff linux-2.4/net/ipv4/tcp_ipv4.c linux-2.4.6-ipacct/net/ipv4/tcp_ipv4.c
--- linux-2.4/net/ipv4/tcp_ipv4.c	Sun May 13 15:06:52 2001
+++ linux-2.4.6-ipacct/net/ipv4/tcp_ipv4.c	Thu Jul  5 15:43:27 2001
@@ -63,6 +63,10 @@
 #include <linux/stddef.h>
 #include <linux/ipsec.h>
 
+#ifdef CONFIG_IP_ACCT_USER
+#include <linux/ip_acct_user.h>
+#endif
+
 extern int sysctl_ip_dynaddr;
 
 /* Check TCP sequence numbers in ICMP packets. */
@@ -1645,6 +1649,11 @@
 
 	bh_lock_sock(sk);
 	ret = 0;
+
+#ifdef CONFIG_IP_ACCT_USER
+        if (sk->socket) ip_acct_user_received(SOCK_INODE(sk->socket)->i_uid, skb->nh.iph->saddr, ntohs(skb->nh.iph->tot_len));
+#endif
+
 	if (!sk->lock.users) {
 		if (!tcp_prequeue(sk, skb))
 			ret = tcp_v4_do_rcv(sk, skb);
diff -urN -X dontdiff linux-2.4/net/ipv4/udp.c linux-2.4.6-ipacct/net/ipv4/udp.c
--- linux-2.4/net/ipv4/udp.c	Sun May 13 15:06:52 2001
+++ linux-2.4.6-ipacct/net/ipv4/udp.c	Thu Jul  5 15:43:27 2001
@@ -93,6 +93,9 @@
 #include <net/route.h>
 #include <net/inet_common.h>
 #include <net/checksum.h>
+#ifdef CONFIG_IP_ACCT_USER
+#include <linux/ip_acct_user.h>
+#endif
 
 /*
  *	Snmp MIB for the UDP layer
@@ -904,7 +907,13 @@
 
 	sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);
 
+
 	if (sk != NULL) {
+/* This seems like a logical place to call this from.
+	25th June 2001: Chris Crowther <shadow@shad0w.org.uk> */
+#ifdef CONFIG_IP_ACCT_USER
+		ip_acct_user_received((SOCK_INODE(sk->socket))->i_uid, saddr, ntohs(skb->nh.iph->tot_len));
+#endif
 		udp_queue_rcv_skb(sk, skb);
 		sock_put(sk);
 		return 0;
