SIIT-DC for Vyos pfzetto's logo

Vyos currently doesn't support SIIT but it can be used with a workaround.

This post was published on 2024-11-25.

My entire infrastructure runs on single-stack IPv6. To support IPv4 clients, I was using Debian VMs running Jool as a stateless IP/ICMP translator. Today, I wanted to remove the extra hop and incorporate the translators into my Vyos routers.

Vyos currently doesn't support stateless IP/ICMP translation (SIIT) but uses Jool to support NAT64.

A little bit of work is required to use Jool as a SIIT translator.

  1. Create a new network namespace for Jool:

    $ set netns name siit
    
  2. Create a virtual ethernet link:

    $ set interfaces virtual-ethernet veth0 address 172.16.0.1/30
    $ set interfaces virtual-ethernet veth0 address fdff:5969:4350::1/48
    $ set interfaces virtual-ethernet veth0 peer-name veth1
    $ set interfaces virtual-ethernet veth1 address 172.16.0.2/30
    $ set interfaces virtual-ethernet veth1 address fdff:5969:4350::2/48
    $ set interfaces virtual-ethernet veth1 peer-name veth0
    $ set interfaces virtual-ethernet veth1 netns siit
    
  3. Load the kernel module (insert into /config/scripts/vyos-postconfig-bootup.script for execution after (re-)boot):

    modprobe jool_siit
    
  4. Create correct routes in the Jool namespace (insert into /config/scripts/vyos-postconfig-bootup.script for execution after (re-)boot):

    ip netns exec siit ip route add default via 172.16.0.1
    ip netns exec siit ip -6 route add default via fdff:5969:4350::1
    
  5. Set up Jool (insert into /config/scripts/vyos-postconfig-bootup.script for execution after (re-)boot):

    ip netns exec siit jool_siit instance add default -6 64:ff9b::/96
    
  6. Configure static routes:

    # for each external IPv4 <ipv4> create
    $ set route <ipv4>/32 next-hop 172.16.0.2
    
    $ set route6 64:ff9b::/96 next-hop fdff:5969:4350::2
    
  7. (optional) Create EAMT mappings if needed (insert into /config/scripts/vyos-postconfig-bootup.script for execution after (re-)boot):

    ip netns exec siit jool_siit eamt add <ipv4> <ipv6>
    
  8. (optional) Create NAT66 rules to use a single external IPv4 address:

    # for each eamt-host with <ipv6> and <ipv4> insert rule <i>
    $ set rule nat66 source rule <i> exclude
    $ set rule nat66 source rule <i> outbound-interface name veth0
    $ set rule nat66 source rule <i> source prefix <ipv6>/128
    
    # choose <n> higher than the highest <i> of the eamt rules
    $ set rule nat66 source rule <n> destination prefix 64:ff9b::/96
    
    # x.x.x.x is the external IPv4 address
    $ set interfaces virtual-ethernet veth0 address 64:ff9b::x.x.x.x/96
    $ set rule nat66 source rule <n> translation address 64:ff9b::x.x.x.x
    $ set rule nat66 source rule <n> outbound-interface name veth0
    

Now, incoming IPv4 packets will be translated into IPv6 packets (originating from 64:ff9b::y.y.y.y/96). Outgoing IPv6 packets that are destined for 64:ff9b::/96 will be translated into IPv4 packets (originating either from the IPv4 specified as EAMT for the source IPv6 address or the IPv4 used with NAT66).

When using zone-based firewalling, I would recommend combining veth0 and your WAN interface into one zone.