Skip to content

Virtual NAT keeps only the last egress range when multiple ranges use the same routing node #1381

Description

@sgolod

When two Virtual NAT egress entries use the same routing node, netclient logs that both ranges were applied, but the node’s iptables VNAT chains contain rules only for the last range. Traffic to the first virtual range therefore has no NETMAP rule.
I found the same code path in develop (dd93f3f) and release-v1.7.0 (4951d35).

Reproduction
The routing node is cd85773d-d134-4c29-8337-ac79271cfc6c in network prod-vpn. It has a route to both real subnets through tap0.
Create these two enabled egress entries, both assigned to that node with metric 250, mode: virtual_nat, and nat: true:

Egress ID	Real range	Virtual range
15740d25-46d5-449d-9280-717f19538510	10.133.1.0/24	100.65.100.0/24
496fd7e6-4a60-4fe6-aec0-5928989332c8	10.133.2.0/24	100.65.103.0/24

After netclient processes the update, run iptables -t nat -S on the routing node.
Actual result
Netclient reports success for both ranges:

Processing virtual NAT-enabled egress range: 10.133.1.0/24 (virtual: 100.65.100.0/24)
Applied virtual NAT rules for egress cd85773d-d134-4c29-8337-ac79271cfc6c: 100.65.100.0/24 -> 10.133.1.0/24
Processing virtual NAT-enabled egress range: 10.133.2.0/24 (virtual: 100.65.103.0/24)
Applied virtual NAT rules for egress cd85773d-d134-4c29-8337-ac79271cfc6c: 100.65.103.0/24 -> 10.133.2.0/24

However, the shared chains contain only the second range:

-A NM-VNAT-PR-cd85773d -d 100.65.103.0/24 -i netmaker -m comment --comment NETMAKER -j NETMAP --to 10.133.2.0/24
-A NM-VNAT-PO-cd85773d -d 10.133.2.0/24 -i netmaker -o tap0 -m comment --comment NETMAKER -j MASQUERADE

There are no corresponding rules for 100.65.100.0/24 and 10.133.1.0/24.
Expected result
Both mappings should remain in the chains:

NM-VNAT-PR-cd85773d:
  100.65.100.0/24 -> 10.133.1.0/24
  100.65.103.0/24 -> 10.133.2.0/24

NM-VNAT-PO-cd85773d:
  10.133.1.0/24 -> MASQUERADE via tap0
  10.133.2.0/24 -> MASQUERADE via tap0

Root cause in netclient
InsertEgressRoutingRules calls applyVirtualNATRules once per range. Both calls pass the same routing node ID as egressID.
VNAT chain names are derived from that ID, so both ranges use NM-VNAT-PR-cd85773d and NM-VNAT-PO-cd85773d.
Inside applyVirtualNATRules, deleteVNATChains is called for every range. deleteVNATChains clears both shared chains. Thus, while processing the second range, netclient removes the first range’s rules before appending the second range’s rules. The success log describes each individual call, not the final contents of the chains.
The relevant lines are also present in release-v1.7.0.

Suggested fix
Clear or recreate a routing node’s VNAT chains once per complete egress configuration, before iterating over its ranges. Then append each range’s NETMAP and MASQUERADE rules to those shared chains. Keep applyVirtualNATRules for installing each mapping; only move its per-range chain cleanup.
Please also check cleanup errors: deleteVNATChains currently ignores failures from the iptables operations. A regression test should verify that two ranges on one routing node survive installation and a subsequent configuration update.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions