分页: 1 / 1

《The BOOK Of PF》中文版 —— 8. 什么是本地网络?

发表于 : 2010-07-13 9:15
whoami

在本章前面我们介绍了interface:network这样的表示方法。它是一个简单的写法, 实际上你可以更多使用地macro让你的规则变得更易读和维护一些。
例如, 你可以将直接连接内部接口的网络指定成一个名为$localnet的macro(也就是上面例子中的re1:network)。
此外你还可以用把$localnet定义为一个IP地址/子网掩码的形式来表示一个网络, 例如用192.168.100.0/24 表示一个私有IPV4地址的子网,或者用fec0:dead:beef::/64 表示一个IPv6范围。
如果需要你甚至可以将$localnet指定为一个list(列表), 下面给出了一个这类网络的$localnet定义和放行规则的实例,以免你头大

代码: 全选

pass proto { tcp, udp } from $localnet to any port $ports
从这里开始我们后面将继续使用这个约定的定义。
设置
我们假设这台主机连接到了另一个网络, 或者不管采用什么方式, 你已经通过以太网卡、PPP或其它方式将本地网络与其它网络连接起来了。
我们不考虑网络接口的连接细节,我们只要知道网络接口已经可以使用了。
在下面的讨论中, PPP和以太网的设置仅在接口名称上有差别, 而且我们将全力尽快地摆脱具体的接口名称。
首先我们需要启用网关功能以便让这台主机将它接收的一个网络的通讯转发到另一个接口连接的网络。首先我们在命令行里输入sysctl命令;
对传统的IPv4来说:

代码: 全选

# sysctl net.inet.ip.forwarding=1

如果你还需要转发IPv6通讯, 命令是

代码: 全选

# sysctl net.inet6.ip6.forwarding=1
这仅是目前有效, 为了将来在重新启动计算机后继续可用, 你需要将以下设定加入适当的配置文件。
在OpenBSD和NetBSD里,你可以通过编辑 /etc/sysctl.conf 文件实现。
OpenBSD的默认的sysctl.conf文件中已经将这些行注视了, 要启用它们你可以删除这些行前面的哈希标志 (#) ,像这样:

代码: 全选

net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
在NetBSD里, 如果配置文件里没有这些行,你需要将手动添加。
在FreeBSD里编辑 /etc/sysctl.conf 文件也同样可以, 但是依据FreeBSD的惯例,
你要将这些航加到 /etc/rc.conf 文件:

代码: 全选

gateway_enable="YES" #for ipv4
ipv6_gateway_enable="YES" #for ipv6
效果是一样的: FreeBSD的rc脚本通过sysctl命令设定这两个值。 但是, 绝大多数的FreeBSD配置集中在rc.conf文件里。
现在是检查的时间了: 是否所有的接口已经准备就绪? 你可以使用ifconfig -a或者ifconfig 接口名称来确认一下。
这里是我系统上的 ifconfig -a 的输出:

代码: 全选

peter@delilah:~$ ifconfig -a
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33224
groups: lo
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x5
xl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:60:97:83:4a:01
groups: egress
media: Ethernet autoselect (100baseTX full-duplex)
status: active
inet 194.54.107.18 netmask 0xfffffff8 broadcast 194.54.107.23
inet6 fe80::260:97ff:fe83:4a01%xl0 prefixlen 64 scopeid 0x1
fxp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:30:05:03:fc:41
media: Ethernet autoselect (100baseTX full-duplex)
status: active
inet 194.54.103.65 netmask 0xffffffc0 broadcast 194.54.103.127
inet6 fe80::230:5ff:fe03:fc41%fxp0 prefixlen 64 scopeid 0x2
pflog0: flags=141<UP,RUNNING,PROMISC> mtu 33224
enc0: flags=0<> mtu 1536

你的设置肯定会稍有不同。我机器上的物理接口是 xl0 和 fxp0, 而逻辑接口是 lo0
(the loopback interface), enc0 (the encapsulation interface for IPsec use),
而你的系统上也应该有 pflog0 (the PF logging device)。
如果你使用拨号连接, 可能你使用各种PPP连接到Internet, 你还会多出tun0伪设备接口。
如果你使用某类宽带连接,例如ADSL, 你应该还有一个以太网接口。 但是, 如果你在一个大的ADSL用户的子网内,通过以太(PPPoE)来使用PPP,
正确的外部接口将是pseudo-devices tun0 or pppoe0(这要根据你使用用户岛的pppoe(8)还是内核模式的pppoe(4)),而不是物理以太接口。
根据你的设置, 你可能需要为你的接口做一些其它的特定设备配置。现在我想说的就是尽快完成它,这样我们就可以把重心转移到TCP/IP层并思考包过滤配置。
如果你仍然想允许所有内部机器发起的通讯,你的 /etc/pf.conf 大致应该这样:

代码: 全选

ext_if = "re0" # macro for external interface - use tun0 or pppoe0 for PPPoE
int_if = "re1" # macro for internal interface
localnet = $int_if:network
# ext_if IP address could be dynamic, hence ($ext_if)
nat on $ext_if from $localnet to any -> ($ext_if)
block all
pass from { lo0, $localnet } to any keep state
说明:这里使用macros来给网络接口指派逻辑名称。这里使用的是RealTek Gigabit以太网卡, 但不管怎样这是最后一次我们提网卡的实际型号了。
像这种简单的设置, 我们可能不太能从使用macros上获益, 但是一旦规则集变大, 你就能从感受到添加macros以后规则集的易读性。
还有一点,注意 nat 规则。 这里就是我们将来自不能路由的本地地址的通讯NAT到分配给你的唯一官方地址。如果你的网络使用的是正式的可路由官方地址,
你只需将这行从配置文件里删除。
nat规则的最后,圆括号内的部分, ($ext_if), 代表了动态分配给外部接口的IP地址。这可确保在外部IP地址发生变化时通讯不会中断。
在另一方面, 这个规则集从内部放行的通讯可能比你希望的多。我在自己的网络上稍微做了一些工作, 相当于macro是

代码: 全选

client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http,\
https, 446, cvspserver, 2628, 5999, 8000, 8080 }"

用这条规则

代码: 全选

pass inet proto tcp from $localnet to any port $client_out

可能你对选择这些奇怪的端口有些疑惑, 但这正好是那时该网络中的用户所需要的。一些数字端口代表了特定的应用,
你设定的规则也许与上面的不尽相同, 但是至少需要包含一些很有用处的服务。
此外, 我们还有一些其它的放行规则。我们在后面马上就讨论其中一些很有意思的规则。 其中一条规则对那些想从任意地方登录到系统的管理员是很有用处的。

代码: 全选

pass in inet proto tcp from any to any port ssh
或者, 如果你愿意,

代码: 全选

pass in inet proto tcp from any to $ext_if port ssh
这里的from any真是相当的宽松。它允许你从任何地方log in, 如果你总是出差并需要不时地从世界各地ssh回公司的网络,这条规则简直太棒了。
如果你并非总是四处旅行, 你可以缩小范围仅指定从合法的地址登录。
不过, 仅用这条很基本的规则还不够。下一步是让域名服务为客户端工作。我们在规则集的开始处定义另一个macro:

代码: 全选

udp_services = "{ domain, ntp }"
我们让防火墙放行我们需要的通讯:

代码: 全选

pass quick inet proto { tcp, udp } to any port $udp_services
注意这里的关键字quick。我们已经开始编写由几个规则构成的规则集了, 现在是你了解它们之间的关系和相互影响的时候了。
我们在前一章也接触了一些, 但是重复说一下并没有害处: 规则的执行自上而下。PF判断每个数据包和连接, 足后一个匹配的规则将被应用。
这个quick关键字提供了一个跳出常规顺序的语法。当一个数据包匹配一条quick规则时, PF将按当前的(quick)规则处理这个数据包。
规则处理结束前不考虑任何下面匹配的规则。当你的规则集变得更长及更复杂时, 你会发现quick很方便, 例如, 在通用规则里你需要某些特例。
quick规则同样适用于用来完成时间同步的Network Time Protocol (NTP), 域名服务和时间同步协议两者都需要特定的环境,也就是进行TCP或UDP通讯。

测试你的规则集
你也许还没有写一个正式的测试套件来测试自己刚编写的规则集,毋庸置疑,你必须测试这个规则集。
在前一章我们对单台主机的基本测试方法现在仍然有效, 只是目前你需要从网络中的另一台主机进行测试,就像在那台包过滤网关上进行测试一样。
在本地网络对每个规则里放行的服务进行有针对性的测试。从本地网络的任何一台主机运行命令,例如:$ host 9971.us,屏幕上的输出结果应该是一致的。
也不你认为没必须, 但是,从网关外测试规则集是否按照你预期的那样工作一点害处也没有。如果你严格按照本章操作,从外部应该不能连接到本地的主机。
为什么只有IP地址, 没有主机名或域名?
现在你注意一下这些例子中的规则集,你可能发现了所有的macros展开后全是IP地址或IP地址范围而从不是主机名或域名。总之为什么PF允许你的规则集里使用服务名称而不使用主机名或域名呢?
答案是, 如果你在PF的规则里使用域名和主机名, 则这些规则仅在域名服务开始运行和可悲访问后才有效。在默认的配置里, PF的导入在所有的网络服务运行前。
这意味着如果此时在PF的配置文件里使用域名和主机名, 你将需要更改系统的启动顺序(也许要通过编辑/etc/rc.local)以便在域名服务生效后导入域名带有域名的服务规则集。