tun0 と VPN プロトコルを一つのものとして扱うと、人は誤ったログへと向かう。インターフェースはローカルな境界であり、ユーザー空間のプログラムがカーネルと IP パケットをやり取りする場所である。プロトコルとは、パケットを受け取った後にそのプログラムが行う処理であり、トランスポート、認証、暗号化、そして対向ピアである。デバイスを作成しても、そのどれも選ばれない。

二つの構成要素、一つのパケット経路

カーネルは IP パケットをデバイスに書き込み、プログラムはファイルディスクリプタからそれを読み取る。逆方向では、プログラムがパケットを書き戻し、カーネルは実際のインターフェースに到着したかのようにそれをルーティングする。TUN は IP を運び、TAP はイーサネットフレームを運ぶ。その境界でパケットを読むとフレーミングが見え、デバイスはまさにそのためにある。

その境界より先のすべてはプログラムの仕事である。二つのプログラムが同じインターフェースの概念を使い、パケットに対してまったく異なることをしてもよい。デバイス自体は、次に何が起きるかについて意見を持たない。ファイルディスクリプタは、プログラムがカーネル側に対して持つ唯一の取っ手である。

デバイスを作成し、そのうえで境界を観察する

境界を試すときは、意図的にデバイスを作成する。永続デバイスはそれを作成したプロセスの終了後も残るため、実験には便利であり、後になって混乱の一般的な原因にもなる。VPN を責める前に、フラグと所有者を確認する。

sudo ip tuntap add dev tun9 mode tun user alice
ip -d link show tun9

リンクの詳細はデバイスの種類と、結び付いている所有者を示す。どのプロセスもそれを開いていなければ、書き込まれたパケットはどこにも行かない。プロセスが結び付いていないデバイスは、リンク一覧では健全に見えても何も通していないことがある。

インターフェース名が約束できないこと

インターフェース名は暗号化や認証について何も語らない。プログラムはパケットを TLS に包んでも、独自プロトコルに包んでも、IPsec に包んでも、何にも包まなくてもよい。TAP ではなく TUN を選ぶことは境界でのフレーミングを変えるだけで、セキュリティ設計を変えるわけではない。フレーミングの選択は現実のものであり、セキュリティの問いよりはるかに小さい。

検出も同じように働く。観測者が見るのは回線上の外側のプロトコルであり、どのローカルデバイスが生成したかを示すラベルではない。別のものに見えるトンネルがそう見えるのは外側のプロトコルのためであり、インターフェース名のためではない。観測者にはどのローカルデバイスがパケットを生成したかは見えずパケットの見え方だけが見えるため、製品を比較するときはこの二つの問いを切り離し、一方の答えがもう一方を意味しないことを忘れない。

修正を失敗している段階に合わせる

何かが壊れたときは、失敗の段階を分けて考える。デバイスの不在、権限のエラー、拒否されたログインは、それぞれ異なる証拠と異なる修正をもたらす。まずローカルの状態を読み、次にプログラム自身のログを読み、最後に対向ピアの見方を読む。何かを変える前に三つすべてを読む。

ip -d link show tun0
journalctl -u openvpn-client@corp --since '10 min ago'

デバイスが存在し、プロセスがそれを保持していれば、ローカルな境界は機能しており、問題はさらに外側にある。デバイスがなければ、どれほど資格情報を確認しても役に立たない。名前を付けられる段階は、試験できる段階である。TUN/TAP のドキュメントは境界とデバイスモデルを説明している。

関連記事