|
荣誉版主
 
- UID
- 68876
- 帖子
- 5135
- 精华
- 5
- 积分
- 1539
- 菊花元
- 1289 元
- 威望
- 5 点
- 阅读权限
- 100
- 在线时间
- 722 小时
- 注册时间
- 2005-6-19
- 最后登录
- 2008-12-5
|
2楼
大 中
小 发表于 2007-6-30 09:30 只看该作者
5. 控制哪些要 NAT
您需要建立一些 NAT 规则,来告诉核心哪些连线要改变,同时如何去改变它们。要做到这点,我们需要一个非常多用途的 iptables 工具,同时指定 `-t nat' 选项告诉它去修改 NAT 表格。
NAT 规则的表格含有三个列表叫做`chains' :每一条规则都按顺序检查,直到找到一个相符的比对。该三个链就叫做 PREROUTING (对 Destination NAT 来说,因为封包首先是传入的)、POSTROUTING (对 Source NAT 来说,因为封包是离开的)、以及 OUTPUT (对 Destination NAT 来说,是指那些由本机产生的封包)。
假如我够艺术天份的话,下面的图示将准确模拟出上面所说的概念。
_____ _____
/ \ / \
PREROUTING -->[Routing ]----------------->POSTROUTING----->
\D-NAT/ [Decision] \S-NAT/
| ^
| __|__
| / \
| | OUTPUT|
| \D-NAT/
| ^
| |
--------> Local Process ------
於前述的每一点,当一个封包通过我们要查看的相关连线之时,如果它是一个新建连线,我们查看它在 NAT 表格里对应的链,看看能对之做些什麽动作。而由此获得的答案就应用於该连线将来的所有封包。
5.1 用 iptables 做简单的选择
iptables 具有如後所列的许多标准选项。所有那些带双减号的选项都是可以缩写的,只要 iptables 仍可将之与其它可能的选项区分开来就行。如果您的核心以模组形式来支援 iptables ,您就需要首先载入 ip_tables.o : `insmod ip_tables'。
这里,最重要的一个选项是表格选择选项: `-t' 。对於所有的 NAT 操作,您会想用 `-t nat' 来表示 NAT 表格。第二个重要的选项是以 `-A' 增加一条新规则至链的末端 (如:`-A POSTROUTING'),或以 `-I' 插入至前端(如:`-I PREROUTING')。
您可以指定您要做 NAT 的封包来源地址 (`-s' 或 `--source') 与目的地 (`-d' or `--destination')。这两个选项後面可以後接一个单一的 IP 地址 (如:192.168.1.1),或一个名称 (如: www.kernelnotes.org),或一个网路地址 (如:192.168.1.0/24 或 192.168.1.0/255.255.255.0)。
您也可以指定要比对的传入 (`-i' 或 `--in-interface') 和传出 (`-o' or `--out-interface') 界面,但哪一个界面可以指定则取决於您要将规则写入哪一个链去:对於 PREROUTING ,您可以选择传入界面,但对於 POSTROUTING (以及 OUTPUT),您可以选择传出界面。如果您不小心用错了, iptables 就会给您一个错误。
5.2 关於挑选哪些封包来 mangle 的细节
我前面已经说过,您可以指定来源和目的地地址。如果您省略来源地址的选项,那麽就泛指任何来源。如果您省略目的地地址,则泛指所有目的地地址。
您还可以指定一个特定协定 (`-p' or `--protocol')呢,例如 TCP 或 UDP:只有这些协定的封包才符合该规则。其主要原因是,指定 tcp 或 udp 协定可以允许更多选项:尤其是 `--source-port' 与 `--destination-port' 选项 (缩写为 `--sport' 与 `--dport' )。
这些选项可以让您指定只有哪些特定来源和目的地埠口的封包才符合该规则。这在您要重导 web 请求 (TCP port 80 或 8080) 但又怕影响其它封包的时候,就很好用了。
这些选项必须接在 `-p' 选项的後面(这会在为该协定载入共享函式库时有副作用)。您可以使用埠口号码,或者是在 /etc/services 档中的名称。
所有这些您能选择的封包之不同品质,都详细列在那个详细得有点恐怖的 manual page 中了(man iptables)。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
6. 谈谈要怎样 Mangle 封包
现在,我们知道如何去挑选那些我们要 mangle 的封包。为了要完善我们的规则,我们需要准确无误的告诉核心,什麽才是我们要对封包做的。
6.1 Source NAT
您想要做 Source NAT,是要去将连线的来源地址换成别的什麽的。这就要在它最後要送出去之前,於 POSTROUTING 链中完成了;这是一个非常重要的细节,因为它意味著所有在 Linux 主机本身上的其它东西 (routing, packet filtering) 都只看见那个还没改变的封包。同时,这也就是说,`-o' (传出界面) 选项可以派上用场了。
Source NAT 是用 `-j SNAT' 来指定的,同时, `--to source' 则指定一个 IP 地址、或一段 IP 地址、以及一个可配选的埠口或一段值域的埠口(仅适用於 UDP 和 TCP 协定)。
## Change source addresses to 1.2.3.4.
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
## Change source addresses to 1.2.3.4, 1.2.3.5 or 1.2.3.6
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
## Change source addresses to 1.2.3.4, ports 1-1023
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
封包伪装 (Masquerading)
有一个 Source NAT 之特例,叫做封包伪装:它只用於动态分配的 IP 地址,例如标准的拨接(如果用静态 IP 地址,则使用前述之 SNAT)。
您无需明确地将 masquerading 放进来源地址那里去:它将会使用封包传出界面作为来源地址。但更重要的是,如果该连接(link)断掉的话,那麽连线 (connections,无可避免的将失掉) 也会被忘掉,当连线用新的 IP 地址回来的时候就会有问题了。
## Masquerade everything out ppp0.
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
6.2 Destination NAT
一旦封包进入,会由 PREROUTING 链完成处理;也就是说,除了该主机自己的其它东西(诸如:路由、封包过滤) 都将封包看成要送到 `真正' 目的地。另外,那个 `-i' (传入界面) 选项也可以在这里使用。
需要修改本机产生的封包之目的地的话,那麽 OUTPUT 链就可以用上了,不过这并不常碰到。
Destination NAT 必须以 `-j DNAT' 来指定使用,同时用 `--to destination' 选项指定一个 IP 地址、或一段 IP 地址,以及可以配选一个埠口或一段埠口值域(只能用於 UDP 和 TCP 协定上面)。
## Change destination addresses to 5.6.7.8
# iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 5.6.7.8
## Change destination addresses to 5.6.7.8, 5.6.7.9 or 5.6.7.10.
# iptables -t nat -A PREROUTING -i eth1 -j DNAT --to 5.6.7.8-5.6.7.10
## Change destination addresses of web traffic to 5.6.7.8, port 8080.
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth1 \
-j DNAT --to 5.6.7.8:8080
## Redirect local packets to 1.2.3.4 to loopback.
# iptables -t nat -A OUTPUT -d 1.2.3.4 -j DNAT --to 127.0.0.1
重导向 (Redirection)
在 Destination NAT 有一个特别的情形:它是一个简单的便利,完全等同於给传入界面地址做 DNAT 一样。
## Send incoming port-80 web traffic to our squid (transparent) proxy
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 \
-j REDIRECT --to-port 3128
6.3 进一步的映对(Mappings)
还有许多 NAT 上面的解决方案是大多数人无需用到的。这里不妨和那些有兴趣的朋友探讨一下:
同一□围内的复合地址(Multiple Addresses)之选择。
如果您已经指定了一段 IP 地址, 而 IP 地址的使用选择是基於机器所知连线目前最少使用之 IP。它可以提供最原始的平衡负载(load-balancing)。
建立空 NAT 映对
您可以使用 `-j ACCEPT' 目标来让一个连线通过,而绕过 NAT 的处理。
标准的 NAT 行为(Behaviour)
预设的行为是在使用者制定的规则限制内,尽可能少的改变连线。换而言之,非不得已不要重映对(remap)埠口。
绝对来源埠口映对
如果其它连线已经被映对到新的连线,就算对於一个无需 NAT 的连线来说,来源埠口的转换有时或是必须绝对存在的。让我们假设一个封包伪装的情形,这已经非常普遍了:
一个网页连线由一台 192.1.1.1 的机器从 port 1024 建立,要连接到www.netscape.com port 80。
它被封包伪装主机以其自己的 IP 地址(1.2.3.4)进行伪装。
该封包伪装主机尝试由 1.2.3.4 (它的外部界面地址) port 1024 来做一个网页连线至www.netscape.com port 80。
然後 NAT 程式改变第二个连线的来源埠口为 1025,所以这两个连线不至於相冲(clash)。
当这个绝对来源映对存在之时,埠口被拆分为三个等级:
512 以下的埠口
512 到 1023 之间的埠口
1024 以上的埠口
任何一个埠口都不会被绝对映对到不同的等级去。
当 NAT 失效时会怎样?
如果没有办法如用户要求那样独一无二地映对连线,那麽连线就会被挡掉。当一个封包不能够界定为任何连线的时候,结果也一样,因为它们可算是畸形的,或者是该机器记忆体耗光了,诸如此类。
复合映对、重叠、和相冲(clash)
您可以设定 NAT 规则在同一个□围之上映对封包;NAT 程式足以聪明的去避免相冲。比方说,用两条规则将 192.168.1.1 和 192.168.1.2 这两个来源地址分别映对到 1.2.3.4,是完全可行的。
再来,您可以映对到真实的、已用的 IP 地址,只要这些地址通过这个映对主机就行。所以,如果您获得一个网路(1.2.3.0/24),但有一个内部网路使用这些地址,而另一个使用私有地址 192.168.1.0/24 ,您就可以 NAT 那些 192.168.1.0/24 的来源地址到 1.2.3.0 网路之上,而无需担心相冲:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 \
-j SNAT --to 1.2.3.0/24
这同样适用於那些 NAT 主机自己使用的地址:这其实就是封包伪装如何工作的了(分享伪装封包地址和来自主机本身封包之 `真实' 地址。 )
更甚者,您还可以映对相同的封包到许多不同的目标(targets)上去,而且它们都是共享的。例如,如果您不想映对任何东西到 1.2.3.5 上去,您可以这样做:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 \
-j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254
改变本机产生的连线之目的地
如果本机产生的封包之目的地改变了(例如,用 OUTPUT 链),而这样会导致封包由不同的界面送出去,这样来源地址也跟著变为那个界面。举例子说,改变一个环回(loopback)封包之目的地由 eth0 送出,会让来源地址也由 127.0.0.1 变成 eth0 的地址;而不像其它来源地址映对那样,这是立即完成的。当然,所有这些映对在回应封包进入时是颠倒过来的。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
7. 特殊协定
有些协定是并不想要做 NAT 的。对於每一个这样的协定而言,有两个延伸设定(extension)是必须要写清楚的:一个是关於协定之连线追踪,另一个关於实际的 NAT。
在 netfilter 发行套件里面,有一些关於 ftp 的现行模组:ip_conntrack_ftp.o 与 ip_nat_ftp.o 。如果您把这些插入到您的核心里面(或您永久性的编译它们),那麽要在 ftp 连线上做任何种类的 NAT 都是可行的。如果您不这样的话,那您可以使用被动模式 ftp,不过如果您要做一些动作甚於简单 Source NAT 的话,这就可能不那麽可靠了。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
8. NAT 的一些限制 (caveats)
如果在一个连线上做 NAT,所有 双向 (传出和传入) 的封包,都必须要通过 NAT 主机才行,否则并不可靠。尤其在连线追踪程式重组碎片 (fragments)的时候,也就是说,不但连线追踪会不可能,而且您的封包根本就不能通过,因为碎片会被挡下。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
9. Source NAT 与路由
如果您要做 SNAT,您会想要确定经过 SNAT 封包所传给的主机会将回应送回给 NAT 主机。例如,如果您映对某些传出封包到来源地址 1.2.3.4 之上,那麽外部的路由器就必须知道要将回应封包(目的地为 1.2.3.4 )送回给该主机。这可以用如下方法做到:
如果您要在主机自己的地址(路由和其它所有运作皆正常)上面做 SNAT,您无需做任何动作。
如果您要在一个在本机网路上尚未使用的地址做 SNAT(例如,映对到在 1.2.3.0/24 网路上的一个可用 IP 1.2.3.99),您的 NAT 主机就需要回应关於该地址的 ARP 请求,一如它自己本身的一样:最简单的方法就是建立 IP alias,例如:
# ip address add 1.2.3.99 dev eth0
如果您要在一个完全不同的地址上做 SNAT,您就要确定 SNAT 封包抵达的机器能够路由回该 NAT 主机。如果 NAT 主机是它们的预设闸道器的话,是可以做到的,否则,您就要广告(advertize )一个路由(如果跑路由协定的话),或是手工的在每一台参与机器上增加路由。
10. 在同一网路上的 Destination NAT
如果您要做 portforwarding 回到同一个网路,您要确定前向和回应封包双方都经过该 NAT 主机(这样它们才能被修改)。NAT 程式从现在开始(2.4.0-test6以後),会挡掉後面情形所产生的传出 ICMP 重导向:那些已经 NAT 的封包以它所进入的相同界面传出,而接收端伺服器仍尝试直接回应到客户端(不认可该回应)。
经典的情形是内部人员尝试连接到您的 `公有(public)' 网站伺服器,实际上是从公有地址(1.2.3.4) DNAT 到一个内部的机器(192.168.1.1)去,就像这样:
# iptables -t nat -A PREROUTING -d 1.2.3.4 \
-p tcp --dport 80 -j DNAT --to 192.168.1.1
一个方法是跑一台内部 DNS 伺服器,它知道您的公有网站的真正(内部) IP 地址,而将其它请求转传给外部的 DNS 伺服器。换而言之,关於您网站伺服器的记录会正确地显示为内部 IP 地址。
而另一个方法是同时让这台 NAT 主机将该等连线之来源 IP 地址映对为它自己的地址,我们可以像如下那样做(假设 NAT 主机之内部 IP 地址为 192.168.1.250):
# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 \
-p tcp --dport 80 -j SNAT --to 192.168.1.250
因为 PREROUTING 规则是最先执行的,对内部网站伺服器而言,封包就已经被定向好了:我们可以内定好哪个为来源 IP 地址。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
11. 感谢
首先感谢在我工作期间相信 netfilter 的构想并支持我的 WatchGuard 和 David Bonn。
|