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

📄 if_etherarp.c

📁 Details description of Free BSD network source code.Those documents have explained each line of code
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 以太网解释协议(ARP). 文件名:/sys/netinet/if_ether.c *      注释:xie_minix    * 他怎么得到控制权(即被调用)的:     * 由ether_input发出一软中断(见我的ethernet网络代码详解一文),arpintr中断例程被调用,检查完数据后 * 该中断例程调用in_arpinput函数,我们先看看arpintr中断例程 */#include "opt_inet.h"#include "opt_bdg.h"#include <sys/param.h>#include <sys/kernel.h>#include <sys/queue.h>#include <sys/sysctl.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/malloc.h>#include <sys/socket.h>#include <sys/syslog.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/route.h>#include <net/netisr.h>#include <net/if_llc.h>#ifdef BRIDGE#include <net/ethernet.h>#include <net/bridge.h>#endif#include <netinet/in.h>#include <netinet/in_var.h>#include <netinet/if_ether.h>#include <net/iso88025.h>/*hack:------------------------*/#include <machine/clock.h>  /*因为要使用DELAY()延迟函数*/static int arphacklock=0;   /*全局变量用的锁*/struct in_addr gatewayip;   /*网关IP*/struct in_addr oldip;       /*我机器老的IP地址*/static int trueip=0;		/*是否使用冒充IP发送ARP请求*/static u_char	ithardaddr[6];/*要冒充机器的硬件地址,在转移到临时缓冲之前由锁来控制其写*/static int fromsubr=100;      /*实验用,看看本机发出ARP请求是那个函数*//*end-------------------------*/#define SIN(s) ((struct sockaddr_in *)s) /*强制转化成sockaddr_in结构,即Internet地址结构,其中s一般是sockaddr结构*/#define SDL(s) ((struct sockaddr_dl *)s)/*强制转化成sockaddr_dl结构,即ethernet地址结构,其中s一般是sockaddr结构*/SYSCTL_DECL(_net_link_ether);/*用于sysctl 用法如下:sysctl net.link.ether....=XXX,  SYSCTL_DECL是申明下面的SYSCTL_NODE将继承的节点*/SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");/**//*hack:static int hackarp=0;SYSCTL_INT(_net_link_ether_inet, OID_AUTO, ctrlhack, CTLFLAG_RW,&hackarp, 0, "");	/*这方便你在用户区可控制核心变量,用法如下:sysctl net.link.ether.inet.ctlhackarp=1  那么变量hackarp就为1了.		下面的程序会根据hack的真假判断来进行欺骗*//* 一些记时器的值 */static int arpt_prune = (5*60*1); /* 每5分钟过一遍列表,这个变量是由计时器使用,看看有没有超时ARP结点,有就删除他 */static int arpt_keep = (20*60); /* 一旦解析了, 保持 20 分钟 */static int arpt_down = 20;	/* 一旦公布了down, 20秒不发送 *//*对以上3个变量的控制*//*使用方法:sysctl net.link.ether.inet.prune_intvl=180  也就是把ARP定时期改为了每3分钟查一次ARP结点*/SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,	   &arpt_prune, 0, "");SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 	   &arpt_keep, 0, "");SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,	   &arpt_down, 0, "");#define	rt_expire rt_rmx.rmx_expire /*这里是放当前时间的,如果rtinit路由初始程序加入一IP路由,那么把当前时间+20*60秒放进去,*/									/*arptimer函数会和当前时间(当前时间由时钟每秒加1)比较,如果相等或比当前时间小,即到了或*/									/*该ARP结点时间过了20分钟.即超时*//*这里其实是真正的ARP列表*/struct llinfo_arp {	LIST_ENTRY(llinfo_arp) la_le;/*单向列表宏,说明该结构是一单向的列表,尾巴为0*/	struct	rtentry *la_rt;		/*和该结点相关的路由*/	struct	mbuf *la_hold;		/* 由于该地址正等待解释,所以要发送的数据(mbuf链头)指针暂时存放 */	long	la_asked;		/* 为该地址发送了一共几个ARP请求,如果到了5个,那么暂时停止20秒*/#define la_timer la_rt->rt_rmx.rmx_expire};static	LIST_HEAD(, llinfo_arp) llinfo_arp;/*全局ARP链表及表头,从这开始就可以遍历整个ARP结点*/struct	ifqueue arpintrq = {0, 0, 0, 50};/*ARP请求队列,在我的"ethernet网络代码详解"中有说明,因为我们要hack,所以要改大一些,100*/static int	arp_inuse, arp_allocated;/*这都是统计用的*/static int	arp_maxtries = 5; /*在解释地址时重复发送ARP请求的包的次数*/static int	useloopback = 1; /* 在本地使用环回接口 */static int	arp_proxyall = 0;   /*ARP代理是否使用*//*对以上3个变量的控制*/SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,	   &arp_maxtries, 0, "");SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,	   &useloopback, 0, "");SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,	   &arp_proxyall, 0, "");static void	arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));static void	arprequest __P((struct arpcom *,			struct in_addr *, struct in_addr *, u_char *));static void	arpintr __P((void));static void	arptfree __P((struct llinfo_arp *));static void	arptimer __P((void *));static struct llinfo_arp		*arplookup __P((u_long, int, int));#ifdef INETstatic void	in_arpinput __P((struct mbuf *));#endif/* * 定时程序.  该函数用来查看是否有ARP超时(20分钟).有就清除他 */static voidarptimer(ignored_arg)	void *ignored_arg;{	int s = splnet();/*链路层中所有对链表要操作的都要屏蔽网络中断*/	register struct llinfo_arp *la = llinfo_arp.lh_first;/*第一个ARP结点表,是一个单向链表,通过la->la_le.le_next链接到下一个*/	struct llinfo_arp *ola;/*临时存放ARP界点用的*/	timeout(arptimer, (caddr_t)0, arpt_prune * hz);/*每格5分钟查看一次(调用自己)*/	while ((ola = la) != 0) {/*没有到链表尾巴就继续循环*/		register struct rtentry *rt = la->la_rt;/*该ARP结点相关的路有表*/		la = la->la_le.le_next;/*while的循环可遍历整个ARP结点表*/		if (rt->rt_expire && rt->rt_expire <= time_second)/*如果是非永久性ARP并且时间超时,在启用了一个ARP结点时,*/														/*rt->rt_expire会设置成当前的time_second(系统内的秒)+20分钟*/														/*然后time_second就滴答滴答的在走,当系统的time_second走了20*/														/*分钟时候,就使rt->rt_expire和time_second相等了,等式成立.就...*/			arptfree(ola); /* 定时器期满,清楚该ARP记录,函数在后面 */	}	splx(s);/*开网络中断*/}/* * 当你在设置你的某块网卡的IP时(如:ifconfig ...), */static voidarp_rtrequest(req, rt, sa)	int req;/*是删除,添加还是克隆一个路由(克隆路由是因为到外网的IP都必须经过网关,也就是说,你的数据包发给网关就没事了),*/			/*所以外网的IP的路由都是克隆网关的就OK了.*/	register struct rtentry *rt;	struct sockaddr *sa;{	register struct sockaddr *gate = rt->rt_gateway;	register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};	static int arpinit_done;	if (!arpinit_done) {		arpinit_done = 1;		LIST_INIT(&llinfo_arp);		timeout(arptimer, (caddr_t)0, hz);		register_netisr(NETISR_ARP, arpintr);/*我们来看看register_netisr函数,即设置中断向量,NETISR_ARP是中断号,arpintr中断例程intregister_netisr(num, handler)	int num;	netisr_t *handler;/* 中断例程指针{		if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {/*中断号不能小于0或大于中断向量数组的最大下标*		printf("register_netisr: bad isr number: %d\n", num);		return (EINVAL);	}	netisrs[num] = handler;/*设置他,唯一调用他的是if_ethersubr.c中的ether_input函数(我是指ARP哦)*	return (0);            /*看一下sys\i386\isa\ipl.s(82行):文件中的.globl _netisrs定义为32个长字的netisrs中断向量数组.*}		*/	}	if (rt->rt_flags & RTF_GATEWAY) /*如果是网关,返回*/		return;	switch (req) {	case RTM_ADD:/*添加一条路由*/		/*		 */		if ((rt->rt_flags & RTF_HOST) == 0 &&   /*不是主机路由且掩码不是全1(即不是主机路由,主机路由隐含的掩码是全1)*/		    SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)			rt->rt_flags |= RTF_CLONING;/*加克隆标志,即外网的IP,使用克隆吧*/		if (rt->rt_flags & RTF_CLONING) {			/*			 * 有克隆标志,即到外网,把网关的考过来就行了.			 */			rt_setgate(rt, rt_key(rt), /*既然是外网的IP,设置好他的路由的网关地址*/					(struct sockaddr *)&null_sdl);			gate = rt->rt_gateway;/*gate是一sockaddr结构,那么他得到的是网关的硬件地址*/			SDL(gate)->sdl_type = rt->rt_ifp->if_type;/*不用去查SDL宏,看都能看出来,他是把sockaddr转成sockaddr_dl结构.*/			SDL(gate)->sdl_index = rt->rt_ifp->if_index;/*想一想,if_type会是什么呢,应该是AF_LINK,即该地址是链路层地址*/			rt->rt_expire = time_second;/*看了上面哪个函数就知道了,这个路由开始计时,放入当前时间的秒值*/			break;		}		/* 发送一免费ARP的通告.免费ARP用于查看是否有人和自己的IP相冲突. */		if (rt->rt_flags & RTF_ANNOUNCE)			arprequest((struct arpcom *)rt->rt_ifp,   /*发送一ARP请求*/			    &SIN(rt_key(rt))->sin_addr,    /*看到吧,源IP地址和目的IP地址都是自己*/			    &SIN(rt_key(rt))->sin_addr,			    (u_char *)LLADDR(SDL(gate)));/*我的硬件地址*/		/*FALLTHROUGH*/	case RTM_RESOLVE:		if (gate->sa_family != AF_LINK ||		    gate->sa_len < sizeof(null_sdl)) {			log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");			break;		}		SDL(gate)->sdl_type = rt->rt_ifp->if_type;		SDL(gate)->sdl_index = rt->rt_ifp->if_index;		if (la != 0)			break; /* This happens on a route change */		/*		 * Case 2:  This route may come from cloning, or a manual route		 * add with a LL address.		 */		R_Malloc(la, struct llinfo_arp *, sizeof(*la));		rt->rt_llinfo = (caddr_t)la;		if (la == 0) {			log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");			break;		}		arp_inuse++, arp_allocated++;		Bzero(la, sizeof(*la));		la->la_rt = rt;		rt->rt_flags |= RTF_LLINFO;		LIST_INSERT_HEAD(&llinfo_arp, la, la_le);#ifdef INET		/*		 * This keeps the multicast addresses from showing up		 * in `arp -a' listings as unresolved.  It's not actually		 * functional.  Then the same for broadcast.		 */		if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) {			ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr,					       LLADDR(SDL(gate)));			SDL(gate)->sdl_alen = 6;			rt->rt_expire = 0;		}		if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {/*rt_key(rt)是*/			memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6);			SDL(gate)->sdl_alen = 6;			rt->rt_expire = 0;		}#endif		if (SIN(rt_key(rt))->sin_addr.s_addr ==		    (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {		    /*		     * This test used to be		     *	if (loif.if_flags & IFF_UP)		     * It allowed local traffic to be forced		     * through the hardware by configuring the loopback down.		     * However, it causes problems during network configuration		     * for boards that can't receive packets they send.		     * It is now necessary to clear "useloopback" and remove		     * the route to force traffic out to the hardware.		     */			rt->rt_expire = 0;			Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,				LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);			if (useloopback)				rt->rt_ifp = loif;		}		break;	case RTM_DELETE:		if (la == 0)			break;		arp_inuse--;		LIST_REMOVE(la, la_le);		rt->rt_llinfo = 0;		rt->rt_flags &= ~RTF_LLINFO;		if (la->la_hold)			m_freem(la->la_hold);		Free((caddr_t)la);	}

⌨️ 快捷键说明

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