Linux マシンを IPv6 ルータにする(Ubuntu 16.04)

Interlink で IPv6 オプションがリリースされ、「ほぼ固定だけど長期間使用しないと変更される可能性がある」 IPv6 prefix が PPPoE で降ってくるようになりました。(「IPv6接続サービス」提供開始のご案内

ということで、Ubuntu 16.04 の VM 経由で PPPoE に繋いでルーターにしてみました。

Raspberry PiでIPv6 PPPoE対応ルータを作る – ももいろテクノロジーフレッツ光ネクスト用IPv6 PPPoEアダプターを作ってみる — SOUM/misc を参考に実施したので、こちらを参照するとよいと思いますが、自分用のメモを兼ねて残します。

なお、色々試してうまく行ったあと記憶を基に再現しているので、追加の手順が必要だったなどあればコメントでお願いします。

VM 構成

  • ens160: フレッツ網に繋がる NIC (ONU 直結、またはそれと等価な状態)
  • ens192: 今回の設定に関係させてはいけない NIC (実験のため設置)
  • ens224: 部屋のネットワークに繋がる NIC。ここに繋いだ端末を IPv6 インターネットに繋ぐのがこの記事の目標

パケットが適切に届けば VM でも特に変わらない。

(余談ですが ens160 みたいなのは、 eth0 みたいなのと同じく NIC のデバイス名。Predictable Network Interface Device Name を Ubuntu 16.04 などのシステムが導入しているのでこういう名前になっている模様。)

フレッツ網からの RA ブロック

NTT東西のフレッツ網は日本国内で IPv6 イントラネットを構成しており、 PPPoE しようとしてフレッツ網に接続すると IPv6 の RA (イントラネットにも関わらずグローバルアドレス)が降ってきてしまう。

状況次第ではあるが、 ISP から直接フレッツ網に IPoE と呼ばれるものを引き込んでくれる契約をしていなければ、この IPv6 網に繋がってしまう.
もし他のプロバイダが IPoE 設定になっていると今度は複数のインターネットに繋がるプレフィックスに同一マシンがつながってしまうことになる。いずれも(理解してそうなっているのでなければ)よろしくない。(IPv6 – Wikipediaに詳しく書かれている)

今回はプロバイダに対して DHCPv6 接続するので、全ての RA の受信を遮断する設定にした。/etc/sysctl.conf に追記。ens160 が、フレッツ網(PPPoEや、フレッツのイントラネットに接続)に繋がる NIC だとする。

$ cat /etc/sysctl.conf | tail -n 4 | head -n 2
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.ens160.accept_ra = 0

$ sudo sysctl -p /etc/sysctl.conf

IPv6 over PPPoE (pppoeconf)

apt で pppoeconf をインストールして pppoeconf コマンドで設定。ダイアログが出てくるのに答えれば PPPoE セッション自体は張ってくれるが、 IPv4 と違って少し追加設定が必要。/etc/ppp/peers/dls-provider を修正。

$ cat /etc/ppp/peers/dsl-provider
# Minimalistic default options file for DSL/PPPoE connections

noipdefault
defaultroute
replacedefaultroute
hide-password
#lcp-echo-interval 30
#lcp-echo-failure 4
noauth
persist
#mtu 1492
#persist
#maxfail 0
#holdoff 20
plugin rp-pppoe.so
nic-ens160
user "***@***"
usepeerdns
+ipv6
ipparam ipv6default

修正したら、

$ sudo poff dsl-provider
$ sudo pon dsl-provider

で再接続して反映。ifconfig ppp0 でリンクローカルアドレスがインターフェイスに付与されていることを確認。

デフォルトルートの設定

PPPoE を起動した際、ルーティングテーブルに追加されるようにする。なお、 /etc/ppp/ipv6-up.d/ 以下のファイルを新規追加する場合は実行権限が必要。

$ cat /etc/ppp/ipv6-up.d/v6route
#!/bin/sh
if [ -z "${CONNECT_TIME}" ]; then
    if [ "${PPP_IPPARAM}" = "ipv6default" ]; then
        ip -6 route add default dev ${PPP_IFACE}
    fi
fi

$ ip -6 route
(snip.)
default dev ppp0  metric 1024  pref medium

DHCPv6 クライアント (wide-dhcpv6)

このままではまだインターリンクとの間に貼られた PPPoE セッションでのみ使えるリンクローカルアドレスしか手に入っていないので、 DHCPv6-PD クライアントを実行し、グローバル IPv6 アドレスの /64 prefix の移譲を受ける。

apt で wide-dhcpv6-client をインストールした。

/etc/wide-dhcpv6/dhcp6c.conf を設定

profile default
{
  information-only;

  request domain-name-servers;
  request domain-name;

  script "/etc/wide-dhcpv6/dhcp6c-script";
};

interface ppp0 {
  send ia-pd 0;
  request domain-name-servers;
  script "/etc/wide-dhcpv6/dhcp6c-script";
};

id-assoc pd 0 {
  prefix-interface ens224 {
    sla-id 1;
    sla-len 8;
  };
};

なお、 ens224 は PPPoE で使っている NIC ですらなく、 LAN 側で使っているインターフェイス。不思議だが、 ppp0 に指定してもうまくいかない上、逆にちゃんと MAC アドレスを持つ NIC なら IPv6 接続に関係のないインターフェイスを指定してもアドレス自体は取得できた。DHCPv6 を含む IPv6 のアドレス取得メカニズム自体にも MACアドレスを利用するものはあるので関係があっても不思議ではないが、検証するのが大変そうなので今のところ深追いはしていない。

ただ、どうもこの後の設定に影響はするらしく、最終的には室内 LAN に繋がる NIC を指定することとなった。

ファイヤーウォール (ip6tables)

RedHat 系だと標準で保存した iptables を起動時に読み込む機能が備わっているが、Debian 系はそういうわけでもない。と思っていたら、 netfilter-persistent なるパッケージがあり、これをインストールすると似たことができる模様。

apt で netfilter-persistent をインストールする。iptables や ip6tables をいじったら、 sudo service netfilter-persistent save などとして保存できる。/etc/iptables/rules.v[46] に保存するようなので、これを直接編集することもできなくはないと思われる。

というわけで、あとは ip6tables を設定する。LAN 内がプライベートアドレスのため変換が必要となり iptables でマスカレードを指示していた IPv4時代と異なり、基本的に全てのマシンがグローバルアドレスを持ち、普通に end to end で通信するのを中継するだけなので、 iptables はなくとも通信は可能ではある(中継設定自体は後述)。が、安全のため、とりあえず従来と同様外から中に通信を開始するのをブロックしてみた。

ip6tables 自体は以下の感じ。ens224 が IPv6 を提供する部屋LAN、 ens192 が今回の設定に関与させない(IPv6 に繋がない)NIC。

# Initialize
ip6tables -X
ip6tables -F

# Default Rule
ip6tables -P OUTPUT ACCEPT
ip6tables -P FORWARD DROP
ip6tables -P INPUT DROP

# Established
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# LAN
ip6tables -A INPUT -i ens224 -j ACCEPT
ip6tables -A INPUT -i ens192 -j DROP

# loopback
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT

# ICMPv6
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT

# FORWARD
ip6tables -A FORWARD -i ens192 -j DROP
ip6tables -A FORWARD -o ens192 -j DROP
ip6tables -A FORWARD -i ens224 -j ACCEPT
ip6tables -A FORWARD -i ppp0 -m state --state RELATED,ESTABLISHED -j ACCEPT

# OUTPUT
ip6tables -A OUTPUT -o ens192 -j DROP

転送設定

ルータなのでここが基幹部分と言える(といっても Linux の機能を呼び出すだけ)。ファイヤーウォールの設定が済んだら設定する。/etc/sysctl.conf に追記。

$ cat /etc/sysctl.conf | tail -n 1
net.ipv6.conf.all.forwarding = 1

$ sudo sysctl -p /etc/sysctl.conf

Router Advertisement (radvd)

RA を用いて接続するマシンの自動設定を行うため radvd を入れた。ただ、現状を踏まえると DHCPv6 を導入した方がいいかもしれない(次のクライアント側の設定の問題)。

cat /etc/radvd.conf

interface ens224 {
  AdvSendAdvert on;
  MinRtrAdvInterval 3;
  MaxRtrAdvInterval 10;
  prefix ::/64 {
    AdvOnLink on;
    AdvAutonomous on;
    AdvRouterAddr on;
  };

  RDNSS 2001:db8::1 2001:db8::2
  {
  };
};

RDNSS の部分の二つの IPv6 アドレスは実際にはプロバイダが公知している DNS キャッシュサーバの IPv6 アドレスを直書きした。書いたら radvd を再起動。

sudo radvdump ens224 などとすると、配布内容を確認できた。

クライアント側

ここでは IPv6 のみに繋がるクライアントを一台構成した。IPv4 を設定する場合は基本的に独立して設定してよいはず。

RFC5006RFC6106などで RDNSS プロトコルが定められており、DHCPv6 を用いなくとも RA で DNS キャッシュサーバのアドレスを通知することができ、radvd も対応している。しかし、少なくとも Ubuntu 16.04 標準の機能でこれを有効にする方法は見つからなかった。そのため、この説明では DNS キャッシュサーバのアドレスをクライアント側で直書きしている。微妙。今後調査したい。

それ以外は自動設定で問題なかった。

/etc/network/interfaces

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
# This is an autoconfigured IPv6 interface
auto ens160
iface ens160 inet6 auto
    dns-nameservers 2001:db8::1 2001:db8::2

しかし、現状では DHCPv6 のほうがよさそうな気もするので、今後試してみたい。

(追記)ルーターではないが、 IPv6 についてはパススルー + DHCPv6 も導入した構成を別の記事で試している。フレッツの IPv6 を Ubuntu + Open vSwitch でパススルーさせて使う | にろきのメモ帳