#define DEBUGP(format, args...)
#endif
+#if (PAGE_SIZE < 4096)
+#error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096"
+#endif
+
struct ipt_account_table *ipt_account_tables = NULL;
struct ipt_account_handle *ipt_account_handles = NULL;
void *ipt_account_tmpbuf = NULL;
/* Recursive free of all data structures */
-void ipt_account_data_free(void *data, unsigned char depth) {
+void ipt_account_data_free(void *data, unsigned char depth)
+{
/* Empty data set */
if (!data)
return;
unsigned int a, b;
for (a=0; a <= 255; a++) {
if (((struct ipt_account_mask_8 *)data)->mask_16[a]) {
- struct ipt_account_mask_16 *mask_16 = (struct ipt_account_mask_16*)((struct ipt_account_mask_8 *)data)->mask_16[a];
+ struct ipt_account_mask_16 *mask_16 = (struct ipt_account_mask_16*)
+ ((struct ipt_account_mask_8 *)data)->mask_16[a];
+
for (b=0; b <= 255; b++) {
if (mask_16->mask_24[b]) {
free_page((unsigned long)mask_16->mask_24[b]);
}
/* Look for existing table / insert new one. Return internal ID or -1 on error */
-int ipt_account_table_insert(char *name, unsigned int ip, unsigned int netmask) {
+int ipt_account_table_insert(char *name, unsigned int ip, unsigned int netmask)
+{
unsigned int i;
- DEBUGP("ACCOUNT: ipt_account_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n", name, NIPQUAD(ip), NIPQUAD(netmask));
+ DEBUGP("ACCOUNT: ipt_account_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n",
+ name, NIPQUAD(ip), NIPQUAD(netmask));
/* Look for existing table */
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
NIPQUAD(ipt_account_tables[i].ip), NIPQUAD(ipt_account_tables[i].netmask));
if (ipt_account_tables[i].ip != ip || ipt_account_tables[i].netmask != netmask) {
- printk("ACCOUNT: Table %s found, but IP/netmask mismatch. IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
+ printk("ACCOUNT: Table %s found, but IP/netmask mismatch. IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
name, NIPQUAD(ipt_account_tables[i].ip), NIPQUAD(ipt_account_tables[i].netmask));
return -1;
}
else if(netsize >= 8)
ipt_account_tables[i].depth = 2;
- printk("ACCOUNT: calculated netsize: %u -> ipt_account_table depth %u\n", netsize, ipt_account_tables[i].depth);
+ DEBUGP("ACCOUNT: calculated netsize: %u -> ipt_account_table depth %u\n",
+ netsize, ipt_account_tables[i].depth);
ipt_account_tables[i].refcount++;
- if ((ipt_account_tables[i].data = (void *)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if ((ipt_account_tables[i].data = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: out of memory for data of table: %s\n", name);
memset(&ipt_account_tables[i], 0, sizeof(struct ipt_account_table));
return -1;
const struct ipt_entry *e,
void *targinfo,
unsigned int targinfosize,
- unsigned int hook_mask) {
+ unsigned int hook_mask)
+{
struct ipt_account_info *info = targinfo;
if (targinfosize != IPT_ALIGN(sizeof(struct ipt_account_info))) {
return 1;
}
-void ipt_account_deleteentry(void *targinfo, unsigned int targinfosize) {
+void ipt_account_deleteentry(void *targinfo, unsigned int targinfosize)
+{
unsigned int i;
struct ipt_account_info *info = targinfo;
spin_unlock_bh(&ipt_account_lock);
}
-void ipt_account_depth0_insert(struct ipt_account_mask_24 *mask_24, unsigned int net_ip, unsigned int netmask,
- unsigned int src_ip, unsigned int dst_ip, unsigned int size, unsigned int *itemcount) {
+void ipt_account_depth0_insert(struct ipt_account_mask_24 *mask_24,
+ unsigned int net_ip, unsigned int netmask,
+ unsigned int src_ip, unsigned int dst_ip,
+ unsigned int size, unsigned int *itemcount)
+{
unsigned char is_src = 0, is_dst = 0;
DEBUGP("ACCOUNT: ipt_account_depth0_insert: %u.%u.%u.%u/%u.%u.%u.%u for net %u.%u.%u.%u/%u.%u.%u.%u, size: %u\n",
DEBUGP("ACCOUNT: Itemcounter after: %d\n", *itemcount);
}
-void ipt_account_depth1_insert(struct ipt_account_mask_16 *mask_16, unsigned int net_ip, unsigned int netmask,
- unsigned int src_ip, unsigned int dst_ip, unsigned int size, unsigned int *itemcount) {
+void ipt_account_depth1_insert(struct ipt_account_mask_16 *mask_16, unsigned int net_ip,
+ unsigned int netmask, unsigned int src_ip, unsigned int dst_ip,
+ unsigned int size, unsigned int *itemcount)
+{
/* Do we need to process src IP? */
if ((net_ip&netmask) == (src_ip&netmask)) {
unsigned char slot = (unsigned char)((src_ip&0x00FF0000) >> 16);
DEBUGP("ACCOUNT: Calculated SRC 16 bit network slot: %d\n", slot);
/* Do we need to create a new mask_24 bucket? */
- if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] = (void *)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: Can't process packet because out of memory!\n");
return;
}
DEBUGP("ACCOUNT: Calculated DST 16 bit network slot: %d\n", slot);
/* Do we need to create a new mask_24 bucket? */
- if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] = (void *)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUT: Can't process packet because out of memory!\n");
return;
}
}
}
-void ipt_account_depth2_insert(struct ipt_account_mask_8 *mask_8, unsigned int net_ip, unsigned int netmask,
- unsigned int src_ip, unsigned int dst_ip, unsigned int size, unsigned int *itemcount) {
+void ipt_account_depth2_insert(struct ipt_account_mask_8 *mask_8, unsigned int net_ip,
+ unsigned int netmask, unsigned int src_ip, unsigned int dst_ip,
+ unsigned int size, unsigned int *itemcount)
+{
/* Do we need to process src IP? */
if ((net_ip&netmask) == (src_ip&netmask)) {
unsigned char slot = (unsigned char)((src_ip&0x0000FF00) >> 8);
DEBUGP("ACCOUNT: Calculated SRC 24 bit network slot: %d\n", slot);
/* Do we need to create a new mask_24 bucket? */
- if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot] = (void *)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot] = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: Can't process packet because out of memory!\n");
return;
}
DEBUGP("ACCOUNT: Calculated DST 24 bit network slot: %d\n", slot);
/* Do we need to create a new mask_24 bucket? */
- if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot] = (void *)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot] = (void *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: Can't process packet because out of memory!\n");
return;
}
const struct net_device *in,
const struct net_device *out,
const void *targinfo,
- void *userinfo) {
+ void *userinfo)
+{
const struct ipt_account_info *info = (const struct ipt_account_info *)targinfo;
unsigned int src_ip = (*pskb)->nh.iph->saddr;
unsigned int dst_ip = (*pskb)->nh.iph->daddr;
but there could be two or more applications accessing the data
at the same time.
*/
-int ipt_account_handle_find_slot(void) {
+int ipt_account_handle_find_slot(void)
+{
unsigned int i;
/* Insert new table */
for (i = 0; i < ACCOUNT_MAX_HANDLES; i++) {
return -1;
}
-int ipt_account_handle_free(unsigned int handle) {
+int ipt_account_handle_free(unsigned int handle)
+{
if (handle >= ACCOUNT_MAX_HANDLES) {
printk("ACCOUNT: Invalid handle for ipt_account_handle_free() specified: %u\n", handle);
return -EINVAL;
/* Prepare data for read without flush. Use only for debugging!
Real applications should use read&flush as it's way more efficent */
-int ipt_account_handle_prepare_read(char *tablename, unsigned int *count) {
+int ipt_account_handle_prepare_read(char *tablename, unsigned int *count)
+{
int handle, i, table_nr=-1;
for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
ipt_account_handles[handle].itemcount = ipt_account_tables[table_nr].itemcount;
/* allocate "root" table */
- if ((ipt_account_handles[handle].data = (void*)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if ((ipt_account_handles[handle].data = (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: out of memory for root table in ipt_account_handle_prepare_read()\n");
memset (&ipt_account_handles[handle], 0, sizeof(struct ipt_account_handle));
return -1;
for (b = 0; b <= 255; b++) {
if (src_16->mask_24[b]) {
- if ((network_16->mask_24[b] = (void*)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if ((network_16->mask_24[b] = (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: out of memory during copy of 16 bit network in ipt_account_handle_prepare_read()\n");
ipt_account_data_free(ipt_account_handles[handle].data, depth);
memset (&ipt_account_handles[handle], 0, sizeof(struct ipt_account_handle));
for (a = 0; a <= 255; a++) {
if (src_8->mask_16[a]) {
- if ((network_8->mask_16[a] = (void*)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if ((network_8->mask_16[a] = (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: out of memory during copy of 24 bit network in ipt_account_handle_prepare_read()\n");
ipt_account_data_free(ipt_account_handles[handle].data, depth);
memset (&ipt_account_handles[handle], 0, sizeof(struct ipt_account_handle));
for (b = 0; b <= 255; b++) {
if (src_16->mask_24[b]) {
- if ((network_16->mask_24[b] = (void*)get_zeroed_page(GFP_KERNEL)) == NULL) {
+ if ((network_16->mask_24[b] = (void*)get_zeroed_page(GFP_ATOMIC)) == NULL) {
printk("ACCOUNT: out of memory during copy of 16 bit network in ipt_account_handle_prepare_read()\n");
ipt_account_data_free(ipt_account_handles[handle].data, depth);
memset (&ipt_account_handles[handle], 0, sizeof(struct ipt_account_handle));
}
/* Prepare data for read and flush it */
-int ipt_account_handle_prepare_read_flush(char *tablename, unsigned int *count) {
+int ipt_account_handle_prepare_read_flush(char *tablename, unsigned int *count)
+{
int handle, i, table_nr=-1;
for (i = 0; i < ACCOUNT_MAX_TABLES; i++)
if ((handle = ipt_account_handle_find_slot()) == -1)
return -1;
+ /* Try to allocate memory */
+ void *new_data_page = (void*)get_zeroed_page(GFP_ATOMIC);
+ if (!new_data_page)
+ {
+ printk("ACCOUNT: ipt_account_handle_prepare_read_flush(): Out of memory!\n");
+ return -1;
+ }
+
/* Fill up handle structure */
ipt_account_handles[handle].ip = ipt_account_tables[table_nr].ip;
ipt_account_handles[handle].depth = ipt_account_tables[table_nr].depth;
*count = ipt_account_tables[table_nr].itemcount;
/* "Flush" table data */
- ipt_account_tables[table_nr].data = (void*)get_zeroed_page(GFP_KERNEL);
+ ipt_account_tables[table_nr].data = new_data_page;
ipt_account_tables[table_nr].itemcount = 0;
return handle;
}
-/* Copy the actual that into a prepared buffer.
+/* Copy 8 bit network data into a prepared buffer.
We only copy entries != 0 to increase performance.
- The memory gets freed again in ipt_account_handle_free().
*/
-int ipt_account_handle_get_data(unsigned int handle, void *buffer) {
+void ipt_account_handle_copy_data(void *to_user, int *pos, struct ipt_account_mask_24 *data,
+ unsigned int net_ip, unsigned int net_OR_mask)
+{
struct ipt_account_handle_ip handle_ip;
unsigned int handle_ip_size = sizeof (struct ipt_account_handle_ip);
- unsigned int i, tmpbuf_pos=0;
+
+ unsigned int i;
+
+ for (i = 0; i <= 255; i++) {
+ if (data->ip[i].src_packets || data->ip[i].dst_packets) {
+ handle_ip.ip = net_ip | net_OR_mask | (i<<24);
+
+ handle_ip.src_packets = data->ip[i].src_packets;
+ handle_ip.src_bytes = data->ip[i].src_bytes;
+ handle_ip.dst_packets = data->ip[i].dst_packets;
+ handle_ip.dst_bytes = data->ip[i].dst_bytes;
+
+ /* Temporary buffer full? Flush to userspace */
+ if (*pos+handle_ip_size >= PAGE_SIZE) {
+ copy_to_user(to_user, ipt_account_tmpbuf, *pos);
+ *pos = 0;
+ }
+ memcpy(ipt_account_tmpbuf+*pos, &handle_ip, handle_ip_size);
+ *pos += handle_ip_size;
+ }
+ }
+}
+
+/* Copy the data from our internal structure
+ We only copy entries != 0 to increase performance.
+ Overwrites ipt_account_tmpbuf.
+*/
+int ipt_account_handle_get_data(unsigned int handle, void *to_user)
+{
+ unsigned int tmpbuf_pos=0;
if (handle >= ACCOUNT_MAX_HANDLES) {
printk("ACCOUNT: invalid handle for ipt_account_handle_get_data() specified: %u\n", handle);
/* 8 bit network */
if (depth == 0) {
struct ipt_account_mask_24 *network = (struct ipt_account_mask_24*)ipt_account_handles[handle].data;
- for (i = 0; i <= 255; i++) {
- if (network->ip[i].src_packets || network->ip[i].dst_packets) {
- handle_ip.ip = net_ip | (i<<24);
- handle_ip.src_packets = network->ip[i].src_packets;
- handle_ip.src_bytes = network->ip[i].src_bytes;
- handle_ip.dst_packets = network->ip[i].dst_packets;
- handle_ip.dst_bytes = network->ip[i].dst_bytes;
-
- /* Temporary buffer full? Flush to userspace */
- if (tmpbuf_pos+handle_ip_size >= PAGE_SIZE) {
- copy_to_user(buffer, ipt_account_tmpbuf, tmpbuf_pos);
- tmpbuf_pos = 0;
- }
- memcpy(ipt_account_tmpbuf+tmpbuf_pos, &handle_ip, handle_ip_size);
- tmpbuf_pos += handle_ip_size;
- }
- }
-
+ ipt_account_handle_copy_data(to_user, &tmpbuf_pos, network, net_ip, 0);
+
/* Flush remaining data to userspace */
if (tmpbuf_pos)
- copy_to_user(buffer, ipt_account_tmpbuf, tmpbuf_pos);
+ copy_to_user(to_user, ipt_account_tmpbuf, tmpbuf_pos);
return 0;
}
for (b = 0; b <= 255; b++) {
if (network_16->mask_24[b]) {
struct ipt_account_mask_24 *network = (struct ipt_account_mask_24*)network_16->mask_24[b];
- for (i = 0; i <= 255; i++) {
- if (network->ip[i].src_packets || network->ip[i].dst_packets) {
- handle_ip.ip = net_ip | (b << 16) | (i<<24);
- handle_ip.src_packets = network->ip[i].src_packets;
- handle_ip.src_bytes = network->ip[i].src_bytes;
- handle_ip.dst_packets = network->ip[i].dst_packets;
- handle_ip.dst_bytes = network->ip[i].dst_bytes;
-
- /* Temporary buffer full? Flush to userspace */
- if (tmpbuf_pos+handle_ip_size >= PAGE_SIZE) {
- copy_to_user(buffer, ipt_account_tmpbuf, tmpbuf_pos);
- tmpbuf_pos = 0;
- }
- memcpy(ipt_account_tmpbuf+tmpbuf_pos, &handle_ip, handle_ip_size);
- tmpbuf_pos += handle_ip_size;
- }
- }
+ ipt_account_handle_copy_data(to_user, &tmpbuf_pos, network, net_ip, (b << 16));
}
}
/* Flush remaining data to userspace */
if (tmpbuf_pos)
- copy_to_user(buffer, ipt_account_tmpbuf, tmpbuf_pos);
+ copy_to_user(to_user, ipt_account_tmpbuf, tmpbuf_pos);
return 0;
}
for (b = 0; b <= 255; b++) {
if (network_16->mask_24[b]) {
struct ipt_account_mask_24 *network = (struct ipt_account_mask_24*)network_16->mask_24[b];
- for (i = 0; i <= 255; i++) {
- if (network->ip[i].src_packets || network->ip[i].dst_packets) {
- handle_ip.ip = net_ip | (a << 8) | (b << 16) | (i<<24);
- handle_ip.src_packets = network->ip[i].src_packets;
- handle_ip.src_bytes = network->ip[i].src_bytes;
- handle_ip.dst_packets = network->ip[i].dst_packets;
- handle_ip.dst_bytes = network->ip[i].dst_bytes;
-
- /* Temporary buffer full? Flush to userspace */
- if (tmpbuf_pos+handle_ip_size >= PAGE_SIZE) {
- copy_to_user(buffer, ipt_account_tmpbuf, tmpbuf_pos);
- tmpbuf_pos = 0;
- }
- memcpy(ipt_account_tmpbuf+tmpbuf_pos, &handle_ip, handle_ip_size);
- tmpbuf_pos += handle_ip_size;
- }
- }
+ ipt_account_handle_copy_data(to_user, &tmpbuf_pos, network, net_ip, (a << 8) | (b << 16));
}
}
}
/* Flush remaining data to userspace */
if (tmpbuf_pos)
- copy_to_user(buffer, ipt_account_tmpbuf, tmpbuf_pos);
+ copy_to_user(to_user, ipt_account_tmpbuf, tmpbuf_pos);
return 0;
}
-
+
return -1;
}
-static int ipt_account_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len) {
+static int ipt_account_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
+{
struct ipt_account_handle_sockopt handle;
int ret = -EINVAL;
return ret;
}
-static int ipt_account_get_ctl(struct sock *sk, int cmd, void *user, int *len) {
+static int ipt_account_get_ctl(struct sock *sk, int cmd, void *user, int *len)
+{
struct ipt_account_handle_sockopt handle;
int ret = -EINVAL;
}
if (copy_from_user (&handle, user, sizeof(struct ipt_account_handle_sockopt))) {
- printk("ACCOUNT: ipt_account_get_ctl: copy_from_user failed for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n");
+ return -EFAULT;
break;
}
spin_unlock_bh(&ipt_account_lock);
if (handle.handle_nr == -1) {
- printk("ACCOUNT: ipt_account_get_ctl: ipt_account_handle_prepare_read failed\n");
+ return -EINVAL;
break;
}
if (copy_to_user(user, &handle, sizeof(struct ipt_account_handle_sockopt))) {
- printk("ACCOUNT: ipt_account_set_ctl: copy_to_user failed for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n");
+ return -EFAULT;
break;
}
ret = 0;
}
if (copy_from_user (&handle, user, sizeof(struct ipt_account_handle_sockopt))) {
- printk("ACCOUNT: ipt_account_get_ctl: copy_from_user failed for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n");
+ return -EFAULT;
break;
}
if (handle.handle_nr >= ACCOUNT_MAX_HANDLES) {
- printk("ACCOUNT: Invalid handle for IPT_SO_GET_ACCOUNT_GET_DATA: %u\n", handle.handle_nr);
+ return -EINVAL;
break;
}
spin_unlock_bh(&ipt_account_userspace_lock);
if (copy_to_user(user, &handle, sizeof(struct ipt_account_handle_sockopt))) {
- printk("ACCOUNT: ipt_account_set_ctl: copy_to_user failed for IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE\n");
+ return -EFAULT;
break;
}
ret = 0;
IPT_SO_GET_ACCOUNT_PREPARE_READ, IPT_SO_GET_ACCOUNT_MAX+1, ipt_account_get_ctl, 0, NULL
};
-static int __init init(void) {
- if (PAGE_SIZE < 4096) {
- printk("ACCOUNT: Sorry we need at least a PAGE_SIZE of 4096. Found: %lu\n", PAGE_SIZE);
- return -EINVAL;
- }
-
+static int __init init(void)
+{
if ((ipt_account_tables = kmalloc(ACCOUNT_MAX_TABLES*sizeof(struct ipt_account_table), GFP_KERNEL)) == NULL) {
printk("ACCOUNT: Out of memory allocating account_tables structure");
return -EINVAL;
return 0;
}
-static void __exit fini(void) {
+static void __exit fini(void)
+{
ipt_unregister_target(&ipt_account_reg);
nf_unregister_sockopt(&ipt_account_sockopts);