目录
--------------------------------------------------------------------------------
介绍
重定向和包过滤
安全隐患
重定向与反射
水平分割DNS
将服务器移至独立的本地网络
TCP代理
RDR和NAT组合
--------------------------------------------------------------------------------
介绍
当你在办公室中运行NAT时, 你可以让内部所有的机器连接到Internet上, 但是如果外部需要访问NAT网关后的一台机器怎么办呢?这就需要设置重定向了。重定向允许将进站通讯发至NAT网关后面的机器。
我们看一个例子:
代码: 全选
rdr on tl0 proto tcp from any to any port 80 -> 192.168.1.20
这行将访问TCP端口80(web服务器)的通讯重定向到内部网络的一台机器192.168.1.20上。这样, 尽管192.168.1.20在网关后面, 而且还在你的内部网络上, 但仍然可以从外部访问它。
上面rdr这行中的 from any to any 这部分很有用, 如果你知道需要访问web服务器的地址或子网, 你可以在这里进行限制:
代码: 全选
rdr on tl0 proto tcp from 27.146.49.0/24 to any port 80 -> \
192.168.1.20
这条规则限制了仅能从指定的子网访问。注意, 这意味着你可以将来自不同区域的外部主机(的通讯)重定向到网关后不同的机器上, 这很有用。例如, 你可以让内部用户从远程站点通过网关上相同的IP地址和端口访问他们自己的计算机, 当然, 前提同样是您知道用户在远程站点上的IP地址:
代码: 全选
rdr on tl0 proto tcp from 27.146.49.14 to any port 80 -> \
192.168.1.20
rdr on tl0 proto tcp from 16.114.4.89 to any port 80 -> \
192.168.1.22
rdr on tl0 proto tcp from 24.2.74.178 to any port 80 -> \
192.168.1.23
重定向规则内同时可以使用端口范围:
代码: 全选
rdr on tl0 proto tcp from any to any port 5000:5500 -> \ <--- #1
192.168.1.20
rdr on tl0 proto tcp from any to any port 5000:5500 -> \ <--- #2
192.168.1.20 port 6000
rdr on tl0 proto tcp from any to any port 5000:5500 -> \ <--- #3
192.168.1.20 port 7000:*
这个例子是将5000到5500(包含)端口重新定向到192.168.1.20上。在规则 #1 里, 端口5000被重定向到5000, 5001到5001........。在规则 #2 里, 范围内所有端口被重定向到端口6000, 而规则e #3 里, 端口5000被重定向到7000, 5001到7001 ........
重定向和包过滤
注意:转换后的数据包必须还途径过滤引擎, 并且根据预先定义的过滤规则判断允许或禁止其通过。
这条规则唯一的例外是在rdr规则里使用了pass 关键字, 这种情况下, 被重定向的数据包可全部通过过滤引擎;过滤规则将不审查这些数据包, 这是避免为每个重定向规则添加过滤规则的一条捷径。你可以想象一下, 与普通的rdr规则(不包含 pass 关键字)相关的过滤规则带有keep state关键字, 然而, 如果你想启用更多指定的过滤选项, 例如synproxy, modulate state等, 你还必须使用一条 pass 规则, 因为这些选项在重定向规则内不适用。
还需要注意的是, 因为转换发生在过滤前, 过滤引擎看到的是经转换的数据包, 因为数据包被看到时目的地址和/或端口已经被修改为rdr规则指定的重定向地址或端口。想象一下这种情形:
192.0.2.1 - Internet上的主机
24.65.1.13 - OpenBSD路由器的外部地址
192.168.1.5 - web服务器的内部地址
重定向规则:
代码: 全选
rdr on tl0 proto tcp from 192.0.2.1 to 24.65.1.13 port 80 \
-> 192.168.1.5 port 8000
未经rdr规则处理的数据包:
源地址: 192.0.2.1
源端口: 4028 (操作系统随机选择)
目的地址: 24.65.1.13
目的端口: 80
经rdr规则处理后的数据包:
源地址: 192.0.2.1
源端口: 4028
目的地址: 192.168.1.5
目的端口: 8000
因为过滤引擎看到数据包时转换已经发生了, 所以过滤引擎看到的是下面的IP数据包。
安全隐患
重定向肯定存在安全隐患, 这等于在防火墙上穿了一个洞允许外部通讯进入内部, 被保护的网络存在潜在的安全威胁。如果通讯被重定向到一个内部的web服务器, 并且服务器程序或上面的CGI脚本的一个弱点被发现, 那么这台机器可能遭受来自Internet的入侵威胁。入侵者可以从它进入内部网络, 因为防火墙允许以这种方式访问内部网络。
通过将把外部访问的机器严格地限制在隔离的网络上可以最小化这种风险。这个隔离的网络经常被称为非军事化区(DMZ)或者私有服务网络(PSN), 仔细地审查过滤内部网络与隔离区域间的来往通讯, 这样即使这台web服务器被攻陷, 受影响的区域也仅限于DMZ/PSN网络。
重定向与反射
通常, 重定向规则被用于将来自Internet的进站连接转发到一台有私有地址的本地网络服务器上, 像这样:
代码: 全选
server = 192.168.1.40
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $server \
port 80
当你从LAN上客户端测试这个重定向规则时, 你会发现它不能工作。原因是重定向规则仅应用于流经指定接口的数据包(在上例中是$ext_if, 外部接口), 然而, 位于LAN的主机连接到防火墙的外部地址并不意味着数据包真的流经它的外部接口, 防火墙上的TCP/IP堆栈将进站数据包的目的地址与自己的地址及别名进行比较并察觉到要连接到它自己, 所以它马上将这些数据包改道至内部接口。 这样的数据包不会物理上真正地通过外部接口, 并且堆栈任何情况下也不会这样处理内部至内部数据包。因此, PF永远不会在外部接口上看见这些数据包, 重定向规则指定的外部接口也不会起作用。
增加第二条针对内部网卡的重定向规则也不能达到期望的效果。当本地的客户端连接防火墙的外部地址时, 完成TCP握手的初始化数据包通过内部接口到达防火墙。重定向规则确实起作用了, 并且目的地址被替换为内部服务器的, 这些数据包被转发回来经过内部接口抵达内部服务器。但是源地址并没有被转换, 也就是说还是本地客户端的地址, 所以服务器将回复直接发送到内部客户端, 防火墙永远看不到这些回复和没有机会进行反向转换, 而这个客户端由从未期望的源地址收到了一个回复, 所以它就直接将这个回复丢弃了, 最终TCP握手失败了, 并且不能建立任何连接。
很明显, 我们还是希望内部的客户端可以像外部的客户端一样连接到内部的服务器。这有几种解决的方法:
水平分割DNS
配置DNS服务器对来自本地和外部的客户端区别应询是有可能的, 这样在域名解析过程中本地客户端将得到内部服务器的地址, 它们就会直接连接到本地服务器上, 而防火墙一点也不会干涉。因为数据包不必通过防火墙, 所以这减少了本地的通讯量。
将服务器移至单独的本地网络
在防火墙上里另外再增加一个网络接口, 并且将服务器从客户端所在网络迁移到一个专门的网络(DMZ), 就像对外部客户端一样允许对内部客户端的连接进行重定向。使用单独的网络有几个优点, 包括通过将服务器和本地其余主机隔离开以提高安全性, 即便服务器总是面临威胁甚至被攻陷 (本例中可以从Internet直接接触它), 它也不能直接访问本地的其余主机, 因为所有的连接必须经过防火墙。
TCP代理
可以在服务器上建立一个普通的TCP代理, 监听被转发到的端口或者将连到内部接口的连接重定向到它监听的端口, 当一个内部客户端连接到防火墙时, 代理承担这个连接, 再建立一个到内部防火墙的连接, 并且在这两个连接间转发数据。
简单的代理可以使用 inetd(8) 和 nc(1)建立。下面 /etc/inetd.conf 的项目在产生一个监听套接字并绑定在loopback地址(127.0.0.1) 和端口5000上。连接被转发到192.168.1.10的80端口上。
代码: 全选
127.0.0.1:5000 stream tcp nowait nobody /usr/bin/nc nc -w \
20 192.168.1.10 80
The following redirection rule forwards port 80 on the internal interface to the proxy:
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
127.0.0.1 port 5000
RDR和NAT组合
在内部接口上附加一条NAT规则, 上面描述的源地址转换中的缺陷将得到修正。
代码: 全选
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
$server
no nat on $int_if proto tcp from $int_if to $int_net
nat on $int_if proto tcp from $int_net to $server port 80 -> \
$int_if
这将导致来自客户端的初始化数据包转发回内部接口时被再次转换, 用防火墙内部地址替换客户端的源地址。内部服务器将回复防火墙, 防火墙转发给内部客户端时将反转NAT和RDR的地址。 这个结构相当的复杂, 因为它为每个反射连接产生两个单独的状态, 必须小心防止NAT规则应用在其它的通讯上, 例如来自外部主机的连接(通过其它的重定向)或防火墙本身。注意上面的rdr规则会导致TCP/IP堆栈看到带有内部网络目的地址到达内部接口的数据包。
通常情况下, 应该用前面所提方法替代此方法。