
macOS同士(Apple Silicon)のマシンをTailscale
でつないでいます。
Eternal Terminal
(GitHub: MisterTea/EternalTerminal
)で接続しようとすると、Receiving client id から進まない沼にハマりました。
結論から言うと、この記事の時点では完全解決していません。 ただ、観測できた挙動と切り分けの手順を整理すると「どこが壊れていそうか」をかなり狭められます。ムダに時間を溶かさず、次のアクションへ進むための記事です。
本文中のホスト名とIPはダミー化しています(例: server, 100.64.0.10)。
最短チェック(ここだけで8割切り分け)
まずは以下だけ確認すると、問題の層をかなり絞れます。
| |
症状(何が起きているか)
自分の環境では、同じホストに対して以下の差が出ました。
[SSH](/tags/SSH/)は通る:ssh serverは成功する- Eternal Terminal は通らない:
et serverがReceiving client idのまま止まり、だいたい30秒でConnect timeout
「SSHでログインできるならETもいけるはず」なのに詰まるのが、精神的に一番きついポイントです。
環境
この記事の再現条件は、だいたい以下です。
- クライアント/サーバともに macOS (Apple Silicon)
- 経路はTailscale
- サーバホスト名(ダミー):
server - サーバのTailscale IP(ダミー):
100.64.0.10 - Eternal Terminal: Homebrew版
6.2.11 - ETのデフォルト待受ポート:
2022
なお、Tailscaleのセキュリティ観点の話は別記事「Tailsnitch: Tailscaleの通信を監査する(macOS) 」にまとめています(この記事では接続不具合の切り分けに集中します)。
環境差分になりやすい点(チェック項目)
自分は今回ここまで深掘りできていません。読者が自分の環境と差分を見つけるためのメモです。
- Tailscale側のACLで
2022/tcpを絞っていないか - macOS側のファイアウォール(アプリ/ポート)で受信が落ちていないか
tailscale serve/tailscale funnelを有効化していないか- Tailscale SSH(
tailscale ssh)の有効/無効で挙動が変わらないか
まず潰すべき前提(ETが依存しているもの)
Eternal Terminalは内部的にSSHを使います。なので最低限、次が成立している必要があります。
- クライアントからサーバへSSHできる(認証も含めて)
- クライアントからサーバの
2022/tcp(または設定したポート)へ到達できる - サーバ側で
etserverが起動していて、待受できている
このうち 1 は「ssh server が成功する」でOKです。残りを順に切り分けます。
切り分け1: 2022/tcp に到達できるか(疎通の最小確認)
まずは「ポート到達性」だけを見ます。成功しても解決ではありませんが、失敗するなら話が早いです。
| |
自分の環境では、ここが成功するケースがありました。つまり「SYNすら届かない」タイプではなさそう、というところまで絞れます。
切り分け2: etserver が本当にLISTENしているか
launchd等で起動しているつもりでも、落ちていたり、別のアドレスにしかbindしていないことがあります。LISTEN の事実をまず確認します。
| |
出力が空なら、少なくともその時点では待受していません。etserver の起動方法(launchd / 手動起動)と設定ファイル(通常 /etc/et.cfg)を見直します。
切り分け3: localhost では通るのか(経路要因の切り分け)
Tailscale経由が怪しいのか、ETそのものが怪しいのかを分けるために、サーバ server 上で自己接続してみます。
| |
自分の環境では、localhostでは acceptNewConnection accepted client-fd=... 的なログに進むケースがありました(後述)。
この差が出るなら、少なくとも「ETが常に壊れている」より「macOS + Tailscale 経路での相性」っぽさが増します。
upstream issue調査(決定打はなし)
Eternal Terminal側の既知の不具合・近い症状を探しましたが、今回の「Receiving client id から進まず Connect timeout」に刺さる決定打は見つけられませんでした。
(状況が近い人はいるものの、再現条件や原因がピン留めされていない、という印象です)
ソースコードを当たって分かったこと(観測ベース)
ここから先は「推測」ではなく「この環境で観測できた挙動」を中心に書きます。
調査で追いかけた主なファイルは以下です。
SshSetupHandler.cppTerminalClient.cppServerConnection.cppUnixSocketHandler.cppTerminalServer.cpp
追加ログを入れて観測すると、サーバプロセス(etserver)自体は生きていて main loop も回り続けます。一方で、クライアント接続に関連する部分で詰まるケースが多いです。
自分の環境での典型パターンは、ざっくりこうでした。
- FIFO(名前付きパイプ。プロセス間通信の仕組み)側の処理は
addClientKeyまで完了する(つまり「途中までは進む」) - ただし、Tailscale経由だと
accept()がEAGAIN(errno=35)を返し続け、clientHandler()に進まないことが多い
accept() は「待受ソケットに来た接続を取り出す」システムコールです。EAGAIN は「今はacceptできる接続がない」なので、単発なら普通です。ただ「接続を試みているのに、ずっと EAGAIN を踏み続ける」状態になるのがポイントで、イベント通知/ソケット状態/経路のどこかで期待が外れている気配があります。
tcpdumpで見えたこと(見えなかったこと)
パケットがどうなっているかを見るため、tcpdump も試しました。
macOSの場合、Tailscaleのインターフェースは utunX になっていることが多いです(utun0 とは限りません)。まずは自分の環境の utunX を特定してから実行してください。
| |
localhost比較をするときは、ループバックで見ます。
| |
ncでの疎通確認は、SYN→SYN-ACK→ACK→FINが素直に見える- しかしET本番のハンドシェイクは、期待するほど明確な流れが取れないケースがあった
自分の理解では、これは「ETが内部で複数の段階を踏む」「アプリ層で詰まっていると、TCPとしては何も起きていないように見える」など、いくつか解釈があり得ます。少なくとも「nc はOKだからネットワークは完全に無罪」とは言い切れません。
Tailscale側で試したこと(効果なし)
Tailscale側の設定が絡んでいる可能性を疑い、以下を試しましたが改善しませんでした。
| |
また、ETの設定で bind_ip = 100.64.0.10 を試す(Tailscale IPに明示bindする)も効果なしでした。
このあたりまでやって改善しないなら、少なくとも「serve/funnelの残骸」や「bindアドレスの取り違え」みたいな分かりやすい地雷ではなさそうです。
結論(現時点)
現時点の結論は、以下です。
- Eternal Terminalと「macOS + Tailscale 経路」の相性問題の可能性が高い
- 恒久修正(原因の特定とパッチ適用)までは到達していない
同じ沼にハマった場合は、この記事の切り分けで「SSHはOK」「2022/tcp到達性は(場合によって)OK」「localhostだと動くことがある」「Tailscale経由でacceptループが不自然」という形まで持っていけると、次の打ち手が選びやすくなります。
代替案(今すぐ作業を進める)
自分は当面、ETを諦めて ssh + tmux に寄せました。作業を止めないのが最優先です。
tmuxセッションを再利用する形なら、体験としてはETにかなり近づけられます。
| |
もし許容できるなら、moshも候補になります(ただし環境によっては別のハマりポイントがあります)。mosh絡みの別の罠は「moshでOSC52クリップボードが壊れるときの対処 」に書きました。
次にやるなら(再現条件を固めてupstreamへ渡す)
完全解決に向けて次にやるなら、優先度はこの順が良さそうです。
- Tailscaleを使わない経路(LAN直、WireGuard直、IPv6直など)と比較し、差分を固定する
- ホスト名解決をいじらずに、
/etc/hostsやローカルトンネル等で「Tailscale IPを使わない形」を試し、回避できるかを見る - upstreamへ再現条件とログを共有する(
accept()がEAGAINで回り続ける点、localhostとの差、macOS/Apple Silicon、ET 6.2.11、Tailscale IP帯など)
この記事の観測が、どなたかの再現・修正の足がかりになればうれしいです。
まとめ
sshが通っても、etがReceiving client idで止まるケースはありましたncが成功しても、ETの接続確立を保証するものではありません(今回の症状では特に)- 観測上は、Tailscale経由で
accept()が進まず、サーバが応答フェーズに入れない可能性が高そうでした - 作業を止めない目的なら、まずは
ssh + tmuxへ退避するのが現実的です