要約
- SOCKS5の
UDP ASSOCIATEは、方式交渉を終えたTCP接続上で中継状態を作り、そのTCP接続が終わると同時に状態を失効させた。TCPが与えたのは寿命であり、UDPデータの信頼性ではない。 - サーバーが返す中継先、期待されるクライアントIP、各データグラム内の遠隔宛先、選択済み認証方式、断片再構成は別々の判断だった。どれも単独では利用者や最終配送を証明しない。
UDPの沈黙には一つの意味がなかった
中継にデータグラムが来なくなったとき、クライアントが終了したとは限らない。アプリケーションが静かなだけかもしれず、経路が切れた可能性もある。反対に、パケットが来続けていても、最初に認証されたプロセスが送っているとは限らない。
そこでRFC 1928は、UDP自身に存在しない終了の意味をTCPから借りた。UDP ASSOCIATE要求を受け取ったTCP接続が終了すれば、UDP associationも終了する。中継ポートに後続パケットが到着しても、それだけで過去の許可は延長されない。
これはUDPをTCPへ載せる方式ではない。業務データは引き続き個別のUDPデータグラムであり、損失、重複、順序逆転は残る。TCPは方式選択と状態生成を運び、その生存がローカルな制御文脈の寿命を示した。
設計の価値は小ささにある。無接続の転送に観測可能な開始と終了を与えながら、ストリームの配送保証まで発明しなかった。
最初のデータグラムより前に三段階があった
クライアントはTCPで利用可能な認証方式を提示し、サーバーが一つを選び、その方式固有の交換を終える。その後に初めてCONNECT、BIND、UDP ASSOCIATEのいずれかを要求できた。
UDP ASSOCIATE要求には、クライアントがUDP送信に使う予定のアドレスとポートを入れられる。サーバーはそれをassociationの制限に利用できる。まだ値を知らないクライアントは両方をゼロにする必要があった。
ゼロは「誰でも使用可」ではない。要求側が具体的な送信元を提示できないというだけであり、サーバーは接続や観測、ローカルポリシーから有効な送信元を定めなければならない。
成功応答のBND.ADDRとBND.PORTは、クライアントがSOCKS UDP要求を送る中継入口を示す。複数インターフェースを持つサーバーなら、TCPで到達したアドレスと異なる値を返し得る。この値は最終宛先の名前ではない。
一つのassociationに複数の宛先が入った
クライアントから中継への各データグラムは、予約フィールド、FRAG、アドレス種別、宛先アドレス、宛先ポート、データを持つ。遠隔宛先はassociation全体ではなく、個々の封筒に記載された。
したがって、中継は透明な管ではない。データグラムごとに宛先を読み、ポリシーを適用し、SOCKSヘッダーを外して送る。遠隔ホストから返信が来れば、同じ文法で送信元を包み直してクライアントへ渡す。
ここで三つのアドレスを区別する必要がある。TCP制御接続で使ったサーバーアドレス、サーバーが返したUDP中継入口、そして各封筒の遠隔宛先である。「プロキシのアドレス」一つだけを記録すると、どの判断が失敗したかが消える。
中継がデータグラムを受け入れたことも、遠隔アプリケーションが処理したことの証明ではない。ローカル送信、経路配送、遠隔受信、業務結果にはそれぞれ別の証人がいる。
送信元IPの一致は本人確認ではなかった
RFC 1928は、UDP relayがSOCKS serverから期待するクライアントIPを取得し、それ以外の送信元から届いたデータグラムを黙って捨てるよう要求した。別アドレスの第三者が既存associationへ流量を注入するのを抑える境界である。
ただし、IPアドレスは人でもプロセスでもない。NATの背後で多数が共有し、移動で変化し、同一ホスト上の別プログラムも利用できる。比較できるのは中継で観測した送信元と保存値だけだ。
認証は先行する方式交渉が担った。RFC 1929のusername/password方式は資格情報をサブネゴシエーション中に平文で運び、盗聴可能な環境での利用を推奨しない。RFC 1961のGSS-API方式は、認証に加えてメッセージ完全性と任意の秘匿性を交渉できた。
同じSOCKS5という表示でも、選択方式によって根拠は異なる。方式名、実際の保護レベル、保護対象範囲を保存しない監視は、プロトコル番号をセキュリティ証明にすり替える。
FRAGは任意実装の短い記憶だった
SOCKS UDPヘッダーでFRAG=0は、そのデータグラムが独立していることを意味する。1から127は断片順序を表し、上位ビットが最終断片を示す。これはIPのFragment Offsetではなく、中継文法の内部状態である。
断片対応は必須ではなかった。非対応実装は、ゼロ以外のFRAGを持つデータグラムを捨てなければならない。対応実装はreassembly queueとtimerを持ち、期限切れなら断片を放棄する。処理済み最大値より小さい番号が新たに来た場合もqueueを初期化する。timerは5秒未満にできず、仕様は可能な限り断片化を避けるよう勧めた。
ここにACKや再送保証はない。完成したqueueは次の送信を可能にするだけであり、配送完了書ではない。不完全な状態を有限時間で捨てること自体が、無制限な記憶を拒む設計だった。
障害分析では、送信元不一致、FRAG非対応、順序後退、期限切れ、宛先ポリシー拒否、外向き送信後の損失を別々に数える必要がある。すべてを「UDP失敗」に畳むと、修正主体まで分からなくなる。
TCP終了は孤立した権限を残さなかった
トラフィックがある間だけassociationを残す案は、知っている中継ポートへパケットを送れる者に事実上の更新権を与える。idle timeoutだけに任せる案は、静かな正規利用と死んだクライアントを区別できない。
TCP制御接続は完全な真実ではないが、サーバー自身が作成、監視、終了できる状態である。そこへ方式結果とUDP entryを結び付け、接続消失時に失効させれば、曖昧さのコストは新規交渉へ戻る。
短いTCP障害が正常なUDPを止めること、移動時にsource bindingも壊れること、制御socketが資源を消費することは現実の負担である。しかし境界はテスト可能で、再接続によって回復できる。誰が送ったか分からないパケットで許可を延命するより、責任の所在が明確だった。
IPv4とIPv6の橋もアプリケーション層に留まった
2001年のInformational文書RFC 3089は、SOCKSをIPv6/IPv4 gatewayに使う方法を記した。両側の通信をアプリケーション層で終端し、dual-stack gatewayへ名前解決を委譲することで、IPv6アドレスを格納できない古いアプリケーションも異なるアドレス族へ到達できた。
この利用はCONNECT、BIND、UDP ASSOCIATEを継承したが、SOCKSをIP routerにはしなかった。要求名、解決結果、制御association、転送データは区別されたままである。
歴史的な教訓は、中央中継に万能の権限を与えることではない。共通仕様は検証可能な最小文法を定め、実行判断は各中継に残し、その結果を隣の層へ勝手に拡張しない。動いているコードの権限は、観測できる境界までである。
出典
会員向け解説
プロフィールの詳細
適切な会員レベルでログインすると、解説全文と出典メモをご覧いただけます。
Strategic Circle 限定
Strategic Circle
すべての読者に公開されています。参加してログインすると プロフィール解説 を閲覧できます。
Strategic Circle に参加Leadership Alliance 会員限定
Leadership Alliance
対象となる IP 資産の所有者・管理者向けです。ログインすると Leadership Alliance の解説を閲覧できます。
Leadership Alliance に参加
