发信人: drillwater(灌水)
整理人: sungang(2004-11-15 10:15:02), 站内信件
|
(续)
这个经过实践是安全的,如果流量进行了整形也没有必要检查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具有这样的能力,就是代理握手。使用握手代理,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代理。
由于synproxy state工作的方式,它具有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.0/24的网络是在fxp0接口,具有这样的源网络地址的数据包绝不应该从其他接口上出现。
* 阻塞任何由10.0.0.1即fxp0接口的IP地址的进入流量。主机绝对不会通过外面的接口给自己发送数据包,因此任何进入的流量源中带有主机自己的IP地址都可以认为是恶意的!
注意:antispoof规则扩展出来的过滤规则会阻塞loopback接口上发送到本地地址的数据包。这些数据包应该明确的配置为允许通过。例如:
pass quick on lo0 all
antispoof for fxp0 inet
使用antispoof应该仅限于已经分配了IP地址的网络接口,如果在没有分配IP地址的网络接口上使用,过滤规则会扩展成:
block drop in on ! fxp0 inet all
block drop in inet all
这样的规则会存在阻塞所有接口上进入的所有流量的危险。
被动操作系统识别
被动操作系统识别是通过基于远端主机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 选项
默认情况下,PF阻塞带有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
------------------------------------------------------------------------------
$OpenBSD: filter.html,v 1.20 2004/05/07 01:55:23 nick Exp $
==============================================================================
PF: 网络地址转换(NAT)
------------------------------------------------------------------------------
目录
* 简介
* NAT 如何工作
* NAT 和包过滤
* IP 转发
* 配置 NAT
* 双向映射 (1:1 映射)
* Translation Rule Exceptions
* 检查 NAT 状态
------------------------------------------------------------------------------
简介
网络地址转换是映射整个网络(或者多个网络)到单个IP地址的方法。当你的ISP分配给你的IP地址数目少于你要连上互联网的计算机数目时,NAT是必需的。NAT在RFC1631中描述。
NAT允许使用RFC1918中定义的保留地址族。典型情况下,你的内部网络可以下面的地址族:
10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
192.168.0.0/16 (192.168.0.0 - 192.168.255.255)
担任NAT任务的openbsd系统必须至少要2块网卡,一块连接到因特网,另一块连接内部网络。NAT会转换内部网络的所有请求,使它们看起来象是来自进行NAT工作的openbsd主机系统。
NAT如何工作
当内部网络的一个客户端连接因特网上的主机时,它发送目的是那台主机的IP数据包。这些数据包包含了达到连接目的的所有信息。NAT的作用和这些信息相关。
* 源 IP 地址 (例如, 192.168.1.35)
* 源 TCP 或者 UDP 端口 (例如, 2132)
当数据包通过NAT网关时,它们会被修改,使得数据包看起来象是从NAT网关自己发出的。NAT网关会在它的状态表中记录这个改变,以便:a)将返回的数据包反向转换和b)确保返回的数据包能通过防火墙而不会被阻塞。例如,会发生下面的改变:
* 源 IP: 被网关的外部地址所替换(例如, 24.5.0.5)
* 源端口:被随机选择的网关没有在用的端口替换 (例如, 53136)
内部主机和因特网上的主机都不会意识到发生了这个转变步骤。对于内部主机,NAT系统仅仅是个因特网网关,对于因特网上的主机,数据包看起来直接来自NAT系统,它完全不会意识到内部工作站的存在。
当因特网网上的主机回应内部主机的数据包时,它会使用NAT网关机器的外部地址和转换后的端口。然后NAT网关会查询状态表来确定返回的数据包是否匹配某个已经建立的连接。基于IP地址和端口的联合找到唯一匹配的记录告诉PF这个返回的数据包属于内部主机192.168.1.35。然后PF会进行和出去的数据包相反的转换过程,将返回的数据包传递给内部主机。
ICMP数据包的转换也是类似的,只是不进行源端口的修改。
NAT和包过滤
注意:转换后的数据包仍然会通过过滤引擎,根据定义的过滤规则进行阻塞或者通过。唯一的例外是如果nat规则中使用了pass关键字,会使得经过nat的数据包直接通过过滤引擎。
还要注意由于转换是在过滤之前进行,过滤引擎所看到的是上面“nat如何工作”中所说的经过转换后的ip地址和端口的数据包。
IP 转发
由于NAT经常在路由器和网关上使用,因此IP转发是需要的,使得数据包可以在openbsd机器的不同网络接口间传递。IP转发可以通过sysctl(3)命令打开:
# sysctl -w net.inet.ip.forwarding=1
# sysctl -w net.inet6.ip6.forwarding=1 (if using IPv6)
要使这个变化永久生效,可以增加如下行到/etc/sysctl.conf文件中:
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
这些行是本来就存在的,但默认安装中被#前缀注释掉了。删除#,保存文件,IP转发在机器重启后就会发生作用。
配置NAT
一般的NAT规则格式在pf.conf文件中是这个样子:
nat [pass] on interface [af] from src_addr [port src_port] to \
dst_addr [port dst_port] -> ext_addr [pool_type] [static-port]
nat
开始NAT规则的关键字。
pass
使得转换后的数据包完全绕过过滤规则。
interface
进行数据包转换的网络接口。
af
地址类型,inet代表Ipv4,inet6代表Ipv6。PF通常能根据源/目标地址自动确定这个参数。
src_addr
被进行转换的IP头中的源(内部)地址。源地址可以指定为:
+ 单个的Ipv4或者Ipv6地址.
+ CIDR 网络地址.
+ 能够在规则集载入时通过DNS解析到的合法的域名,IP地址会替代规则中的域名。
+ 网络接口名称。网络接口上配置的所有ip地址会替代进规则中。
+ 带有/掩码(例如/24)的网络接口的名称。每个根据掩码确定的CIDR网络地址都会被替代进规则中。.
+ 带有()的网络接口名称。这告诉PF如果网络接口的IP地址改变了,就更新规则集。这个对于使用DHCP或者拨号来获得IP地址的接口特别有用,IP地址改变时不需要重新载入规则集。
+ 带有如下的修饰词的网络接口名称:
o :network – 替代CIDR网络地址段 (例如, 192.168.0.0/24)
o :broadcast – 替代网络广播地址(例如, 192.168.0.255)
o :peer – 替代点到点链路上的ip地址。
另外,:0修饰词可以附加到接口名称或者上面的修饰词后面指示PF在替代时不包括网络接口的其余附加(alias)地址。这些修饰词也可以在接口名称在括号()内时使用。例如:fxp0:network:0
+ 表.
+ 上面的所有项但使用!(非)修饰词
+ 使用列表的一系列地址.
+ 关键字 any 代表所有地址
+ 关键字 all 是 from any to any的缩写。
src_port
4层数据包头中的源端口。端口可以指定为:
+ 1 到 65535之间的整数
+ /etc/services中的合法服务名称
+ 使用列表的一系列端口
+ 一个范围:
o != (不等于)
o < (小于)
o > (大于)
o <= (小于等于)
o >= (大于等于)
o >< (范围)
o <> (反转范围)
最后2个是二元操作符(他们需要2个参数),在范围内不包括参数。
o : (inclusive range)
inclusive range 也是二元操作符但范围内包括参数。
Port选项在NAT规则中通常不使用,因为目标通常会NAT所有的流量而不过端口是否在使用。
dst_addr
被转换数据包中的目的地址。目的地址类型和源地址相似。
dst_port
4层数据包头中的目的目的端口,目的端口类型和源端口类型相似。
ext_addr
NAT网关上数据包被转换后的外部地址。外部地址可以是:
+ 单个的Ipv4或者Ipv6地址.
+ CIDR 网络地址.
+ 能够在规则集载入时通过DNS解析到的合法的域名,IP地址会替代规则中的域名。
+ 网络接口名称。网络接口上配置的所有ip地址会替代进规则中。
+ 带有/掩码(例如/24)的网络接口的名称。每个根据掩码确定的CIDR网络地址都会被替代进规则中。.
+ 带有()的网络接口名称。这告诉PF如果网络接口的IP地址改变了,就更新规则集。这个对于使用DHCP或者拨号来获得IP地址的接口特别有用,IP地址改变时不需要重新载入规则集。
+ 带有如下的修饰词的网络接口名称:
o :network – 替代CIDR网络地址段 (例如, 192.168.0.0/24)
o :broadcast – 替代网络广播地址(例如, 192.168.0.255)
o :peer – 替代点到点链路上的ip地址。
另外,:0修饰词可以附加到接口名称或者上面的修饰词后面指示PF在替代时不包括网络接口的其余附加(alias)地址。这些修饰词也可以在接口名称在括号()内时使用。例如:fxp0:network:0
+ 使用列表的一系列地址.
pool_type
指定转换后的地址池的类型
static-port
告诉PF不要转换TCP和UDP数据包中的源端口
这条规则最简单的形式如下:
nat on tl0 from 192.168.1.0/24 to any -> 24.5.0.5
这条规则是说对从tl0网络接口上到来的所有192.168.1.0/24网络的数据包进行NAT,将源地址转换为24.5.0.5。
尽管上面的规则是正确的,但却不是推荐的形式。因为维护起来有困难,当内部或者外部网络有变化时都要修改这一行。比较一下下面这条比较容易维护的规则:(tl0时外部,dc0是内部):
nat on tl0 from dc0:network to any -> tl0
优点是相当明显的,你可以任意改变2个接口的IP地址而不用改变这条规则。
象上面这样在地址转换中使用接口名称时,IP地址在pf.conf文件载入时确定,并不是凭空的。如果你使用DHCP还配置外部地址,这会存在问题。如果你分配的IP地址改变了,NAT仍然会使用旧的IP地址转换出去的数据包。这会导致对外的连接停止工作。为解决这个问题,应该给接口名称加上括号,告诉PF自动更新转换地址。
nat on tl0 from dc0:network to any -> (tl0)
这个方法对IPv4 和 IPv6地址都用效。
双向映射 (1:1 映射)
双向映射可以通过使用binat规则建立。Binat规则建立一个内部地址和外部地址一对一的映射。这会很有用,比如,使用独立的外部IP地址用内部网络里的机器提供web服务。从因特网到来连接外部地址的请求被转换到内部地址,同时由(内部)web服务器发起的连接(例如DNS查询)被转换为外部地址。和NAT规则不过,binat规则中的tcp和udp端口不会被修改。
例如:
web_serv_int = "192.168.1.100"
web_serv_ext = "24.5.0.6"
binat on tl0 from $web_serv_int to any -> $web_serv_ext
转换规则例外设置
使用no关键字可以在转换规则中设置例外。例如,如果上面的转换规则修改成这样:
no nat on tl0 from 192.168.1.10 to any
nat on tl0 from 192.168.1.0/24 to any -> 24.2.74.79
则除了192.168.1.10以外,整个192.168.1.0/24网络地址的数据包都会转换为外部地址24.2.74.79。
注意第一条匹配的规则起了决定作用,如果是匹配有no的规则,数据包不会被转换。No关键字也可以在binat和rdr规则中使用。
检查 NAT 状态
要检查活动的NAT转换可以使用pfctl(8)带-s state 选项。这个选项列出所有当前的NAT会话。
# pfctl -s state
fxp0 TCP 192.168.1.35:2132 -> 24.5.0.5:53136 -> 65.42.33.245:22 TIME_WAIT:TIME_WAIT
fxp0 UDP 192.168.1.35:2491 -> 24.5.0.5:60527 -> 24.2.68.33:53 MULTIPLE:SINGLE
解释 (对第一行):
fxp0
显示状态绑定的接口。如果状态是浮动的,会出现self字样。
TCP
连接使用的协议。
192.168.1.35:2132
内部网络中机器的IP地址 (192.168.1.35),源端口(2132)在地址后显示,这个也是被替换的IP头中的地址。 of the machine on the internal network. The
source port (2132) is shown after the address. This is also the address
that is replaced in the IP header.
24.5.0.5:53136
IP 地址 (24.5.0.5) 和端口 (53136) 是网关上数据包被转换后的地址和端口。
65.42.33.245:22
IP 地址 (65.42.33.245) 和端口 (22) 是内部机器要连接的地址和端口。
TIME_WAIT:TIME_WAIT
这表明PF认为的目前这个TCP连接的状态。
------------------------------------------------------------------------------
$OpenBSD: nat.html,v 1.15 2004/05/07 01:55:23 nick Exp $
==============================================================================
PF: 重定向 (端口转发)
------------------------------------------------------------------------------
目录
* 简介
* 重定向和包过滤
* 安全隐患
* 重定向和反射
+ 水平分割 DNS
+ 将服务器移到独立的本地网络
+ TCP 代理
+ RDR 和 NAT 结合
------------------------------------------------------------------------------
简介
如果在办公地点应用了NAT,内部网所有的机器都可以访问因特网。但如何让NAT网关后面的机器能够被从外部访问?这就是重定向的来源。重定向允许外来的流量发送到NAT网关后面的机器。
看个例子:
rdr on tl0 proto tcp from any to any port 80 -> 192.168.1.20
这一行重定向了TCP端口80(web服务器)流量到内部网络地址192.168.1.20。因此,即使192.168.1.20在网关后面的内部网络,外部仍然能够访问它。
上面rdr行中from any to any部分非常有用。如果你明确知道哪些地址或者子网被允许访问web服务器的80端口,你可以在这部分严格限制:
rdr on tl0 proto tcp from 27.146.49.0/24 to any port 80 -> \
192.168.1.20
这样只会重定向指定的子网。注意这表明可以重定向外部不同的访问主机到网关后面不同的机器上。这非常有用。例如,如果你知道远端的用户连接上来时使用的IP地址,你可以让他们使用网关的IP地址和端口访问他们各自的桌面计算机。
rdr on tl0 proto tcp from 27.146.49.14 to any port 80 -> \
192.168.1.20
rdr on tl0 proto tcp from 16.114.4.89 to any port 80 -> \
192.168.1.22
rdr on tl0 proto tcp from 24.2.74.178 to any port 80 -> \
192.168.1.23
重定向和包过滤
注意:转换后的数据包仍然会通过过滤引擎,根据定义的过滤规则进行阻塞或者通过。唯一的例外是如果rdr规则中使用了pass关键字,会使得重定向的数据包直接通过过滤引擎。
还要注意由于转换是在过滤之前进行,过滤引擎所看到的是在匹配rdr规则经过转换后的目标ip地址和端口的数据包。
* 192.0.2.1 – 因特网上的主机
* 24.65.1.13 – openbsd路由器的外部地址
* 192.168.1.5 – web服务器的内部IP地址
重定向规则:
rdr on tl0 proto tcp from 192.0.2.1 to 24.65.1.13 port 80 \
-> 192.168.1.5 port 8000
数据包在经过rdr规则前的模样:
* 源地址: 192.0.2.1
* 源端口: 4028 (由操作系统任意选择)
* 目的地址: 24.65.1.13
* 目的端口: 80
数据包经过rdr规则后的模样:
* 源地址: 192.0.2.1
* 源端口: 4028
* 目的地址: 192.168.1.5
* 目的: 8000
过滤引擎看见的IP数据包时转换发生之后的情况。
安全隐患
重定向确实存在安全隐患。在防火墙上开了一个允许流量进入内部网络的洞,被保护的网络安全潜在的受到了威胁!例如,如果流量被转发到了内部的web服务器,而web服务器上允许的守护程序或者CGI脚本程序存在漏洞,则这台服务器存在会被因特网网上的入侵者攻击危险。如果入侵者控制了这台机器,就有了进入内部网络的通道,仅仅是因为这种流量是允许通过防火墙的。
这种风险可以通过将允许外部网络访问的系统限制在一个单独的网段中来减小。这个网段通常也被称为非军事化区域(DMZ)或者私有服务网络(PSN)。通过这个方法,如果web服务器被控制,通过严格的过滤进出DMZ/PSN的流量,受影响的系统仅限于DMZ/PSN网段。
重定向和反射
通常,重定向规则是用来将因特网上到来的连接转发到一个内部网络或者局域网的私有地址。例如:
server = 192.168.1.40
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $server \
port 80
但是,当一个重定向规则被从局域网上的客户端进行测试时,它不会正常工作。这是因为重定向规则仅适用于通过指定端口($ext_if,外部接口,在上面的例子中)的数据包。从局域网上的主机连接防火墙的外部地址,并不意味着数据包会实际的通过外部接口。防火墙上的TCP/IP栈会把到来的数据包的目的地址在通过内部接口时与它自己的IP地址或者别名进行对比检测。那样的数据包不会真的通过外部接口,栈在任何情况下也不会建立那样的通道。因而,PF永远也不会在外部接口上看到那些数据包,过滤规则由于指定了外部接口也不会起作用。
指定第二条针对内部接口的也达不到预想的效果。当本地的客户端连接防火墙的外部地址时,初始化的TCP握手数据包是通过内部接口到达防火墙的。重定向规则确实起作用了,目标地址被替换成了内部服务器,数据包通过内部接口转发到了内部的服务器。但源地址没有进行转换,仍然包含的是本地客户端的IP地址,因此服务器把它的回应直接发送给了客户端。防火墙永远收不到应答不可能返回客户端信息,客户端收到的应答不是来自它期望的源(防火墙)会被丢弃,TCP握手失败,不能建立连接。
当然,局域网里的客户端仍然会希望象外部客户一样透明的访问这台内部服务器。有如下的方法解决这个问题:
水平分割 DNS
存在这样的可能性,即配置DNS服务器使得它回答内部主机的查询和回答外部主机的查询不一样,因此内部客户端在进行名称解析时会收到内部服务器的地址。它们直接连接到内部服务器,防火墙根本不牵扯。这会降低本地流量,因为数据包不会被送到防火墙。
将服务器移到独立的本地网络
增加单独的网络接口卡到防火墙,把本地的服务器从和客户端同一个网段移动到专用的网段(DMZ)可以让本地客户端按照外部重定向连接的方法一样重定向。使用单独的网段有几个优点,包括和保留的内部主机隔离增加了安全性;服务器(我们的案例中可以从因特网访问)一旦被控制,它不能直接存取本地网络因为所有的连接都必须通过防火墙。
(待续)
----
|
|