--------------------------------------------------------------------------------
目录
介绍
使用宏
使用列表
PF语法
精简关键字
简化Return
关键字
--------------------------------------------------------------------------------
介绍
PF提供了许多方法可以让规则集简化, 一些好的范例是通过使用宏和列表, 另外规则集的语言或语法也提供了一些捷径使创建规则集更简单。依据惯例, 规则集越简单就越容易理解和维护。
使用宏
宏很有用处, 因为它们为硬编码地址、端口号、接口名称等提供了一个替代方案。一台服务器的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 keep state
pass in quick on ep0 inet proto tcp from 21.14.24.80 to any \
port = 6667 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \
port = 80 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.79 to any \
port = 6667 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \
port = 80 keep state
pass in quick on ep0 inet proto tcp from 24.2.74.178 to any \
port = 6667 keep state
PF语法
PF的语法顺序很灵活, 允许定义一个轻灵的规则集。 PF能推断出确定的关键字, 这意味着这些关键字无需在规则里明确地规定;并且PF对关键字顺序要求的也不严格, 因此不必去记忆严格的语法。
精简关键字
定义一个“默认拒绝”的策略使用了两行规则:
代码: 全选
block in all
block out all
上面的规则可精简为:
代码: 全选
block all
如果没有指定方向, 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通讯。
简化Return
用来阻止数据包和带有TCP RST或ICMP不可到达回复的规则集可能像这样:
代码: 全选
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
另外, 类似的变化也没问题。