我有一个相当标准的 debian 10 系统,设置为路由器 (echo 1 > /proc/sys/net/ipv4/ip_forward),带有一个 WAN (=enp11s0) 接口和一个 DMZ (=enp10s0) 接口。WAN 接口绑定了几个公共 IP 地址,例如
ip addr add 81.2.3.4/25 brd + dev enp11s0
ip addr add 81.2.3.5/25 brd + dev enp11s0
ip addr add 81.2.3.6/25 brd + dev enp11s0
ip addr add 81.2.3.7/25 brd + dev enp11s0
DMZ 接口分配有一个本地 IP,即 10.2.10.10。下面的服务器名称 zz、zz-dmz 等均在 /etc/hosts 中声明。
我已经设置 NFT 在预路由钩子中执行 DNAT:
flush ruleset
define DMZ = enp10s0
define WAN = enp11s0
define WAN_NET = 81.2.3.0/25
define wan2dmz_map = {
www : www-dmz,
zz : zz-dmz,
dns0 : dns0-dmz,
dns1 : dns1-dmz,
drift78 : drift78-dmz
}
define dmz2wan_map = {
www-dmz : www,
zz-dmz : zz,
dns0-dmz : dns0,
dns1-dmz : dns1,
drift78-dmz : drift78
}
table ip fail2ban {
chain input {
type filter hook forward priority 0;
}
}
table ip global {
map ip_mapWD {
type ipv4_addr : ipv4_addr
elements = $wan2dmz_map
}
map ip_mapDW {
type ipv4_addr : ipv4_addr
elements = $dmz2wan_map
}
# Accepted WAN ports
chain SRV_ACCEPT {
ip daddr www-dmz tcp dport {http,https} counter accept
ip daddr zz-dmz tcp dport {http,https,smtp,pop3,imap2,submission,imaps,465} accept
ip daddr drift78-dmz accept
ip daddr dns0-dmz tcp dport 53 accept
ip daddr dns1-dmz tcp dport 53 accept
}
chain input {
type filter hook input priority 0; policy drop;
iif {lo,$DMZ} accept
ct state established,related accept
ct state invalid drop
ct status dnat accept
ip saddr 127.0.0.0/8 drop
ip protocol icmp icmp type echo-request limit rate over 1/second burst 5 packets drop
ip frag-off & 0x1fff != 0 counter drop
tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop
ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, router-solicitation, router-advertisement, tr-problem } accept
}
chain output {
type filter hook output priority 0;
}
chain forward {
type filter hook forward priority 0; policy drop;
iif {lo, $DMZ} accept
ct state established,related accept
ct state invalid drop
ct status dnat accept
ip protocol icmp icmp type echo-request limit rate over 1/second burst 5 packets drop
ip frag-off & 0x1fff != 0 counter drop
tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop
ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, router-solicitation, router-advertisement, tr-problem } accept
# Accept selected dest. ip/ports from WAN
iif $WAN jump SRV_ACCEPT
# VPN
ip saddr 10.8.0.0/8 iifname tun0 accept
# Log denied on WAN
iif $WAN log prefix "[NFT] WAN: "
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
# Hairpin
iif {lo,$DMZ} fib daddr type local dnat to ip daddr map @ip_mapWD
# From WAN, change dest. to DMZ
iif $WAN ip daddr $WAN_NET counter dnat to ip daddr map @ip_mapWD
}
chain postrouting {
type nat hook postrouting priority 100;
oif {tun0,$DMZ} counter masquerade;
}
}
(zz 是服务器 zz 的公网 IP,zz-dmz 是 10.2.10.x 网络上的私有 IP)。
这有效:我可以通过探测 zz 从 WAN 端到达 zz-dmz。我还没有真正尝试过发夹。
现在的问题是:debian 10 机器上的本地服务(例如 exim4)查找公共 IP(“zz”)作为其域的 mx,并尝试连接到其公共 IP,但数据包不会重新路由到 zz-dmz。相反,它们卡在 lo 接口上,从 WAN 接口上的主 IP 地址反弹到公共 IP“zz”,而该 IP(显然)没有本地响应的服务。登录 debian 路由器并输入以下内容即可看到这一点
root@opax:~/firewall# telnet zz 25
Trying 81.2.3.4...
telnet: Unable to connect to remote host: Connection refused
Tcpdump 显示数据包在 lo 上。我以为规则
iif {lo,$DMZ} fib daddr type local dnat to ip daddr map @ip_mapWD
也会替换 lo 上的目标 IP 并将它们重新路由到 $DMZ?
我错过了什么?