我目前正在设置尽可能安全的基于 KVM 的服务器。VM 主机应该或多或少对互联网不可见,并且只应暴露运行单个服务的 VM 客户端。VM 客户端应该具有不互联网访问(--> 无 NAT 伪装)。
现在我想将 VM 客户端的 HTTP(s) 端口公开192.168.122.183
到互联网。所有现有文档都使用iptables
几乎已弃用的 。因此我更喜欢使用 的解决方案nftables
。
根据文档,这应该相当简单,所以我的nft list ruleset
外观如下:
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
iif "enp35s0" tcp dport { http, https } dnat to 192.168.122.183
}
}
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy accept;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
还激活了 IP 转发sysctl -a | grep forward
:
net.ipv4.conf.all.bc_forwarding = 0
net.ipv4.conf.all.forwarding = 1
net.ipv4.conf.all.mc_forwarding = 0
net.ipv4.conf.default.bc_forwarding = 0
net.ipv4.conf.default.forwarding = 1
net.ipv4.conf.default.mc_forwarding = 0
net.ipv4.conf.enp35s0.bc_forwarding = 0
net.ipv4.conf.enp35s0.forwarding = 1
net.ipv4.conf.enp35s0.mc_forwarding = 0
net.ipv4.conf.virbr10.bc_forwarding = 0
net.ipv4.conf.virbr10.forwarding = 1
net.ipv4.conf.virbr10.mc_forwarding = 0
net.ipv4.conf.virbr10-dummy.bc_forwarding = 0
net.ipv4.conf.virbr10-dummy.forwarding = 1
net.ipv4.conf.virbr10-dummy.mc_forwarding = 0
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_update_priority = 1
net.ipv4.ip_forward_use_pmtu = 0
从 VM 主机访问 Web 服务器一切正常,但从 Internet 访问时却没有收到响应。我遗漏了什么?
可能与此有关问题。
以下是主机 tcpdump 的摘录。从中可以看出,来自 VM 主机的请求得到了正确响应,并且外部请求虽然弹出但从未得到响应。有什么想法吗?
23:43:28.048714 IP 192.168.122.1.35584 > 192.168.122.183.http: Flags [S], seq 502099991, win 64240, options [mss 1460,sackOK,TS val 3361102460 ecr 0,nop,wscale 7], length 0
23:43:28.048746 IP 192.168.122.183.http > 192.168.122.1.35584: Flags [S.], seq 3142491522, ack 502099992, win 65160, options [mss 1460,sackOK,TS val 519662698 ecr 3361102460,nop,wscale 7], length 0
23:43:28.048801 IP 192.168.122.1.35584 > 192.168.122.183.http: Flags [.], ack 1, win 502, options [nop,nop,TS val 3361102460 ecr 519662698], length 0
23:43:28.048846 IP 192.168.122.1.35584 > 192.168.122.183.http: Flags [P.], seq 1:143, ack 1, win 502, options [nop,nop,TS val 3361102460 ecr 519662698], length 142: HTTP: GET / HTTP/1.1
23:43:28.048851 IP 192.168.122.183.http > 192.168.122.1.35584: Flags [.], ack 143, win 508, options [nop,nop,TS val 519662698 ecr 3361102460], length 0
23:43:28.048960 IP 192.168.122.183.http > 192.168.122.1.35584: Flags [P.], seq 1:325, ack 143, win 508, options [nop,nop,TS val 519662698 ecr 3361102460], length 324: HTTP: HTTP/1.1 200 OK
23:43:28.049015 IP 192.168.122.1.35584 > 192.168.122.183.http: Flags [.], ack 325, win 501, options [nop,nop,TS val 3361102460 ecr 519662698], length 0
23:43:45.263545 STP 802.1d, Config, Flags [none], bridge-id 8000.52:54:00:de:a7:a9.8002, length 35
23:43:45.537492 IP external.dip0.t-ipconnect.de.46866 > 192.168.122.183.http: Flags [S], seq 1122615229, win 64240, options [mss 1452,sackOK,TS val 2536247181 ecr 0,nop,wscale 7], length 0
23:43:47.247528 STP 802.1d, Config, Flags [none], bridge-id 8000.52:54:00:de:a7:a9.8002, length 35
23:43:47.553490 IP external.dip0.t-ipconnect.de.46866 > 192.168.122.183.http: Flags [S], seq 1122615229, win 64240, options [mss 1452,sackOK,TS val 2536249197 ecr 0,nop,wscale 7], length 0
作为参考我的ip addr
输出:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp35s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether a8:a1:59:0e:**:** brd ff:ff:ff:ff:ff:ff
inet 95.217.***.***/26 brd 95.217.120.127 scope global enp35s0
valid_lft forever preferred_lft forever
inet6 2a01:4f9:**:****::2/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::aaa1:59ff:****:*****/64 scope link
valid_lft forever preferred_lft forever
3: virbr10-dummy: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue master virbr10 state UNKNOWN group default qlen 1000
link/ether 52:54:00:de:a7:a9 brd ff:ff:ff:ff:ff:ff
4: virbr10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 52:54:00:de:a7:a9 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr10
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fede:a7a9/64 scope link
valid_lft forever preferred_lft forever
5: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr10 state UNKNOWN group default qlen 1000
link/ether fe:54:00:94:b9:ce brd ff:ff:ff:ff:ff:ff
inet6 fe80::fc54:ff:fe94:b9ce/64 scope link
valid_lft forever preferred_lft forever
另一个问题回答说virt-manager
与不兼容,nftables
因为它仍然使用iptables
。但 iptable 规则为空,并且 iptables 模块(尤其是iptable_nat
)未加载
# lsmod | grep ip
nft_chain_route_ipv4 16384 0
nft_chain_nat_ipv4 16384 1
ipt_MASQUERADE 16384 0
nf_nat_ipv4 16384 2 ipt_MASQUERADE,nft_chain_nat_ipv4
nf_nat 36864 2 nft_nat,nf_nat_ipv4
ipt_REJECT 16384 0
nf_reject_ipv4 16384 1 ipt_REJECT
nf_conntrack 172032 5 xt_conntrack,nf_nat,nft_nat,ipt_MASQUERADE,nf_nat_ipv4
nf_defrag_ipv6 20480 1 nf_conntrack
nf_defrag_ipv4 16384 1 nf_conntrack
nf_tables 143360 13 nft_chain_route_ipv4,nft_compat,nft_nat,nft_chain_nat_ipv4,nft_counter,nf_tables_set
ip_tables 28672 0
x_tables 45056 7 xt_conntrack,nft_compat,xt_tcpudp,ipt_MASQUERADE,xt_CHECKSUM,ipt_REJECT,ip_tables
答案1
为了使 VM 能够接收来自外部的连接,必须满足以下条件:
- VM 有一个指向 的默认路由
192.168.122.1
。 - 防火墙已配置 DNAT 规则。
在您的案例中,第一个可能缺失。这会导致 VM 网络堆栈丢弃 TCP 协议发送的 SYN-ACK 数据包。发生这种情况的原因是客户端 VM 不知道将响应数据包转发到哪里。
答案2
您要么需要明确的源 NAT 或伪装,您的 VM 可能会应答,但您不会重写传出数据包的源 IP,因此外部客户端收到的数据包没有意义。