[OpenBSD]

[上一小节: Authpf: 认证网关的User Shell] [总目录] [下一小节: 为家庭或小型办公环境搭建防火墙]

PF: 使用 CARP 和 pfsync 构建冗余防火墙


目录


CARP介绍

CARP是通用地址冗余协议。它的主要目的是允许位于同一网段的多台主机共享一个IP地址。CARP是 虚拟路由冗余协议(VRRP) 和 热备份路由协议(HSRP) 的一个安全、自由的替代品。

CARP是通过允许位于同一网段的一组主机共享一个IP地址来工作的, 这一组主机被称为"冗余组"。冗余组成员间共享一个被分派的IP地址。在组内,一台主机被指定为"主力机", 而其余的作为"热备份"。主力机平时"持有"共享的IP地址; 它应答所有外来的通讯或ARP请求。一台主机可以同时属于几个冗余组。

CARP常用来构建一组冗余的防火墙。分配到冗余组的虚拟IP作为客户端计算机的默认网关地址, 一旦主力机失效或未掉线, 这个IP将移到一台备份的防火墙上, 服务将继续而不会受影响。

CARP 支持 IPv4 和 IPv6.

CARP操作

主力机对本地网络发送定期的公告,所以备份机知道它仍在正常工作。如果备份机在一个设定的时间间隔内没有收到公告, 那么它们其中一台会接替主力机的工作。(advbaseadvskew值设置的最低的那台)。

有可能在同一网段存在多个CARP组, CARP的公告包含了虚拟主机ID, 它可以让组成员分辨出公告属于哪个冗余组。

为了防止此网段内的恶意用户发送虚假的CARP公告, 可以为每个组设置一个密码, 每个发到该组的CARP数据包会采用SHA1 HMAC加密算法进行保护。

因为CARP采用它自己的协议, 所以需要在过滤规则里添加明确pass规则:

pass out on $carp_dev proto carp keep state

$carp_dev 是CARP通讯经过的物理接口。

CARP配置

每个冗余组被重新分配了一个carp(4) 虚拟网络接口。因此CARP也使用 ifconfig(8) 来配置。
ifconfig carpN create
ifconfig carpN vhid vhid [pass password] [carpdev carpdev] \    [advbase advbase] [advskew advskew] [state state] [group|-group group] \    ipaddress netmask mask
carpN
carp(4) 虚拟接口的名称, 这里的 N 是一个整数, 它表示这个虚拟接口的编号(例如 carp10)。
vhid
虚拟主机ID。这是一个唯一的数字号码, 用它来区分这个冗余组与网络上的其它节点。有效值从1到255。
password
认证密码。用来与同组的CARP主机通讯。组内所有成员的认证密码吗必须一致。
carpdev
这个可选项指定了一个属于此冗余组的物理网络接口。 默认情况下, CARP会在尝试确定使用哪个物理接口,它通过在同一网段上寻找到一个物理接口以ipaddressmask组合的形式提供给carp(4)接口。
advbase
这个可选参数指定了向冗余组内成员公告的频率, 以秒为单位。默认值是1秒, 有效值从1到255。
advskew
这个可选参数指定了发送CARP公告的误差(延迟)。 利用 advskew, 可以选择CARP主力机。 这个数值越大, 则越不可能被选为主力机。默认值是0, 有效值从0到254。
state
强制一个carp(4)接口进入特定的状态。有效的状态是init, backup, 和 master
group, -group
在一个特定的接口组内添加或删除一个 carp(4) 接口。 默认情况下,所有的 carp(4) 接口被添加到这个 carp 组。 每个组有一个 carpdemote 计数器影响术语这个组的所有的 carp(4)接口。 正如 下面 描述的那样, 它可以用于将特定的接口组合在一起来实现故障转移的目的。
ipaddress
这是分配给冗余组的共享IP地址。这个IP地址不是必须和物理接口(如果存在)处于同一个子网内。然而, 组内的所有主机这个地址必须相同。
mask
共享IP的子网掩码。

CARP的更多功能可以通过 sysctl(8) 来控制。

net.inet.carp.allow
是或否允许CARP进站数据包。默认值是1(是)。
net.inet.carp.preempt
允许在一个荣誉组内的主机有一个更好的 advbaseadvskew 已担当主力机。此外, 这个参数在一个接口发生故障时时也对一组接口启用了故障转移。如果一个启用CARP的物理接口发生故障, CARP将增加其降级计数器, 该carp(4)所在的接口组的carpdemote 为1时, 这会导致所有改组成员一起故障转移。默认情况下 net.inet.carp.preempt 是0(禁用)。
net.inet.carp.log
记录状态的变化,损坏的CARP数据包和其它错误。范围在0和7之间,对应于syslog(3)的优先级,默认值是2(仅状态变化)。

CARP范例

这里有一个CARP配置的例子:
# sysctl -w net.inet.carp.allow=1
# ifconfig carp1 create
# ifconfig carp1 vhid 1 pass mekmitasdigoat carpdev em0 \
    advskew 100 10.0.0.1 netmask 255.255.255.0

它完成了如下设置:

在carp1上运行 ifconfig 来显示这个接口的状态。

# ifconfig carp1
    carp1: flags=8802<UP, BROADCAST, SIMPLEX, MULTICAST> mtu 1500
     carp: BACKUP carpdev em0 vhid 1 advbase 1 advskew 100
     groups: carp
     inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255 

pfsync介绍

pfsync(4) 网络接口显示 pf(4) 状态表的确切变化。通过使用 tcpdump(8) 监视这个设备, 状态表的变化可以实时显示。 此外, pfsync(4)接口能将这些状态变化信息发到这个网络外面的其它节点上, 而其它节点上面运行的PF能将这些变化并入自己的状态表内。同样, pfsync(4)也能监听网络上的进站信息。

pfsync操作

默认情况下, pfsync(4)不在网络上发送和接收状态表更新; 不过,仍可在本地计算机上使用tcpdump(8)监视更新。

当pfsync(4)设置为在网络上发送和接收更新, 默认行为是在本地网络上组播(多点传送)更新, 所有更新的发送不需要认证。通常的最优方法有下面两种:

  1. 用一根交叉电缆背靠背的连接两个交换更新的节点, 并用那个接口作为同步设备syncdev(看下面)。
  2. 用ifconfig(8)的syncpeer选项(看下面)以便将信息直接单播至对方, 然后在两台主机间配置 ipsec(4) 以保护pfsync(4)的通讯。

当在网络上发送和接收更新时, pfsync的数据包应该被规则集放行:

pass on $sync_if proto pfsync

$sync_if 应该是 pfsync(4) 通讯采用的物理接口。

pfsync配置

因为pfsync(4)是一个虚拟网络接口, 所以用 ifconfig(8) 配置:
ifconfig pfsyncN syncdev syncdev [syncpeer syncpeer] [defer|-defer]
pfsyncN
pfsync(4)接口的名。使用GENERIC内核时pfsync0默认存在
syncdev
用来发出 pfsync 更新的物理接口名。
syncpeer
这个可选项指定了与之交换 pfsync 更新的对方主机IP地址。默认情况下, 在本地网络上pfsync更新是组播。这个选项调整组播的行为, 将其取代为用单播直接将更新发送到指定的syncpeer
defer
如果使用了 defer 标签, 一个新连接的首个数据包通过防火墙时将不被传送,直到另一个(译者:此处应该是说成对方吧?)pfsync(4)系统已经有了公认的状态表增项, 否则将以一个timeout终结。 This adds small delays but allows traffic to flow when more than one firewall might actively handle packets ("active/active"), e.g. with certain ospfd(8), bgpd(8) or carp(4) configurations.

pfsync范例

这是一个配置 pfsync 的例子:
# ifconfig pfsync0 syncdev em1

这是在em1接口上启用pfsync。出站更新将在网络上组播, 允许任何运行pfsync的主机接收它们。

结合CARP和pfsync完成故障切换

通过结合CARP和pfsync的功能, 一组两台以上的防火墙能被用来创建一个高可用性、完全冗余的防火墙集群。
CARP:
负责从一个防火墙到另一个防火墙的故障切换。
pfsync:
负责在所有防火墙之间同步状态表。在故障切换时, 通讯通过经新的主力防火墙而不停顿。

一个例子, 两个防火墙, fw1fw2

         +----| WAN/Internet |----+ 
         |                        |
      em2|                        |em2   
      +-----+                  +-----+
      | fw1 |-em1----------em1-| fw2 |
      +-----+                  +-----+
      em0|                        |em0
         |                        | 
      ---+-------Shared LAN-------+---

这两个防火墙用一根交叉线背靠背连接在em1。全通过em0连接到LAN;通过em2连接到WAN/Internet。 IP地址如下:

网络策略为 fw1 是首选的主力机。

配置 fw1:

! enable preemption and group interface failover
# sysctl -w net.inet.carp.preempt=1
! configure pfsync
# ifconfig em1 10.10.10.1 netmask 255.255.255.0
# ifconfig pfsync0 syncdev em1
# ifconfig pfsync0 up
! configure CARP on the LAN side
# ifconfig carp1 create
# ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \
     172.16.0.100 netmask 255.255.255.0
! configure CARP on the WAN/Internet side
# ifconfig carp2 create
# ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \
    192.0.2.100 netmask 255.255.255.0

配置 fw2:

! enable preemption and group interface failover
# sysctl -w net.inet.carp.preempt=1
! configure pfsync
# ifconfig em1 10.10.10.2 netmask 255.255.255.0
# ifconfig pfsync0 syncdev em1
# ifconfig pfsync0 up
! configure CARP on the LAN side
# ifconfig carp1 create
# ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \
     advskew 128 172.16.0.100 netmask 255.255.255.0
! configure CARP on the WAN/Internet side
# ifconfig carp2 create
# ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \
    advskew 128 192.0.2.100 netmask 255.255.255.0

操作问题

一些使用 CARP/pfsync 时常见的操作问题。

启动时配置CARP和pfsync

因为 carp(4) 和 pfsync(4) 全是网络接口类型, 可以通过创建一个 hostname.if(5) 文件以便在启动时配置它们。 netstart 启动脚本可以完成创建接口和配置接口的工作。

例如:

/etc/hostname.carp1
inet 172.16.0.100 255.255.255.0 172.16.0.255 vhid 1 carpdev em0 \
    pass lanpasswd
/etc/hostname.pfsync0
up syncdev em1

强制切换主力机

这可能发生在故障切换或有目的的降级主力机节点。 例如包括为了维护关闭主力机或者发现并处理一个问题。这里的目的是在用户丝毫没有察觉的情况下, 平滑地完成切换。

切换到一个指定的CARP组, 关闭主力节点上的carp(4)接口, 将导致主力机公告: 它自己带有一个"无限大"的dvbaseadvskew。备份机(们)将看见这个公告,随后立即担任起主力机的角色。

# ifconfig carp1 down

还有一个替代方法可以将主力机的advskew值增到高于备份机。这将导致切换但仍允许主力机参与到CARP组中。

另一个故障切换的方法是调整CARP的demotion counter。demotion counter用来衡量一台备机成为主机的"预备"情况如何, 例如一台启动中的主机不太可能成为CARP主力机, 只能等到所有接口已经配置完毕、所有网络进程已经启动等才可以承担此任务。 那些公告的demotion值较高的主机成为主力机的机会更小。

demotion counter储存在属于CARP接口的每个接口组中。默认情况下, 所有的CARP接口全是属于"carp"接口组的成员。可以用 ifconfig(8) 查看目前的demotion counter数值:

# ifconfig -g carp
carp: carp demote count 0

这个例子中显示了与"carp"接口组相关的counter。当一个CARP主机在网络上公告自己时, 它得到所有接口组的demotion counters总和, 它将这个总和作为自己的demotion值公告。

现在假设下面的例子, 两个防火墙运行CARP带有如下的CARP接口:

目标是故障切换时, 仅将carp1和carp2组切换到第二个防火墙上。

首先, 将它们全部指派到一个新的接口组, 本例中被称为"internal":

# ifconfig carp1 group internal
# ifconfig carp2 group internal
# ifconfig internal
carp1: flags=8843<UP, BROADCAST, RUNNING, SIMPLEX, MULTICAST> mtu 1500
     carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 100
     groups: carp internal
     inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255
carp2: flags=8843<UP, BROADCAST, RUNNING, SIMPLEX, MULTICAST> mtu 1500
     carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 100
     groups: carp internal
     inet 10.0.1.1 netmask 0xffffff00 broadcast 10.0.1.255

现在用 ifconfig(8) 增大 "internal" 组的demotion counter:

# ifconfig -g internal
internal: carp demote count 0
# ifconfig -g internal carpdemote 50
# ifconfig -g internal
internal: carp demote count 50

这个防火墙在carp1和carp2上被平滑地切换为防火墙集群内的其它防火墙, 但是这个防火墙还是carp3和carp4的主力机。如果那个其它的防火墙开始公告自己有一个高于50的demotion值, 或者完全停止公告, 那么这个防火墙会重新担当carp1和carp2的主力防火墙。

如果这个防火墙返回主力位置, 反向变化:

# ifconfig -g internal -carpdemote 50
# ifconfig -g internal
internal: carp demote count 0

网络进程诸如 OpenBGPDsasyncd(8) 利用demotion counter来确保这个防火墙没有变成主力机, 直到建立了BGP会话和IPsec SAs已经被同步。

规则集技巧

过滤物理接口. 至于和PF有关的, 网络通讯来自物理接口, 并非CARP虚拟接口(例如, carp0), 所以, 参照词条编写规则。别忘了在PF规则中一个接口名可以使用物理接口名也可以使用这个接口被分配的IP地址, 例如:下面的规则是正确的:
pass in on fxp0 inet proto tcp from any to carp0 port 22
但是如果用carp0替换fxp0,它就不会想你期望的那样工作了。

别忘记 放行carp协议和pfsync协议!

其它参考

请参阅这里的其它资源你获得更多的知识:

[上一小节: Authpf: 认证网关的User Shell] [总目录] [下一小节: 为家庭或小型办公环境搭建防火墙]


[back] www@openbsd.org
$OpenBSD: carp.html, v 1.22 2008/11/12 02:53:32 nick Exp $