⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipt_recent.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Kernel module to check if the source address has been seen recently. *//* Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org *//* Author: Stephen Frost <sfrost@snowman.net> *//* Project Page: http://snowman.net/projects/ipt_recent/ *//* This software is distributed under the terms of the GPL, Version 2 *//* This copyright does not cover user programs that use kernel services * by normal system calls. */#include <linux/module.h>#include <linux/skbuff.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <linux/ctype.h>#include <linux/ip.h>#include <linux/vmalloc.h>#include <linux/moduleparam.h>#include <linux/netfilter_ipv4/ip_tables.h>#include <linux/netfilter_ipv4/ipt_recent.h>#undef DEBUG#define HASH_LOG 9/* Defaults, these can be overridden on the module command-line. */static int ip_list_tot = 100;static int ip_pkt_list_tot = 20;static int ip_list_hash_size = 0;static int ip_list_perms = 0644;#ifdef DEBUGstatic int debug = 1;#endifstatic char version[] =KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n";MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>");MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER);MODULE_LICENSE("GPL");module_param(ip_list_tot, int, 0400);module_param(ip_pkt_list_tot, int, 0400);module_param(ip_list_hash_size, int, 0400);module_param(ip_list_perms, int, 0400);#ifdef DEBUGmodule_param(debug, int, 0600);MODULE_PARM_DESC(debug,"debugging level, defaults to 1");#endifMODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list");MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember");MODULE_PARM_DESC(ip_list_hash_size,"size of hash table used to look up IPs");MODULE_PARM_DESC(ip_list_perms,"permissions on /proc/net/ipt_recent/* files");/* Structure of our list of recently seen addresses. */struct recent_ip_list {	u_int32_t addr;	u_int8_t  ttl;	unsigned long last_seen;	unsigned long *last_pkts;	u_int32_t oldest_pkt;	u_int32_t hash_entry;	u_int32_t time_pos;};struct time_info_list {	u_int32_t position;	u_int32_t time;};/* Structure of our linked list of tables of recent lists. */struct recent_ip_tables {	char name[IPT_RECENT_NAME_LEN];	int count;	int time_pos;	struct recent_ip_list *table;	struct recent_ip_tables *next;	spinlock_t list_lock;	int *hash_table;	struct time_info_list *time_info;#ifdef CONFIG_PROC_FS	struct proc_dir_entry *status_proc;#endif /* CONFIG_PROC_FS */};/* Our current list of addresses we have recently seen. * Only added to on a --set, and only updated on --set || --update  */static struct recent_ip_tables *r_tables = NULL;/* We protect r_list with this spinlock so two processors are not modifying * the list at the same time.  */static DEFINE_SPINLOCK(recent_lock);#ifdef CONFIG_PROC_FS/* Our /proc/net/ipt_recent entry */static struct proc_dir_entry *proc_net_ipt_recent = NULL;#endif/* Function declaration for later. */static intmatch(const struct sk_buff *skb,      const struct net_device *in,      const struct net_device *out,      const void *matchinfo,      int offset,      int *hotdrop);/* Function to hash a given address into the hash table of table_size size */static int hash_func(unsigned int addr, int table_size){	int result = 0;	unsigned int value = addr;	do { result ^= value; } while((value >>= HASH_LOG));#ifdef DEBUG	if(debug) printk(KERN_INFO RECENT_NAME ": %d = hash_func(%u,%d)\n",			 result & (table_size - 1),			 addr,			 table_size);#endif	return(result & (table_size - 1));}#ifdef CONFIG_PROC_FS/* This is the function which produces the output for our /proc output * interface which lists each IP address, the last seen time and the  * other recent times the address was seen. */static int ip_recent_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data){	int len = 0, count, last_len = 0, pkt_count;	off_t pos = 0;	off_t begin = 0;	struct recent_ip_tables *curr_table;	curr_table = (struct recent_ip_tables*) data;	spin_lock_bh(&curr_table->list_lock);	for(count = 0; count < ip_list_tot; count++) {		if(!curr_table->table[count].addr) continue;		last_len = len;		len += sprintf(buffer+len,"src=%u.%u.%u.%u ",NIPQUAD(curr_table->table[count].addr));		len += sprintf(buffer+len,"ttl: %u ",curr_table->table[count].ttl);		len += sprintf(buffer+len,"last_seen: %lu ",curr_table->table[count].last_seen);		len += sprintf(buffer+len,"oldest_pkt: %u ",curr_table->table[count].oldest_pkt);		len += sprintf(buffer+len,"last_pkts: %lu",curr_table->table[count].last_pkts[0]);		for(pkt_count = 1; pkt_count < ip_pkt_list_tot; pkt_count++) {			if(!curr_table->table[count].last_pkts[pkt_count]) break;			len += sprintf(buffer+len,", %lu",curr_table->table[count].last_pkts[pkt_count]);		}		len += sprintf(buffer+len,"\n");		pos = begin + len;		if(pos < offset) { len = 0; begin = pos; }		if(pos > offset + length) { len = last_len; break; }	}	*start = buffer + (offset - begin);	len -= (offset - begin);	if(len > length) len = length;	spin_unlock_bh(&curr_table->list_lock);	return len;}/* ip_recent_ctrl provides an interface for users to modify the table * directly.  This allows adding entries, removing entries, and * flushing the entire table. * This is done by opening up the appropriate table for writing and * sending one of: * xx.xx.xx.xx   -- Add entry to table with current time * +xx.xx.xx.xx  -- Add entry to table with current time * -xx.xx.xx.xx  -- Remove entry from table * clear         -- Flush table, remove all entries */static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned long size, void *data){	static const u_int32_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };	u_int32_t val;	int base, used = 0;	char c, *cp;	union iaddr {		uint8_t bytes[4];		uint32_t word;	} res;	uint8_t *pp = res.bytes;	int digit;	char buffer[20];	int len, check_set = 0, count;	u_int32_t addr = 0;	struct sk_buff *skb;	struct ipt_recent_info *info;	struct recent_ip_tables *curr_table;	curr_table = (struct recent_ip_tables*) data;	if(size > 20) len = 20; else len = size;	if(copy_from_user(buffer,input,len)) return -EFAULT;	if(len < 20) buffer[len] = '\0';#ifdef DEBUG	if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl len: %d, input: `%.20s'\n",len,buffer);#endif	cp = buffer;	while(isspace(*cp)) { cp++; used++; if(used >= len-5) return used; }	/* Check if we are asked to flush the entire table */	if(!memcmp(cp,"clear",5)) {		used += 5;		spin_lock_bh(&curr_table->list_lock);		curr_table->time_pos = 0;		for(count = 0; count < ip_list_hash_size; count++) {			curr_table->hash_table[count] = -1;		}		for(count = 0; count < ip_list_tot; count++) {			curr_table->table[count].last_seen = 0;			curr_table->table[count].addr = 0;			curr_table->table[count].ttl = 0;			memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(unsigned long));			curr_table->table[count].oldest_pkt = 0;			curr_table->table[count].time_pos = 0;			curr_table->time_info[count].position = count;			curr_table->time_info[count].time = 0;		}		spin_unlock_bh(&curr_table->list_lock);		return used;	}        check_set = IPT_RECENT_SET;	switch(*cp) {		case '+': check_set = IPT_RECENT_SET; cp++; used++; break;		case '-': check_set = IPT_RECENT_REMOVE; cp++; used++; break;		default: if(!isdigit(*cp)) return (used+1); break;	}#ifdef DEBUG	if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl cp: `%c', check_set: %d\n",*cp,check_set);#endif	/* Get addr (effectively inet_aton()) */	/* Shamelessly stolen from libc, a function in the kernel for doing	 * this would, of course, be greatly preferred, but our options appear	 * to be rather limited, so we will just do it ourselves here.	 */	res.word = 0;	c = *cp;	for(;;) {		if(!isdigit(c)) return used;		val = 0; base = 10; digit = 0;		if(c == '0') {			c = *++cp;			if(c == 'x' || c == 'X') base = 16, c = *++cp;			else { base = 8; digit = 1; }		}		for(;;) {			if(isascii(c) && isdigit(c)) {				if(base == 8 && (c == '8' || c == '0')) return used;				val = (val * base) + (c - '0');				c = *++cp;				digit = 1;			} else if(base == 16 && isascii(c) && isxdigit(c)) {				val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A'));				c = *++cp;				digit = 1;			} else break;		}		if(c == '.') {			if(pp > res.bytes + 2 || val > 0xff) return used;			*pp++ = val;			c = *++cp;		} else break;	}	used = cp - buffer;	if(c != '\0' && (!isascii(c) || !isspace(c))) return used;	if(c == '\n') used++;	if(!digit) return used;	if(val > max[pp - res.bytes]) return used;	addr = res.word | htonl(val);	if(!addr && check_set == IPT_RECENT_SET) return used;#ifdef DEBUG	if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl c: %c, addr: %u used: %d\n",c,addr,used);#endif	/* Set up and just call match */	info = kmalloc(sizeof(struct ipt_recent_info),GFP_KERNEL);	if(!info) { return -ENOMEM; }	info->seconds = 0;	info->hit_count = 0;	info->check_set = check_set;	info->invert = 0;	info->side = IPT_RECENT_SOURCE;	strncpy(info->name,curr_table->name,IPT_RECENT_NAME_LEN);	info->name[IPT_RECENT_NAME_LEN-1] = '\0';	skb = kmalloc(sizeof(struct sk_buff),GFP_KERNEL);	if (!skb) {		used = -ENOMEM;		goto out_free_info;	}	skb->nh.iph = kmalloc(sizeof(struct iphdr),GFP_KERNEL);	if (!skb->nh.iph) {		used = -ENOMEM;		goto out_free_skb;	}	skb->nh.iph->saddr = addr;	skb->nh.iph->daddr = 0;	/* Clear ttl since we have no way of knowing it */	skb->nh.iph->ttl = 0;	match(skb,NULL,NULL,info,0,NULL);	kfree(skb->nh.iph);out_free_skb:	kfree(skb);out_free_info:	kfree(info);#ifdef DEBUG	if(debug) printk(KERN_INFO RECENT_NAME ": Leaving ip_recent_ctrl addr: %u used: %d\n",addr,used);#endif	return used;}#endif /* CONFIG_PROC_FS */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -