今回は、Linux の Network Namespace と radvd / dnsmasq を使って IPv6 の SLAAC を試してみる。 IPv6 では、アドレスの自動設定にいくつかのやり方がある。 SLAAC というのは、そのひとつで RFC 4862 で定義されている IPv6 Stateless Address Autoconfiguration のことを指す。 SLAAC では ICMPv6 NDP (Neighbor Discovery Protocol) の RA (Router Advertisement) というメッセージでアドレスとデフォルトルートを設定する。 その上で、RFC 8415 で定義されている Stateless DHCPv6 というプロトコルを使って DNS や NTP サーバを設定する。 なお、現在では RFC 8106 で定義されている RDNSS というオプションを使うことで、RA 単独でも DNS サーバを設定することができる。
使った環境は次のとおり。
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=18.04 DISTRIB_CODENAME=bionic DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS" $ uname -r 4.15.0-76-generic $ dpkg -l | egrep "(radvd|dnsmasq|isc-dhcp-client)" ii dnsmasq 2.79-1 all Small caching DNS proxy and DHCP/TFTP server ii dnsmasq-base 2.79-1 amd64 Small caching DNS proxy and DHCP/TFTP server ii isc-dhcp-client 4.3.5-3ubuntu7.1 amd64 DHCP client for automatically obtaining an IP address ii radvd 1:2.16-3 amd64 Router Advertisement Daemon
もくじ
作るネットワーク
用意するネットワークの物理的な構成は次のとおり。 白抜きになっている箱が Network Namespace を表している。 また、端点をもった線は veth インターフェイスを表している。
ネットワークの論理的な構成は次のとおり。
実験では host
のアドレスやデフォルトルートを設定することになる。
下準備
下準備として、必要なパッケージをインストールしておく。
$ sudo apt-get -y install radvd dnsmasq isc-dhcp-client tcpdump
ネットワークを作る
まずは Network Namespace を作る。
$ sudo ip netns add host $ sudo ip netns add router
そして、Network Namespace 同士をつなぐ veth インターフェイスを作る。
$ sudo ip link add ht-veth0 type veth peer name gw-veth0
作ったインターフェイスを Network Namespace に所属させる。
$ sudo ip link set ht-veth0 netns host $ sudo ip link set gw-veth0 netns router
デフォルトでは EUI-64 を使ってアドレスの下位 64 ビットが生成されるため、わかりやすいように MAC アドレスを変更しておく。
$ sudo ip netns exec host ip link set dev ht-veth0 address 00:00:5E:00:53:01 $ sudo ip netns exec router ip link set dev gw-veth0 address 00:00:5E:00:53:02
veth インターフェイスの状態を UP に設定する。
$ sudo ip netns exec host ip link set ht-veth0 up $ sudo ip netns exec router ip link set gw-veth0 up
router
の方にリンクローカルアドレス (fe80::1
と、グローバルアドレスを模したドキュメンテーションアドレス (2001:db8::1
) を付与しておく。
$ sudo ip netns exec router ip address add fe80::1/64 dev gw-veth0 $ sudo ip netns exec router ip address add 2001:db8::1/64 dev gw-veth0
次のようにアドレスが付与された。
$ sudo ip netns exec router ip address show gw-veth0 16: gw-veth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:00:5e:00:53:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 2001:db8::1/64 scope global valid_lft forever preferred_lft forever inet6 fe80::1/64 scope link valid_lft forever preferred_lft forever inet6 fe80::200:5eff:fe00:5302/64 scope link valid_lft forever preferred_lft forever
あとは router
の方で IPv6 のルーティングを有効にしておく。
ちなみに、このカーネルパラメータのフラグを立てておかないと radvd が起動しない。
$ sudo ip netns exec router sysctl -w net.ipv6.conf.all.forwarding=1
radvd
はじめに、radvd から試してみる。 このプログラムは ICMPv6 NDP の RA を送ることができる。
はじめに、radvd の設定ファイルを用意する。
次の設定で、プレフィックスとして 2001:db8::/64
を広告しつつ、デフォルトルートを 2001:db8::1
に向けることができる。
cat << 'EOF' > radvd.conf interface gw-veth0 { # 定期的にルータ広告を送る AdvSendAdvert on; # SLAAC でアドレスの自動生成に使うプレフィックスを広告する prefix 2001:db8::/64 { }; }; EOF
通信を観察するために tcpdump をしかけておく。
$ sudo ip netns exec host tcpdump -tnlvv -i ht-veth0 ip6 tcpdump: listening on ht-veth0, link-type EN10MB (Ethernet), capture size 262144 bytes
準備ができたら、用意した設定ファイルを使って radvd を起動する。
$ sudo ip netns exec router radvd -C radvd.con
すると、次のように prefix
オプションを含む RA メッセージが出る。
$ sudo ip netns exec host tcpdump -tnlvv -i ht-veth0 ip6 tcpdump: listening on ht-veth0, link-type EN10MB (Ethernet), capture size 262144 bytes IP6 (flowlabel 0xa72b0, hlim 255, next-header ICMPv6 (58) payload length: 56) fe80::1 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 56 hop limit 64, Flags [none], pref medium, router lifetime 1800s, reachable time 0ms, retrans timer 0ms prefix info option (3), length 32 (4): 2001:db8::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s 0x0000: 40c0 0001 5180 0000 3840 0000 0000 2001 0x0010: 0db8 0000 0000 0000 0000 0000 0000 source link-address option (1), length 8 (1): 00:00:5e:00:53:02 0x0000: 0000 5e00 5302
host
のインターフェイスは、RA を受信して prefix
オプションを使ってアドレスを自動設定する。
$ sudo ip netns exec host ip address show dynamic ht-veth0 11: ht-veth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:00:5e:00:53:01 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet6 2001:db8::200:5eff:fe00:5301/64 scope global dynamic mngtmpaddr valid_lft 86379sec preferred_lft 14379sec
また、同時にルータ広告を送ってきたリンクローカルアドレスにデフォルトルートを設定する。
$ sudo ip netns exec host ip -6 route show 2001:db8::/64 dev ht-veth0 proto kernel metric 256 expires 86388sec pref medium fe80::/64 dev ht-veth0 proto kernel metric 256 pref medium default via fe80::1 dev ht-veth0 proto ra metric 1024 expires 1788sec hoplimit 64 pref medium
RDNSS の設定を追加してみる
RA の基本的な動作が確認できたので、つづいては RDNSS の設定を追加してパケットを観察してみる。
radvd の設定ファイルに RDNSS の設定を追加する。
配布する DNS サーバのアドレスは 2001:db8::dead:beef
に指定した。
$ cat << 'EOF' > radvd.conf interface gw-veth0 { # 定期的にルータ広告を送る AdvSendAdvert on; # SLAAC でアドレスの自動生成に使うプレフィックスを広告する prefix 2001:db8::/64 { }; # RDNSS (RFC 8106) で DNS サーバを広告する RDNSS 2001:db8::dead:beef { }; }; EOF
radvd のプロセスに SIGHUP を送って設定ファイルを読み直させる。
$ sudo kill -HUP $(cat /var/run/radvd.pid)
すると、次のとおり RDNSS オプションを含む RA が観察できた。
$ sudo ip netns exec host tcpdump -tnlvv -i ht-veth0 ip6 tcpdump: listening on ht-veth0, link-type EN10MB (Ethernet), capture size 262144 bytes ...(snip)... IP6 (flowlabel 0xa72b0, hlim 255, next-header ICMPv6 (58) payload length: 80) fe80::1 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 80 hop limit 64, Flags [none], pref medium, router lifetime 1800s, reachable time 0ms, retrans timer 0ms prefix info option (3), length 32 (4): 2001:db8::/64, Flags [onlink, auto], valid time 86400s, pref. time 14400s 0x0000: 40c0 0001 5180 0000 3840 0000 0000 2001 0x0010: 0db8 0000 0000 0000 0000 0000 0000 rdnss option (25), length 24 (3): lifetime 600s, addr: 2001:db8::dead:beef 0x0000: 0000 0000 0258 2001 0db8 0000 0000 0000 0x0010: 0000 dead beef source link-address option (1), length 8 (1): 00:00:5e:00:53:02 0x0000: 0000 5e00 5302
dnsmasq (RA + Stateless DHCPv6)
つづいては dnsmasq を使って RA + Stateless DHCPv6 のパターンを検証してみる。
どうやら dnsmasq には RA を送る機能もあるようなので、いったん radvd のプロセスは kill しておく。
$ sudo kill $(cat /var/run/radvd.pid)
あらためて tcpdump をしかけておく。
$ sudo ip netns exec host tcpdump -tnlvv -i ht-veth0 ip6
そして、dnsmasq を起動する。
--enable-ra
オプションが RA を送る指定になっている。
$ sudo ip netns exec router dnsmasq \ --enable-ra \ --dhcp-range=::,constructor:gw-veth0,ra-stateless \ --dhcp-option=option6:dns-server,[2001:db8::dead:beef] \ --dhcp-option=option6:ntp-server,[2001:db8::dead:beef] \ --no-daemon
準備ができたら isc-dhcp の dhclient を起動する。
-6
オプションと -S
オプションを組み合わせることで IPv6 SLAAC のモードになる。
$ sudo ip netns exec host dhclient -6 -S ht-veth0
tcpdump のターミナルを確認すると、次のとおり RA と Stateless DHCPv6 のパケットがやり取りされていることがわかる。 なお、RA にはデフォルトで RDNSS オプションが付与されるらしい。 まあ、たしかに Stateless DHCPv6 と同じ DNS サーバのアドレスを配布するなら、オプションがあっても副作用はとくにないのかな?
$ sudo ip netns exec host tcpdump -tnlvv -i ht-veth0 ip6 tcpdump: listening on ht-veth0, link-type EN10MB (Ethernet), capture size 262144 bytes ... (snip) ... IP6 (class 0xc0, flowlabel 0xa72b0, hlim 255, next-header ICMPv6 (58) payload length: 88) fe80::1 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 88 hop limit 64, Flags [other stateful], pref medium, router lifetime 1800s, reachable time 0ms, retrans timer 0ms prefix info option (3), length 32 (4): 2001:db8::/64, Flags [onlink, auto], valid time 3600s, pref. time 3600s 0x0000: 40c0 0000 0e10 0000 0e10 0000 0000 2001 0x0010: 0db8 0000 0000 0000 0000 0000 0000 mtu option (5), length 8 (1): 1500 0x0000: 0000 0000 05dc source link-address option (1), length 8 (1): 00:00:5e:00:53:02 0x0000: 0000 5e00 5302 rdnss option (25), length 24 (3): lifetime 3600s, addr: 2001:db8::dead:beaf 0x0000: 0000 0000 0e10 2001 0db8 0000 0000 0000 0x0010: 0000 dead beaf IP6 (flowlabel 0x5f40a, hlim 1, next-header UDP (17) payload length: 48) fe80::200:5eff:fe00:5301.546 > ff02::1:2.547: [bad udp cksum 0xafc9 -> 0x2ffe!] dhcp6 inf-req (xid=29221d (client-ID hwaddr/time type 1 time 634459916 00005e005301) (option-request DNS-server DNS-search-list Client-FQDN SNTP-servers) (elapsed-time 0)) IP6 (class 0xc0, flowlabel 0x48785, hlim 64, next-header UDP (17) payload length: 76) fe80::1.547 > fe80::200:5eff:fe00:5301.546: [bad udp cksum 0xaf61 -> 0x705b!] dhcp6 reply (xid=29221d (client-ID hwaddr/time type 1 time 634459916 00005e005301) (server-ID hwaddr/time type 1 time 634459172 00005e005302) (DNS-server 2001:db8::dead:beaf) (lifetime 3600))
めでたしめでたし。