VPC VR: static-NAT SNAT rule can precede the site-to-site VPN NAT exemption, so a static-NAT VM's VPN traffic leaves with its public IP
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 55/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- linux, python
- Lĩnh vực
- cloud, networking
Hướng nghiên cứu
Start in systemvm/debian/opt/cloud/bin/configure.py at CsForwardingRules.processStaticNatRule and CsSite2SiteVpn.configure_iptables, then inspect CsNetfilter.py for front insertion and has_rule behavior. Reproduce the ordering-dependent case by enabling static NAT after the VPN connection; done means VPN-marked traffic retains its private source while internet-bound traffic still uses public SNAT.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
problem
On a VPC virtual router, the per-VM static-NAT rule
-A POSTROUTING -o <public dev> -s <vm>/32 -j SNAT --to-source <public ip>
and the site-to-site VPN NAT exemption
-A POSTROUTING -o <public dev> -m mark --mark 0x525 -j ACCEPT
are both inserted at the front of the nat POSTROUTING chain, and whichever is created later ends up first. When static NAT is enabled on a VM after a site-to-site VPN connection already exists, the SNAT rule precedes the exemption and every packet that VM sends into the tunnel carries its public address instead of its private one. The remote side sees traffic from the public IP, its rules for the VPC's guest CIDR do not match, and that VM cannot reach the remote network while VMs without static NAT can. Nothing in the API or UI indicates a problem: the connection stays Connected.
Where the other end of the tunnel is does not matter (another VPC, another zone, another cloud, a customer gateway); the translation happens on the local VPC router before encryption.
Observed:
- Ping and TCP/22 from the static-NAT VM (A) to a VM behind the peer (B) fail. B's kernel receives no echo requests (
/proc/net/snmpInEchosdoes not move). - Temporarily allowing all ingress on B's tier makes the traffic arrive, and a listener on B reports the connection from A's static-NAT public address, not from the VPC's guest CIDR.
- Traffic initiated by B toward A is not affected (connection tracking keeps the reply un-translated), so the failure is one-directional and only for the VM with static NAT.
- The order of operations decides the outcome. Measured on the same setup:
- static NAT enabled on A before the VPN gateway, customer gateway and connection are created: traffic crosses with private addresses;
- static NAT disabled and re-enabled after the connection exists: ICMP and TCP/22 from A both fail;
- the connection deleted and recreated with static NAT left in place: traffic crosses again.
- Replacing the static NAT with a port-forwarding rule also avoids it, since port forwarding only source-translates hairpin traffic to the VM's own public IP.
Analysis (4.22.1.1 sources):
systemvm/debian/opt/cloud/bin/configure.py,CsForwardingRules.processStaticNatRule, lines 1559-1560 (4.23.0.0: line 1685):
["nat", "front", "-A POSTROUTING -o %s -s %s/32 -j SNAT --to-source %s"]configure.py,CsSite2SiteVpn.configure_iptables, line 1059 (4.23.0.0: line 1184):
["nat", "front", "-A POSTROUTING -t nat -o %s -m mark --mark 0x525 -j ACCEPT"]systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py, lines 164-176:frontbecomesiptables -I <chain> <rule>(insert at position 1), and a rule that already exists is skipped (has_rule).
So on a fresh apply the databags are processed forwardingrules first and site2sitevpn second (configure.py lines 1591-1595), the exemption is inserted last and lands on top, and everything works. On an incremental apply only the new rule is inserted: enabling static NAT after the connection exists puts the SNAT rule at position 1 above the existing exemption, so the VM's VPN-bound packets are translated before the exemption can match them. The order then persists until the connection is deleted and recreated (measured) or the router is rebuilt (expected from the fresh-apply order).
The VPN mark itself is set correctly (mangle FORWARD -s <vpc cidr> -d <peer cidr> -j MARK --set-xmark 0x525), so the exemption matches whenever it is reached. The VPC-wide source-NAT rule is appended rather than front-inserted and is not affected; only per-VM static NAT is.
versions
- Apache CloudStack 4.22.1.1, KVM, advanced zone, VPC with "Default VPC offering" (NAT mode, VPC virtual router),
DefaultIsolatedNetworkOfferingForVpcNetworkstiers, IKEv2 site-to-site connections between two VPC virtual routers. - The same rules and insertion logic are present in 4.23.0.0 (line numbers above).
The steps to reproduce the bug
- Two VPCs in one zone with non-overlapping CIDRs, e.g.
10.90.0.0/22(A) and10.91.0.0/22(B), one tier each, one VM each. Tier ACLs on both sides allow ICMP and TCP/22 from the peer VPC CIDR. (A second VPC is only the simplest peer; any site-to-site endpoint reproduces it.) createVpnGatewayon each VPC, acreateVpnCustomerGatewayon each side describing the other (peer gateway IP, peer VPC CIDR, IKEv2), andcreateVpnConnectionon each side. Send traffic once; both connections reachConnected.associateIpAddresson VPC A andenableStaticNatit to VM A.- From VM A, ping VM B's private address and open TCP/22 to it.
Expected: traffic between VM A and VM B crosses the tunnel with private source and destination addresses, as it does for a VM without static NAT. Static NAT should apply to internet-bound traffic only.
Actual: both fail; with the peer tier temporarily open, VM B sees the connection arriving from VM A's public address.
What to do about it?
Make the static-NAT rule itself skip VPN-marked traffic, so chain order stops mattering:
-A POSTROUTING -o <dev> -s <vm>/32 -m mark ! --mark 0x525 -j SNAT --to-source <public ip>
Alternatives: re-assert the VPN exemption at position 1 whenever forwarding rules are (re)applied, or stop inserting the per-VM SNAT rule at the front. The first option is the smallest change, and it matches what a Neutron router does for floating IPs, which are exempted from source translation by an IPsec policy match.
Remote-access VPN was not checked.
- Ngôn ngữ chính
- Java
- Star
- 3.1k
- Fork
- 1.4k
- Merge trung bình
- 7 ngày 5 giờ
- Pull request đã merge (30 ngày)
- 28
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của apache/cloudstack
-
bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
apache/cloudstack#14222 ·
-
create-kubernetes-binaries-iso.sh builds the ISO without setting a volume ID on EL8 based os's Đang mởbug component:kubernetes
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
apache/cloudstack#14180 ·
-
bug component:projects component:UI
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
apache/cloudstack#14070 · 5 bình luận ·
-
component:backup
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
apache/cloudstack#14013 ·
-
KVM agent fails to connect to Ceph RBD storage pool after upgrading Ceph client to Tentacle 20.2.4 Đang mởbug component:ceph
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
apache/cloudstack#13989 · 3 bình luận ·
Tất cả issue của apache/cloudstack
Issue tương tự
-
[BUG]茶杯方块在取茶时会引发崩溃 Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
-
Cannot differ own consent and managed consents in My Consents view and detailed consent view. Đang mở1.0.0-alpha2 Type/Improvement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
wso2/dpdp-accelerator#272 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
infinispan/infinispan#18150 ·
-
area/frontend
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100