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

📄 dv.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		Generic frame diversion * * Version:	@(#)eth.c	0.41	09/09/2000 * * Authors:	 * 		Benoit LOCHER:	initial integration within the kernel with support for ethernet * 		Dave Miller:	improvement on the code (correctness, performance and source files) * */#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/ip.h>#include <linux/udp.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/errno.h>#include <linux/init.h>#include <net/dst.h>#include <net/arp.h>#include <net/sock.h>#include <net/ipv6.h>#include <net/ip.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/checksum.h>#include <linux/divert.h>#include <linux/sockios.h>const char sysctl_divert_version[32]="0.46";	/* Current version */int __init dv_init(void){	printk(KERN_INFO "NET4: Frame Diverter %s\n", sysctl_divert_version);	return 0;}/* * Allocate a divert_blk for a device. This must be an ethernet nic. */int alloc_divert_blk(struct net_device *dev){	int alloc_size = (sizeof(struct divert_blk) + 3) & ~3;	if (!strncmp(dev->name, "eth", 3)) {		printk(KERN_DEBUG "divert: allocating divert_blk for %s\n",		       dev->name);		dev->divert = (struct divert_blk *)			kmalloc(alloc_size, GFP_KERNEL);		if (dev->divert == NULL) {			printk(KERN_DEBUG "divert: unable to allocate divert_blk for %s\n",			       dev->name);			return -ENOMEM;		} else {			memset(dev->divert, 0, sizeof(struct divert_blk));		}	} else {		printk(KERN_DEBUG "divert: not allocating divert_blk for non-ethernet device %s\n",		       dev->name);		dev->divert = NULL;	}	return 0;} /* * Free a divert_blk allocated by the above function, if it was  * allocated on that device. */void free_divert_blk(struct net_device *dev){	if (dev->divert) {		kfree(dev->divert);		dev->divert=NULL;		printk(KERN_DEBUG "divert: freeing divert_blk for %s\n",		       dev->name);	} else {		printk(KERN_DEBUG "divert: no divert_blk to free, %s not ethernet\n",		       dev->name);	}}/* * Adds a tcp/udp (source or dest) port to an array */int add_port(u16 ports[], u16 port){	int i;	if (port == 0)		return -EINVAL;	/* Storing directly in network format for performance,	 * thanks Dave :)	 */	port = htons(port);	for (i = 0; i < MAX_DIVERT_PORTS; i++) {		if (ports[i] == port)			return -EALREADY;	}		for (i = 0; i < MAX_DIVERT_PORTS; i++) {		if (ports[i] == 0) {			ports[i] = port;			return 0;		}	}	return -ENOBUFS;}/* * Removes a port from an array tcp/udp (source or dest) */int remove_port(u16 ports[], u16 port){	int i;	if (port == 0)		return -EINVAL;		/* Storing directly in network format for performance,	 * thanks Dave !	 */	port = htons(port);	for (i = 0; i < MAX_DIVERT_PORTS; i++) {		if (ports[i] == port) {			ports[i] = 0;			return 0;		}	}	return -EINVAL;}/* Some basic sanity checks on the arguments passed to divert_ioctl() */int check_args(struct divert_cf *div_cf, struct net_device **dev){	char devname[32];			if (dev == NULL)		return -EFAULT;		/* GETVERSION: all other args are unused */	if (div_cf->cmd == DIVCMD_GETVERSION)		return 0;		/* Network device index should reasonably be between 0 and 1000 :) */	if (div_cf->dev_index < 0 || div_cf->dev_index > 1000) 		return -EINVAL;				/* Let's try to find the ifname */	sprintf(devname, "eth%d", div_cf->dev_index);	*dev = dev_get_by_name(devname);		/* dev should NOT be null */	if (*dev == NULL)		return -EINVAL;		/* user issuing the ioctl must be a super one :) */	if (!suser())		return -EPERM;	/* Device must have a divert_blk member NOT null */	if ((*dev)->divert == NULL)		return -EFAULT;	return 0;}/* * control function of the diverter */#define	DVDBG(a)	\	printk(KERN_DEBUG "divert_ioctl() line %d %s\n", __LINE__, (a))int divert_ioctl(unsigned int cmd, struct divert_cf *arg){	struct divert_cf	div_cf;	struct divert_blk	*div_blk;	struct net_device	*dev;	int			ret;	switch (cmd) {	case SIOCGIFDIVERT:		DVDBG("SIOCGIFDIVERT, copy_from_user");		if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf)))			return -EFAULT;		DVDBG("before check_args");		ret = check_args(&div_cf, &dev);		if (ret)			return ret;		DVDBG("after checkargs");		div_blk = dev->divert;					DVDBG("befre switch()");		switch (div_cf.cmd) {		case DIVCMD_GETSTATUS:			/* Now, just give the user the raw divert block			 * for him to play with :)			 */			if (copy_to_user(div_cf.arg1.ptr, dev->divert,					 sizeof(struct divert_blk)))				return -EFAULT;			break;		case DIVCMD_GETVERSION:			DVDBG("GETVERSION: checking ptr");			if (div_cf.arg1.ptr == NULL)				return -EINVAL;			DVDBG("GETVERSION: copying data to userland");			if (copy_to_user(div_cf.arg1.ptr,					 sysctl_divert_version, 32))				return -EFAULT;			DVDBG("GETVERSION: data copied");			break;		default:			return -EINVAL;		};		break;	case SIOCSIFDIVERT:		if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf)))			return -EFAULT;		ret = check_args(&div_cf, &dev);		if (ret)			return ret;		div_blk = dev->divert;		switch(div_cf.cmd) {		case DIVCMD_RESET:			div_blk->divert = 0;			div_blk->protos = DIVERT_PROTO_NONE;			memset(div_blk->tcp_dst, 0,			       MAX_DIVERT_PORTS * sizeof(u16));			memset(div_blk->tcp_src, 0,			       MAX_DIVERT_PORTS * sizeof(u16));			memset(div_blk->udp_dst, 0,			       MAX_DIVERT_PORTS * sizeof(u16));			memset(div_blk->udp_src, 0,			       MAX_DIVERT_PORTS * sizeof(u16));			return 0;						case DIVCMD_DIVERT:			switch(div_cf.arg1.int32) {			case DIVARG1_ENABLE:				if (div_blk->divert)					return -EALREADY;				div_blk->divert = 1;				break;			case DIVARG1_DISABLE:				if (!div_blk->divert)					return -EALREADY;				div_blk->divert = 0;				break;			default:				return -EINVAL;			};			break;		case DIVCMD_IP:			switch(div_cf.arg1.int32) {			case DIVARG1_ENABLE:				if (div_blk->protos & DIVERT_PROTO_IP)					return -EALREADY;				div_blk->protos |= DIVERT_PROTO_IP;				break;			case DIVARG1_DISABLE:				if (!(div_blk->protos & DIVERT_PROTO_IP))					return -EALREADY;				div_blk->protos &= ~DIVERT_PROTO_IP;				break;			default:				return -EINVAL;			};			break;		case DIVCMD_TCP:			switch(div_cf.arg1.int32) {			case DIVARG1_ENABLE:				if (div_blk->protos & DIVERT_PROTO_TCP)					return -EALREADY;				div_blk->protos |= DIVERT_PROTO_TCP;				break;			case DIVARG1_DISABLE:				if (!(div_blk->protos & DIVERT_PROTO_TCP))					return -EALREADY;				div_blk->protos &= ~DIVERT_PROTO_TCP;				break;			default:				return -EINVAL;			};			break;		case DIVCMD_TCPDST:			switch(div_cf.arg1.int32) {			case DIVARG1_ADD:				return add_port(div_blk->tcp_dst,						div_cf.arg2.uint16);							case DIVARG1_REMOVE:				return remove_port(div_blk->tcp_dst,						   div_cf.arg2.uint16);			default:				return -EINVAL;			};			break;		case DIVCMD_TCPSRC:			switch(div_cf.arg1.int32) {			case DIVARG1_ADD:				return add_port(div_blk->tcp_src,						div_cf.arg2.uint16);			case DIVARG1_REMOVE:				return remove_port(div_blk->tcp_src,						   div_cf.arg2.uint16);			default:				return -EINVAL;			};			break;		case DIVCMD_UDP:			switch(div_cf.arg1.int32) {			case DIVARG1_ENABLE:				if (div_blk->protos & DIVERT_PROTO_UDP)					return -EALREADY;				div_blk->protos |= DIVERT_PROTO_UDP;				break;			case DIVARG1_DISABLE:				if (!(div_blk->protos & DIVERT_PROTO_UDP))					return -EALREADY;				div_blk->protos &= ~DIVERT_PROTO_UDP;				break;			default:				return -EINVAL;			};			break;		case DIVCMD_UDPDST:			switch(div_cf.arg1.int32) {			case DIVARG1_ADD:				return add_port(div_blk->udp_dst,						div_cf.arg2.uint16);			case DIVARG1_REMOVE:				return remove_port(div_blk->udp_dst,						   div_cf.arg2.uint16);			default:				return -EINVAL;			};			break;		case DIVCMD_UDPSRC:			switch(div_cf.arg1.int32) {			case DIVARG1_ADD:				return add_port(div_blk->udp_src,						div_cf.arg2.uint16);			case DIVARG1_REMOVE:				return remove_port(div_blk->udp_src,						   div_cf.arg2.uint16);			default:				return -EINVAL;			};			break;		case DIVCMD_ICMP:			switch(div_cf.arg1.int32) {			case DIVARG1_ENABLE:				if (div_blk->protos & DIVERT_PROTO_ICMP)					return -EALREADY;				div_blk->protos |= DIVERT_PROTO_ICMP;				break;			case DIVARG1_DISABLE:				if (!(div_blk->protos & DIVERT_PROTO_ICMP))					return -EALREADY;				div_blk->protos &= ~DIVERT_PROTO_ICMP;				break;			default:				return -EINVAL;			};			break;		default:			return -EINVAL;		};		break;	default:		return -EINVAL;	};	return 0;}/* * Check if packet should have its dest mac address set to the box itself * for diversion */#define	ETH_DIVERT_FRAME(skb) \	memcpy(skb->mac.ethernet, skb->dev->dev_addr, ETH_ALEN); \	skb->pkt_type=PACKET_HOST		void divert_frame(struct sk_buff *skb){	struct ethhdr			*eth = skb->mac.ethernet;	struct iphdr			*iph;	struct tcphdr			*tcph;	struct udphdr			*udph;	struct divert_blk		*divert = skb->dev->divert;	int				i, src, dst;	unsigned char			*skb_data_end = skb->data + skb->len;	/* Packet is already aimed at us, return */	if (!memcmp(eth, skb->dev->dev_addr, ETH_ALEN))		return;		/* proto is not IP, do nothing */	if (eth->h_proto != htons(ETH_P_IP))		return;		/* Divert all IP frames ? */	if (divert->protos & DIVERT_PROTO_IP) {		ETH_DIVERT_FRAME(skb);		return;	}		/* Check for possible (maliciously) malformed IP frame (thanks Dave) */	iph = (struct iphdr *) skb->data;	if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) {		printk(KERN_INFO "divert: malformed IP packet !\n");		return;	}	switch (iph->protocol) {	/* Divert all ICMP frames ? */	case IPPROTO_ICMP:		if (divert->protos & DIVERT_PROTO_ICMP) {			ETH_DIVERT_FRAME(skb);			return;		}		break;	/* Divert all TCP frames ? */	case IPPROTO_TCP:		if (divert->protos & DIVERT_PROTO_TCP) {			ETH_DIVERT_FRAME(skb);			return;		}		/* Check for possible (maliciously) malformed IP		 * frame (thanx Dave)		 */		tcph = (struct tcphdr *)			(((unsigned char *)iph) + (iph->ihl<<2));		if (((unsigned char *)(tcph+1)) >= skb_data_end) {			printk(KERN_INFO "divert: malformed TCP packet !\n");			return;		}		/* Divert some tcp dst/src ports only ?*/		for (i = 0; i < MAX_DIVERT_PORTS; i++) {			dst = divert->tcp_dst[i];			src = divert->tcp_src[i];			if ((dst && dst == tcph->dest) ||			    (src && src == tcph->source)) {				ETH_DIVERT_FRAME(skb);				return;			}		}		break;	/* Divert all UDP frames ? */	case IPPROTO_UDP:		if (divert->protos & DIVERT_PROTO_UDP) {			ETH_DIVERT_FRAME(skb);			return;		}		/* Check for possible (maliciously) malformed IP		 * packet (thanks Dave)		 */		udph = (struct udphdr *)			(((unsigned char *)iph) + (iph->ihl<<2));		if (((unsigned char *)(udph+1)) >= skb_data_end) {			printk(KERN_INFO			       "divert: malformed UDP packet !\n");			return;		}		/* Divert some udp dst/src ports only ? */		for (i = 0; i < MAX_DIVERT_PORTS; i++) {			dst = divert->udp_dst[i];			src = divert->udp_src[i];			if ((dst && dst == udph->dest) ||			    (src && src == udph->source)) {				ETH_DIVERT_FRAME(skb);				return;			}		}		break;	};	return;}

⌨️ 快捷键说明

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