Java Solaris 加入Sun中国技术社区 我的社区 注册说明
 
ISV Online
 
Zones的常见问题---- 如何让Local Zone共享外部地址
 
By chris.zhu@Sun.COM, 4/3/07  
        Solaris Zones软件分区技术提供了一种虚拟操作系统服务,以创建多个隔离运行环境的方法。在使用者看来,每 一个Local Zone就好比一台独立的机器,那么如何在Local Zone中实现机器的一些常用功能呢成为一个突出的问题。针对那些最常见的问题,跟大家一起分享一下我找到的解决方案。

        问题:我想让Local Zone访问外网。

        某天和同事聊天时提到怎么让Local Zone也访问外网呢,当然最简单的办法是给它一个外部地址。不 过外部IP实在是稀缺资源,不太可能分配给众多的Local Zone,再者,这和我们一般配置Local Zone的习惯也不符。

        一般说来,我们总是会将若干个Local Zone构成一个子网,并且给Global Zone也配上一个该网段的地址,这样各个Local Zone和Global Zone就可以相互进行网络通信了,见图1。

zones_faq2
图1:通用的Zone网络配置图
        那么如何让这些Local Zone既不占用网络资源,又 可以访问外部网络呢?

        尝试1:让Global Zone做路由

        最先想到的是把Global Zone设置为路由,各Local Zone通过它访问外网。但结果不理想,该 路由对Local Zone根本不起效,在Local Zone中甚至无法ping通Global Zone的外部IP。
        为此,我找来三台独立的机器进行实验,两台机器位于两个不同的子网段,第三台机器同时拥有两个网段的地址,并 设置为路由,不同子网内的机器通过它成功的进行了通信。
        看来这一策略本身没有问题,但由于路由表只能在Global Zone中进行维护,我 为LocalZone添加路由的同时,给Global Zone的路由选择带来了复杂性,第一次尝试失败。

        尝试2:让另一台机器充当路由

        既然自己做路由有问题,我把目光转向了另一台机器,给它添加一个子网地址,并将其配成路由,Local Zone终于可以ping通Global Zone的外部IP地址了,另一台机器的外部IP地址也
可以ping通,但是发往外网的报文却有去无回。
        通过跟踪,发现原因在于自己配置的路由使用的是子网地址(也就是常说的非法地址),无法得到公网内路由的认同,因 而并没有加入其路由表中,导致报文返回的通路被截断了。

        尝试3:路由 + NAT

        如何让不合法的地址也能得到承认呢?IP伪装无疑是第一选择,通 过Ipfilter中的网络地址转换功能NAT,把不合法的地址变为公网认可的地址,这里也就是Global Zone的外部IP。
        在上例的基础上(即让另一台机器充当路由,进行转发),启动本机的Ipfilter服务,并添加NAT规则,终 于我的Local Zone通过路由和NAT的双重合作,可以自由的访问外网了。

        具体的步骤如下:
       
        步骤1. 为机器B设置子网环境。
            为机器B配置添加子网的地址,例:192.1.1.200
            将机器B配置为路由,提供IP forwarding的功能。
            # touch /etc/defaultrouter
            # routeadm -e ipv4-forwarding
            # routeadm -u

        步骤2. 为本机增加缺省路由,该缺省路由是为local zone服务的,但由于路由表由global zone统一管理,因此只能在global zone中进行添加。
            # route add default 192.1.1.200

        步骤3. 在本机启用Ipfilter服务的NAT功能,具体的设置方法在尝试4的步骤3中有详细的介绍。
       
        如果设置完毕后还不能工作,可以适当的交换global zone中缺省路由的位置。
        再设置一下DISPLAY,就可以在Local Zone中试试用mozilla上网了。

        尝试4:路由 + NAT 的改良

        但是为了访问外网,还要借用其他的机器,这看起来并不是一个完美的解决方案。后来,在Michael Ditto的blog上找到了一片介绍如何在Global zone中使用NAT的文章,思路和上例类似,但Michael的方法更为巧妙,他采用了一个虚拟的路由,并将本机缺省路由的物理地址赋予该虚拟路由,为 Local Zone构建了一条通向外网路由的通路。
        下面详细列出了改良后的实现方法。

        步骤1. 设置子网环境。
            参照图1中的例子,让Global Zone和Local Zone构成了一个虚拟的子网(192.1.1.*)。
        ● 为Global Zone增加子网IP
            在/etc/hosts中添加子网IP和hostname的映射关系:
                  192.1.1.100 globalzone
            新建文件/etc/hostname.eri0:1, 并加入如下信息:
                   globalzone
        ● 设置各Local Zone的网络环境
            # zonecfg -z zone1
            ...
            zonecfg:zone1> add net
            zonecfg:zone1:net> set address=192.1.1.1/24 #各个zone的IP不同
            zonecfg:zone1:net> set physical=eri0
            zonecfg:zone1:net> end
            zonecfg:zone1> commit
            zonecfg:zone1> exit
           
            Local Zone安装完毕后,一定要先用Console的方式登陆,就 象安装了一台新的机器一样,进行初始化,之后Local Zone就可以正常使用了。

        步骤2. 设置路由
        Michael Ditto提供的方法非常简单,添加一个子网段可识别的虚拟路由,该路由的逻辑IP( 192.1.1.254)位于子网段中,而它的物理地址则直接使用外网路由器的物理地址,一个小小的技巧帮我省去了一台机器。这里我写了一个脚本来实现这一功能,把脚本放到/etc/rc2.d/下,每 次启动就可自动执行。
        在/etc/rc2.d/下新建文件S99routeForZone,文件内容如下:
        #!/usr/bin/bash
        #增加的虚拟路由的IP地址为192.1.1.254
        VIRTUAL_ROUTE=192.1.1.254
        #找到实际使用的外部路由IP
        DEFAULT_ROUTE=`netstat -rn|grep default |grep -v $VIRTUAL_ROUTE |awk 'NR==1 {printf $2 }'`
        #通过arp获取外部路由的物理地址
        ARP_ADDRESS=`arp $DEFAULT_ROUTE|awk '{printf $4 }'`
        #将外部路由的物理地址赋予虚拟路由( 192.1.1.254)
        arp -s $VIRTUAL_ROUTE $ARP_ADDRESS
        #将虚拟路由加入到全局的路由表中
        route add default $VIRTUAL_ROUTE

        执行后,可 以到Local Zone中确认一下自己的路由信息:
            #zlogin zone1
            #netstat -rn
        Routing Table: IPv4
        Destination         Gateway           Flags Ref     Use  Interface
        -------------------- -------------------- -------- ------- -------- ------------
        192.1.1.0          192.1.1.1             U         1         4         eri0:1
        224.0.0.0          192.1.1.1             U         1         0         eri0:1
        default               192.1.1.254        UG      1         5
        127.0.0.1           127.0.0.1            UH       5        80       lo0:1

        #arp 192.1.1.254
        需要说明的是Global Zone和Local Zone的路由表是共享的,而且只有在Global Zone中才有增删的权限。

        步骤3. 启动ipfilter服务
        ipfilter是Solaris10自带的模块,不需要额外的安装。在Solaris10中,所 有的服务统一由SMF进行管理,ipfilter也不例外。
        首先检查一下ipfilter服务和它所依赖的pfil服务是否已经正常启动。
            # svcs -a | grep pfil
                disabled 12:03:43 svc:/network/ipfilter:default
                online Aug_16 svc:/network/pfil:default
                online Aug_16 svc:/system/rmtmpfiles:default

        从上面的输出可以看到ipfilter服务缺省并不启动的。
        在root权限下启动ipfilter服务:
            # svcadm enable svc:/network/ipfilter:default
        不过启动并不成功,始终显示为maintenance状态。仔细观察log文件后,才 发现是因为pfil模块缺省并未加载到网络设备中,导致了ipfilter服务的启动异常。
        修改pfil的配置文件"/etc/ipf/pfil.ap",把你需要进行过滤的网口打开,然后重启机器,p fil模块被成功加载,pfil服务和ipfilter服务也都正常启动了。
            # svcs -a | grep pfil
                online 8月_09 svc:/system/rmtmpfiles:default
                online 13:36:55 svc:/network/pfil:default
                online 14:06:26 svc:/network/ipfilter:default

        提示:
  • 通过SMF启动和关闭ipfilter是永久有效的,即使机器重启也会保留。
  • 可以通过ifconfig -a modlist指令观察各网口所加载的模块。
  • 可以等下列步骤全部完成后,再重启机器。
        步骤4. 配置NAT,将子网的IP转换为公网IP
            对于图1所示的例子,在 "/etc/ipf/ipnat.conf"文件中加入如下的网络地址转换的规则:
                map eri0 192.1.1.0/24 -> 0/32
        令新设置的NAT规则生效。
            # ipnat -CF -f /etc/ipf/ipnat.conf
        ipnat -l可以观察当前的NAT规则,也可以用ipmon -t -o N实时观测网络地址的转换情况。

小结
        ipfilter的NAT功能加上虚拟路由为Local Zone构建了一条联通外部的网络通道:
  • 虚拟路由成为各Local Zone和外部通信的可用路由;
  • 从Local Zone发出的包经过ipfilter时,NAT根据规则将包头中的子网IP转换为外部可识别的共网IP;
  • 转换的同时,NAT向它的内部 NAT 表发送此地址,这样当包从公网返回时,就能够把地址映射回原先的内网 IP 地址。
  • 可以通过snoop和ipmon观察这一通讯的过程。

        用Michael Ditto的话说,方法4玩了一个小小的手段,伪造了一个虚拟路由,并赋予它真正路由的mac地址,0 但是当你无法获取缺省路由的mac 地址时,该方法就无法奏效了,这时我们不得不借助另一台机器,也就是文中提到的尝试三,利用另一台本地的机器提供路由转发的功能,加上ipfilter的NAT进行ip伪装,L ocal Zone也可以访问外网了。