我正在尝试使用 nftables 在新的 centos 8 上设置 DNAT。这个实用程序(和 centos 8)对我来说很新,我已经使用 iptables(centos 到 6)很久了。
我的猜测是,我没有正确设置 DNAT 以使其生效,但我可能只是没有正确使用这些工具。或者两者兼而有之。
无论如何,如果有关系的话,这里是我之前就同一盒子上的一些路由问题提出的一个问题:多个互联网连接,错误的 NIC 端口上的传入数据包(入站路由问题?)(问题是 ARP 通量,已解决)。
下面是我当前设置的草图,蓝线标记了我想要发生的事情(预期的“路径”)
基本上,数据包从互联网进入,经过接口 2(ens2),通过本地接口(ens5,本地 IP 192.168.1.10)进行 DNAT 到 192.168.1.2。(一旦此操作成功,ens 3 和 ens 4 将进行相同的设置,并进入同一 LAN 上的几个不同的虚拟机)
我已经验证数据包通过正确的接口进入(预期的 nft 日志触发),但是 conntrack -E
没有显示任何内容。
此外,centos 6 框(实际目标,192.168.1.2)上的 iptables 日志没有显示任何内容(很久以前设置的相同日志在我上次检查时,也就是几个月前,显示了预期的输出,所以理论上那个框应该没问题)
这是我现在的 nftables 脚本,其中 IP/IF 已翻译以匹配草图。
table ip nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
iif "ens2" goto PREROUTING_RDS2
iif "ens3" goto PREROUTING_RDS3
}
chain PREROUTING_RDS2 {
tcp dport { http, https } log prefix "RDS2_dnat-3 "
tcp dport { http, https } dnat to IP_6
}
chain PREROUTING_RDS3 {
tcp dport { http, https } log prefix "RDS3_dnat-3 "
tcp dport { http, https } dnat to IP_6
}
}
table inet filter {
chain INPUT {
type filter hook input priority 0; policy drop;
#
iif "lo" accept
#
# allow ping
ip protocol icmp icmp type echo-request limit rate 1/second log prefix "PING "
ip protocol icmp icmp type echo-request limit rate 1/second accept
# following is required and must be BEFORE the ct state established otherwise the ping flooding will not be stopped
ip protocol icmp drop
#
ct state established,related accept
ct status dnat accept
#
iifname "ens5" goto INPUT_LOCAL
#
# now we drop the rest
ct state invalid log prefix "INPUT_STATE_INVALID_DROP: "
ct state invalid drop
log prefix "INPUT_FINAL_REJECT: "
reject with icmpx type admin-prohibited
}
chain FILTER {
type filter hook forward priority 50; policy drop;
iif "ens2" goto FILTER_RDS2
iif "ens3" goto FILTER_RDS3
}
chain INPUT_LOCAL {
tcp dport ssh goto INPUT_LOCAL_ssh
}
chain INPUT_LOCAL_ssh {
ip saddr IP_MY_PC accept
}
chain FILTER_RDS2 {
oifname "ens5" ip daddr IP_6 tcp dport { http, https } accept
}
chain FILTER_RDS3 {
oifname "ens5" ip daddr IP_6 tcp dport { http, https } accept
}
}
先感谢您。
答案1
事实上,如果不仔细研究,这个问题很难回答。先前的问答解决初始设置centos8。解决方案变得非常复杂。考虑到必须为此实施的配置类型,每个接口一个 IP 可能不值得,多个接口位于同一个 LAN 上,而不是所有 IP 都位于同一个接口上,尤其是考虑到它处于虚拟环境中:不会有任何加速。对配置的任何更改都必须反映在下面的所有命令中,因此正确管理它将很困难。
centos8路由器
由于为了解决同一 LAN 中的多个接口问题,需要额外的路由表,因此在本问答中centos8充当路由器,必须将更多路由条目从主表复制到附加路由表:
# ip route add 192.168.1.0/24 dev ens5 table 1001 src 192.168.1.10
# ip route add 192.168.1.0/24 dev ens5 table 1002 src 192.168.1.10
# ip route add 192.168.1.0/24 dev ens5 table 1003 src 192.168.1.10
# ip route add 192.168.1.0/24 dev ens5 table 1004 src 192.168.1.10
否则,ens1,ens2,ens3或者ens4和基因通过ens5将失败反向路径过滤器因为没有路可以穿过ens5在那些桌子上。
当然这还不够:回复数据包中没有任何信息(例如:从centos6) 关于使用了哪个接口以及应该以相反的方式重用哪个接口。因此,必须使用 netfilter 的 conntrack 逐个流记住此信息。在 nftables 规则中,删除整个ip nat
表:
# nft delete table ip nat
并用这个新表替换它ip markandnat
:
# nft -f - << 'EOF'
table ip markandnat {
map iif2mark {
type iface_index : mark;
elements = {
ens1 : 101,
ens2 : 102,
ens3 : 103,
ens4 : 104
}
}
map mark2daddr {
type mark : ipv4_addr;
elements = {
102 : 192.168.1.2,
103 : 192.168.1.2, # same IP, as per OP's config
104 : 192.168.1.4 # some other VM
}
}
chain premark {
type filter hook prerouting priority -150; policy accept;
meta mark set ct mark meta mark != 0 return
meta mark set iif map @iif2mark meta mark != 0 ct mark set meta mark
}
chain prenat {
type nat hook prerouting priority -100; policy accept;
tcp dport { http, https } dnat to meta mark map @mark2daddr
}
}
EOF
这将映射接口 => 标记 => dnat 目的地,同时将标记保存为 conntrack 的标记(请参阅末尾的链接关于康马克使用)。现在,通过添加以下规则,此标记将可用并由路由堆栈使用,以指向相同的附加路由表:
# ip rule add pref 11001 fwmark 101 table 1001
# ip rule add pref 11002 fwmark 102 table 1002
# ip rule add pref 11003 fwmark 103 table 1003
# ip rule add pref 11004 fwmark 104 table 1004
但还有一部分没有说明:再次介绍反向路径过滤器。当使用标记时,反向路径过滤器不会使用标记更改的新路线重新检查,并且通常会检查失败。实际上有一个未记录的功能,在 2009/2010 年的内核 2.6.33/2.6.32.8 中添加,恰好解决了这个问题,而不需要使用松散反向路径模式:src_valid_mark
。
# sysctl -w net.ipv4.conf.ens1.src_valid_mark=1
# sysctl -w net.ipv4.conf.ens2.src_valid_mark=1
# sysctl -w net.ipv4.conf.ens3.src_valid_mark=1
# sysctl -w net.ipv4.conf.ens4.src_valid_mark=1
centos6服务器
如果您想暂时使用备用网关,即使这又会增加复杂性,并且可能带来无法预见的微妙副作用,也可以通过标记来实现。由于它是 CentOS 6,nftables不可用,因此iptables将会被使用。
我会认为centos6VM 在(唯一)接口上有 IP 192.168.1.2/24eth0,默认网关为 192.168.1.1。让我们为备用网关 192.168.1.10 添加新的路由表和规则:
# ip route add table 10 default via 192.168.1.10
# ip rule add fwmark 10 lookup 10
放在iptables规则(这里只有曼格尔需要表格):
# iptables-restore << 'EOF'
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -j CONNMARK --restore-mark
-A PREROUTING -m mark ! --mark 0 -j RETURN
-A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j MARK --set-mark 10
-A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j MARK --set-mark 10
-A PREROUTING -m mark ! --mark 0 -j CONNMARK --save-mark
-A OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark
COMMIT
EOF
现在,端口 80 或 443 上收到的任何流都将标记传入数据包及其回复。路由堆栈将使用此标记将传入和回复的网关更改为 192.168.1.10(mangle/输出触发重新路由检查,参见下面的第二个链接)。
在这种情况下似乎不需要使用src_valid_mark
,但只需设置它或设置rp_filter=2
如果它不起作用。此设置不允许同时接收基因通过 192.168.1.1 编辑流量。
一些链接:
答案2
从评论来看,最直接、最重要的遗漏是关闭 IP 转发。只需:
echo 1 > /proc/sys/net/ipv4/ip_forward
并检查DNAT数据包是否已经到达IP6。
第二个问题是非对称路由。经过 DNAT 处理的数据包通过 192.168.1.10 (IP5) 到达 IP6,在那里它们被修改(目标地址被更改)。返回数据包将通过 LAN 上的默认网关(182.168.1.1),并且在路由到连接源时不会被修改。它们可能会保留其 RFC1918 地址,或者在 192.168.1.1 上被 SNAT 为其他地址,并且永远不会匹配其目的地上的任何连接,并且可能会被丢弃。
编辑:
因此,为了解决 FORWARD 链,我会将其重写为以下内容(在我看来更简单):
table inet filter {
:
chain FORWARD {
type filter hook forward priority 0; policy drop;
ct state established,related accept
ct status dnat accept
}
:
}