Page MenuHomeVyOS Platform

Support NAT for ipv6(NPT)
In progress, NormalPublicFEATURE REQUEST

Description

At present, there are configuration options about NPT in vyos version, but they seem to have no effect. Does anyone know how to implement this feature.

Referring to H3C, NPT is also called nat66 technology. In fact, it is SNAT and DNAT implemented by IPv6. Different from IPv4, nat66 only supports 1-to-1 mapping of routing prefix, which will provide vyos with nat66 experimental support supporting SNPT and DNPT. This implementation needs to be tested. Please summarize all bugs and modification suggestions under this task for tracking.

set nat66 source rule <ruleid> description <description>
set nat66 source rule <ruleid> disable
set nat66 source rule <ruleid> log
set nat66 source rule <ruleid> source prefix <prefix>
set nat66 source rule <ruleid> translation prefix <prefix>|masquerade
set nat66 destination rule <ruleid> description <description>
set nat66 destination rule <ruleid> disable
set nat66 destination rule <ruleid> log
set nat66 destination rule <ruleid> destination address <ipv6-address>
set nat66 destination rule <ruleid> translation address <ipv6-address>

I refer to the configuration structure of H3C. In the original command structure, NPT does not support the division of SNAT and DNAT. In order to implement nat66, I separated it for the following reasons:

  1. I can modify it according to the existing script of NAT, and I can modify it less nat.py , I created nat66 and the independent nftables-nat66.tmpl to complete the implementation of nat66.
  2. It can fully support the configuration of SNPT and DNPT in nat66. If users do not need SNPT or DNPT, it should not take effect by default.

My initial implementation of npt is in:

https://github.com/jack9603301/vyos-1x/tree/nptv6

Details

Difficulty level
Normal (likely a few hours)
Version
vyos 1.3
Why the issue appeared?
Will be filled on close
Is it a breaking change?
Config syntax change (non-migratable)

Related Objects

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

If so, it's better to consider porting the 1.2 NPT implementation instead of using a new solution. Can they coexist? I'm just a suggestion.

alexandrestein added a subscriber: alexandrestein.EditedJun 9 2020, 4:44 PM

I made this works.

I needed to add an firewall table to make change active.
The strange thing is that this works even if the table is not affected to any interface.
It works when assigned also but it looks like you need at least one IPv6 table.

Here is what I use:

ipv6-name inFromProviderVPN6 {
    default-action reject
    enable-default-log
    rule 10 {
        action accept
        state {
            established enable
            related enable
        }
    }
}

I did not played much with it because it does what I want.
So I don't know where the limits are.

Related to: https://forum.vyos.io/t/nat-ipv6-local-address-global-scope/5462

In fact, according to official comments and my retrospection of nptv6 code, vyos has not generated any code for nptv6 at present.

It‘s implemented in 1.2 but not with the new nftables based NAT backend as the required commands could not be translated from ip6tables.

Looks like currently there is no nftables NAT66 example around, also the new MAP feature of nftables is yet not acailable in Debian Buster/Bullseye as there is yet no nftables release with the feature.

You are right.

I removed the rule and it works the same :-)

@alexandrestein To be honest, I don't understand why NPTs work in your configuration. It seems to have nothing to do with NPTs.

c-po added a comment.Jun 9 2020, 6:13 PM

NPTv6 is available in VyOS 1.2 (crux) and currently not implemented in 1.3 (equuleus) as nftables package should be updated to 0.9.5 to make use of netmap.

https://git.netfilter.org/nftables/commit/?id=35a6b10c1bc488ca195e9c641563c29251f725f3

Sorry.
It had some kind of persistency and I had to turn it on again to have it working.

I don't know but it is working for now.

I'm running: 1.3-rolling-202005100117

@alexandrestein Vyos1.3 's npt is temporarily unavailable, but vyos1.3 basically supports dhcpv6-pd,. If there is no special reason, you can consider using a global address instead of ULA, to obtain the delegation prefix directly from ISP and distribute it to the client (via RA), instead of using ULA+NPT.

@jack9603301, you look to have way more knowledge on IPv6 routing and the VyOS capabilities than I.

On an other switch, regular IPv6 connexions are actually working fine. My machines get public IPs and it all good.

In this case, I try to use a Wireguard interface to anonymise the traffic for a specific subnet/interface (which is in my case an other Wireguard interface).
So I don't want a global address and I need some kind of NAT.

PS: The config is broken again. I don't understand why.

If you want NPT, you may have to wait for the time to come when conditions are right, and the community may implement NPT at that time.

jack9603301 added a comment.EditedJun 10 2020, 4:35 PM

@alexandrestein Or, a disguised solution is to directly use iptables instruction rules to manually implement temporary nptv6 conversion. But I don't know when it will work. You can try it.
PS: because vyos uses nftables to implement NAT in 1.3, but because of the function limitation of nftables version, this function cannot be realized at present.

It‘s implemented in 1.2 but not with the new nftables based NAT backend as the required commands could not be translated from ip6tables.

Looks like currently there is no nftables NAT66 example around, also the new MAP feature of nftables is yet not acailable in Debian Buster/Bullseye as there is yet no nftables release with the feature.

and

NPTv6 is available in VyOS 1.2 (crux) and currently not implemented in 1.3 (equuleus) as nftables package should be updated to 0.9.5 to make use of netmap.

https://git.netfilter.org/nftables/commit/?id=35a6b10c1bc488ca195e9c641563c29251f725f3

Thanks a lot for your time and knowledge on VyOS.
I will try with 1.2.

@alexandrestein Note that vyos 1.2 (crux) does not implement DHCPv6 PD.

FYI.

Thank you @jack9603301.

No problem about DHCP.
AFAIK Wireguard does not support DHCP and it always been static IPs in my mind.

Using 1.2.5 works perfectly.
Thanks again and sorry for the noise on this thread.
If this feature is implemented in 1.3 I can try it.

Regards

jack9603301 added a comment.EditedJun 15 2020, 4:45 PM

@alexandrestein Sorry, I didn't understand some of them, but I opened this task list to track 1.3 nptv6 process, not about the DHCP support of wireguard. If you need this function or find that there is a bug in wireguard's DHCP, you should submit a bug report task list separately.

Maybe when the conditions are mature, nptv6 support will be implemented, which is expected.

edit: I'll go back to your reply. Maybe I understand it wrong, because you haven't submitted your reply until now.

c-po added a comment.Jun 15 2020, 5:15 PM

@alexandrestein can I assume you‘re using NPTv6 on VyOS 1.2 series? If so you mind sharing an example/configuration so we can also improve our documentation?

c-po added a comment.Jun 25 2020, 6:22 PM

nftables updated to 0.9.6 so the new nftables netmap feature can be used

https://git.netfilter.org/nftables/commit/?id=35a6b10c1bc488ca195e9c641563c29251f725f3

maybe someone can hack up a nftables commandline for NPTv6?

I checked the usage of netmap, but unfortunately I only found the equivalent configuration method of IPv4 on Wiki

https://wiki.nftables.org/wiki-nftables/index.php/Multiple_NATs_using_nftables_maps

Hi @c-po!

Yes I'm using 1.2 series.

Here is my config:

set nat nptv6 rule 500 outbound-interface 'wg1'
set nat nptv6 rule 500 source prefix 'fc10::/20'
set nat nptv6 rule 500 translation prefix 'fc00::100/128'

I'm connected two private networks.
The fc10::/20 is my local network.
fc00::1/128 is my address on the gateway network.

Do you need more of it?
The configuration is pretty simple.

I wish it will help.
Thank for your work.

@c-po What is the progress of NPT implementation?

c-po added a comment.Jul 20 2020, 1:58 PM

As VyOS is a hobby project for me and I‘m not paid by any party tvere is no progress planned in the near future from my side until ither things have been resolved. As you need it a contribution from your side would be much appreciated - all binary tools are in place.

jack9603301 added a comment.EditedJul 20 2020, 2:03 PM

@c-po Thank you. If I have the opportunity, I will consider and continue to pay attention to the implementation progress of NPT until it is implemented. For vyos, NPT is an optional technology, so that I can run normally without relying on NPT. Therefore, this is a relatively low priority task. If someone else implements it, thank you very much

If there are conditions, I will consider how to achieve it, but this is not the time

Although this document may not be a direct help, it may help us understand how to set up IPv6 NAT for nftables?

https://stephank.nl/p/2017-06-05-ipv6-on-production-docker.html

jack9603301 added a comment.EditedJul 29 2020, 4:38 PM

@c-po In my vyos, the following commands run successfully, and the rule settings are normal, but the rules are not tested to be effective and correct. For reference only, if I have time, I will open the eve ng simulation environment.

sudo nft add rule ip6 nat POSTROUTING ip6 saddr fc00:470:f1cd::/64 oif pppoe0 masquerade
XT target TCPMSS not found
table ip raw {
	chain PREROUTING {
		type filter hook prerouting priority raw; policy accept;
		counter packets 63046023 bytes 49431959896 jump VYATTA_CT_IGNORE
		counter packets 63046023 bytes 49431959896 jump VYATTA_CT_HELPER
		counter packets 63046023 bytes 49431959896 jump VYATTA_CT_HELPER
		counter packets 63046023 bytes 49431959896 jump VYATTA_CT_TIMEOUT
		counter packets 63046023 bytes 49431959896 jump VYATTA_CT_PREROUTING_HOOK
		counter packets 63046023 bytes 49431959896 jump NAT_CONNTRACK
		counter packets 0 bytes 0 jump FW_CONNTRACK
		counter packets 0 bytes 0 jump FW_STATE_POLICY_CONNTRACK
		counter packets 0 bytes 0 # NOTRACK
	}

	chain OUTPUT {
		type filter hook output priority raw; policy accept;
		counter packets 198316 bytes 29084773 jump VYATTA_CT_IGNORE
		counter packets 198316 bytes 29084773 jump VYATTA_CT_HELPER
		counter packets 198316 bytes 29084773 jump VYATTA_CT_HELPER
		counter packets 198316 bytes 29084773 jump VYATTA_CT_TIMEOUT
		counter packets 198316 bytes 29084773 jump VYATTA_CT_OUTPUT_HOOK
		counter packets 198316 bytes 29084773 jump NAT_CONNTRACK
		counter packets 0 bytes 0 jump FW_CONNTRACK
		counter packets 0 bytes 0 jump FW_STATE_POLICY_CONNTRACK
		counter packets 0 bytes 0 # NOTRACK
	}

	chain VYATTA_CT_IGNORE {
		counter packets 63244339 bytes 49461044669 return
	}

	chain VYATTA_CT_TIMEOUT {
		counter packets 63244339 bytes 49461044669 return
	}

	chain VYATTA_CT_HELPER {
		meta l4proto tcp tcp dport 1536 counter packets 0 bytes 0 # CT helper tns
		meta l4proto tcp tcp dport 1525 counter packets 0 bytes 0 # CT helper tns
		meta l4proto tcp tcp dport 1521 counter packets 0 bytes 0 # CT helper tns
		meta l4proto udp udp dport 111 counter packets 0 bytes 0 # CT helper rpc
		meta l4proto tcp tcp dport 111 counter packets 0 bytes 0 # CT helper rpc
		counter packets 126488678 bytes 98922089338 return
	}

	chain VYATTA_CT_PREROUTING_HOOK {
		counter packets 63046023 bytes 49431959896 return
	}

	chain VYATTA_CT_OUTPUT_HOOK {
		counter packets 198316 bytes 29084773 return
	}

	chain FW_STATE_POLICY_CONNTRACK {
		counter packets 0 bytes 0 accept
	}

	chain FW_CONNTRACK {
		counter packets 0 bytes 0 accept
	}

	chain NAT_CONNTRACK {
		counter packets 63244339 bytes 49461044669 accept
	}
}
table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy accept;
		counter packets 699116 bytes 174302694 jump VYATTA_PRE_FW_IN_HOOK
		counter packets 642357 bytes 166140910 jump VYATTA_FW_LOCAL_HOOK
		counter packets 613773 bytes 160133447 jump VYATTA_POST_FW_IN_HOOK
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
		counter packets 62734427 bytes 49387525702 jump VYATTA_PRE_FW_FWD_HOOK
		counter packets 2391807 bytes 328165500 jump VYATTA_FW_IN_HOOK
		counter packets 2391807 bytes 328165500 jump VYATTA_FW_OUT_HOOK
		counter packets 2391807 bytes 328165500 jump VYATTA_POST_FW_FWD_HOOK
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		counter packets 198255 bytes 29079749 jump VYATTA_PRE_FW_OUT_HOOK
		counter packets 62717 bytes 8527815 jump VYATTA_POST_FW_OUT_HOOK
	}

	chain VYATTA_PRE_FW_IN_HOOK {
		counter packets 699116 bytes 174302694 jump VYATTA_STATE_POLICY_IN_HOOK
		counter packets 642357 bytes 166140910 return
	}

	chain VYATTA_PRE_FW_FWD_HOOK {
		counter packets 62734427 bytes 49387525702 jump VYATTA_STATE_POLICY_FWD_HOOK
		counter packets 2391807 bytes 328165500 return
	}

	chain VYATTA_PRE_FW_OUT_HOOK {
		counter packets 198255 bytes 29079749 jump VYATTA_STATE_POLICY_OUT_HOOK
		counter packets 62717 bytes 8527815 return
	}

	chain VYATTA_POST_FW_IN_HOOK {
		counter packets 670532 bytes 168295231 accept
	}

	chain VYATTA_POST_FW_FWD_HOOK {
		counter packets 62734427 bytes 49387525702 accept
	}

	chain VYATTA_POST_FW_OUT_HOOK {
		counter packets 198255 bytes 29079749 accept
	}

	chain VYATTA_STATE_POLICY_IN_HOOK {
		ct state invalid counter packets 20228 bytes 832977 log prefix "[FW-STATE_POL-INVALID-A]"
		ct state invalid counter packets 20228 bytes 832977 jump VYATTA_POST_FW_IN_HOOK
		ct state established counter packets 35351 bytes 7188385 log prefix "[FW-STATE_POL-ESTABLISHED-A]"
		ct state established counter packets 35351 bytes 7188385 jump VYATTA_POST_FW_IN_HOOK
		ct state related counter packets 1180 bytes 140422 log prefix "[FW-STATE_POL-RELATED-A]"
		ct state related counter packets 1180 bytes 140422 jump VYATTA_POST_FW_IN_HOOK
		counter packets 642357 bytes 166140910 return
	}

	chain VYATTA_STATE_POLICY_OUT_HOOK {
		ct state invalid counter packets 1201 bytes 51142 log prefix "[FW-STATE_POL-INVALID-A]"
		ct state invalid counter packets 1201 bytes 51142 jump VYATTA_POST_FW_OUT_HOOK
		ct state established counter packets 99716 bytes 12337625 log prefix "[FW-STATE_POL-ESTABLISHED-A]"
		ct state established counter packets 99716 bytes 12337625 jump VYATTA_POST_FW_OUT_HOOK
		ct state related counter packets 34621 bytes 8163167 log prefix "[FW-STATE_POL-RELATED-A]"
		ct state related counter packets 34621 bytes 8163167 jump VYATTA_POST_FW_OUT_HOOK
		counter packets 62717 bytes 8527815 return
	}

	chain VYATTA_STATE_POLICY_FWD_HOOK {
		ct state invalid counter packets 178384 bytes 8681564 log prefix "[FW-STATE_POL-INVALID-A]"
		ct state invalid counter packets 178384 bytes 8681564 jump VYATTA_POST_FW_FWD_HOOK
		ct state established counter packets 60150157 bytes 49048144227 log prefix "[FW-STATE_POL-ESTABLISHED-A]"
		ct state established counter packets 60150157 bytes 49048144227 jump VYATTA_POST_FW_FWD_HOOK
		ct state related counter packets 14079 bytes 2534411 log prefix "[FW-STATE_POL-RELATED-A]"
		ct state related counter packets 14079 bytes 2534411 jump VYATTA_POST_FW_FWD_HOOK
		counter packets 2391807 bytes 328165500 return
	}

	chain VYATTA_FW_OUT_HOOK {
	}

	chain VYATTA_FW_IN_HOOK {
		iifname "pppoe0" counter packets 0 bytes 0 jump wan
	}

	chain VYATTA_FW_LOCAL_HOOK {
		iifname "pppoe0" counter packets 28744 bytes 6023923 jump wan-local
	}

	chain wan-local {
		ct state related,established counter packets 0 bytes 0 return comment "wan-local-1"
		meta l4proto icmp ct state new icmp type echo-request counter packets 0 bytes 0 return comment "wan-local-2"
		meta l4proto tcp ct state new tcp dport 22 # recent: UPDATE seconds: 60 hit_count: 4 name: wan-local-3 side: source mask: 255.255.255.255 counter packets 0 bytes 0 drop comment "wan-local-3"
		meta l4proto tcp ct state new tcp dport 22 # recent: SET name: wan-local-3 side: source mask: 255.255.255.255 counter packets 0 bytes 0 comment "wan-local-3"
		meta l4proto tcp ct state new counter packets 160 bytes 16460 return comment "wan-local-4"
		counter packets 28584 bytes 6007463 drop comment "wan-local-10000 default-action drop"
	}

	chain wan {
		ct state related,established counter packets 0 bytes 0 return comment "wan-1"
		meta l4proto tcp tcp dport 80 counter packets 0 bytes 0 drop comment "wan-2"
		meta l4proto tcp tcp dport 443 counter packets 0 bytes 0 drop comment "wan-3"
		counter packets 0 bytes 0 drop comment "wan-10000 default-action drop"
	}
}
table ip6 raw {
	chain PREROUTING {
		type filter hook prerouting priority raw; policy accept;
		counter packets 18742735 bytes 14741450142 jump VYATTA_CT_PREROUTING_HOOK
		counter packets 18742735 bytes 14741450142 jump FW_CONNTRACK
		counter packets 18742735 bytes 14741450142 jump FW_STATE_POLICY_CONNTRACK
		counter packets 0 bytes 0 # NOTRACK
	}

	chain OUTPUT {
		type filter hook output priority raw; policy accept;
		counter packets 1831599 bytes 800057711 jump VYATTA_CT_OUTPUT_HOOK
		counter packets 1831599 bytes 800057711 jump FW_CONNTRACK
		counter packets 1831599 bytes 800057711 jump FW_STATE_POLICY_CONNTRACK
		counter packets 0 bytes 0 # NOTRACK
	}

	chain VYATTA_CT_PREROUTING_HOOK {
		counter packets 18742735 bytes 14741450142 return
	}

	chain VYATTA_CT_OUTPUT_HOOK {
		counter packets 1831599 bytes 800057711 return
	}

	chain FW_STATE_POLICY_CONNTRACK {
		counter packets 20574334 bytes 15541507853 accept
	}

	chain FW_CONNTRACK {
		counter packets 20574334 bytes 15541507853 return
	}
}
table ip6 filter {
	chain INPUT {
		type filter hook input priority filter; policy accept;
		counter packets 1879125 bytes 243159154 jump VYATTA_PRE_FW_IN_HOOK
		counter packets 435768 bytes 32417230 jump VYATTA_FW_LOCAL_HOOK
		counter packets 435768 bytes 32417230 jump VYATTA_POST_FW_IN_HOOK
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
		counter packets 16872501 bytes 14498533369 jump VYATTA_PRE_FW_FWD_HOOK
		counter packets 534580 bytes 47841099 jump VYATTA_FW_IN_HOOK
		counter packets 534580 bytes 47841099 jump VYATTA_FW_OUT_HOOK
		counter packets 534580 bytes 47841099 jump VYATTA_POST_FW_FWD_HOOK
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		counter packets 1831599 bytes 800057711 jump VYATTA_PRE_FW_OUT_HOOK
		counter packets 328652 bytes 24416046 jump VYATTA_POST_FW_OUT_HOOK
	}

	chain VYATTA_PRE_FW_IN_HOOK {
		counter packets 1879125 bytes 243159154 jump VYATTA_STATE_POLICY_IN_HOOK
		counter packets 435768 bytes 32417230 return
	}

	chain VYATTA_PRE_FW_FWD_HOOK {
		counter packets 16872501 bytes 14498533369 jump VYATTA_STATE_POLICY_FWD_HOOK
		counter packets 534580 bytes 47841099 return
	}

	chain VYATTA_PRE_FW_OUT_HOOK {
		counter packets 1831599 bytes 800057711 jump VYATTA_STATE_POLICY_OUT_HOOK
		counter packets 328652 bytes 24416046 return
	}

	chain VYATTA_POST_FW_IN_HOOK {
		counter packets 1879125 bytes 243159154 accept
	}

	chain VYATTA_POST_FW_FWD_HOOK {
		counter packets 16872501 bytes 14498533369 accept
	}

	chain VYATTA_POST_FW_OUT_HOOK {
		counter packets 1831599 bytes 800057711 accept
	}

	chain VYATTA_STATE_POLICY_IN_HOOK {
		ct state invalid counter packets 3 bytes 360 log prefix "[FW-STATE_POL-INVALID-A]"
		ct state invalid counter packets 3 bytes 360 jump VYATTA_POST_FW_IN_HOOK
		ct state established counter packets 1442701 bytes 210668884 log prefix "[FW-STATE_POL-ESTABLISHED-A]"
		ct state established counter packets 1442701 bytes 210668884 jump VYATTA_POST_FW_IN_HOOK
		ct state related counter packets 653 bytes 72680 log prefix "[FW-STATE_POL-RELATED-A]"
		ct state related counter packets 653 bytes 72680 jump VYATTA_POST_FW_IN_HOOK
		counter packets 435768 bytes 32417230 return
	}

	chain VYATTA_STATE_POLICY_OUT_HOOK {
		ct state invalid counter packets 278 bytes 36261 log prefix "[FW-STATE_POL-INVALID-A]"
		ct state invalid counter packets 278 bytes 36261 jump VYATTA_POST_FW_OUT_HOOK
		ct state established counter packets 1493473 bytes 773873807 log prefix "[FW-STATE_POL-ESTABLISHED-A]"
		ct state established counter packets 1493473 bytes 773873807 jump VYATTA_POST_FW_OUT_HOOK
		ct state related counter packets 9196 bytes 1731597 log prefix "[FW-STATE_POL-RELATED-A]"
		ct state related counter packets 9196 bytes 1731597 jump VYATTA_POST_FW_OUT_HOOK
		counter packets 328652 bytes 24416046 return
	}

	chain VYATTA_STATE_POLICY_FWD_HOOK {
		ct state invalid counter packets 57479 bytes 3582409 log prefix "[FW-STATE_POL-INVALID-A]"
		ct state invalid counter packets 57479 bytes 3582409 jump VYATTA_POST_FW_FWD_HOOK
		ct state established counter packets 16250493 bytes 14443518797 log prefix "[FW-STATE_POL-ESTABLISHED-A]"
		ct state established counter packets 16250493 bytes 14443518797 jump VYATTA_POST_FW_FWD_HOOK
		ct state related counter packets 29949 bytes 3591064 log prefix "[FW-STATE_POL-RELATED-A]"
		ct state related counter packets 29949 bytes 3591064 jump VYATTA_POST_FW_FWD_HOOK
		counter packets 534580 bytes 47841099 return
	}

	chain VYATTA_FW_OUT_HOOK {
	}

	chain VYATTA_FW_IN_HOOK {
		iifname "pppoe0" counter packets 199 bytes 74758 jump WAN-IN
	}

	chain VYATTA_FW_LOCAL_HOOK {
		iifname "pppoe0" counter packets 1513 bytes 159802 jump WAN-LOCAL
	}

	chain WAN-IN {
		meta l4proto tcp tcp dport 22 counter packets 0 bytes 0 drop comment "WAN-IN-1"
		counter packets 199 bytes 74758 return comment "WAN-IN-10000 default-action accept"
	}

	chain WAN-LOCAL {
		meta l4proto tcp tcp dport 22 counter packets 0 bytes 0 drop comment "WAN-LOCAL-1"
		meta l4proto tcp tcp dport 80 counter packets 0 bytes 0 drop comment "WAN-LOCAL-2"
		meta l4proto tcp tcp dport 443 counter packets 0 bytes 0 drop comment "WAN-LOCAL-3"
		counter packets 1513 bytes 159802 return comment "WAN-LOCAL-10000 default-action accept"
	}
}
table ip6 mangle {
	chain PREROUTING {
		type filter hook prerouting priority mangle; policy accept;
		counter packets 18742735 bytes 14741450142 jump VYOS_DNPT_HOOK
	}

	chain INPUT {
		type filter hook input priority mangle; policy accept;
	}

	chain FORWARD {
		type filter hook forward priority mangle; policy accept;
		counter packets 16872501 bytes 14498533369 jump VYOS_FW_OPTIONS
	}

	chain OUTPUT {
		type route hook output priority mangle; policy accept;
	}

	chain POSTROUTING {
		type filter hook postrouting priority mangle; policy accept;
		counter packets 18710043 bytes 15299540488 jump VYOS_SNPT_HOOK
	}

	chain VYOS_DNPT_HOOK {
		counter packets 18742735 bytes 14741450142 return
	}

	chain VYOS_SNPT_HOOK {
		counter packets 18710043 bytes 15299540488 return
	}

	chain VYOS_FW_OPTIONS {
		oifname "pppoe0" meta l4proto tcp tcp flags & (syn|rst) == syn counter packets 95385 bytes 7575456 # TCPMSS set 1452
	}
}
table ip6 nat {
	chain PREROUTING {
		type nat hook prerouting priority dstnat; policy accept;
		counter packets 484189 bytes 43387579 jump VYOS_DNPT_HOOK
	}

	chain INPUT {
		type nat hook input priority 100; policy accept;
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		counter packets 439371 bytes 38179628 jump VYOS_SNPT_HOOK
		ip6 saddr fc00:470:f1cd::/64 oif "pppoe0" masquerade
	}

	chain OUTPUT {
		type nat hook output priority -100; policy accept;
	}

	chain VYOS_DNPT_HOOK {
		counter packets 484189 bytes 43387579 return
	}

	chain VYOS_SNPT_HOOK {
		counter packets 439371 bytes 38179628 return
	}
}
table ip nat {
	chain PREROUTING {
		type nat hook prerouting priority dstnat; policy accept;
	}

	chain INPUT {
		type nat hook input priority 100; policy accept;
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		oifname "pppoe0" ip saddr 0.0.0.0/0 counter packets 1409244 bytes 96692581 log prefix "[NAT-DST-1-MASQ]" comment "DST-NAT-1"
		oifname "pppoe0" ip saddr 0.0.0.0/0 counter packets 1409244 bytes 96692581 masquerade comment "DST-NAT-1"
	}

	chain OUTPUT {
		type nat hook output priority -100; policy accept;
	}

	chain VYATTA_PRE_DNAT_HOOK {
	}

	chain VYATTA_PRE_SNAT_HOOK {
	}
}
table ip mangle {
	chain PREROUTING {
		type filter hook prerouting priority mangle; policy accept;
	}

	chain INPUT {
		type filter hook input priority mangle; policy accept;
	}

	chain FORWARD {
		type filter hook forward priority mangle; policy accept;
		counter packets 62734426 bytes 49387525626 jump VYOS_FW_OPTIONS
	}

	chain OUTPUT {
		type route hook output priority mangle; policy accept;
	}

	chain POSTROUTING {
		type filter hook postrouting priority mangle; policy accept;
	}

	chain VYOS_FW_OPTIONS {
		oifname "pppoe0" meta l4proto tcp tcp flags & (syn|rst) == syn counter packets 424402 bytes 25463848
	}
}
jack9603301 added a comment.EditedJul 31 2020, 10:54 AM

@c-po This is a simple draft of my current implementation of NPT. At present, I haven't tested it, and I haven't applied for merger. I can send it here for some discussion.

https://github.com/jack9603301/vyos-1x/blob/nptv6/data/templates/firewall/nftables-nat.tmpl

diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl
index 0c29f536..64f7b699 100644
--- a/data/templates/firewall/nftables-nat.tmpl
+++ b/data/templates/firewall/nftables-nat.tmpl
@@ -1,7 +1,8 @@
 #!/usr/sbin/nft -f
 
 # Start with clean NAT table
-flush table nat
+flush table ip nat
+flush table ip6 nat
 
 {% if helper_functions == 'remove' %}
 {# NAT if going to be disabled - remove rules and targets from nftables #}
@@ -14,6 +15,14 @@ flush table nat
 
 delete chain ip raw NAT_CONNTRACK
 
+{%   set base_command = "delete rule ip6 raw" %}
+{{ base_command }} PREROUTING handle {{ pre_ct_ignore }}
+{{ base_command }} OUTPUT     handle {{ out_ct_ignore }}
+{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
+{{ base_command }} OUTPUT     handle {{ out_ct_conntrack }}
+
+delete chain ip6 raw NAT_CONNTRACK
+
 {% elif helper_functions == 'add' %}
 {# NAT if enabled - add targets to nftables #}
 add chain ip raw NAT_CONNTRACK
@@ -25,8 +34,62 @@ add rule ip raw NAT_CONNTRACK counter accept
 {{ base_command }} OUTPUT     position {{ out_ct_ignore }}    counter jump VYATTA_CT_HELPER
 {{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
 {{ base_command }} OUTPUT     position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
+
+{%   set base_command = "add rule ip6 raw" %}
+
+{{ base_command }} PREROUTING position {{ pre_ct_ignore }}    counter jump VYATTA_CT_HELPER
+{{ base_command }} OUTPUT     position {{ out_ct_ignore }}    counter jump VYATTA_CT_HELPER
+{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
+{{ base_command }} OUTPUT     position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
+
+{# NPT if going to be disabled - remove rules and targets from nftables #}
+
+
+
+
 {% endif %}
 
+{% macro nptv6_rule(rule, chain) %}
+{%   set src_prefix  = "ip saddr " + rule.source_prefix if rule.source_prefix %}
+{%   if chain == "POSTROUTING" %}
+{%     set interface = " oifname \"" + rule.interface_out + "\"" if rule.interface_out is defined and rule.interface_out != 'any' else '' %}
+{%     if rule.translation_prefix == 'masquerade' %}
+{%       set trns_prefix = rule.translation_prefix %}
+{%     else %}
+{%       set trns_prefix = "snat to " + rule.translation_prefix %}
+{%     endif %}
+{%   endif %}
+{%   set comment   = "NPT-NAT-" + rule.number %}
+{%   if rule.log %}
+{%     set base_log = "[NPT-DST-" + rule.number %}
+{%     if rule.translation_prefix == 'masquerade' %}
+{%       set log = base_log + "-MASQ]" %}
+{%     else %}
+{%       set log = base_log + "]" %}
+{%     endif %}
+{%   endif %}
+{%   set output = "add rule ip6 nat " + chain + interface %}
+{#   Count packets #}
+{%     set output = output + " counter" %}
+
+{#   Special handling of log option, we must repeat the entire rule before the #}
+{#   NAT translation options are added, this is essential                      #}
+{%   if log %}
+{%     set log_output = output + " log prefix \"" + log + "\" comment \"" + comment + "\"" %}
+{%   endif %}
+
+{%   if trns_prefix %}
+{%     set output = output + " " + trns_prefix %}
+{%   endif %}
+
+{%   if comment %}
+{%     set output = output + " comment \"" + comment + "\"" %}
+{%   endif %}
+
+{{ log_output if log_output }}
+{{ output }}
+{% endmacro %}
+
 {% macro nat_rule(rule, chain) %}
 {%   set src_addr  = "ip saddr " + rule.source_address if rule.source_address %}
 {%   set dst_addr  = "ip daddr " + rule.dest_address if rule.dest_address %}
@@ -155,3 +218,10 @@ add rule ip raw NAT_CONNTRACK counter accept
 {% for rule in source if not rule.disabled -%}
 {{ nat_rule(rule, 'POSTROUTING') }}
 {% endfor %}
+
+#
+# NPTv6 rules build up here
+#
+{% for rule in nptv6 if not rule.disabled -%}
+{{ nptv6_rule(rule, 'POSTROUTING') }}
+{% endfor %}
diff --git a/interface-definitions/nat.xml.in b/interface-definitions/nat.xml.in
index f8415b7c..e44a5508 100644
--- a/interface-definitions/nat.xml.in
+++ b/interface-definitions/nat.xml.in
@@ -90,6 +90,9 @@
                   <leafNode name="prefix">
                     <properties>
                       <help>IPv6 prefix to be translated</help>
+                      <completionHelp>
+                        <list>masquerade</list>
+                      </completionHelp>
                       <valueHelp>
                         <format>ipv6net</format>
                         <description>IPv6 prefix</description>
@@ -97,6 +100,10 @@
                       <constraint>
                         <validator name="ipv6-prefix"/>
                       </constraint>
+                      <valueHelp>
+                        <format>masquerade</format>
+                        <description>NPT to the primary address of outbound-interface</description>
+                      </valueHelp>
                     </properties>
                   </leafNode>
                 </children>

I didn't get any specific help. The modified pudding was set up based on the trial and limited third-party data here, and it needs to be fully tested.

jack9603301 changed the task status from Open to In progress.Jul 31 2020, 11:00 AM
jack9603301 claimed this task.
c-po added a comment.EditedJul 31 2020, 2:04 PM

Well I would just have plumbed up the commands locally before doing any templating. Please keep us updated if it works.

Please note NPT is not about masquerading, it is about translating an entire prefix 1:1

This comment was removed by jack9603301.
This comment was removed by jack9603301.

@c-po It has been revised as follows:

diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl
index 0c29f536..0a66098a 100644
--- a/data/templates/firewall/nftables-nat.tmpl
+++ b/data/templates/firewall/nftables-nat.tmpl
@@ -1,7 +1,8 @@
 #!/usr/sbin/nft -f
 
 # Start with clean NAT table
-flush table nat
+flush table ip nat
+flush table ip6 nat
 
 {% if helper_functions == 'remove' %}
 {# NAT if going to be disabled - remove rules and targets from nftables #}
@@ -14,6 +15,14 @@ flush table nat
 
 delete chain ip raw NAT_CONNTRACK
 
+{%   set base_command = "delete rule ip6 raw" %}
+{{ base_command }} PREROUTING handle {{ pre_ct_ignore }}
+{{ base_command }} OUTPUT     handle {{ out_ct_ignore }}
+{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
+{{ base_command }} OUTPUT     handle {{ out_ct_conntrack }}
+
+delete chain ip6 raw NAT_CONNTRACK
+
 {% elif helper_functions == 'add' %}
 {# NAT if enabled - add targets to nftables #}
 add chain ip raw NAT_CONNTRACK
@@ -25,8 +34,67 @@ add rule ip raw NAT_CONNTRACK counter accept
 {{ base_command }} OUTPUT     position {{ out_ct_ignore }}    counter jump VYATTA_CT_HELPER
 {{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
 {{ base_command }} OUTPUT     position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
+
+{%   set base_command = "add rule ip6 raw" %}
+
+{{ base_command }} PREROUTING position {{ pre_ct_ignore }}    counter jump VYATTA_CT_HELPER
+{{ base_command }} OUTPUT     position {{ out_ct_ignore }}    counter jump VYATTA_CT_HELPER
+{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
+{{ base_command }} OUTPUT     position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
+
+{# NPT if going to be disabled - remove rules and targets from nftables #}
+
+
+
+
 {% endif %}
 
+{% macro nptv6_rule(rule, chain) %}
+
+{%   if chain == "PREROUTING" %}
+{%     set src_prefix  = "ip saddr " + rule.translation_prefix if rule.translation_prefix %}
+{%     set interface = " iifname \"" + rule.interface_out + "\"" if rule.interface_out is defined and rule.interface_out != 'any' else '' %}
+{%     set trns_prefix = "dnat to " + rule.source_prefix %}
+{%   elif chain == "POSTROUTING" %}
+{%     set src_prefix  = "ip saddr " + rule.source_prefix if rule.source_prefix %}
+{%     set interface = " oifname \"" + rule.interface_out + "\"" if rule.interface_out is defined and rule.interface_out != 'any' else '' %}
+{%     if rule.translation_prefix == 'masquerade' %}
+{%       set trns_prefix = rule.translation_prefix %}
+{%     else %}
+{%       set trns_prefix = "snat to " + rule.translation_prefix %}
+{%     endif %}
+{%   endif %}
+{%   set comment   = "NPT-NAT-" + rule.number %}
+{%   if rule.log %}
+{%     set base_log = "[NPT-DST-" + rule.number %}
+{%     if rule.translation_prefix == 'masquerade' %}
+{%       set log = base_log + "-MASQ]" %}
+{%     else %}
+{%       set log = base_log + "]" %}
+{%     endif %}
+{%   endif %}
+{%   set output = "add rule ip6 nat " + chain + interface %}
+{#   Count packets #}
+{%     set output = output + " counter" %}
+
+{#   Special handling of log option, we must repeat the entire rule before the #}
+{#   NAT translation options are added, this is essential                      #}
+{%   if log %}
+{%     set log_output = output + " log prefix \"" + log + "\" comment \"" + comment + "\"" %}
+{%   endif %}
+
+{%   if trns_prefix %}
+{%     set output = output + " " + trns_prefix %}
+{%   endif %}
+
+{%   if comment %}
+{%     set output = output + " comment \"" + comment + "\"" %}
+{%   endif %}
+
+{{ log_output if log_output }}
+{{ output }}
+{% endmacro %}
+
 {% macro nat_rule(rule, chain) %}
 {%   set src_addr  = "ip saddr " + rule.source_address if rule.source_address %}
 {%   set dst_addr  = "ip daddr " + rule.dest_address if rule.dest_address %}
@@ -155,3 +223,11 @@ add rule ip raw NAT_CONNTRACK counter accept
 {% for rule in source if not rule.disabled -%}
 {{ nat_rule(rule, 'POSTROUTING') }}
 {% endfor %}
+
+#
+# NPTv6 rules build up here
+#
+{% for rule in nptv6 if not rule.disabled -%}
+{{ nptv6_rule(rule, 'PREROUTING') }}
+{{ nptv6_rule(rule, 'POSTROUTING') }}
+{% endfor %}
diff --git a/interface-definitions/nat.xml.in b/interface-definitions/nat.xml.in
index f8415b7c..e44a5508 100644
--- a/interface-definitions/nat.xml.in
+++ b/interface-definitions/nat.xml.in
@@ -90,6 +90,9 @@
                   <leafNode name="prefix">
                     <properties>
                       <help>IPv6 prefix to be translated</help>
+                      <completionHelp>
+                        <list>masquerade</list>
+                      </completionHelp>
                       <valueHelp>
                         <format>ipv6net</format>
                         <description>IPv6 prefix</description>
@@ -97,6 +100,10 @@
                       <constraint>
                         <validator name="ipv6-prefix"/>
                       </constraint>
+                      <valueHelp>
+                        <format>masquerade</format>
+                        <description>NPT to the primary address of outbound-interface</description>
+                      </valueHelp>
                     </properties>
                   </leafNode>
                 </children>

@c-po According to H3C and the third-party information on the Internet, NPT is also called nat66. Nat66 is actually the SNAT and DNAT implementation of IPv6, and implements 1-to-1 mapping and prefix address translation. Since there is no separate configuration directory for these two directions in the configuration, this draft implements two directions. Tomorrow, we will try to modify the configuration path according to the document of H3C device, add the diff of the draft, and then propose Submit merger request.

jack9603301 added a comment.EditedJul 31 2020, 4:02 PM

@c-po According to H3C, the relevant operations are as follows:

nat66 prefix source original-ipv6-prefix prefix-length translated-ipv6-prefix prefix-length
nat66 prefix destination original-ipv6-prefix prefix-length translated-ipv6-prefix prefix-length

Nat66 can also be divided into SNAT and DNAT

According to the current configuration path of vyos, there are two solutions:

a) Change the command of NPT to add a subset, as follows:

set nat nptv6 source
set nat nptv6 destination

b) Introduce a new top-level command set nat66

set nat66 source
set nat66 destination

@c-po Can you give me a better suggestion? I prefer to use scheme b, because it can modify the command code of NAT as little as possible.

@c-po

This PR will provide experimental nat66 support, which needs to be tested

https://github.com/vyos/vyos-1x/pull/520

jack9603301 updated the task description. (Show Details)Aug 1 2020, 8:41 AM
jack9603301 triaged this task as Normal priority.Aug 1 2020, 8:52 AM
jack9603301 changed Difficulty level from Unknown (require assessment) to Normal (likely a few hours).
jack9603301 changed Version from - to vyos 1.3.
jack9603301 changed Is it a breaking change? from Unspecified (possibly destroys the router) to Config syntax change (non-migratable).
c-po added a comment.Aug 1 2020, 8:53 AM

I ask myself if it not would make more sense to get the prefix translation working again and then add new features here?

Also such a new feature should earn a smoketest which verifies the features functionality on a live system: https://github.com/vyos/vyos-smoketest/

@c-po The related nftables policy in the local environment test did not find syntax problems, only need to be tested to verify the effectiveness of the function, so I call it experimental support.

There is no additional driver or related software, and its script is modified by Nat script. For example, nftables policy is OK, and it should work normally

If nat66 functions properly, vyos will support NPT prefix conversion technology

I don't use this kind of tool to test his nftables policy, but I'm used to testing it by manually configuring nftables and replacing my nftables template file with that of the vyos system. Vyos did not report errors during its build configuration.

It is hoped that this implementation can make the prefix translation work again. Refer to the relevant operation of H3C equipment and fully support nat66

@thomas-mangin As mentioned in my comments, I refer to the configuration structure of H3C. In the original command structure, nptv6 does not support the division of SNAT and DNAT. In order to implement nat66, I separated it for the following reasons:

  1. I can modify it according to the existing script of NAT, and I can modify it less nat.py , I created nat66 and the independent nftables-nat66.tmpl to complete the implementation of nat66.
  2. It can fully support the configuration of SNAT and DNAT in nat66. If users do not need SNAT or DNAT, it should not take effect by default.

Note: since I am in China, I said that the H3C device document I read is in Chinese, so I didn't want to put it up at first, because it may increase your reading difficulty. If you can, please refer to (H3C supports English version, but I haven't found the corresponding page of English version for the moment).

http://www.h3c.com/cn/d_201911/1246667_30005_0.htm#_Toc25743038

This comment was removed by jack9603301.

@thomas-mangin Maybe it's better to discuss it here

Please check the comments above

jack9603301 updated the task description. (Show Details)Aug 1 2020, 10:17 AM
jack9603301 updated the task description. (Show Details)Aug 1 2020, 10:32 AM
jack9603301 added a comment.EditedAug 4 2020, 6:29 AM

Use cases for sNPT testing

  • R2
set interfaces ethernet eth0 address 'dhcp'
set interfaces ethernet eth0 ipv6 address autoconf
set interfaces ethernet eth1 address 'fc00::1/64'
set interfaces loopback lo address '127.0.0.1/8'
set interfaces loopback lo address '::1/128'
set interfaces tunnel tun1 address '2001::2/64'
set interfaces tunnel tun1 encapsulation 'ip6gre'
set interfaces tunnel tun1 local-ip 'fc00:470:f1cd:101:b4e8:3aff:fe31:2482'
set interfaces tunnel tun1 remote-ip 'fc00:470:f1cd::1'
set nat66 destination rule 1 outbound-interface 'any'
set nat66 destination rule 1 source prefix '2001::/64'
set nat66 destination rule 1 translation prefix 'fc00::/64'
set nat66 source rule 1 log
set nat66 source rule 1 outbound-interface 'any'
set nat66 source rule 1 source prefix 'fc00::/64'
set nat66 source rule 1 translation prefix '2001::/64'
set service router-advert interface eth1 prefix ::/0
set service ssh listen-address '::'
set service ssh listen-address '0.0.0.0'
set system config-management commit-revisions '100'
set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$w7O7gqm6xhfbiTj$5V44o4InKK4osyIaz5us9NuSOL9X8azG7clu5h6HJIzgTV0XQQs64KEm0fTSwWRj8.80Z2dNMjciWciicVYRU.'
set system login user vyos authentication plaintext-password ''
set system ntp server 0.pool.ntp.org
set system ntp server 1.pool.ntp.org
set system ntp server 2.pool.ntp.org
set system syslog global facility all level 'info'
set system syslog global facility protocols level 'debug'
  • R1
set interfaces tunnel tun1 address '2001::1/64'
set interfaces tunnel tun1 encapsulation 'ip6gre'
set interfaces tunnel tun1 local-ip 'fc00:470:f1cd::1'
set interfaces tunnel tun1 remote-ip 'fc00:470:f1cd:101:b4e8:3aff:fe31:2482'
  • Perform the operation in PC1
ping 2001::1
  • R2 packet capture
04:37:16.432761 IP6 (flowlabel 0xa22aa, hlim 64, next-header ICMPv6 (58) payload length: 64) fc00::2477:c2ff:fe2f:d532 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 18
04:37:16.432804 IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 18
	IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 18
	IP6 (flowlabel 0x67e06, hlim 64, next-header ICMPv6 (58) payload length: 64) 2001::1 > 2001::246b:739: [icmp6 sum ok] ICMP6, echo reply, seq 18
04:37:16.434477 IP6 (flowlabel 0x67e06, hlim 64, next-header ICMPv6 (58) payload length: 64) 2001::1 > 2001::246b:739: [icmp6 sum ok] ICMP6, echo reply, seq 18
04:37:16.434524 IP6 (flowlabel 0x67e06, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::1 > fc00::2477:c2ff:fe2f:d532: [icmp6 sum ok] ICMP6, echo reply, seq 18
04:37:17.433964 IP6 (flowlabel 0xa22aa, hlim 64, next-header ICMPv6 (58) payload length: 64) fc00::2477:c2ff:fe2f:d532 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 19
04:37:17.433996 IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 19
	IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 19
	IP6 (flowlabel 0x67e06, hlim 64, next-header ICMPv6 (58) payload length: 64) 2001::1 > 2001::246b:739: [icmp6 sum ok] ICMP6, echo reply, seq 19
04:37:17.435694 IP6 (flowlabel 0x67e06, hlim 64, next-header ICMPv6 (58) payload length: 64) 2001::1 > 2001::246b:739: [icmp6 sum ok] ICMP6, echo reply, seq 19
04:37:17.435742 IP6 (flowlabel 0x67e06, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::1 > fc00::2477:c2ff:fe2f:d532: [icmp6 sum ok] ICMP6, echo reply, seq 19
04:37:18.435273 IP6 (flowlabel 0xa22aa, hlim 64, next-header ICMPv6 (58) payload length: 64) fc00::2477:c2ff:fe2f:d532 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 20
04:37:18.435320 IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 20
	IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 20
	IP6 (flowlabel 0x67e06, hlim 64, next-header ICMPv6 (58) payload length: 64) 2001::1 > 2001::246b:739: [icmp6 sum ok] ICMP6, echo reply, seq 20
04:37:18.437310 IP6 (flowlabel 0x67e06, hlim 64, next-header ICMPv6 (58) payload length: 64) 2001::1 > 2001::246b:739: [icmp6 sum ok] ICMP6, echo reply, seq 20
04:37:18.437356 IP6 (flowlabel 0x67e06, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::1 > fc00::2477:c2ff:fe2f:d532: [icmp6 sum ok] ICMP6, echo reply, seq 20
04:37:19.436783 IP6 (flowlabel 0xa22aa, hlim 64, next-header ICMPv6 (58) payload length: 64) fc00::2477:c2ff:fe2f:d532 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 21
04:37:19.436823 IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 21
	IP6 (flowlabel 0xa22aa, hlim 63, next-header ICMPv6 (58) payload length: 64) 2001::246b:739 > 2001::1: [icmp6 sum ok] ICMP6, echo request, seq 21
^C111 packets captured
179 packets received by filter
0 packets dropped by kernel

Test cases for DNAT R2

set interfaces ethernet eth0 address 'dhcp'
set interfaces ethernet eth0 ipv6 address autoconf
set interfaces ethernet eth1 address 'fc00::1/64'
set interfaces loopback lo address '127.0.0.1/8'
set interfaces loopback lo address '::1/128'
set interfaces tunnel tun1 address '2001::2/64'
set interfaces tunnel tun1 encapsulation 'ip6gre'
set interfaces tunnel tun1 local-ip 'fc00:470:f1cd:101:b4e8:3aff:fe31:2482'
set interfaces tunnel tun1 remote-ip 'fc00:470:f1cd::1'
set nat66 destination rule 1 destination prefix '2001::246b:739/128'
set nat66 destination rule 1 outbound-interface 'any'
set nat66 destination rule 1 translation prefix 'fc00::2477:c2ff:fe2f:d532'
set nat66 source rule 1 log
set nat66 source rule 1 outbound-interface 'any'
set nat66 source rule 1 source prefix 'fc00::/64'
set nat66 source rule 1 translation prefix '2001::/64'
set service router-advert interface eth1 prefix ::/0
set service ssh listen-address '::'
set service ssh listen-address '0.0.0.0'
set system config-management commit-revisions '100'
set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$w7O7gqm6xhfbiTj$5V44o4InKK4osyIaz5us9NuSOL9X8azG7clu5h6HJIzgTV0XQQs64KEm0fTSwWRj8.80Z2dNMjciWciicVYRU.'
set system login user vyos authentication plaintext-password ''
set system ntp server 0.pool.ntp.org
set system ntp server 1.pool.ntp.org
set system ntp server 2.pool.ntp.org
set system syslog global facility all level 'info'
set system syslog global facility protocols level 'debug'

The dnat66 communication of this instance is successful

I have consulted some documents of vyos about DNAT of IPv4, and I don't understand why there seems to be SNAT content in the DNAT IPv4 syntax of vyos, and what is the meaning of supporting the prefix format address setting of dsddr in DNAT syntax? Is there something wrong with me?

vyos@vyos# set nat destination rule 1 
Possible completions:
   description  Rule description
 > destination  NAT destination parameters
   disable      Disable NAT rule
   exclude      Exclude packets matching this rule from NAT
   inbound-interface
                Inbound interface of NAT traffic
   log          NAT rule logging
   protocol     Protocol to NAT
 > source       NAT source parameters
 > translation  Inside NAT IP (destination NAT only)
[edit]
vyos@vyos# set nat destination rule 1 destination 
Possible completions:
   address      IP address, subnet, or range
   port         Port number
[edit]
vyos@vyos# set nat destination rule 1 destination pre
  Configuration path: nat destination rule 1 destination [pre] is not valid
[edit]
vyos@vyos# set nat destination rule 1 destination pre
  Configuration path: nat destination rule 1 destination [pre] is not valid
[edit]
vyos@vyos# set nat destination rule 1 destination port 
Possible completions:
   1-65535      Numeric IP port
   start-end    Numbered port range (e.g., 1001-1005)
Multiple destination ports can be specified as a comma-separated list.
The whole list can also be negated using '!'.
For example: '!22,telnet,http,123,1001-1005'
[edit]
vyos@vyos# set nat destination rule 1 destination address 
Possible completions:
   <x.x.x.x>    IPv4 address to match
   <x.x.x.x/x>  IPv4 prefix to match
   <x.x.x.x>-<x.x.x.x>
                IPv4 address range to match
   !<x.x.x.x>   Match everything except the specified address
   !<x.x.x.x/x> Match everything except the specified prefix
   !<x.x.x.x>-<x.x.x.x>
                Match everything except the specified range
[edit]
vyos@vyos# set nat destination rule 1 translation address 
Possible completions:
   <x.x.x.x>    IPv4 address to match
   <x.x.x.x/x>  IPv4 prefix to match
   <x.x.x.x>-<x.x.x.x>
                IPv4 address range to match
[edit]
vyos@vyos# set nat destination rule 1 translation address ^C
[edit]
jack9603301 updated the task description. (Show Details)Aug 4 2020, 8:20 AM

Thank you for writing some testing code using the smoketest repository. It may take a few working days for anyone to come back to you.

jack9603301 added a comment.EditedAug 7 2020, 3:23 PM

GNS3 virtualization network verification passed

After verification, the strategy can convert sNPT and dnpt normally

The sNPT strategy of router R2 is as follows:

set interfaces bridge br1 address 'fc00:2::1/64'
set interfaces bridge br1 member interface eth4
set interfaces ethernet eth3 address 'fc00:1::2/64'
set interfaces ethernet eth3 description 'r1'
set interfaces ethernet eth3 hw-id '0c:64:81:33:34:00'
set interfaces ethernet eth4 description 'pc2'
set interfaces ethernet eth4 hw-id '0c:64:81:33:34:01'
set interfaces loopback lo
set interfaces tunnel tun1 address '2001::2/64'
set interfaces tunnel tun1 encapsulation 'ip6gre'
set interfaces tunnel tun1 local-ip 'fc00:1::2'
set interfaces tunnel tun1 remote-ip 'fc00:1::1'
set nat66 source rule 1 outbound-interface 'any'
set nat66 source rule 1 source prefix 'fc00:2::/64'
set nat66 source rule 1 translation prefix '2001::/64'
set service router-advert interface br1 prefix ::/0
set system config-management commit-revisions '100'
set system console device ttyS0 speed '115200'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$4QJ4QA..QnoGw$1gXLHmy9QSZUU/Y9bfjSMZ2tqXgO1lIeqzaIlrRif3Tm4DaHninRagoBSPUVC4hh0imiJQ7DGBbS4blUsn6On1'
set system login user vyos authentication plaintext-password ''
set system ntp server 0.pool.ntp.org
set system ntp server 1.pool.ntp.org
set system ntp server 2.pool.ntp.org
set system syslog global facility all level 'info'
set system syslog global facility protocols level 'debug'
jack9603301 updated the task description. (Show Details)Aug 10 2020, 11:03 AM
jack9603301 updated the task description. (Show Details)Aug 15 2020, 3:58 PM
jack9603301 updated the task description. (Show Details)Aug 17 2020, 1:27 PM
jack9603301 changed the task status from In progress to On hold.Aug 22 2020, 2:09 PM

The SNPT and DNPT functions are basically implemented, but because they have not been reviewed and approved for the time being, they enter the hold state, waiting for processing and discussion

If possible, please conduct further review. If necessary, I can send my test iso to testers to help the community test and improve functions

jack9603301 added a comment.EditedAug 23 2020, 10:10 AM

As described in T2814, under 5.1, nft_chain_nat_ipv6 will be merged into nft_chain_nat, I have updated pr to support this change, but like T2814, it has not been tested

from distutils.version import LooseVersion
import platform
if LooseVersion(platform.release()) > LooseVersion("5.1"):
    k_mod = ['nft_nat', 'nft_chain_nat']
else:
    k_mod = ['nft_nat', 'nft_chain_nat_ipv6']

The updated code was successfully tested on the virtual machine, and 5.1 has not been tested yet, waiting for the release of kernel 5.1

jack9603301 renamed this task from Support nptv6 to Support NAT for ipv6(NPT).Aug 31 2020, 10:50 AM
jack9603301 updated the task description. (Show Details)Aug 31 2020, 11:09 AM
jack9603301 changed the task status from On hold to Blocked.Sep 2 2020, 11:34 AM
jack9603301 changed the task status from Blocked to On hold.Sep 2 2020, 11:39 AM

Hey guys, I am testing nat66 from @jack9603301 which @c-po provided the ISO for me today (VyOS 1.3-nat66-202009161808)

I have a remote access "road warrior" Wireguard instance running, which assigns clients addresses from fc00:dead:beef::/64. I have a nat66 rule in place when traffic should leave my R2 VyOS Router.

The nat66 source rule does translate prefix as expected, but the trouble is my upstream router (R1) is unable to reply from it's interface on the same translated-prefix.

Upstream R1 is unable to reply to PC2.

Attached is a simple diagram for my use case, and the configuration for R2, and laptop ping tests.

set firewall all-ping 'enable'
set firewall broadcast-ping 'disable'
set firewall config-trap 'disable'
set firewall ipv6-name OUTSIDE_IN_V6 default-action 'drop'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1000 action 'accept'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1000 description 'IPv6 Allow established/related'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1000 state established 'enable'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1000 state related 'enable'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1100 action 'drop'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1100 description 'Drop invalid state'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1100 state established 'disable'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1100 state invalid 'enable'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1100 state new 'disable'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1100 state related 'disable'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1200 action 'accept'
set firewall ipv6-name OUTSIDE_IN_V6 rule 1200 protocol 'icmpv6'
set firewall ipv6-name OUTSIDE_IN_V6 rule 9999 action 'accept'
set firewall ipv6-name OUTSIDE_IN_V6 rule 9999 protocol 'ipv6-icmp'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 default-action 'drop'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1000 action 'accept'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1000 description 'IPv6 Allow established/related'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1000 state established 'enable'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1000 state related 'enable'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1100 action 'drop'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1100 description 'Drop invalid state'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1100 state established 'disable'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1100 state invalid 'enable'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1100 state new 'disable'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1100 state related 'disable'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1200 action 'accept'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1200 protocol 'icmpv6'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1300 action 'accept'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1300 destination port '9922'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1300 protocol 'tcp'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1400 action 'accept'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1400 destination port '53'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 1400 protocol 'udp'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 9999 action 'accept'
set firewall ipv6-name OUTSIDE_TO_RTR_V6 rule 9999 protocol 'ipv6-icmp'
set firewall ipv6-receive-redirects 'disable'
set firewall ipv6-src-route 'disable'
set firewall ip-src-route 'disable'
set firewall log-martians 'enable'
set firewall receive-redirects 'disable'
set firewall send-redirects 'enable'
set firewall source-validation 'disable'
set firewall syn-cookies 'enable'
set firewall twa-hazards-protection 'disable'
set interfaces ethernet eth0 description 'WAN1 - 10G'
set interfaces ethernet eth0 firewall in ipv6-name 'OUTSIDE_IN_V6'
set interfaces ethernet eth0 firewall local ipv6-name 'OUTSIDE_TO_RTR_V6'
set interfaces ethernet eth0 hw-id 'XX:XX:XX:XX:XX:2f'
set interfaces ethernet eth0 smp-affinity 'auto'
set interfaces ethernet eth1 address 'xxxx:xxxx:16:10::3/64'
set interfaces ethernet eth1 description 'WAN2 - 1G'
set interfaces ethernet eth1 firewall in ipv6-name 'OUTSIDE_IN_V6'
set interfaces ethernet eth1 firewall local ipv6-name 'OUTSIDE_TO_RTR_V6'
set interfaces ethernet eth1 hw-id 'XX:XX:XX:XX:XX:3f'
set interfaces ethernet eth1 smp-affinity 'auto'
set interfaces ethernet eth3 description 'Inside VLAN2400'
set interfaces ethernet eth3 address '2001:xxxx:16:24::62/64'
set interfaces ethernet eth3 firewall local ipv6-name 'OUTSIDE_TO_RTR_V6'
set interfaces ethernet eth3 smp-affinity 'auto'
set interfaces wireguard wg01 address 'fc00:dead:beef::1/64'
set interfaces wireguard wg01 description 'Remote Access'
set interfaces wireguard wg01 peer MacbookAir_WAN1_v4 allowed-ips 'fc00:dead:beef::90/128'
set interfaces wireguard wg01 peer MacbookAir_WAN1_v4 pubkey 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
set interfaces wireguard wg01 port '53'
set nat66 source rule 1 outbound-interface 'eth3'
set nat66 source rule 1 source prefix 'fc00:dead:beef::/64'
set nat66 source rule 1 translation prefix '2001:xxxx:16:24::/64'
set protocols static interface-route6 fc00:dead:beef::/64 next-hop-interface wg01
set system conntrack

Laptop / Wireguard client:

➜  ~ ifconfig utun10
utun10: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1420
    options=6403<RXCSUM,TXCSUM,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
    inet 172.16.10.90 --> 172.16.10.90 netmask 0xffffff00
    inet6 fe80::3af9:d3ff:fe21:d814%utun10 prefixlen 64 scopeid 0x1b
    inet6 fc00:dead:beef::90 prefixlen 64
    nd6 options=201<PERFORMNUD,DAD>

➜  ~ ping6 fc00:dead:beef::1
PING6(56=40+8+8 bytes) fc00:dead:beef::90 --> fc00:dead:beef::1
16 bytes from fc00:dead:beef::1, icmp_seq=0 hlim=64 time=19.681 ms

--- fc00:dead:beef::1 ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 19.681/19.681/19.681/0.000 ms

➜  ~ ping6 2001:xxxx:16:24::251
PING6(56=40+8+8 bytes) fc00:dead:beef::90 --> 2001:xxxx:16:24::251
^C
--- 2001:xxxx:16:24::251 ping6 statistics ---
3 packets transmitted, 0 packets received, 100.0% packet loss

R1 packet-capture on it's eth2 interface:

22:33:44.996301 IP6 2001:xxxx:16:24::cfa3:82d4 > 2001:xxxx:16:24::251: ICMP6, echo request, seq 0, length 16
22:33:44.996361 IP6 2001:xxxx:16:24::251 > ff02::1:ffa3:82d4: ICMP6, neighbor solicitation, who has 2001:xxxx:16:24::cfa3:82d4, length 32
22:33:45.997372 IP6 2001:xxxx:16:24::251 > ff02::1:ffa3:82d4: ICMP6, neighbor solicitation, who has 2001:xxxx:16:24::cfa3:82d4, length 32
22:33:45.997559 IP6 2001:xxxx:16:24::cfa3:82d4 > 2001:xxxx:16:24::251: ICMP6, echo request, seq 1, length 16
22:33:47.006692 IP6 2001:xxxx:16:24::cfa3:82d4 > 2001:xxxx:16:24::251: ICMP6, echo request, seq 2, length 16
22:33:47.021376 IP6 2001:xxxx:16:24::251 > ff02::1:ffa3:82d4: ICMP6, neighbor solicitation, who has 2001:xxxx:16:24::cfa3:82d4, length 32
22:33:50.064586 IP6 fe80::9c84:d3ff:fe7d:9f77 > 2001:xxxx:16:24::251: ICMP6, neighbor solicitation, who has 2001:xxxx:16:24::251, length 32
22:33:50.064655 IP6 2001:xxxx:16:24::251 > fe80::9c84:d3ff:fe7d:9f77: ICMP6, neighbor advertisement, tgt is 2001:xxxx:16:24::251, length 24

Please give the configuration of R1 so that I can immediately test your topology in the simulation environment

@jack9603301 Here is R1

set interfaces ethernet eth0 address '2001:xxxx:16:9::1/64'
set interfaces ethernet eth1 address '2001:xxxx:16:10::1/64'
set interfaces ethernet eth2 address '2001:xxxx:16:24::251/64'
set interfaces ethernet eth2 description 'LAN2400 - Inside Management'
set interfaces ethernet eth3 address '2001:xxxx:16:17::18/64'
set interfaces ethernet eth3 description 'NET-A Backbone'
set interfaces ethernet eth4 address '2001:xxxx:16:18::18/64'
set interfaces ethernet eth4 description 'NET-B Backbone'
set interfaces loopback lo address '2001:xxxx:16:11::1/64'
set protocols static route6 ::/0 next-hop fe80::xxxx:xxxx:fedf:2a71 distance '185'
set protocols static route6 ::/0 next-hop fe80::xxxx:xxxx:fe65:c019 distance '200'
This comment was removed by jack9603301.
jack9603301 changed the task status from On hold to In progress.Sep 18 2020, 10:50 AM

It is confirmed that there is a bug in the implementation, but no solution has been found yet. In the nat66 rule, the prefix translation is indeed performed in the expected behavior, but the upstream device cannot return the data packet from the specific prefix. If the community has a good solution, please let me know

I worked with @jack9603301 and discovered [1] that stateless NAT66 depends on IPv6 neighbor proxy, otherwise VyOS will not respond to IPv6 neighbor discovery broadcasts.

To manually test I did the following for my environment:

sysctl -w net.ipv6.conf.all.proxy_ndp=1
sudo ip -6 neigh add proxy 2001:xxxx:16:24::e686:9490 dev eth3

And immediately saw ping replies from the test VM.

Obviously managing each host address is not ideal, so there is a daemon called "ndppd".
ndppd runs as a daemon, and uses a simple ndppd.conf

Alternatively, we could look at using a stateful approach with NPTv6, but that has not been tested/discussed.

Reference: [1] Re: How to use IPv6 SNPT?

This is a milestone, which means we have to decide whether to use stateful or stateless

c-po added a comment.Sep 18 2020, 2:49 PM

Beeing stateless or statefull both should work. We can add a CLI node for the proxy.ndp option like we have for proxy arp on ipv4, no big deal.

In T2518#75586, @c-po wrote:

Beeing stateless or statefull both should work. We can add a CLI node for the proxy.ndp option like we have for proxy arp on ipv4, no big deal.

Support at the same time?

jack9603301 changed the status of subtask T2898: Support NDP proxy from Open to In progress.Sep 19 2020, 9:39 AM

Hey guys,

I've been working closely with @jack9603301 on testing ndp-proxy (ndppd) and his stateless nat66 code. We've tested SNAT prefix translation and DNAT address translation.

Here's some update:

  • With NFT SNAT prefix translation, the address is not a 1:1 mapping. For example, if we have source prefix 2001:db8:1::/64 and translation prefix of 2001:db8:2::/64, the source address 2001:db8:1::1 will not translate to 2001:db8::2::1. The nftables translation calculates a new address which prevents the 1:1 host address mapping.
  • SNAT Prefix translation is working
  • DNAT address translation is working

In the case of building a DNAT rule, the operator needs to figure out what nftables has assigned the new snat host address. I do not know how nftables determines this, so without first enabling an SNAT rule, and then getting the public IP address, and then building the DNAT ruleset with this calculated host address number.

set nat66 source rule 1 outbound-interface 'eth3'
set nat66 source rule 1 source prefix 'fc00:dead:beef::/64'
set nat66 source rule 1 translation prefix '2001:xxxx:16:24::/64'

set nat66 destination rule 1 destination address '2001:xxxx:16:24::2ae8:926b'
set nat66 destination rule 1 inbound-interface 'eth3'
set nat66 destination rule 1 translation address 'fc00:dead:beef::25'

To get this to actually work, ndppd deb package is installed with the following config file built manually

ndppd.conf:

route-ttl 30000

proxy eth3 {
        router yes
        timeout 500
        ttl 30000
        rule 2001:xxxx:16:24::/64 {
                static
        }
}

proxy eth4 {
        router yes
        timeout 500
        ttl 30000
        rule fc00:dead:beef::/64  {
                static
        }
}

The next steps need input from devs - should ndppd be operationally hooked into the nat66 ruleset? That is, with the data we have from nat66 rules, should we just have ndppd config managed automatically? Or - provide config options for nat66 AND separate ndp arp proxy parameters? Alone, stateless nat66 cannot work in all (most?) network topologies. I think there may be use cases where ndp arp proxy is needed, but nat66 is not.

With NFT SNAT prefix translation, the address is not a 1:1 mapping. For example, if we have source prefix 2001:db8:1::/64 and translation prefix of 2001:db8:2::/64, the source address 2001:db8:1::1 will not translate to 2001:db8::2::1. The nftables translation calculates a new address which prevents the 1:1 host address mapping.

I'm thinking about a problem. In fact, now nat66 may have met the one-to-one unique mapping, but the host segment of its mapped address after conversion is not equal to the host segment of the address before conversion

The example of H3C shows that the conversion is also asymmetric. I don't know the effect of other devices, but it seems that this is normal

As long as the address is unique, it should meet the design requirements

c-po added a comment.Tue, Sep 22, 6:46 PM

I must disagree, prefix translation means only the prefix is translated and the interface identifier keeps the same. Meaning fc00::1111:2222:3333:4444/64 should be translated to 2001:db8::1111:2222:3333:4444/64.

jack9603301 added a comment.EditedTue, Sep 22, 6:50 PM

Well, at present, the nat66 prefix conversion of nftables has not found a way to not change the interface identifier. Maybe other people in the community can provide some suggestions?

I think about it carefully. What if the user inputs two unequal prefixes? For example, the prefix 56 is converted to the prefix 64, or vice versa

Do other community members test the behavior of other devices?

c-po added a comment.Tue, Sep 22, 8:18 PM

prefix translation should only be done on equal sized prefixes. This can be easily checked in verify() stage.

nftables nat66 seems to be the best solution that can be done now, I am still exploring a better implementation, do you have any suggestions?

c-po added a comment.Wed, Sep 23, 6:14 AM

We are not forced to nftables and still use iptables6 if its not supported properly.

jack9603301 added a comment.EditedWed, Sep 23, 9:03 AM

Thank you for your suggestion. I am considering how to implement peer-to-peer translation without modifying the interface identifier. According to some information on the Internet, the support of ipv6 nat is divided into peer address and non-equivalent address. The standard https://tools.ietf.org/html/rfc6296 display does not indicate the interface identifier. The symbol cannot be modified, but only stipulates that the address mapping conforms to the one-dimensional linear equation relationship (that is, an address mapping is unique.

Searching for related solutions is continuing

jack9603301 added a comment.EditedWed, Sep 23, 9:11 AM

@c-po The map66 solution last released on July 25th, 2015 does not seem to have been explored. It can work with iptables. I am not sure if it has stopped maintenance. I am considering whether to consider it, but it means that it needs to be compiled, installed and generated deb package , Otherwise vyos cannot install it

I don’t really want to use an old or even obsolete solution, which means we can’t receive its updates to ensure normal maintenance, but if possible, we can maintain it ourselves

https://sourceforge.net/projects/map66/

jack9603301 added a comment.EditedWed, Sep 23, 1:49 PM

Hi, everyone, I have been looking for a way to handle the 1-to-1 address prefix symmetry mapping. I contacted the IRC channel of the official community. According to the official information, it seems to be resolved in the 5.8 kernel version, otherwise the patch needs to be backported To 4.19.

The official community tells me that I only need to change snat to into snat prefix to, but need to operate on the kernel above 5.8,otherwise the patch needs to be backported To 4.19.

patch:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3ff7ddb

jack9603301 added a comment.EditedThu, Sep 24, 11:36 AM

In linux kernel version 5.8 and above, you can start symmetric translation of ipv6 address prefix by changing snat to to snat prefix to in the policy (without changing the interface identifier), but this function cannot be used before vyos upgrade 5.9 , This patch is not a back-portable patch, so this feature cannot be used in 4.19. There are now 3 solutions:

a) Wait for the kernel to be upgraded to 5.9 merge, and only support symmetric mapping

b) Add compatibility switch to switch between two mapping methods

c) Waiting for the kernel to be upgraded to 5.9 merge, but support 2 different mapping modes at the same time

ps: The function still depends on the NDP proxy

Also come back to this question?

The next steps need input from devs - should ndppd be operationally hooked into the nat66 ruleset? That is, with the data we have from nat66 rules, should we just have ndppd config managed automatically? Or - provide config options for nat66 AND separate ndp arp proxy parameters? Alone, stateless nat66 cannot work in all (most?) network topologies. I think there may be use cases where ndp arp proxy is needed, but nat66 is not.

jack9603301 updated the task description. (Show Details)Thu, Sep 24, 6:06 PM
jack9603301 added a comment.EditedWed, Sep 30, 2:19 PM

NDP Proxy has been implemented in T2898. For nat66 to work normally, proxy-ndp must be operated in static mode.

When the merger of nat66 and proxy-ndp is completed, consider adding the function of nat66 auto-proxy-ndp to realize automatic configuration of proxy-ndp