Archive for ‘Uncategorized’ Category

What makes a good IPv6 implementation?

datePosted on 12:23, November 23rd, 2018 by Craig Miller

Bad IPv6 support costs Money

I have been working with Docker lately, and as cool as the container technology is, it was originally built without consideration for IPv6, and then IPv6 was bolted on later. Making supporting IPv6 full of expensive work-a-rounds.

But that got me thinking what makes a good IPv6 implementation? Of course this is my opinion, and you are free to toss in other criteria, so think of this as a thought starter.

Why is this important?

With 25% of the internet carried over IPv6 as of this writing, if you are developing a product which has a lifetime of 5 to 10 years, and you aren’t giving thought as to how you will support IPv6, then your product will:

  • A) fail, or
  • B) you will try to bolt on IPv6 on the side, or
  • C) have to be completely rewritten.

All of that costs money.

A good IPv6 device implementation

There are broad areas where IPv6 should work well.


As much as I like the simplicity of SLAAC (Stateless Address Auto Config), there are certainly use cases where DHCPv6 is a better choice. A good implementation should:

  • Support both addressing methods, SLAAC, and DHCPv6
  • Be able to reestablish IPv6 GUA (Global Unique Address) once the device comes out of sleep/suspend or link down/up (systemd suffers this problem)
  • Play well with DNS. Very few of us enjoy typing IPv6 addresses, the implementation should have a stable IPv6 address which can be entered into DNS without requiring a lot of DNS churn.


IPv6 is not IPv4 with colons. There are somethings which are different for good reason.

  • Default routes are link-local addresses (Docker fails on this one big time). GUAs may change, link-locals shouldn’t.
  • Supports RA (Router Advertisement) fields, RDNSS (DNS server), and DNSSL (DNS domain search list). Not much use having an address if the host can’t resolve names
  • If the device is routing (such as Docker) then support DHCPv6-PD, and provide the option of prefix delegation into the container/downstream network.


Basic protection from network misconfiguration, or out right attacks makes the IPv6 device better prepared for production use.

  • Rational limit on the number of IPv6 addresses an interface may have. Before systemd, the Linux kernel defaulted to 16. This seemed like a good compromise. Back in systemd v232, it was possible to exhaust memory on an IPv6 host by feeding it Random RA addresses, creating a denial of service. FreeBSD v11.5 has a similar problem, where the system will add over 3000 IPv6 addresses, and the system will slow to a crawl.
  • Rational limit on the number of neighbours. IPv6 /64 networks are sparsely populated and therefore one shouldn’t have to expect to support all 16 Quintilian (2^64) neighbours. Something like 1000, or even 256 should be enough.
  • Don’t assume that the Linux Stack has your back. Since systemd has become widespread, there are many IPv6 systemd bugs, which weren’t there in the pre-systemd kernel days. IPv6 is a different stack, be sure to test it.


I am sure I missing a few, but this is a start. When developing a product, the business case for supporting IPv6 well, is that it will save you money in the long run, by not having to go back and try to bolt IPv6 on, or rewrite your network stack later.

P.S I wouldn’t recommend putting Docker into production because of the severe IPv6 limitations. I’ll be looking at LXC next.

Image: Yachts colliding: Creative Commons/Mark Pilbeam


categoryPosted in Uncategorized | commentsComments Off on What makes a good IPv6 implementation? | moreRead More »

Hi Neighbour!

datePosted on 04:28, October 11th, 2018 by Craig Miller

Mr. Rogers

Neighbour Discovery Protocol (NDP) is more than just an IPv6 version of ARP (Address Resolution Protocol). It really is Neighbour Discovery, handling Layer 2 MAC address resolution, but also router discovery, and even better path handling (Redirection).

ARP is a funny protocol, as it isn’t part of the IPv4 suite, but IPv4 will not work without it. The creators of IPv6, were looking for an inclusive method (e.g. part of the IPv6 protocol) to accomplish MAC Address resolution. They chose to use ICMPv6, which is a Layer 4 protocol.

But how does one use a Layer 4 (L4) protocol to resolve Layer 2 (L2) information (the MAC address) when both L2 and L3 information is needed before the packet requesting Address Resolution can be sent?

ND Addressing

To answer this question, some special L3 addresses had to be created. The first is the Link-Local address, a non-routable address limited to the scope of the link (think broadcast domain), and always start with FE80.

The second involves multicast. Since it was decided that broadcast wouldn’t be used in IPv6 (since every end-station must listen to broadcast), a few special multicast addresses would be created.

  • FF02::1 All Nodes Address (all nodes must listen to this address on the link)
  • FF02::2 All Routers Address (all routers must listen to this address)
  • FF02::1:FF:XX:YYZZ Solicited Node Address where the last 3 bytes are the last 3 bytes of the L3 destination address (each node must listen to their own Solicited Node Multicast Address)

An example of the Solicited Node Address where the L3 address is: 2001:db8:ebbd:0:5066:64f6:547e:4872 would be ff02::1:ff7e:4872

ND Functions

Neighbour Discovery (ND) does more than just MAC Address Resolution. It also performs:

  • Duplicate Address Detection – DAD
  • Redirection (to a router with a better path)

In the early days of IPv4, duplicate addresses on the network was easy to do, since there was no automatic way to get an address (pre-DHCP), and addresses were manually entered. Creating a list of used addresses was quite common, some even used MS Excel. After DHCP had been created, duplicate addresses seemed like a thing of the past. But then VMs (Virtual Machines) came along, and cloning VMs became common. A clone which included the MAC address, would get the same IP address from the DHCP server as the original (one reason why DHCPv6 does not use a simple MAC address as an identifier).

Duplicate Address Detection

But back in the early days of creating IPv6, there was no DHCP, and the creators wanted to improved upon the situation by creating Duplicate Address Detection (DAD).

Because IPv6 nodes can create a globally unique address (GUA) without contacting any servers, using SLAAC (StateLess Auto Address Config), DAD becomes important in preventing duplicate addressing. When a node forms its GUA, it sends out a Neighbour Solicitation (NS) message to its own Solicited Node Address, similar to a gratuitous ARP in IPv4.

But the key difference from ARP is that if there isn’t a duplicate address on the network, no other host will hear the NS message. Why? Because no other nodes are listening to that specific multicast address, where as ARP requires ALL nodes to listen.


Part of knowing the neighbourhood, is knowing what routers exist on the link. Communication with routers will use another special mutlicast address FF02::2.

As a host becomes active on the network, it will send Router Solicitations (RS) to the All Routers address. The routers on the link will then respond with Router Advertisements (RA), which include important bits of information, such as default gateway, prefixes defined on the link, even DNS servers.

On a network (shown below) where there is more than one router on the link, the default gateway router (e.g. the Production Router) may send a Redirect to host (DNS Server), stating another router (Test Network Router) on the link is a better path. The Redirect will also include the link-local address of the better path router.

Network Diagram

Unlike IPv4, next hop addresses, and default gateways are usually link-local addresses, rather than GUAs. Since link-local addresses are limited to the link, they are a good choice for next hop addresses. IPv6 Tip resist the temptation to make all router interface link-local addresses fd80::1.

  • This will break Redirection, which will lower the resiliency of your network (how to you say use this other address that is the same as my address?)
  • Should two networks get crossed (someone plugs in an ethernet cable to the wrong port), you will spend a long time sniffing fe80::1packets, wondering which router they are coming from.

Link-layer or MAC Address Resolution

Oh, and ND also does MAC Address resolution (like ARP). When Host A has the IP address, but not the MAC address of Host B, it will send a NS message to the Multicast Solicited Node address of Host B, using the last 3 bytes of the IPv6 address as the last 3 bytes of the Solicited Node Address.

Since on the average network, only one host will be listening to the Solicited Node Multicast Address, the Host B will respond with a NA which includes the destination MAC address ***.

After receiving the destination MAC address from Host BHost A can send an IPv6 packet to Host B.

ICMPv6 and ND

ND uses the following ICMPv6 message types to discover what is happening in the neighbourhood:

  • NS (type 135)
  • NA (type 136)
  • RS (type 133)
  • RA (type 134)
  • Redirect (type 137)

Because ND uses ICMPv6 extensively, the quickest way to cut yourself off of the internet is to block all ICMPv6 traffic on your firewall. Although this is common in IPv4, resist this temptation. ICMPv6 messages are required to remain connected in IPv6.

Free IPv6 Book

If you want to learn how IPv6 really works, check out this free eBook (PDF). It is an excellent Cisco Press book published in 2013. It may not have the latest RFC references, like RFC 8200 (the IPv6 Standard RFC), but it is still a good read.

IPv6 Fundementals

Download IPv6 Fundementals

The second edition is even better (but not free)

** Fred Rogers Creative Commons

*** Of course, it is possible that the last 3 bytes of the IPv6 address will match that of another host on the network (a 1/16 million chance), but multicast will prevent the rest of the hosts on the network from hearing the idle chatter, unlike ARP.

categoryPosted in Uncategorized | commentsComments Off on Hi Neighbour! | moreRead More »

Babel: a routing protocol with wireless support

datePosted on 14:52, July 29th, 2018 by Craig Miller


Previously I wrote about resurrecting the old forgotten routing protocol, RIPng. In a small network of more than one router, you need a routing protocol to share information between the routers. I used RIPng for about six months, turned it on, and pretty much forgot that it was running. Worked like a charm in my wired network.

I moved to a new (to me) house this summer, and thought it was a good opportunity to try out a routing protocol which not only handles wired networks but also wireless. Babel seemed just the thing for this environment.

Enter Babel

Babel is a loop-avoiding distance-vector routing protocol that is robust and efficient both in ordinary wired networks and in wireless mesh networks. Based on the loss of hellos the cost of wireless links can be increased, making sketchy wireless links less preferred.

RFC 6126 standardizes the routing protocol.There are two implementations which are supported on OpenWrt routers, babeld and bird

Creating a network with redundant paths

Like anything in networking, it starts with the physical layer (wireless is a form of physical layer). I attached the wireless links of the backup link router to the production and test routers. Thus creating redundant path of connectivity within my house.

Network Diagram

Running BIRD with Babel

I chose bird6 (the IPv6 version of bird on OpenWrt) because I already had it installed on the routers for RIPng. It was merely a matter of commenting out the RIP section in the /etc/bird6.conf file, and enabling Babel.

The Bird Documentation provides an example. Add the following to /etc/bird6.conf get Babel running in bird6

protocol babel {
    interface "wlan0", "wlan1" {
        type wireless;
        hello interval 1;
        rxcost 512;
    interface "br-lan" {
        type wired;
    import all;
    export all;

In the example above, wlan0 is the 2.4 Ghz radio, and wlan1 is the 5 Ghz radio.

Checking the path of connectivity

When determining the connectivity path, traceroute6 (the IPv6 version) is your friend. Checking between the laptop and the DNS server, the path is:

$ traceroute6 6dns
traceroute to (2001:db8:ebbd:4118::1) from 2001:db8:ebbd:bac0:d999:cd8a:cd9b:2037, port 33434, from port 49819, 30 hops max, 60 bytes packets
 1  2001:db8:ebbd:bac0::1 (2001:db8:ebbd:bac0::1)  4.561 ms  0.510 ms  0.487 ms 
 2  2001:db8:ebbd:4118::1 (2001:db8:ebbd:4118::1)  2.562 ms  2.193 ms  1.927 ms 

The traceroute is showing the path going clockwise through the 2.4 Ghz wireless link.

Network Failure!

To test how well Babel can automatically route around failed links, I started a ping to the DNS server from the laptop and disabled the 2.4 Ghz radio, thus blocking the link the pings were using, and waited…

$ ping6 6dns
PING 6dns(2001:db8:ebbd:4118::1) 56 data bytes
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=1 ttl=63 time=3.54 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=2 ttl=63 time=1.64 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=3 ttl=63 time=2.02 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=4 ttl=63 time=1.64 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=5 ttl=63 time=1.51 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=6 ttl=63 time=1.65 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=7 ttl=63 time=1.58 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=8 ttl=63 time=5.80 ms
From 2001:db8:ebbd:bac0::1 icmp_seq=33 Destination unreachable: No route
From 2001:db8:ebbd:bac0::1 icmp_seq=34 Destination unreachable: No route
From 2001:db8:ebbd:bac0::1 icmp_seq=48 Destination unreachable: No route
From 2001:db8:ebbd:bac0::1 icmp_seq=49 Destination unreachable: No route
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=101 ttl=61 time=2.12 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=102 ttl=61 time=3.42 ms
64 bytes from 2001:db8:ebbd:4118::1: icmp_seq=103 ttl=61 time=3.16 ms

As you can see the outage was 93 seconds (101 – 8). Not a record time, OSPF would converge much faster, but still it did fix itself without human intervention.

Checking the connectivity path with traceroute6:

$ traceroute6 6dns
traceroute to (2001:db8:ebbd:4118::1) from 2001:db8:ebbd:bac0:d999:cd8a:cd9b:2037, port 33434, from port 47725, 30 hops max, 60 bytes packets
 1  2001:db8:ebbd:bac0::1 (2001:db8:ebbd:bac0::1)  0.541 ms  0.445 ms  0.437 ms 
 2  2001:db8:ebbd:2080::1 (2001:db8:ebbd:2080::1)  1.705 ms  1.832 ms  1.817 ms 
 3  2001:db8:ebbd:2000::1 (2001:db8:ebbd:2000::1)  2.273 ms  1.891 ms  2.584 ms 
 4  2001:db8:ebbd:4118::1 (2001:db8:ebbd:4118::1)  2.348 ms  2.822 ms  2.289 ms 

The path can now be seen to be traveling counter-clockwise around the circle via the 5 Ghz link. The Babel routing protocol is routing packets around the failure.

Wireless is great, except …

As more and more things come online using wireless there will be more interference and contention for bandwidth, especially in the 2.4 Ghz band. Babel can enables routing of packets around sketchy wireless links due to interference in a crowded wifi environment.

Your Metric may vary

Because wireless is variable, Babel applies differing metrics to routes as the wireless signal changes. An unfortunate side effect of this is that the network is continuously converging (or changing). The route that may have been used last minute to the remote host, my be invalid the next minute.

I noticed this as my previously very stable IPv6-only servers were now disconnecting, or worse, not reachable.

Route Flapping!

As I looked at the OpenWrt syslog (using the logread command) I could see that the routes were continually changing.

Tue Jul 24 14:46:45 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:46:45 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:46:46 2018 odhcpd[778]: Using a RA lifetime of 1800 seconds on br-lan
Tue Jul 24 14:47:01 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:47:01 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:47:02 2018 odhcpd[778]: Using a RA lifetime of 1800 seconds on br-lan
Tue Jul 24 14:47:33 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:47:33 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:47:34 2018 odhcpd[778]: Using a RA lifetime of 1800 seconds on br-lan
Tue Jul 24 14:47:49 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:47:49 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:47:50 2018 odhcpd[778]: Using a RA lifetime of 1800 seconds on br-lan
Tue Jul 24 14:48:53 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:48:53 2018 odhcpd[778]: Raising SIGUSR1 due to default route change
Tue Jul 24 14:48:54 2018 odhcpd[778]: Using a RA lifetime of 1800 seconds on br-lan

The problem with this route flapping is that it was being propagated to the other routers which were busy adding and removing routes, causing unreachable to parts of my network. Not a desired behaviour.

Settling things down

To rid my network of the route churn, I changed the Babel wireless interfaces to wired, giving them a stable metric, no longer tied to the variability of the wireless signal quality (signal to noise).

The /etc/bird6.conf now looks like:

protocol babel {
    interface "wlan0", "wlan1" {
        type wired;
        hello interval 5;
    interface "br-lan" {
        type wired;
    import all;
    export all;

Restarting bird6, and looking at the syslog, a brief activity can be seen, then the route churn stops, and the network is stable.

Babel, still a work in progress

Babel is still being actively developed, and has a more modern approach to wireless links (something that was near non-existent when RIPng was being standardized back in 1997). Like RIPng, it is easy to set up without having to understand the complexities of OSPF. It is easy to setup on OpenWrt routers and provides redundancy in your network. That said the wireless functionality as implemented by Bird (v 1.63) is not quite there. Fortunately, there is Bird v2.0 out, and I look forward to giving it a try when it comes to OpenWrt.


Although the route churn has subsided, I re-measured the convergence time for Babel, and it was quite long, 317 seconds, probably due to the hello timer being set to 5 seconds.

In the end, I reverted my house network to RIPng. Running the same convergence test which yielded an outage of only 11 seconds with no route churn.

Perhaps many of the Babel issues are just Bird’s implementation. And there may be tweaks to reduce network converge times. I’d happily give Babel another chance, but for now, I’ll stick with good ol’ RIPng.

** if you are running a firewall, the default on OpenWrt/LEDE, you will need to put in a rule to accept IPv6 UDP port 6696

** Originally posted (with more detail) on


categoryPosted in Uncategorized | commentsComments Off on Babel: a routing protocol with wireless support | moreRead More »


datePosted on 12:59, June 7th, 2018 by Craig Miller

RIPE held an IPv6 Education seminar in Amsterdam on this year’s World IPv6 Day (6 June).  There were 18 presentations in seven hours. Lots of good presentations, here some of the highlights.

ISP Status

The good news is that IPv6 deployment continues to increase with Mobile operators taking the lead.

IP Transitions

Sadly, there are still IPv4-only sites out there in the world. We are going to need Transition Mechanisms to get there. NAT64 is not without its problems, most notably, it breaks DNSSEC. But its cousin, 464XLAT does not break DNSSEC, and it provides IPv4 support for the Apps which, unfortunately, still use IPv4-only socket calls.

Guidance on how to get to IPv6-only

There was also good guidance on how to get to IPv6-only. After all, dual-stack is not the end goal, but a transition mechanism to get to IPv6-only. OpenWrt routers already support a CLAT client, making 464XLAT even easier to deploy.

The cost of IPv4 is going up

Lastly, it was pointed out that the cost of computing continues its downward trend while the cost of IPv4 addresses is increasing. And this has proven to be one of business case drivers for some Cloud Providers to move to IPv6-only.

One can now buy a Raspberry PI Zero for $5, and the IPv4 address for that computer is going to cost nearly 5 times as much.

Celebrating IPv6 Day

The IPv6 Educa was well attended, with about 150 people online, and was quite timely given that 6 June was the 6th anniversary of World IPv6 Launch Day (in 2012). The Educa Agenda and recording can be found online.

Go forth and Deploy.

categoryPosted in Uncategorized | commentsComments Off on RIPE-NCC IPv6 Educa | moreRead More »

Link-Local Address to the rescue

datePosted on 10:36, March 23rd, 2018 by Craig Miller

I was recently setting up an OpenWrt router as a Managed AP (Access Point), but was having challenges setting up a global IPv6 address on the device. I could have put a static IPv4 address on the device, but it is on my IPv6-only network, and that just seemed like the wrong direction.

Then it occurred to me I had a tool, like the slingshot in my back pocket, which I could use: the link-local address of the AP. After all, every IPv6 interface has a link-local address. Of course this has the limitation that the PC must be on the same link, but that less of an issue for me that putting on an IPv4 address in an IPv6-only network.

Link-local addresses can also be used, when your network has gone terribly wrong, such as RAs (router advertisements) are no longer being sent, and you still need to get to that device to fix it.

Using IPv6 Scoped Addresses

The thing about using link-local addresses is that you have to indicate which interface to use (or scope), since all interfaces will have the same link-local subnet (FE80::/64). Fortunately RFC 4007 gives guidance on how to represent a scoped IPv6 Address. From the RFC (section 11):



<address> is a literal IPv6 address,

<zone_id> is a string identifying the zone of the address, and

`%' is a delimiter character to distinguish between <address> and

SSH using an IPv6 scoped link-local address

By using the scoped address, it is easy to ssh to the AP using the link-local address:

$ ssh admin@fe80::6a1:51ff:fea0:9338%wlan0
admin@fe80::6a1:51ff:fea0:9338%wlan0's password:

BusyBox v1.25.1 () built-in shell (ash)

    /        /\      _    ___ ___  ___
   /  LE    /  \    | |  | __|   \| __|
  /    DE  /    \   | |__| _|| |) | _|
 /________/  LE  \  |____|___|___/|___|            
 \        \   DE /
  \    LE  \    /  -----------------------------------------------------------
   \  DE    \  /    Reboot (17.01.4, r3560-79f57e422d)
    \________\/    -----------------------------------------------------------


Using the Link-Local Address in a Web Browser

The AP also has a web interface which can transform a complex configuration into a click of the mouse. But using Scoped Addresses in your browser isn’t as straight forward as it would seem.

RFC 6874 shows how to encode a scoped address in a URL. Since IPv6 literals are enclosed in square brackets, the URL should be as simple as: http://[fe80::6a1:51ff:fea0:9338%wlan0]/

But, wait, the percent sign is used to escape characters in a URL. So if we escape the percent sign, then the URL should be http://[fe80::6a1:51ff:fea0:9338%25wlan0]/. Unfortunately, this doesn’t work.

No support for scoped addresses in the major browsers

Unfortunately, this doesn’t work in most browsers. The browser manufactures have decided to not implement RFC 6874. In some cases like Chrome, publicly saying that it isn’t worth the effort to parse the URL. Firefox also decided they won’t fix this issue. Even the which makes a reference browser Arora, has decided it won’t fix this lack of conformance to RFC 6874.

SSH to the rescue

Fortunately, there is a work-around which can trick your modern browser to use a scoped link-local address. It requires the help of ssh and its TCP forwarding capability. By using the following command (put in your link-local address and scoped interface):

ssh -L '8080:[fe80::6a1:51ff:fea0:9338%wlan0]:80' localhost

Now return to your favourite browser, and use the URL localhost:8080 and magically you will be transported to your device (in my case my AP) using the scoped link-local address.

Tricking the Browser

Not the prettiest of solutions, but until the Browser folks realize there is a need for scoped link-local address it is what we have.

Using Link-Local Address as a last resort, when the network has gone wonky, or when the device won’t take a GUA (Global Unique Address), can be very useful. Keep it in your back pocket (like a slingshot) for when you really need to get there using IPv6.

categoryPosted in Uncategorized | commentsComments Off on Link-Local Address to the rescue | moreRead More »

Writing IPv6 Apps: Python Webserver

datePosted on 14:39, January 17th, 2018 by Craig Miller

Moving to IPv6 starts at home. Applications have to speak IPv6 as well as the network. The good news is that there is lots of software available which already supports IPv6. Unfortunately, there is much more that doesn’t.

An example, a Python-based webserver. Certainly not ready for a production network, but handy as a learning tool about how easy it can be to support IPv6 in your application.

Why Python? Python is a wonderful programming language, and getting only better with version 3. There are libraries for most needs, including one which serves up the web. And it runs just about anywhere that Python runs (Windows, Linux, BSD, Mac, Pi, ODROID, etc)

Python module SimpleHTTPServer

The python module SimpleHTTPServer supports IPv4 out of the box with the simple command:

python -m SimpleHTTPServer

However it does not support IPv6. There is no one-line equivalent to support IPv6, so a small script is required.

Looking at the code

The ipv6-httpd script is a short script supporting both IPv4 and IPv6. Looking at the following sections:

  1. Initialization of the HTTPServer object (from SimpleHTTPServer library)
  2. Class creation (of HTTPServerV6) to support IPv6

As with all Python scripts, the details roll backwards from the bottom. Initialization occurs in main

def main():
    global server
    server = HTTPServerV6(('::', listen_port), MyHandler)
    print('Listening on port:' + str(listen_port) + '\nPress ^C to quit')

The IPv6 part

In order to support IPv6, we use a bit of object oriented inheritance trickery to modify the default of an existing class HTTPServer

class HTTPServerV6(HTTPServer):
    address_family = socket.AF_INET6

This creates a new class (which is used in our server ) with the address_family set to AF_INET6 (aka IPv6). This two-line change to the script transforms an IPv4-only script into an application that also supports IPv6.

Running the code

Now that we have a server which supports both IPv4 and IPv6, all we need to do is cd to the directory we wish to share, and start the server

$ cd public/
$ ~/bin/ 
Listening on port:8080
Press ^C to quit
2001:db8:ebbd:0:4d18:71cd:b814:9508 - - [09/Jul/2017 11:49:41] "GET / HTTP/1.1" 200 -
^CCaught SIGINT, dying

The webserver log is sent to standard out (stdout), and can be redirected to a file if desired. In the above example, an IPv6 client ..:9508 requests an index, then the server is terminated with a ^C.

Want to server from a different directory? Stop the server, cd to another directory, and restart the server, it will now serve files from the new current working directory (cwd) location.

Security (or lack there of)

This is a personal webserver, designed to be started and stopped whenever you need it. It is NOT a production quality webserver that you should put on the internet.

It does not server encrypted pages (read: no SSL/TLS), and it is single threaded, which means if a second request comes in while serving the first request, the second request will have to wait.

Adding IPv6 Support to your App

As you can see, it doesn’t have to be difficult to add IPv6 to your apps, you just need to give it some thought when planning your App. By adding IPv6, you will future proof your App by being ready for the future of the Internet.

categoryPosted in Uncategorized | commentsComments Off on Writing IPv6 Apps: Python Webserver | moreRead More »

Video From The IPv6 Solutions Tutorials at I2 Tech Exchange

datePosted on 15:10, December 21st, 2017 by Alan Whinery

Thanks to long and hard work by Richard Machida from U. Alaska, we have a video on You Tube with content from the tutorials we did at Internet2 Tech Exchange 2017 in San Francisco, October 15, 2017.

Presentation Markers, with links to start times in the video:

0:00:00 – 0:22:00 Intro and Context

0:22:58 – 1:42:01 – IPv6 Security

  • Jeff Harrington, NYSERNET

1:42:10 – 1:44:49 – Acknowledgments

1:44:49 – 2:51:30 – The IPv6-Only Network:

(Experiences setting up NAT64, DNS64, 464XLAT)

  • Alan Whinery – U. Hawaii
  • Jeffry Handal, Cisco Meraki



categoryPosted in Uncategorized | commentsComments Off on Video From The IPv6 Solutions Tutorials at I2 Tech Exchange | moreRead More »

RIPng the forgotten routing protocol

datePosted on 12:20, December 4th, 2017 by Craig Miller


In a small network of more than one router, one will quickly figure out that you can’t get there from here, even with DHCPv6-PD (Prefix Delegate) providing IPv6 addressing,. Sure you can get to the internet, but you can’t get to other parts of the network which are behind the other routers. You need a routing protocol to share information between the routers on your small network.

How to Get There?

So when we all have /56s or larger delegated to our house/SOHO, and we put in multiple IPv6 capable routers, how will the routers convey connectivity information? Well we could use HomeNet RFC 7788, but currently home routers don’t come out of the box configured for HomeNet (for example the Wifi is on the same subnet as the LAN). Not to diminish HomeNet’s work, but there is a forgotten protocol that can solve the problem.

The Forgotten Protocol: RIPng

RIPng (RFC 2080), the IPv6 cousin of RIPv2  RFC 2453 , has all the advantages of RIPv2, except it conveys IPv6 route information (rather than RIPv2’s IPv4-only info). But the same principles apply, easy to deploy, works pretty well, solves the problem (of distributing routes to multiple routers).

But finding support, and documentation on RIPng on the internet is threadbare. Even the venerable BIRD (BIRD Internet Routing Daemon) has a non-functional example configuration, not to mention they just call it RIP confusing whether it is for IPv4 or IPv6.

But why has it been forgotten? Because real men use OSPF (or IS-IS). And you can too, if you want to spend a week (or more) learning the complexities of the protocol. But what if you just wanted it to work, and move onto the next problem.

Getting from here to there

Although some ISPs will give a fairly stable prefix (via DHCPv6-PD), others do not, leading to a very dynamic prefix environment at home or the SOHO (see Request: Less Dynamic Prefix, Mr./Ms. ISP. Cascaded routers can further divide the /56 via DHCPv6-PD allocating smaller chunks downstream. If one only needs to get to the internet (everything is in the cloud, right?), this works quite well. After all each cascaded router has a default route pointing upstream (towards the ISP).

But what if you have your NAS on Network B, and you client on Network C, it isn’t going to work.


Router 3 doesn’t know about Router 2, or even the subnet B behind Router 2

Of course, you could put in static route in each of Routers 2 & 3. But not only does that take a bit more knowledge of routing (hint: the next hop is a link-local address), but it doesn’t work in a dynamic prefix (where the ISP is changing the prefix) environment.

RIPng to the rescue

So, enter an easy to configure, easy to use routing protocol, RIPng. Running RIPng, Routers 2 & 3 can share information about themselves, and more importantly, the subnets they are serving. If the ISP changes the prefix, DHCPv6-PD will propagate the new prefix down to the cascaded routers, and RIPng will refresh the routing information between the routers, all automagically.

Making RIPng work

First, use router software that supports RIPng. Of course Cisco supports RIPng, but not everyone has multiples of these at home. OpenWrt/LEDEis a good option, since if your router is not over 5 years old, it is probably supported. And it has BIRD as an easy to install package.

First, install bird6 & birdc6 (the CLI for bird6). The bird6 package is a direct port from the bird maintainers, and therefore uses its own configuration file (rather than UCI). But RIPng is easy, so onto the next step.

Uncomment the following lines in the package-provided configuration file /etc/bird6.conf

router id;

protocol kernel {
    learn;          # Learn all alien routes from the kernel
    scan time 20;       # Scan kernel routing table every 20 seconds
    export all;     # Default is export none

protocol rip {
    import all;
    export all;
    infinity 16;
    interface "*" { mode multicast; };

Even though RIPng does not require a “router id” bird6 won’t run without it. Restart the bird6 daemon with /etc/init.d/bird6 restart, and you are done*

Of course you could optimize it a bit by telling the config which interfaces to use, such as interface "eth1" {mode multicast }; but this article is about making it easy, and it doesn’t break anything sending route updates out the other interfaces.

How to tell RIPng is working

ssh to the router. The birdc6 CLI is the easiest in showing the routing table, which includes sources of the routes, like this:

# bindc6
bird> show route
fdcd:5cb4:d0e1::/64 dev br-lan [kernel1 2017-11-30] * (10)
fdcd:5cb4:d0e1::/48 unreachable [kernel1 2017-11-30] * (10)
2001:db8:ebbd:8::/64 dev br-lan [kernel1 2017-11-30] * (10)
2001:db8:ebbd:8::/62 unreachable [kernel1 2017-11-30] * (10)
2001:db8:ebbd:c::/64 via fe80::224:a5ff:fed7:3089 on eth1 [rip1 23:30:58] * (120/2)
2001:db8:ebbd:c::/62 via fe80::224:a5ff:fed7:3089 on eth1 [rip1 23:30:58] * (120/2)
2001:db8:ebbd::/60 via fe80::221:29ff:fec3:6cb0 on eth1 [rip1 00:00:44] * (120/2)
2001:db8:ebbd:4::/64 via fe80::221:29ff:fec3:6cb0 on eth1 [rip1 00:00:44] * (120/2)
2001:db8:ebbd:4::/62 via fe80::221:29ff:fec3:6cb0 on eth1 [rip1 00:00:44] * (120/2)
2001:270:ebbd::/60 via fe80::221:29ff:fec3:6cb0 on eth1 [kernel1 2017-11-30] * (10)
fd37:5218::/64     via fe80::221:29ff:fec3:6cb0 on eth1 [rip1 00:00:44] * (120/2)
fd37:5218::/48     via fe80::221:29ff:fec3:6cb0 on eth1 [rip1 00:00:44] * (120/2)
64:ff9b::/96       via fe80::221:29ff:fec3:6cb0 on eth1 [rip1 00:00:44] * (120/2)
fd11::/64          via fe80::224:a5ff:fed7:3089 on eth1 [rip1 23:30:58] * (120/2)
fd11::/48          via fe80::224:a5ff:fed7:3089 on eth1 [rip1 23:30:58] * (120/2)

All those “rip1” lines are routes learned from RIPng. Since no filters were used, not only are the globally unique addresses shared, but so are the Unique Local addresses (ULA) configured in each router. Here’s the fun part, even though there is not ULA on subnet A, RIPng provides connectivity between the ULA islands. Of course, it would be better to have a single ULA /48 for the entire network, but this is a test network, and OpenWrt/LEDE creates a ULA by default for each router. I wanted to see how RIPng would handle this non-optimal situation. And, it handles is pretty well.

While it is possible to figure out who the other RIPng routers are, it is easier to use the bindc6 command:

bird> show rip neigh
IP address                Interface  Metric Routes   Seen
fe80::224:a5ff:fed7:3089  eth1            1      4     27
fe80::221:29ff:fec3:6cb0  eth1            1      9      6

What’s missing in this simple configuration: authentication

RIPv2 included authentication, to ensure that the routing updates that are being received, are from the correct sources.

RIPng RFC 2080 does not use authentication natively, but rather relies on IPv6’s Authentication Header (AH), one of the extension header types, for authentication (see Stretching IPv6 with extension headers). The configuration above, does not utilize the AH header, however, the risk should be low in a small network. More to come later on RIPng with AH.

Don’t forget DNS

Of course, if you creating a network with IPv6 and more than one subnet, don’t forget the DNS. Have each router forward DNS requests to your local DNS server (you do have a local DNS server, right?).

Add your local DNS server address the following to dnsmasq section of /etc/config/dhcp

config dnsmasq
    list server '2001:db8:ebbd:0::dbc8'

Now all your IPv6 addresses will have names, and it will be a breeze getting around your network.

Wrapping up RIPng

RIPng may have been forgotten, and overlooked for the past 20 years, but that doesn’t mean it can’t still solve problems for small networks (say less that 25 routers) quickly and easily. Sure, you can put in a more complex routing protocol like OSPFv3, but on the other hand, you might want to spend your time just going to the NAS, fire up a good movie, and enjoy the popcorn.

*traffic photo – Creative Commons

**if you are running a firewall, the default on OpenWrt/LEDE, you will need to put in a rule to accept IPv6 UDP port 521


See for full article with tcpdump output.

categoryPosted in Uncategorized | commentsComments Off on RIPng the forgotten routing protocol | moreRead More »

Campus Networks In The Post-IPv4-Exhaustion World

datePosted on 15:58, October 25th, 2017 by Alan Whinery

Talk from Internet2 Technology Exchange 2017, entitled “Campus Networks In The Post-IPv4 Exhaustion World”.

Note: I cited the IPv4AAS vendor as “” when it is actually “”.



categoryPosted in Uncategorized | commentsComments Off on Campus Networks In The Post-IPv4-Exhaustion World | moreRead More »

How much IPv6 address space do you have?

datePosted on 07:56, October 9th, 2017 by Craig Miller
ip everywhere

IPv6 Everywhere

In a recent, rather unscientific poll on Reddit, IPv6 advocates were asked how much IPv6 address space did their respective ISPs give them. It looks like ISPs are getting it, and on average giving out a /56 to home users, which should be plenty for most.

The results

  • U.S.
    • Comcast /60
    • TWC/Spcturm /64 (with “hint” /56)
    • AT&T Uverse /60
    • Cox /56 (with “hint”)
    • Charter /64
    • Frontier (no IPv6 support)
  • Canada
    • Rogers /56
    • TekSavvy /56 (DSL-0nly)
    • Telus /56
  • UK
    • Sky /56
    • BT /56
    • IDNet /56
  • Germany
    • Deutsche Telecom /56
    • 1&1 /56
    • Unitymedia /56
  • France
    • Free (5 /64s)
  • Norway Telenor NO xDSL /48
  • Denmark Kviknet /48
  • Europe  Orange /56
  • Austrailia
    • Internode /56 (static, tied to account, nice!)
    • Australian WISP /56
  • New Zealand  2degrees /56 static (or /48 dynamic)

The good and bad

Of course, this is the good news. The less good news is that there are still ISPs out there which provide no IPv6 support for their customers. But it is a good start, and those who are supporting IPv6 have realized that one /64 at the home isn’t enough networks for the future (think: /64 for IoT, /64 for appliances, /64 for HVAC (such as Nest), /64 for your kids, etc, all with different traffic rules). Keep up the good work.




categoryPosted in Uncategorized | commentsComments Off on How much IPv6 address space do you have? | moreRead More »