備忘録的小ネタ。
動機
- ネットワーク的に制限されている社内基盤のAPIを利用するプログラムを書いているが、オフィスのネットワークからじゃ直接アクセスできないので通信が許可されているサーバからじゃないとHTTPでアクセスできないのでタルい
- Mock使ってテスト書くわけだけど、それ以前に実際にリクエスト投げてトライアンドエラーしたい。
このようなネットワーク制限を飛び越えてHTTPアクセスするためによく利用されるのがHTTP Proxyであり、それをSSH経由でセキュアに実現するのがSocks Proxyです。
そもそもSocks Proxyとは
素のHTTP Proxyとは違い、踏み台まではSSHトンネルすることでクライアントから目的地までセキュアにHTTPリクエストをすることができる仕組みです。イメージは以下のような感じですね。
クライアント <==SSH===>踏み台<===HTTP/HTTPS===>目的の閉じられたサーバ
Socks Proxyを立てる
まずローカルにSocks Proxyを立てます。そして目的地となるAPIサーバに実際にHTTPリクエストを投げる踏み台となるサーバを用意します。 以下のようなsshコマンドで1080ポートがSocks ProxyのポートとしてListenします(-f -Nオプションをつけてバックグラウンド実行させてます)
ssh -f -N -D localhost:1080 username@your_fumidai
1080がListenしたら、curl等で実際にリクエストできるかを確認してみるとよいですね。
curl --socks5 localhost:1080 http://your_closed_host/api/hogehoge
okhttpでリクエストする
okhttpといえばJava界(というかAndroidメインだと思うけど)で広く利用されているHTTPクライアントです。
ちょっと今JVM系言語であるKotlinを使って書いているので、こんな感じでSocks Proxy経由でHTTPリクエストができるようになります。
class SocksTest {
@Test
fun testRequest() {
val socketAddress = InetSocketAddress("localhost", 1080)
val proxy = Proxy(Proxy.Type.SOCKS, socketAddress)
val client = OkHttpClient.Builder().proxy(proxy).build()
val request = Request.Builder()
.url("http://your_closed_host/api/hogehoge")
.build()
val response = client.newCall(request).execute()
println(response.body().string())
}
}
OkHttpClientにproxyで、Socks Proxy情報を持つjava.net.Proxyオブジェクトを渡すだけです。あとはいつものokhttp。Javaでやりたい場合はJavaに置き換えてください。 別にokhttpじゃなくとも、proxyサポートしてるHTTPクライアントであれば同じ感じで応用が効くと思われます。
おわり。