解决eCos系统的lwIP存在的bug,该bug导致TCP重发失效,最终导致TCP拒绝服务

您所在的位置:网站首页 tcp发包和重发 解决eCos系统的lwIP存在的bug,该bug导致TCP重发失效,最终导致TCP拒绝服务

解决eCos系统的lwIP存在的bug,该bug导致TCP重发失效,最终导致TCP拒绝服务

#解决eCos系统的lwIP存在的bug,该bug导致TCP重发失效,最终导致TCP拒绝服务| 来源: 网络整理| 查看: 265

问题描述

跑 eCos + lwIP 的设备作为 TCP 服务器,在网络不繁忙不丢包的情况下,一切正常,在网络繁忙会出现丢包的情况下,重试几次后 TCP 拒绝服务(对 SYN 包都不会有任何响应, ping 功能可能正常也可能无响应),其它任务正常。能够承受的重试次数和选项 lwIP networking stack >> Protocols >> TCP support >> Sender pbufs (CYGNUM_LWIP_TCP_SND_QUEUELEN) 有关(据我推测,没有实测)。

抓到的数据包如下: 在这里插入图片描述

Time 栏是两个数据包的间隔。835 号数据包是客户端向服务器发起的请求,跑 eCos + lwIP 的设备作为服务器端。836 号数据包是服务器在接收到请求后给出的响应。836 号同时还携带了 835 号包的 ACK。837 号数据包是 835 号数据包的重发包,显然客户端没有收到 836 号数据包,836 号数据包丢失了。客户端既没有收到响应数据,也没有收到 835 号包的 ACK,经过 250 ms 后重发请求数据包,即 837 号数据包。838 号数据包是服务器告诉客户端已经接收到 837 号包了,不用再重发了,注意这个包只有 ACK 没有响应数据。10 秒后,客户端没有收到响应,关闭了连接,839 号包 ~ 841 号包是关闭连接三次握手。

看出来了吗?

客户端没有收到服务器的响应,服务器也没有重发!这不是 TCP 啊!TCP 是会重发的,对方没有收到就会重发,但是这里就是没有重发。

解决办法

原因是定时器资源不够,TCP 没有申请到定时器,没法处理任何和超时有关的事物。先给出解决办法,问题分析在后面。有两个办法可以解决这个问题,二选一,第二方法更彻底。

一、在配置工具中增加一个用户定时器

在这里插入图片描述

将上图所示的 Simultaneous active timeouts by user modules 选项值加1。这样 lwIP 就有足够的定时器可用了,TCP 所需要的定时器也能正确分配到。

二、修改 lwip_net.cdl

这个办法更加地彻底,从根本上解决了缺少定时器的问题。

关于超时定时器的配置部分(lwip_net.cdl:1342):

cdl_option CYGNUM_LWIP_MEMP_NUM_CORE_SYS_TIMEOUT { display "Simultaneous active timeouts by core modules" flavor data calculated { CYGPKG_LWIP_TCP + CYGFUN_LWIP_IP_REASSEMBLY + CYGPKG_LWIP_ARP + (CYGPKG_LWIP_DHCP * 2) + CYGPKG_LWIP_AUTOIP + CYGPKG_LWIP_IGMP + CYGPKG_LWIP_DNS + CYGPKG_LWIP_PPP } description " The number of simulateously active timeouts used by the lwIP core modules." }

从这个选项的脚本可以看出,lwIP 所需要的定时器数量是根据所选择的功能自动算出来的,但是少了 lwip_select 所需要的那个超时定时器。

将该脚本改成如下:

cdl_option CYGNUM_LWIP_MEMP_NUM_CORE_SYS_TIMEOUT { display "Simultaneous active timeouts by core modules" flavor data calculated { CYGPKG_LWIP_TCP + CYGFUN_LWIP_IP_REASSEMBLY + CYGPKG_LWIP_ARP + (CYGPKG_LWIP_DHCP * 2) + CYGPKG_LWIP_AUTOIP + CYGPKG_LWIP_IGMP + CYGPKG_LWIP_DNS + CYGPKG_LWIP_PPP + CYGPKG_LWIP_SOCKET_API } description " The number of simulateously active timeouts used by the lwIP core modules." }

即在选项的计算式中加入 + CYGPKG_LWIP_SOCKET_API 。lwip_select 是 CYGPKG_LWIP_SOCKET_API 组件提供的一个函数。

修复后抓取的包: 在这里插入图片描述

204 号包是客户端发起的请求。205 号包是我们的设备返回的响应,这个包没有到达客户端,中途丢失了。206 号包是 204 号包的重发。207 号包是对 206 号包的确认,客户端接收到这个 ACK 包后,知道服务器已经接收到请求包了,不再重发请求包。208 号包是对 205 号的重发,我们的设备一直没有收到客户端对 205 号包的 ACK ,因此重发此包。209 号包是客户端确认接收到了我们的设备返回的响应。这个处理丢包的流程是正确的。 原因分析

lwIP 有个很好的特性,那就是 Traffic statistics,打开这个特性,lwIP 可以统计数据包的收发以及内存的使用情况。在资源足够的情况下,强烈建议打开该选项。在 eCos 中,这个选项是 lwIP networking stack >> Traffic statistics (CYGPKG_LWIP_STATS)。

调试是查找问题的好帮手,一定要留调试接口,一定要掌握调试这么手艺。

将设备连接调试器,连续运行直到故障重现,暂停程序执行,这个时候就可以检查 statistics 了,查看 lwip_tcpip >> current >> src >> core >> stats.c 文件中的 lwip_stats 结构。

检查的结果就是 SYS_TIMEOUT 类型的 LWIP_MEMPOOL 发生了错误,只分配了 6 个,但是实际最多需要 7 个。

给 lwIP 多增加几个定时器资源,再执行就不会出现故障了。

因此可以肯定 TCP 处理超时重发的定时器分配失败了,也就没有 TCP 的超时处理了,也就不会重发了。lwIP 所需要的定时器,大部分都在 tcpip_thread 的开始处申请完了,TCP 的定时器是在有需要的时候调用 tcp_timer_needed 函数申请的。在 eCos 中,lwIP 所需要的定时器个数是自动计算的:

CYGNUM_LWIP_MEMP_NUM_CORE_SYS_TIMEOUT = CYGPKG_LWIP_TCP + CYGFUN_LWIP_IP_REASSEMBLY + CYGPKG_LWIP_ARP + (CYGPKG_LWIP_DHCP * 2) + CYGPKG_LWIP_AUTOIP + CYGPKG_LWIP_IGMP + CYGPKG_LWIP_DNS + CYGPKG_LWIP_PPP

经检查发现,除了上面引用到的特性会使用定时器外,socket 的 lwip_select 函数也会使用到定时器,因此这里算式少算了一个定时器,问题就出在这。

lwip_select 函数通过调用 sys_sem_wait_timeout 函数间接地使用到了定时器。

我们的程序使用了 lwip_select 函数,而且还带超时,所以触发了这个bug。

缺少 TCP 定时器引起TCP拒绝服务的原因:

TCP 发送一个数据包后不会立即释放该数据包的内存资源,因为该数据包可能还需要重发。网络不丢包的情况下,对方能正确地接收数据包,并返回 ACK 包,lwip 在接收到 ACK 包后释放发送包的内存资源。所以在不丢包的情况下,不会有问题。网络丢包的情况下,超时定时器会重发没有被 ACK 的数据包,直到接收到 ACK 或发送超时再释放发送包的内存资源,超时定时器未被开启的情况下,发送的数据包丢失以后,因为没有了超时重发,对方永远都接收不到数据包,lwip 也不会接收到该数据包的ACK而释放资源,同样也不会因为发送超时而释放资源(因为定时器没开启,所有超时机制都失效了),因此这个数据包将永远占据着资源而不释放。发生多次这样的情况以后,内存资源被耗尽,lwip 已经申请不到内存来处理新的数据包了,开始出现拒绝服务。lwip 使用的内存资源有多种,看哪种资源首先被耗尽,可能会导致ping不通的情况。

还有更快捷地发现问题的途径:启用断言!

lwIP 的断言设计也是很完善的,完全可以使用断言来捕获资源不够的问题,查看定时器申请的代码(sys_timeout函数):

timeout = memp_malloc(MEMP_SYS_TIMEOUT); if (timeout == NULL) { LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL); return; }

如果启用了断言,当资源分配失败,这里的 LWIP_ASSERT 就被触发了!

但是断言有一点不好,非调试状态下它会引起系统死机或复位,而不仅仅是网络功能失效,对产品的口碑而言,网络功能失效比死机或复位要好一些。

要打开 eCos 中 lwIP 的断言,那么就要打开整个 eCos 的断言。

嗯 …… 下次找问题,先打开断言!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3