Featured image of post Using NETMAP to obtain persistent IPv6 addresses and control source address

Using NETMAP to obtain persistent IPv6 addresses and control source address

IPv6 does indeed not require NAT, but prefix translation is not entirely useless.

IPv6 addresses assigned by ISPs are usually not static:

1
2
3
4
5
[admin@shanghai-router] > /ipv6/dhcp-client/print
Columns: INTERFACE, STATUS, REQUEST, PREFIX
# INTERFACE          STATUS  REQUEST  PREFIX
0 pppoe-chinanet     bound   prefix   240e:388:6501:XX00::/56, 40m57s
1 pppoe-chinamobile  bound   prefix   2409:8a1e:6a64:2XX0::/60, 2d20h10m

While the address won’t change during the PPPoE session’s lifespan, ISPs often have mechanisms like timed interruptions and reconnections on their BRAS, leading to changes in our IPv6 address. In newer versions of RouterOS, when the DHCPv6-acquired prefix becomes invalid, the device updates the address “lifetime” to 0, thereby removing the old address. This is a good solution.

However, in this article about optimizing multi-line internet access using BGP full tables on RouterOS, it’s mentioned:

although v6 achieves traffic diversion through these methods, there are still issues because there is no NAT and devices cannot intelligently choose which prefix of the IP address to use.

So, having a stable prefix alone isn’t sufficient; we need the device’s firewall to “intelligently” update the outgoing IPv6 source address to the one we want it to use. This is crucial to achieve optimal results for multi-ISP optimization. To achieve this goal, we can use the NETMAP target provided by netfilter.


Let’s assume our router has the following prefixes:

  1. From China Telecom: 240e:388:6501:ab00::/56
  2. From China Mobile: 2409:8a1e:6a64:2XX0::/60
  3. Self-announced: 2602:feda:de0:700::/56

We’re selecting a fixed address range with the smallest prefix for translation, which is 2602:feda:de0:700::/60.

Notice

If you don’t have your own prefix, you can configure IPv6 SLAAC using IPv6 ULA addresses, for example, fd34:38a:f295:a00::/64.

For outgoing connections to the pppoe-chinanet interface, where the source address is within the range of 2602:feda:de0:700::/60, we’ll use the firewall to map the source address to the range of 240e:388:6501:ab00::/60 (which is China Telecom’s address range):

1
/ipv6/firewall/nat add chain=srcnat out-interface=pppoe-chinanet src-address=2602:feda:de0:700::/60 action=netmap to-address=240e:388:6501:ab00::/60

Of course, we can’t just handle outbound traffic and ignore incoming traffic. Otherwise, when responses from external services reach the router and it realizes there’s no directly adjacent address using the 240e:388:6501:ab00::/60 prefix, we need to handle the return traffic:

1
/ipv6/firewall/nat add chain=dstnat in-interface=pppoe-chinanet dst-address=240e:388:6501:ab00::/60 action=netmap to-address=2602:feda:de0:700::/60

Similarly, rules for China Mobile can be written as follows:

1
2
3
/ipv6/firewall/nat
add chain=srcnat out-interface=pppoe-chinamobile src-address=2602:feda:de0:700::/60 action=netmap to-address=2409:8a1e:6a64:2XX0::/60
add chain=dstnat in-interface=pppoe-chinamobile dst-address=2409:8a1e:6a64:2XX0::/60 action=netmap to-address=2602:feda:de0:700::/60

Finally, we also need to add an update script to the corresponding DHCPv6 configuration to update the firewall rules, using China Mobile’s client as an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
:log info ("dhcpv6 up script started");

:local  [/ipv6/pool/get [find name="ipv6-chinamobile-pd"] prefix];
:log info "prefix assigned by China Mobile is: $china_mobile_prefix";
:local china_mobile_new_prefix [:pick "$china_mobile_prefix" 0 ([:len "$china_mobile_prefix"] - 3)]

/ipv6/firewall/nat/set dst-address="$china_mobile_new_prefix/60" [find chain=dstnat action=netmap in-interface="pppoe-chinamobile"];
/ipv6/firewall/nat/set to-address="$china_mobile_new_prefix/60" [find chain=srcnat action=netmap out-interface="pppoe-chinamobile"];

:log info "netmap update okay";

That’s it!


We can pick an IPv6 address and try a traceroute:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
ntzyz@nas-v2 ~ % curl ipv6.ip.sb
2406:4440:10:<redacted>
ntzyz@nas-v2 ~ % mtr 240e:f7:e01f:f1::30 --report -z
Start: 2023-08-18T13:58:52+0800
HOST: nas-v2                      Loss%   Snt   Last   Avg  Best  Wrst StDev
  1. AS142641 <redacted>           0.0%    10    0.3   0.4   0.3   0.4   0.0
  2. AS24400  2409:801e:f0:1::2fb 10.0%    10    4.3   4.9   3.9  10.5   2.1
  3. AS24400  2409:801e:f0:1::2fa  0.0%    10    4.2   4.3   3.9   5.2   0.4
  4. AS9808   2409:8080:0:2:206:2  0.0%    10    4.7   4.7   4.5   4.8   0.1
  5. AS9808   2409:8080:0:1:206:1  0.0%    10   21.8  16.4   7.9  25.4   6.6
  6. AS9808   2409:8080:0:1:1106: 70.0%    10   10.2  10.2  10.2  10.3   0.0
  7. AS9808   2409:8080:0:3:11e2:  0.0%    10   13.8  13.7  13.1  14.0   0.2
  8. AS4134   240e::c:b:5100:302   0.0%    10    8.5   8.5   8.1   8.7   0.2
  9. AS136190 240e:1c:b111:1fff:: 10.0%    10   12.2  15.3  11.1  43.4  10.5
 10. AS136190 240e:1c:b112:1122::  0.0%    10   11.9  11.9  11.8  12.0   0.1
 11. AS136190 240e:f7:e01f:ff::11  0.0%    10   13.0  14.7  12.6  27.2   4.5
 12. AS136190 240e:f7:e01f:f1::30  0.0%    10   10.6  11.5  10.6  11.8   0.3

As we can see, when this NAS accesses Cloudflare, it uses its my own prefix. When accessing domestic addresses, it actually uses China Telecom’s prefix.

comments powered by Disqus
Except where otherwise noted, content on this blog is licensed under CC-BY 2.0.
Built with Hugo
Theme Stack designed by Jimmy