2つのLinux間でIPv4 over IPv6トンネリング

IPv4 over IPv6トンネリングを使うと、IPv6しか使えない環境から、IPv4/IPv6どちらも使える環境(VPSなど)を経由してIPv4でインターネットに出ていくことができます。

今回は別にIPv4が使えなかったわけではないのですがこれを試してみました。

リモート側のみLinux(ローカル側はNECYAMAHAルーター)、あるいはローカル側のみLinux(リモート側はDS-Liteなど)という設定方法は結構ネット上にあったのですが両側ともLinuxというのは意外と少なかったので役に立つかもしれません。とはいえ他にもフレッツ網内折返しのv6 で拠点間を単純にIPIP/GREでトンネル接続してVPNする。 - それマグで!などはあるので、短めにします。リモート側をLinuxでやる記事はhttps://emeth.jp/diary/2018/05/ipv4-over-ipv6/IPv6とlinuxでネットを快適にしてみた #Linux - QiitaさくらのVPS で IPv4 over IPv6ルータの構築 | PPT固定IPv4アドレスを失ったので、VPS上にDS-Lite方式に対応したルーターを作ってみた | DevelopersIOあたりです。

今回の環境は、ローカル側がフレッツ光のIPoE(OCNバーチャルコネクト)(HGWはRX-600KI)、リモート側がGoogle Cloud PlatformのCompute Engineです。ローカル側を2400::xxxx、リモート側を2600::xxxxとします。IPv4トンネルのアドレスはローカル側が192.168.6.3/24でリモート側が192.168.6.6/24としましょう。ルートテーブル名などは適当につけています。

まずローカル側です。

sudo ip -6 tunnel add ip46 mode ip4ip6 remote 2600::xxxx local 2400::xxxx
sudo ip link set ip46 up
sudo ip a a 192.168.6.3/24 dev ip46
sudo ip route add default dev ip46 table ip46
sudo ip rule add from 192.168.6.3 lookup ip46

まずトンネルデバイスip46を作り、upし、アドレスを割り当てます。ip46をデフォルトゲートウェイとしたテーブルを作成します(/etc/iproute2/rt_tablesの編集は省略しました)。そして、192.168.6.3からのパケットはこれを使うように設定します。

次にリモート側です。基本的にローカル側とやることはほとんど同じです。

sudo ip -6 tunnel add tun46 mode ip4ip6 remote 2400::xxxx local  2600::xxxx encaplimit none
sudo ip link set tun46 up
sudo ip a a 192.168.6.6/24 dev tun46
sudo ip route add default dev tun46 table ipip
sudo ip rule add from 192.168.6.6 lookup ipip

重要な違いはencaplimit noneが付いていることです。https://emeth.jp/diary/2018/05/ipv4-over-ipv6/に詳しく書いてありますが、これがないと一部ルーターで不正パケットとして弾かれてしまうようです。手元でも、tcpdumpで見るとGCP側では正しく応答が出て行っているにもかかわらずローカル側に何も届かない状態になっていました。

encaplimit noneをつけない場合のパケットをtcpdumpで見ると「DSTOPT IP 192.168.6.3 > 192.168.6.6:」のようにIPの前にDSTOPTが付いていることがわかります。これがあると(一部のルーターでは)ダメということのようです。

他のサイトではrp_filterなどの設定が書いてありますが、この設定ではちゃんとIPアドレスを割り当てたためか、そのへんはデフォルトのままでも問題なく動きました。

また、ip6tnl0というデバイスが勝手に作られます。fb_tunnelsというのを無効にするとこれを防ぐことができるようです(Ubuntu / Debian でIPv4 over IPv6 (OCNバーチャルコネクト, v6プラス), systemdによる設定, ルーター化, VPNおよび自宅サーバー可能な固定グローバルIPv4アドレス #RaspberryPi - Qiita)。

tunnelの作成時にdev eth0などと物理デバイスを指定する方法もあるようですが、それがなくても動きました。何も指定しない場合、ip46@NONEのような名前のデバイスが作られますが、それで問題なかったということです。しかし、dev ip6tnl0やdev eth0を指定した場合でも問題なく動きました。

ローカル側ではencaplimit noneを指定する必要はないようですが、指定した場合でも問題なく動きました。

2台のPCから同時につなぎに行くのは普通にやるとうまくいかないっぽいのでやめたほうが良さそうです。(参照:さくらのVPS で IPv4 over IPv6ルータの構築 | PPT

(トンネル経由で)curlがだめでもpingだけ通ったり、逆にpingがだめでもcurlが通ることがあったりして挙動は全体的に結構謎です。確率的に通らないようなときもあります。おかしいなと思ったら再起動してIPv6アドレスの割り当てを変えたりしばらく待ったりすると治ることもあります。

安定しないときは大人しくTCP/UDP上で動作するVPNとかを使った方がいいかもしれません。