もうわれわれはほろ苦い青春の思い出(おそるおそる自宅ルータのポートを開ける・移り気なIPを追いかけてDDNSでドメインを振る・得体の知れない無料VPNに身を委ねる)に悩まされなくていい。なぜならTailscaleがあるから。
以下は知っておけばよかったTailscaleの小技集。
テクニック編
他のデバイスと直接疎通できるか確認する
直接疎通できるまで何度か試行してくれる。疎通できなかった場合、経由したリレーが表示される。
ファイアウォール等でtailnet内からのアクセスを判別する
100.64.0.0/10
からのアクセスは、tailnet内からのアクセスとみなせる1(TailscaleはこのIP範囲から各デバイスにIPを割り振るため)。以下はLAN内とtailnet内のみアクセスを許可する例2。
トラブル編
/etc/resolv.conf
が勝手に書き換えられる
デフォルトの設定では nameserver 100.100.100.100
に書き換えられてしまう。ローカルで別のDNSプロキシを使っているなどの理由で、書き換えてほしくない場合、
とすると回避できる。ただしこのままではMagicDNSの解決が行われないので、お使いのDNSプロキシ等で*.ts.net
の解決を100.100.100.100
に委ねるとよい(以下はctrldの例)。
ホスト名も適当に解決できるようにする。
Tailscaleを使っているとIPv6リンクローカルアドレスが使えない
Linuxで遭遇した現象。Tailscaleの使うインターフェース(例:tailscale0
)に、自動でIPv6リンクローカルアドレスが割り振られ、経路情報にも反映されることが原因だった。ルーティングテーブルを見ると、tailscale0
を経由する経路が優先されてしまっている3のがわかる。
したがって、リンクローカルアドレスが勝手に割り振られないようにすればよい(以下はsystemd-networkdでの例4)。
subnet内の端末でTailscaleを動かすと、経路が冗長になる
これはやや複雑なので前提を整理する。
状況としては、LAN(例:10.10.0.0/24
)内にsubnet router(端末A、10.10.0.2
)を設置し、そのLAN全体をsubnetとして広告している(--advertise-routes=10.10.0.0/24
)場合を考える。
このときsubnet routerの機能により、Tailscaleがインストールされた端末Xは、LAN外にいてもLAN内と同じIPでLAN内の端末B(10.10.0.3
)にアクセスできる。これはXが、Aの広告したtailnet経由の経路情報を受け取っているためである。
問題は、Tailscaleがインストールされた端末がこのLAN内に入った(10.10.0.4
)場合である。この状態でLAN内の端末(10.10.0.3
)と通信すると、tailnetを通る経路情報が通常のLAN内の経路情報より優先されてしまう。その結果、LAN内の端末にアクセスしているのにわざわざtailnetを経由するという奇妙な事態が起きる(参考)。
これを避けるには、LAN内の経路をtailnet経由の経路より優先させる必要がある。公式の解決手順が二つ示されている。
解決策1:subnet routerに/23
で広告させる
かなり野蛮な解決策に見えるが、Windows / MacOS / iOSなどの場合はこれで劇的に解決する5。要するに、よりマスク長の大きい=粒度の細かい経路情報(LAN内の経路情報は/24
、tailnet経由の経路は/23
)が優先されるというシンプルなメカニズムである。
解決策2:より高い優先度のルールを追加(Linux)
Linuxではポリシーベースのルーティングが使われるため、上の解決策ではうまくいかない。代わりにより高い優先度のルールを追加する必要がある。以下はsystemd-networkdでルールを永続化する例である(参照)。
無事まともな経路が選ばれるようになる。
環境依存編
(OpenWRTなど)記憶領域が少ない端末で使う
古いルータなどで不揮発性の記憶領域(フラッシュメモリ)が少ない場合、通常の方法(公式のインストールスクリプト、またはディストリビューションの公式パッケージ)ではTailscaleをインストールできないことがある。このとき、メモリ(RAM)に余裕が十分あれば6、openwrt-tailscale-enablerを使うことで導入できる。
やっていることは単純で、/usr/bin/tailscale
、/usr/bin/tailscaled
が(バイナリの実体ではなく)スクリプトになっている。これが再起動のあと最初に実行されると、最新バージョンのバイナリがメモリ上にダウンロードされ、以後参照されるという仕組みである。実用例は別記事を参照。
(Windows)複数ユーザで使う
Windowsの場合、Tailscaleはユーザ権限で動作する。このため、誰もログインしていない場合(あるいは複数ユーザがログインしている場合)には自動で接続されない。これを避けるため "Run Unattended" モードが用意されている。
脚注
-
ところでこのIP範囲は、ISPがキャリアグレードNAT(?)を行う際に用いるIP範囲でもある。したがってインターネット側と接続されているデバイスの場合、ISPによっては、この判別が厳密に機能しない可能性もある。 ↩
-
「WAN」と書いてあるが、この端末(OpenWRT)は別のルータの配下にぶら下がっているため、WAN側が「LAN内」になる。 ↩
-
二つのルールの優先度は同等なので、起動順によって挙動が変わる。試しにこの状態からTailscaleとsystemd-networkdのデーモンを再起動すると、ルールの順序が替わってリンクローカルアドレスが使える(LAN内のデバイスにアクセスできる)ようになり、問題の所在に気づけた。 ↩
-
KeepConfiguration=yes
というのがミソ。これがないとTailscaleが設定した内容がsystemd-networkdに抹消されてしまう。詳細はマニュアルを参照。 ↩ -
Androidでどうなるかはよくわからないが、たぶん問題ないのだろう。 ↩
-
具体的には27MB以上の空きがあればよいらしい。 ↩