两个看似无关的支持工单其实同因同源。第一个里,管理员希望服务器只接受来自隧道的连接;第二个里,VPN 用户应当只能到达一台内网主机,别的哪里都去不了。这两条策略都属于 FORWARD,却通常都被写进 INPUT。结果看起来像防火墙,实际行为却像个占位符。

该由哪条链来回答

VPN 客户端发往局域网主机、或继续发往互联网的报文,由内核转发并在 FORWARD 中评估。INPUT 和 OUTPUT 只能看到以服务器自身为终点的流量。因此,凡是针对并非从 tun0 进来的拒绝,保护的都是服务器自己的监听端口,而且除非先放行已建立的连接,它还会把你的 SSH 会话一起断掉。它对客户端能去哪里毫无影响。

先把问题说清楚:谁能访问服务器,或者客户端能去哪里。多数网络两个答案都需要,只是写在不同链里。

先放行状态,再放行许可,最后拒绝

白名单只有满足两个条件才成立:具体许可排在通用拒绝之上,返回流量又排在两者之上。把规则插到明确的位置,再用 iptables -S FORWARD 把链打印出来,让顺序看得见,而不是靠假设。

POOL=10.99.0.0/24
iptables -I FORWARD 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD 2 -s "$POOL" -d 172.31.20.15 -p tcp -m multiport --dports 443,3389 -j ACCEPT
iptables -I FORWARD 3 -s "$POOL" -j REJECT

这条规则能否经得起真实流量的检验,取决于两个细节。没有状态规则时,你刚刚放行的连接,其回程报文会自己撞上拒绝并被丢弃。无节流的 LOG 规则在第一次被扫描打到时就可能写满一个小分区,所以在继续记录之前先加上 -m limit --limit 10/min。REJECT 会立刻返回错误,调列表阶段更友好;DROP 静默丢弃,任何失误都表现为超时。选哪一个要有明确理由,并把理由写进变更记录。

转发与 NAT 必须先跑通

过滤无法证明路径存在。先确认内核到底转不转发,并把这项设置做成持久化,而不是在 shell 里执行一次的临时命令。过滤器是最后一层,不是第一层。

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s "$POOL" -o eth0 -j MASQUERADE

masquerade 写在哪,取决于客户端从哪儿出去。如果客户端经隧道去往远端网络,NAT 规则就写在那张网卡上,而不是 WAN 口。然后看计数器:若 POSTROUTING 的计数纹丝不动,而 FORWARD 的放行数在涨,说明回程路径断了,过滤器没问题。这样读一次,能省下一下午去重写那些从来不是问题所在的规则。

邮件封锁属于隔壁那条链

在 INPUT 里封 25 端口,只挡得住发给 VPN 服务器本身的邮件。被攻陷的客户端经隧道发信,走的是转发,所以封锁必须落在 FORWARD 里、和 465、587 并排。如果某个应用确实合法地中继邮件,把它的目的地址和端口放到那条规则上面。

iptables -I FORWARD 2 -s "$POOL" -p tcp -m multiport --dports 25,465,587 -j REJECT

让拒绝计数先跑一周,再收紧别的东西。停止上涨的那个数字,就是你刚刚弄断的合法流量。

回读一遍,再从客户端验证

要读内核报告出来的规则集,而不是你脚本写出来的样子。先用 iptables -S FORWARD,再用 iptables -t nat -L POSTROUTING -n -v 看 NAT 表,然后查你正在探测的那条流的 conntrack 记录。工作期间始终备好回滚命令或计划中的清空。每次调用都要带 -w,否则两个管理员会撞在 xtables 锁上。变更窗口期这几样没有一项是可选的。

最后分别在池内和池外的客户端上验证。只能在你敲命令那台机器上生效的规则,算不上策略。

相关文章