Wednesday, September 3, 2025

So, you want to try IPv6?

I decided I should build an access router using VyOS 1.4.3. I thought you might like the journey.

I drew a lot of useful config snippets and inspiration from https://blog.daknob.net/ipv6-first-with-vyos/. Make sure you take a look at their posts.

I recently brought an Xfinity Now! connection into my house. It runs a bit over 100M/20M, so qualifies as broadband according to the lastest definition from the FCC here in the USA. At $30/month, it's pretty cheap.

My primary connection is with a WISP that I work for on/off, and we use the link to test new configurations, etc. So this Xfinity link is a backup for the times when I break the primary connection.

Knowing that Xfinity does a good job with IPv6, I thought I'd build up soemthing to show:
  • a VyOS config so people can implement it themselves if they want
  • the use of a management VRF
  • integrated recursive DNS (you don't need external resolvers who sell your data)
  • dual-stack IPv4 and IPv6 capabilities
  • IPv6 only with some IPv4 transition
  • use of IPv6 ULA for local services (DNS in this case)


Here's a diagram of the network that built up:

You'll note four interfaces in use:
  • eth0 -- a VRF used only for managment
  • eth1 -- our WAN connection to Xfinity
  • eth2 -- a dual-stack LAN
  • eth3 -- an IPv6-only LAN with DNS64/NAT64
I'm likely to add more LANs to this configuration as I go. In particular, I want a reference network using NAT66, but for now we'll live with the examples above.

First, I built up a management interface (eth0) that sits in its own VRF, then built up what you'd expect for an IPv4 environment.
#
# Build the VRF
set vrf name Mgmt table '101'
#
#setup the interface, and put it into the VRF
set interfaces ethernet eth0 address '198.51.100.11/24'
set interfaces ethernet eth0 description 'Management'
set interfaces ethernet eth0 vrf 'Mgmt'
#
# Make sure the VRF has a default route
set vrf name Mgmt protocols static route 0.0.0.0/0 next-hop 198.51.100.1 distance '200'
#
# make ssh works inside the VRF rather than in the data plane of the router
set service ssh vrf 'Mgmt'
#
# setup the WAN link
set interfaces ethernet eth1 description 'Xfinity WAN'
set interfaces ethernet eth1 address 'dhcp'
#
# setup the LAN link
set interfaces ethernet eth2 description 'LAN'
set interfaces ethernet eth2 address '192.0.2.1/24'
#
# Setup a DHCP pool for the LAN
set service dhcp-server listen-address '192.0.2.1'
set service dhcp-server shared-network-name Xfinity-Dual-Stack authoritative
set service dhcp-server shared-network-name Xfinity-Dual-Stack subnet 192.0.2.0/24 default-router '192.0.2.1'
set service dhcp-server shared-network-name Xfinity-Dual-Stack subnet 192.0.2.0/24 lease '3600'
set service dhcp-server shared-network-name Xfinity-Dual-Stack subnet 192.0.2.0/24 range 0 start '192.0.2.101'
set service dhcp-server shared-network-name Xfinity-Dual-Stack subnet 192.0.2.0/24 range 0 stop '192.0.2.200'
#
# setup NAT masquarade for the LAN
set nat source rule 100 outbound-interface name 'eth1'
set nat source rule 100 source address '192.0.2.0/24'
set nat source rule 100 translation address 'masquerade'
#
# Setup a recursive DNS server, and let it cache 10000 names
set service dns forwarding allow-from '192.0.2.0/24'
set service dns forwarding dnssec 'validate'
set service dns forwarding listen-address '127.0.0.1'
set service dns forwarding listen-address '192.0.2.1'
set service dns forwarding cache-size '10000'
#
# Make sure the dhcp-server hands out this information
set service dhcp-server shared-network-name Xfinity-Dual-Stack name-server '192.0.2.1'
Cool! Now we have IPv4 connecvitiy. Most people stop here!

Why stop with leagcy protocols? Xfinity will give us the ability to run IPv6 too!

It don't cost nuthin'
#
# First, we get an address from the provider via SLAAC.
set interfaces ethernet eth1 ipv6 address autoconf
#
# Next, we request a /56 as PD #1  (Xifiniy will only give us a /60,
# but I can dream, right?)
set interfaces ethernet eth1 dhcpv6-options pd 1 length '56'
#
# Now, we tell VyOS to build up the IPv6 address for eth2 based on the
# IA-PD we received on eth1.  It gets built up in the form:
#        [prefix]:[sla-id]:[address]
set interfaces ethernet eth1 dhcpv6-options pd 1 interface eth2 sla-id '0'
set interfaces ethernet eth1 dhcpv6-options pd 1 interface eth2 address '1'
Now the router has a dynamic address based on what our provider sends us.

Our LAN clients can build their own network addresses via SLAAC if we start router advertisements on eth2:
#
# advertise all the prefixes on the interface
set service router-advert interface eth2 prefix ::/64
At this point, anyone on eth2 has dual-stack capability, but only the IPv4 folks have DNS resolution. We have a DNS resolver running on the VyOS host, but for IPv4, it is using non-unique addresses for local communication. This local addressing is NATted before leaving the local network.

(I'm publishing this using the addresses assigned for test/examples as defined in RFC5735. You might want to substitue addresses from RFC1918 if you follow this config.)

Our IPv6 setup has dynamically assigned unique addressing. We don't have any means to setup the DNS server to listen on those addresses, becasue we don't know them!

To address this situation, we're going to utilize IPv6 ULA addresses. This block of space is defined in RFC4193, and has similar use to the IPv4 addresses defined in RFC1918.

IPv6 has an example network (2001:db8::/32), but there is not clear ULA space set aside for examples. In this config, I'm going to use fd89:73ab:e943::/48. You should generate your own prefix based on RFC4193.

At the time of this writing, there is a site that will generate a prefix for you: https://www.unique-local-ipv6.com/

Another important note at this point. We are going to have both GUA and ULA addresses on the LAN hosts. The use of mutlitple addresses on an IPv6 host is expected, but sometimes feels a bit strange to folks habituated to IPv4.

We're using fd89:73ab:e943::/48 for our ULA block, but this LAN will be using fd89:73ab:e943:2::/64.

#
# anchor the router in the ULA space, by giving it a loopback address in that space
set interfaces loopback lo address 'fd89:73ab:e943::1/128'
#
#  Assign a static ULA address to the interface (and point out we're dual-stack!)
set interfaces ethernet eth2 address 'fd89:73ab:e943:2::1/64'
set interfaces ethernet eth2 description 'dual-stack LAN'
#
# Tell the LAN hosts that they should generate SLACC addresses with this ULA block
#    (this isn't actually neeed, because we did it earlier with ::/64, but
#     leaving things this explicit might help someone trying to reason this out)
set service router-advert interface eth2 prefix fd89:73ab:e943:2::/64
#
# Start advertising the DNS server via RA
set service router-advert interface eth2 name-server 'fd89:73ab:e943:2::1'
At this point, we have a LAN that has dual-stack capabilities!

IPv4 address and DNS server information are delivered via DHCP. IPv6 hosts will hear RAs instructing them to generate their owan addgesses (both GUA and ULA). Those RAs will also indicate the DNS server address as well.

In IPv4, a side effect of NAT denies inbound connections. We can deny inbound IPv6 connections in a similar fashion with a stateful firewall. One example follows:
#
# build a stateful firewall so inbound connections are denied
set firewall group interface-group LAN interface 'eth2'
set firewall group interface-group WAN interface 'eth1'
set firewall ipv6 forward filter default-action 'drop'
set firewall ipv6 forward filter rule 10 action 'accept'
set firewall ipv6 forward filter rule 10 state 'established'
set firewall ipv6 forward filter rule 10 state 'related'
set firewall ipv6 forward filter rule 20 action 'accept'
set firewall ipv6 forward filter rule 20 protocol 'ipv6-icmp'
set firewall ipv6 forward filter rule 30 action 'accept'
set firewall ipv6 forward filter rule 30 inbound-interface group 'LAN'
set firewall ipv6 forward filter rule 90 action 'drop'
set firewall ipv6 forward filter rule 90 inbound-interface group 'WAN'
Now, we'll setup the final LAN as an IPv6 only network:
#
# setup our static ULA assignement for eth3
set interfaces ethernet eth3 description 'IPv6 only - NAT64'
set interfaces ethernet eth3 address 'fd89:73ab:e943:3::1/64'
#
# add our dynamic allocation as well for GUA
set interfaces ethernet eth1 dhcpv6-options pd 1 interface eth3 address '1'
set interfaces ethernet eth1 dhcpv6-options pd 1 interface eth3 sla-id '1'
#
# Setup RA for this LAN (we'll trust the "prefix ::/64" to advertise both GUA and ULA
set service router-advert interface eth3 prefix ::/64
set service router-advert interface eth3 name-server 'fd89:73ab:e943:3::1'
#
# Tell the DNS server that it's ok to listen to the new LAN
set service dns forwarding listen-address 'fd89:73ab:e943:3::1'
We now have a working IPv6-only LAN!

With a little bit more of configuration, we can take advantage of a pair of IPv6 transtition technologies referred to as DNS64/NAT64. I'll leave deeper study to the casual reader, but a quick overview of this is:
  • DNS64 -- In cases of host that have A records, but no AAAA records, we'll synthesize a AAAA that uses a special IPv6 prefix
  • NAT64 -- Whenever the special prefix is used, we'll NAT from IPv6 to IPv4 to proxy the service requested
In this case, we're going to use the default IPv6 DNS64 prefix: 64:ff9b::/96

Let's say you want to connect to example.com which has an A record for 192.0.2.123. The DNS transaction will look like:
  • you request an AAAA record from the DNS server (you're IPv6 only, remember?)
  • the DNS server will note that no AAAA is published, but there is an A record
  • the DNS servie will create an AAAA record based on the A record, and return it to you
In essence, the DNS serve will LIE to you. The AAAA record in this case would be: 64:ff9b::192.0.2.123

When you iniate a connection to anything within the 64:ff9b::/96 prefix, the router will undertand that it needs to proxy an IPv4 connection to the appropriate host.

Although not strictly needed, RFC8781 also points out good reasons to let the LAN hosts know the NAT64 prefix.

The VyOS config is rather short for all of this:
#
# tell the DNS server we're going to do DNS64
set service dns forwarding dns64-prefix '64:ff9b::/96'
#
# tell the router to do NAT64
set nat64 source rule 1 source prefix '64:ff9b::/96'
#
# use RAs to tell the LAN hosts the NAT64 prefix
set service router-advert interface eth3 nat64prefix 64:ff9b::/96
#
# add this LAN to the stateful firewall setup
set firewall group interface-group LAN interface 'eth3'
At this point, there are two working LANs:
  1. eth2 -- dual stack IPv4/6
  2. eth3 -- IPv6 only with DNS64/NAT64
I'll probably add a few more LANs before I'm done to document other IPv6 transitional technologies. For now, I'm pretty happy with this setup.

As I started to publish this, I realized that the router itself didn't have DNS services! I decided that it should use it's own recursion and use IPv6 for all queries, so add this:
#
# allow queries from the loopback
set service dns forwarding listen-address '::1'
#
# send queries to the loopback
set system name-server '::1'
~

No comments:

Post a Comment