简介:
这是一些在分析LINUX2.2.x网络安全实现时碰到的问题,有些是网友问的,有些是同事问的,有些是自己觉得比较重要的。现在将问题和答案一一列出,希望能够有点用处。
1. ipchains如何检查循环?
ipchains的链和规则都是单向链表,如下图所示:
[图1.1]
规则加在链上,规则的数据结构是ip_fwkernel。它的成员ip_fw是规则的参数,simplebranch是规则的返回值,branch指向其他的链。对传入ip_fw_check的包,它按下面的流程处理:
[图1.2]
从流程中可以看到,每次对传入的包进行匹配时,如果规则的目标是一个链,都会将当前链的指针保存在目标链中,以标记此链已检查过了。如果规则的目标是个动作,就会将此前所作的所有标记都清除。如果目标链上的规则都没有被匹配,在返回前一个链时,会将目标链上的标记清除。所以如果规则的目标是一个链,并且链上已做过标记,则说明规则中有循环。
2. ipchains如何禁止对本机的ping?
ping是基于ICMP协议实现的。在ipchains的规则中,将ICMP的type看作源端口,将ICMP的code看作目的端口。所以,如果要禁止本机应答ping的请求,可以用如下的规则:
ipchains -A input -s 0/0 8 -j DENY ,禁止任意地址ping的请求。
或者用如下的规则:
ipchains -A output -d 0/0 0 -j DENY,禁止本机的ping的应答。
3. ipchains如何支持SMP?
ipchains的规则可以在两种上下文中被访问。一是在系统调用的上下文中(本机发出的包),在这个上下文中,访问会被硬件中断或bottom half打断;另一个是在net_bh中,这是中断上下文,与进程无关,只能被硬件中断打断。ipchains中的链的成员(struct ip_reent reent[0])保存进入链的指针,规则的成员(struct ip_counters counters[0])保存对数据包的统计。这两个结构成员都是动态创建的,并且为每个CPU创建了两个相同的结构,一个在系统调用上下文中引用,一个在中断上下文中引用。这样即使有多个执行路径都得到读锁,它们所访问的结构是不同的,互不影响,这样既支持了SMP,又不影响效率。但是如果有写的执行路径得到写锁,这种情况下是独占的,其他的路径不能进入临界区。
4. ipmasq如何完成状态变迁?
ipmasq记录了TCP连接的状态变迁,以及不同状态上的超时。看看它是如何实现这个功能的。
首先,它定义了一系列的状态:
这些状态与TCP中定义的状态一致。其中IP_MASQ_S_NONE是初始状态, IP_MASQ_S_LAST用于捕获错误。IP_MASQ_S_UDP、IP_MASQ_S_ICMP标记UDP和ICMP协议的地址伪装结构。
对TCP协议,它定义了一个状态数组:
下面是A到B(OUTBOUND方向)的TCP的主动连接的状态转换过程:
(1) A发出syn的连接请求包。这个包在ip_fw_masquerade中处理,它创建一个新的伪装结构,并将它的状态置为IP_MASQ_S_NONE。然后调用函数masq_set_state,查找OUTPUT方向的,syn行的IP_MASQ_S_NONE状态对应的状态,是mSS。
(2) B回应sy/ack的包。这个包在ip_fw_demasquerade中处理。它调用函数masq_set_state,查找INPUT方向的,syn行的mSS状态对应的状态,是mES。
(3) A发出ack的应答包。这个包在ip_fw_demasquerade中处理。它调用函数masq_set_state,查找OUTPUT方向的,ack行的mES状态对应的状态,是mES。
A到B(OUTBOUND方向)的TCP的主动关闭的状态转换过程:
(4) A发出fin的包。这个包在ip_fw_masquerade中处理。它调用函数masq_set_state,查找OUTPUT方向的,fin行的mES状态对应的状态,是mFW。
(5) B回应ack的包。这个包在ip_fw_demasquerade中处理。它调用函数masq_set_state,查找INPUT方向的,ack行的mFW状态对应的状态,是mFW。
(6) B发出fin的包。这个包在ip_fw_demasquerade中处理。它调用函数masq_set_state,查找INPUT方向的,fin行的mFW状态对应的状态,是mTW。
(7) A回应ack的包。这个包在ip_fw_masquerade中处理。它调用函数masq_set_state,查找OUTPUT方向的,ack行的mTW状态对应的状态,是mTW。
INBOUND方向的状态变迁也可用相同的方法分析。
每个状态都有对应的超时值,默认的超时值在表masq_timeout_table中定义,如下:
可以定义自己的超时值的结构,并在创建伪装结构时指向这个结构。没有被引用的地址伪装结构过了超时时间会被删除。
5. ipmasq如何查找伪装地址和伪装端口?
伪装地址在调用函数ip_fw_masquerade时传入。如果这个地址为0,则调用函数ip_route_output选取一个地址。这个地址一般是发出设备上的第一个地址。伪装端口的范围是[61000,65096]。创建一个新的地址伪装结构,可用端口数减小1;释放一个地址伪装结构,可用端口数增加1。记录可用端口数量的结构是masq_free_ports。这是一个数组,分别记录TCP,UDP,ICMP协议的可用端口。参数PORT_MASQ_MUL定义端口可复用的次数,默认定义是1,所以默认只能创建4096个TCP、UDP、ICMP协议的伪装结构。如果有多个可选的伪装地址,则可以增大这个值,使可作地址伪装的连接数增多,而不是默认的4096个。
变量mport_count记录指定伪装端口的数量。如果创建伪装结构时指定伪装端口,这个伪装结构会加入IP_MASQ_F_MPORT的标记。
6. ipmasq中修改应用协议数据如何重新计算序列号?
在对地址伪装的分析中我们提到,可以通过修改应用协议数据并创建相应的地址伪装结构来支持穿过防火墙的包含动态地址和端口的应用协议。对于基于TCP协议的应用协议,修改它的数据有可能会改变TCP的序列号。如果不修正它的序列号,会引起通讯错乱。所以在应用协议的地址伪装模块的流程中会重新计算它修改过的TCP数据的序列号。举个例子来说明它的过程:
a. A(内网)向B(外网)发送了一个包含动态地址和端口的TCP包,在ip_masq_app_pkt_out中将修改这个地址和端口,这可能会使包的长度与原来的长度不同。
b. B回复的确认序列号是对修改过数据的确认,如果不进行修正,A将会发送确认序列号之后的数据,中间有一段数据会被跳过。所以在ip_masq_app_pkt_in中会用确认序列号减去第一步中得出的差额。
c. A在第三步的序列号是正常的,但是对B来说,它的一部分已经确认过了。所以在ip_masq_app_pkt_out中,要将A的序列号加上在第一步中得出的差额。
值得指出的是,在一个TCP连接中,可能有多个包的数据被改动,在修正序列号时,这些改动都要计算在内。
7. 路由代码中实现的地址转换与ipmasq有什么区别?
在路由代码中实现的路由只改变地址而不改变端口。它根据策略路由的规则来决定相应的包是否要改变其地址。增加这个功能需要打开编译选项CONFIG_IP_ROUTE_NAT。