[上一小节: 重定向(端口转发)] [总目录] [下一小节: 运行选项]
PF提供了许多方法可以让规则集简化, 一些好的范例是通过使用macro(宏)和list(列表), 另外规则集的语言或语法也提供了一些简便方法使创建规则集更简单。 依据惯例, 规则集越简单就越容易理解和维护。
宏很有用处, 因为它们为硬编码地址、端口号、接口名称等提供了一个 替代方案。一台服务器的IP地址变了吗?没关系, 只需要更新宏;不需要把 时间浪费在调整规则上, 这些规则你已经花了你不少的时间和精力并已经 调整到最理想的状态了。
在PF规则集里有一个惯例是为每一个网络接口定义一个宏。如果一块网卡 需要替换为使用不同驱动的另一块, 例如用一块Intel的网卡换掉原来的3 Com的, 宏可以被更新但过滤功能仍有效。另一个好处是多台机器安装同一个规则集, 不同的机器可能有不同的网卡, 但利用宏定义网络接口可以使规则集的修改工作量降至最低。用宏定义规则集中的变量也是一种推荐的做法, 例如:端口号、IP地址和接口名称等。
# define macros for each network interface IntIF = "dc0" ExtIF = "fxp0" DmzIF = "fxp1"
另一个惯例是用宏定义IP地址或网段。这在IP地址变化时可极大地减少规则集的维护工作量。
# define our networks IntNet = "192.168.0.0/24" ExtAdd = "24.65.13.4" DmzNet = "10.0.0.0/24"
如果内部网络不断膨胀或重新编号到一个不同的IP段, 只需更新一下宏就可以了:
IntNet = "{ 192.168.0.0/24, 192.168.1.0/24 }"
一旦规则集被重新载入, 一切全和从前一样。
我们来看一组比较好的规则, 它用来处理 RFC 1918 定义的内部地址, 这些地址不能暴露在在Interenet上, 否则会有麻烦:
block in quick on tl0 inet from 127.0.0.0/8 to any block in quick on tl0 inet from 192.168.0.0/16 to any block in quick on tl0 inet from 172.16.0.0/12 to any block in quick on tl0 inet from 10.0.0.0/8 to any block out quick on tl0 inet from any to 127.0.0.0/8 block out quick on tl0 inet from any to 192.168.0.0/16 block out quick on tl0 inet from any to 172.16.0.0/12 block out quick on tl0 inet from any to 10.0.0.0/8
现在看一下下面这个简化的:
block in quick on tl0 inet from { 127.0.0.0/8, 192.168.0.0/16, \ 172.16.0.0/12, 10.0.0.0/8 } to any block out quick on tl0 inet from any to { 127.0.0.0/8, \ 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
规则集从8行减少到2行。 当宏和列表结合使用时就更简化了:
NoRouteIPs = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \ 10.0.0.0/8 }"
ExtIF = "tl0" block in quick on $ExtIF from $NoRouteIPs to any block out quick on $ExtIF from any to $NoRouteIPs
注意宏和列表简化了 pf.conf 文件, 但是这些行实际上会被 pfctl(8) 扩展为下面的多条规则:
block in quick on tl0 inet from 127.0.0.0/8 to any block in quick on tl0 inet from 192.168.0.0/16 to any block in quick on tl0 inet from 172.16.0.0/12 to any block in quick on tl0 inet from 10.0.0.0/8 to any block out quick on tl0 inet from any to 10.0.0.0/8 block out quick on tl0 inet from any to 172.16.0.0/12 block out quick on tl0 inet from any to 192.168.0.0/16 block out quick on tl0 inet from any to 127.0.0.0/8
如你所见, PF扩展仅减少了 pf.conf 文件编写及维护的工作量, 但实际上并未简化 pf(4) 的规则处理过程。
宏的应用范围并非仅限于地址或端口; 它们在PF规则文件中随处可见:
pre = "pass in quick on ep0 inet proto tcp from " post = "to any port { 80, 6667 } keep state"
# David's classroom $pre 21.14.24.80 $post
# Nick's home $pre 24.2.74.79 $post $pre 24.2.74.178 $post
扩展为:
pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \ port = 80 pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \ port = 6667 pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \ port = 80 pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \ port = 6667 pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \ port = 80 pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \ port = 6667
PF的语法顺序很灵活, 允许一个相当灵活的规则集。PF能推断出特定的关键字, 这意味着这些关键字无需在规则里明确地规定;并且PF对关键字顺序要求的也不严格, 因此不必去记忆严格的语法。
定义一个“默认拒绝”的策略使用了两行规则:
block in all block out all
上面的规则可精简为:
block
如果没有指定方向, PF会假设这条规则应用在双方向的数据包上。
同样, "from any to any" 和 "all" 等字句也可以在规则中省略, 例如:
block in on rl0 all pass in quick log on rl0 proto tcp from any to any port 22 keep state
可以简化为:
block in on rl0 pass in quick log on rl0 proto tcp to port 22 keep state
第一行在rl0上禁止从anywhere到anywhere的所有进入的数据包, 而第二行在rl0端口22上放行所有进入的TCP通讯。
要阻止数据包和带有TCP RST或ICMP Unreachable这样的回复的规则集可能像这样:
block in all block return-rst in proto tcp all block return-icmp in proto udp all block out all block return-rst out proto tcp all block return-icmp out proto udp all
这些内容可以简化为:
block return
当PF看到 return 关键字时, 它能根据被阻止的数据包的协议巧妙地发送适当的回应, 或者不回应,根据被阻止数据包的协议来确定。
多数情况下可以灵活地组织关键字的顺序。例如, 一条规则:
pass in log quick on rl0 proto tcp to port 22 \ flags S/SA keep state queue ssh label ssh
也可以这样写:
pass in quick log on rl0 proto tcp to port 22 \ queue ssh keep state label ssh flags S/SA
另外, 类似的变化也没问题。
[上一小节: 重定向(端口转发)] [总目录] [下一小节: 运行选项]