IPv6 ND proxy for multi-LAN

Started by georgeman, May 28, 2026, 06:34:41 PM

Previous topic - Next topic
TL;DR: my ISP doesn't understand IPv6

After weeks of insisting, my company's ISP (IPlan from Argentina, full name and shame here), has decided to comply to their advertised offer and enabled IPv6 on our business-class internet service. They provided a public /48 (great), but it is statically assigned and not routed (not great). So we ended up with an on-link /48, without DHCPv6 (so no prefix delegation), and they refuse to even put a static route to my router. Just the plain /48 living on my WAN interface, with an address in the /48 being the default gateway for the whole /48. Period.

I escalated this to the highest level and they don't seem to even understand what I am talking about. Of course we are looking for a different ISP, but what are my options to make this setup a bit useful in the meantime? My internal network has ULA addresses and I am not planning to give internal devices GUAs for a number of reasons.

The plan was to use NPT with ndproxy and this in fact works fine, but ndproxy has a limitation that it works for only one internal network (and we have many).

ndp-proxy-go does not seem to work with ULA + NPT (I get the message "skip learn fdfd:xxxx:xxxx:xxxx::xxxx (not in allowed RA prefixes)" when trying to proxy ULA addresses). Am I missing something?

ndppd sounds like it might work but it's not available as an OPNsense package and I would prefer to avoid tinkering too much with the underlying FreeBSD (I don't want this to break in an upgrade, etc)

Any other alternatives or ideas?
Thanks!

May 28, 2026, 06:42:00 PM #1 Last Edit: May 28, 2026, 06:51:04 PM by Monviech (Cedrik)
Hello,

the ndproxy package is not maintained anymore and thus will be removed in an upcoming version (it also had build issues with Freebsd 15, they were fixed but it looks flakey)

----

The ndp-proxy-go package requires Router Advertisements from upstream that contain the on-link prefix that can be proxied.

It's not supposed to be used with NPT, it would proxy the GUAs of the on-link prefix that the provider offers via SLAAC.

These won't contain any ULAs in most cases.

Does your provider not offer any /64 prefix via SLAAC?

I'm the original author of that package, so if usage with NPT is a requirement I could give it a look, but it's not on my personal wishlist since I don't use it, I always proxy GUAs directly.

You can read about it here:
https://github.com/Monviech/ndp-proxy-go

And here your specific log message explained:
https://docs.opnsense.org/manual/ndp-proxy-go.html#logging
Hardware:
DEC740

Thanks for the reply!

Of course it would be great (not just for me, but for the community) to have additional functionality available. Unfortunately I don't think I can help with Go programming but if you ever decide to implement this, count on me for testing.

EDIT: by the way, my provider doesn't assign anything via SLAAC or DHCPv6. Only a static assignment.

May 28, 2026, 07:25:55 PM #3 Last Edit: May 28, 2026, 07:34:39 PM by Monviech (Cedrik)
Hello,

I would assume that if the ndp proxy would allow setting an arbitrary static prefix that has not been sent via RA from upstream, it should theoretically also work (no promised, I didnt check any assumptions). And it would need to statically set the LLA of the upstream router.

But that means GUAs must be used, no NPT or ULAs.

Internally you would also need a static IPv6 configuration with /64 networks carved out of your /48 network.

Though Router Advertisements from upstream reveal more than just a prefix, it also reveals the source MAC address of the primary ISP router.

Most of these configuration that is set statically in ndproxy, are automatically derived via RAs in ndp-proxy-go since its main audience are users with dynamic prefixes where these settings can change anytime.

Your setup seems to be one of the rarer ones.

You could also probably just use NAT66 just like NAT44 is probably already used.
Hardware:
DEC740

I could definitely do NAT66 but NPT is a much cleaner solution.

ndproxy works perfectly for my scenario except that it doesn't work for multiple LANs (I don't fully understand the reason behind this).

If ndp-proxy-go had some sort of "manual mode" where you could set similar parameters as ndproxy, I think that would cover it, given that it supports multiple LANs.

May 28, 2026, 08:32:16 PM #5 Last Edit: May 28, 2026, 08:34:07 PM by Monviech (Cedrik)
NPT is also worse than being able to directly use the GUAs.

I assume something like this in ndp-proxy-go could be an idea as implementation:

--allow-prefix 2001:db8::/48
--router-lla fe80::1

It would then be allowed to learn clients inside that prefix, and would proxy NDP towards that upstream router, and install the required host routes.

Though this would most likely not make NPTv6 work, it would make the actual GUAs work without any translation needed.

Radvd must then send prefixes in your public GUA range to clients, and interally you would use static GUAs on your interfaces, not ULAs.

If that is something you are willing to test, I could potentially cook a small patch up that allows this.

Best would be a small github issue in my repo.
Hardware:
DEC740

Today at 07:28:49 AM #6 Last Edit: Today at 07:35:48 AM by Monviech (Cedrik)
I added a branch for testing:
https://github.com/Monviech/ndp-proxy-go/tree/static-prefix

It's used on CLI like this, the new static-prefix and static-router flags are repeatable:

root@bsd01:/src/git/ndp-proxy-go # ./ndp-proxy-go --static-prefix 2001:db8:1234::/48 --static-router fe80::3 --debug --no-ra hn0 hn1

detected ethernet interface on hn0 (DLT=1)
detected ethernet interface on hn1 (DLT=1)
static prefix added: 2001:db8:1234::/48 <--- This means the static prefix has been added successfully
static router LLA added: fe80::3 <--- This means the static upstream router has been added successfully, must be link local address
upstream=hn0 downstream=hn1 no-ra=true no-routes=false no-dad=false no-rewrite-lla=false cache-ttl=10m0s cache-max=4096 route-qps=50 pf-qps=50 pcap-timeout=50ms cache-file="" static-prefixes=1 static-routers=1
sending Router Solicitation on hn0 <--- Try to find out information about upstream router (dynamic setup path)
router LLA learned: fe80::f690:XXXXXXXX<--- This means the upstream router has sent an RA that contained its link local address, added additionally when discovered even if static information is provided.
RA prefix learned: 2003:d4:XXXXXXXX::/64 (valid 2h0m0s) <--- This means the upstream router has sent an RA that contains a prefix, added additionally when discovered even if static information is provided.

You have to build the binary yourself to test it.

Please test this with public GUA addresses from the assigned prefix on the internal interfaces/clients. This branch does not add NPT/ULA translation support (if it still works yaaay?, since it was not a supported test target)

Since your setup should most likely use radvd for the internal GUA prefixes, start testing with --no-ra so upstream RAs (if they even exist) are not forwarded downstream.

For an example how you can use radvd together with the proxy, check the manual here. I don't know if this also works as intended if the WAN does not have a /64 prefix, you might need a static configuration in your case, and not the Constructur (but unsure).
https://docs.opnsense.org/manual/ndp-proxy-go.html#router-advertisements
Hardware:
DEC740

That's awesome, thanks! I will give it a try next week and will report back.