《LwIP协议栈源码详解——TCP/IP协议的实现》ARP表查询

姓名:朱小鹏    学号:16010130023

转载:

http://blog.sina.com.cn/s/blog_62a85b950101anvd.html

【嵌牛导读】:这一节主要针对ARP讲解ARP表的创建,更新,查询等操作。这里我们先从几个简单的函数入手讲解ARP各个子模块功能,然后再将各个模块与上层协议结合起来,宏观的讲解ARP模块。

【嵌牛鼻子】:ARP表的创建,更新,查询等操作

【嵌牛提问】:LWIP是怎样进行ARP表的创建,更新,查询等操作?

【嵌牛正文】:

ARP攻击,是针对以太网地址解析协议(ARP)的一种攻击技术。在局域网中,ARP病毒收到广播的ARP请求包,能够解析出其它节点的(IP, MAC)地址,然后病毒伪装为目的主机,告诉源主机一个假MAC地址,这样就使得源主机发送给目的主机的所有数据包都被病毒软件截取,而源主机和目的主机却浑然不知。ARP攻击通过伪造IP地址和MAC地址实现ARP欺骗,能够在网络中产生大量的ARP通信量使网络阻塞,攻击者只要持续不断的发出伪造的ARP响应包就能更改目标主机ARP缓存中的IP-MAC条目。ARP协议在设计时未考虑网络安全方面的特性,这就注定了其很容易遭受ARP攻击。黑客只要在局域网内阅读送上门来的广播ARP请求数据包,就能偷听到网内所有的(IP, MAC)地址。而源节点收到ARP响应时,它也不会质疑,这样黑客很容易冒充他人。

这一节主要针对ARP讲解ARP表的创建,更新,查询等操作。这里我们先从几个简单的函数入手讲解ARP各个子模块功能,然后再将各个模块与上层协议结合起来,宏观的讲解ARP模块。

第一个需要迫不及待要说的函数是find_entry,该函数最重要的输入是一个IP地址,返回值是该IP地址对应的ARP缓存表项索引。函数声明原型如下,

static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)

这里,很有必要翻译一下源代码中注释的内容:该函数主要功能是寻找一个匹配的ARP表项或者创建一个新的ARP表项,并返回该表项的索引号。如果参数ipaddr为给定的非空的内容,则函数需要返回一个处于pending或stable的索引表项,如果没有匹配的表项,则该函数需要返回一个empty的表项,但该表项的IP字段的值要被设置为ipaddr的值,这种情况下,find_entry函数返回后,调用者需要将表项从状态empty改为pending。还有一种情况,如果参数ipaddr为空值,同样返回一个状态为empty的表项。

返回状态为empty的表项,首先从状态标示为empty的空闲ARP表项中选取,如果这样的表项都用完了,同时参数flags的值被设置为ETHARP_TRY_HARD,则find_entry就回收最老的ARP表项,将该表项设置为empty状态返回。

这个函数比较大,有将近200行代码,这里就不贴了,直接讲讲它的工作流程。这部分的讨论还是参考了网上某位大侠的博客,名字记不得了,对不起啊啊啊啊啊!网络,有时确实是个好东西,越发的明白。好了,看看find_entry的工作流程。

首先,lwip有一个比较巧妙的地方,它并不是冲上去就是就把arp缓存中所有的表项搜索一遍,而是做了一个假设,假设这次的表项索引还是上一次的(在很多情况下就是这样的)。所以,LWIP中有个全局的变量etharp_cached_entry,它始终保存着上次用到的索引号,如果这个索引恰好就是我们要找的内容,且索引的表项已经处于stable状态,那就直接返回这个索引号就完成了,we're really fast!

如果情况不够理想,就必须去检索整个ARP表了,检索的过程是从ARP表的第一个表项开始,依次往后检索直至最后一个表项,过程较复杂。对于每个表项首先判断它是否为empty状态,find_entry只关心第一个状态为empty的表项索引值,对该索引值以后的empty表项不感兴趣,忽略。如果一个表项不是empty状态,则判断它是不是pending状态。对于pending状态的表项,需要做以下的事情,先看看它里面存的IP地址和我们的ipaddr是否匹配,如果匹配,好返回该索引值,记住还要更新etharp_cached_entry为该索引值,如果不匹配,则判断该索引的数据包指针是否为空,find_entry试图记录生存时间最长的pending状态有数据缓冲或无数据缓冲的表项索引。如果一个表项也不是pending状态,则判断它是不是stable状态。对于stable状态的表项,与pending状态的表项处理过程相似,find_entry试图记录生存时间最长的stable表项的索引。很晕吧,我也很晕,看了下面这段可能你会好点!

如果到这里都还没有找到匹配的表项,那就很杯具了,我们需要为find_entry调用者返回一个empty的表项索引。经过上面一段后,find_entry已经知道了第一个empty状态表项的索引、生存时间最老的pending状态且有数据缓冲表项的索引、生存时间最老的pending状态且无数据缓冲表项的索引、生存时间最老的stable状态表项的索引,我们暂且先将这四个值假设为a、b、c、d。如果参数flags的值被设置为ETHARP_TRY_HARD,那么find_entry会按照a-->d-->c-->b的顺序选择一个合适的索引返回,为什么是这样的顺序?很明显,不解释。find_entry首先判断a是否在ARP表项范围内,如果是,则选择a,如果不是,则判断b是否在ARP表项范围内,依此类推。当选中一个索引后,随即就会将该索引对应的表项设置为empty状态,并且将该表项的IP地址设置为ipaddr的值,ctime值设置为0,最后返回索引。至此,find_entry大功告成!

接下来,我很感兴趣的一个函数是etharp_query,该函数的功能是向给定的IP地址发送一个数据包或者发送一个ARP请求,当然情况远不如此简单。还是很有必要翻译一下源代码中函数功能注释的内容:如果给定的IP地址不在ARP表中,则一个新的ARP表项会被创建,此时该表项处于pending状态,同时一个关于该IP地址的ARP请求包会被广播出去,再同时要发送的数据包会被挂接在该表项的数据缓冲指针上;如果IP地址在ARP表中有相应的表项存在,但该表项处于pending状态,则操作与前者相同,即发送一个ARP请求和挂接数据包;如果IP地址在ARP表中有相应的表项存在,且表项处于stable状态,此时再来判断给定的数据包是否为空,不为空则直接将该数据包发送出去,为空则向该IP地址发送一个ARP请求。

etharp_query函数原型如下所示,源代码在150行左右,这里主要讲解其流程:

err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)

(1)首先判断给定的ipaddr是否合法,对于空IP地址、广播IP地址、多播IP地址不予处理。

(2)将ipaddr作为参数调用函数find_entry,函数返回一个ARP表项索引,该表项可能是原来已经有的,此时该表项应该是pending或stable状态;该表项也可能是新申请得到的,此时该表项应该是empty状态。

(3)根据返回的表项索引找到该ARP表项,判断该表项是否为empty状态,如果是,说明该表项是新申请的,则将该表项状态设置为pending状态。

(4)判断要发送的数据包是否为空,或者判断ARP表项是否为pending状态,这两个条件只要有一个成立,就发送一个ARP请求出去,发送ARP请求的函数是etharp_request。

(5)如果待发送的数据包不为空,此刻就根据ARP表项的状态作不同的处理:若ARP表项处于stable状态,则直接调用函数etharp_send_ip发送数据包;若ARP表项处于pending状态,则需要将该数据包挂接到表项的待发送数据链表上,由于pending状态的表项必然在第(4)步中发出了一个ARP请求,当内核接收到ARP回应时,会将表项设置为stable状态,并将其链表上的数据全部发送出去,当然这项工作具体是怎样完成的那是后话了。

将数据包挂接在表项的发送链表上,这又是一个较复杂的过程:最重要的一点是判断该数据包pbuf的类型,对于PBUF_REF、PBUF_POOL、PBUF_RAM型的数据包不能直接挂在发送链表上,因为这些数据包在被挂接后并不会被立刻发送出去,这可能导致数据包在等待发送的过程中内部数据被改动。对于以上这些类型的待发送数据包,需要将数据拷贝至新的pbuf中,然后将新的pbuf挂接至发送链表。至此,etharp_query函数功德圆满!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容