雑記: 動的ポートフォワードする話

お気付きの点がありましたらご指摘いただけますと幸いです。

わたしの端末は Windows 10 です。わたしは特定のリモートマシンからしかアクセスすることができない Web サイトにアクセスしたいことがあると思います。端末に Git for Windows をインストールしていて Git Bush が利用できる場合、そこで ssh と打ってみると ssh コマンドが入っていることがわかります。

$ ssh -V
OpenSSH_8.7p1, OpenSSL 1.1.1k  25 Mar 2021

ssh コマンドが何かわからないのでマニュアル [1] を読むと、例えば ssh user@hostname でリモートマシンにログインすることができるようです。何でもこのとき指定された方法のうちいずれかで自分が怪しい者ではないことを証明しなければならないようです(The user must prove their identity ... / The methods available for authentication are: ...)。もっともだと思います。以下では公開鍵認証を使用します。公開鍵認証とは秘密鍵をもつわたしだけが「この値はわたしの公開鍵で『りんご』を変換したものですね?」と当てられるというあれだと思います。ともかく ssh コマンドとはリモートマシンにログインしてリモートマシンでコマンドを実行するものであるとあります。

というわけで以下のコマンドでリモートマシン hoge.fuga.jp に接続します。リモートマシンにはあらかじめわたしの公開鍵を登録していてそれに対応する手元の秘密鍵を -i で指定しています。

$ ssh -i ~/.ssh/id_rsa_hogefuga -D localhost:1080 -v remote_username@hoge.fuga.jp
(略)
debug1: Local connections to localhost:1080 forwarded to remote address socks:0
(略)

ここで -D localhost:1080 の部分は「わたしの端末の 1080 番ポートにデータを送受信するとリモートマシン hoge.fuga.jp にデータを送受信するようにせよ」という意味になります。1080 番でなくてもいいです。この機能を動的ポートフォワードというようです。何が動的なのかというと、リモートマシンのポート番号まで指定して接続するローカルポートフォワード(-L)と違い、動的ポートフォワードではわたしの端末の 1080 番ポートに送受信したデータをみて ssh さんがリモートマシンの適切な窓口(ポート番号)によしなにつないでくれるので、一回の接続の確立で HTTP, HTTPS, FTP などの色々な流儀の通信ができるということのようです [1] [2]。このときローカル 1080 番への通信自体は SOCKS という流儀でラップしなければならないようです。

それでやりたかったことはリモートマシン hoge.fuga.jp からしかアクセスできないサイトにわたしの端末からアクセスすることでした。上記の ssh コマンドでやったことはわたしの端末の 1080 番ポートへの送受信をリモートマシン hoge.fuga.jp への送受信にしただけなので、別途「わたしの端末でインターネットとデータを送受信しようとするとき、特定のサイトであったらわたしの PC の1080番ポートに SOCKS で送受信せよ」とわたしの端末に対して命令しなければなりません。これは自動構成スクリプト(PAC)という JavaScript で記述したファイルを適宜設定することで実現できます [3] [4] [5]。ただしこのファイルは Web サーバ上に配置してそのアドレスを指定しなければならないという制約があり(Windows 10 では)、適当な Web サーバをもたないわたしは仕方ないのでこのファイルを配置したディレクトリに Python で Web サーバをたてて設定画面から以下のように設定しました。

function FindProxyForURL(url, host) {
  if (dnsDomainIs(host, "example.co.jp")) {
    return "SOCKS5 localhost:1080; DIRECT";  // SOCKS サーバが利用できなければ直接接続
  }
  return "DIRECT";
}

$ python -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

f:id:cookie-box:20211102122253p:plain

これで Web ブラウザ(少なくとも Chrome)から目的のサイトにアクセスできます。以下は細かい話です。

  • PAC ファイルの設定内容を変更したいとき、PAC ファイルを編集しただけではただちに変更が反映されません(ローカル 8080 に通信がきません)。設定画面の「セットアップ スクリプトを使う」を一度 OFF にて再度 ON にし「保存」をクリックするとローカル 8080 に通信がきて反映されるようです。
  • PAC ファイルに alert を仕込んでデバッグしようとしても期待通りに alert ダイアログは出ないので、特定のサイトが SOCKS プロキシされているかどうかみるだけなら ssh コマンドを -v オプション付きで実行してアクセス時にコンソールにログが流れるかをみるのがいいと思います。
    • alert メッセージでデバッグしたい場合は、chrome://net-export/ にアクセスし、そこの指示にしたがって一定期間ログを吐き出し、そのログを netlog viewer に読み込んで Events タグから Description 列が PAC_JAVASCRIPT_ALERT の行をクリックすればメッセージがみれます。日本語は文字化けします。

ちなみにわたしはこの手順で目的のサイトに到達したものの、そこに自分のほしい情報がなかったということがわかりました。