What's new
  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

IPv6 traffic forwarding problem: connection hangs

i0ntempest

Regular Contributor
WAS: Options for providing services on IPv6 w/ ISP prefix delegation
EDIT: I'm close to successfully configuring a working IPv6 forwarding rule set, with one issue remaining (see my replies). Below is the original post.

Hi all,
I have some questions regarding IPv6 stuff. I'm new to v6 stuff so please be gentle.
I have a public IPv4 address (but that may change soon, to CGNAT) and a /64 IPv6 block from my ISP. Because prefix delegation does not give stable addresses, I also have v6 ULA setup. I also have a DDNS domain pointing to my router's v4 and v6 address. Currently I have some ports forwarded to my LAN devices' v4 addresses to provide VPN and stuff - they all work fine.
Now - what if I want to expose those services from IPv6 too? I have considered these options:
1. Open port thru IPv6 firewall, and update DDNS to point to the v6 address to the device running the service. The problem would be 1) as I said my v6 address isn't stable, and 2) the DDNS domain would point to only one device, but my services are on multiple devices. If there's a way to open port on the v6 firewall by MAC, then part of the problem is solved.
2. If such thing can be done, keep the DDNS pointing to my router's v6, and have some sort of "port forwarding" on v6 to forward traffic to devices' ULAs. This *seems* ideal and is similar to a v4 setup but can it be done?

Thoughts welcome, thanks in advance.
 
Last edited:
It may help if you provide or include router model and firmware version for others just in case a response is dependent on router and or firmware.
 
I tried some ip6tables commands with some help from ChatGPT, and found out that if I open the port on IPv6 firewall using the ULA address, and use this command to create the forward rule:
ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 38443 -j DNAT --to-destination [fd00:d:e:f::e123]:38443
Then the service will become available on the router's public IP.
The problem is that, if the internal port and the external port is different, say:
ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 2222 -j DNAT --to-destination [fd00:d:e:f::e123]:22
Then the service is unstable. Using SSH as an example, the it would initially connect but before a shell prompt can be shown the connection hangs and eventually times out.
ChatGPT suggested these:
Code:
ip6tables -t nat -A POSTROUTING -p tcp -d fd00:d:e:f::e123 --dport 22 -j MASQUERADE
ip6tables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
But those are ineffective, and I'm out of ideas.
Prety unlikely the solution would be dependent on the router model but I have a TUF-AX3000 and an AX86U, both running the latest merlin firmware.
 
I tried some ip6tables commands with some help from ChatGPT, and found out that if I open the port on IPv6 firewall using the ULA address, and use this command to create the forward rule:
ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 38443 -j DNAT --to-destination [fd00:d:e:f::e123]:38443
Then the service will become available on the router's public IP.
The problem is that, if the internal port and the external port is different, say:
ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 2222 -j DNAT --to-destination [fd00:d:e:f::e123]:22
Then the service is unstable. Using SSH as an example, the it would initially connect but before a shell prompt can be shown the connection hangs and eventually times out.
ChatGPT suggested these:
Code:
ip6tables -t nat -A POSTROUTING -p tcp -d fd00:d:e:f::e123 --dport 22 -j MASQUERADE
ip6tables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
But those are ineffective, and I'm out of ideas.
Prety unlikely the solution would be dependent on the router model but I have a TUF-AX3000 and an AX86U, both running the latest merlin firmware.
Feels like you are thinking about this in an ipv4 type of way. For ipv6 each unit already have a publically routable ip.

I would imagine each ipv6 device update there own ddns record with their own public ip. I use dynv6 for this.

You don't need to port forward in that sense, neither should you need any port translation as each service has their own ip.

What you do need however is to open firewall for incoming data on this specific port to this specific destination. There are several ways to do this.
 
Feels like you are thinking about this in an ipv4 type of way. For ipv6 each unit already have a publically routable ip.

I would imagine each ipv6 device update there own ddns record with their own public ip. I use dynv6 for this.

You don't need to port forward in that sense, neither should you need any port translation as each service has their own ip.

What you do need however is to open firewall for incoming data on this specific port to this specific destination. There are several ways to do this.
Indeed - I actually considered using public IPv6 addresses first. But to do this I'll need to configure a hostname for each device, and it won't be compatible with my existing port forwarding IPv4 setup so that need to be redone as well. I do have a plan to move everything to my cloudflare lvl 2 domain but that's something for the future me.

Right now I just need to figure out how to do IPv6 forwarding with different internal and external ports. I know this isn't how IPv6 is supposed to be used but it'll be fine for now.
 
Indeed - I actually considered using public IPv6 addresses first. But to do this I'll need to configure a hostname for each device, and it won't be compatible with my existing port forwarding IPv4 setup so that need to be redone as well. I do have a plan to move everything to my cloudflare lvl 2 domain but that's something for the future me.

Right now I just need to figure out how to do IPv6 forwarding with different internal and external ports. I know this isn't how IPv6 is supposed to be used but it'll be fine for now.
Alright, I understand. Meanwhile, please check out dynv6 as it is tailored for ipv6 operation.

I don't know why it becomes unstable when you change port. Ipv6 dnat is rather newly ported into the fw.

But besides to DNAT you posted, did you open the firewall for forwarding new packets for these services? Router uses a stateful ipv6 firewall, just as ipv4.

Something like:
Code:
ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 38443 -j DNAT --to-destination [fd00:d:e:f::e123]:38443
ip6tables -I FORWARD -i ppp0 -p tcp --dport 38443 -o [fd00:d:e:f::e123] -j ACCEPT
sorry if there is a typo, in a hurry...
 
Alright, I understand. Meanwhile, please check out dynv6 as it is tailored for ipv6 operation.

I don't know why it becomes unstable when you change port. Ipv6 dnat is rather newly ported into the fw.

But besides to DNAT you posted, did you open the firewall for forwarding new packets for these services? Router uses a stateful ipv6 firewall, just as ipv4.

Something like:
Code:
ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 38443 -j DNAT --to-destination [fd00:d:e:f::e123]:38443
ip6tables -I FORWARD -i ppp0 -p tcp --dport 38443 -o [fd00:d:e:f::e123] -j ACCEPT
sorry if there is a typo, in a hurry...
Yea I did open the port in v6 firewall, just not on the cli but on the webui. I also tried disabling v6 firewall entirely and that didn't change anything. Maybe a bug in v6 DNAT?
Also I tried TPROXY as well but that doesn't seem to be included in the firmware.
 
ip6tables -I FORWARD -i ppp0 -p tcp --dport 38443 -o [fd00:d:e:f::e123] -j ACCEPT
This command alone (typo corrected: ip6tables -A FORWARD -m state --state NEW -p tcp --dport 38443 -d fd00:d:e:f::e123 -j ACCEPT) isn't enough to make the service reachable outside, but opening a port in the webui firewall page does. So may I know what exactly is executed by the system for webui to open a port?
 
This command alone (typo corrected: ip6tables -A FORWARD -m state --state NEW -p tcp --dport 38443 -d fd00:d:e:f::e123 -j ACCEPT) isn't enough to make the service reachable outside, but opening a port in the webui firewall page does. So may I know what exactly is executed by the system for webui to open a port?
Edit: don't use -A (append) for this as it would add the rule last, after all been dropped. You need to use -I (insert) to put the rule at the top. That may be why it's not working.

(before edit) No, I don't. But you could probably track it down by looking at the rules:
Code:
ip6tables -nvL FORWARD
It may create new chain with the rules in it.

When I initially only ran ipv6 ula on my network the router just refused to route this to wan. It somehow gets dropped during routing and I never figure out how to make this work. Forward to a wg interface worked though. There may be a setting for this somewhere.
 
Last edited:
Edit: don't use -A (append) for this as it would add the rule last, after all been dropped. You need to use -I (insert) to put the rule at the top. That may be why it's not working.

(before edit) No, I don't. But you could probably track it down by looking at the rules:
Code:
ip6tables -nvL FORWARD
It may create new chain with the rules in it.

When I initially only ran ipv6 ula on my network the router just refused to route this to wan. It somehow gets dropped during routing and I never figure out how to make this work. Forward to a wg interface worked though. There may be a setting for this somewhere.
Yes indeed, changing -A to -I made it work. Thanks!
 
@i0ntempest, thanks for sharing this! I've been looking at doing something similar for quite a while. I was waiting for the ip6tables upgrade to 1.4.18+ to do this.

I'm interested in how you setup the ULA assignment? Did you use a script on the router or on the server itself?
 
Edit: don't use -A (append) for this as it would add the rule last, after all been dropped. You need to use -I (insert) to put the rule at the top. That may be why it's not working.

(before edit) No, I don't. But you could probably track it down by looking at the rules:
Code:
ip6tables -nvL FORWARD
It may create new chain with the rules in it.

When I initially only ran ipv6 ula on my network the router just refused to route this to wan. It somehow gets dropped during routing and I never figure out how to make this work. Forward to a wg interface worked though. There may be a setting for this somewhere.
@ZebMcKayhan, I think I might be coming across the same issue with the traffic refusing to route. I can see packets being captured, but web pages and Plex won't load on an external client. Hopefully you have a second to help a novice out.

I'm excited for this functionality. I've been waiting for the ip6tables update for a while now to use netfilter6 NAT66 to mimic IPv4 NAT functionality. My ISP assigns an unstable v6, just like v4.

If I manually enter the currently assigned IPv6 GUA of the webserver into the AAAA DNS record, and manually update the router firewall GUI (for ports 80, 443, and 32400), everything works as expected until my ISP changes my v6. Then I have to manually update the AAAA DNS record and the router GUI firewall forward to the GUA again. I'd love to do this dynamically! I've got the DDNS setup with inadyn for both v4 and v6. The A and AAAA records update fine with the respective router WAN address.

  • v4 continues to work fine after a DDNS update since the GUI router firewall forward rule points to the static local v4 IP of the server.
  • v6 needed a ULA assigned to forward to a static local v6 IP address. I used the same format as @i0ntempest to assign a ULA on the network.

Code:
ip -6 addr add dev br0 fd00:d:e:f::1/64

My WAN adapter is eth0 and my LAN is br0.

I used these PREROUTING rules for Plex (32400) and Web (80, 443) on both tcp and udp:

Code:
ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 32400 -j DNAT --to-destination [fd00:d:e:f:f9cf:9078:bf5f:5621]:32400
ip6tables -t nat -A PREROUTING -i eth0 -p udp --dport 32400 -j DNAT --to-destination [fd00:d:e:f:f9cf:9078:bf5f:5621]:32400
ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination [fd00:d:e:f:f9cf:9078:bf5f:5621]:80
ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination [fd00:d:e:f:f9cf:9078:bf5f:5621]:443
ip6tables -t nat -A PREROUTING -i eth0 -p udp --dport 80 -j DNAT --to-destination [fd00:d:e:f:f9cf:9078:bf5f:5621]:80
ip6tables -t nat -A PREROUTING -i eth0 -p udp --dport 443 -j DNAT --to-destination [fd00:d:e:f:f9cf:9078:bf5f:5621]:443

Then I used these FORWARD rules:

Code:
ip6tables -I FORWARD -m state --state NEW -p tcp --dport 32400 -d fd00:d:e:f:f9cf:9078:bf5f:5621 -j ACCEPT
ip6tables -I FORWARD -m state --state NEW -p udp --dport 32400 -d fd00:d:e:f:f9cf:9078:bf5f:5621 -j ACCEPT
ip6tables -I FORWARD -m state --state NEW -p tcp --dport 80 -d fd00:d:e:f:f9cf:9078:bf5f:5621 -j ACCEPT
ip6tables -I FORWARD -m state --state NEW -p tcp --dport 443 -d fd00:d:e:f:f9cf:9078:bf5f:5621 -j ACCEPT
ip6tables -I FORWARD -m state --state NEW -p udp --dport 80 -d fd00:d:e:f:f9cf:9078:bf5f:5621 -j ACCEPT
ip6tables -I FORWARD -m state --state NEW -p udp --dport 443 -d fd00:d:e:f:f9cf:9078:bf5f:5621 -j ACCEPT

Finally, I used these POSTROUTING rules:

Code:
ip6tables -t nat -A POSTROUTING -o br0 -p tcp -d fd00:d:e:f:f9cf:9078:bf5f:5621 --dport 32400 -j MASQUERADE
ip6tables -t nat -A POSTROUTING -o br0 -p udp -d fd00:d:e:f:f9cf:9078:bf5f:5621 --dport 32400 -j MASQUERADE
ip6tables -t nat -A POSTROUTING -o br0 -p tcp -d fd00:d:e:f:f9cf:9078:bf5f:5621 --dport 80 -j MASQUERADE
ip6tables -t nat -A POSTROUTING -o br0 -p tcp -d fd00:d:e:f:f9cf:9078:bf5f:5621 --dport 443 -j MASQUERADE
ip6tables -t nat -A POSTROUTING -o br0 -p udp -d fd00:d:e:f:f9cf:9078:bf5f:5621 --dport 80 -j MASQUERADE
ip6tables -t nat -A POSTROUTING -o br0 -p udp -d fd00:d:e:f:f9cf:9078:bf5f:5621 --dport 443 -j MASQUERADE

I think I might be at a dead end:

  • I can see packets captured in both the PREROUTING and POSTROUTING chains using "ip6tables -t nat -L -n -v."
  • I can see packets captured in the FORWARD chain using "ip6tables -nvL FORWARD."
  • Wireshark shows a PSH, ACK on the first packet, then TCP retransmission.
  • I can curl and telnet into the external WAN IP.
I know this isn't the intended use of IPv6. I have limitations as a self hosted tinkerer with a single machine serving external requests, behind the router. This functionality would be great to have! I would take any suggestions you would be willing to share.

Edit:

Here's a screenshot of the Wireshark packet activity when using the web server's direct IPv6 GUA (2603:7080:d603:d900:1520:52cd:30f6:c4d) in the AAAA record. The client (2600:1017:b004:c99c:0:46:e0e6:8201) connects.

1745430478219.png


Here is Plex which also loads:

1745432886081.png


Here is a screenshot of the Wireshark packet activity when using the IPv6 of the router WAN (2604:6000:bfc0:6a:610f:42c6:9243:5227) in the AAAA record, forwarded to the ULA (fd00:d:e:f:f9cf:9078:bf5f:5621). The client (2600:1017:b004:c99c:0:46:e0e6:8201) hangs.

1745430581570.png


Here is Plex which also hangs:

1745432918800.png
 
Last edited:
If I manually enter the currently assigned IPv6 GUA of the webserver into the AAAA DNS record, and manually update the router firewall GUI (for ports 80, 443, and 32400), everything works as expected until my ISP changes my v6. Then I have to manually update the AAAA DNS record and the router GUI firewall forward to the GUA again. I'd love to do this dynamically! I've got the DDNS setup with inadyn for both v4 and v6. The A and AAAA records update fine with the respective router WAN address.
This is the way... you should have the plex server update the AAAA record itself as the router don't know what address the server picks.

Then the tricky part, how to open the firewall... you obviously don't want to open these ports for your entire lan. You could perhaps use some script to have the router check the AAAA record itself, like:
Code:
admin@RT-AX86U_Pro:/# nslookup ipv6.google.com | grep '::' | cut -d" " -f 3
2a00:1450:400f:803::200e
Then some formatting and you would only need to add a rule to accept this in filter, forward table.
Not sure what hook script to trigger this, wan-event perhaps?

Regarding your ULA attemp,You could see same as me, possibly. I always thought there is a switch somewhere in
Code:
/proc/sys/net/ipv6/
To enable ULA routing to WAN but I grew tired before I managed to find it... you could modify your ULA with i.e starting with AA instead of FD to see if that changes anything, that worked for me:
https://github.com/ZebMcKayhan/Wire...-ov-file#ipv6-over-wireguard-without-ipv6-wan
 
This is the way... you should have the plex server update the AAAA record itself as the router don't know what address the server picks.

Then the tricky part, how to open the firewall... you obviously don't want to open these ports for your entire lan. You could perhaps use some script to have the router check the AAAA record itself, like:
Code:
admin@RT-AX86U_Pro:/# nslookup ipv6.google.com | grep '::' | cut -d" " -f 3
2a00:1450:400f:803::200e
Then some formatting and you would only need to add a rule to accept this in filter, forward table.
Not sure what hook script to trigger this, wan-event perhaps?

Regarding your ULA attemp,You could see same as me, possibly. I always thought there is a switch somewhere in
Code:
/proc/sys/net/ipv6/
To enable ULA routing to WAN but I grew tired before I managed to find it... you could modify your ULA with i.e starting with AA instead of FD to see if that changes anything, that worked for me:
https://github.com/ZebMcKayhan/Wire...-ov-file#ipv6-over-wireguard-without-ipv6-wan
Thank you very much for taking the time to provide quick insight and suggestions!

I can do the DDNS updates directly from the web server to update the AAAA record with it's dynamic GUA. Of course, the only issue being the complexity of dynamically updating the firewall on the router for the servers new GUAs. I'd really like to use the IPv6 NAT on the router to update a single DDNS record and selectively router ports to a static address. I know this is old thinking, but like @i0ntempest had mentioned, if I could route to a MAC address, I don't think this would be a problem at all.

Although using the prefix aaff still didn't route, I went looking in the /proc/sys/net/ipv6/conf directory. Forwarding is enabled in the following files:

  • /proc/sys/net/ipv6/conf/all/forwarding = 1
  • /proc/sys/net/ipv6/conf/br0/forwarding = 1,

However, /proc/sys/net/ipv6/conf/eth0/forwarding = 0.

I wonder if my eth0 adapter should be set to 1 as well? I believe I can't make any modifications to files in the ROM to test this out. Do you know if there any way to override this one forwarding setting temporary to test?
 
Although using the prefix aaff still didn't route
Then your problem is not the same as mine, or you have more than 1 problem.


I wonder if my eth0 adapter should be set to 1 as well? I believe I can't make any modifications to files in the ROM to test this out. Do you know if there any way to override this one forwarding setting temporary to test?
Sure you can change it. It's as easy as
Code:
echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding
 
This is the script I use to create forwarding rules. If the source and destination port is the same, this should be enough. I only have problems if the ports are different.
Bash:
#!/bin/sh

# Remember to set static ULA in dnsmasq config
#ip6tables -I FORWARD -i [IF] -m state --state NEW -p [PROT] --dport [DEV_PORT] -d [DEV_IP] -j ACCEPT
# Open firewall
#ip6tables -t nat -A PREROUTING -i [IF] -p [PROT] --dport [EXT_PORT] -j DNAT --to-destination [DEV_IP]:[DEV_PORT]
# The actual forward

if [ "$#" -lt 4 ] || [ "$#" -gt 5 ] ; then
    echo "Error: incorrect number of arguments" >&2
    echo "Usage: $0 EXT_PORT DEV_PORT DEV_IP PROT [SRC_IP]" >&2
    exit 1
fi

WAN_IF=$(nvram get wan0_gw_ifname)
EXT_PORT="$1"
DEV_PORT="$2"
DEV_IP="$3"
PROT="$4"
SRC_IP="$5"

ip6tables -I FORWARD \
          -i "$WAN_IF" -m state --state NEW \
          -p "$PROT" --dport "$DEV_PORT" -d "$DEV_IP" -j ACCEPT
if [ "$#" -eq 4 ]; then
    ip6tables -t nat -A PREROUTING \
              -i "$WAN_IF" -p "$PROT" --dport "$EXT_PORT" \
              -j DNAT --to-destination ["$DEV_IP"]:"$DEV_PORT"
elif [ "$#" -eq 5 ]; then
    ip6tables -t nat -A PREROUTING \
              -i "$WAN_IF" -p "$PROT" -s "$SRC_IP" --dport "$EXT_PORT" \
              -j DNAT --to-destination ["$DEV_IP"]:"$DEV_PORT"
fi
Use it like this:
ipv6pf 38443 38443 fd00:d:e:f::13 tcp
 
Last edited:

Similar threads

Latest threads

Support SNBForums w/ Amazon

If you'd like to support SNBForums, just use this link and buy anything on Amazon. Thanks!

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Back
Top