[OpenBSD]

[上一小节: 包过滤] [总目录] [下一小节: 重新定向网络通讯(端口转发)]

PF: 网络地址转换(NAT)


目录


介绍

网络地址转换(NAT)是将一(或多)个网络整体映射到一个IP地址的方法。当Internet服务提供商提供给你的IP地址数量少于需访问Internet的主机数量时NAT是必须的。NAT的描述请参看 RFC 1631的"The IP Network Address Translator (NAT)."

NAT允许你使用保留的地址段, 在 RFC 1918, "Address Allocation for Private Internets."对其进行了典型性地描述。你的内部网络可以使用下列的一个或多个网络地址段:

	10.0.0.0/8       (10.0.0.0 - 10.255.255.255)
	172.16.0.0/12    (172.16.0.0 - 172.31.255.255)
	192.168.0.0/16   (192.168.0.0 - 192.168.255.255)

OpenBSD系统要进行NAT至少需要两个网络适配器, 一个连接Internet, 另一个连接内部网络。 NAT将转换来自内部网络的请求, 所以看起来它们似乎都来自你的OpenBSD NAT系统。

NAT怎样工作

当一个内部网络的客户端与Internet上的一台计算机通讯时, 它发送IP数据包到那台计算机。这些数据包包含了所有抵达所需的地址信息。NAT会参与修改这些信息:

当数据包流经NAT网关时将会被修改, 所以对外它们看起来像是发自NAT网关的数据包。NAT网关会将这些变化记录在自己的状态表中以便它可以 a)对回应的数据包逆向操作(还原)和 b) 确保返回的数据包不被防火墙阻止。例如, 可能产生如下的变化:

无论内部的机器和外部的主机都不知道这些转换步骤。对内部主机来说, NAT系统只是一个Internet网关;对Internet上的主机来说, 这些数据包看起来直接来自NAT系统; 它们甚至无法察觉存在一个这样的内部工作站。

当Internet主机回应内网机器的数据包时, 这些回应数据包会被冠以NAT网关的外部IP地址(24.5.0.5)和转换端口(53136)。NAT网关会搜索状态表, 确认这些回应的数据包是否匹配一个已经建立的连接。状态表内基于IP地址和端口的匹配项会告诉PF这些数据包属于位于192.168.1.35的内部机器发起的连接, PF将会对回应的数据包进行逆向修改操作, 并将修改后的回应数据包转发给内部机器。

ICMP数据包的转换过程类似上面的操作, 但是不修改源端口。

NAT和包过滤

注意: 转换后的数据包必须还途径过滤引擎, 并且根据预先定义的过滤规则判断允许或禁止其通过。唯一的例外是在NAT规则里使用了pass 关键字, 这将使被NAT的数据包不经检查而直接通过过滤引擎。

还需要知道的是, 因为转换发生在过滤之前, 过滤引擎看见的是带有转换地址和端口的被转换的数据包, 这在 NAT怎样工作.里有相关的描述。

IP转发

因为NAT总是用于路由器和网关, 所有可能必须在OpenBSD机器上启用IP转发以便让数据可以在网络接口间传送, 使用sysctl机制启用IP转发:

# sysctl net.inet.ip.forwarding=1
# sysctl net.inet6.ip6.forwarding=1  (如果使用 IPv6)

要使这些变化永久生效, 将下面的两行加入 /etc/sysctl.conf:

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1

这两行在默认安装时已经有了, 不过是被注释的(最前面有#)。删除#并保存文件, 重新启动后IP转发据生效了。

配置NAT

说明: OpenBSD 4.7中的NAT配置与以往版本相比有了显著的不同。

NAT被指定为一个出站 pass 规则可选项 nat-to 参数。 一般来说, 并非直接应用在 pass 规则上, 而是应用于一个 match 规则。 当一个数据包被一个 match 规则选中, 参数 (例如,在那条规则里的 nat-to) 被记住了,并且当一个符合这条 pass 规则的一个数据包抵达时,这个参数就被应用到这个数据包上。 这允许整个一类数据包由一条单独的 match 规则来处理,然后通过 blockpass 规则对数据包进行处理。

通常在 pf.conf 里的格式为:

match out on interface [af] \
   from src_addr to dst_addr \
   nat-to ext_addr [pool_type] [static-port]
...
pass out [log] on interface [af] [proto protocol] \    from ext_addr [port src_port] \    to dst_addr [port dst_port]
match
当一个数据包经过规则集并匹配其中一条时 match 规则时, 所有在这条规则里被指定的可选的参数就被记住了以备将来使用 (made "sticky").
pass
这条规则允许这个数据包被传送。如果这个数据包先前已经匹配了一条指定了参数的 match 规则, 这些参数将被应用到这个数据包上。 pass 规则也许有它们自己的参数; 这些参数的优先权将高于在一条 match 规则中指定的参数。
out
指定这条规则应用在数据流的什么方向上。nat-to 只能指定到出站数据包上。
log
通过pflogd(8)来Log匹配的数据包。 一般只log第一个匹配的数据包。 如果要log所有的匹配数据包, 则要使用 log (all)
interface
用于传送数据包的网络接口的名称或组。
af
地址族, 无论是用 inet 表示IPv4、或者用 inet6 表示IPv6。PF通常有能力根据 源/目标 的地址判断出这个参数。
protocol
这里表示允许的数据包的协议 (例如tcp, udp, icmp)。 如果 src_port 或者 dst_port 被指定了, 也必须 给出协议类型。
src_addr
将被传送的数据包的源(内部)地址。 源地址可被指定为:
src_port
在第四层数据包头里的源端口。端口可以被指定为: 这里的 port 选项一般不用在 nat 规则里,因为它的目标一般是NAT所有的通讯,无论使用哪个(些)端口。
dst_addr
被转换的数据包的目标地址。目的地址的指定方式和源地址类似。
dst_port
在第四层数据包头里的目标端口。端口指定方式与源端口类似。
ext_addr
转发数据包的NAT网关上的外部(转换)地址。外部地址可以指定为:
pool_type
指定用于转换的 address pool 的类型。
static-port
告诉PF不转换TCP和UDP数据包里面的源端口。

这样的话,一个常用的基本的格式看起来像这样:

match out on tl0 from 192.168.1.0/24 to any nat-to 24.5.0.5
pass on tl0 from 192.168.1.0/24 to any
或者你可以简化一下
pass out on tl0 from 192.168.1.0/24 to any nat-to 24.5.0.5

这条规则的含义是在接口 tl0 上对所有来 192.168.1.0/24 的数据包进行地址转换,并且将源地址替换为24.5.0.5。

尽管上面的规则时正确的,但这并非推荐的格式。 因为这样的规则维护起来很困难,任何外部或内部网络的数字变化都要重新修改上述规则。我们对比一下便于维护的规则:(tl0 表示外部接口, dc0表示内部接口):

pass out on tl0 from dc0:network to any nat-to tl0

简化的规则的优点很明显: 无论哪个接口的IP地址发生了变化,你也不用去修改规则。

像上面那样指定一个接口名称用于转换地址时,IP地址在载入配置文件 pf.conf 时PF会自动测定IP地址, 并非实时的。如果你使用DHCP来配置你的外部接口, 则会也许就是以个问题了。如果分配给你的IP地址变化了, NAT还用那个原来的IP地址继续转换出站数据包。 这会导致出站连接功能失效。要解决这个问题, 你可以将网络接口名称放在圆括号内,这样可以告诉PF自动更新转换地址:

pass out on tl0 from dc0:network to any nat-to (tl0)

这个方法在IPv4和IPv6的地址转换中都有效。

双向映射(1:1映射)

一个双向映射可以通过 binat-to 参数建立。一个 binat-to 规则在内部IP地址和外部IP地址之间建立一个一对一的映射。这很有用处, 例如: 在内部网络上提供一个web服务器,而用自己外部的IP地址。来自Internet到外部IP地址的连接将被转发到内部地址,而来自web服务器的连接(例如DNS请求)将被转换为外部地址。TCP和UDP端口永远不会被 binat-to 修改,因为它们随着nat规则走。

例子:

web_serv_int = "192.168.1.100"
web_serv_ext = "24.5.0.6"

pass on tl0 from $web_serv_int to any binat-to $web_serv_ext

转换规则的例外情况

如果你想转换大多数通讯, 但是在某些情况下有例外, 请确保有一条过滤规则来说处理例外的选项,这条规则不包含 nat-to 参数。 例如, 如果上面的NAT例子修改为这样:
pass out on tl0 from 192.168.1.0/24 to any nat-to 24.2.74.79
pass out on tl0 from 192.168.1.208 to any

那么整个的 192.168.1.0/24 网络的数据包将被转换到外部地址24.2.74.79,除了来自 192.168.1.208 的数据包。

检查NAT状态 Status

要查看正在运行的NAT转换可以使用 pfctl(8) 工具加上 -s 状态选项。这个选项将列出所有当前的NAT会话:

# pfctl -s state
fxp0 TCP 192.168.1.35:2132 -> 24.5.0.5:53136 -> 65.42.33.245:22 TIME_WAIT:TIME_WAIT
fxp0 UDP 192.168.1.35:2491 -> 24.5.0.5:60527 -> 24.2.68.33:53   MULTIPLE:SINGLE

解释 (仅首行):

fxp0
表示状态被绑定的接口, 如果状态是 floating 会出现self字句。
TCP
连接使用的协议。
192.168.1.35:2132
这个IP地址(192.168.1.35)是机器在内网上的IP地址, 它的源端口为2132。IP头中这个地址将被替换掉。
24.5.0.5:53136
IP地址(24.5.0.5)和端口(53136)是网关的地址和端口, 所有的内部数据包的IP地址和端口将全被转换为此IP和端口。
65.42.33.245:22
这个IP地址(65.42.33.245)和端口(22)是内部机器要访问的。
TIME_WAIT:TIME_WAIT
这表示PF认为此TCP连接应处于的状态。

[上一小节: 包过滤] [总目录] [下一小节: 重新定向网络通讯(端口转发)]


[back] www@openbsd.org
$OpenBSD: nat.html, v 1.29 2008/10/31 16:49:34 nick Exp $