用Linux实现路由器和包过滤防火墙

用Linux实现路由器和包过滤防火墙

  路由器和防火墙

  路由器是一种广泛运用在IP网段之间的设备,市场上有许多现成的产品。在应用中,我们经常将路由器跨接在广域网和局域网之间,大多数的路由器产品也就是基于这种需要来设计的。但是随着用户IP网络的扩展,我们需要一种能够在多个以太网络之间进行寻址的路由器,传统的路由器产品中偶尔有几款双以太网络接口的,但是这样的产品价格尤其昂贵,而且要是支持快速以太网络应用的话价格将是天文数字;第三层交换机可以实现这样的功能,但是第三层交换机也不是便宜的家伙。

  路由器工作的时候,根据它的某个端口收到的数据包的目的IP地址,查询路由器自己的路由表,然后决定将数据包转发到相应的端口。路由器的路由表有几种:一种是根据路由器自己的每个端口IP地址和子网掩码计算出来的路由,这种路由叫做“固定路由”;第二种是有系统管理员种设置的到某个子网需要通过某个下一级路由器的路由,这种叫“静态路由”;还有就是在网络环境中让每个路由器都把自己的路由信息广播出去,让路由器之间进行互相学习,这样学到的路由就叫做“动态路由”。路由器还会把目的地址不在自己路由表中的数据包固定转发给一个预先设定IP地址,这样的路由设置又叫“默认路由”。在路由匹配的过程中,一般有这样的优先级:固定路由>静态路由>动态路由>默认路由。

  路由器只会查看IP数据包的目的地址,也就是说原则上它是“照单全收”,而且全部转发,除非真的发不出去了。如果让路由器在转发数据包的时候,加一项检查,检查数据包的来源和数据包要求的应用层服务类型,根据预先设计的规则来判定这个数据包是应该转发还是作别的处理,这样这个路由器就不再是一个单纯意义上的路由器,而是一种类型的防火墙——包过滤防火墙。

  包过滤防火墙可以检查数据包的来源、源端口、目的地址、目的端口,使用的传输层协议类型等项目,根据检查的项目的内容来匹配一个规则表,当符合规则表中的定义的时候,就执行规则表事先定义的操作。一般来说,规则表可以定义这样的操作:ACCEPT(通过)、NAT(MASQ地址转换)、DENY(丢弃)、REJECT(拒绝,同时回送‘不可用’消息给源端)。

  当然目前市场上也能买到支持包过滤防火墙的现成产品,但是价格问题还是我们不得不考虑的重要因素。尤其大多数产品都有许多许可证、性能等方面的限制。

  Linux操作系统应运IP网络而生,除了Linux价格上的优势之外,更吸引人的是它内建的强大的网络功能,除了做各种Internet上的应用服务之外,Linux还提供了完整的路由器功能和防火墙功能。而它所带来的系统造价和功能的比例是相当诱人的,为什么不一试呢?
  Linux系统的准备

  相对于现成的路由器产品,我们把这样的路由器称为“软路由器”,当然这样做出来的路由器性能绝对不会比“硬件路由器”的性能差,我们只要明白比如很多“25××”系列的路由器才只是采用25M主频的摩托罗拉68030CPU(性能相当于Intel 80386)我们就知道了。

  用来做“软件路由器”的Linux系统主机硬件配置要求并不是太高,用作三五个局域网之间的路由选择,数百台计算机的话,选用奔腾133以上的主机就足够了,当然现在的市场上赛杨2或者奔腾4或者其他的CPU也不是很贵;配置64M内存,有条件的话可以配置到128M也无所谓;硬盘就不要太大了,否则也是浪费.

  关键在于网络适配器的配置,Linux系统支持大多数市场上能见到的以太网络适配器,PCI卡的安装比较简单,只要内核支持,在开机的时候有多少卡都会被系统正确的识别出来。下面是我在实际使用过的能够正常工作的网卡:

  ★Intel EtherExpress Pro PCI100M

  ★RealTek 8029/8139 PCI 10M/100M

  ★D-link 系列 (使用Tulip 2114X驱动) PCI 10M

  ★ACCTON EN1207 (使用Tulip 2114X驱动) PCI 100M

  ★3COM全系列 (PCI/ISA 10M/100M)

  ★AMD PC-NET 32 PCI 10M

  ★大部分NE2000兼容网卡,Topstar、Dlink、ACCTON、SN2000等等

  ★HardLink PCMCIA 笔记本专用网卡 10M

  当然Linux能支持的网卡远远不止这些。

  将网卡驱动加挂到Linux中有几种方法,最常用的是用modprobe系统工具加挂一个内核模块,比如加载一个NE2000兼容网卡的驱动可以这样:
引用:
  #modprobe ne io=0x300
  Linux实现路由器

  正确配置IP地址等参数以后,系统就自动计算出了每个端口所接的子网的固定路由,在这样的一个例子中我们可以看到:

  我们可以用命令“route -n”或者“netstat -r -n”来查看系统目前的路由表,在右边图二所示的例子中,我们可以得到这样的路由表:
引用:
  # route -n
  Kernel IP routing table
  Destination Gateway Genmask Flags Metric Ref Use Iface
  10.3.2.4 0.0.0.0 255.255.255.252 U 0 0 0 eth0
  10.3.2.128 0.0.0.0 255.255.255.128 U 0 0 0 eth3
  10.3.253.0 0.0.0.0 255.255.255.0 U 0 0 0 eth2
  172.16.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth1
  做防火墙的系统准备

  包过滤防火墙比起路由器来说就是在转发数据包的时候多了一个规则表的检测,按照规则表的定义决定数据包的命运。可以说,路由器其实就是一个允许所有数据包正常通过的“防火墙”。

  防火墙还有一个很重要的功能就是保护一个内部的子网,以及将内部的私有地址转换成外部的IP地址,这个功能不但可以对内部网络起到保护作用,还可以节省IP地址资源,或者用来使一个本来不能被某设备识别的某网段IP能够实现对它的访问。这样的技术叫做NAT(网络地址翻译),实现的方式很多,直接在路由层次上实现是效率最高的。CISCO的PIX就是这样技术的商用产品的代表。 Linux的IP-MASQ(IP伪装)就是这样技术在Linux上的一个实现。

  当一个主机发起一个对其他主机的TCP/IP访问, 它必须在数据包的报头中指明对方的IP地址,以及对方提供连接的TCP/UDP端口,同时它会打开一个临时的端口准备接受返回的数据,然后把它自己的IP地址以及这个临时端口写到IP数据报的报头中。当一个数据包被NAT处理的时候,它的源地址将被替换成防火墙的出端口上的IP(有些防火墙产品使用地址池),同时NAT防火墙上也会在出端口上开放一个临时端口,将这个端口号替换数据包中的源端口号。当回应数据到来的时候,由于外部的主机只能看到NAT防火墙的IP和端口号,它发出的数据的目的地址和端口将是防火墙上的,而数据回来到防火墙以后,防火墙就把原来的内部主机的地址和端口号替换回来,将数据包转到内部网络上传送。

  而在NAT防火墙上,还需要建立一个此次地址转换的对应关系表。以便知道随后到来的源、回应数据包应该被怎样的替换回来。

  由于包过滤防火墙的所有操作都是根据规则表来的,所以规则表就显得格外的重要。我们使用一个叫ipchains的工具来维护系统规则表,ipchains把规则表叫做防火链。当一个数据包进入Linux机器时,要通过进入链(input)的检查,当一个Linux机器准备发送一个数据包时,这个包又要通过输出链(output)的检查,当作为路由器使用的时候,还要点所有中转的数据包增加一道中转链(forward)的检查,每个链都可以配置自己的规则表。所以,其实一个通过Linux防火墙的数据包需要经过input、forward、output三个规则的检查,当这个Linux作为普通路由器使用的时候,三个链的规则都是ACCEPT(允许通过)。

  这是一个需要中转的数据包通过ipchains的过程:

  在规则表中,数据包总是先和第一条规则进行匹配,如果不匹配在比较下一条规则,一旦某条规则适应了,就不再比较,直接按此规则执行,所以排列在前面的规则总是优先与排列在后面的规则。

  用ipchains建立规则表

  使用命令:
引用:
  ipchains -P 链名 动作
  只有一种情况例外,由于IP伪装回来的数据包不经过中转链,所以不需要再中转链中只需要为IP伪装设置一个单向的规则,比如说把所有从10.3.2.0/25来访问172.16.0.0/16的数据包都做一个伪装,那么就可以这样设置:
引用:
  #ipchains -A forward -s 10.3.2.0/25 -d 172.16.0.0/16 -j MASQ
  设置防火墙中不应该被过滤的信息

  我们设置防火墙的时候,总是要想办法过滤我们所不能识别的东西,但有些信息对于网络的运行来说是必须的,一般正常情况下不能被过滤,否则将影响网络的正常运行,而这一点又是初学的系统管理员经常忽略的内容。

  ICMP,很多系统管理员过滤ping,主要使因为可以用ping把一些网络线路带宽比较窄的地方堵塞,为了贪图省事,就把整个ICMP过滤了。但是其实 ICMP 包还被用来为其它协议(TCP, UDP)指示错误。 如: “destination-unreachable” 等等。这些信息被过滤的话意味这你将不会收到 “Host unreachable”或者“No route to host” 等报错信息, 所有的连接将等待一个永不会来的回复。将会使客户机花费很长的一段时间等候TCP/IP协议的超时。 这样做虽然不好, 但还不致命。

  一个更糟的问题是 ICMP 包在“MTU (最大传输单元)测试”中担任角色。 为良好的完成 TCP 连接,主机会使用“ MTU测试”去算出不被分解成片段就可以到达目的地的最大包。 “MTU测试”是这样工作的: 发送带有“Don\'t Fragment(不分解成片段)位”的包, 如果收到 “Fragmentation needed but DF set(包需要分解成片段)”包,那么就发送较小的包;如果禁止了ICMP信息,本地主机将不会减小 MTU, 测试就将永远进行或没有意义。如果网络上存在MTU不一致的网段,这样将会极大的影响网络性能。

  正确过滤ping的做法是过滤ICMP的0号和8号端口:
引用:
  #ipchains -A input -s 0.0.0.0/0 -d 0.0.0.0/0 -p icmp 0 -j DENY
  #ipchains -A input -s 0.0.0.0/0 -d 0.0.0.0/0 -p icmp 8 -j DENY
:0L :0L


再顶了