1. 引言
本文将分析linux2.2.x地址伪装实现中对ICMP协议的处理。与TCP和UDP协议不同,ICMP协议没有端口的概念,所以必须采用其他的参数来区分相同地址的伪装后的ICMP协议包,并且在有应答包时做反向的转换。下面就是对这个过程的分析。
2.概述
ICMP协议有两种类型: 查询报文和差错报文。其格式如下:
[图1.1]
查询报文中,Type是查询类型;Code值为0没有使用;Checksum是ICMP头和数据的校验和;Identifier用于标识发包的session,一般填为进程的进程号;Sequence标识同一session中的不同包,序列号每次加1;Data中的数据因Type的不同而不同。地址伪装中处理的查询报文类型以及其应答报文的类型为:
ICMP_ECHO,ICMP_ECHOREPLY回显请求应答;
ICMP_TIMESTAMP,ICMP_TIMESTAMPREPLY时间戳请求应答;
ICMP_INFO_REQUEST,ICMP_INFO_REPLY信息请求应答(已作废不用);
ICMP_ADDRESS,ICMP_ADDRESSREPLY地址掩码请求应答。
[图1.2]
差错报文中,Type是差错类型;Code是差错类型中的子类型;Checksum是ICMP的校验和(校验和覆盖ICMP的头和数据)。其数据部分包含出错包的IP头(包括选项)和IP数据的前八个字节。地址伪装只处理三种协议(ICMP,TCP,UDP)的差错包,并且只处理三种类型的差错报文,如下:
ICMP_DEST_UNREACH(目的不可达),ICMP_SOURCE_QUENCH(源端被关闭),ICMP_TIME_EXCEEDED(超时)。
3. ICMP协议的地址伪装
下面分析伪装和解伪装两个过程对ICMP包的处理,并引用下图所示的环境进行分析:
[图2.1]
在FW上配置A到B的地址伪装,B到A的端口转发规则如下:
ipchains -A forward -s 10.0.0.0/8 -d 192.168.0.0/24 -j MASQ
ipmasqadm portfw -a -P tcp -L 192.168.0.88 80 -R 10.0.0.1 80
分析所涉及的几个不同的情形是:
(1) A到B的ICMP查询报文,B返回成功的应答报文。
(2) A到B的ICMP查询报文,B返回失败的差错报文。
(3) A到B的TCP或UDP请求,B返回失败的差错报文。
(4) B到A的ICMP查询报文,这种情况没有处理。
(5) B到A的TCP或UDP请求,A返回失败的差错报文。
3.1. ip_fw_masquerade
ip_fw_masquerade处理A到B的查询报文和差错报文。首先在ip_fw_masquerade中判断协议类型是否是ICMP,如果是,则调用函数ip_fw_masq_icmp。在这个函数中,对查询报文和差错报文的处理过程不同,下面分两种情况讨论。
3.1.1. 查询报文
a: 判断ICMP的类型是否是查询报文类型:
ICMP_ECHO,ICMP_TIMESTAMP,ICMP_INFO_REQUEST,
ICMP_ADDRESS。如果不是,跳过下面的处理。如果是,到下一步。
b: 在伪装结构的哈希表中查找相应的伪装结构是否已创建
(ip_masq_out_get),查找时用icmp_id(查询报文中的Identifier)代替源端口;用icmp_hv_req(查询报文中的Code加Type左移八位)代替目的端口。如果查找不成功,创建新的伪装结构,如图:
[图2.2]
(图中icmp_id,icmp_hv_req只是示意,并不是真实填写的值,真实的值应当是一个16位的无符号整数)
c: 将IP头中的源地址替换为伪装地址: iph->saddr = ms->maddr,ICMP头中的Identifier替换为伪装端口:(icmph->un).echo.id = ms->mport。以上的修改需要重新计算IP和ICMP的校验和。
3.1.2. 差错报文
对差错报文的处理可以分为两类来讨论。第一类是ICMP查询报文的差错报文(差错报文不会产生新的差错报文,否则会造成死循环);第二类是TCP/UDP的差错报文。在处理之前首先判断差错报文的类型是否是系统可以处理的类型:
ICMP_DEST_UNREACH,ICMP_SOURCE_QUENCH,ICMP_TIME_EXCEEDED。 如果不是,直接返回0。
3.1.2.1. ICMP的差错报文
a: 找到差错报文中包含的原IP头,查看其协议是否是ICMP,如果不是,跳过下一步的处理。
b: 在伪装结构的哈希表中查找是否有差错报文中原查询报文对应的伪装结构(这个结构应该在ip_fw_demasquerade中创建)。 这里查找所使用的地址是原查询报文的地址,所以源地址/目的地址与正常的查找是相反的。如果没有找到相应的结构,返回0。
c: 然后修改IP头中的源地址:iph->saddr = ms->maddr,
原IP头中的目的地址: ciph->daddr = ms->maddr,
和原查询报文中的Identifier: (cicmph->un).echo.id = ms->mport。 以上的修改需要重新计算IP和ICMP的校验和。
3.1.2.2. TCP/UDP的差错报文
a: 找到差错报文中包含的原IP头,查看协议是否是TCP或UDP,如果不是,返回0。
b: 在伪装结构的哈希表中查找是否有与差错报文中的原TCP或UDP包对应的伪装结构(这个结构应该在ip_fw_demasquerade中创建)。 这里查找所使用的地址和端口同样是原TCP或UDP包中的地址和端口,所以源地址/源端口和目的地址/目的端口与正常的查找是相反的。如果没有找到相应的结构,返回0。
c: 然后修改IP头中的源地址:iph->saddr = ms->maddr,
原TCP或UDP包中的目的地址和目的端口:
ciph->daddr = ms->maddr, pptr[1] = ms->mport。 以上的修改需要重新计算IP和ICMP的校验和。
3.2. ip_fw_demasquerade ip_fw_demasquerade处理B到A查询报文和差错报文。对ip_fw_demasquerade的分析也采用与分析ip_fw_masquerade相同的分类来进行。首先在ip_fw_demasquerade中判断协议类型是否是ICMP,如果是,则调用ip_fw_demasq_icmp来处理。
3.2.1. 查询报文
a: 首先判断查询报文的类型是否是系统可以处理的类型: ICMP_ECHOREPLY,ICMP_TIMESTAMPREPLY,ICMP_INFO_REPLY, ICMP_ADDRESSREPLY(这里的类型都是查询报文的应答报文,所以必须先有A到B的查询报文。默认不处理B到A的查询报文)。如果不是,跳过后面的处理。如果是,到下一步。
b: 在伪装结构的哈希表中查找相应的伪装结构是否已创建(这个结构应该在ip_fw_masquerade中处理A到B的查询报文时创建)。 查找使用icmp_hv_rep得出的值代替源端口,用icmp_id得出的值代替目的端口。
c: 然后拷贝SKB中的数据(在这之前使用的是SKB指针,如果这是一个clone的指针,说明数据被共享,改动之前,应先复制一份新的数据,后面的分析中也有相同的操作)。
d: 将IP头中的目的地址替换为伪装结构中的源地址:iph->daddr = ms->saddr, 将ICMP头中的Identifier替换为伪装结构中的源端口:(icmph->un).echo.id = ms->sport。 以上的修改需要重新计算IP和ICMP的校验和。
3.2.2. 差错报文
差错报文同样分为ICMP查询报文的差错报文和TCP或UDP的差错报文两种情况讨论。处理之前先要判断差错报文的类型是否是系统可以处理的三种类型:
ICMP_DEST_UNREACH,ICMP_SOURCE_QUENCH,ICMP_TIME_EXCEEDED。如果不是,返回0。
3.2.2.1. ICMP的差错报文
a: 首先判断原IP头中的协议号是否是ICMP。如果不是,跳过下面的处理。
b: 在伪装结构的哈希表中查找与原ICMP包对应的伪装结构(这应该在ip_fw_masquerade中创建)是否存在。查找使用的是原ICMP包中的地址,所以源地址和目的地址与正常的查找相反。如果没有找到这个结构,则返回0。
c: 拷贝SKB的数据(masq_skb_cow)。
d: 修改IP头中的目的地址: iph->daddr = ms->saddr,
原ICMP头中的源地址和Identifier:ciph->saddr = ms->saddr;
(cicmph->un).echo.id = ms->sport。以上的修改需要重新计算IP和ICMP的校验和。
3.2.2.2. TCP/UDP的差错报文
a: 首先判断原IP头中的协议号是否是TCP或UDP,如果不是,返回0。
b: 在伪装结构的哈希表中查找与原TCP或UDP包对应的伪装结构(这应该在ip_fw_masquerade中创建)是否存在。查找使用的是原TCP或UDP包中的地址和端口。所以源地址/源端口,目的地址/目的端口与正常的查找相反。如果没有找到这个结构。则返回0。
c: 拷贝SKB的数据(masq_skb_cow)。
d: 修改IP头中的目的地址: iph->daddr = ms->saddr,
原TCP或UDP包中的源地址/源端口:ciph->saddr = ms->saddr,
pptr[0] = ms->sport。以上的修改需要重新计算IP和ICMP的校验和。
3.3. 总结
地址伪装修改转发包的源地址和源端口,收到包的目的地址和目的端口。 ICMP协议中没有端口的概念,所以使用了一些特殊的处理方法。从上面的分析可以看到。默认情况下,只处理OUTBOUND(内到外的转发)方向上的查询报文,INBOUND(外到内的应答)方向上只处理OUTBOUND查询报文的应答报文。差错报文在两个方向上都处理。
文章转载地址:http://www.cnpaf.net/Class/hack/05121820345226347493.htm