networking n stuff

Monday, July 23, 2018

IPv6 Lab: ISP & Client Side using Linux and Cisco

So I got really tired of reading about some basic IPv6  stuff and then forgetting it in a couple of months due to lack of practice and decided to set up a lab, which will contain both ISP and client sides.
This is what my topology will look like:

Components used:
  • Client_PC: Linux box with Ubuntu Server 18.04 installed with rdnssd (which is required to receive list of DNS servers via RA);
  • Home_Router: Linux box with Ubuntu Server 18.04 installed with wide-dhcpv6-client and radvd. (I had to install wide-dhcpv6-client, cause isc-dhcp-client, which comes by default, barely has any decent documentation and I wasn't even able to find out if it supports some of the features we're going to use in this lab);
  • ISP_R1: Cisco C7200 15.2(4)S6. It's used as DHCPv6 server as well.
How I'm going to assign IPv6 addresses to devices (I'll cover the details of different ways to achieve this further)
  • Client_PC: no DHCPv6 at all, only Stateless Address Autoconfiguration
  • Home_Router: DHCPv6.

So before we start let's review how we can assign all the necessary stuff like addresses, default gateways and DNS servers in IPv6.

  • Configuring hosts without DHCPv6 at all, using only Router Advertisements (SLAAC).
Example of a RA message
With RA you can provide your host with prefix information (host generates its IPv6 address based on this), DNS servers list (note IETF didn't originally planned to include support of this option, and it was added later, so most clients don't usually support it out of box; you'll have to install rddnsd on Linux to support this and I don't think Windows support it at all without any third-party-software. Ugh) and default gateway (note it's not listed anywhere specifically, host just assumes that the source of accepted RA is gateway indeed). You can't use RA to provide things like standalone IPv6 address or advanced DHCP options like domain name.
In SLAAC, host doesn't send any requests to router, it just listens passively.
  • Configuring hosts with RA and DHCPv6 server
Example of DHCPv6 request

With DHCPv6 you can provide your host with prefix information, standalone IPv6 address, DNS servers list and other cool stuff. Note you can't define default gateway in DHCPv6 message, you still have to use RA for it). And of course, with DHCPv6 it's just like good old DHCPv4: client requests, server responds, so unlike plain RA with DHCPv6 you can distinguish clients from each other and make decisions based now it (for instance, assign prefix blocks to clients based on DUID - one of the things I'm going to do in this lab). 

What would an ideal configuration look like from ISP side and from client, considering you as a client have a router and few devices behind it? Well, ISP would probably like to delegate a single /64 prefix to you. ISP would probably like this prefix to be static so they don't have to keep track of it, so there should be something you can be identified by. 

Another question that rises is whether your router's WAN interface should be assigned a separate globally routed /128 address? Note that you don't need global address on WAN interface to route traffic. So the scheme can basically work like this:

We're all good without global IPv6 addresses on WAN link
The routing entry for delegated prefix will look like this on ISP_R1 (it says "static" so you can think "oh so you just configured it that way", but it's generated automatically - I'll show it later):

S   2001:DB8:6666:6666::/64 [1/0]
     via FE80::250:1FF:FE00:301, FastEthernet1/0

So, once again, the ISP don't need you to have global address on your WAN link. ISP's edge router is all good with having your global address with link-local address as next-hop. There's nothing wrong about it, and some ISPs have it just like this - they only delegate a /64 prefix to you and you live happily ever after with this.
However, some ISPs, Comcast for instance, not only delegate you a /64 prefix but also a single /128 address. Why would they do such a thing if it's not really required for routing? I can think of a several scenarios here:
- it's just a single unified configuration for two scenarios: when there's a client router with other devices behind it (so there's obviously a need for prefix) and when there's a single host (so there's no need to delegate a whole prefix and one /128 would be enough)
- your home router needs not only to route traffic, but also interact with the outer space world like a host (for instance, you have VPN configured on it..), and it's not smart enough to use address from its internal interface as source address - it can only use address from WAN interface. So we'll have to give it this address.

Now we're armed with this knowledge, let's start configuring our devices.

On your Linux router first of all you'll need to add following lines to /etc/sysctl.conf:


The first line tells your box to enable IPv6 forwarding. The second one tells your box that although it's acting as router, it still has to listen to other routers Router Advertisements specifically on WAN interface, which is ens4 in my case.

As I said, you'll have to install wide-dhcp client. Your configuration file (/etc/wide-dhcpv6/dhcp6c.conf) should look like this:

interface ens4 {
  send ia-pd 1;
  send ia-na 1;
  request domain-name-servers;
  script "/etc/wide-dhcpv6/dhcp6c-script";

id-assoc pd 1 {
        prefix-interface ens5 {
        sla-id 1;
        sla-len 0;


So, what's going on here? Let's examine every line:
send ia-pd 1 - this line tells our host to request a /64 prefix from ISP. "1" refers to the next section id-assoc pd 1, so we're just saying something like "the prefix received with the id of 1 should be used with the piece of configuration contained in id-assoc pd 1.

send ia-na 1 - this line tell our host to request for a single /128 address. As I said before, it's not required for routing to function, so you can just throw this piece away. NA stands for Non-temporary address and there's immediately a question - if there's a nontemporary addresses, what's temporary address and what it's for? I won't describe it here so just google "ipv6 privacy extensions".
As you see there's an id of "1", but there's no related to it "id-assoc na 1" piece of configuration so that assumes this configuration will be appended to interface it was configured on (hence, ens4).

prefix-interface ens5 - our LAN interface;

sla-id - is used together with sla-len. That's basically needed when you receive, for instance, /48 prefix from and want to break it to several /64 networks. I'll just refer to wide-dhcp man here: "For example, if SLA-ID is 1, SLA-LEN is 16 and the client is delegated an IPv6 prefix 2001:db8:ffff::/48, dhcp6c will combine the two values into a single IPv6 prefix, 2001:db8:ffff:1::/64, and will configure the prefix on the specified interface."

sla-len - see above. If you're assigned anything different from /64 (/48, /56..), subtract the prefix size you're assigned from 64.

You'll also have to configure your /etc/network/interfaces like this:

allow-hotplug ens4
iface ens4 inet6 manual

allow-hotplug ens5
iface ens5 inet6 manual

Now let's proceed to configuring Cisco.

ipv6 unicast-routing
ipv6 dhcp pool MY_RAD_POOL
 prefix-delegation 2001:DB8:6666:6666::/64 0001000122E31BA0005001000300
 address prefix 2001:DB8:5555:5555::/64
 dns-server 2001:4860:4860::8888
 dns-server 2001:4860:4860::8844
ipv6 cef
interface FastEthernet1/0
 no ip address
 duplex full
 ipv6 address 2001:DB8:5555:5555::1/64
 ipv6 enable
 ipv6 nd prefix 2001:DB8:5555:5555::/64 no-advertise
 ipv6 dhcp server MY_RAD_POOL

Let's examine it:

prefix-delegation 2001:DB8:6666:6666::/64 0001000122E31BA0005001000300 probably looks intriguing. 0001000122E31BA0005001000300 is DUID, which stands for Driving Under the Influence of Drugs DHCPv6 Unique Identifier - it's generated by client unique value which it send in DHCP request and is used by DHCPv6 server to identify the client. I'll show you how it's generated (there's actually three different ways to generate it) and where it's stored in a few minutes. So now we're just saying that we give 2001:DB8:6666:6666::/64 to the client which DUID is 0001000122E31BA0005001000300.

address prefix 2001:DB8:5555:5555::/64 - range for giving out /128 addresses to WAN interface. Is required only if you chose to configure send ia-na 1 on a client.

ipv6 address 2001:DB8:5555:5555::1/64 - is also required only if you're giving out /128 addresses. NOT requited if you only give out a prefix. You should note though that if your router is acting not as DHCP Server, but as DHCP Relay Agent, you got to have global or site-local (not link-local!) address on client facing interface, otherwise agent will drop all requests (because client facing interface address is a required field in Relay message).

ipv6 nd prefix 2001:DB8:5555:5555::/64 no-advertise - here we tell R1 not to include prefix 2001:DB8:5555:5555::/64 in RA advertisement.

Now let's take Wireshark and look closely to what's going on. Note I cut off packets not related to RA and DHCPv6 and I'm not going to examine Neighbour Solicitation messages and stuff like that. If you're not confident about this things, here is a brilliant post explaining it. You can also download all the captures I used here to look at them instead of looking at screenshots.

Let's examine every packet in this capture.

1. Our host simply asks for RA, sending packet to FF02::2, thus asking all the routers which listen to this multicast group send a response.
2. R1 sends a RA to all hosts (FF02::1). Note it doesn't have any prefix information in it, because we disabled it with ipv6 nd prefix 2001:DB8:5555:5555::/64 no-advertise.

3. Here our host sends message to all DHCPv6 servers (FF02::1:2), asking for everything we have configured before and sending DUID:

Fields marked are identical to what we've configured in dhcp6c.conf. But now it's time to look closer to DUID. 

DUID is generated by wide-dhcp client and is located in /var/lib/dhcpv6/dhcp6c_duid. You'll have to convert it to a normal hex format to view it, however (credits for that trick go here):

rootx@ubuntu18_eve:~$ hexdump -s 2 -e '14/1 "%02x " "\n"' /var/lib/dhcpv6/dhcp6c_duid
00 01 00 01 22 e3 1b a0 00 50 01 00 03 00

OK, but how it's generated? There are three different ways to generate it, you can read about them here. Our DUID, as you can see on the screenshot, is Type 1—Link-layer address plus time (DUID-LLT).

4. Server sends DHCPv6 Advertise message (note it's unicast now):

5. If we're satisfied with what DHCPv6 server offers to us, we send a request with the values listed in Advertise message. 
6. Server responds with everything we requested.

Let's make sure our host got all the configuration it requested:

rootx@ubuntu18_eve:~$ ifconfig ens4 | grep global

        inet6 2001:db8:5555:5555:480b:94eb:53fa:de5a  prefixlen 128  scopeid 0x0<global>
rootx@ubuntu18_eve:~$ ifconfig ens5 | grep global   
        inet6 2001:db8:6666:6666:250:1ff:fe00:302  prefixlen 64  scopeid 0x0<global>

I cut the output of route command to include only the routes we're interested in.
rootx@ubuntu18_eve:~$ route -n -A inet6   
Kernel IPv6 routing table
Destination                    Next Hop                   Flag Met Ref Use If
2001:db8:5555:5555:480b:94eb:53fa:de5a/128 ::             U    256 1     0 ens4
2001:db8:6666:6666::/64        ::                         U    256 1     0 ens5
::/0                           fe80::c801:3aff:febf:1c    UGDAe10242    10 ens4
2001:db8:5555:5555:480b:94eb:53fa:de5a/128 ::             Un   0   3     9 ens4
2001:db8:6666:6666::/128       ::                         Un   0   2     0 ens5
2001:db8:6666:6666:250:1ff:fe00:302/128 ::                Un   0   2     0 ens5

rootx@ubuntu18_eve:~$ cat /etc/resolv.conf 
nameserver 2001:4860:4860::8888
nameserver 2001:4860:4860::8844

OK, everything seems to be fine - our WAN interface was assigned an /128 address, our LAN ens5 interface was assigned an address from /64 prefix we were given, there's a default route in our table and we receive DNS servers list. Now let's configure some extra prefix on R1 to check connectivity:

interface Loopback0

 no ip address
 ipv6 address 2001:DB8:9999:9999::1/128
 ipv6 enable

Now let's ping it from our router:

rootx@ubuntu18_eve:~$ ping6 2001:DB8:9999:9999::1
PING 2001:DB8:9999:9999::1(2001:db8:9999:9999::1) 56 data bytes
64 bytes from 2001:db8:9999:9999::1: icmp_seq=1 ttl=64 time=11.1 ms
64 bytes from 2001:db8:9999:9999::1: icmp_seq=2 ttl=64 time=1.35 ms
64 bytes from 2001:db8:9999:9999::1: icmp_seq=3 ttl=64 time=7.01 ms

Great. How does our route looks from Cisco's side?

R1#sh ipv6 route
IPv6 Routing Table - default - 5 entries
Codes: C - Connected, L - Local, S - Static, U - Per-user Static route
       B - BGP, R - RIP, H - NHRP, I1 - ISIS L1
       I2 - ISIS L2, IA - ISIS interarea, IS - ISIS summary, D - EIGRP
       EX - EIGRP external, ND - ND Default, NDp - ND Prefix, DCE - Destination
       NDr - Redirect, O - OSPF Intra, OI - OSPF Inter, OE1 - OSPF ext 1
       OE2 - OSPF ext 2, ON1 - OSPF NSSA ext 1, ON2 - OSPF NSSA ext 2, l - LISP
C   2001:DB8:5555:5555::/64 [0/0]
     via FastEthernet1/0, directly connected
L   2001:DB8:5555:5555::1/128 [0/0]
     via FastEthernet1/0, receive
S   2001:DB8:6666:6666::/64 [1/0]
     via FE80::250:1FF:FE00:301, FastEthernet1/0
L   FF00::/8 [0/0]
     via Null0, receive

Cool. As you remember, we didn't configure route 2001:DB8:6666:6666::/64 statically. It's put in routing table automatically after DHCP server assigns that prefix to someone.

The last thing we need to do is to configure our home router to send RA announcements to Home_PC. You need to add the following lines to your /etc/radvd.conf file:

interface ens5
   AdvSendAdvert on;
   prefix 2001:DB8:6666:6666::/64
      AdvOnLink on;
          AdvAutonomous on;
          AdvRouterAddr on;

RDNSS 2001:4860:4860::8888 2001:4860:4860::8844

"But you hardcoded our prefix here! What if I receive a dynamic prefix from my ISP?" - you might ask. Well, at the moment there's no ready-to-go workarounds for it so if you have a dynamic prefix and want to use stateless configuration for your LAN you'll have to write a script that will generate config file for radvd based on prefix you received from your ISP.

On Home_PC you need to install rdnssd - no additional config required.
So, let's run Wireshark once again:

Just a RA and then a Neighbour Solicitation from a client to ensure no one is using this address already.

Let's check client received the route and DNS servers list:

rootx@home_pc:~$ route -n -A inet6   
Kernel IPv6 routing table
Destination                    Next Hop                   Flag Met Ref Use If
2001:db8:6666:6666::/64        ::                         UAe  256 1     0 ens5
::/0                           fe80::250:1ff:fe00:302     UGDAe10241     0 ens5
2001:db8:6666:6666:250:1ff:fe00:402/128 ::                Un   0   2     0 ens5

rootx@home_pc:~$ cat /etc/resolv.conf
nameserver 2001:4860:4860::8888
nameserver 2001:4860:4860::8844

Checking connectivity:

rootx@home_pc:~$ ping6 2001:DB8:9999:9999::1
PING 2001:DB8:9999:9999::1(2001:db8:9999:9999::1) 56 data bytes
64 bytes from 2001:db8:9999:9999::1: icmp_seq=1 ttl=63 time=12.1 ms
64 bytes from 2001:db8:9999:9999::1: icmp_seq=2 ttl=63 time=6.03 ms
64 bytes from 2001:db8:9999:9999::1: icmp_seq=3 ttl=63 time=1.73 ms

Wow! Our network is IPv6 ready now. Amazing. 
I have a serious doubt anyone is still reading this but if you are and have some questions/comments -  don't hestitate to post a comment!

No comments:

Post a Comment