ほとんどの解説では SSTP に関する二つの事実が混同され、その混同こそがキャプチャを分かりにくくしている。アプリケーションのパケットは保護されたチャネルの内側で生き残り、そのチャネルを運ぶ TCP 接続は最後まで自らのアドレスを保つ。回線上を流れるのは運び手とその貨物であり、どちらかの代わりになるものではない。スタックを外側から内側へたどり、越えるたびに各境界に名前を付けよう。

外側の運び手から始める

回線上で最初に現れるのはポート 443 へのごく普通の TCP 接続で、ルーターが転送する実在のアドレスを持つ。まさにこの接続がネットワークアドレス変換を生き延び、アクセス事業者が数えられる対象になる。ペイロードを守っても運び手は消えず、 量やタイミングも隠されない。

この地点より後のすべては、経路制御されるのではなく運ばれる。内側のやり取りが失敗しても運び手は動き続ける。

カプセル化を内側へたどる

保護されたチャネルの内側には SSTP の制御交換があり、次に PPP セッション、次にクライアントが届けたいネットワークパケットがある。各層には独自の交渉、独自のエラーメッセージ、独自の状態機械がある。したがって障害は、ある視点からは TLS の障害に見え、別の視点からは PPP の障害に見える。層を順に読めば、どの状態機械が止まったかが分かる。

一枚のキャプチャがスタック全体を示すことはまれだ。外側のヘッダーは端点の外でしか見えず、内側のヘッダーは非カプセル化の後でしか見えない。その非対称性はプロトコルではなく、あなたがどこに立つかから来る。

下の図は層をまとめたもので、そもそも議論できるようにするためのものだ。バイト配置ではなく、パケットごとに一つのレコードを約束するものでもなく、実装が何回の暗号処理を行うかについても何も語らない。

outer IP header
  TCP to port 443
    TLS record layer
      SSTP control and data packets
        PPP frames
          inner IP packet
            application transport and payload

キャプチャを読む前に観測者に名前を付ける

同じセッションの二枚のキャプチャは異なる問いに答えるが、どちらの問いかは取得したインターフェースが決める。アクセス経路では運び手と TLS レコードが見え、内側のアドレスを見なくてもサイズと間隔を測れる。端点では非カプセル化の後、内側のパケットは私的な転送ポリシーの下の普通のトラフィックである。

解釈する前に、すべてのキャプチャへインターフェースと方向を書く。物理アダプターで取ったトレースが内側アプリケーションのアドレスを通常の外側フィールドとして示すことは決してなく、その不在を暗号化の失敗と読むのはよくある誤りだ。トンネルの内側で取ったトレースは運び手をまったく示さないので、事業者の見え方についての問いには答えられない。同じ規律は端点のログにも当てはまり、そこには内容ではなく交渉の順序が記録される。

図が証明できない確認を残す

層の順序は、配備がサーバー証明書を検証すること、対応する TLS バージョンを交渉すること、アカウントを認可することを示さない。そのどれもがカプセル化とは独立に失敗する設定上の判断である。

図から推論するのではなく、何を交渉したかを報告するクライアントで確認する。TLS ハンドシェイクから始め、次に SSTP の交換、次に PPP と進み、エラーを報告する最初の段階で止める。一つ目のコマンドは連鎖と交渉されたバージョンを出力し、二つ目はキャプチャ内に存在するハンドシェイクを一覧する。

openssl s_client -connect vpn.corp.internal:443 -servername vpn.corp.internal
tshark -r sstp.pcap -Y "tls.handshake.type == 1"

関連記事