14.2. 防火墙或者包过滤

回到基础 防火墙

防火墙是计算机设备的一部分,该设备使用硬件和(或者)软件分拣流入和流出的网络数据包(源自或者源于局域网),并且只允许符合预定义条件的包通过。

防火墙是一个过滤网关,并且只对要通过它的数据包有作用。因此,只有在防火墙是这些数据包的唯一路由器的时候才有效。

缺乏标准配置(之前“过程,而非产品”的格言)就缺少交钥匙解决方案。然而,有些工具使配置 netfilter 防火墙更加简单,使用图形显示过滤规则。fwbuilder 无疑是其中的佼佼者。

特例 局部防火墙

防火墙可以应用在个别机器上(相对于整个网络而言),在这些情况中其角色是过滤或限制对一些服务的访问,或阻止用户有意或无意安装的流氓软件对外部的连接。

Linux 内核嵌入了 netfilter 防火墙。可以使用用户空间的 iptablesip6tables 命令控制。这两个命令直接的区别在于前者作用在 IPv4 网络,而后者作用在 IPv6。由于两种网络协议可能在多年内共存,这就需要同时使用两个工具。

14.2.1. Netfilter 行为

netfilter 使用四个截然不同的表存储规则,来规定对数据包的三种操作:

  • filter 关注过滤规则(接受,拒绝或者忽略数据包);

  • nat 关注转化源地址或者目的地址和数据包端口;

  • mangle 关注对 IP 数据包的其他变化(包含 ToS - 服务类型 -区段和选项);

  • raw 允许在到达追踪系统之前手动更改数据包。

每个表都包含称为链(chains)的规则列表。防火墙使用标准链处理预定义环境下的数据包。管理员可以创建其他链,该链只有在被标准链引用(直接或间接)时才会起作用。

过滤 表有三个标准链:

  • 输入:关注目的地是防火墙自身的数据包;

  • 输出:关注防火墙发出的数据包;

  • 转发:关注通过防火墙的数据包(既不是源头也不是目的地)。

nat 表也有三个标准链:

  • 预先路由:一旦数据包到达就修改;

  • 后路由:在准备继续上路时修改数据包;

  • 输出:修改防火墙自身产生的数据包。

netfilter 中的链是如何被调用的

图 14.1. netfilter 中的链是如何被调用的

每个链是一个规则列表;每个规则是条件集合以及符合条件时要采取的行动。当处理数据包时,防火墙逐一扫描链;当碰到规则条件时,“跳(jumps)”到(因此在命令中使用 -j 选项)规定的行为并继续处理。大多数常用的行为都已经标准化,并有专门操作。使用标准操作会中断对链的处理过程,此时数据包的去向未知(除了下面提到的例外):

回到基础 ICMP

ICMP (互联网控制信息Internet Control Message 协议)是用来在通信中传递补充信息的协议。支持使用 ping 命令来测试网络的连通性(发送 ICMP 回应请求信息,接收者要用 ICMP回应应答信息应答)。它会产生防火墙拒绝数据包,显示接收缓冲区溢出,为连接中后续数据包提供更好的路由,等等。该协议有几个 RFC 文档定义;起先 RFC777 和 RFC792 很快就完成了,并被扩展。

http://www.faqs.org/rfcs/rfc777.html

http://www.faqs.org/rfcs/rfc792.html

接收缓冲区是一个小内存区域,用来存储已经从网络到达而内核还未来得及处理的数据。如果该区域满了,新的数据就不能被接收,ICMP 会发出错误信号,这样发送者会减缓传输速率(理想情况下,过段时间就会达到平衡)。

注意,虽然 IPv4 在没有 ICMP 的情况下,仍然能工作;但是,ICMPv6 对于 IPv6 来说是必须的。因为它结合了一些,在 IPv4 的世界中,遍布 ICMPv4 功能,IGMP(Internet Group Membership Protocol)和 ARP(Address Resolution Protocol)。 ICMPv6 在 RFC4443 中定义。

http://www.faqs.org/rfcs/rfc4443.html

  • 接受(ACCEPT):允许数据包继续往下走;

  • 拒绝(REJECT):通过 ICMP 错误数据包拒绝(命令 iptables--reject-with *type* 选项可以设定错误类型);

  • 丢弃(DROP):删除(忽略)数据包;

  • 记录(LOG):记录(通过 syslogd)描述数据包的信息;注意该行为不会中断处理,并且会继续执行链中断的下一条规则,这就为什么记录拒绝数据包既需要记录规则,也需要拒绝/丢弃规则;

  • ULOG:通过 ulogd 记录信息,在处理大量信息时,它比 syslogd 更合适有效;注意该规则,类似 LOG,也会返回到调用链的下一条规则;

  • 链名(chain_name):跳转到指定链并处理其规则;

  • 返回:中断当前链的处理过程,并返回调用链;如果当前链是一个标准链,并且没有调用链,默认(有iptables-P 定义)就会执行该链;

  • DNAT(仅存在于 nat 表中,即只在 IPv4 中):申请 目的地 NAT(额外选项描述而外的应用改变);

  • DNAT(仅存在于 nat 表中,即只在 IPv4 中):应用 目的地 NAT(额外的选项描述应用的精细改变);

  • MASQUERADE(仅存在于 nat 表中,即只在 IPv4 中):申请 伪装源 NAT的一个特例);

  • REDIRECT (only in the nat table): redirect a packet to a given port of the firewall itself; this can be used to set up a transparent web proxy that works with no configuration on the client side, since the client thinks it connects to the recipient whereas the communications actually go through the proxy.

其他规则,特别是和 mangle 表相关的,不在本章的范围。 iptables(8) 和 ip6tables(8) 有全面的清单介绍。

14.2.2. iptables 和 ip6tables语法

iptablesip6tables 命令允许操作表格,链和规则。-t *table* 选项指明要操作哪个表(默认,filter)。

14.2.2.1. 命令

The -N *chain* option creates a new chain. The -X *chain* deletes an empty and unused chain. The -A *chain* *rule* adds a rule at the end of the given chain. The -I *chain* *rule_num* *rule* option inserts a rule before the rule number rule_num. The -D *chain* *rule_num* (or -D *chain* *rule*) option deletes a rule in a chain; the first syntax identifies the rule to be deleted by its number, while the latter identifies it by its contents. The -F *chain* option flushes a chain (deletes all its rules); if no chain is mentioned, all the rules in the table are deleted. The -L *chain* option lists the rules in the chain. Finally, the -P *chain* *action* option defines the default action, or “policy”, for a given chain; note that only standard chains can have such a policy.

14.2.2.2. 规则

Each rule is expressed as *conditions* -j *action* *action_options*. If several conditions are described in the same rule, then the criterion is the conjunction (logical and) of the conditions, which is at least as restrictive as each individual condition.

-p *protocol* 条件匹配 IP 数据包的协议区段。最常见的是 tcpudpicmp,和 icmpv6。条件之前加上感叹号表示求反,就变成了“除了指定协议之外的任何数据包”。这种求反机制不仅仅适用于 -p 选项,也可用于其它所有条件。

-s *address*-s *network/mask* 条件匹配数据包的源地址。相应地,-d *address*-d *network/mask* 匹配目的地地址。

-i *interface* 条件选择源自指定网络接口的数据包。-o *interface* 条件选择从指定接口出去的数据包。

根据上述的通用条件,可以定义更具体的条件。例如,-p tcp 条件可以和 TCP 端口条件互为补充,就形成例如--source-port *port*--destination-port *port*

--state *state* 条件匹配连接中某个状态的数据包(这需要 ipt_conntrack 内核模块,用于连接追踪)。新(NEW) 状态指明开启新连接的数据包;建立(ESTABLISHED) 匹配属于已存在连接的数据包;相关(RELATED) 匹配发起与已存在连接相关的数据包(这对处于“活动”模式的 ftp-data 连接是很有用的)。

前面的段落列出了可用的操作,但是没有相应的选项。例如:记录 LOG 操作,有如下的选项:

  • --log-level, with default value warning, indicates the syslog severity level;

  • --log-prefix 可用来指定不同文字前缀来区分消息;

  • --log-tcp-sequence--log-tcp-options--log-ip-options 指定需附加的消息数据:相对应的 TCP 序列号码,TCP 选项,和 IP 选项。

The DNAT action provides the --to-destination *address*:*port* option to indicate the new destination IP address and/or port. Similarly, SNAT provides --to-source *address*:*port* to indicate the new source IP address and/or port.

The REDIRECT action (only available if NAT is available) provides the --to-ports *port(s)* option to indicate the port, or port range, where the packets should be redirected.

14.2.3. 创建规则

每次创建规则需要使用 iptables/ip6tables命令。手工输入这些命令是繁琐的,可以将调用存储在脚本中,这样机器每次启动后就可以进行同样的自动配置。脚本可以手工输入,但是也可以使用很有趣的高级工具(例如,fwbuilder)来准备。

  1. #

规则很简单。第一步,列出所有要调用的规则元素:

  • 防火墙自身以及网络接口;

  • 网络,及其相应的 IP 范围;

  • 服务器;

  • 宿主服务器上服务所使用的端口号。

然后可以使用对象拖拽(drag-and-drop)来创建规则。一些上下文菜单可以改变条件(例如,求反)。然后选择操作和配置。

至于 IPv6,可以为 IPv4 和 IPv6 分别创建规则集,或者只创建一个并使用 fwbuilder 来根据赋给对象的地址来转化规则。

Fwbuilder 主窗口

图 14.2. Fwbuilder 主窗口

fwbuilder can then generate a script configuring the firewall according to the rules that have been defined. Its modular architecture gives it the ability to generate scripts targeting different systems (iptables for Linux, ipf for FreeBSD and pf for OpenBSD).

14.2.4. 每次启动时加载规则

其他情况下,推荐的方法是将配置脚本在 up 目录下作为 /etc/network/interfaces 文件。在后面的例子中,脚本存储在 /usr/local/etc/arrakis.fw

例 14.1. 接口(interfaces) 文件调用防火墙脚本

  1. auto eth0
  2. iface eth0 inet static
  3. address 192.168.0.1
  4. network 192.168.0.0
  5. netmask 255.255.255.0
  6. broadcast 192.168.0.255
  7. up /usr/local/etc/arrakis.fw

以上内容显然假设您正在使用 ifupdown 来配置网络接口。如果您正在使用其它工具(例如 NetworkManagersystemd-networkd),那么您需要参考他们对应的文档来了解接口被启动后执行脚本的配置方式。