发新话题
打印

OpenBSD 数据包过滤 PF FAQ中文版(转)-5

OpenBSD 数据包过滤 PF FAQ中文版(转)-5

(续上)


NAT 地址池

地址池在NAT规则中可以被用做转换地址。连接的源地址会被转换成使用指定的方法从地址池中选择的地址。这对于PF负载一个非常大的网络的NAT会非常有用。由于经过NAT的连接对每个地址是有限的,增加附加的转换地址允许NAT网关增大服务的用户数量。

在这个例子中,2个地址被用来做输出数据包的转换地址。对于每一个输出的连接,PF按照顺序循环使用地址。


    nat on $ext_if inet from any to any -> { 192.0.2.5, 192.0.2.10 }

这个方法的一个缺点是成功建立连接的同一个内部地址不会总是转换为同一个外部地址。这会导致冲突,例如:浏览根据用户的ip地址跟踪登录的用户的web站点。一个可选择的替代方法是使用source-hash 方法,以便每一个内部地址总是被转换为同样的外部地址。,要实现这个方法,地址池必须是CIDR网络地址。

    nat on $ext_if inet from any to any -> 192.0.2.4/31 source-hash

这条NAT规则使用地址池192.0.2.4/31 (192.0.2.4 - 192.0.2.5)做为输出数据包的转换地址。每一个内部地址会被转换为同样的外部地址,由于source-hash关键字的缘故。

外来连接负载均衡

地址池也可以用来进行外来连接负载均衡。例如,外来的web服务器连接可以分配到服务器群。

    web_servers = "{ 10.0.0.10, 10.0.0.11, 10.0.0.13 }"

    rdr on $ext_if proto tcp from any to any port 80 -> $web_servers \
        round-robin sticky-address

成功的连接将按照顺序重定向到web服务器,从同一个源到来的连接发送到同一个服务器。这个sticky connection会和指向这个连接的状态一起存在。如果状态过期,sticky
connection也过期。那个主机的更多连接被重定向到按顺序的下一个web服务器。

输出流量负载均衡

地址池可以和route-to过滤选项联合使用,在多路径路由协议(例如BGP4)不可用是负载均衡2个或者多个因特网连接。通过对round-robin地址池使用route-to,输出连接可以平均分配到多个输出路径。

需要收集的附加的信息是邻近的因特网路由器IP地址。这要加入到route-to选项后来控制输入数据包的目的地址。

下面的例子通过2条到因特网的连接平衡输出流量:

    lan_net = "192.168.0.0/24"
    int_if  = "dc0"
    ext_if1 = "fxp0"
    ext_if2 = "fxp1"
    ext_gw1 = "68.146.224.1"
    ext_gw2 = "142.59.76.1"

    pass in on $int_if route-to \
       { ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
       from $lan_net to any keep state

route-to 选项用来在收到流量的内部接口上指定平衡的流量经过各自的网关到输出的网络接口。注意route-to 选项必须在每个需要均衡的过滤规则上出现。返回的数据包会路由到它们出去时的外部接口(这是由ISP做的),然后正常路由回内部网络。

要保证带有属于$ext_if1源地址的数据包总是路由到$ext_gw1($ext_if2 和 $ext_gw2也是同样的),下面2行必须包括在规则集中:

    pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 \
       to any
    pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 \
       to any

最后,NAT也可以使用在输出接口中:

    nat on $ext_if1 from $lan_net to any -> ($ext_if1)
    nat on $ext_if2 from $lan_net to any -> ($ext_if2)

一个完整的输出负载均衡的例子应该是这个样子:

lan_net = "192.168.0.0/24"
int_if  = "dc0"
ext_if1 = "fxp0"
ext_if2 = "fxp1"
ext_gw1 = "68.146.224.1"
ext_gw2 = "142.59.76.1"

#  nat outgoing connections on each internet interface
nat on $ext_if1 from $lan_net to any -> ($ext_if1)
nat on $ext_if2 from $lan_net to any -> ($ext_if2)

#  default deny
block in  from any to any
block out from any to any

#  pass all outgoing packets on internal interface
pass out on $int_if from any to $lan_net
#  pass in quick any packets destined for the gateway itself
pass in quick on $int_if from $lan_net to $int_if
#  load balance outgoing tcp traffic from internal network.
pass in on $int_if route-to \
    { ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
    proto tcp from $lan_net to any flags S/SA modulate state
#  load balance outgoing udp and icmp traffic from internal network
pass in on $int_if route-to \
    { ($ext_if1 $ext_gw1), ($ext_if2 $ext_gw2) } round-robin \
    proto { udp, icmp } from $lan_net to any keep state

#  general "pass out" rules for external interfaces
pass out on $ext_if1 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if1 proto { udp, icmp } from any to any keep state
pass out on $ext_if2 proto tcp from any to any flags S/SA modulate state
pass out on $ext_if2 proto { udp, icmp } from any to any keep state

#  route packets from any IPs on $ext_if1 to $ext_gw1 and the same for
#  $ext_if2 and $ext_gw2
pass out on $ext_if1 route-to ($ext_if2 $ext_gw2) from $ext_if2 to any
pass out on $ext_if2 route-to ($ext_if1 $ext_gw1) from $ext_if1 to any

------------------------------------------------------------------------------
$OpenBSD: pools.html,v 1.12 2004/05/07 01:55:24 nick Exp $
==============================================================================

PF: 数据包标记

------------------------------------------------------------------------------

目录

  * 简介
  * 给数据包打标记
  * 检查数据包标记
  * 过滤策略
  * 标记以太网的帧

------------------------------------------------------------------------------

简介
数据包标记是给数据包打内部标记的方法,以后可以在过滤和转换规则中使用。使用标记,有可能做这样的事情,比如在接口间产生信任关系,或者确定数据包是否已经经过了转换规则处理。也可能从基于规则的过滤中移出,开始执行基于策略的过滤。
.

给数据包打标记

要给数据包打标记,使用tag 关键字:

    pass in on $int_if all tag INTERNAL_NET keep state

标记 INTERNAL_NET 会增加到任何匹配上述规则的数据包中。
注意keep state的使用; keep state (或者 modulate state/synproxy state) 在标记数据包通过的规则中使用。

标记也可以通过宏来打,比如:

    name = "INTERNAL_NET"
    pass in on $int_if all tag $name keep state

有一组预先定义的宏也可以被使用。

  * $if – 接口
  * $srcaddr – 源 IP 地址
  * $dstaddr – 目的 IP 地址
  * $srcport – 源端口
  * $dstport – 目的端口
  * $proto – 协议
  * $nr – 规则号

这些宏在规则集装入时扩展,而不是运行时。

标记遵循以下规则:

  * 标记是粘性的。一旦一个标记被匹配的规则打到一个数据包,就不能被删除。但它可以被不同的标记替换。
  * 由于标记的粘性,打了标记的数据包会一直保持,即使所有的规则都没有使用这个标记。
  * 一个数据包一次最多只能打一个标记。
  * 标记是内部标识符,标记不会被送到网上。

看看下面的例子:

    (1) pass in on $int_if tag INT_NET keep state
    (2) pass in quick on $int_if proto tcp to port 80 tag \
            INT_NET_HTTP keep state
    (3) pass in quick on $int_if from 192.168.1.5 keep state

  * 按照规则1,$int_if 接口上收到的数据包会打上INT_NET 标记。
  * $int_if 接口上收到的目标端口80的数据包根据规则1首先打上INT_NET 标记,然后根据规则2,被INT_NET_HTTP 标记替代。
  * $int_if 接口上收到的来自192.168.1.5的数据包根据规则3会方向,由于这是最终匹配规则,因此如果它们的目标端口是80,则标记是INT_NET_HTTP ,否则标记是INT_NET 。

标记除了适用于过滤规则以外, nat, rdr, binat转换规则也可以用tag关键字使用标记。

检查数据包标记

要检查先前已经打的标记,可以使用tagged关键字:

    pass out on $ext_if tagged INT_NET keep state

在$ext_if输出的数据包为了匹配上述规则必须打上INT_NET标记。反转匹配也可以使用!操作:  

    pass out on $ext_if tagged ! WIFI_NET keep state

策略过滤

过滤策略提供了编写过滤规则集的不同方法。定义的策略设定规则,说明哪种流量放行,哪种流量阻塞。数据包被基于传统的标准如源/目的IP地址,协议等等分配到不同的策略。例如,检查下面的防火墙策略:

  * 自内部LAN到DMZ的流量是允许的 (LAN_DMZ)。
  * 自因特网到DMZ的服务器流量是允许的。 (INET_DMZ)
  * 自因特网被重定向到spamd(8)是允许的 (SPAMD)
  * 其他所有流量阻塞。

注意策略是如何覆盖所有通过防火墙的流量的。括号里面的项目指示这个策略项目将使用的标记。

需要过滤和转换规则来把数据包分配到不同的策略。

    rdr on $ext_if proto tcp from <spamd> to port smtp \
       tag SPAMD -> 127.0.0.1 port 8025

    block all
    pass in on $int_if from $int_net tag LAN_INET keep state
    pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
    pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep
    state

现在要设置定义策略的规则。

    pass in  quick on $ext_if tagged SPAMD keep state
    pass out quick on $ext_if tagged LAN_INET keep state
    pass out quick on $dmz_if tagged LAN_DMZ keep state
    pass out quick on $dmz_if tagged INET_DMZ keep state

现在要建立整个规则集,修改分类规则。例如,如果pop3/SMTP服务器增加到了DMZ区,就需要增加针对POP3和SMTP流量的分类,如下:

    mail_server = "192.168.0.10"
    ...
    pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
       tag INET_DMZ keep state

Email 流量会作为INET-DMZ策略的条目被放行。t
完整的规则:

# macros
int_if  = "dc0"
dmz_if  = "dc1"
ext_if  = "ep0"
int_net = "10.0.0.0/24"
dmz_net = "192.168.0.0/24"
www_server = "192.168.0.5"
mail_server = "192.168.0.10"

table <spamd> persist file "/etc/spammers"

# classification -- classify packets based on the defined firewall
# policy.
rdr on $ext_if proto tcp from <spamd> to port smtp \
    tag SPAMD -> 127.0.0.1 port 8025

block all
pass in on $int_if from $int_net tag LAN_INET keep state
pass in on $int_if from $int_net to $dmz_net tag LAN_DMZ keep state
pass in on $ext_if proto tcp to $www_server port 80 tag INET_DMZ keep state
pass in on $ext_if proto tcp to $mail_server port { smtp, pop3 } \
    tag INET_DMZ keep state

# policy enforcement -- pass/block based on the defined firewall policy.
pass in  quick on $ext_if tagged SPAMD keep state
pass out quick on $ext_if tagged LAN_INET keep state
pass out quick on $dmz_if tagged LAN_DMZ keep state
pass out quick on $dmz_if tagged INET_DMZ keep state

标记以太网帧

打标记可以在以太网级别进行,如果执行标记/过滤的机器同时做为网桥。通过创建使用tag关键字的网桥过滤规则,PF可以建立基于源/目的MAC地址的过滤规则。网桥规则可以由brconfig(8)命令产生,例如:

    # brconfig bridge0 rule pass in on fxp0 src 0:de:ad:be:ef:0 \
       tag USER1

然后在 pf.conf文件中:

    pass in on fxp0 tagged USER1

------------------------------------------------------------------------------
$OpenBSD: tagging.html,v 1.4 2004/05/07 01:55:24 nick Exp $
==============================================================================
* 附加主题


PF: 日志

------------------------------------------------------------------------------

目录

  * 简介
  * 读取日志文件
  * 导出日志
  * 通过Syslog记录日志

------------------------------------------------------------------------------

简介

PF的包日志是由pflogd(8)完成的,它通过监听pflog0接口然后将包以tcpdump(8)二进制格式写入日志文件(一般在/val/log/pflog)。过滤规则定义的日志和log-all关键字所定义的日志都是以这种方式记录的。

读取日志文件

由pflogd生成的二进制格式日志文件不能通过文本编辑器读取,必须使用Tcpdump来查看日志。

使用如下格式查看日志信息:

    # tcpdump -n -e -ttt -r /var/log/pflog

使用tcpdump(8)查看日志文件并不是实时的,若要实时查询日志信息需加上pflog0参数:

    # tcpdump -n -e -ttt -i pflog0

注意:当查看日志时需要特别注意tcpdump的详细协议解码(通过在命令行增加-v参数实现)。
Tcpdump的详细协议解码器并不具备完美的安全历史,至少在理论上是这样。日志记录设备所记载的部分包信息可能会引发延时攻击,因此推荐在查询日志文件信息之前先将该日志文件从防火墙上移走。

另外需要注意的是对日志文件的安全访问。默认情况下,pflogd 将在日志文件中记录96字节的包信息。访问日志文件将提供访问部分敏感包信息的途径(就像telnet(1)或者ftp(1)的用户名和密码)。

导出日志

由于pflogd以tcpdump二进制格式记录日志信息,因此当回顾这些日志时可以使用tcpdump的很多特点。例如,只查看与特定端口匹配的包:

    # tcpdump -n -e -ttt -r /var/log/pflog port 80

甚至可以限定具体的主机和端口:

    # tcpdump -n -e -ttt -r /var/log/pflog port 80 and host 192.168.1.3

同样的方法可以应用到直接从pflog0接口读取的信息:

    # tcpdump -n -e -ttt -i pflog0 host 192.168.4.2

注意这与包被记录到pflogd日志文件不相冲突;上述语句只以包被记录的形式显示。

除了使用标准的tcpdump(8)过滤规则外,OpenBSD的tcpdump过滤语言为读取pflogd而被扩展:

  * ip –IPv4版本地址。
  * ip6 - IPv6版本地址。
  * on int – 包通过int接口。
  * ifname int – 与 on int相同.
  * rulenum num – 包匹配的过滤规则编号为num。
  * action act – 对包的操作。可能是pass(通过)或者block(阻断)。
  * reason res – 执行对包操作的原因。可能的原因是match(匹配), bad-offset, fragment, short, normalize(规格化), memory(内存)。
  * inbound –入栈包。

举例:

    # tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0

这将以实时方式显示被wi0接口阻断的入栈包的日志信息。

通过Syslog记录日志

很多情况下需要将防火墙的日志记录以ASCII代码格式存储,或者(同时)把这些日志存到远程的日志服务器上。这些可以通过两个小的脚本文件实现,是对openbsd配置文件和syslogd(8),日志守护进程的少许修改。Syslogd进程以ASCII格式存储日志,同时可以将日志存储到远程日志服务器。  

首先我们必须建立一个用户,pflogger,使用 /sbin/nologin shell.最简单的建立用户的方法是使用adduser(8)。

完成后建立如下两个脚本:

/etc/pflogrotate
        FILE=/home/pflogger/pflog5min.$(date "+%Y%m%d%H%M")
        kill -ALRM $(cat /var/run/pflogd.pid)
        if [ $(ls -l /var/log/pflog | cut -d " " -f 8) -gt 24 ]; then
           mv /var/log/pflog $FILE
           chown pflogger $FILE
           kill -HUP $(cat /var/run/pflogd.pid)
        fi

/home/pflogger/pfl2sysl
        for logfile in /home/pflogger/pflog5min* ; do
           tcpdump -n -e -ttt -r $logfile | logger -t pf -p local0.info
           rm $logfile
        done

编辑root的cron 任务:
  
    # crontab -u root -e

增加如下两行:

    # rotate pf log file every 5 minutes
    0-59/5 * * * * /bin/sh /etc/pflogrotate

为用户pflogger建立一个cron任务:

    # crontab -u pflogger -e

增加如下两行:

    # feed rotated pflog file(s) to syslog
    0-59/5 * * * * /bin/sh /home/pflogger/pfl2sysl

将下行增加到 /etc/syslog.conf:

    local0.info     /var/log/pflog.txt

如果需要日志记录到远程日志服务器,增加:
  
    local0.info     @syslogger

确定主机syslogger已在hosts(5)中定义。

建立文件 /var/log/pflog.txt 使 syslog 可以向该文件写入日志:

    # touch /var/log/pflog.txt

重启syslogd使变化生效:

    # kill -HUP $(cat /var/run/syslog.pid)

所有符合标准的包将被写入/var/log/pflog.txt. 如果增加了第二行,这些信息也将被存入远程日志服务器syslogger。

脚本 /etc/pflogrotate 将执行,然后删除 /var/log/pflog ,因此
rotation of pflog by newsyslog(8) 不再必需可以被禁用。然而, /var/log/pflog.txt 替代 /var/log/pflog and rotation of it 要被启用。 改变 /etc/newsyslog.conf 如下:

    #/var/log/pflog       600    3    250    *    ZB /var/run/pflogd.pid
    /var/log/pflog.txt    600    7    *      24

PF 将日志以ASCII格式记录到/var/log/pflog.txt. 如果这样配置 /etc/syslog.conf, 系统将把日志存到远程服务器。存储过程不会马上发生,但是会在符合条件的包出现在文件中前5-6分钟实现。
------------------------------------------------------------------------------
$OpenBSD: logging.html,v 1.15 2004/05/07 01:55:23 nick Exp $
==============================================================================

PF: 性能

------------------------------------------------------------------------------

“PF可以处理多少带宽?”
“我需要多少台计算机处理因特网连接?”
  
这个问题没有简单的答案。对于一些应用程序来说,一台486/66主机,带有2个比较好的ISA网卡在做过滤和NAT时接近5Mbps,但是对于其他应用程序,一个更快的计算机加上更有效的PCI网卡也会显得能力不足。真正的问题不是每秒处理的位数而是每秒处理的包数和规则集的复杂程度。

体现PF性能的几个参数:

  * 每秒处理包的数量. 一个1500字节的包和一个只有1个字节的包所需要的处理过程的数目几乎是一样的。每秒处理包的数量标志着状态表和过滤规则集在每秒内被评估的次数 ,标志着一个系统最有效的需求(在没有匹配的情况下)。
  * 系统总线性能. ISA 总线最大带宽 8MB/秒, 当处理器访问它时, 它必须降速到80286的有效速度,不管处理器的真实处理速度如何,PCI总线有更有效的带宽,与处理器的冲突更小。
  * 网卡的效率. 一些网卡的工作效率要高于其他网卡。 基于Realtek 8139 (rl(4)) 的网卡性能较低,而基于Intel 21143 (dc(4)) 的网卡性能较好。 为了取得更好的性能,建议使用千兆网卡,尽管所连接的网络不是千兆网,这些千兆网卡拥有高级的缓存,可以大幅提高性能。   
* 规则集的设计和复杂性。规则越复杂越慢。越多的包通过keep和quick方式过滤,性能越好。对每个包的策略越多,性能越差。
  * 值得一提: CPU 和内存。由于PF是基于内核的进程,它不需要swap空间。所以,如果你有足够的内存,它将运行很好,如果没有,将受影响。不需要太大量的内存。 32MB内存对小型办公室或者家庭应用足够,300MHz的cpu如果配置好网卡和规则集,足够满足要求。  

人们经常询问PF的基准点。唯一的基准是在一个环境下系统的性能。不考虑环境因素将影响所设计的防火墙的系统性能。  

PF 曾经在非常大流量的系统中工作,同时PF的开发者也是它的忠实用户。

------------------------------------------------------------------------------
$OpenBSD: perf.html,v 1.14 2004/05/07 01:55:24 nick Exp $
==============================================================================

PF: 研究 FTP

------------------------------------------------------------------------------

目录

  * FTP 模式
  * 工作在防火墙之后的FTP客户端
  * PF "自保护" FTP服务器
  * 被运行NAT的外部PF防火墙所保护的FTP服务器
  * FTP的更多信息

------------------------------------------------------------------------------

FTP 模式

FTP是一种协议,它可以追溯到因特网发展初期,那时的因特网规模小,联网的计算机彼此友好,过滤和严格安全性在那时不是必须的。FTP设计之初就没有考虑包过滤、穿透防火墙和NAT。

FTP的工作模式分为被动(passive)和主动(active)两种。通常这两种选择被用来确定哪边有防火墙问题。实际上,为了方便用户你应该全部支持这两种模式。

在active模式下,当用户访问远程FTP服务器并请求一个文件信息时,那台FTP服务器将与该用户建立一个新的连接用来传输请求的数据,这被称为数据连接。具体过程为:客户端随机选择一个端口号,在该端口监听的同时将端口号传给服务器,由服务器向客户端的该端口发起连接请求,然后传递数据。在NAT后的用户访问FTP服务器的时候会出现问题,由于NAT的工作机制,服务器将向NAT网关的外部地址的所选端口发起连接,NAT网关收到该信息后将在自己的状态表中查找该端口对应的内部主机,由于状态表中不存在这样的记录,因此该包被丢弃,导致无法建立连接。

在passive模式下(OpenBSD的ftp客户端默认模式),由客户端请求服务器随机选择一个端口并在此端口监听,服务器通知客户端它所选择的端口号,等待客户端连接。不幸的是,ftp服务器前的防火墙可能会阻断客户端发往服务器的请求信息。OpenBSD的ftp(1)默认使用passive模式;要强制改为active模式,使用-A参数,或者在“ftp>”提示符下使用命令“passive off”关闭passive模式。

工作在防火墙之后的FTP客户端

如前所述,FTP对NAT和防火墙支持不好。

包过滤机制通过将FTP数据包重定向到一个FTP代理服务器解决这一问题。这一过程将引导FTP数据包通过NAT网关/防火墙。OpenBSD和PF使用的FTP代理是ftp-proxy(8),可以通过在pf.conf中的NAT章节增加下列信息激活该代理:

    rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \
       port 8021

这条语句的解释为:在内部接口上的ftp数据包被重定向到本机的8021端口

显然该代理服务器应该已在OpenBSD中启动并运行。配置方法为在/etc/inetd.conf中增加下列信息:

    127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy \
       ftp-proxy

重启系统或者通过下列命令发送一个‘HUP’标记来生效:

    kill -HUP `cat /var/run/inetd.pid`

ftp代理在8021端口监听,上面的rdr语句也是将数据包转发到这一端口。这一端口号是可选的,因为8021端口没有被其他应用程序占用,因此不失为一个好的选择。

请注意ftp-proxy(8)是用来帮助位于PF过滤器后的ftp客户端传递信息;并不用于PF过滤器后的ftp服务器。

PF“自保护”FTP服务器

当PF运行在一个FTP服务器上,而不是单独的一台防火墙。这种情况下处理passive模式的FTP连接请求时FTP服务器将随机取一个较大的TCP端口接收数据。默认情况下OpenBSD的本地FTP服务器ftpd(8)使用49152~65535范围内的端口,显然,必须要有对应的过滤规则放行这些端口的数据:


(待续)

TOP

发新话题