FreeBSD

DS-lite と PPPoE の共存

とあるところで、PPPoE の固定 IP を維持しながら IPv4 over IPv6 接続をすることになった。自宅サーバとほぼ同じ構成なのでまず手元で検証。

下調べ

プロバイダのページを見ると、どうやら DS-lite でつなぐよう。 過去にいろんなひとが記事にしているのでそれを試してみた。

最終的には、サーバ上のサービスはこれまでどおり固定 IP (PPPoE) で利用し、 LAN 内の他のマシンからの IPv4 トラフィックを DS-Lite に逃がす状態にする。

DS-lite の実現方法

基本的には、gif(4) でトンネルを作るだけ。

これで終わりかと思ったんだけど、どうも全体の動作が変。 外から固定 IP への通信ができないし、DNS lookup がやたら遅い。

各インターフェイスを tcpdump(1) しまくった結果、

という状態だと判った。

丸一日悩んだけど、調べたら前者は sys/netinet/ip_output.c のバグ。 システムの更新は freebsd-update(8) に一本化してるからパッチ当てて kernel 作り直すのは無し。

後者はどうしても解決法が見つからず。

ipfw fwd で行先を振り分ける方法は不採用。

fib を使う

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で複数のルーティングテーブルを使い分ける