自从进入了pfsense 2.2时代,tinc就从pfsense的官方repo中消失了一段时间。前段时间发布的pfsense2.3.3又把tinc给带回来了。不过官方自带的GUI功能实在有限,无法满足我的要求:具备在firewall中提供接口功能;因为我需要在firewall webUI中设置多个1:1的NAT。so,hack it。

tinc

安装

不要通过webUI来安装tinc,要通过命令行:

pkg install tinc

配置

tinc的配置文件位置为:/usr/local/etc/tinc,在命令行中安装tinc,是不会自动创建该目录的,需要手工创建:mkdir /usr/local/etc/tinc

然后创建相应的文件

└── mgmt
     ├── hosts
     │   ├── e40
     │   ├── home
     │   ├── guangdong
     │   ├── corp
     │   └── tpl450
     ├── rsa_key.priv
     ├── tinc.conf
     ├── tinc-down
     └── tinc-up

跟linux不同,freebsd没有iproute这个软件包,只能通过ifconfig来配置tun这个接口。

tinc-up
#!/bin/sh
syxy_VIP="10.9.1.1"
/sbin/ifconfig $INTERFACE up
/sbin/ifconfig $INTERFACE inet ${syxy_VIP}/16
tinc-donw
#!/bin/sh
/sbin/ifconfig $INTERFACE down

其它的没有什么差别。

启动/停止tincd

/usr/local/sbin/tincd -n $netname $flags (1) (2)
1 netname 可以运行多个tincd进程,每个进程通过netname进行区分,不同netname可以创建不同的mesh vpn。
2 flags tincd运行参数,譬如"-d 1 --log-files /var/log/tincd.log",也可以是"-k",即杀掉$netname的tincd进程

至此,暂时搞定了pfsense中的tincd,但是还没完,因为还没有实现自启动功能,不过先放一下,先看看如何添加防火墙策略。

手工添加防火墙策略

在pfsense中,添加防火墙策略都要通过webUI,但是由于tincd是动态启停的,相关的防火墙策略需要根据tincd的状态来增加和删除,而pfsense官方是不支持这种做法,hack again:

有个网友找到了一个办法:将动态变化的防火墙策略放到/usr/local/pkg/CUSTOM_rules.inc这个文件中,随着/etc/rc.filter_configure的执行而自动添加。

/usr/local/pkg/CUSTON_rules.inc
<?php

// Add this file as:  /usr/local/pkg/CUSTOM_rules.inc
// pfSense will automatically add the rules defined here into the rules it loads in pf

require_once("util.inc");

        function CUSTOM_rules_generate_rules($type) { // called by filter.inc when pfSense rules generation happens
        $rules = "";
        switch($type) {
        case 'nat':
                $rules .= "# CUSTOM NAT RULES \n";
                $rules .= "binat on tun0 from 192.xx.xx.154 to any -> 10.x.x.154\n"; // esxi4
                $rules .= "# END CUSTOM NAT RULES \n";
                break;
        case 'filter':
                $rules .= "# CUSTOM FILTER RULES \n";
                $rules .= "pass in quick on tun0 inet proto { tcp udp } from any to any\n";
                $rules .= "# END CUSTOM FILTER RULES \n";
                break;
        }
        return $rules;
}
?>

然后手工reload防火墙

/etc/rc.filter_configure

查看这些策略是否已经生效(两种方式):

  1. vim /tmp/rules.debug

  2. pfctl -sr

组合起来并自动化之

接下来考虑如何自动启动tinc和自动添加/删除这些策略,由于我们的pfsense是HA的,所以可以使用devd根据carp的状态来触发脚本:

/etc/devd.conf
options {
        directory "/etc/devd";
        directory "/usr/local/etc/devd";
        pid-file "/var/run/devd.pid";
        set scsi-controller-regex
                "(aac|adv|adw|aha|ahb|ahc|ahd|aic|amd|amr|asr|bt|ciss|ct|dpt|\
                esp|ida|iir|ips|isp|mlx|mly|mpt|ncr|ncv|nsp|stg|sym|trm|wds)\
                [0-9]+";
};

# CARP notify hooks. This will call carpup/carpdown with the
# interface (carp0, carp1) as the first parameter.
notify 100 {
    match "system"          "CARP";
    match "type"            "MASTER";
    action "/usr/local/sbin/pfSctl -c 'interface carpmaster $subsystem'";
};

notify 100 {
    match "system"          "CARP";
    match "type"            "BACKUP";
    action "/usr/local/sbin/pfSctl -c 'interface carpbackup $subsystem'";
};

notify 100 {
    match "system"          "CARP";
    match "type"            "INIT";
    action "/usr/local/sbin/pfSctl -c 'interface carpbackup $subsystem'";
};

依葫芦画瓢,在下面添加了两个section:

notify 150 {  (1)
    match "system"          "CARP";
    match "type"            "MASTER";
    action "/usr/local/etc/tinc/change_tincState.sh up";
};

notify 150 {
    match "system"          "CARP";
    match "type"            "BACKUP";
    action "/usr/local/etc/tinc/change_tincState.sh down";
};
1 notify的优先级要低于系统默认的carp section的优先级(此处为150,默认为100),假如这里仍然保留100,则不会触发该section

然后重启一下devd

/etc/rc.d/devd restart

接着写个change_tincState.sh的启动脚本

/usr/local/etc/tinc/change_tincState.sh
#!/bin/sh

STATE=$1
command="/usr/local/sbin/tincd"
tinc_cfg="mgmt"
tinc_flags="-d 1 --logfile /var/log/tincd.log"
custom_rules_file="CUSTOM_rules.inc"
src_path="/usr/local/etc/tinc/"
dst_path="/usr/local/pkg/"
reload_fw_rules="/etc/rc.filter_configure"

case $STATE in
        "up")   /bin/echo "start tinc for carp:master" | /usr/bin/logger -p local6.notice -t change_tincState
                $command -n $tinc_cfg $tinc_flags
                cp -f ${src_path}${custom_rules_file} $dst_path
                $reload_fw_rules
                exit 0
                ;;
        "down") /bin/echo "stop tinc for carp:backup" | /usr/bin/logger -p local6.notice -t change_tincState
                $command -n $tinc_cfg -k
                rm -rf ${dst}${custom_rules_file}
                $reload_fw_rules
                exit 0
                ;;
        *)      echo "Unknown state of CARP"
                exit 1
                ;;
esac

现在让我们来转换两台pfsense中的master/backup角色,确认一下devd能否正常工作:

  • pfsense-1:master/pfsense-2:backup→pfsense-1:backup/pfsense-2:master

    在pfsense-1中

    sysctl net.inet.carp.demotion=240

    此时,pfsense-1和pfsense-2的master/backup角色发生了互换,devd检测到carp的状态变化,于是

    • pfsense-1的tinc进程被杀掉,之前添加的防火墙策略也被删除;

    • pfsense-2的tinc进程启动,添加新的防火墙策略;

  • pfsense-1:backup/pfsense-2:master→pfsense-1:master/pfsense-2:backup

    在pfsense-1中

    sysctl net.inet.carp.demotion=-240

    此时,pfsense-1和pfsense-2的backup/master角色发生了互换,devd检测到carp的状态变化,于是

    • pfsense-1的tinc进程启动,添加新的防火墙策略;

    • pfsense-2的tinc进程被杀掉,之前添加的防火墙策略也被删除;

It’s awesome!

其它

为了方便维护,建议将/etc/devd.conf的新增的两段section单独放在一个配置文件中:

/usr/local/etc/devd/tincd.conf
notify 150 {
    match "system"          "CARP";
    match "type"            "MASTER";
    action "/usr/local/etc/tinc/change_tincState.sh up";
};

notify 150 {
    match "system"          "CARP";
    match "type"            "BACKUP";
    action "/usr/local/etc/tinc/change_tincState.sh down";
};
切记,不能放在/etc/devd/这个目录中,经过测试,该目录的conf不起作用。