Linux的IPv6速成班

On 2011年04月23日, in linux, tips, by netoearth

You might be used to working with IPv4 on Linux, but like it or not IPv6 is on its way in. Roll up your sleeves, spit on your palms, and get ready to go to work because this is your crash course in actually using IPv6. It hardly hurts at all. Linux has supported it since the 2.1 kernel, so you shouldn’t have to install anything. Make sure you have the ping6, ip, and ifconfig commands.

Let’s get my favorite nitpick out of the way right now — we do not have IPs, we have IP addresses. IP stands for Internet Protocol. As my wise grandmother used to say, sloppy speech equals sloppy habits, which equals a trip to hell in a handbasket.

IPv6 Advantages

What does IPv6 offer over IPv4? Well, aside from the fact that we’re more or less out of new IPv4 addresses, IPv6 has a number of additional advantages.

  • No more private address collisions.
  • Network address translation (NAT) is optional, rather than a necessity.
  • Simplified routing.
  • Say good-bye to DHCP.

One major drawback to IPv6 is unwieldy long hexadecimal addresses. IPv4 dotted quads are easy to remember. Eight clumps of hexadecimal numbers are a lot harder, at least for my old brain.

Does My Linux System Support IPv6?

How do you know if your system supports IPv6? Simple:


$ cat /proc/net/if_inet6
000000000000000000000000000000 01 01 80 10 80       lo
fe80000000000000020b6afffeef7e 8d 02 40 20 80     eth0

This means yes. Most modern distros should support IPv6 out of the box.

Pinging IPv6

If you want to ping IPv6 addresses, you’ll need the ping6 command. This pings localhost twice:


$ ping6 -c2 ::1
PING ::1(::1) 56 data bytes
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from ::1: icmp_seq=2 ttl=64 time=0.054 ms

--- ::1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.043/0.048/0.054/0.008 ms

::1 is shorthand for 0000:0000:0000:0000:0000:0000: 0000:0001. Any one unbroken sequence of consecutive zeros can be shortened to a pair of colons, and any quad of all zeroes can be condensed to a single zero, like 0.0.0.0.0.0.0:1.

LAN Discovery

Want to find out if you have IPv6 neighbors on your LAN?


$ ping6 -c4 -I eth0 ff02::1
PING FF02:0:0:0:0:0:0:1(ff02::1) from fe80::20d:b9ff:fe05:25b4 eth0: 56 data bytes
64 bytes from fe80::20d:b9ff:fe05:25b4: icmp_seq=1 ttl=64 time=0.301 ms
64 bytes from fe80::20b:6aff:feef:7e8d: icmp_seq=1 ttl=64 time=3.69 ms (DUP!)
64 bytes from fe80::221:97ff:feed:ef01: icmp_seq=1 ttl=64 time=8.91 ms (DUP!)
[snip duplicate lines]

--- FF02:0:0:0:0:0:0:1 ping statistics ---
4 packets transmitted, 4 received, +6 duplicates, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.254/1.698/8.911/2.593 ms

The response shows that yes, there are two — fe80::20b:6aff:feef:7e8d and fe80::221:97ff:feed:ef01. Note that you must specify which network interface to use, even if you have only one. ff02::1 is short for ff02:0:0:0:0:0:0:1, which is a special link-local multicast address for discovering all link-local hosts.

Link-local addresses are all in the fe80::/10 address range. These are comparable to the 169.254.0.0/16 address block in IPv4, the stateless address auto-configuration blocks. The IPv6 protocol requires link-local addresses, even if you are using other assigned addresses.

Now that you have connected to two LAN IPv6 hosts they are in the IPv6 neighbor table, which is just like the IPv4 ARP (address resolution protocol) table. You can read this table with the ip command:


$ ip -6 neigh show

fe80::221:97ff:feed:ef01 dev eth0 lladdr 00:21:97:ed:ef:01 nud reachable
fe80::20b:6aff:feef:7e8d dev eth0 lladdr 00:0b:6a:ef:7e:8d nud reachable

Here, nud reachable means the network unreachability detection status is reachable; the node(s) have been contacted and cached in the neighbor table. The neighbor table is temporary and entries disappear in a few minutes when there is no traffic to them.

You can ping these neighbors:


$ ping6 -c4 -I eth0  fe80::221:97ff:feed:ef01

Using Hostnames

We’ll get to the proper “leet” network administrator method of assigning hostnames in a future installment; for today let’s use good old reliable /etc/hosts. Let’s say you have three PCs in your little link-local LAN: fatfreddy, phineas, and franklin. You can use these fine hostnames over IPv6 as easy as pie. You’ll make identical entries in the /etc/hosts file of each PC, like this:


fe80::20b:6aff:feef:7e8d  fatfreddy
fe80::221:97ff:feed:ef01  phineas
fe80::3f1:4baf:a7dd:ba4f  franklin

Now you can ping6 by hostname:


$ ping6 -I eth0 phineas
PING phineas(phineas) from fe80::221:97ff:feed:ef01 eth0: 56 data bytes
64 bytes from phineas: icmp_seq=1 ttl=64 time=17.3 ms

SSH and SCP

SSH and SCP both speak IPv6. Warning: there are some syntax gotchas, so pay attention. You can log in and copy files on your ad-hoc IPv6 link-local network just like on your old-fashioned IPv4 network. If you have IPv6 name services set up then you don’t do anything differently. For example, you can login via ssh as a different user in the usual way, ssh user@remotehost. Copying a file is also exactly the same: scp filename user@remotehost:/home/username/directory/.

It gets tricky using your IPv6 link-local addresses. This is how you establish an SSH session:

ssh phineas@fe80::221:97ff:feed:ef01%eth0

Again, you must specify the network interface name on your PC, and you must do it as shown, appended with a percent sign and no spaces. scp has its own fiendish syntax quirks:


$ scp test.txt phineas@\[fe80::221:97ff:feed:ef01%eth0\]:
phineas@fe80::221:97ff:feed: ef01%eth0's password:
test.txt 100%   19     0.0KB/s   00:00

The IPv6 address must be enclosed in square braces, including the interface name, and the braces must be escaped.

What is My IPv6 Address?

The ifconfig -a command displays complete information on all of your network interfaces, both physical and virtual. When you know which interface to query you can quickly narrow it down with grep:


$ ifconfig eth0 |grep "inet6 addr:"

          inet6 addr: fe80::20d:b9ff:fe05:25b4/64 Scope:Link

Venturing Forth Upon the Internet

Faffing around on your LAN is all right, but what about venturing forth into the great wide Internet via IPv6? For this you need an Internet service provider that offers native IPv6, which in the US is a sadly small number. I set up my first test IPv6 network in 2004. If you had told me back then that seven years later it would have been pretty much the same I would not have believed you. Well here we are in this glorious year 2011, a little bit advanced from 2004. In the meantime you can test the waters with IPv6-over-IPv4 tunnel brokers (just like in 2004!) such as SixXS or Hurricane Electric.

June 8, 2011 is World IPv6 Day, when Google, Comcast, Facebook, Yahoo!, Akamai and Limelight Networks and other providers will provide native IPv6 connectivity for 24 hours. Test your readiness and learn more at Test IPv6.

Just like IPv4, you need to receive an allocation of IPv6 addresses from your ISP. These are global unicast addresses, and they are in the 2000::/3 range. Let’s fake one up for practice and assign it to a network interface:

# ip -6 addr add 2001::1/64 dev eth0

Now let’s check our work:


$ ifconfig eth0 |grep "inet6 addr:"

          inet6 addr: 2001::1/64  Scope:Global
          inet6 addr: fe80::20b:6aff:feef:7e8d/64 Scope:Link

If you need to remove it, use the del command with the ip utility:

# ip -6 addr del 2001::1/64 dev eth0

In real life you’ll get a big block of addresses, like 256 or more, and you’ll set up a proper server for allocating them to your hosts. Come back in part two to learn how to do this both simulated and for real, some firewall rules for IPv6 so you don’t leave yourself open to sneak attacks, and how to manage name services.

Preventing IPv6 Leaks

We’ll be practicing with real global unicast IPv6 addresses, since most of us don’t have any real ones assigned to us by a friendly IPv6-supporting ISP. It’s unlikely this will cause problems, but prevention is cheaper than cleanup, so these iptables rule block all IPv6 traffic from entering or leaving your LAN:

ip6tables -P output drop
ip6tables -p input drop
ip6tables -p forward drop

If you have a different firewall then of course you’ll have to do whatever works for it.

Assigning Global IPv6 Addresses

The link-local addresses we used in part 1 are very limited. To do real work we need to use global unicast addresses. These are the squillions of addresses in the 2000::/3 range. As an excellent reader reminded me, the 2001:0DB8::/32 block is reserved for documentation and examples, so that is what we are going to use. So we can assign a new global unicast address to an interface like this:

# ip -6 addr add 2001:0db8::1/64 dev eth0

/64 is not CIDR (classless inter-domain routing) notation, but the size in bits of the prefix. This artistic ASCII diagram explains it:

 

2001:db8:0000:0000:0000:0000:0000:0001
_____________|____|___________________
network ID   subnet  interface ID

 

The network ID is determined by your ISP when you receive a block of real IPv6 addresses. You control the subnet and interface. So there are 64 bits for the network ID + subnet, and 64 bits just for the interface ID. The entire IPv4 address space is 32 bits, so your personal block of IP addresses is going to last you a long, long time.

Now you can ping this address locally. I’ve expanded it just as a reminder of how long IPv6 addresses really are. The ping6 command helpfully shortens it:

$ ping6 2001:db8:0:0:0:0:0:1
PING 2001:db8:0:0:0:0:0:1(2001:db8::1) 56 data bytes
64 bytes from 2001:db8::1: icmp_seq=1 ttl=64 time=0.043 ms

But you can’t ping from another PC, because just like IPv4 we need a router to do this.

Adding More Addresses

You can add more addresses to a single network interface, or to more of your PCs. Just count up sequentially in hexadecimal, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, 10, 11, and so on, like this:

2001:db8::1
2001:db8::2
2001:db8::3

2001:db8::18
2001:db8::19
2001:db8::1a
2001:db8::1b

Routing

Your router must support IPv6, of course. If you’re using a Linux PC as your test machine you’re in business. First start IPv6 forwarding:

# sysctl -w net.ipv6.conf.all.forwarding=1

Verify forwarding is enabled:

# cat /proc/sys/net/ipv6/conf/eth0/forwarding
1

A return value of 1 means it is enabled, 0 means it is not. Now install radvd, the router advertiser daemon. Then create /etc/radvd.conf with this simple configuration:

 

interface eth0
{
   AdvSendAdvert on;
   prefix 2001:db8::/64
   {
   };
};

 

Copy it exactly, changing only the interface name if necessary. Now create an IPv6 address on your router, or PC acting as your router, and set an IPv6 route:

# ip address add 2001:db8::1a/64 dev eth0
# ip route add 2001:db8::/64 dev eth0

Check your work by running ifconfig and ip -6 route show. Your ip output should look similar to this:

2001:db8::/64 dev eth0 proto kernel metric 256 mtu 1500 advmss 1440 hoplimit 4294967295
2001:db8::/64 dev eth0 metric 1024 mtu 1500 advmss 1440 hoplimit 4294967295
fe80::/64 dev eth0 proto kernel metric 256 mtu 1500 advmss 1440 hoplimit 4294967295

Finally, start up the radvd daemon:

# etc/init.d/radvd start

You should now be able to ping the router from another PC. Note that unlike our link-local addresses, we don’t need to specify the network interface:

$ ping6 2001:0db8::1a

All of the computers on the same switch as your IPv6 router should have new addresses in the 2001:0db8::/64 range. You can look these up and go on a ping6 frenzy. A default gateway (for connecting to other networks) is the IPv6 address of your router:

# ip -6 route add default via 2001:db8::1a

 

Of course it’s less work to configure it in radvd.conf and have it advertised automatically by adding these lines:

route ::/0
{
};

Then when you run ip -6 route show you’ll see this:

default via 2001:db8::1a dev eth0 metric 1024 mtu 1500 advmss 1440 hoplimit 0

What if you don’t want radvd blasting IPv6 addresses all over your network? No worries, for you can limit its clients by listing their IPv6 link-local addresses like this:

 

       interface eth0
       {
               AdvSendAdvert on;
               prefix 2001:db8::/64
               {
                       AdvOnLink on;
                       AdvAutonomous on;
               };
               route ::/0
               {
               };
               clients
               {
                       fe80::20d:b9ff:fe05:25b4;
                       fe80::20b:6aff:feef:7e8d;
                       fe80::221:97ff:feed:ef01;
               };
       };

 

Mind your braces and semi-colons!

IPv6 Address Calculator

Understanding the binary math behind IPv6 addressing is crucial to understanding IPv6 addresses. Working out any conversions manually is fun and instructive a couple of times, and then it becomes an error-prone exercise in tedium, so don’t be shy about using a calculator. ip6calc is available on most Linux distributions, and there are many online Web-based IPv6 calculators.

Name Services

Setting up DNS for IPv6 is a whole article by itself, so hopefully these hints will help you.

The idea behind IPv6 auto-configuration (via link-local addressing and router advertisements) is to make it easy for hosts to join and leave the network without needing a DHCP server. You still need a DNS server to assign hostnames. BIND9 supports IPv6, and in classic BIND fashion requires too much work and too many separate configuration files. (DNS is matching numbers to names, so it seems it shouldn’t require such heavy lifting. And it doesn’t in other DNS servers, but none of them have complete IPv6 support yet.) Please refer to the BIND9 manual because it’s too long to include here. The Linux IPv6 howto has some hints on configuring BIND that breaks it down into digestible chunks.

In part 1 we did a quick review of using plain old hosts files. Another option is using Dnsmasq, which is my favorite for LAN name services. It supports IPv6 for DNS and TFTP, but not DHCP, so it’s not yet a complete solution. Dnsmasq makes the contents of /etc/hosts available in DNS. First set up static IPv6 addresses on the clients you want to access by hostname, such as servers and any machines you administer remotely. Then write an /etc/hosts file on your Dnsmasq server and restart Dnsmasq. Next, install rdnssd, the IPv6 recursive DNS server discovery daemon, on your radvd server. Then add this line to /etc/radvd.conf, using the IPv6 address of your Dnsmasq server:

RDNSS 2001:0db8::1b

 

Restart radvd and it should all work. rdnssd and radvd are works in progress, so it may or may not be glitchy. On my Debian Sid systems everything works nicely. So far.

Tagged with:  

Comments are closed.