nat cgnat checks its input too little. Values the CLI accepts make the commit fail with a Python traceback instead of an error message. Worse, some valid-looking configurations commit fine but give the same external address and port block to two subscribers. All cases below were reproduced on rolling (vyos-1x 999.0-15088-gce2baa317).
All examples start from this working configuration:
set nat cgnat pool external EXT range 192.0.2.1/32 set nat cgnat pool internal INT range 100.64.0.0/29 set nat cgnat rule 10 source pool INT set nat cgnat rule 10 translation pool EXT
Port range given as a single port or service name.
external-port-range uses the generic port-range validator, which also accepts 2000 or http. The handler expects start-end and crashes with ValueError: not enough values to unpack or invalid literal for int(). A reversed range such as 3000-1000 is accepted too and only fails later with a misleading "not enough ports" message.
set nat cgnat pool external EXT external-port-range 2000 commit
Range with host bits set.
Both pool range nodes include the ipv4-host validator, so 100.64.0.1/29 is accepted. Turning it into a network then fails
with `ValueError: 100.64.0.1/29 has host bits set`.
set nat cgnat pool internal INT range 100.64.0.1/29 commit
Empty translation node.
A rule with translation but no pool below it passes verify and crashes with KeyError: 'pool'. An empty source node is already caught.
delete nat cgnat rule 10 translation pool set nat cgnat rule 10 translation commit
Same external address used twice.
Ports are allocated range by range, starting over at the first port of each range. If an external address is in two ranges, or in the pools of two different rules, it is handed out twice, so two subscribers share the same external address and port block. The commit succeeds, so nothing tells the operator.
set nat cgnat pool external EXT2 range 192.0.2.1/32 set nat cgnat pool internal INT2 range 100.64.1.0/31 set nat cgnat rule 20 source pool INT2 set nat cgnat rule 20 translation pool EXT2 commit
sudo nft list map ip cgnat tcp_nat_map 100.64.0.0 : 192.0.2.1 . 1024-3023, ... 100.64.1.0 : 192.0.2.1 . 1024-3023, ...
The same happens inside one pool, e.g. range 192.0.2.1/32 plus range 192.0.2.0/31. The address is also counted twice in the capacity check, so the pool looks bigger than it is.
Overlapping internal ranges.
An internal address in two ranges (one pool, or pools of two rules) produces overlapping nftables map elements. The commit then fails only at the nft --check step with "Configuration file errors encountered!", which says nothing about the cause.
set nat cgnat pool internal INT range 100.64.0.0-100.64.0.7
External range overlapping an internal range.
Nothing stops an external pool from using subscriber addresses, so one subscriber can be translated to another subscriber's address. This commits without complaint:
set nat cgnat pool external EXT range 100.64.0.4/30 commit
Op-mode crash with one port per subscriber.
With per-user-limit port 1, nftables stores each allocation as a single port instead of a range, and show nat cgnat allocation fails with TypeError: 'int' object is not subscriptable.
set nat cgnat pool external EXT per-user-limit port 1 commit run show nat cgnat allocation
Seen but not addressed here: commit time grows with the number of subscribers (a /16 internal pool takes about 6 s, almost all of it nftables loading four maps of 65536 elements each). Also, changing only a rule's translation pool does not clear existing conntrack entries.