所属分类:安全文章 来源:666w.com 作者:666w.com 日期:2003-9-20 21:21:13 阅读次数:     打印本页

路由器和防火墙


介绍如何进行网间互连,以及如何用Linux实现为廉价的路由器/防火墙。
  
      本章具体包括以下内容。
  
    基于Linux的路由器
  
    基于Linux的防火墙系统
  
    PPP连接和拨号服务器的配置
  
    各种代理服务器
  
1.1 核心IP转发和Linux路由器
  
  让我们首先从软件路由器开始。一般来说,Linux的软件路由器是非常容易使用的,并
且效果也不错。通常在教育系统我们会经常看到基于软件的路由机器。许多人认为软件
路由器速度比较慢,可靠性也比不上硬件路由器,不过,根据大部分使用者的经验,对
于10MB的以太网,软件路由不会带来任何瓶颈问题。而大部分单位的接入速度只有256甚
至64KB。对于100MB的系统,软件路由的速度有时跟不上网络的速度,不过考虑到正常路
由器的速度,这也不是什么严重的问题。

  
1.1.1 Linux的IP转发功能


  
  在配置内核中我们可以看到Linux内核本身就具有路由的功能,当然这些必须在编译内
核时定义。在2.2.14的内核配置中,与之相关的配置项目有好几项,并且不少属于实验
中的代码,所以如果你确实要使用Linux作为路由器或者防火墙你应该允许使用实验中的
选项。在编译核心的时候,建议打开大部分与IP路由相关的选项,这些选项的含义可以
从帮助中看到,例如IP路由,IP防火墙等等。当然你也可以用实验的方法,由于配置选
项的名称在不断改变,我不想给出详细的说明,其实你只要自己看看那些选项的名字就
应该差不多了,不是吗?当然,大部分发行版本的内核都是支持软件路由的,不过你还
是自己编译一下比较好。
  
  假设你已经正确地编译了内核,那么下一步就是启动IP转发(forwarding)功能了。IP
转发的概念很简单,如果你的系统上有多片网卡,那么IP转发功能会把IP包在这些网卡
接口之间传递,所以只要你开启了这个功能,Linux就可以正确地实现路由器的信息传递
功能了。
  
  启动IP转发的功能倒是十分简单,还记得我们在研究启动脚本的时候看到的那个直接
在/proc文件系统下面生成文件来启动内核功能的例子吗?启动IP转发也是这样作:
  
  echo 1 > /proc/sys/net/ipv4/ip_forward
  
  这样,IP转发功能就被启动了。如果你需要自动启动IP转发,就把这一行添加到/etc
/rc.d/rc.sysinit里面去。
  
  另外一种方法是利用缺省的/etc/rc.d/init.d/network脚本,例如对于redhat,你会
看到其中有这样的行:
  
  if [ ! -f /etc/sysconfig/network ]; then
  
   exit 0
  
  fi


  
  . /etc/sysconfig/network
  
   …………………………


  
  ipv4_forward_set ()
  
{
  
  if [ -d /proc/sys/net/ipv4 ]; then
  
  if [ ! -f /proc/sys/net/ipv4/ip_forward ] ; then
  
   echo "/proc/sys/net/ipv4/ip_forward is missing --" \
  
                          "cannot control IP forwarding" >&2
  
              else
  
                  if [ "$FORWARD_IPV4" = "no" -o "$FORWARD_IPV4" = "false" ]
; the
  
                      value=0
  
                      message="Disabling IPv4 packet forwarding"
  
                  else
  
                      value=1
  
                      message="Enabling IPv4 packet forwarding"
  
                  fi


  
                  if [ $value != `cat /proc/sys/net/ipv4/ip_forward` ]; then
  
                      action "$message"  /bin/true
  
                      echo "$value" > /proc/sys/net/ipv4/ip_forward
  
                  fi
  
              fi
  
          fi
  
}
  
  显然,只要设置了FORWARD_IPV4这个变量并且让它等于true,系统启动的时候就会自
动加入启动IP转发的项目,因此可以在/etc/sysconfig/network文件中加入这样一行:
  
  FORWARD_IPV4="yes"
  
  然后重新启动机器,就可以使用IP转发功能了。


  设eth0和eth1的网络地址分别是192.161.6.1和192.161.4.6,服务器接受到的IP数据
包将自动在两个网络接口之间传递。eth0接受到的数据包将被送到内核,如果目标地址
是192.161.6.1(eth0地址),那么服务器直接处理这个数据包;如果目标地址是192.161
.4.x,那么数据包将被转发到192.161.4.6。然后,eth1接口根据核心的路由表,发现凡
是192.161.4.x的数据包应该通过以太网设备直接广播出去,因此它会正确地把这个数据
包发送出去。当192.161.4.x的机器发出一个到192.161.6.x的申请的时候,步骤正好颠
倒过来。因此,只要把192.161.6.x和192.161.4.x的机器的路由路径中分别加入192.16
1.6.1和192.161.4.6,就可以实现两个子网之间的正确互访。对于windows客户机,可以
通过设置缺省网关为192.161.6.1(对192.161.6.x)和192.161.4.6(对于192.161.4.x)
实现。
  
  容易看到,这种互连并不对两个子网的IP地址有什么实际限制。
  
  然而这只是实现了两个以太子网之间的互连,在实际的情况中,我们通常有不止一条
的路由路径,或者需要实现多个网络的互连。最常见的情况是,网络系统中已经有了一
个路由,某些子网已经能够通过它和外部网络互连,而我们现在需要增加IP地址或者分
割子网,这时就需要在路由之间建立路径连接。也有这样的情况,我们需要通过Linux机
器将本地局域网连接入Internet。这个时候,我们需要使用一些特殊的工具,典型的是
IPChains。
  
1.1.2 Linux路由器
  
  从上一节的内容很容易看到,用Linux实现路由功能是一件很容易的事情。路由器有多
种,一种是我们在第一章中说的Proxy ARP类型的路由,曾经有一段时间,这种路由被用
来分割网络;不过,目前已经很少有人使用了,毕竟分割B类地址远比不上重新构作网络
拓扑可靠。另一种就是标准的路由器,我们用一个实例来说明这个问题。
  
  我们有两个C类网络地址,分别是202.199.241.0/24和202.199.249.0/24。其中,202
.199.241.0/24这个子网用专线接入internet,路由器是202.199.241.1。由于路由器上
只有一个以太网接口,所以限制了系统中只能有一个以太网段,除非引入其他的路由器
。现在,我们把202.199.241.0和202.199.249.0分别构成一个以太网段,然后用一个Li
nux路由器来连接这两个网段。
  
  Linux路由器上安装两片网卡,地址分别是202.199.241.6和202.199.249.2,首先用i
fconfig配置两片网卡的IP地址:
  
  ifconfig eth0 202.199.241.6 netmask 255.255.255.0
  
  ifconfig eth1 202.199.249.2 netmask 255.255.255.0
  
  配置网络的时候,会设置缺省的广播路由,可以用route命令显示:
  
  root@mail /root]# route
  
  Kernel IP routing table
  
  Destination   Gateway      Genmask         Flags Metric Ref    Use Iface
  
  202.199.241.6  *           255.255.255.255 UH    0      0        0 eth0
  
  255.255.255.255 *          255.255.255.255 UH    0      0        0   eth0
  
  202.199.249.0   *          255.255.255.0   U     0      0        0 eth1
  
  202.199.241.0   *          255.255.255.0   U     0      0        0 eth0
  
  127.0.0.0       *          255.0.0.0       U     0      0        0 lo
  
  显然,到202.199.241.*和202.199.249.*的广播路径都已经正确了,下一步是按照上
一节的办法启动IP转发:
  
  echo "1" > /proc/sys/net/ipv4/ip_forward
  
  现在要面对我们作软件路由器的一个主要问题了。如同我们说的那样,系统的主路由
器是202.199.241.1,而202.199.241.x的机器都将其缺省网关指向了这个路由。这意味
着,如果有一个数据包从202.199.249.x发送到202.199.241.y,那么发送过程中不会有
什么问题,而当202.199.241.y回应这个信息的时候,它将数据包发送到202.199.241.1
,但是202.199.241.1并不知道202.199.249.0的任何事情,它无法正确投递这个数据包

  
  解决的办法是将202.199.241.6加入到202.199.241.1的投递路径中去,设置202.199.
241.1的缺省投递路径,使得它碰到目标地址是202.199.249.x的数据包就投递到202.19
9.241.6:
  
  route add –net 202.199.249.0 netmask 255.255.255.0 gw 202.199.241.6
  
  (这里我把事情简化了。实际上,202.199.241.1是一个cisco路由器,它的配置要使用
自己的语法,不过内容是一样的)。
  
  现在两个子网已经可以正确地互相访问了,但是,为了使202.199.249.x的机器能够访
问internet,需要定义202.199.241.6的缺省投递路径,让它把对外的访问投递到202.1
99.241.1:
  
  route add default gw 202.199.241.1
  
  这样,就在系统中添加了一个子网。如果你需要作更复杂的网络连接,只要按照自己
的设计定义递送路径,然后打开核心转发就可以了。
  
1.1.3 广播路由路径
  
  很容易看出来,我们上面使用的是缺省路由传递的方式。整个配置中,我们使用的一
直是静态路径。在很多情况下,让路由器动态广播它所知道的路径更好一些。
  
  要广播路由路径,基本的方法是使用路由守护进程。最基本的路由守护进程是routed
。它作为Linux的一部分提供,可以收听网络上的路由广播,或者自己发出路由广播。不
过,routed的功能有限,同时又很占服务器资源。
  
  要使用routed,方法很简单,在命令行下面直接使用routed:
  
  routed [-s] [-q] 
  
  -s和-q是routed的两种工作模式,简单地说,-s是服务器模式,routed将不断地广播
和接受各种路由信息,-q则是客户模式,routed将只是接受别的机器广播的路由信息,
并且以此为根据修正自己的路由表。一般来说,routed会根据机器上的网络接口自动确
定路由信息,因此不需要提供其他信息。有时,你的系统比较复杂,这时你需要用/etc
/gateways文件来设定一下静态路由信息。关于gateways文件的信息详情可以参考route
d的手册页面。
  
  更常用的路由守护进程是gated。这个程序是一个路由外壳程序,可以插入各种路由通
信协议的支持。例如RIP,HELLO,IGRP等等。
  
  配置gated是一件很痛苦的事情,因为需要管理的事情实在是太多了。我们建议尽可能
地使用静态路由路径,只有在迫不得已的时候才使用gated守护进程(或者routed)来通
过广播动态设置路由路径。
  
  再申明一次:routed和gated在Linux中仅仅起到了一个广播路由信息的作用,真正的
路由工作是由Linux内核完成的。因此,如果你的网络配置全是静态路径,那么,你并不
需要使用这种程序,简单地打开内核IP转发和正确地配置路由表就是你需要的一切。
  
1.2 IP过滤和代理
  
  在前面我们已经看到,配置Linux作为一个静态路由其实是非常简单的事情,但是,在
实际的情况中,问题也许会比较复杂,例如,你需要对Linux内核转发的IP进行过滤以便
构造一个防火墙系统,或者你需要把你的私用网络接入到Internet。这一节我们就来讨
论这方面的问题。
  
1.2.1 ipchains和IP过滤
  
  正常情况下,内核会转发一切它认为应该转发的数据包,也许你想对这种转发加以控
制,Linux的绝大部分发行版本中都包含了一个用于控制这种转发的工具,称为ipchain
s。在早期版本的Linux中,有一个产品叫ipfwadm,两者在语法上是相当近似的,不过在
现在版本的Linux中,使用的都是ipchains。
  
  要使用ipchains,你必须首先安装这个产品,例如:
  
  rpm –i ipchains-1.3.9-3.rpm
  
  接下来就可以使用ipchains了。
  
  链
  
  要理解ipchains,首先应该知道它是基于所谓“链”的概念,所谓的“链”基本上是
一个TCP/IP连接模式,可以在这个模式上运用各种过滤规则,在缺省情况下,ipchains
定义了三个基本的链:
  
  input  由网络接口进入本机
  
  output  由网络接口输出
  
  forward  在各个网络接口之间转发
  
  你也可以建立自己的链,但是前面三个链不能更改,而且自己建立的链是没有缺省定
义的。要建立自己的链,使用ipchains –N指令:
  
  ipchains –N mychains
  
  这样就建立了一个名为mychains的链。要删除某个链,使用ipchains –X指令,如
  
  ipchains –X mychains
  
  匹配模式
  
  第二个需要理解的概念是匹配模式,匹配模式就是对TCP/IP连接的源/目的地址、端口
、协议等进行匹配,例如,可以在连接请求中过滤所有源地址是202.199.240.2,目标地
址是11.0.0.3的部分:
  
  -s 202.199.240.2   –d 11.0.0.3
  
  在匹配规则中可以使用下面的一些选项:
  
  -s 源地址 -d 目标地址
  
  这两个选项都可以使用网络地址,例如,要过滤源地址在子网202.199.241.0-202.19
9.241.255中,目标地址在202.199.249.0-202.199.249.255中的请求,可以使用下面两
种方法(等价)
  
  -s 202.199.241.0/24 –d 202.199.249.0/24
  
  -s 202.199.241.0/255.255.255.0 –d 202.199.249.0/255.255.255.0
  
  如果在某个匹配规则中没有标出源地址或者目标地址,那么缺省是0.0.0.0/0,即
  
  -s 202.199.241.0/24 等价于-s 202.199.241.0/24 –d 0.0.0.0/0
  
  -p 连接协议
  
  -p选项用来设置使用的连接协议,可以是TCP,UDP或者ICMP,例如:
  
  -s 202.199.241.0/24 –p TCP
  
  所有从C类子网202.199.241.0出发的TCP连接。
  
  在ICMP连接的情况下有一个特殊情况,就是可以使用-icmp-type来指出ICMP的类型。
  这个类型一般用数字标出,常用的有:
  
   数值  含义     常见应用
  
    0               网络回应               ping
  
         3         网络不可达           TCP/IP寻址失败
  
         5          路由重定向            静态路由主机
  
         1              请求回应                ping
  
         11         网络超时               traceroute
  
  例如,-s 127.0.0.1 –p ICMP –-icmp-type 0 表示所有从127.0.0.1发出的ping回
应。
  
  端口号
  
  直接在源/目的地址的后面加上的数字表示端口号,但是要注意端口号必须和协议类型
一起使用,例如,通往C类网202.199.241.0内任何www服务器的连接可以表示成
  
  -d 202.199.241.0/24 10 -p TCP
  
  也可以使用名字代替端口号,例如上面的形式也可以写成
  
  -d 202.199.241.0/24 www –p TCP
  
  没有限定端口号的规则表示适用于任何端口。
  
  端口号可以使用段落,方法是[最小端口号]:[最大端口号]。例如从A类网10.0.0.0/
1出发的所有源端口大于1024小于4096的UDP请求可以写成:
  
  -s 10.0.0.0/1 1024:4096 –p UDP
  
  上下界可以省略,例如所有大于64的端口可以写成64:,小于1024的端口号写成:1023
等等。
  
  也可以使用-source-port和-destination-port来标志端口号。
  
  否定
  
  !符号用于对地址规则取否定,例如-s !202.199.241.0/24代表所有源地址不是C类地
址202.199.241.0的数据包。在端口、协议类型等处也可以使用!符号。
  
  处理规则
  
  下一个问题是对特定的链实行特定的处理规则,所谓规则就是对某种确定的链执行特
定的操作。通常对于某个确定的链,我们用“跳转”使它进入另外一个链中,而在一切
跳转的末端,有几个预先定义好的处理规则:
  
  ACCEPT 允许这个请求正常通过,这时Linux表现的象一个普通的路由器
  
  DENY 禁止这个请求通过,这个数据包会就此在网络上消失,表现得如同网络在这里断
开一样
  
  RETURN 正常情况下,ipchains会依次察看链中所有的规则,所以一个链后面的规则可
以覆盖前面的规则,但是当遇到RETURN规则时,处理链将立即返回,即使下面还有与之
相关的处理选项也会被忽略。这样,RETURN规则将强迫ipchains自动转向下一个链。
  
  REJECT 这个选项跟DENY非常相似,所不同的是它在禁止这个请求的同时可以返回一些
ICMP信息,使得请求者能够知道数据包在何处被禁止。如果客户是windows NT,将会看
到一个“网络不可达”的错误信息。
  
  REDIRECT 这个规则只能用于input或者output链,而且不能用于ICMP协议。它将使得
Linux机器代替定义的目标机器收发信息报文。例如,ipchains –A input –d 202.11
2.51.200 –j REDIRECT将使得客户机器向202.112.51.200发出的数据包在Linux网关处
直接接受到并且截留下来。REDIRECT后面可以跟上端口号,例如把指向202.112.51.200
的10端口的数据包重定向到网关的9090端口:
  
  ipchains –A input –d 202.112.51.200 10 –p TCP –j REDIRECT 9090
  
  MASQ 这个规则只能用于forward链,它用于对客户机器进行IP代理。
  
  使用规则的方法是将它“加入”到某个链中,语法是ipchains –A [链] [地址匹配]
 [规则]。例如,可以用ipchains –A指令对forward链建立一条新的规则集:
  
  ipchains –A forward  -s 202.112.45.0/24 –d 13.0.0.0/1 –j REJECT
  
  这条规则禁止了从202.199.45.0到13.0.0.0的所有数据包。
  
  也可以用规则在链间跳转,例如,我们首先建立一个空链:
  
  ipchains –N disable
  
  然后将这条链设定为自动跳转到禁止:
  
  ipchains –A disable –j DENY
  
  接下来,我们可以让某些链跳转到这条链:
  
  ipchains –A input –s 202.112.51.0/24 –j disable
  
  那么效果和下面的指令:
  
  ipchains –A input –s 202.112.51.0/24 –j DENY是一样的。
  
  在不需要某一条规则时,可以将它删除,这可以使用命令ipchains –D。例如,要删
除上面的链规则,使用
  
  ipchains –D forward  -s 202.112.45.0/24 –d 13.0.0.0/1 –j REJECT
  
  如果你要删除某条链中的所有规则,使用ipchains –F:
  
  ipchains –F forward
  
  这时forward链中所有的规则都被清除。
  
  如果你不给出链的名字,那么ipchains –F将清除所有链中的规则。
  
  如果想察看目前链的规则,使用ipchains –L:
  
  $ipchains -L
  
  Chain input (policy ACCEPT):
  
  Chain forward (policy ACCEPT):
  
  target     prot opt     source                destination           ports
  
  ACCEPT     all  ------  202.199.249.0/24     anywhere              n/a
  
  Chain output (policy ACCEPT):
  
  对链的修改可以使用-R选项,即替换某一条规则,这需要知道规则的序号,例如:
  
  [root@mail /root]# ipchains -L
  
  Chain input (policy ACCEPT):
  
  Chain forward (policy ACCEPT):
  
  target     prot opt     source                destination           ports
  
  DENY       all  ------  202.199.249.14       anywhere              n/a
  
  Chain output (policy ACCEPT):
  
  现在forward链中只有一条规则,因此这条规则的序号就是1,现在可以替换这条规则
为:
  
  ipchains -R forward 1 -s 202.199.249.14 -d 0.0.0.0/0 -j ACCEPT


  
  然后可以看到
  
  [root@mail /root]# ipchains -L 
  
  Chain input (policy ACCEPT):
  
  Chain forward (policy ACCEPT):
  
  target     prot opt     source                destination           ports
  
  ACCEPT     all  ------  202.199.249.14       anywhere              n/a
  
  Chain output (policy ACCEPT):
  
  ipchains –D指令中也可以直接使用序号,如ipchains –D 1。
  
  通常,加入的新规则会放在已有规则的后面,如果你想要把规则插入到某个特定的位
置,使用ipchains –I [链] [序号] [规则]
  
  Policy
  
  这个词不太合适。ipchains的policy是指对链的缺省行为,例如,刚才的三个链的po
licy都是ACCEPT,表示在对系统的三个缺省链没有定义规则时,所有的包都可以通过。
  
  要设置Policy,使用ipchains –P指令:
  
  ipchains –P forward DENY
  
  log
  
  可以设置ipchains对符合规则的包的信息进行记录。这可以通过-l选项来实现,例如
,要记录从202.199.249.0/24出发的所有被转发的包的情况,使用:
  
  ipchains –A forward –s 202.199.249.0/24 –l –j ACCEPT
  
  然后在dmesg中就可以看到核心记录的包的信息了。如果要进一步分析这些信息,需要
将其记录到系统的日志文件中(见系统记账部分)。
  
  基本上,各种IP过滤型的防火墙都是利用上面解释的各种规则对IP包进行分析和监控

  
  接口
  
  用-i选项可以明确地给出链所涉及的网络接口,例如-i eth0代表第一个网络连接,可
以用+号来统配,例如
  
  ipchains –A input –p ICMP –s 0.0.0.0/0 –d 202.199.241.11 –i eth0 –j 
DENY
  
  关闭了通过eth0网络接口的ping回应。
  
  当-i选项用于input和output链的时候,其意义是很简单的,如果用于forward链,那
么它给出的是转发的目标接口。
  
  保存和恢复链规则
  
  在一个复杂的ipchains防火墙系统中,可能有许多规则。每次重新启动,这些规则都
必须被重新启动。原则上,可以在系统启动脚本中直接写入相应的规则,不过实践中,
我们一般采用首先测试规则是否正确的方法,在确定规则正确之后,使用ipchains-sav
e和ipchains-restore命令完成链规则的保存和读入。
  
  例如,我们已经有了下面形式的链:
  
  $ipchains -L
  
  Chain input (policy ACCEPT):
  
  Chain forward (policy ACCEPT):
  
  target     prot opt     source                destination           ports
  
  ACCEPT     all  ------  202.199.249.0/24     anywhere              n/a
  
  Chain output (policy ACCEPT):
  
  那么,可以使用ipchains-save命令将现在的链设置保存起来:
  
  $ipchains-save > mychains
  
  Saving `forward.
  
  ipchains-save缺省的情况下在标准输出送出信息,所以要使用重定向的办法,现在m
ychains文件中就包含我们的链的所有规则:
  
  $cat mychains
  
  :input ACCEPT
  
  :forward ACCEPT
  
  :output ACCEPT
  
  -A forward -s 202.199.249.0/255.255.255.0 -d 0.0.0.0/0.0.0.0 -j ACCEPT
  
  如果要从文件中读入ipchains的配置,使用ipchains-restore命令:
  
  $ipchains-restore < mychains
  
  同样,ipchains-restore从标准输入读取信息,因此需要使用重定向命令。
  
1.2.2 NAT和IP代理
  
  现在我们来考虑一个重要的ipchains应用,即NAT(网络地址翻译),也称为IP代理。在
第一章我们已经介绍过有关的概念,处于私用网络内的主机将自己的请求传递给代理机
器,由代理机器重写源地址和端口,使得看上去数据包好像是从代理机器发出的,接受
到的数据包也由代理机器转发给私用网络内的主机。在ipchains的术语中,这称为“伪
装”(MASQ)。
  
  要使用伪装功能,可以简单地使用-j MASQ命令。考虑一个典型的例子,eth0接到正常
的internet中,地址是202.199.241.120,现在在eth1上连接一个私用网络,地址是192
.161.254.0/24,eth1的地址是192.161.254.1,而且eth0已经能够正常访问internet,
那么需要作的事情就是设置所有从192.161.254.0/24发出的请求包应该被伪装然后发送
,因此,首先要按照前面的方法打开核心IP转发,然后设置对192.161.254.0的机器发出
的数据包进行伪装:
  
  ipchains –A forward –s 192.161.254.0/24 –d !192.161.254.0/24 –j MASQ
  
  然后把私用网络中的机器的网关设置成eth1的地址(192.161.254.1)就可以让私用网
络中的机器访问internet了。
  
  这种技术也用于设置拨号网关,即用一个拨号网络连接让局域网内的所有机器都能连
接到internet。
  
  telnet,www等服务都可以简单地通过这种伪装方法代理出去,但是ftp有一个特殊的
问题。在第一章中,我们已经指出,ftp依赖于两个连接,其中用来传输数据的连接通常
由服务器发起。问题是远端服务器根本不知道关于私用网络的事情,因此连接不会成功
,例如,当你通过我们这里介绍的网关让私用网络内的机器进行ftp请求时,会产生这样
的情况:
  
  C:\>ftp
  
  ftp> o 202.199.241.3
  
  Connected to 202.199.241.3.
  
  220 asnt_1 Microsoft FTP Service (Version 4.0).
  
  User (202.199.241.3:(none)): ftp
  
  331 Anonymous access allowed, send identity (e-mail name) as password.
  
  Password:
  
  230 Anonymous user logged in.
  
  ftp> ls
  
  500 Invalid PORT Command.
  
  150 Opening ASCII mode data connection for file list.
  
  然后这个ftp程序就会挂起。
  
  解决问题的第一个办法是使用被动(passive)模式,在被动模式下,所有的ftp连接
和数据传输请求都由ftp客户发起,这样就可以避免服务器反过来连接私用网络的机器。
通常基于GUI的ftp客户软件一般都是使用的被动模式(例如cute_ftp),而命令行ftp工
具则使用的是主动模式。
  
  不幸的是,最常用的浏览工具:Internet Explorer 用的正好是主动模式。显然,让
你的客户了解这种晕头转向的概念显然无益于帮助他们使用internet。因此,ipchains
提供了一个附加模块,专门用于解决ftp的问题,可以用insmod命令来加载这个模块:
  
  insmod ip_masq_ftp
  
  然后客户机器就可以正确地使用ftp了:
  
  C:\>ftp
  
  ftp> o 202.199.241.3
  
  Connected to 202.199.241.3.
  
  220 asnt_1 Microsoft FTP Service (Version 4.0).
  
  User (202.199.241.3:(none)): ftp
  
  331 Anonymous access allowed, send identity (e-mail name) as password.
  
  Password:
  
  230 Anonymous user logged in.
  
  ftp> ls
  
  200 PORT command successful.
  
  150 Opening ASCII mode data connection for file list.
  
  incoming
  
  pub
  
  226 Transfer complete.
  
  ftp: 15 bytes received in 0.11Seconds 0.14Kbytes/sec.
  
  ftp>
  
  对于那些不想对客户解释什么是被动模式的管理者,这可能是唯一的方法了。
  
  还有一些应用软件也需要类似的内核不定,其中最重要的应该是irc,要使得私用网上
的用户能够使用irc程序,使用这个模块:
  
  insmod ip_masq_irc
  
  还有几个这一类的模块,都放在/lib/modules/2.2.14/ipv4目录下,你可以自己参考
,例如连线对战quake用的模块等等。
  
1.3 基于IPChains的防火墙系统
  
  现在我们可以考虑如何实现一个简单的防火墙了。在这里我们将考虑一个代理和包过
滤混合的防火墙系统,尽管比较简单,但是它仍然包含通常所说的防火墙的主要内容。
对于这样的防火墙,ipchains就是你需要的一切。技术上,更强大的防火墙系统(例如
带有数据过滤功能)也是存在的,但是对于一般的单位,下面解释的防火墙强度已经足
够了。
  
1.3.1 防火墙的设计
  
  防火墙有两种,称为代理防火墙和包过滤型的防火墙。代理防火墙基本上就是前面说
的NAT系统,或者是其他某种代理软件,客户机器把自己的请求提交给代理机器,然后由
代理服务程序代替它进行网络访问。这种防火墙的主要优势在于其安全性,理论上,只
要防火墙主机不出现问题,对客户机器进行非授权访问实际是不可能的。但是它的主要
缺陷就是灵活性和功能,显然,页面服务是无法安装在私用网络中的(除非使用端口转
发或者反向的NAT服务)。
  
  包过滤型的防火墙是一个软件的路由器,由路由机器对通过的数据包进行检查,拦截
所有非法的请求,并且对必要的情况进行记录。这种防火墙不会影响内部网络的正常功
能,缺点则是不像代理防火墙那样可靠,必须记住,由于TCP/IP的实现,数据包可能会
在你注意不到的地方穿过,而过分严厉的过滤策略又会影响网络的正常使用。
  
  一般来说,设计防火墙的主要任务是确定哪些数据包可以透过,哪些数据包必须加以
阻挡。这里,最重要的是熟知TCP/IP连接的性质和传输模式。
  
  设计防火墙的策略有两种基本的思路,一种是一开始就禁止所有的数据包流通,然后
根据需要打开的服务,依次开放各种端口;另外一种是一开始开放所有的服务,然后对
不可靠的端口进行封锁。原则上,前一种方法比较可靠,但是对于不熟悉TCP/IP的用户
,可能会导致一些困扰。
  
  要使得防火墙起作用,显然必须将你的本地网络放在防火墙后面,这又存在许多的情
况,最常见的情况,是将本地网络分成两部分,一部分使用正常的Internet地址,另一
部分则使用私用的网络地址。这两部分可以正常相互通信。当与外部网络的机器对话的
时候,使用正常地址的机器简单地通过防火墙,而私用网的机器则通过防火墙使用代理
方式访问。
  
  显然,这个系统需要有三个网络接口,一个用于连接到internet,另一个与正常地址
的内部机器对话,另一个用来和私用网络地址的机器对话。其中,正常地址的内部机器
是网络的中心部分,因为所有的本地服务器必须放在这个区域。在文献中,这个部分通
常称为DMZ(停火区)。
  
  在设计包过滤策略的时候,主要的应该是考虑TCP/IP连接的方式,如同我们知道的那
样,TCP/IP连接是双向的,如果你要访问某台主机的www服务,那么这个连接涉及到的是
:对方的主机地址;对方的www端口地址(10);自己的IP地址;除此之外,你的ftp程序
还要申请一个端口地址用来通讯,本地机器的TCP/IP管理程序将为它分配一个大于1024
的端口地址,这样才能实现连接。这样,通常为了避免对自己机器的非授权访问,你需
要封禁对本地网络机器所有非必要的小于1024端口的访问,但是你仍然应该允许大于10
24的端口的使用,否则本地机器无法使用internet。
  
  从/etc/services文件可以查找到各种端口的定义,不过要注意ftp使用两个端口,即
端口21(ftp)和20(ftp-data),分别用于发送ftp命令和发送ftp数据。另外,NFS服务要
使用portmap端口。
  
  ftp是一个几乎象是噩梦一样的东西,在主动模式中,除了我们说的两个端口之外,实
际上,由于数据连接是从服务器发起,因此它是申请一个客户机器上的端口(同样>102
4),然后构作这个连接。显然,这个端口的值是不固定的,因此你实际上没有办法来判
断一个连接会不会是ftp主动模式的数据,这也就意味着如果你想允许主动模式,那么对
大于1024的端口进行过滤实际是不可能的。如果你坚持要一个“可靠”的防火墙,那么
唯一的方法是强制性地命令你的员工使用被动模式的ftp工具。这是过分严厉的管理政策
使得工作效率降低的一个例子。
  
  另外一个需要注意的内容是关于IP隧道。IP隧道可以让TCP/IP连接运行在别的协议之
上,例如IPX。这样,如果你的系统允许IPX路由,就有可能有别的网络上的用户利用IP
隧道功能穿透你的防火墙设置。这是危险的事情,解决的方法就是原则上不对TCP/IP以
外的任何协议路由。如果你的路由器有多协议路由功能,将它禁止掉。
  
 1.3.2 实例说明
  
  现在我们用实例来说明一下一个上述的标准防火墙的配置过程,我们完全用ipchains
来完成这个工作,首先我们可以考虑一下防火墙的基本构架:
  
  防火墙通过一个网卡接入internet,这片网卡构成了所有internet访问的数据通路,
不妨假定其地址是202.199.241.1,接口是eth0。(当然,实际情况中,我们更多地通过
专用的路由器接入广域网,不过这不会影响我们的问题的本质)。
  
  DMZ中包含了我们的所有对外服务主机,外部网络可以透过防火墙申请这些主机的服务
。我们假设这些主机的地址在C类网202.199.241.0中,地址空间是从202.199.241.2到2
02.199.241.255,或者说202.199.241.0/24。其中,我们有一台www主机,地址是202.1
99.241.1,ftp主机的网络地址是202.199.241.9,电子邮件主机是202.199.241.10,DN
S主机是202.199.241.11。另外,ftp主机也同时提供samba服务。为了使DMZ能够直接和
防火墙主机通信,我们将DMZ用独立的一个以太网系统连接起来,并且在防火墙上加入第
二块网卡与之通联,设为eth1,IP地址是202.199.241.2。所有DMZ区域中的机器的网关
地址都设置为202.199.241.2。
  
  第三个区域是私用网络(private),假设我们使用的私用网络是192.161.0.0/24,它
们也用一个独立的以太网连接起来,然后在防火墙上加入第三片网卡,设为eth2,其地
址为192.161.0.1,与私用网络连接在一起,所有私用网络内的主机网关设置为192.161
.0.1。
  
  
  
  现在我们来考虑防火墙策略,首先要按照上一节的方法打开核心的IP转发,接下来,
我们首先定义几个链,用来表示各种访问模式:
  
  ipchains –N wan_DMZ
  
  从外部网访问DMZ。
  
  ipchains –N wan_private
  
  从外部网访问私用网
1.4 拨号网络连接

  
  现在我们来研究另外一种网络连接工具,即调制解调器连接。对于许多用户,这是上
网的基本手段。虽然不太可能有某个网站使用拨号网络连接internet,但用一台普通机
器构成一个局域网的IP代理让所有网内机器一起上网的情况却是相当常见的。另外,一
直到不久以前,很多ISP都利用Linux+多串口卡作为拨号服务器给客户提供网络服务。
  
  我们将主要把精力聚焦在PPP(点对点协议)上,以前许多单位流行UUCP,还有不少人
使用SLIP。但是随着时代的发展,Internet的推广使UUCP没有什么实际意义,而SLIP的
优点也由于pppd管理的简化而失去了原有的意义。
  
  1.4.1 拨号网络连接
  
  我们首先来介绍使用PPP进行拨号网络连接的过程。Linux的PPP连接是通过pppd程序来
完成的,实际上,这个程序的行为相当简单,就是将调制解调器信息映射成一个虚拟的
网络接口。一般来说,建立PPP连接的过程需要这样几个步骤:
  
  建立调制解调器连接
  
  其实这个过程就是向调制解调器发送初始化和拨号命令,接受到命令后,调制解调器
和对方系统建立电气连接。
  
  登录网络
  
  ISP将ip地址和路由信息传递到你的系统上,pppd程序将根据这个信息启动ppp0网络接
口。
  
  为了说明这个问题,我们现在来看一个实际的PPP配置例子,假设你的核心编译时允许
了PPP支持,而且系统中已经安装了ppp-2.3.10(比如说)软件包,那么,在/usr/doc/pp
p-2.3.10目录下应该有一个scripts目录,里面有类似这样的一些文件:
  
  $ls
  
  README    chat-callback  ip-down.local.add  ppp-off  ppp-on-dialer  secure
-card
  
  callback  chatchat       ip-up.local.add    ppp-on   redialer
  
  这里,ppp-on是启动ppp程序的主要脚本,我们可以看一下它的内容:
  
  #!/bin/sh
  
  TELEPHONE=555-1212      # The telephone number for the connection
  
  ACCOUNT=george          # The account name for logon (as in George Burns
)
  
  PASSWORD=gracie         # The password for this account (and Gracie Allen
)
  
  LOCAL_IP=0.0.0.0        # Local IP address if known. Dynamic = 0.0.0.0
  
  REMOTE_IP=0.0.0.0       # Remote IP address if desired. Normally 0.0.0.0
  
  NETMASK=255.255.255.0   # The proper netmask if needed
  
  export TELEPHONE ACCOUNT PASSWORD
  
  DIALER_SCRIPT=/etc/ppp/ppp-on-dialer
  
  exec /usr/sbin/pppd debug lock modem crtscts /dev/ttyS0 31400 \
  
          asyncmap 20A0000 escape FF kdebug 0 $LOCAL_IP:$REMOTE_IP \
  
    noipdefault netmask $NETMASK defaultroute connect $DIALER_SCRIPT
  
        容易看出来,真正的执行程序只有最后的exec程序,其他一些行只是一些设置
参数。说实话pppd程序的参数实在太多,我们总是建议你在已有的脚本的基础上进行修
改。其中,要注意的是pppd命令行中/dev/ttyS0的参数,这个是pppd程序拨号时的端口
设备,显然,这里假定你的调制解调器接在com1。如果是接在com2,就使用/dev/ttyS1
,以此类推。
  
  我们首先必须说明一个关于身份认证的问题。如果你的机器已经有了一个以太网接口
,并且发现按照下面的做法无法正确地建立连接的话,你需要把ppp-on脚本中的pppd的
命令行选项auth改成noauth。这个选项和windows 9x类型的身份认证有关,由于我们使
用的是用户名/口令的明文认证方式,所以选择noauth不会影响拨号的成功。当然,如果
你发现不需要更改这个选项,那当然也行。
  
  LOCALIP和REMOTEIP是你的本地机器以及ISP的IP地址,在我们的情况下,本地机器的
IP是拨号时动态分配,在拨号之前是不知道的,这种情况下要设置成0.0.0.0。ISP的地
址在拨号以前也是不知道的,所以也设置成0.0.0.0。
  
  其他三个参数是在ppp-on-dial脚本里面使用的,从pppd的命令行中我们可以看到ppp
d程序调用了这个脚本,我们看一看这个脚本的内容:
  
  #!/bin/sh
  
  exec chat -v                                            \
  
          TIMEOUT         3                               \
  
          ABORT           \nBUSY\r                      \
  
          ABORT           \nNO ANSWER\r                 \
  
          ABORT           \nRINGING\r\n\r\nRINGING\r    \
  
                        \rAT                            \
  
          OK-+++\c-OK   ATH0                            \
  
          TIMEOUT         30                              \
  
          OK              ATDT$TELEPHONE                  \
  
          CONNECT                                       \
  
          ogin:--ogin:    $ACCOUNT                        \
  
          assword:        $PASSWORD
  
  容易看出,这个脚本实际上只是调用了chat程序。chat程序是一个自动的对话-应答程
序,-v参数是启动调试信息纪录,这可以使你在测试的时候容易发现问题,(看看/var
/log/messages文件就知道了),而其他的行定义了一些提示和对应的应答。例如,ass
word: $PASSWORD在chat的参数后面出现,意味着每当chat程序收听到一个包含assword
:的提示的时候,就送出一个$PASSWORD字符串。每一行或者是一些控制选择,或者是这
样的一个提示-应答对,也就是说,上面的这段指令稿可以这样解释:
  
  TIMEOUT         3
  
  这设定接收所期待的输入逾时时限为三秒。你可以考虑将它加大一些
  
  ABORT           \nBUSY\r
  
  如果接收到 BUSY 字串,中止执行。(也就是说,拨号程序发现对方的线路忙)。
  
  ABORT           \nNO ANSWER\r
  
  如果接收到 NO ANSWER 字串,中止执行. 
  
  ABORT           \nRINGING\r\n\r\nRINGING\r
  
  如果接收到(重复的)RINGRING 字串,中止执行.这是因为某人正打电话给你! 
  
  (呵呵,对于经常拨BBS的朋友,这些内容再熟悉不过了)。
  
   “              \rAT
  
  不期待数据机传送任何讯息并且送出 AT 字串. 
  
  OK-+++\c-OK   ATH0
  
  这是第一个提示-应答对。当pppd程序向调制解调器发出初始化命令时,它期待 OK ,
如果调制解调器正常,就会会应一个OK字符串;否则,没有期待到意味着拨出没有收到
(因为数据机并不在指令模式下)那麽送出 +++ (使数据机返回指令模式的标准 Haye
s 相容数据机字串)并且期待 OK;不管那种情况,一旦期待到OK,接著送出 ATH0 (数
据机挂断字串).这主要是应付一些难以断线的意外情况。 
  
  TIMEOUT         30
  
  设定下面的脚本执行的超时时限为 30 秒。
  
  OK              ATDT$TELEPHONE
  
  如果ATH0命令被正常执行,那么调制解调器应该返回一个OK,所以这里期待 OK,一旦
得到就拨叫$TELEPHONE(前面在ppp-on里面定义的电话号码)。 
  
  CONNECT         ”
  
  一旦拨号成功,与远端调制解调器建立了连接,我们的调制解调器应该返回一个CONN
ECT,因此我们期待 CONNECT 字串并且不送出任回覆讯息。当然实际上我们根本不需要
回应这个提示,问题是chat程序就是这么蠢,即使是一个“死行”也要回应一次,哪怕
回应中什么也没有。顺便提一句,对于空字符串、带空格的字符串等等,我们要用单引
号把它括起来,现在括起来的就是一个“空”。
  
  ogin:--ogin:    $ACCOUNT
  
  我们将期待登录提示(...ogin:),但是如果我们在超时前没有接收到,送出一个返回
字元(return)然後再次找寻签入提示.当接收到提示时,送出使用者名称(存放在$ACC
OUNT 环境变量里,在前面的ppp-on中定义)。
  
  assword:        $PASSWORD
  
  期待密码提示并且送出密码(存放在环境变量里)。
  
  关于pppd程序,如果你想要作拨号的话,内容就是这些了;这里面最需要理解的是ch
at程序,在上面的缺省脚本中,它使用的是login:和password:提示。你的ISP会使用什
么样的指令对?这个很难说,解决问题的唯一方法是手工拨号到对方的服务器上面,然
后看一看对方到底使用的什么样的配置,完成这个任务的最好方式是使用一个终端仿真
程序,比如Windows 9x的超级终端或者Linux的Minicom。
  
  让我们来解释一下minicom。假设你的系统已经安装了这个产品,你首先需要建立/de
v/modem设备。在我们的一般情况下,系统中已经有了/dev/cua0,/dev/cua1,/dev/cu
a2或者/dev/ttyS0,/dev/ttyS1等设备,你只需要将调制解调器连接到正确的端口上,
然后建立符号连接就可以了,/dev/ttyS0和/dev/cua0都是COM1,/dev/ttyS1和/dev/cu
a1是COM2,以此类推。假设你的调制解调器接在COM2上,那么首先将/dev/modem连接到
/dev/cua1:
  
  ln –s /dev/cua1 /dev/modem
  
  然后启动minicom:
  
  $ minicom
  
  Welcome to minicom 1.12


  
  OPTIONS: History Buffer, F-key Macros, Search History Buffer, I11n 
  
  Compiled on Sep 23 1999, 22:29:11.


  
  Press CTRL-A Z for help on special keys
  
                                                       
  
  AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0                     
  
  OK                                      
  
  出现这样的提示就可以拨号了,输入拨号命令:
  
  at                                                   
  
  OK                                                   
  
  atdt 163
  
  CONNECT 33600/V42BIS
  
  *** Welcome To AnShan 163 Arc03 *** 
  
  login: test
  
  Password:
  
  容易看到,在CONNECT连接符号之后,对方的拨号服务程序要送出一个Welcome To An
Shan 163 Arc03的字符串,所以我们要在对应的chat脚本里面加上对应的行-虽然这个行
根本不需要应答。我们首先把scripts目录里面的ppp-on,ppp-on-dialer和ppp-off,o
ptions文件复制到/etc/ppp,然后将/etc/ppp-on里面的TELEPHONE,ACCOUNT,PASSWOR
D都设置成你自己的内容,REMOTE_IP和LOCAL_IP设置为0.0.0.0:
  
  #!/bin/sh
  
  TELEPHONE=163      # The telephone number for the connection
  
  ACCOUNT=lnte          # The account name for logon (as in George Burns)
  
  PASSWORD= lnte        # The password for this account (and Gracie Allen)
  
  LOCAL_IP=0.0.0.0        # Local IP address if known. Dynamic = 0.0.0.0
  
  REMOTE_IP=0.0.0.0       # Remote IP address if desired. Normally 0.0.0.0
  
  NETMASK=255.255.255.0   # The proper netmask if needed
  
  export TELEPHONE ACCOUNT PASSWORD
  
  DIALER_SCRIPT=/etc/ppp/ppp-on-dialer
  
  exec /usr/sbin/pppd debug lock modem crtscts /dev/ttyS0 31400 \
  
          asyncmap 20A0000 escape FF kdebug 0 $LOCAL_IP:$REMOTE_IP \
  
    noipdefault netmask $NETMASK defaultroute connect $DIALER_SCRIPT
  
  然后设置ppp-on-dialer进行应答:
  
  #!/bin/sh
  
  exec chat -v                                            \
  
          TIMEOUT         3                               \
  
          ABORT           \nBUSY\r                      \
  
          ABORT           \nNO ANSWER\r                 \
  
          ABORT           \nRINGING\r\n\r\nRINGING\r    \
  
                        \rAT                            \
  
          OK-+++\c-OK   ATH0                            \
  
          TIMEOUT         30                              \
  
          OK              ATDT$TELEPHONE                  \
  
          CONNECT                                       \
  
          Arc        \
  
          ogin:--ogin:    $ACCOUNT                        \
  
          assword:        $PASSWORD
  
  注意我们用的是Arc而不是Arc03,因为我们面对的是一个多道连选的拨号服务器,拨
163会随机地拨到服务器的某一个modem上,而每个的提示都是ArcXX,所以我们提取相同
的信息,就是Arc。
  
  最后是/etc/ppp/options,这个文件只有一行:
  
  [root@wxd ppp]# cat options
  
  lock
  
  ppp-off文件可以保持原状:
  
  !/bin/sh
  
                                    ##
  
#
  
  # Determine the device to be terminated.
  
#
  
  if [ "$1" = "" ]; then
  
          DEVICE=ppp0
  
  else
  
          DEVICE=$1
  
  fi


  
                                    ##
  
#
  
  # If the ppp0 pid file is present then the program is running. Stop it.
  
  if [ -r /var/run/$DEVICE.pid ]; then
  
          kill -INT `cat /var/run/$DEVICE.pid`
  
#
  
  # If the kill did not work then there is no process running for this
  
  # pid. It may also mean that the lock file will be left. You may wish
  
  # to delete the lock file at the same time.
  
          if [ ! "$?" = "0" ]; then
  
                  rm -f /var/run/$DEVICE.pid
  
                  echo "ERROR: Removed stale pid file"
  
                  exit 1
  
          fi
  
#
  
  # Success. Let pppd clean up its own junk.
  
          echo "PPP link to $DEVICE terminated."
  
          exit 0
  
  fi
  
#
  
  # The ppp process is not running for ppp0
  
  echo "ERROR: PPP link is not active on $DEVICE"
  
  exit 1
  
  最后把ppp-on,ppp-on-dialer,ppp-off的属性都设置成700。
  
  配置现在就完毕了,然后就可以执行PPP:
  
  $ cd /etc/ppp
  
  $ ./ppp-on
  
  会听到拨号声音,一会拨号就连通了,连通后,用ifconfig命令可以看到ppp0设备及
其IP地址。
  
  当拨号网络连通的时候,ISP会向客户机器传递域名服务器的地址,对于Windows 95,
拨号网络程序可以自动下载这个地址并且刷新名字服务器信息,不过对于Linux,我们一
般自己直接在名字服务器解析文件/etc/resolv.conf中加入ISP提供的名字服务器地址。
  
  使用完毕后,可以用ppp-off命令切断ppp连接:
  
  上面的内容就是一般的启动拨号服务的办法。个别的ISP会使用所谓PAP认证方式,这
个认证方式不使用username:/password:指令对,而是由拨号程序在建立连线时自动传输
认证信息(换句话说,当你使用minicom拨号的时候并不出现要求你登录的提示)。如果
是这样,那么设置ppp的方式和我们这里讲的有所不同,详细的资料可以参考Linux PPP
-HOWTO,这部分内容已经被翻译成中文。
  
  如同上面显示的那样,配置ppp的任务并不算困难但是却很讨厌,一般来说,人们总是
希望使用简化的配置。最常用的拨号程序除了直接使用ppp-on之外,就是图形界面下的
kppp。当然对于服务器,为了拨号而启动X Window有些不值得。kppp的配置与Windows下
的拨号网络一样简单,因此我们不再详细叙述了。
  
  另外一个基于命令行的拨号工具称为wvdial,它和ppp的配置其实差不多,但是不需要
设置令人头痛的应答过程。(笔者当初配置邮电局的16道连选弄得晕头转向,作了两天
还没有解决,而用wvdial十分钟就连通了。)
  
  要使用wvdial,需要安装wvdial软件包,在新的Linux发行版本中有不少包含这个程序
。安装后,你只要按照下面的格式生成一个配置文件/etc/wvdial.conf:
  
  [Dialer Defaults]
  
  Modem=/dev/ttyS0
  
  #调制解调器在com1,com2=/dev/ttyS1
  
  Baud=57600
  
  #调制解调器的速度
  
  Init = ATZ
  
  Init2 = AT S11=50
  
  #调制解调器的初始化命令
  
  Phone=163
  
  #ISP电话号码
  
  Username=user
  
  Password=user
  
  #ISP给你的用户名和口令
  
  然后执行wvdial ,就可以看到一连串内容在屏幕上滚过,最后出现starting pppd .
...表示连线成功了。连线结束时,可以用^C退出wvdial程序,这时wvdial会自动切断线
路。
  
  wvdial工作时需要保持运行,如果你觉得把它放在前台影响工作,可以用wvdial &将
它放到后台,结束时用killall wvdial 命令。
  
  要记住,pppd可能因为稀奇古怪的原因挂掉,如果你拨号没有成功,可以察看/var/l
og/messages文件(或者在/etc/syslog.conf里面定义的任何记账文件)找出问题何在。
  
  1.4.2 拨号代理
  
  拨号代理其实就是我们前面说的IP代理系统,只是它的代理出口是使用拨号网络接口
。简单地说,拨号代理就是一台能够拨号连接到internet的机器,局域网内的其他机器
可以通过它连接到internet。
  
  说到这里,大家应该已经理解一个拨号代理应该怎么做了,首先要按照前面的方法配
置拨号网络使得拨号机器能够访问internet;配置局域网的机器IP为私用网络的IP,比
如说私用网络是10.0.0.0/24,拨号代理的机器网卡IP地址为10.0.0.1;配置私用网络客
户机器的网关地址为10.0.0.1;配置拨号代理机器启动核心IP转发功能;然后只要在拨
号代理的机器上:
  
  ipchains -A forward -s 10.0.0.1/24 –i ppp0 –j MASQ
  
  insmod ip_masq_ftp
  
  现在整个局域网就可以通过这条电话线访问internet了。
  
  实际上,作拨号代理确实十分简单,最多再加上身份鉴别,避免别的用户冒充为你的
私用网络用户进入系统:
  
  ipchains –A input –s 10.0.0.1/24 –i ppp0 –j REJECT
  
  其他像禁止某些用户访问别的站点等等都可以按照前面讨论防火墙的方法去做。
  
  如果你想用拨号网络连接两个局域网,那么做法仍然和这里是类似的,只是不再使用
MASQ选项,而且要按照第一节的原则来考虑路由递送问题。特别是,现在我们需要使用
静态IP地址,就是将ppp-on里面的LOCAL_IP和REMOTE_IP正确配置。另外,在ppp-on脚本
中的pppd命令行选项defaultroute必须仔细考虑,这个参数表示将拨号连接当成缺省路
由,如果你认为有问题的话,把它改成nodefaultroute并且手工用route命令设置路由。
  
  在使用拨号代理的过程中,你很可能会感到在用户开始上网的同时进行拨号是很方便
的,而一旦所有用户都已经停止连接就自动切断ppp连接。这个功能可以用diald程序来
完成。diald并不包含在一般的Linux发行版本中,你需要自己去下载这个程序。
  
  要使用diald,你需要在内核中编译加入SLIP支持(即使你仅仅准备使用ppp连接网络
)。然后你可以编译并且安装diald。一般情况下,有几个文件设置了diald的行为,最
主要的是/etc/diald.conf。
  
  如果你按照我们上面说的那样已经配置好了ppp连接,ppp-on-dial脚本已经正常,那
么你可以写这样一个非常简单的/etc/diald.conf:
  
          mode ppp
  
                connect /etc/ppp/ppp-on-dial 
  
                device /dev/ttyS1
  
                speed 57600
  
                modem
  
                lock
  
                crtscts
  
                local 10.0.0.2
  
                remote 10.0.0.1
  
                dynmatic
  
                defaultroute
  
                include /usr/lib/diald/standard.filter
  
  注意这个文件中的local和remote参数。这两个参数是设置拨号两端的IP的,现在因为
使用的ip地址是ISP动态分配给你的,所以用dynmatic参数设置地址为动态地址。问题是
如果在配置文件中不给出地址的话,diald程序就无法正确启动拨号脚本,所以你可以给
它一对私用IP让diald程序自己去处理。剩下的任务就是启动diald,然后让服务器自己
去拨号就可以了。
  
  1.4.3 拨号服务器
  
  现在我们来研究如何做一个拨号网络服务器。作拨号服务器仍然是利用pppd程序,不
过,这一次我们必须解释一点东西。
  
  在最简单的情况下,假如你是一个ISP管理者,你只需要让用户连接到你的系统中,就
可以为他们提供网路服务。在这种情况下,客户的机器逻辑上是你的子网的一部分,为
了是客户机器可以和同一子网的机器通讯,我们可以使用ARP代理功能,就是拨号服务器
替客户应答ARP询问,因此其他机器会把应该送给客户机器的信息包交给服务器,服务器
再转交给客户机器。这个和我们前面讨论分割地址空间时的ARP代理没有任何区别。这种
情况下,客户机器到外界的联系完全由服务器代理,因此客户端几乎不需要设置任何东
西。相反,如果你是要用电话线把两个子网连接起来,那么你需要的是在两个子网上建
立缺省投递路径,内容就和我们第一节介绍的完全一样,甚至也可以用ipchains控制信
息的流动。
  
  当客户拨号到服务器上的时候,首先是调制解调器之间建立连接,为了实现这个功能
,服务器的调制解调器必须设置为等待/应答方式,一旦有拨入就能接受服务。如果你仅
仅是想把客户机器当成终端来使用服务器,那么这就足够了;否则,如果你使用拨号网
络等windows 9x的ppp客户程序来拨入,它将向服务器传输PAP认证信息。你的拨号服务
器接受到这些信息之后,对客户的身份进行验证并且去处理缺省的拨号脚本,启动pppd
程序在两台机器之间建立起数据通路,这样,客户机器就被连接到服务器所在的网络上

  
  现在我们来介绍如何制作第一种情况下的PPP服务器,仍然假定你的内核编译的时候已
经加入了PPP支持。我们首先建立一个下面形式的/etc/ppp/options文件:
  
  asyncmap 0
  
  netmask 255.255.255.0
  
  proxyarp
  
  lock
  
  crtscts
  
  modem
  
  ms-dns 202.199.241.2
  
  这个文件的详细含义请参考man ppp。proxyarp和netmask给出了PPP连接的工作方式为
ARP代理。lock是锁定调制解调器避免拨号连接被其他程序干扰,crtscts设置调制解调
器使用硬件流控制方式。需要特殊说明的只有最后一行,一般来说,作为拨号客户的总
是windows 机器,而windows 9x期望从服务器上取得关于网关和DNS服务器的信息,这行
就是起这个作用的,ms-dns将DNS服务器的地址传递给拨号客户。另外还有几个很常用的
参数,其中最重要的是nodetach,它避免pppd复制出一个在后台运行的子进程,如果你
发现在拨号连接被切断之后pppd程序没有正确退出,加入这样一行。另外,还有一对de
faultroute和nodefaultroute选项,在我们现在的情况,缺省值nodefaultroute就可以
满足要求了。
  
  下一步,我们必须为每个拨入调制解调器准备一个配置文件,配置文件的名字规则是
/etc/ppp/options.ttyXX,例如你的modem接在COM1上,就需要生成一个文件/etc/ppp/
options.ttyS0。以此类推。
  
  options.ttyXX的内容非常简单,就是[本地IP]:[远端IP]。例如,我的PPP server的
IP地址是202.199.241.1,名字是server,我想为从com1拨入的用户分配IP地址202.199
.241.19,名字是dialclient。那么需要在/etc/ppp/options.ttyS0文件中写上:
  
  202.199.241.1:202.199.241.19
  
   或者
  
  server:dialclient
  
  接下来,需要作的是建立身份验证文件。一般情况下,我们在客户端用的是windows 
9x,而windows使用的是PAP验证,所以我们必须为PAP准备身份验证文件。这个文件的缺
省名字是/etc/ppp/pap-secrets,而它的行的格式是:
  
  [用户名] [远端机器名] [口令] [远端IP]。可以使用通配符"*"。
  
  例如,我们希望允许用户user01可以从任何地方拨入,并且可以使用前面定义的远端
IP地址202.199.241.11,口令是test01,那么使用这样的行:
  
  user01 * test01 202.199.241.11
  
  如果希望user01可以从任何地方拨入,而且可以使用所有定义在options.ttyXX中的远
端IP地址,那么使用
  
  user01 * test01 *
  
  由于pppd程序需要控制网络接口(建立网络接口),所以需要使用root身份来执行,
为了让所有拨号用户都能使用pppd,需要设置pppd为setuid程序:
  
  # ls -l /usr/sbin/pppd
  
  -rwxr-xr-x   1 root     root       131596 Sep 20  1999 /usr/sbin/pppd
  
  pppd程序的拥有者是root,只要setuid就行了:
  
  chmod u+s /usr/sbin/pppd
  
  接下来是最困难的步骤了,启动调制解调器应答。为了驱动调制解调器,你的系统中
必须有一个串行口管理程序。我们使用的是mgetty,它包含在大部分Linux发行版本中。
假设你已经安装了mgetty程序,例如
  
  $rpm -q mgetty
  
  mgetty-1.1.14-9
  
  就可以开始设置调制解调器应答了,进入到/etc/mgetty+sendfax目录,编辑mgetty.
config文件。
  
  下面是我们的mgetty.config文件,你可以按照这个方式自己编写:
  
  # !mgetty.config
  
  debug 4
  
  speed 31400
  
  port ttyS0
  
  init-chat "" ATZ OK "AT M0E1Q0S0=0" OK
  
  answer-chat "" ATA CONNECT \c \r
  
        port ttyS1
  
  init-chat "" ATZ OK "AT M0E1Q0S0=0" OK
  
  answer-chat "" ATA CONNECT \c \r
  
  这个文件的内容倒是十分简单的,debug 4将mgetty的纪录级别定义为4,在你调试正
常之后可以将它改成一个合适得值;speed 31400设置了传输速度为33.6k;接下来的就
是各端口连接的调制解调器的初始化段落,port ttyS0往下的段落定义了一个接在COM1
上的调制解调器,而init-chat和answer-chat分别定义调制解调器的初始化和应答命令
。port ttyS1则是COM2上的调制解调器,这样,每一个调制解调器都需要自己的段落。
这里的init-chat和answer-chat中的命令可以适用于大部分调制解调器。不要问我这些
命令从那里来的,你可以自己参考关于调制解调器的标准。必须注意缺省的mgetty.con
fig文件中,有一行(fax_id ....)是用来设置缺省应答为传真的,你必须手工把它去掉

  
  如同我们说的,调制解调器的驱动是靠mgetty程序,我们可以手工启动mgetty程序,
不过更常见的方法是修改运行级别。我们知道,缺省的/etc/inittab定义了所有的运行
级别,在多用户级别,它利用mingetty程序开出了六个虚拟屏幕,我们可以用同样的方
法开出一个虚拟终端,这只需要修改/etc/inittab文件的下面部分(加粗体的是我们加
入的部分):
  
  #!/etc/inittab
  
  ………………
  
  1:2345:respawn:/sbin/mingetty tty1
  
  2:2345:respawn:/sbin/mingetty tty2
  
  3:2345:respawn:/sbin/mingetty tty3
  
  4:2345:respawn:/sbin/mingetty tty4
  
  5:2345:respawn:/sbin/mingetty tty5
  
  6:2345:respawn:/sbin/mingetty tty6
  
  sm1:35:respawn:/sbin/mgetty ttyS0
  
  …………………………
  
  在运行级别三和五,对ttyS0启动mgetty。如果你有更多的调制解调器,启用更多的m
getty行就可以了。
  
  上面给出的是一个接在com1上的调制解调器的驱动方式,如果你有更多的调制解调器
,为每个调制解调器在mgetty.config文件中加入一个段落,并且在/etc/inittab中开出
一个mgetty进程。不过,我个人只实验过连接两个调制解调器,如果你需要接续1个或更
多的同时连接,你多半需要某种多串口卡。据说,多串口卡上的串行口相应的设备名字
是ttyCXX,你可以自己试试。也许要在核心中编译相应的支持。
  
  在客户程序拨入的时候,mgetty程序将试图调用/etc/mgetty+sendfax/login.config
,从中查找关于AutoPPP的内容,所以我们必须建立这个文件,如果你只是要使用PPP服
务,可以将这个文件设置为只有下面这样一行:(实际上,你的缺省安装的mgetty里面
已经有一个这样的模板了)
  
  !#login.config
  
  /AutoPPP/ -     a_ppp   /usr/sbin/pppd auth silent -chap +pap login
  
  -chap +pap表示使用pap身份认证方式。为了避免输出不必要的垃圾信息,使用silen
t选项。另外,如果你希望用户连接中的信息以用户的名字(而不是缺省的a_ppp)进行
记录的话,将a_ppp改成一个"-"。
  
  至此,我们配置好了调制解调器的行为,接下来,连接调制解调器,打开调制解调器
电源,重新启动服务器以便确保inittab中开出的mgetty被正确执行,不要忘了打开核心
IP转发,然后就可以接受客户机器的拨号呼叫了。
  
  上面说的是基于ProxyARP的拨号服务,这个服务的最大特点是客户机器和服务器处在
一个子网之内,如果你想要用拨号网络连接两个子网,那么你需要去掉/etc/ppp/optio
ns文件中的proxyarp命令行,并且设置缺省路由递送路径。特别是,需要把拨号网络的
服务器/客户的拨号网络接口当成一个缺省路由路径,这可以手工加入路由路径,但是更
常用的方法是使用在/etc/ppp/options文件中加入defaultroute行(没有参数),这样
ppp管理程序会自动将拨号连接作为一个缺省路由路径加入,在ppp被切断之后自动删除
路径。注意服务器和客户端都必须使用这个选项。
  
  ppp server是一种非常容易出现问题的东西,为此,缺省情况下,pppd产生的信息将
会被存储到/var/log/messages中,而mgetty则对任何ttyXX产生一个/var/log/mgetty.
log.ttyXX文件,如果你的ppp莫名其妙地当掉或者无法建立连接,请研究这些记录文件
中的错误信息。
  
  另外,也存在其他的拨号连接数据传递方式,例如uucp和slip。不过,由于本书是一
本处理常规问题的教本,我不想在这里讨论这个问题。毕竟,ppp已经够用了,对吗?
  
  最后我们要额外说明一句,有时某些人并不希望建立一个网络连接,相反,他希望能
够以终端方式连接到服务器上。在这种情况下,你只要按照前面的方法设置好调制解调
器应答,开出合适的mgetty进程,就会发现用户已经可以拨号连接到服务器上了。这个
技术的一个古怪的应用是用Null-Modem连接来接通两台机器,详细的资料可以参考随mg
etty提供的文档。
  
  1.5 网络代理程序
  
  在Apache服务器的部分我们已经接触到了浏览代理的概念。与IP代理不同,浏览器代
理或者类似的其他代理程序通常只能对确定的应用程序进行代理。这类代理程序往往是
为了减少网络流量,提高网络速度或者是绕过防火墙用。
  
  我们在这里讨论最常用的代理程序。squid类似于apache的浏览代理,实际就是一个高
速缓冲器,但是在某些方面,它比apache更容易管理。而socks5代理则是一个特殊的转
发器,它利用某种特定的编程接口接受客户的请求并且代替客户处理请求。
  
  1.5.1 squid代理程序
  
  与Apache的proxy功能类似,squid也是一个接受客户请求,代替客户处理并且加以缓
冲的产品。但是与apache不同的是,squid不需要forks自身。另外,squid可以配置成为
利用用户名和口令来限制用户的身份,这在按照IP地址进行身份认证不适用的时候是很
重要的。
  
  squid是一个功能非常强大的程序,例如你可以将它配置成向“内”的服务器(提高你
自己的服务器的响应能力),或者是用多个squid机器构成复杂的缓冲系统,如此等等,
你可以自己参考squid的文档。作为一本教程,我们不想涉及到这一类过于专门的问题中
去。我们将主要介绍如何配置一个可以通过密码验证用户的代理系统。实际上,很多防
火墙的设计者都利用squid在不损害防火墙的可靠性的同时使得用户的应用更加简便。例
如,你可以用防火墙将除了squid机器之外的所有内部机器全部挡住,然后让客户通过s
quid访问外界,这样的方法比建立复杂的ipchains过滤规则更容易,而且除非防火墙机
器被攻克,内部的机器是安全的。
  
  要使用squid,首先必须安装这个程序,例如:
  
  [root@wxd linux]# rpm -q squid
  
  squid-2.2.STABLE4-5
  
  然后就可以配置squid程序了。
  
  squid的配置文件在/etc/squid/squid.conf,(编译时定义),实际上,你完全可以
在缺省的配置文件上改动,不过,按照我们的一般方法,我们从一个适当构作的最小的
squid.conf开始:
  
  http_port 4444
  
  acl LOCALDOMAIN src 202.199.241.0/255.255.255.0
  
  acl test proxy_auth REQUIRED
  
  acl all src 0.0.0.0/0
  
  acl SSL_ports port 443 563
  
  cache_mem  1 MB
  
  cache_dir /var/squid/cache 100 16 256
  
  cache_access_log /var/log/squid/access.log
  
  cache_log /var/log/squid/cache.log
  
  cache_store_log /var/log/squid/store.log
  
  cache_dns_program /usr/bin/dnsserver
  
  dns_children 5
  
  authenticate_program /usr/bin/ncsa_auth /etc/squid/passwd
  
  authenticate_children 5
  
  authenticate_ttl 30
  
  reference_age 1 month
  
  acl Safe_ports port 10 21 443 563 70 210 1025-65535
  
  acl CONNECT method CONNECT
  
  http_access allow LOCALDOMAIN
  
  http_access allow test
  
  http_access deny !Safe_ports
  
  http_access deny CONNECT !SSL_ports
  
  http_access deny all
  
  这个配置文件包含了squid的主要内容,首先,http_port 4444定义squid使用的代理
服务端口。这里利用4444端口作为代理端口,注意由于squid是以nobody权限运行,这个
端口必须大于1024。
  
  接下来,acl是一种定义行,上面的定义可以这样解释:
  
  acl all src 0.0.0.0/0将"all"定义为一个类,包含所有客户机器。src说明这里的定
义是对源地址的,也可以用dest对目标地址进行定义,如acl sth dest 202.199.241.0
/24。
  
  acl LOCALDOMAIN src 202.199.241.0/255.255.255.0如上述是定义所有位于202.199
.241.*处的客户机器为LOCALDOMAIN类。
  
  acl SSL port 443 563 将所有目标端口是443或563的访问定义为SSL类。同样另外的
一句acl safe_ports port 10 21 443 563 70 210 1025-65535定义连接到这些端口的访
问为安全端口。
  
  acl test proxy_auth REQUIRED定义所有需要身份验证的用户为test类。
  
  acl CONNECT method CONNECT 定义所有使用TCP连接的用户为CONNECT类。
  
  实际上,所有这些类的定义都是为了给后面的存取限制提供定义,我们可以在最后看
到存取限制语句:
  
  http_access allow LOCALDOMAIN
  
  http_access allow test
  
  http_access deny !Safe_ports
  
  http_access deny CONNECT !SSL_ports
  
  http_access deny all
  
  允许202.199.241.0/24的用户使用代理;另外凡是通过了身份验证的用户也可以使用
代理;其他的全部禁止。访问到非安全端口的全部禁止。
  
  squid的用户身份验证是通过密码验证。要使用这个功能,首先必须编译squid的密码
验证程序。这要求你安装了squid的源代码,然后在squid源代码的目录中
  
  $make
  
  gcc -g -O2 -Wall -I. -I../../include -I../../include    -c ncsa_auth.c -o 
ncsa_auth.o
  
  gcc -g ncsa_auth.o -o ncsa_auth -L../../lib -lmiscutil -lcrypt -lm -lresol
v -lbsd -lnsl
  
  将会在当前目录下产生一个ncsa_auth程序。将它拷贝到/usr/bin下面。
  
  我们可以通过Apache部分讲到的htpasswd程序生成身份验证需要的密码文件:
  
  $htpasswd -c /etc/squid/passwd wanghy
  
  New password: 
  
  Re-type new password: 
  
  Adding password for user wanghy
  
$
  
  这样就加入了一个名叫wanghy的squid用户,然后就可以用上面的行来启用身份验证程
序了:
  
  authenticate_program /usr/bin/ncsa_auth /etc/squid/passwd
  
  authenticate_children 5
  
  说明用/usr/bin/ncsa_auth作为身份验证程序,验证密码文件为/etc/squid/passwd,
注意这个文件必须全局可读,因为squid在工作的时候,是用一个属主为nobody的子进程
来执行,相应地ncsa_auth的权限也是nobody。authenticate_children是身份验证程序
的个数。设置了身份验证后,用户访问代理服务时会弹出这样的对话框:
  
 
  
  图1.3 squid的身份验证
  
  只有用户名和口令符合,才能通过代理访问外界。
  
  authenticate_ttl 3600这样的行用来定义一次身份验证的有效期,如果超过了这个时
间用户没有动作,再连接时squid会要求用户重新进行身份验证。
  
  接下来的几行设置squid用的内存数量,使用的纪录文件,而最重要的是下面一行:
  
  cache_dir /var/squid/cache 100 16 256
  
  这个命令设置squid用来存贮cache文件的目录,这个目录必须是全局可写的;后面三
个参数,第一个是目录的容量,或者说最大允许多大的cache;第二个和第三个则是第一
层和第二层目录下允许有多少个子目录,你可以自己调节这些数字。
  
  如果你处在防火墙内部,而名字服务器位于防火墙外,你可能希望代理服务器能同时
对DNS进行代理,下面两行:
  
  cache_dns_program /usr/bin/dnsserver
  
  dns_children 5
  
  启动了这个功能,dnsserver程序是缺省的dns代理程序,包含在squid软件包中。dns
_children是缺省的DNS代理程序的个数。
  
  最后的一个常用参数是reference_age,它表示一个无人访问的缓冲文件将在硬盘上保
留多长时间,缺省是一个月,你可以自己调整。
  
  当squid.conf配置正确之后,需要生成一下cache目录,这可以用-z参数完成:
  
  $ /usr/sbin/squid -z
  
  然后就可以启动squid了:
  
  $/usr/sbin/squid
  
  接下来,将客户机器的代理服务器添成你的squid机器,一切正常的的话就可以使用了
,如果有什么问题,可以看定义的几个记录文件。一定要注意,squid真正的缓冲程序是
以nobody身份执行。
  
  关于squid,比较容易出现问题的是它的用户身份验证。实际上,这个身份验证可以用
你自己写的程序完成。当squid接收用户身份认证信息的时候,它传递一个用户名/密码
的字符串给squid.conf里面设定的密码验证程序,并且期望验证程序在密码正确时输出
OK,否则输出ERR。这种行为可以用nsca_auth程序的工作方式来说明:
  
  bash# ./ncsa_auth passwd
  
  user1 password
  
  OK
  
  test testerror
  
  ERR
  
  这是个无限循环,如果输入正确的用户名 口令,输出OK,直到系统给它一个中止信号
。你可以自己写一个类似的密码验证程序。
  
  1.5.2 socks 5及其使用
  
  socks代理是另外一种“在防火墙上钻孔”的常用程序。与前面提到的浏览器代理程序
不同,socks代理是使用一种特殊的API,让客户机器和服务器进行对话,客户将数据包
(而不是浏览器请求)提交给服务器,服务器代替客户机器与网络进行对话,并且返回
结果。socks的最大优势是,几乎所有的正常TCP/IP程序都可以利用socks5的客户程序“
包装”来使用代理,即使这个程序本来并不支持socks5。由于透明的支持UDP proxy,s
ocks5程序经常被用来让防火墙内的机器使用ICQ等聊天程序。目前最常用的socks代理协
议是socks5。
  
  要使用socks5代理,简单地取回socks5服务程序,例如我们用的是socks5-1.0r4,取
回socsk5-v1.0r4.tar.gz,展开成源代码目录,进入后编译安装:
  
  ./configure
  
  make
  
  make install
  
  将会产生/usr/local/bin/socks5程序,启动socks5只要执行这个程序。
  
  socks5的缺省配置文件是/etc/socks5.conf,我们在这里不想对socks5作太多的介绍
,如果你想制作一个对某些客户可以使用的socks代理,参考下面的socks5.conf配置:
  
  permit  -       -       202.199.241.0/255.255.255.0     -       -       -
  
  auth -  -       -
  
  这样就构成了一个对202.199.241.0/24的网络开放的socks代理。使用的时候,只要在
IE的代理服务器的socks代理中添上你的socks5服务器地址就可以了,端口号是(缺省)
1010。
  
  IE/Netscape/ICQ都可以直接使用socks5代理,如果需要让一些不支持socks代理的客
户程序能够使用socks5代理,你需要使用socks的专用客户程序。通常我们的客户机器是
Windows 9X,对应的客户程序是sockscap程序,你可以自己下载这个程序,安装到客户
机器上,使用方法很简单,这里不再叙述。



  • 上篇文章:Red Hat9.0安装配置指南(2003-9-20 21:18:38)
  • 下篇文章:解读防火墙记录(2003-9-20 21:23:20)
  • 相关文章
    没有相关文章

  • 联盟网站→[ 中国黑客联盟  |  网嗅网络 |  泰安铁通  |  小尤格斗界 ]