Linux中IP隧道的分析与建议( 二 )



/;;;;子网A;;;;;;;/;;;子网C;

//;;;

|;;|;;;;;;|;;;;;;;|

|;;;;;&;;;;|;;;;;;|;;;;;;;|

|;;;;; ;;;;;;;|;;;;;;|;;;;;;*****;;;;|

|;;;;;;;; ;;;;|;;;;;;|;;;;;;*;;;*;;;;|

|;;;;; ;;;;|;;;;;;|;;*****;;;*;;;;|

;;;/;;-----------;;;*;;;;;;;*;;;;/;;----------

>;#;*;**>(#);*;;;;;;;***>;#;;;;;

--------------;;/;**;;;;------------;;/;;;

|;;**;;;|;;;;;;|;;;; ;|

|;;**;;;|;;;;;;|;;;; ;|

|;;*****;;;;*;;;|;;;;;;|;;;;;;;|

|;;;;;;*****;;;;|;;;;;;|;;V;;;|

|;;;;;;;|;;;;;;|;;&;;;|

/;;;;;/

子网B;;;/;;;;子网D;;;;/

-----------;;;;----------



;;;;;;;原数据报

******;;;;;;;封装后的数据包(封包)

#;;;;封装/解封

&;;;;用户主机



图一.;;封包协议实现模型





看图中的设备;# , 分别处于隧道的两端 , 分别起打包(封装)和解包(解封)

的作用 , 在整个数据包的传送路径中 , 除了隧道两端的;#;设备 , 其他网关把

数据包看成一个普通的IP包进行转发 。

设备;#;就是一个封包基于的两个实现部件--封装部件和解封部件 。封装和解封

部件(设备)都应当同时属于两个子网 。封装部件对接收到的数据报加上封包头

, 然后以解封部件地址作为目的地址转发出去;而解封部件则在收到封包后 , 还

原原数据报 , 转发到目的子网 。



隧道的源端(封装部件)对进入隧道的数据包进行封装 , 形成封包 。一个完整

的封包如图二所示 。



/;; -----------------

|;;|;;;;封包IP头;;;;;|;

封包头;;;|;; -----------------

|;;|;;;封包协议头;;;;|

-----------------

/;;|;;;;原协议头;;;;;|;

|;; -----------------

|;;|;|

原数据报;;|;;|;;;原协议数据;;;;|;

|;;.;.

|;;.;.

|;;|;|

-----------------



图二.;;;;;;封包结构







二、

Linux中的实现



本人分析的版本是Linux2.0.34(RedHat5.2采用) 。



在Linux中 , 隧道的实现主要基于两个文件new_tunnel.c和ipip.c



同时Linux定义了一种新的协议类型--IPIP(IPPROTO_IPIP) , 与上面所说封包

类型类似 。



基本思路

在Linux中IP;Tunnel的实现也分为两个部件:封装部件和解封部件 , 分别司职发送和接

收 。但这两个部分是在不同的层次以不同的方式实现的 。

封装部件是在数据链路层以虚设备的方式实现 。所有源代码见

/usr/src/linux/drivers/net/new_tunnel.c

为实现封装 , Linux实现一个称为tunl的网络设备(类似loopback设备) , 此设备

具有其他网络设备共有的特征 , 对于使用此设备的上层应用来说 , 对这些网络设备

不加区分 , 调用及处理方法当然也完全一样 。

tunnel_init()和tunnel_xmit()是new_tunnel.c中的两个主要过程 。

tunnel_init()初始化与设备tunl相关的device结构 。

而tunnel_xmit()在从tunl设备发送数据时被调用 , tunl设备作为实现IP隧道

技术的封装部分 , 在此过程中完成对相应的数据报进行封装所需的全部操作 ,

形成IPIP类型的IP包 , 并重新转发此数据包(ip_forward()) 。

解封部件在IP的上层实现 , 系统把它作为一个虚的传输层(实际上与传输层毫无

关系) , 具体处理见文件

/usr/src/linux/net/ipv4/ipip.c 。

我们知道 , 每一个IP数据包均交由ip_rcv函数处理 , 在进行一些必要的判断后 , ip_rcv

对于发送给本机的数据包将交给上层处理程序 。对于IPIP包来说 , 其处理函数是

ipip_rcv(就如TCP包的处理函数是tcp_rcv一样 , IP层不加区分) 。也就是说 , 当

推荐阅读