Linux 版 (精华区)

发信人: wxh (装做不知道), 信区: Linux
标  题: Linux中IP隧道的分析与建议
发信站: 紫 丁 香 (Sat Jun 26 16:32:54 1999), 转信

  

--------------------------------------------------------------------------------
 
电脑科技 
 1999年06月26日 
  
标 题: Linux中IP隧道的分析与建议
(选自:Linux区,作者:xiaoman04 (xiaoman),时间:1999年06月21日)

            
                 Linux中IP隧道的分析与建议 

********************************************************************** 
**** 
作者的话: 
本文系在阅读Linux源码及一些相关资料的基础上写成的。 
欢迎就文章的各个方面提出建议和批评意见,作者希望更多的交流和探讨。 
欢迎在保留原文完整性的前提下在网上转贴,需部分引用请通知作者。 
传统媒体转载和引用此文,请务必经过作者同意。 
欢迎在实际的应用中使用此文提出的思想,希望同时知会作者。 

作者信箱: xiaoman04@hotmail.com 

欢迎来信!! 

********************************************************************** 
**** 
O、 
由于网络的日益普及,网络的安全成为目前的热门话题。本文对隧道技术的分析 
, 
就侧重安全领域,对利用隧道技术实现虚拟专网提出建议。 

为什么需要IP隧道?没有接触过这个概念的人自然提出这样的疑问。实际上概念 

最初的提出很简单,为了在TCP/IP网络中传输其他协议的数据包。设想IPX协议或 

X.25封装的数据包如何通过Internet网进行传输,在已经使用多年的桥接技术中 
是 
通过在源协议数据包上再套上一个IP协议头来实现,形成的IP数据包通过Intern 
et后 
卸去IP头,还原成源协议数据包,传送给目的站点。对源协议数据来说,就如被 
IP 
带着过了一条隧道。这种技术在业余无线网络(Amateur Packet Radio network 
, 
应该怎么翻,请告诉我)得到了最广泛的应用。 
利用IP隧道来传送的协议包也包括IP数据包,本文主要分析的IPIP封包就是如此 
,从字 
面来理解IPIP就对了,就是把一个IP数据包又套在一个IP包里。为什么要这么做 
呢? 
多此一举嘛。其实不然,见过一些应用就会明白,移动IP(Mobile-IP)和IP多点 
广播 
(IP-Multicast)是两个通常的例子。目前,IP隧道技术在构筑虚拟专网( Vir 
tual  
Private Network)中也显示出极大的魅力。本文也将对利用IP隧道技术构筑VPN 
做 
简单设想。 



背景:隧道的多种理解和实现 

Internet的研究者多年前就感到需要在网络中建立隧道,最初的理解是在网络 
中建立一条固定的路径,以绕过一些可能失效的网关。可以说,隧道就是一条 
特定的路径。 
这样的隧道是通过IP报头中的源路由选项来实现的,在目前看来,这个方法的缺 
陷 
十分明显。要设置源路由选项就必须知道数据包要经过的确切路径,而且目前 
多数路由实现中都不支持源路由。 

另一个实现隧道的机制是开发一种新的IP选项,用来表明源数据包的信息,原IP 
头 
可能成为此选项的一部分。这种隧道的意义与我们所说的隧道已十分接近。但它 
的 
不足在于要对目前IP选项的实现和处理做较大的修改,也缺乏灵活性。 

最后常用的一种实现方法是开发一种新的IP封包协议,仍然套用当前的IP头格式 
。 
通过IP封包,不须指明网络路径,封包就能透明地到达目的地。也可以通过封包 
空 
间把未直接连接的机器绑在一起,从而创建虚拟网络。这种方法易行、可靠、可 
扩 
展性强,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层不加区分)。也就是说, 
当 
一个目的地址为本机的封包到达后,ip_rcv函数进行一些基本检查并除去IP头, 
然后 
交由ipip_rcv解封。 
ipip_rcv所做的工作就是去掉封包头,还原数据包,然后把还原后的数据包放入 
相应的 
接收队列(netif_rx())。 

从以上IP Tunnel实现的思想来看,思路十分清晰,但由于IP Tunnel的特殊性, 
其 
实现的层次并不单纯。实际上,它的封装和解封部件不能简单地象上面所说的那 
样 
分层。tunl设备虽应算进链路层,但其发送程序中做了更多的工作,如制作IPIP 
头 
及新的IP头(这些一般认为是传输层或网络层的工作),调用ip_forward转发新 
包 
也不是一个网络设备应当做的事。可以说,tunl借网络设备之名,一把抓干了不 
少 
工作,真是‘高效’。而解封部件宏观上看在网络层之上,解出IPIP头,恢复原 
数据包 
是它分内的事,但在它解出数据包(即原完整的协议数据包)后,它把这个包 
放入相应的协议接收队列。这种事可不是一个上层协议干的,这是网络设备中断 

接收程序的义务。看到了,在这点上,它好象到了数据链路层。 
是不是有点乱,隧道机制就是这样,你有没有更好的办法? 




三、 
为实现VPN的扩展 

实际上Linux只为实现隧道机制提供了一个框架,图二中的封包协议头在 
Linux中被忽略了,也就是说,封包头只含封包IP头,其后紧跟原IP数据包。 
这样的结构用于传输公开数据没有关系,但对于一个VPN来说,安全保密是 
不可缺少的重要功能。我们希望通过隧道的数据可靠且不可窃取和冒充的, 
那么,加密和认证就必不可少。 
为实现这一构想,设计以下封包协议头: 

         0    4     8          16           24          31  
        +-----+-----+-----------+------------------------+ 
        | ver |type |   hlen    |      OldPacketLen      | 
        +-----------------------+------------------------+ 
        |        DeviceID       |       EncapID          | 
        +-----------------------+------------------------+ 
        |         Flags         |       CheckSum         | 
        +------------------------------------------------+ 
        |         IPIP Options( If any )                 | 
        +------------------------------------------------+ 
        .                                      | padding | 
        .                                                . 
        +------------------------------------------------+ 
         
                 图三、 IPIP头设想图 

ver:  版本号,利于扩展 
type: 用于建立不同目的的隧道(可能处理上有差别) 
OldPacketLen:  进入隧道的原数据包长度 
DeviceID: 对数据包进行封装的设备标识 
EncapID: 此封包的ID号 
Flags: 标志位,共16位,初步定义如下: 
0 保留 
  1 有否加密 
  2 有否做摘要 
  3 有否签名 
  4 保留 
  5 有否传送消息密钥 
  6 消息密钥有否加密 
  7 消息密钥是否需保留 
  8-15 保留 
  
CheckSum: 头校验 
IPIP Options:  用来传送一些必要的数据,比如消息密钥、签名等 
    格式: +-------------------------------------+ 
           | 类型 | 长度 | 数据 ...              | 
           +-------------------------------------+ 
        
好了,有了这个东西,我们就可以扩展Linux IP Tunnel为我们的VPN服务了。 
首先,改写new_tunnel.c和ipip.c两个文件,加入对IPIP头的处理。 

接着,我们要实现一种密钥的管理和传送机制。 
当然,对称密钥是必需的,而对IP数据包加密要使用序列密码。从全体考虑, 

我们可以提出建立VPN的逻辑步骤; 
1、准备工作:建网安装系统完成配置等等 
2、隧道的两端分别向对方发送自己的公开密码和设备号 
3、如有必要,产生序列密码,后加密签名传给对方 
4、正常通信,----放心,你的数据已经很保险了。 

在一个VPN的隧道中,一个封包的格式应如图四所示。 

                    /  +-----------------+ 
                    |  |    封包IP头     |  
           封包头   |  +-----------------+ 
                    |  |   封包协议头    | 
                    \  +-----------------+ 
                    /  |                 |    
                    |  |    原协议头     | 
                    |  |       及        | 
          封包数据  |  |   原协议数据    |  
                    |  .    (密文)     . 
                    |  .                 . 
                    |  |                 | 
                    \  +-----------------+ 
             

                    图四.      VPN封包结构 



你的几种使用方法。 
事情往往不能两全其美,你在安全强度和通信速度上必须作出选择, 
(不然你就需要在安全强度和Money的耗费中做选择。) 
使用这样的协议,根据你的需求不同,你可有不同的使用方法,下面列举 
一些: 
0、跨Internet的公司多个内部网之间进行通信,保密性并不重要 
    直接使用原框架机制,无任何加密措施 
    这样速度快、效率高,公司也不用申请多个IP地址,方便可行 
1、一般性的商业应用,具有保密要求 
    利用事先产生的序列密码,每次对原数据包加密 
    安全度提高了,是一种十分实用的方法。只要强度足够,一般很难破译 
    速度快 
2、密码不变的方式你认为不够安全 
    你可以自己实现一种密码传送方法,每隔一段时间更换一次密码。 
    其中一些握手关系需要完善,有兴趣的欢迎探讨。 
    如果发展成熟,此法相信很有前途。 
4、高度机密领域 
    敬请使用一次一密,并进行每次签名。 
    每次产生新密钥和签名十分费时,在目前我国Internet网络的速度下 
    几乎不可行。 
    但相信有此需要的部门也能够设法提高其网络带宽,让网络状况适合 
    这种应用。 

另外,当然还可以就加密强度自身作出选择,比如选择128位,还是512位、1024 
位 




四、 
待完善 

主要牵涉到隧道的管理,在封包的传送过程中如果出现错误是十分正常的, 
当一台路由器检测到错误时,它会发送一个ICMP包给隧道的发送端,但遗憾的是 

ICMP返回的数据除了IP头外,只含8个字节的上层协议信息。只凭这个难以对 
ICMP信息作出反应,因此,在隧道端保留一些状态信息是必须的。这些信息 
主要包括: 
隧道的另一端的可达性 
隧道的拥塞状况 
隧道的MTU 
    同时所发送的封包信息也是需要保留的,举例说,当一个路由不可达信息 
到来时,封包的发送者要能够找出所封装的数据来自何方,并发送相应的ICMP 
包。 

强调一点,MTU的更新对隧道来将很重要,因为一个灵活的隧道的下一级设备是 

不定的,同时一些数据包本身也要求更改MTU。 



所有这些,在Linux中的处理都不够或根本没有处理。大家努力呀! 
  
  

-- 
※ 来源:.网易虚拟社区 http://club.netease.com.[FROM: 210.28.144.166] 

--
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: mtmail.hit.edu.c]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:208.718毫秒