とあるところで、PPPoE の固定 IP を維持しながら IPv4 over IPv6 接続をすることになった。自宅サーバとほぼ同じ構成なのでまず手元で検証。
プロバイダのページを見ると、どうやら DS-lite でつなぐよう。 過去にいろんなひとが記事にしているのでそれを試してみた。
最終的には、サーバ上のサービスはこれまでどおり固定 IP (PPPoE) で利用し、 LAN 内の他のマシンからの IPv4 トラフィックを DS-Lite に逃がす状態にする。
基本的には、gif(4) でトンネルを作るだけ。
# dhcp6c -i interface
して DNS サーバを調べた。firewall に注意。udp 546, 547 を通しておく。
これで終わりかと思ったんだけど、どうも全体の動作が変。 外から固定 IP への通信ができないし、DNS lookup がやたら遅い。
各インターフェイスを tcpdump(1) しまくった結果、
という状態だと判った。
丸一日悩んだけど、調べたら前者は sys/netinet/ip_output.c のバグ。 システムの更新は freebsd-update(8) に一本化してるからパッチ当てて kernel 作り直すのは無し。
後者はどうしても解決法が見つからず。
ipfw fwd で行先を振り分ける方法は不採用。
fib を使ってルーティングテーブルを分ける方法を試す。 fib についての詳しい解説はここ[3]。
まずこのへん[4]を試してみた。 確かに動くけど、デーモンの起動順序とか依存関係のあるものがたくさんあるとたぶん破綻する。 このままの方法は不採用。
ifconfig(8) や ipfw(8) の man ページを読んでいると、 インターフェイスに対して fib を指定したり、 フィルタルールの中で fib を指定・変更したりできるみたい。
ということは、従来のサービスは fib 0 で PPPoE のままにしておき、 fib 1 のほうで default を gif0 に向けて、 DS-lite に向けたいパケットだけフィルタルールで setfib 1 すればシンプル。
最終的にたどり着いた設定はこんな感じ。
/boot/loader.conf | net.fibs="2" |
/etc/sysctl.conf | net.add_addr_allfibs="1" |
/etc/rc.conf | # DS-lite => fib 1. cf. ipfw setting. cloned_interfaces="gif0" ipv6_ifconfig_gif0="tunnel My_IPv6_address AFTR's_IPv6_address" defaultrouter="-interface gif0 -fib 1" |
ipfw config file | add 3010 setfib 1 ip from 10.0.0.0/8 to not 10.0.0.0/8
add 3020 allow ip6 from AFTR's_IPv6_address to me6 |
ipv6_ifconfig_gif0
は古い書き方で、
ifconfig_gif0_ipv6
を使えって怒られるんだけど、そっちに変えるとなぜかちゃんと動かないので、このまま。
[1] ASAHIネットのDS-Liteの終端(AFTR)を取得する
[2] IIJmioのFiberAccess/NFとIPv4固定プロバイダを併用する
[3] FreeBSDにおけるFIB
[4] FreeBSDで複数のルーティングテーブルを使い分ける