依据网络上检索到的步骤,在/etc/ufw/before.rules中添加PREROUTING链规则,重启或者重载UFW会出现重复的iptables条目。

这并不是一个BUG,而是UFW设计如此。它只会管理自己的链,以ufw-*开头。在重启或者重载的时候,ufw清空这些链,然后再执行配置文件中的规则。对于iptables内置的链,考虑到其他应用程序也会使用,所以UFW不会进行重置。

这里简述一下UFW的启动流程,UFW启动时,首先执行/usr/lib/ufw/ufw-init脚本,用于创建UFW所用到的自定义链和一些默认配置,这个脚本还会用于用户配置的/etc/ufw/before.init,/etc/ufw/after.init。

如果需要自定义规则,在/etc/ufw/before.init和/etc/ufw/after.init中添加。before.init会在UFW初始化前执行,after.init会在UFW初始化之后执行。

在执行完成init脚本之后,会再执行before.rules,user.rules,after.rules中定义的规则。

了解了上面的流程,就知道接下来如何处理NAT规则了。

1、通过init脚本添加自定义链,用于创建NAT规则;
2、通过rules配置NAT规则。

开启转发支持

修改文件/etc/default/ufw,将默认转发策略修改为ACCEPT。

DEFAULT_FORWARD_POLICY="ACCEPT"

修改文件/etc/ufw/sysctl.conf,开启系统转发支持。

net/ipv4/ip_forward=1

自定义初始化流程

修改文件/etc/ufw/before.init。

start)块中添加如下内容,创建NAT规则所需要的链。

start)
    if iptables -t nat -L -n >/dev/null 2>&1;then
        printf "*nat\n"\
":PREROUTING ACCEPT [0:0]\n"\
":POSTROUTING ACCEPT [0:0]\n"\
"COMMIT\n" | iptables-restore -n
    fi
    # flush the chains (if they exist)
    if iptables -t nat -L ufw-nat -n >/dev/null 2>&1; then
        iptables -t nat -D PREROUTING -j ufw-nat 2>/dev/null || true
        iptables -t nat -F ufw-nat 2>/dev/null || true
        iptables -t nat -X ufw-nat 2>/dev/null || true
    else
        # setup nat chains
        printf "*nat\n"\
":ufw-nat - [0:0]\n"\
"-A PREROUTING -j ufw-nat\n"\
"COMMIT\n" | iptables-restore -n
    fi
;;

stop)块中添加如下内容,删除自定义规则。

stop)
    if iptables -t nat -L ufw-nat -n >/dev/null 2>&1; then
        iptables -t nat -D PREROUTING -j ufw-nat 2>/dev/null || true
        iptables -t nat -F ufw-nat 2>/dev/null || true
        iptables -t nat -X ufw-nat 2>/dev/null || true
    fi
    ;;

给before.init脚本可执行权限,这样脚本才会被ufw-init调用。

chmod a+x /etc/ufw/before.init

配置NAT规则

修改文件/etc/ufw/before.rules,在文件末尾添加如下规则:

#
# ufw-nat
#
*nat
:ufw-nat - [0:0]
-A ufw-nat -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.20.5:80
-A ufw-nat -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.20.5:443
COMMIT

重载UFW

最后进行测试,重启或者重载几次UFW,通过iptables查看规则是否生效,是否有重复。

# 查看规则是否生效
ufw disable && ufw enable
iptables -t nat -L

# 重载查看是否有重复规则
ufw reload
ufw reload

iptables -t nat -L

# 停止后查看规则是否清除
ufw disable
iptables -t nat -L
在before.int和after.init阶段配置其实都是可以的,包括before.rules和after.rules,这取决于你定义的规则的依赖顺序。具体执行顺序应该是before.init -> (ufw-setup) -> after.init -> before.rules -> after.rules -> user.rules。

关于地址伪装

由于我配置了回程路由,因此转发出去的数据包能够正常返回,如果没办法配置路由,则需要开启地址伪装。

在上述的基础上,将ufw-nat链分成ufw-before-nat,ufw-aftar-nat,分别添加到PREROUTING和POSTROUTING链上,然后ufw-before-nat上配置端口转发规则,ufw-after-nat上配置地址伪装。

参考文档:

https://gist.github.com/kimus/9315140?permalink_comment_id=3139569

https://manpages.ubuntu.com/manpages/xenial/man8/ufw-framework.8.html

最后修改:2024 年 02 月 27 日
如果觉得我的文章对你有用,请随意赞赏