diff -urN -X dontdiff linux-2.4/Documentation/Configure.help linux-2.4-ipacct/Documentation/Configure.help --- linux-2.4/Documentation/Configure.help Sat May 26 10:49:23 2001 +++ linux-2.4-ipacct/Documentation/Configure.help Mon Jun 25 12:52:58 2001 @@ -4939,6 +4939,15 @@ If unsure, say Y. +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. + Routing messages CONFIG_RTNETLINK If you say Y here, user space programs can receive some network diff -urN -X dontdiff linux-2.4/Makefile linux-2.4-ipacct/Makefile --- linux-2.4/Makefile Sat May 26 10:49:24 2001 +++ linux-2.4-ipacct/Makefile Mon Jun 25 15:41:45 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 5 -EXTRAVERSION = +EXTRAVERSION = -ipacct KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN -X dontdiff linux-2.4/arch/i386/defconfig linux-2.4-ipacct/arch/i386/defconfig --- linux-2.4/arch/i386/defconfig Sat May 26 10:49:25 2001 +++ linux-2.4-ipacct/arch/i386/defconfig Tue Jun 19 10:30:49 2001 @@ -156,6 +156,7 @@ # CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set +CONFIG_IP_ACCT_USER=y # # diff -urN -X dontdiff linux-2.4/include/linux/ip_acct_user.h linux-2.4-ipacct/include/linux/ip_acct_user.h --- linux-2.4/include/linux/ip_acct_user.h Thu Jan 1 01:00:00 1970 +++ linux-2.4-ipacct/include/linux/ip_acct_user.h Mon Jun 25 15:55:08 2001 @@ -0,0 +1,161 @@ +/* + * 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 + +#define IPAU_VERSION "UserIPAcct: version @VERSION@\n" + +#define IPAU_NOUSER (uid_t)(@NOBODY@) /* 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 */ +struct ip_acct_user_ctrl_entry { + + uid_t uid; + int flags; + unsigned long r_addr; + +}; + +/* sructure for argument to SIOCADDCE ioctl --- to make above obsolete*/ +struct ip_acct_user_new_ctrl_entry { + + uid_t uid; + /* policy (accept=1,deny=0) */ + int policy; + /* type (default change=0, remote address=1, local address=2) */ + int type; + /* address if needed */ + unsigned long addr; + /* mask if needed */ + unsigned long mask; +}; + +/* 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*/ + unsigned long r_addr; /* Remote IP address - added 21/2/1999 ZM */ + 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-ipacct/net/ipv4/Config.in --- linux-2.4/net/ipv4/Config.in Sat May 26 10:49:55 2001 +++ linux-2.4-ipacct/net/ipv4/Config.in Tue Jun 19 15:51:08 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-ipacct/net/ipv4/Makefile --- linux-2.4/net/ipv4/Makefile Fri Dec 29 22:07:24 2000 +++ linux-2.4-ipacct/net/ipv4/Makefile Tue Jun 19 15:54:00 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-ipacct/net/ipv4/af_inet.c --- linux-2.4/net/ipv4/af_inet.c Sat May 26 10:49:55 2001 +++ linux-2.4-ipacct/net/ipv4/af_inet.c Tue Jun 19 15:56:59 2001 @@ -100,6 +100,9 @@ #include #include #include +#ifdef CONFIG_IP_ACCT_USER +#include +#endif #ifdef CONFIG_IP_MROUTE #include #endif @@ -844,6 +847,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: @@ -1027,6 +1037,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/net/ipv4/ip_acct_user.c linux-2.4-ipacct/net/ipv4/ip_acct_user.c --- linux-2.4/net/ipv4/ip_acct_user.c Thu Jan 1 01:00:00 1970 +++ linux-2.4-ipacct/net/ipv4/ip_acct_user.c Mon Jun 25 16:07:06 2001 @@ -0,0 +1,870 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#include + +#include + +#define VERIFY_READ 0 + +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; */ + +/***********************************************************************/ +/***********************************************************************/ + +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; +} + +/***********************************************************************/ + +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; +} + +/***********************************************************************/ + +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; +} + +/***********************************************************************/ + +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; +} + +/***********************************************************************/ + +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(posoffset+length) break; + } + sti(); + + if (pos<=offset+length) { + + len+=sprintf(buffer+len,"%08lX\t%08lX\t%-5i\n",htonl(0x00000000),htonl(0xffffffff),wlist->default_weight); + + pos=begin+len; + if(poslength) + len=length; + return len; +} + +/***********************************************************************/ +/***********************************************************************/ + +/* Added remote address part 21/02/1999 - Zaheer Merali * + * - returns the pointer that points to the total usage by user */ + +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) && ((p->r_addr) == 0) ) + break; + p=p->succ; + } + +#ifdef DEBUG + if ((p != NULL) && (p->magic != IPAU_MAGIC)) + { + printk("ipacct: user list corrupt.\n"); + p = NULL; + } +#endif + + return p; +} + +/* find_user_with_ip added 21/02/1999 - Zaheer Merali * + * - returns the pointer that points to the usage by the user with the * + * specific remote IP */ + +static struct ip_acct_user_s * +find_user_with_ip(uid_t user, unsigned long raddr) +{ + struct ip_acct_user_s *p = user_stat[IPAU_HASHVAL(user)]; + + while (p!=NULL) { + if ( ((p->uid) == user) && (((p->r_addr) ^ raddr)==0) ) { + break; + } + 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 * + * - 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 && userindexuid) != user)) p=p->succ; + else p_users[userindex++]=p; + } + + *numofusers=userindex; + + return p_users; +} + + +/***********************************************************************/ + +/* Added remote address part 21/02/1999 - Zaheer Merali */ + +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->r_addr = 0; + + 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 %i\n",user,p); +#endif + return p; +} + +/* Adds with remote IP - Zaheer Merali 21/02/1999 */ + +static struct ip_acct_user_s *create_user_with_ip(uid_t user,unsigned long raddr) +{ + struct ip_acct_user_s *p; + int hashval = IPAU_HASHVAL(user); + + + + + + 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->r_addr = raddr; + + p->sent=p->recv=0; + + 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("ipacct: create user (uid %i ip %s memref %i).\n",user,in_ntoa(raddr),p); +#endif + + return p; +} + +/***********************************************************************/ + +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); +} + +/***********************************************************************/ + +/* Added remote ip address checking 23/2/1999 * + * - Zaheer Merali */ + +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_with_ip(ct->uid,ct->r_addr))) + { + p->flags = ct->flags; + } + else if (ct->flags) + { + if ((q = find_user(ct->uid))) + { + // total entry for user exists.. + if ((p=create_user_with_ip(ct->uid,ct->r_addr)) == 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; + + // now create entry with ip.. + if ((p=create_user_with_ip(ct->uid,ct->r_addr)) == NULL) return -ENOMEM; + p->sent=p->recv=0; + p->flags=ct->flags; + } + } + } + + sti(); + + return 0; +} + +/***********************************************************************/ + +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;jreset >= 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;isucc; + 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; +} + +/***********************************************************************/ + +int +ip_acct_user_allowed(uid_t user, unsigned long daddr) +{ + struct ip_acct_user_s *p, *q; + unsigned long flags; + +#ifdef DEBUG + printk("ip_acct_user_allowed: %i %s\n",user,in_ntoa(daddr)); +#endif + + save_flags(flags); + cli(); + + /* check first if user is allowed to connect to that IP */ + if ((q = find_user_with_ip(user,daddr))) { +#ifdef DEBUG + printk("found user with ip, flags: %u\n",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; +} + +/***********************************************************************/ + +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 %s sent %i\n",user,in_ntoa(daddr),sent); +#endif + + save_flags(flags); + cli(); + if ((p = find_user(user))) + { + + p->sent += sent*get_weight(&user_weight_list, daddr); + + if ((p_ip = find_user_with_ip(user,daddr))) { + p_ip->sent+=sent*get_weight(&user_weight_list,daddr); + } + else { + if ((p_ip=create_user_with_ip(user,daddr)) ==NULL) return -ENOMEM; + + p_ip->sent = sent*get_weight(&user_weight_list, daddr); + p_ip->recv=0; + p_ip->flags=0; + } + + + } + else + { + if ((p = create_user(user)) == NULL) return -ENOMEM; + + p->sent = sent*get_weight(&user_weight_list, daddr); + p->recv = 0; + p->flags = 0; + + if ((p_ip = create_user_with_ip(user,daddr)) == NULL) return -ENOMEM; + + p_ip->sent = sent*get_weight(&user_weight_list,daddr); + p_ip->recv=0; + p_ip->flags=0; + + } + restore_flags(flags); + + return 0; +} + +int +ip_acct_user_received(uid_t user, unsigned long daddr, int recv) +{ + struct ip_acct_user_s *p; + struct ip_acct_user_s *p_ip; + unsigned long flags; + +#ifdef DEBUG + printk("ipacct: user %i daddr %s recv %i\n",user,in_ntoa(daddr),recv); +#endif + + save_flags(flags); + cli(); + if ((p = find_user(user))) + { + + p->recv += recv*get_weight(&user_weight_list, daddr); + + if ((p_ip = find_user_with_ip(user,daddr))) { + //printk("ip_acct_user_received: found user %i with ip %s\n",user,in_ntoa(daddr)); + p_ip->recv+=recv*get_weight(&user_weight_list,daddr); + } + else { + //printk("ip_acct_user_received: did not find user %i with ip %s\n",user,in_ntoa(daddr)); + if ((p_ip=create_user_with_ip(user,daddr)) ==NULL) return -ENOMEM; + + p_ip->recv = recv*get_weight(&user_weight_list, daddr); + p_ip->sent=0; + p_ip->flags=0; + } + } + else + { + if ((p = create_user(user)) == NULL) return -ENOMEM; + + p->sent = 0; + p->recv = recv*get_weight(&user_weight_list, daddr); + p->flags = 0; + + + if ((p_ip = create_user_with_ip(user,daddr)) == NULL) return -ENOMEM; + + p_ip->recv = recv*get_weight(&user_weight_list,daddr); + p_ip->sent=0; + p_ip->flags=0; + } + restore_flags(flags); + + return 0; +} + +/***********************************************************************/ + +/* I've removed the reset code from this as a quick-fix, because I couldn't + figure out how to do it in the time I had (ie, not much). + 25th June 2001: Chris Crowther */ +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 remote ip 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; + + if (p->r_addr==0) + len+=sprintf(buffer+len,"%-8i %-15s %-10i %-10i %02X\n",p->uid,"*",p->sent,p->recv,p->flags); + else + len+=sprintf(buffer+len,"%-8i %-15s %-10i %-10i %02X\n",p->uid,in_ntoa(p->r_addr),p->sent,p->recv,p->flags); + + pos=begin+len; + if(posoffset+length) + { + len = last_len; + break; + } +/* + else if(reset) + { + 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++; + } + } + } +*/ + 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); +} + +/***********************************************************************/ + +void +ip_acct_user_init(void) +{ + int i; + + /* Changed to the 2.4.x calling convention + 25th June 2001: Chris Crowther */ + 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 #include #include +#ifdef CONFIG_IP_ACCT_USER +#include +#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-ipacct/net/ipv4/raw.c --- linux-2.4/net/ipv4/raw.c Sat May 26 10:49:56 2001 +++ linux-2.4-ipacct/net/ipv4/raw.c Tue Jun 19 17:09:15 2001 @@ -64,6 +64,10 @@ #include #include #include +#ifdef CONFIG_IP_ACCT_USER +#include +#endif + struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE]; rwlock_t raw_v4_lock = RW_LOCK_UNLOCKED; @@ -234,6 +238,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-ipacct/net/ipv4/tcp_ipv4.c --- linux-2.4/net/ipv4/tcp_ipv4.c Sun May 13 15:06:52 2001 +++ linux-2.4-ipacct/net/ipv4/tcp_ipv4.c Tue Jun 19 17:10:29 2001 @@ -63,6 +63,10 @@ #include #include +#ifdef CONFIG_IP_ACCT_USER +#include +#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-ipacct/net/ipv4/udp.c --- linux-2.4/net/ipv4/udp.c Sun May 13 15:06:52 2001 +++ linux-2.4-ipacct/net/ipv4/udp.c Mon Jun 25 16:08:04 2001 @@ -93,6 +93,9 @@ #include #include #include +#ifdef CONFIG_IP_ACCT_USER +#include +#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 */ +#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;