?? if_etherarp.c
字號:
/* * 以太網解釋協議(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 + -