diff --git a/migration/vyos-mode-delta.py b/migration/vyos-mode-delta.py index 1b646d7..befccdb 100755 --- a/migration/vyos-mode-delta.py +++ b/migration/vyos-mode-delta.py @@ -125,8 +125,20 @@ def build_delta(inv: dict, priority: int, wan_user: str) -> list[str]: f"set nat destination rule {rule} protocol {proto}", f"set nat destination rule {rule} destination port '{p['dst_port']}'", f"set nat destination rule {rule} translation address {p['fwd']}", - f"set nat destination rule {rule} translation port '{p['fwd_port']}'", ] + # `destination port` accepts a comma list but `translation port` does + # NOT -- "16881,6881 is not a valid service name" -- because mapping a + # list onto a list is ambiguous. Every forward here maps a port to + # itself, and omitting translation port makes VyOS preserve the + # original, which is exactly right. Only emit it when it genuinely + # differs, and refuse rather than guess when a differing list appears. + if p["fwd_port"] != p["dst_port"]: + if "," in str(p["fwd_port"]) or "," in str(p["dst_port"]): + raise SystemExit( + f"port forward '{p['name']}' remaps a LIST of ports " + f"({p['dst_port']} -> {p['fwd_port']}). VyOS cannot express " + f"that in one rule; split it into one rule per port by hand.") + out.append(f"set nat destination rule {rule} translation port '{p['fwd_port']}'") out += [ "",