- 论坛徽章:
- 0
|
基本配置
PF: 包过滤
------------------------------------------------------------------------------
简介
包过滤是在数据包通过网络接口时进行选择性的运行通过或者阻塞。
标准是源地址和目的地址,源端口和目的端口,以及协议。
过滤规则集指定了数据包在匹配时通过或者阻塞。
规则集由开始到结束顺序执行。除非规则包含 quick关键字,否则数据包在执行前会被检验。
如果数据包和规则集里的所有规则都不匹配,则它会被通过。
规则语法
一般而言,最简单的过滤规则语法是这样的:
action direction [log] [quick] on interface [af] [proto protocol] \
from src_addr [port src_port] to dst_addr [port dst_port] \
[tcp_flags] [state]
action
数据包的动作,放行动作或者阻塞动作。
direction
数据包传递的方向,进或者出
log
指定数据包被pflogd(进行日志记录)。要记录所有的日志,使用log-all
quick
关键字,这条规则被认为最终的匹配规则,指定的动作会立即执行。
interface
数据包通过的网络接口的名称或组。组是接口的名称但没有最后的整数。比如ppp,会使得规则匹配任何ppp接口上的任意数据包。
af
数据包的地址类型,inet代表Ipv4,inet6代表Ipv6。通常PF能够自动确定这个参数。
protocol
数据包的4层协议: ^-^ (参见pf中文手册)
src_addr, dst_addr ^-^ (参见pf中文手册)
IP头中的源/目标地址。
src_port, dst_port ^-^ (参见pf中文手册)
4层数据包头中的源/目标端口。
tcp_flags
指定使用TCP协议时TCP头中必须设定的标记。例如: flags S/SA -这指引PF只检查S和A(SYN and ACK)标记,如果SYN标记是“on”则匹配。
state
状态信息匹配时是否保持。
+ keep state - 对 TCP, UDP, ICMP起作用
+ modulate state - 只对 TCP起作用
+ synproxy state - 代理
默认拒绝
先拒绝所有,然后有选择的允许某些通过防火墙。
默认拒绝的过滤规则,开始2行必须是:
block in all
block out all
这会阻塞所有流量(包括任何协议,源/目的地址,任意接口)。
通过流量
流量必须被明确的允许通过或丢弃。也只有已经设计好的流量可以被允许通过。
实例:
# 允许本地网络192.168.0.0/24流量通过dc0接口进入,访问openbsd机器的192.168.0.1地址,
# 同时也允许返回的数据包从dc0接口出去。
pass in on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24
quick 关键字
规则指定的动作马上执行。例子:
错误:
block in on fxp0 proto tcp from any to any port ssh
pass in all
在这样的条件下,block行会被检测,但永远也不会有效果,因为它后面的一行允许所有的流量通过。
正确:
block in quick on fxp0 proto tcp from any to any port ssh
pass in all
这个block行被匹配,由于quick选项的原因,数据包会被阻塞,而且剩下的规则也会被忽略。
状态规则
状态检测指PF跟踪或者处理网络连接状态的能力。
状态保持指通过存贮连接的信息到一个状态表中,确定一个通过防火墙的数据包是否属于已经建立的连接。如果是,它会直接通过防火墙而不用再进行规则检验。这样PF用于处理这些数据包的时间大为减少。大幅度提高防火墙的性能。
当一条规则使用了keep state选项,第一个匹配这条规则的数据包在收发双方之间建立了一个状态。现在,不仅发送者到接收者之间跟据这个状态绕过规则检验,而且接收者回复发送者的数据包也是同样的。例如:
pass out on fxp0 proto tcp from any to any keep state
这允许fxp0接口上的任何TCP流量通过,并且允许返回的流量通过防火墙。
状态调整选项,输入连接的初始化序列号(ISN)是随机的,这对于保护某些选择ISN存在问题的操作系统的连接初始化非常有用。
对输出的TCP, UDP, ICMP数据包保持状态,并且调整TCP ISN。
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state
状态保持的另一个优点是ICMP通信流量可以直接通过防火墙。例如,如果一个TCP连接使用了状态保持,当和这个TCP连接相关的ICMP数据包到来时,它会自动找到合适的状态记录,直接通过防火墙。
状态记录的范围被state-policy runtime选项总体控制,也能基于单条规则由if-bound, group-bound, 和 floating state选项关键字设定。例如:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state (if-bound)
为了使数据包匹配状态条目,它们必须通过fxp0网络接口传递。
需要注意的是,nat,binat,rdr规则隐含在过滤规则集审核中产生匹配连接的状态。
UDP状态保持
UDP是无状态的协议。对于没有开始和结束数据包的协议,PF仅简单追踪匹配的数据部通过的时间。如果到达超时限制,状态被清除,超时的时间值可以pf.conf配置文件中设定。
TCP 标记
经常被用于过滤试图打开新连接的TCP数据包。TCP标记和他们的意义如下所列:
* F : FIN - 结束; 结束会话
* S : SYN - 同步; 表示开始会话请求
* R : RST - 复位;中断一个连接
* P : PUSH - 推送; 数据包立即发送
* A : ACK - 应答
* U : URG - 紧急
* E : ECE - 显式拥塞提醒回应
* W : CWR - 拥塞窗口减少
要使PF检查TCP标记,flag关键需按如下语法设置。
flags check/mask
mask部分告诉PF仅检查指定的标记,check部分说明在数据包头中哪个标记设置为“on”才算匹配。
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
带SYN标记的TCP流量仅查看SYN和ACK标记。带有SYN和ECE标记的数据包会匹配上面的规则,而带有SYN和ACK的数据包或者仅带有ACK的数据包不会匹配。
标记常常和状态保持规则联合使用,来控制创建状态条目:
pass out on fxp0 proto tcp all flags S/SA keep state
为所有输出带SYN和ACK标记的数据包中,仅带有SYN标记的TCP数据包创建状态。
一些人建议创建状态“只有当SYN标记设定而没有其他标记”时,这样的规则如下:
. . . flags S/FSRPAUEW 糟糕的主意!!
这个理论是,仅为TCP开始会话时创建状态,会话以SYN标记开始,而没有其他标记。问题在于一些站点使用ECN标记开始会话,而任何使用ECN连接你的会话都会被那样的规则拒绝。比较好的规则是:
. . . flags S/SAFR
这个经过实践是安全的,如果流量进行了整形就没有必要检查FIN和RST标记。整形过程会让PF丢弃带有非法TCP
标记的进入数据包(例如SYN和FIN以及SYN和RST)。强烈推荐总是进行流量整形:
scrub in on fxp0
.
.
.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA \
keep state
TCP SYN 代理
当客户端向服务器初始化一个TCP连接时,PF会在二者直接传递"握手数据包"。这就是代理握手。使用代理握手,PF自动和客户端完成握手,初始化和服务器的握手,然后在二者之间传递数据。这样做的优点是在客户端完成握手之前,没有数据包到达服务器。这样就消沉了TCP SYN FLOOD欺骗影响服务器的问题,因为进行欺骗的客户端不会完成握手。
TCP SYN 代理在规则中使用synproxy state关键字打开。例如:
pass in on $ext_if proto tcp from any to $web_server port www \
flags S/SA synproxy state
这样, web服务器的连接由PF进行TCP代理。它具有keep state 和 modulate state一样的功能。
如果PF工作在桥模式下,SYN代理不会起作用。
阻塞欺骗数据包
地址欺骗是传递的数据包使用虚假地址。他们可以隐蔽真实地址实施网络攻击。
PF通过antispoof关键字提供一些防止地址欺骗的保护。
antispoof [log] [quick] for interface [af]
log
指定匹配的数据包应该被pflogd(8)进行日志记录
quick
如果数据包匹配这条规则,则这是最终的规则,不再进行其他规则集的检查。
interface
激活要进行欺骗保护的网络接口。也可以是接口的列表。
af
激活进行欺骗保护的地址族,inet代表Ipv4,inet6代表Ipv6。
实例:
antispoof for fxp0 inet
任何出现了antispoof关键字的规则都会扩展成2条规则。假定接口fxp0具有ip地址10.0.0.1和子网掩码
255.255.255.0(或者/24),上面的规则会扩展成:
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
这些规则实现下面的2个目的:
* 阻塞任何不是由fxp0接口进入的10.0.0.0/24网络的流量。
* 阻塞任何由10.0.0.1即fxp0接口的IP地址的进入流量。
注意:扩展出来的过滤规则会阻塞loopback接口上发送到本地地址的数据包。这些数据包应该明确的配置为允许通过。例如:
pass quick on lo0 all
antispoof for fxp0 inet
使用antispoof应该仅限于已经分配了IP地址的网络接口,不要在没有分配IP地址的网络接口上使用。
被动操作系统识别
通过基于远端主机TCP SYN数据包中某些特征,进行操作系统被动检测的技术。这些信息可以作为标准在过滤规则中使用。
PF检测远端操作系统,是通过比较TCP SYN数据包中的特征和已知的特征文件对照来确定的,特征文件默认是/etc/pf.os。如果PF起作用,可使用下面的命令查看当前的特征列表。
# pfctl -s osfp
在规则集中,特征可以指定为OS类型,版本,或者子类型/补丁级别。这些条目在上面的pfctl命令中有列表。
要在过滤规则中指定特征,需使用os关键字:
pass in on $ext_if any os OpenBSD keep state
block in on $ext_if any os "Windows 2000"
block in on $ext_if any os "Linux 2.4 ts"
block in on $ext_if any os unknown
系统类型unknow允许匹配操作系统未知的数据包。
注意以下的内容::
*操作系统识别偶尔会出错
* 某些操作系统和特征文件不符,或者符合了另外的操作系统特征。
* OSFP 仅对TCP SYN数据包起作用,它不会对其他协议或者已经建立的连接起作用。
IP 选项
默认情况下,带有IP选项的数据包会被阻塞。使得类似nmap的操作系统识别软件工作困难。如果你的应用程序需要通过这样的数据包,例如多播或者IGMP,你可以使用allow-opts关键字。。
pass in quick on fxp0 all allow-opts
过滤规则实例
下面是过滤规则得实例。运行PF的机器充当防火墙,在一个小的内部网络和因特网之间。只列出了过滤规则,
queueing, nat, rdr,等等没有在实例中列出。
ext_if = "fxp0"
int_if = "dc0"
lan_net = "192.168.0.0/24"
# scrub incoming packets
scrub in all
# setup a default deny policy
block in all
block out all
# pass traffic on the loopback interface in either direction
pass quick on lo0 all
# activate spoofing protection for the internal interface.
antispoof quick for $int_if inet
# only allow ssh connections from the local network if it‘s from the
# trusted computer, 192.168.0.15. use "block return" so that a TCP RST is
# sent to close blocked connections right away. use "quick" so that this
# rule is not overridden by the "pass" rules below.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh flags S/SA
# pass all traffic to and from the local network
pass in on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net
# pass tcp, udp, and icmp out on the external (Internet) interface.
# keep state on udp and icmp and modulate state on tcp.
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state
# allow ssh connections in on the external interface as long as they‘re
# NOT destined for the firewall (i.e., they‘re destined for a machine on
# the local network). log the initial packet so that we can later tell
# who is trying to connect. use the tcp syn proxy to proxy the connection.
pass in log on $ext_if proto tcp from any to { !$ext_if, !$int_if } \
port ssh flags S/SA synproxy state |
|