IPv6 on Solaris

Table of Contents

Introduction
Configuring Solaris as an IPv6 router
Configuring Solaris as an IPv6 host
Setting up DNS for IPv6
Adding some vigilance onto IPv6 hosts
Exploring the web with IPv6

Introduction

IPv6 offering from NTT Communications

NTT Communications launched an experimental IPv6 Tunneling Project that was offered to the customers of OCN economy, their leased line service. optix.org gains its IP connectivity from NTT Communications and applied to this experimental service offering as a project partner. This project will end on March 31, 2001 (has exteded to May 31, 2001 and terminated on that date).

APNIC allocated sub-TLA of 2001:218::/35 to NTT for production use. NTT Communications sub-allocates address blocks as large as /48 or so to each project partners.

Running IPv6 on Solaris

Now that IPv4 hosts are running all around the world and that most of backbone routers are not capable of IPv6, the most realistic configuration is tunneling. In fact, that's what is offered by NTT Communications for this experimental IPv6 project.

IPv6 protocol stack is incorporated into the core OS/Networking software since Solaris 8. Solaris machines described below are all running Solaris 8 as of this writing.

Designing your IPv6 network

NTT Communications assigned 2001:218:466::/48 to optix.org. Our network is small. I decided to make this network a flat one, i.e. without hierarchical subnets. IPv6 Hosts reside in single subnet 2001:218:466:1000::/64.

I'll show you how to configure a Solaris host as an IPv6 router and another Solaris host as an IPv6 end-node. Both hosts are configured as an IPv4/IPv6 dual stack machine. Your mileage may vary, though.

Configuring Solaris as an IPv6 router

Once you have your IPv6 network configuration information ready, joining in the IPv6 is not so complicated. Activate in.ndpd (neighbor discovery protocol daemon), configure some IPv6 addresses, establish a IPv6-over-IPv4 tunnel and look after the routing table.

What you need to have before you proceed is the following information.
local IPv6 address
Configured automatically by in.ndpd.
remote IPv4 tunneling address (e.g. 210.163.36.3)
Your service provider will inform you which address is configured.
local IPv4 tunneling address (e.g. 210.164.85.211)
You can pick one from IPv4 address block sub-allocated from the service provider.
remote IPv6 tunneling address (e.g. 2001:218:0:1000:2c0:4fff:fe16:f4b0)
I found this out after establishing a tunnel using IPv4 tunneling address.
local IPv6 tunneling address (e.g. 2001:218:466:1000:800:20ff:fe73:5e9b)
You can pick one arbitrarily from IPv6 address block assigned to you. This must be different from one assigned automagically by in.ndpd. (I changed the 9th octet from '0a' to '08')

Configuration files

/etc/inet/ndpd.conf

Let the neighbor discovery protocol daemon advertise its network prefix such as 2001:218:466:1000::/64. Advertise site local network prefix too if you want (this is totally optional). This machine has only one network interface, which is le0 and the network auto-configuration information must be advertised on this interface.
ifdefault AdvReachableTime 30000 AdvRetransTimer 2000 

if le0 AdvSendAdvertisements on
prefix 2001:218:466:1000::/64 le0 
prefix fec0:0:0:56::/64 le0

/etc/hostname6.??#

An empty file would do. Just create a file (e.g. # touch /etc/hostname6.le0).

/etc/hostname6.ip.tun0

The following setting will make two IPv6 tunneling interfaces, which are ip.tun0 and ip.tun0:1, configured. The first line with 'tsrc/tdst' keyword establishes ip.tun0 and the second line with 'addif' keyword establishes ip.tun0:1.

tsrc <local tunneling IPv4 address> tdst <remote tunneling IPv4 address> up
addif <local tunneling IPv6 address> <remote tunneling IPv6 address> up
# It seems remote tunneling IPv6 address is not necessary, which is good because it's more flexible against remote site's change such as renumbering.

On ip.tun0 interface, link local IPv6 address is assigned based on specified tunneling IPv4 addresses. IPv4 addresses must be global addresses, of course. I'm not sure IPv6 tunneling addresses speficied in addif have to be global address. But I used global addresses anyway and it worked. Note that local tunneling IPv6 address is different from one assigned on le0:2 which is configured automatically by in.ndpd.

/etc/rc2.d/S69inet6

IPv6 routing table did't seem to contain default route entry. I, therefore, create one using the following start up script. Thanks Tetsuya Nakai of NTT Communications for giving me advise on putting a static route on default entry.
#!/bin/sh

echo 'adding default route entry into IPv6 routing table'
/usr/sbin/route add -inet6 default <remote tunneling link-local IPv6 address> -interface
Remote tunneling link-local IPv6 address here is as follows: fe80::<IPv4 addr(colon separated hexadecimal)>, where
210 -> 0xd2
163 -> 0xa3
36 -> 0x24
3 -> 0x3
210.163.36.3 -> d2a3:2403

/etc/inet/ipnodes

IPv6 host name resolution is basically performed by looking up this file.
#
# Internet host table
#
::1             localhost
127.0.0.1       localhost
# Just for informational purpose. 
# Not really necessary as long as DNS works fine.
# In fact, maybe you shouldn't put this entry because hardcoding IPv6 addresses
# makes renumbering harder than it has to be.
2001:218:466:1000:a00:20ff:fe73:5e9b    gravity.v6.optix.org gravity-v6

/etc/nsswitch.conf

Make sure 'ipnodes' line contains 'dns' entry so that IPv6 hostname lookup can be performed through DNS in case that resolution failed by looking up a local file.
gravity:/home/dxy[10:55pm] egrep '^hosts|^ipnodes' /etc/nsswitch.conf
hosts:      files dns
ipnodes:   files dns
gravity:/home/dxy[10:55pm] 

Now, that's enough. Reboot the machine and let's move on.

Utilities

Solaris (not only Solaris 8 but older ones) has a command called 'getent'. getent performs name service lookup according to /etc/nsswitch.conf regardless of name services specified in that file. You don't have to travel between nslookup, ypmatch or nismatch. This might be helpful in troubleshooting name services.

gravity:/home/dxy[11:44am] getent ipnodes gravity.v6.optix.org
2001:218:466:1000:a00:20ff:fe73:5e9b    gravity.v6.optix.org gravity-v6
gravity:/home/dxy[11:44pm] getent ipnodes www.v6.iijlab.net
3ffe:507:0:1:260:97ff:fe07:69ea sh1.v6.iijlab.net www.v6.iijlab.net
gravity:/home/dxy[11:44pm]

Next, prepare a few tiny scripts. This step is not necessary at all because network utilities (such as ping, traceroute, snoop and so on) are IPv6 compatible on Solaris 8.

It, however, might be useful more or less in case that you want to ping or traceroute to a host which has both A and AAAA record, in other words IPv4 and IPv6 address respectively, assigned to it and that you would like to specify an IPv6 address as a target address.

ping6

Save the following as ping6 and put it somewhere in the command search path of your shell.
#!/bin/sh

PING=/usr/sbin/ping

if [ -x $PING ]; then  

        $PING -A inet6 $@

fi

traceroute6

Save the following as traceroute6 and put it somewhere in the command search path of your shell.
#!/bin/sh

TRACEROUTE=/usr/sbin/traceroute

if [ -x $TRACEROUTE ]; then  

        $TRACEROUTE -A inet6 $@

fi

Now that it's ready...

You can see that three IPv6 interfaces configured (le0 as link local, le0:1 as site local, le0:2 as global) and two tunneling interfaces configured (ip.tun0 with link local addresses assigned to it and ip.tun0:1 with global addresses assigned to it).
gravity:/home/dxy[9:18pm] ifconfig -a
lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
        inet 127.0.0.1 netmask ff000000 
le0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2
        inet 210.164.85.211 netmask fffffff0 broadcast 210.164.85.223
lo0: flags=2000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv6> mtu 8252 index 1
        inet6 ::1/128 
le0: flags=2100841<UP,RUNNING,MULTICAST,ROUTER,IPv6> mtu 1500 index 2
        inet6 fe80::a00:20ff:fe73:5e9b/10 
le0:1: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
        inet6 fec0::56:a00:20ff:fe73:5e9b/64 
le0:2: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
        inet6 2001:218:466:1000:a00:20ff:fe73:5e9b/64 
ip.tun0: flags=2200851<UP,POINTOPOINT,RUNNING,MULTICAST,NONUD,IPv6> mtu 1480 index 3
        inet tunnel src 210.164.85.211  tunnel dst 210.163.36.3
        inet6 fe80:::55d3/10 --> fe80::d2a3:2403 
ip.tun0:1: flags=2200851<UP,POINTOPOINT,RUNNING,MULTICAST,NONUD,IPv6> mtu 1480 index 3
        inet6 2001:218:466:1000:800:20ff:fe73:5e9b/128 --> :: 
gravity:/home/dxy[9:18pm] netstat -rn

Routing Table: IPv4
  Destination           Gateway           Flags  Ref   Use   Interface
-------------------- -------------------- ----- ----- ------ ---------
210.164.85.208       210.164.85.211        U        1    832  le0
224.0.0.0            210.164.85.211        U        1      0  le0
default              210.164.85.209        UG       1   2603  
127.0.0.1            127.0.0.1             UH       2   3151  lo0

Routing Table: IPv6
  Destination/Mask            Gateway                   Flags Ref   Use   If  
--------------------------- --------------------------- ----- --- ------ -----
::                          2001:218:466:1000:800:20ff:fe73:5e9b UH      1      0 ip.tun0:1
fe80::d2a3:2403             fe80::d2a4:55d3             UH      1      0 ip.tun0
fec0:0:0:56::/64            fec0::56:a00:20ff:fe73:5e9b U       1      0 le0:1
2001:218:466:1000::/64      2001:218:466:1000:a00:20ff:fe73:5e9b U       1    175 le0:2
fe80::/10                   fe80::a00:20ff:fe73:5e9b    U       1     41 le0  
ff00::/8                    fe80::a00:20ff:fe73:5e9b    U       1      0 le0  
default                     2001:218:466:1000:800:20ff:fe73:5e9b U       1     83 ip.tun0:1
::1                         ::1                         UH      1      0 lo0  
At first, make sure the tunnel has been properly established by pinging a multicast address ff02::1, which is pre-defined as 'all hosts on the link local domain'.
gravity:/home/dxy[10:15pm] ping -s -i ip.tun0 ff02::1
PING ff02::1: 56 data bytes
64 bytes from fe80::d2a4:55d3: icmp_seq=0. time=2. ms
64 bytes from fe80::2c0:4fff:fe15:f4b0: icmp_seq=0. time=90. ms
64 bytes from fe80::d2a4:55d3: icmp_seq=1. time=1. ms
64 bytes from fe80::2c0:4fff:fe15:f4b0: icmp_seq=1. time=270. ms
64 bytes from fe80::d2a4:55d3: icmp_seq=2. time=1. ms
64 bytes from fe80::2c0:4fff:fe15:f4b0: icmp_seq=2. time=317. ms
^C
----ff02::1 PING Statistics----
3 packets transmitted, 6 packets received, 2.00 times amplification
round-trip (ms)  min/avg/max = 1/113/317
gravity:/home/dxy[10:15pm] 
ICMP6 echo reply packets from fe80::2c0:4fff:fe15:f4b0 are received. This link local address belongs to the OCN tunneling server. Things seem to be in pretty good shape so far. Let's move on and see how you can get to the world.
gravity:/home/dxy[10:17pm] ping6 -s www.kame.net
PING www.kame.net: 56 data bytes
64 bytes from 3ffe:501:4819:2000:5054:ff:fedc:50d2: icmp_seq=0. time=174. ms
64 bytes from 3ffe:501:4819:2000:5054:ff:fedc:50d2: icmp_seq=1. time=187. ms
64 bytes from 3ffe:501:4819:2000:5054:ff:fedc:50d2: icmp_seq=2. time=350. ms
^C
----www.kame.net PING Statistics----
3 packets transmitted, 3 packets received, 0% packet loss
round-trip (ms)  min/avg/max = 174/237/350
gravity:/home/dxy[10:17pm] traceroute6 www.6bone.net
traceroute: Warning: Multiple interfaces found; using 2001:218:466:1000:800:20ff:fe73:5e9b @ ip.tun0:1
traceroute to 6bone.net (3ffe:b00:c18:1::10), 30 hops max, 60 byte packets
 1  2001:218:0:1000:2c0:4fff:fe15:f4b0  80.656 ms  83.560 ms  85.727 ms
 2  2001:218:0:1000:2c0:4fff:fe15:f549  92.867 ms  86.256 ms  84.243 ms
 3  3ffe:1801:0:1:2a0:c9ff:fec8:cd38  84.624 ms  83.257 ms  84.462 ms
 4  3ffe:1801:ffff::3  93.748 ms  98.313 ms  94.735 ms
 5  3ffe:1800:0:3:2a0:c9ff:fec8:8564  93.084 ms  102.786 ms  94.638 ms
 6  3ffe:1810:ffff::8  213.594 ms  219.337 ms  218.198 ms
 7  3ffe:1810:0:ffff::15  218.403 ms  216.105 ms  219.233 ms
 8  3ffe:b00:c18::12  378.608 ms  361.135 ms  359.252 ms
 9  www.6bone.net (3ffe:b00:c18:1::10)  358.583 ms  363.629 ms  354.323 ms
gravity:/home/dxy[10:18pm] 

Configuring Solaris as an IPv6 host

Once you've got an IPv6 router on your network, adding an IPv6 host (as an end node) on the network is pretty straight-forward.

Configuration file

/etc/hostname6.??#

As long as the neighbor discovery is working on your IPv6 network (on an IPv6 router, to be exact), the machine will automatically configure a link-local address (and hopefully site-local and/or global address too). All you need is to create an empty file /etc/hostname6.??0.

/etc/inet/ipnodes

Prepare this file just as you did for the IPv6 router above.
#
# Internet host table
#
::1             localhost
127.0.0.1       localhost

2001:218:466:1000:a00:20ff:fe88:a683    velocity.v6.optix.org velocity-v6

/etc/nsswitch.conf

Again, just add 'dns' on 'ipnodes' line.
velocity:/home/dxy[11:35pm] egrep '^hosts|^ipnodes' /etc/nsswitch.conf
hosts:      files dns
ipnodes:   files dns
velocity:/home/dxy[11:35pm] 

Let's see how it's working

velocity:/home/dxy[10:32pm] ifconfig -a
lo0: flags=1000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4> mtu 8232 index 1
        inet 127.0.0.1 netmask ff000000 
hme0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2
        inet 210.164.85.214 netmask fffffff0 broadcast 210.164.85.223
lo0: flags=2000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv6> mtu 8252 index 1
        inet6 ::1/128 
hme0: flags=2000841<UP,RUNNING,MULTICAST,IPv6> mtu 1500 index 2
        inet6 fe80::a00:20ff:fe88:a683/10 
hme0:1: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
        inet6 fec0::56:a00:20ff:fe88:a683/64 
hme0:2: flags=2080841<UP,RUNNING,MULTICAST,ADDRCONF,IPv6> mtu 1500 index 2
        inet6 2001:218:466:1000:a00:20ff:fe88:a683/64 
velocity:/home/dxy[10:32pm] netstat -rn

Routing Table: IPv4
  Destination           Gateway           Flags  Ref   Use   Interface
-------------------- -------------------- ----- ----- ------ ---------
210.164.85.208       210.164.85.214        U        1     13  hme0
224.0.0.0            210.164.85.214        U        1      0  hme0
default              210.164.85.209        UG       1     15  
127.0.0.1            127.0.0.1             UH       2      6  lo0

Routing Table: IPv6
  Destination/Mask            Gateway                   Flags Ref   Use   If  
--------------------------- --------------------------- ----- --- ------ -----
fec0:0:0:56::/64            fec0::56:a00:20ff:fe88:a683 U       1      0 hme0:1
2001:218:466:1000::/64      2001:218:466:1000:a00:20ff:fe88:a683 U       1      1 hme0:2
fe80::/10                   fe80::a00:20ff:fe88:a683    U       1      1 hme0 
ff00::/8                    fe80::a00:20ff:fe88:a683    U       1      0 hme0 
default                     fe80::a00:20ff:fe73:5e9b    UG      1      3 hme0 
::1                         ::1                         UH      1      0 lo0  

Unlike the machine 'gravity', which is the IPv6 tunneling host, this node doesn't have tunneling interface such as ip.tun?. This machine points to link local address of gravity as its default router. Now, let's see if they can reach outside.

velocity:/home/dxy[10:25pm] ping6 -s www.iijlab.net
PING www.iijlab.net: 56 data bytes
64 bytes from sh1.v6.iijlab.net (3ffe:507:0:1:260:97ff:fe07:69ea): icmp_seq=0. time=367. ms
64 bytes from sh1.v6.iijlab.net (3ffe:507:0:1:260:97ff:fe07:69ea): icmp_seq=1. time=260. ms
64 bytes from sh1.v6.iijlab.net (3ffe:507:0:1:260:97ff:fe07:69ea): icmp_seq=2. time=159. ms
^C
----www.iijlab.net PING Statistics----
3 packets transmitted, 3 packets received, 0% packet loss
round-trip (ms)  min/avg/max = 159/262/367
velocity:/home/dxy[10:25pm] traceroute6 www.kame.net
traceroute: Warning: Multiple interfaces found; using 2001:218:466:1000:a00:20ff:fe88:a683 @ hme0:2
traceroute to kame212.kame.net (3ffe:501:4819:2000:5054:ff:fedc:50d2), 30 hops max, 60 byte packets
 1  gravity.v6.optix.org (2001:218:466:1000:a00:20ff:fe73:5e9b)  5.952 ms  0.997 ms  0.748 ms
 2  2001:218:0:1000:2c0:4fff:fe15:f4b0  83.583 ms  86.234 ms  94.885 ms
 3  2001:218:0:1000:2c0:4fff:fe15:f549  85.140 ms  90.676 ms  84.842 ms
 4  3ffe:1801:0:1:2a0:c9ff:fec8:cd38  85.638 ms  96.169 ms  84.135 ms
 5  pc6.otemachi.wide.ad.jp (3ffe:501:0:1800:210:5aff:fe76:2040)  84.760 ms  83.603 ms  84.076 ms
 6  pc2.komatsu.wide.ad.jp (3ffe:501:0:14ff::1)  104.681 ms  106.120 ms  105.032 ms
 7  3ffe:501:0:1400:280:c8ff:fe54:f5bb  104.622 ms  104.609 ms  117.675 ms
 8  iravati.kyoto.wide.ad.jp (2001:200:0:c00::1)  116.978 ms  127.678 ms  116.658 ms
 9  swift.sakyo.wide.ad.jp (2001:200:0:5201:290:27ff:fecb:9294)  314.947 ms  114.433 ms  119.630 ms
10  3ffe:501:0:2c01:290:27ff:fe08:ad5d  119.886 ms  124.045 ms  248.476 ms
11  3ffe:501:0:1c01:200:f8ff:fe03:d9c0  290.035 ms  126.788 ms  145.489 ms
12  paradise.v6.kame.net (3ffe:501:4819:2000:5054:ff:fedc:5217)  128.924 ms  124.942 ms  134.669 ms
13  3ffe:501:4819:2000:5054:ff:fedc:50d2  129.872 ms  132.433 ms  125.064 ms
velocity:/home/dxy/bin[10:27pm]

Setting up DNS for IPv6

Just like other sites, I created a sub domain for v6 addresses, which is .v6.optix.org. Our site is running BIND 8.2.2-P5 as its domain name server as of writing this. The name server is capable of handling IPv6 addresses as its data. Let me show you how to add IPv6 name service capability on the existing domain name server.

named.conf

Add the following in /etc/named.conf.
zone "v6.optix.org" in {
        type master;
        file "v6.optix.zone";
};

zone "6.6.4.0.8.1.2.0.1.0.0.2.ip6.int" {
        type master;
        file "2001:218:466.rev";
};

v6.optix.zone

Put AAAA RR entries like the following.
gravity                 IN      AAAA    2001:218:466:1000:a00:20ff:fe73:5e9b
velocity                IN      AAAA    2001:218:466:1000:a00:20ff:fe88:a683

2001:218:466.rev

Put PTR RR entries like the following.
b.9.e.5.3.7.e.f.f.f.0.2.0.0.a.0.0.0.0.1 IN PTR  gravity.v6.optix.org.
3.8.6.a.8.8.e.f.f.f.0.2.0.0.a.0.0.0.0.1 IN PTR  velocity.v6.optix.org.

An article of KAME Newsletter will give you a hint on which IPv6 address should/shouldn't appear on DNS.

An article on a more elaborate migration utilizing BIND 9 would be forthcoming.

Adding some vigilance onto IPv6 hosts

tcp_wrappers doesn't natively handle connections between hosts with IPv6 addresses. There are several patches available to turn tcp_wrappers IPv6 compliant.

I picked up one available at here.

/etc/inetd.conf

# grep tcp6 /etc/inetd.conf | egrep 'telnet|rlogin'
telnet  stream  tcp6    nowait  root    /usr/local/sbin/tcpd          in.telnetd
login   stream  tcp6    nowait  root    /usr/local/sbin/tcpd          in.rlogind
# 

/etc/hosts.allow

In hosts.allow/deny files, colon is used as a field separator between a daemon name and a list of remote IP address. IPv6 colon separated address notation doesn't fit well with this original hosts.allow/deny syntax. You have to escape colon-separated IPv6 addresses with square brackets (like "Format for Literal IPv6 Addresses in URL's" described in RFC2732).

#
# /etc/hosts.allow
#
in.telnetd: 210.164.85.208/255.255.255.240 [2001:218:466::]/48
in.rlogind: 210.164.85.208/255.255.255.240 [2001:218:466::]/48

/etc/hosts.deny

# 
# /etc/hosts.deny
#
in.telnetd in.rlogind: ALL
Now, it's ready. After sending HUP signal to inetd, the setting configured above would take effect.
Apr 18 22:02:20 gravity in.rlogind[2809]: [ID 905499 mail.info] connect from velocity.optix.org (210.164.85.214)
Apr 18 22:02:38 gravity in.rlogind[2823]: [ID 905499 mail.info] connect from velocity.v6.optix.org (2001:218:466:1000:a00:20ff:fe88:a683)

Exploring the web with IPv6

There are several ways for web browsing on IPv6. Newer version of Mozilla supports IPv6. So does w3m, a text based web browser. If you're so familiar with Netscape that you can't live without it, you can use a HTTP/FTP proxy program called wwwoffle as an IPv4/IPv6 gateway for your Netscape, which doesn't speak IPv6.

Let met show you a screen shot of Mozilla on my Ultra 1 running IPv6. From netstat output, you can see Mozilla's speaking to the web server running on 'www.6bone.net' using IPv6.

WWW with IPv6

You must be able to build your Mozilla without problem by following steps in my installation note. On the other hand, you can build an IPv6-ready web server like this (to reach this page, you need an IPv6 ready web browser since this server doesn't have A record, but just AAAA record). Refer to this installation note for detail of installation.

Acknowledgement

Let me thank Masaki Minami of WIDE Project for his advise on troubleshooting IPv6 tunneling configuration. It really helped and saved a lot of my time and effort.

Links