Debian 8 + DNS64 + NAT64 on the Raspberry Pi 2

Debian 8 上に DNS64 + NAT64 を設定した備忘録である。例によって無保証である。

2017/02/11 追記: Jool 3.5.x 系でも同じようにインストール出来ることを確認した。

Linux カーネルのビルドは、「Kernel Building – Raspberry Pi Documentation」に記載の通り、DNS64, NAT64 関係は、「DSAS開発者の部屋:Raspberry Pi 2 で NAT64 箱をつくってみた」の通りとなる。

両者のドキュメントに感謝しつつ、実際に設定を行ってみた。なお、私の環境では、USB で NIC を接続して別インタフェースを接続している。


■ Linux カーネルビルド

カーネルヘッダが欲しいだけのために、とりあえず Linux カーネルビルドを行う。

・Linux カーネルのビルドに必要なパッケージをインストールする。

# apt-get install bc build-essential git

・Linux ソースをダウンロードしてくる。

$ cd /usr/local/src/linux
$ git clone --depth=1 https://github.com/raspberrypi/linux
$ cp -a linux linux-4.1.21-v7+

cp のコピー先の数字は、Makefile に「VERSION」、「PATCHLEVEL」、「SUBLEVEL」で書いてあるもので指定した。

・Linux カーネルのビルドとインストールを行う。

$ cd linux-4.1.21-v7+
$ KERNEL=kernel7
$ make bcm2709_defconfig
$ make -j4 zImage modules dtbs
$ sudo make modules_install
$ sudo cp arch/arm/boot/dts/*.dtb /boot/
$ sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
$ sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/
$ sudo scripts/mkknlimg arch/arm/boot/zImage /boot/$KERNEL.img

上記「make -j4 zImage modules dtbs」が完了するまで、Raspberry Pi 2 で大体1時間半ぐらいかかった。

・再起動する。

再起動後、新しいカーネルで起動したか確認する。


■ Unbound のインストールと設定

Debian 8 の Unbound は 1.4 系統なので、DNS64 に対応していない。このため、Backports から 1.5 系統をインストールする。

・/etc/apt/sources.list に以下を追加

deb http://ftp.jp.debian.org/debian/ jessie-backports main
deb-src http://ftp.jp.debian.org/debian/ jessie-backports main

・インストールする。

# apt-get update
# apt-get install -t jessie-backports unbound

・ルートヒントファイルを置く。

# cd /etc/unbound
# wget "https://www.internic.net/domain/named.cache"

・/etc/unbound/unbound.conf.d/remote-control.conf ファイルを設定する。

remote-control:
	control-enable: yes
	control-interface: 127.0.0.1
	control-interface: ::1

・/etc/unbound/unbound.conf.d/server.conf ファイルを設定する。

server:
	interface: 0.0.0.0
	interface: ::

	num-threads: 4
	msg-cache-slabs: 4
	rrset-cache-slabs: 4
	infra-cache-slabs: 4
	key-cache-slabs: 4
	rrset-cache-size: 50m
	msg-cache-size: 25m
	outgoing-range: 200
	num-queries-per-thread: 100

	access-control: 127.0.0.1/32 allow
	access-control: ::1/128 allow
	access-control: 2001:2:0:aab1::/64 allow

	log-queries: yes
	log-time-ascii: yes
	verbosity: 1

	root-hints: "/etc/unbound/named.cache"

	identity: "HOST"
	version: "DNS Server"

	private-address: 10.0.0.0/8
	private-address: 172.16.0.0/12
	private-address: 192.168.0.0/16
	private-address: 169.254.0.0/16
	private-address: fd00::/8
	private-address: e80::/10

	module-config: "dns64 iterator"
	dns64-prefix: 64:ff9b::/96
	dns64-synthall: yes

■ネットワークの設定

・/etc/network/interfaces に以下を追加する。

auto eth1
iface eth1 inet6 static
	address 2001:2:0:aab1::1
	netmask 64
	offload-tso off
	offload-ufo off
	offload-gso off
	offload-gro off
	offload-lro off
	pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_ra
	pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/autoconf
	pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_ra_defrtr
	pre-up echo 0 > /proc/sys/net/ipv6/conf/eth1/accept_redirects

・ip6tables で以下のように定義した。

ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP
# loopback
ip6tables -A INPUT  -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
# ICMPv6
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type packet-too-big          -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type time-exceeded           -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type parameter-problem       -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type echo-request            -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type router-solicitation     -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type neighbour-solicitation  -j ACCEPT
ip6tables -A INPUT  -i eth1 -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type packet-too-big          -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type time-exceeded           -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type parameter-problem       -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type echo-request            -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type router-advertisement    -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type neighbour-solicitation  -j ACCEPT
ip6tables -A OUTPUT -o eth1 -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT
# DHCPv6
ip6tables -A INPUT  -p udp -i eth1 --sport 546 --dport 547 -j ACCEPT
ip6tables -A OUTPUT -p udp -o eth1 --sport 547 --dport 546 -j ACCEPT
# ESTABLISHED,RELATED Packet
ip6tables -A INPUT  -i eth1 -s 2001:2:0:aab1::/64 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A OUTPUT -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT
# DNS
ip6tables -A INPUT -p tcp --dport 53 -i eth1 -s 2001:2:0:aab1::/64 -d 2001:2:0:aab1::1 -m state --state NEW -j ACCEPT
ip6tables -A INPUT -p udp --dport 53 -i eth1 -s 2001:2:0:aab1::/64 -d 2001:2:0:aab1::1 -m state --state NEW -j ACCEPT

・IPv6 のパケット転送を許可する (これをやらないと、radvd が起動できない)

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

※個人的には、ip6tables をまとめているスクリプトの一番最後で実行すれば良いと思う。
なお、/etc/sysctl.conf の方では以下のようにしている。

net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.all.autoconf = 0
net.ipv6.conf.all.accept_ra_defrtr = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_ra = 0
net.ipv6.conf.default.autoconf = 0
net.ipv6.conf.default.accept_ra_defrtr = 0
net.ipv6.conf.default.accept_redirects = 0

・再起動する。

再起動後、eth1 に IPv6 アドレス、2001:2:0:aab1::1 が割り当てられているか確認する。


■ radvd のインストールと設定

・インストールする。

# apt-get install radvd

・/etc/radvd.conf ファイルを設定する。

interface eth1 {
	AdvSendAdvert on;
	MinRtrAdvInterval 3;
	MaxRtrAdvInterval 10;
	AdvOtherConfigFlag on;
	prefix 2001:2:0:aab1::/64 {
		AdvOnLink on;
		AdvAutonomous on;
		AdvRouterAddr on;
	};
};

・radvd を再起動する。

# systemctl restart radvd

■ DHCPv6 のインストールと設定

・インストールする。

# apt-get install isc-dhcp-server

・/etc/default/isc-dhcp-server ファイルを設定する。

DHCPD_CONF=/etc/dhcp/dhcpd6.conf
DHCPD_PID=/var/run/dhcpd6.pid
OPTIONS="-6"
INTERFACES="eth1"

・/etc/dhcp/dhcpd6.conf ファイルを設定する。

default-lease-time 600;
max-lease-time 7200; 
log-facility local7;

subnet6 2001:2:0:aab1::/64 {
	option dhcp6.name-servers 2001:2:0:aab1::1;
}

・DHCP を再起動する。

# systemctl restart isc-dhcp-server

■ Jool のインストールと設定

・ユーザコマンドのビルドに必須のパッケージを追加インストールする。

# apt-get install pkg-config libnl-3-dev

・Jool をダウンロードして展開する。

$ cd /usr/local/src/jool
$ wget "https://github.com/NICMx/jool-doc/raw/gh-pages/download/Jool-3.4.2.zip"
$ unzip Jool-3.4.2.zip

Jool の Download ページで公開されているものをダウンロードしてくる。

・カーネルモジュールをビルドしてインストールする。

$ cd Jool-3.4.2/mod
$ make
$ sudo make modules_install
$ sudo depmod -a

2017/02/11 追記: Jool 3.5.x 系でインストールした時は、「sudo make modules_install」は「sudo make install」で行った。

・Jool モジュールを組み込む。

# modprobe jool pool6=64:ff9b::/96

・ユーザコマンドをビルドしてインストールする。

$ cd /usr/local/src/jool/Jool-3.4.2/usr/
$ ./configure
$ make
$ sudo make install

2017/02/11 追記: Jool 3.4.x 系のコマンドをアンインストールする際は、「sudo make unstall」で行った。

・Jool モジュールの組み込みを恒久的に有効とする。

# echo "jool" >> /etc/modules
# echo "options jool pool6=64:ff9b::/96" > /etc/modprobe.d/jool.conf

・再起動する。

再起動後、lsmod 等で、モジュールが組み込まれているか確認する。


これで、eth1 に接続されたネットワーク機器には、IPv6 アドレスが自動的に割り振られて、DNS64 + NAT64 で IPv4 なネットワークへアクセス可能となる。
ただしこの設定では、IPv6 しかアドレスを持っていないようなホストには到達できない。
なお、IPv4 のパケット転送は不要だった。

OS X El Capitan のマシンを有線で接続して通信の確認と、適当な Wi-Fi AP を入れて iPad2 での Wi-Fi での通信を確認したが、どちらも普通の IPv4 だけのネットワークと同じようにアクセス出来た。

課題としては、IPv6 アドレスしか持たないホストへのアクセスを出来る様にすること。
実は eth0 側には IPv6 アドレスが当たっているので、たぶん eth1 側に割り当てるネットワークをここから割り当てたものにして、ip6tables でパケット転送を設定して、ルータ側でルーティングテーブルを設定したらいけそうな気がするが、ちょっと疲れたのでこの辺りで。


・追記 (2017/02/17) IPv6 アドレスのみのホストにも接続できるように設定

この設定を行っているサーバは、外側のインタフェース (eth0) にグローバル IPv6 アドレスが 1 つ当たっていました。そして、いつの間にか IPv6 で MASQUERADE が使用できるようになっていたため、NAPT 出来る様になっていました。

ということで、DNS64 + NAT64 配下の端末が、サーバの IPv6 アドレスから IPv6 ネットワークへそのまま出て行けるように、ip6tables のルールに以下を挿入しました。

ip6tables のルールに挿入する内容。

ip6tables -A FORWARD -i eth1 -o eth0 -s 2001:2:0:aab1::/64 -d ::/0 -j ACCEPT
ip6tables -A FORWARD -i eth0 -o eth1 -s ::/0 -d 2001:2:0:aab1::/64 -j ACCEPT -m state --state ESTABLISHED,RELATED
ip6tables -t nat -A POSTROUTING -o eth0 -s 2001:2:0:aab1::/64 -d ::/0 -j MASQUERADE

/etc/unbound/unbound.conf.d/server.conf の「dns64-synthall」オプションを「no」にして、IPv6 アドレスはそのまま変更せず返すようにする。

dns64-synthall: no

これで、DNS64 + NAT64 配下の端末も、NAPT されているとは言え、IPv6 ネットワークにそのまま繋がるようになりました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です