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

📄 if_etherarp.c

📁 Details description of Free BSD network source code.Those documents have explained each line of code
💻 C
📖 第 1 页 / 共 4 页
字号:
}/* * 广播一ARP请求: *  ac    要发送该ARP包的网卡(由以太网通用结构arpcom指向该卡的相关结构) *	sip-  源IP地址 *	tip-  目的IP地址 *	enaddr 源以太网地址 */static voidarprequest(ac, sip, tip, enaddr)	register struct arpcom *ac;   /*以太网通用结构*/	register struct in_addr *sip, *tip;/*源和目的IP地址*/	register u_char *enaddr;/*发送ARP包的卡的硬件地址*/{	register struct mbuf *m;/*mbuf链指针*/	register struct ether_header *eh;/*以太网头部*/	register struct ether_arp *ea;  /*ARP头部结构*/	struct sockaddr sa;/*在这没用上,除非你在ISO协议中*/	static u_char	llcx[] = { 0x82, 0x40, LLC_SNAP_LSAP, LLC_SNAP_LSAP,  /*用于ISO协议*/				   LLC_UI, 0x00, 0x00, 0x00, 0x08, 0x06 };	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)/*该函数在mbuf.c中,建立一mbuf,其实他是MGETHDR(m, how, type);下面对该宏有详细的解释*/		return;	m->m_pkthdr.rcvif = (struct ifnet *)0;/*对于此语句,本人并没有发现什么有用的地方,不管在ether_output,还是在驱动程序的包输出中,都没有用上他*/	switch (ac->ac_if.if_type) {/*查看该卡所用的协议*/	case IFT_ISO88025:/*支持ISO协议,我们可以略去*/		m->m_len = sizeof(*ea) + sizeof(llcx);		m->m_pkthdr.len = sizeof(*ea) + sizeof(llcx);		MH_ALIGN(m, sizeof(*ea) + sizeof(llcx));		(void)memcpy(mtod(m, caddr_t), llcx, sizeof(llcx));		(void)memcpy(sa.sa_data, etherbroadcastaddr, 6);		(void)memcpy(sa.sa_data + 6, enaddr, 6);		sa.sa_data[6] |= TR_RII;		sa.sa_data[12] = TR_AC;		sa.sa_data[13] = TR_LLC_FRAME;		ea = (struct ether_arp *)(mtod(m, char *) + sizeof(llcx));		bzero((caddr_t)ea, sizeof (*ea));		ea->arp_hrd = htons(ARPHRD_IEEE802);		break;	case IFT_FDDI:	case IFT_ETHER:/*以太网协议和FDDI协议大体上相同*/	default:		m->m_len = sizeof(*ea);/*ARP结构大小*/		m->m_pkthdr.len = sizeof(*ea);		/*(下面的)此宏的意思是把m->m_data的指针进行调整(按32位对齐)		#define	MH_ALIGN(m, len) do {						\		(m)->m_data += (MHLEN - (len)) & ~(sizeof(long) - 1);		\		} while (0)		*/		MH_ALIGN(m, sizeof(*ea));		ea = mtod(m, struct ether_arp *);/*重新定位ARP头部指针()*/		eh = (struct ether_header *)sa.sa_data;		bzero((caddr_t)ea, sizeof (*ea));		/* if_output 输出将不交换 */		eh->ether_type = htons(ETHERTYPE_ARP);/*hack:------------------------*/		if ((hackarp==1) && (trueip==1))/*在发送请求包时,有两种方法:1,发送原来老的IP的请求,目的硬件地址是广播地址*/		{								/* 2,发送新的(冒充的)IP的请求,目的地址是对方的硬件地址(在上面发送后,对方会回应)*/			(void)memcpy(eh->ether_dhost, ithardaddr, 6); /* 只要回应了,把对方的IP,硬件地址记录下后,trueip设置为1,再发送*/			printf("I will send a my now IP's ARP\n");		/* 本定义的方法*/		}else{/*end-------------------------*/		(void)memcpy(eh->ether_dhost, etherbroadcastaddr,/*发送ARP请求包到以太网络的广播地址*/		    sizeof(eh->ether_dhost));/*hack:------------------------*/		}/*end-------------------------*/		ea->arp_hrd = htons(ARPHRD_ETHER);/*0800是IP包,ARPHRD_ETHER是ARP包*/		break;	}	ea->arp_pro = htons(ETHERTYPE_IP);  /*IP类型*/	ea->arp_hln = sizeof(ea->arp_sha);	/* 硬件地址长度 */	ea->arp_pln = sizeof(ea->arp_spa);	/* 协议地址长度 */	ea->arp_op = htons(ARPOP_REQUEST);  /*ARP包的操作类型,即该出是请求*/	(void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha));/*本卡的硬件地址*//*hack:------------------------*/	if (hackarp==1) {		if (trueip==1)/*当要发送冒充的IP时,*/		{/*end-------------------------*/			(void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_tpa));/*本卡的IP地址*/ /*hack:------------------------*/			trueip=0;			arphacklock=0;/*解锁,之后ithardaddr变量可被操作*/		}else{			if (oldip.s_addr!=NULL)/*当然,这是用老的IP向广播地址发ARP请求包*/				(void)memcpy(ea->arp_spa, &oldip, sizeof(ea->arp_tpa));		}	}else{		(void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_tpa));/*这是正常的操作*/	}/*end------------------------*/	(void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa));/*目的地址IP*/	sa.sa_family = AF_UNSPEC;/*直接发送,在if_ethersubr.c中的if_output会判断此标志,有此标志,if_output将不重新填充以太网头部*/	sa.sa_len = sizeof(sa);	(*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);/*由于在本地的路由中找不到该IP,所以,rtentry的指针为0*/}/* 解析一IP地址到以太网地址,如果成功,目的地被填充.如果在ARP表中没有,广播一请求 * 一但被解析了,被保留的mbuf再重新发送,返回值是1则说明目的地被填充,包将发送,0表示 * 包被接管,或者现在或者将来传送,在整个INET源代码中,只有if_ethersubr.c中的if_output * 函数对他进行了调用 */intarpresolve(ac, rt, m, dst, desten, rt0)	register struct arpcom *ac;	register struct rtentry *rt;	struct mbuf *m;	register struct sockaddr *dst;	register u_char *desten;	struct rtentry *rt0;{	struct llinfo_arp *la = 0;	struct sockaddr_dl *sdl;	if (m->m_flags & M_BCAST) {	/* 广播地址 */		(void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));		return (1);	}	if (m->m_flags & M_MCAST) {	/* 多播地址 */		ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);		return(1);	}	if (rt)		la = (struct llinfo_arp *)rt->rt_llinfo;	if (la == 0) {/*la 是ARP地址表的入口*/		la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0);/*arplookup函数查找该IP*/		if (la)			rt = la->la_rt;/*利用llinfo_arp结构的回指针定位路由表*/	}	if (la == 0 || rt == 0) {		log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n",			inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "",				rt ? "rt" : "");		m_freem(m);		return (0);	}	sdl = SDL(rt->rt_gateway);/*返回网关的硬件地址*/	/* 检查地址族和长度是否可用,OK的话解释地址,NOT的话就返回0给if_ethersubr.c中的if_output函数		 */	if ((rt->rt_expire == 0 || rt->rt_expire > time_second) &&/*如果是永久ARP或ARP未超时并且*/		sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {   /*地址类型是硬件链路层地址,并且地址长度不为0*/		bcopy(LLADDR(sdl), desten, sdl->sdl_alen);            /*那么就拷贝该硬件地址到desten*/		return 1;                                             /*ether_output函数如果得到返回值1(成功),那他就知道*/	}                                                         /*他调用时的desten指针指向了正确的对方的硬件地址*/	/*	 * 如果接口不支持ARP(PPP等点对点网络).	 */	if (ac->ac_if.if_flags & IFF_NOARP)		return (0);	/*	 * 先把要发送的数据指针临时保存,等到发送ARP请求查询包后,得到正确的对方硬件地址时再发送	 */	if (la->la_hold)               /*上次还有没发的吗(也是因为同样的原因,但要发送的IP没被解释)?*/		m_freem(la->la_hold);      /*释放掉上次的包(一个mbuf链)*/	la->la_hold = m;			   /*把这次的保存进去*/	if (rt->rt_expire) {           /*如果*/		rt->rt_flags &= ~RTF_REJECT;		if (la->la_asked == 0 || rt->rt_expire != time_second) {			rt->rt_expire = time_second;			if (la->la_asked++ < arp_maxtries)/*在解释地址时重复发送ARP请求的包的次数,共5次*/			    arprequest(ac,&SIN(rt->rt_ifa->ifa_addr)->sin_addr,&SIN(dst)->sin_addr, ac->ac_enaddr);			else {				rt->rt_flags |= RTF_REJECT;/*为了防止ARP泛洪,*/				rt->rt_expire += arpt_down;/*arpt_down=20秒,一旦公布了down, 20秒不发送 */				la->la_asked = 0;			}		}	}	return (0);}/* * 当数据包在if_ethersubr.c中的ether_input函数处理后,如果查到源,目的地址后的 * 2字节是ETHERTYPE_ARP时会产生一软中断,中断向量指向此arpintr函数,实际上的意思 * 是网络上有一ARP包被我们的网卡接收了.就由arpint函数处理 */static voidarpintr(){	register struct mbuf *m;	register struct arphdr *ar;	int s;/*要理解下面的while循环,你必须看看我从if_ethersubr.c中的处理数据包到队列的情况,	下面是我ctrl+v过来的:---------------------------------------------------------------------------------------------		s = splimp();/*关网络中断*	if (IF_QFULL(inq)) {      /*#原型是define	IF_QFULL(ifq)		((ifq)->ifq_len >= (ifq)->ifq_maxlen)  队列满*		IF_DROP(inq);		/*原型是#define	IF_DROP(ifq)		((ifq)->ifq_drops++)     丢弃数加1*		m_freem(m);	} else		IF_ENQUEUE(inq, m);	/*以下是原型,作用是把m(mbuf链)加入到队列inq的尾巴	#define	IF_ENQUEUE(ifq, m) { \	(m)->m_nextpkt = 0; \        mbuf链表的下一个链表为结束,注意:不是mbuf链中的下一mbuf	if ((ifq)->ifq_tail == 0) \  如果队列尾巴为没有,则该队列没初始化		(ifq)->ifq_head = m; \   初始化队列头为M	else \                       有尾巴,即该队列已经有mbuf		(ifq)->ifq_tail->m_nextpkt = m; \  当前队列的尾巴的mbuf链首指针为m 	(ifq)->ifq_tail = m; \        队列的尾巴指向m(是一mbuf链首)	(ifq)->ifq_len++; \           队列长度加1}	*如果您对队列,mbuf,mbuf链,mubf链首搞的稀里糊涂的话,不要紧,我会写一篇关于mbuf的文章	splx(s); /*开网络中断*-----------------------------------------------------------------------------------------------	*/	while (arpintrq.ifq_head) {/*arpintrq就是上面的inq*/		/*		这里我解释一下arpintrq结构,该结构实际上是一ifqueue结构,在if_ether.h中定义如下:		struct	ifqueue arpintrq;		那么ifqueue又是什么样的呢?		在if_var.h中是这样定义的:		struct	ifqueue {			struct	mbuf *ifq_head;          /* mbuf链(排在队列的第一个)			struct	mbuf *ifq_tail;			 /* mbuf链(排在队列的最后一个)  注意:记住了,是mbuf链,不是单个的mbuf			int	ifq_len;                     /* 多少个链			int	ifq_maxlen;                 /*最大容纳mbuf链数,他有个初始值,由网卡驱动程序填写,我见到的是5			int	ifq_drops;                  /*和ifq_maxlen配合使用,当队列放满了即ifq_len>ifq_maxlen时,ifq_drops加1,		};                                  /*并且抛弃进来的mbuf链		*/		s = splimp();/*关中断,凡是对队列进行操作的都要*/		IF_DEQUEUE(&arpintrq, m);/*把队列中的第一个mbuf链的指针放入m中		我们来看看这个宏		#define	IF_DEQUEUE(ifq, m) { \              /*当然,这ifq是指arpintrq			(m) = (ifq)->ifq_head; \                 /* 第一个mbuf链放到m中			if (m) { \                              /*如果m指向空,在宏之外的函数会处理				if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \ /*把该链的下一个链首放入队列头并判断是否为空					(ifq)->ifq_tail = 0; \      /*如果头都为空,那么尾巴一定要置空,要不然...就全乱套了					(m)->m_nextpkt = 0; \  /*多此一举,你们看看上面都判断了为空,这里还要填空					(ifq)->ifq_len--; \    /* 长度减一				} \			}				*/		splx(s);/*操作完成,开中断*/		if (m == 0 || (m->m_flags & M_PKTHDR) == 0)/*因为上面的宏会返回空,所以在这里要处理一下*/			panic("arpintr");	                if (m->m_len < sizeof(struct arphdr) &&                    ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {					/*注意上面这个if,他是先执行m->m_len<sizeof(struct arphdr),					也就是说如果mbuf链的第一个mubf的长度小于标准的arp头部的话,有可能在这个mbuf中					只有arp头的一部分,另外一部分通过调用m_pullup合并相邻的这两个mbuf看看是否有效,					根据统计,通常是无效的,这种情况在判断IP头的时候也会遇到.m_pullup是一大函数,以后我					会讲一讲					*/			log(LOG_ERR, "arp: runt packet -- m_pullup failed\n");/*记录下来*/			continue;/*既然这个mbuf链是无意义的,那么进行下一个while*/		}		ar = mtod(m, struct arphdr *);		if (ntohs(ar->ar_hrd) != ARPHRD_ETHER		    && ntohs(ar->ar_hrd) != ARPHRD_IEEE802) {			log(LOG_ERR,			    "arp: unknown hardware address format (0x%2D)\n",			    (unsigned char *)&ar->ar_hrd, "");			m_freem(m);/*释放掉该mbuf链*/			continue;/*既然这个mbuf链是无意义的,那么进行下一个while*/		}		if (m->m_pkthdr.len < sizeof(struct arphdr) + 2 * ar->ar_hln/*这是判断该mbuf链的			总长度(即一arp包的长度)是否合格,在我的ARP头文件解释中有说明ARP包的长度及结构*/		    + 2 * ar->ar_pln) {			log(LOG_ERR, "arp: runt packet\n");			m_freem(m);/*释放掉该mbuf链*/			continue;/*既然这个mbuf链是无意义的,那么进行下一个while*/		}		switch (ntohs(ar->ar_pro)) {#ifdef INET			case ETHERTYPE_IP:/*我们知道的ARP解释就目前只有对IP的*/				in_arpinput(m);/*调用分析函数,在下面*/				continue;

⌨️ 快捷键说明

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