(題は微妙に違うかも。題と「毒を喰らわば−」と「背に腹は−」を足して3で割った感じかw)
先日の、IPv4(以下v4)だけがネットに繋がらなくなったトラブルの予防的対処のため、仕方なく、IPv6(以下v6)が使えるところは使って行くことにした。
いや、僕はそんな仕様はどっちでも良くて、そもそも「アドレス枯渇する・した」とか「遅いからv6にする」なんてのがおかしいと思って居るので、積極的にIPv6を使う気持ちはさらさらなかったのだが、ああいうトラブルがあると、さすがに全面移行とまでは行かないが、代替手段を用意して可用性を高めておく必要性を痛感したのだ。※ それが無料(自分の時間は別)で実現できるし、各アプリ・プロセスの通信速度が向上・安定する可能性がある(といっても、IPoEにしてから全体でも個々でも速度が遅いと感じたことはほとんどないが)から、まあ悪い話ではない。
※そもそも、可用性を高めることが必要なことをしているかどうかは別でw、「気分の問題」であろう。
それで、まずは、自分のサーバから始めた。サーバは、プロバイダがv6対応の環境で提供してくれていて、OSも対応しているので、設定すれば使える状態だったが、面倒なので今までは有効にしていなかった。
最初にサーバのv6関係の設定をした。普通にできて、デスクトップPCからpingが通った(v6のアドレスを直接指定した)。試しにwebサーバにアクセスしてみたが、通らなかった。Webサーバの設定をしていないので、v6では接続を受け付けていないためだ。
次に、設定を誤ると面倒なことになるwebサーバの、比較的単純な部分をv6対応の設定にした。試しにブラウザからv6のアドレスでアクセスしたら、例によって「怪しいサーバです。これ以上は駄目よんw」みたいなのが返って来て(HTTPSでSSL証明書がおかしいため)、めでたく繋がった。
それからDNSサーバにv6用のホスト名(サブドメイン)を登録した。今はv4とv6のホスト名を共通化する(同じ名前で両方に対応)のが一般的だろうが、予期できないさまざまな問題が起こりそうだったので(実際に問題は起こった(後述))、ひとまず別にした。作業としては、v6用のサブドメインにAAAAレコードだけを設定した。設定してから数分で反映され、ホスト名の検索(nslookupコマンドなど)に出るようになった。
次に、HTTPSをちゃんと使えるようにするために、Let's EncryptのSSL証明書にv6用のサブドメインを追加した。証明書の生成時にサーバの設定の調整が必要だった。証明書を作る時には、確認のためそのサーバにアクセスされるのだが、それを忘れていてwebサーバはHTTPSだけ有効にしていたが、真っ当な証明書(これを作ろうとしている!)がないのでアクセスされず、HTTP接続しようとして失敗した。それで、仕方なくHTTPも有効にして、無事(でもないけど)作れた。新しい証明書を作ってからブラウザでアクセスしてみたら、ちゃんと"404 Not found"が返って来た。
設定が複雑なので間違うと面倒なことになるブログは落ち着いてからにすることにして、まずは、普通のweb(BNoteを含む)とDAV(カレンダー・アドレス帳やJoplinで使っている)をv6対応にすることにした。とは言え、webサーバに関しては証明書を作るために調整してほとんど出来ているので、DAVサーバやクライアントアプリなどの設定変更や追加がほとんどだった。クライアント側の機器やアプリが多いので手間は掛かったものの、ほとんど問題なく終わり、ちゃんとv6でアクセスできるようになった。
とりあえずできたので、しばらく使って問題がないかをチェックすることにした。使っているうちに、以前から気になって居た、v6のプライバシーの問題※の解決策が見付かった。デスクトップPC(Linux)のv6の設定に、"IPv6 privacy extensions"というものがあるのに気付き、調べてみたら、僕の懸念を解消できそうなものだった。
※IPv6のアドレスは全世界でユニーク(かつ、不変なものもある)なので、そのクライアント(PCなど)からアクセスしている個人の特定や追跡が容易そうだという僕の懸念。
その機能を有効にし、モードを"Prefer temp. addr."にしたら、PCのv6のアドレスが増えた。今までのもの(通常のグローバルアドレス)に加え、一時アドレスが表示されている。このアドレスは通常のアドレスより秘匿性(?)が高いらしく、また、定期的に(1日-1週間のようだ※)変わるので、個人の特定や追跡が困難になるとのことだ。
※設定後1日経った今現在でもアドレスが変わっていないので、しばらくは観察する必要がありそうだ。 → 忘れると嫌なので、愛用のcrontabで自動チェックするようにした。
→ (12/2 19:35) 昨日くらいからアドレスが変わるようになった。大体30時間で変わった。設定変更後、OSの再起動またはNW IFの切断と再接続が必要だったようだ。
ただ、これには欠点もある。アドレスがコロコロ変わるので、僕がサーバのログを見て、本当に自分でアクセスしたのか分からないということだ。でもまあ、他の情報から判別できるし、プライバシーの問題の方が重要なので、Privacy extensionsを使うことにした。
一方、Androidはその点はどうなのかと調べたら、結果的には問題なさそうだ。rootになれないのでprivacy extensionsを有効にしたりすることはできないが、挙動を調べたら、v6アドレスが結構頻繁に変化することが分かった。
そもそも、Androidスマフォには2つ(以上)のv6アドレスがある。モバイル(LTE)とWi-Fiである。モバイルは、詳しいタイミングは分からないが、基地局に接続するたび(基地局が変わるたび?)に変わるようだ(機内モードをon/offした前後でアドレスが変わっていた)。Wi-Fiも同様に、APに接続するたびに変わる。
だから、僕の観察が間違っていなければ、Androidに関しても、v6で概ね問題なさそうだということになった。
なお、僕のスマフォ(AQUOS sense lite)はAPN登録時にはv6は無効になっていたが、APN設定でv4/v6のモードに切り替えたら、v6が使えるようになった。MVNOの場合、プロバイダによってはv6が使えないことがあるらしいが、僕は(IIJが下回りらしい)イオンモバイルで、全く問題なく使えた。
随分調子良かったので、このあともこの調子でスルッと行くかと思って気を良くして居たが、やっぱり、そうは問屋が卸してくれなかった。問屋というのは そんなに厳しいのだろうか?w 作業面での手間はなかったが、原因不明で解決が難しそうな問題が残っている。
切っ掛けは、欲を出して早くも(サブ)ドメインをv4/v6両用にしたくなって、v6用に作ったものをそうしてみたところ、一見うまく動いているのだが、Joplinだけがおかしかったことだ。本来の動作は全く問題ないのだが、なぜかサーバのv4のアドレスにアクセスしてしまうのだ。PCのOS(Linux)のv4とv6の優先順位がおかしいせいだろうと考えて、いろいろ調べて調整しても、結局直らなかった。
それで、Joplinのフォーラムに質問を出しつつ、更にJoplinのソースなどを調べたら、確定はできないが、どうやらJoplinの下回りのNode.jsのnode-fetchという通信用モジュールの仕様(または「現状」)によるのではないかと推測している。というのはnode-fetchのcustom agentオプションのうち、v4とv6の切り替えに関係するfamilyは、socket.connectによって以下のように規定されている。
family <number>: Version of IP stack. Must be 4, 6, or 0. The value 0 indicates that both IPv4 and IPv6 addresses are allowed. Default: 0.
字義通り解釈すれば、デフォルトの0で、v4/v6どちらも使える場合に、どちらが使われるか不明(不定)だ。※ 「普通」ならOSの優先順位(Linuxではv6が優先)と同じになると期待するが、実際の動作はそうではない。もちろん、Joplinに「v4優先」という意思や仕様があれば別だが、そうする理由は全くない。また、familyには優先順位が指定できないので、「v4優先」を実装するのは面倒だ。
※Node.jsのそこのソースを読めば分かるだろうが、なかなか面倒だ。一体、Joplinから何階層下がらせるつもりだ!?w
そこで想像してみると、OSまたはシステムコールまたはライブラリからホスト名に対応するIPアドレス一覧を得たあと、familyが0以外ならv4かv6でフィルタリングする。そして、残ったものを使う。複数あっても気にせず、「最初の1個」を使うのだろう。
結局、OSなどからどういうふうにIPアドレス一覧が来るかが問題だ。どうも、単にソートされているだけのような気がする。その場合、v4が先に来る可能性が高そうだ。 (まあ、余計なこと考えてないで、実物を読めば速いのだがw)
(11/29 0:01) 書いた後で更に調査・実験して、ほぼ原因が分かった。Node.jsのDNSモジュールのdns.lookupという関数は、ホスト名からIPアドレスを取得する(これをnode-fetchが使っているかは未確認だが、おそらく使っていると思う)。そのデフォルトの動作はDNSリゾルバの結果をv4のアドレスをv6より先に並べ替えて出すため、Joplinはv4/v6両用ホストに対しては(Linuxの標準・通常動作とは逆に)v4のアドレスにアクセスする。参考のため、dns.lookupの設定を行うオプションverbatimの説明を引用する。
verbatim <boolean> When true, the callback receives IPv4 and IPv6 addresses in the order the DNS resolver returned them. When false, IPv4 addresses are placed before IPv6 addresses. Default: currently false (addresses are reordered) but this is expected to change in the not too distant future. New code should use { verbatim: true }.
確認のため、簡単なプログラム(→ 参照: そのページ下部の"Live Demo"から開けるOnline Node Compilerが便利。ただし、そこではDNS検索は失敗してしまう)で、dns.lookupをv4/v6両用ドメインに対して実行したら、本当にv4アドレスが返って来た。そして、オプションを追加してverbatimをtrueにして実行したらv6アドレスが返って来た。。。
どういう理由か知らない(IPv6の実装が今一つだった頃からの経緯?)が、折角OSが苦労して(そのうえ、ユーザから文句を言われたであろう: 例)RFCに準拠して並べ替えたIPアドレスを、ライブラリごときが勝手に並べ替えてしまうなんて、余計なお世話もいいとこだ! 上の説明に「近い将来は逆になる」と書いてあるが、現行版ですらこの勝手な動作なので、当面は直りそうにない。ということは、Joplinの問題も直りそうにない。
直すとすれば、自分でNode.jsに手を入れることだろうが、そもそもビルド環境を作るのが面倒だ。更に、Node.jsは結構更新されそうなので、僕の修正を残すようにするのが難しい(でも、できれば爽快だろうな・・・)。
(11/29 12:57) 直し方を検討したが、「まあ不可能」という結論になった。まず、dns.lookup(DNSモジュール)はNodeに埋め込まれている(コンパイルされているようなので、パッチはまずできない。さらに、NodeはJoplinに埋め込まれている)ので、Node(この場合、Joplinも)をビルドし直さない限り入れ替えられない。
次に、dns.lookupは最終的にはLinuxのgetaddrinfo()を呼ぶが、これはlibcまたはlibnssに入っているようで(未確認)、どちらも大変基本的なライブラリなので安易には改造できない。うまくしてライブラリとNodeの間に割り込めばいいが、さすがに、いくら暇でもクソのためにそんな面倒なことはやってられない。
ってことで、気に入らないけど我慢するのがベストだ。
てな訳で、別に大きな問題ではないが、喉に魚の小骨が刺さったような気持ち悪さが残っている。しかし、そもそも論とか現実問題としては全く問題ない。というのは、最初に書いたように、v4が使えなくなった時の代替手段が欲しかった。そして、この仕様では、v4が駄目になったら自動でv6に切り替わる(正確には、アクセスする時に、生きているであろうv6が使われる)はずだからだ。
が、通信速度の向上・安定化とか、前回書いた、JPNEのMAP-Eのv4のポート数の上限の問題も改善したいという欲があるので、気に入らない。それで、今は、v6用に作ったドメインをやっぱりv6専用に戻して使っている(他の方にすれば「は?」って感じだろう)。
まあ、(気分は悪いが、)自分用サーバはv6専用でも何も問題ないから、このままでもいいかという気はしている。一つだけ問題が起こる可能性としては、何らかのトラブルでv6だけ通らなくなった場合にアクセスできなくなることだ(そんなことが本当に起こるのか、検討の余地はあるw ただ、ルータ故障時にv6非対応の物に交換したらそうなる)。その時はv4/v6両用の方がいい。ということは、そもそも論で言えば、v4/v6両用にして、Joplin(と他のNode.jsのアプリ?)だけはv4でも見逃すべきなのだろう。もう少し考えよう。
→ 全体的には、しばらくv6用ドメインで試して問題なければ、基本ドメインをv4/v6両用に変更し、v6用ドメインに換えた自分用サーバを使っているアプリの宛先をそっちに戻すのが一番美しそうだ。多くのアプリの設定を戻すのは手間だが、これなら、v6用ドメインは本当にv6用で筋がとおるし、基本ドメインはv4/v6両用で今風になるし、可用性も高まるから、いいことづくめだ。 (本当に?w)
それから、Joplinと似たような問題がEvolution(メーラー)でも起こった。通常時はv6をアクセスするのだが、スリープからの復帰後にv4に戻ってしまうのだ。どうやら、Linuxの動作なのだろうが、復帰時にv6が使えるようになるのが少し遅れるようで、※その関係で先に使えるようになったv4にアクセスしてしまうようだ。
※推測だが、v6の初期化の処理が多いために遅くなるのかも知れない。確かに、普通の処理(v6アドレスの取得・調整?)ですら重そうだし、上に書いたPrivacy extensionsは複雑そうだ。そういう処理はv4には全くないので、時間差ができても不思議はない。
それで、効果確認中だが、Evolutionのネットの設定の"Method to detect online state"を"Always online"にして試している(今まではNet Managerから取得するようにしていた)。これは他の普通のアプリと同じ動作(ネットの状態には関知しない)と考えられるから、一旦v6にアクセスしたら、そのまま使い続けることが期待できる。気になるのは起動時で、その時にv4だったら嫌だから、ログイン時の自動起動では数秒送らせて起動するようにした(ログイン時はスリープと違ってOSは普通に起動しているので、必要ない気もするが・・・)。
最後に、v6化した効果というのか、v4のポート数の削減率を調べたところ、当然ながらあった。僕のサーバ以外にもv6対応のサーバ・サイト(例: メールサーバ)があるため、アイドル時(例: Webブラウズしていない時)のv4のポート数が半分くらいに減り、その分がv6になった。以下に例を示す。
デスクトップPCで使っているTCPの全ポート数
デスクトップPCで使っているTCPのポート数(自分用サーバとプロバイダのメールサーバ宛のもの)
v6を使わない場合に比べ、v4率は、全ポートでは約27-50%減少し、自分用サーバなどに関しては約40-77%減少した。
とはいえ、もちろん、「Webの表示やJoplinの同期が倍速になった!」とかいうことは全くないw
という訳で、少し前までは使いたくもなかったIPv6を頼まれてもいないのにゴリゴリ使うことになって、いつものように疲れたでござるw