Hide IPv6 host behind router like port forward

Hi,

I have a network with IPv6 addresses on all the nodes. All host have a global public IPv6 address as well as an fd00::…/64 local address.

I would like to use the IPv6 address of my router like I did in case of IPv4 with port forward meaning that I need to be visible for the external world, from incoming connections point of view, like a single node.

I know I could add a rule in my firewall to allow incoming connections towards the other IPv6 addresses but I do not want to do so. I need to be visible for the external world like a single node.

In other words:
Host “A” has a web server on the port 443 and Host “B” has an SSH jump host on port 22. Both service should be available on the WAN IP of my router. How to implement this?

Thanks!

See https://www.animmouse.com/p/how-to-nat-ipv6-in-mikrotik/

Thanks for the link!

As I have globally routeable IPv6 address on all the nodes in my LAN, I would like to leave them as they are with no NAT while the port forward kind of thing influence only the router’s WAN facing IP. Does it possible?

If I’m right, link above push all the LAN nodes behind NAT which is slightly different then what I want. Right?

I don’t think that you can have both, either NAT or access trough public IP of client. Because if you want to use input port on router WAN IP address for address that is not behind NAT that will be port tunneling not forwarding. For tunneling you need client/service connection like VPN. Maybe there is some hybrid solution on ROS for this but I’m not aware of unless you want to use VPN just for that.

Edit: maybe if you setup vlan as additional interface on host A, B and router. On both hosts services needs to have listen port on that vlan interface and then you can setup forwarding on router to vlan, not a IPv6 expert, maybe this helps regarding setup vlan on IPv6 https://www.youtube.com/watch?v=YAIAukW0bFs

What doesn’t work? There is /ipv6/firewall/nat in v7, just add a dst-nat rule.

Actually I made a nat rule but it doesn’t work so far.

Please ignore the fact that this rule below is disabled right now.

  • d00::100:6ef0:49ff:fe00:efc5 is the IPv6 address of the SSH server behind the router.
  • 2001:REDACTED::/64 is the internet facing address of the router where I would like to make SSH server visible for the external world.
  • each internal host has IP from 2001… range from my ISP as well as an fd00:… address. In the below nat rule I used the second one because it is fixed but the other.

One more thing: I have a dynamic IPv6 pool from my ISP via DHCPv6 so if dst-address part is needed in the rule then I guess I will need to periodically update it with a script. Right?


[admin@router] > /ipv6/firewall/nat/print
Flags: X - disabled, I - invalid; D - dynamic 
 0 X  ;;; SSH
      chain=dstnat action=dst-nat to-address=fd00::100:6ef0:49ff:fe00:efc5/128 to-ports=22 protocol=tcp dst-address=2001:REDACTED::/64 in-interface-list=WAN dst-port=22 
      log=no log-prefix="" 
[admin@router] >

Perhaps the SSH server is not listening on the fd00::/64 interface and/or firewall rejects the packets?

Try adding passthrough rules to the filter’s prerouting and postrouting chains at the very top to log the packets flow to fd00::100:6ef0:49ff:fe00:efc5:22


Right, you can use the DHCPv6 client script and firewall’s address lists for that.

SSH server listens on the tcp/22 port of fd00::100:6ef0:49ff:fe00:efc5

hal@hal:~$ nc -v fd00::100:6ef0:49ff:fe00:efc5 22
Connection to fd00::100:6ef0:49ff:fe00:efc5 22 port [tcp/ssh] succeeded!
SSH-2.0-OpenSSH_8.9p1
^C



[admin@router] > sy telnet fd00::100:6ef0:49ff:fe00:efc5 22
Connecting to fd00::100:6ef0:49ff:fe00:efc5
Connected to fd00::100:6ef0:49ff:fe00:efc5
SSH-2.0-OpenSSH_8.9p1

I have added a firewall rule which should allow all incoming traffic on that ip:port pair. Nothing has changed.

[admin@router] /ipv6/address> /ipv6/firewall/filter/print
Flags: X - disabled, I - invalid; D - dynamic 
 0    ;;; SSH test
      chain=input action=accept protocol=tcp dst-address-list=CURRENT-WAN-ADDRESS dst-port=22 log=no log-prefix=""

I tried with the pre- and postrouting chains too but no match on them:

[admin@router] > /ipv6/firewall/filter/print   
Flags: X - disabled, I - invalid; D - dynamic 
 0    ;;; SSH test
      chain=prerouting action=accept protocol=tcp dst-address-list=CURRENT-WAN-ADDRESS dst-port=22 log=no log-prefix="" 

 1    ;;; SSH test
      chain=postrouting action=accept protocol=tcp dst-address-list=CURRENT-WAN-ADDRESS dst-port=22 log=no log-prefix=""



[admin@router] /ipv6/address> /ipv6/firewall/nat/print
Flags: X - disabled, I - invalid; D - dynamic 
 0    ;;; SSH
      chain=dstnat action=dst-nat to-address=fd00::100:6ef0:49ff:fe00:efc5/128 to-ports=22 protocol=tcp dst-address-list=CURRENT-WAN-ADDRESS in-interface-list=WAN dst-port=22 
      log=no log-prefix=""

Ah, I gave you wrong chain names, these are not available in filter. You need input (to log incoming packets to WAN) and forward (to log to NATed packets to the SSH host).


Right, DST-NAT likely happens earlier and changes input chain to forward. You need to to accept CURRENT-WAN-ADDRESS → fd00::100:6ef0:49ff:fe00:efc5/128 in the forward chain. E.g. via /ipv6/firewall/filter add chain=forward action=accept connection-nat-state=dstnat

Hi,

Sorry for the delay! There were a few task I had to respond immediately.

It works fine now.

Allowing in the forward chain all dst-natted connections was the key to solve my problem.

Thanks for your help!

[admin@router] > /ipv6/firewall/nat/print
Flags: X - disabled, I - invalid; D - dynamic 
 0    ;;; SSH
      chain=dstnat action=dst-nat to-address=fd00::100:6ef0:49ff:fe00:efc5/128 to-ports=22 protocol=tcp dst-address-list=CURRENT-WAN-ADDRESS in-interface-list=WAN dst-port=22 log=no 
      log-prefix=""



[admin@router] > /ipv6/firewall/filter/print
Flags: X - disabled, I - invalid; D - dynamic 

14    ;;; accept dst-nat forwarded packets (SSH port forward)
      chain=forward action=accept connection-nat-state=dstnat log=no log-prefix=""

Why would you break the end-to-end principle, create a network that now needs to rely on STUN/TURN to function in the application layer and defeat the purpose of IPv6 by using NAT66?

What you should be doing is plain stateful firewalling, each host/device in the network has a /128 GUA, and it can be stable, you simply add a firewall rule to permit inbound traffic to specified ports for a specific /128 address.

This means, in the forward chain, you can use the template from MikroTik’s official docs, and simply add a rule for accepting certain ports to certain hosts, that’s it.

Some more details here.

When you want to rely on DNS but your delegated IPv6 prefix is unstable, NAT66 is fewer steps if all you want is SSH access to that one machine.

For dynamic IPv6 PD. Use NPTv6 instead of NAT66, NPTv6 doesn’t break end to end principle and is natively supported on ROSv7. Use a script to update the external prefix whenever it changes from upstream.

I wanted to make the change transparent for the clients. This means I wanted to use one IPv6 address assigned to a domain name same way as it is implemented with IPv4: one IP for all the published services. Domain name also must be the same in both stacks. Maintaining more then one domain name would make my system more complex with no benefit in my case.

Now all works as excepted but I will check other options too, just to learn, so thanks for the heads-up!