私は以下のPHPコードを使ってTorの隠しサービスに接続しようとしています。
$url = 'http://jhiwjjlqpyawmpjx.onion/'
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, "http://127.0.0.1:9050/");
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);
print_r($output);
print_r($curl_error);
実行すると、次のエラーが発生します。
ホスト名を解決できませんでした
しかし、Ubuntuのコマンドラインから次のコマンドを実行すると、
curl -v --socks5-hostname localhost:9050 http://jhiwjjlqpyawmpjx.onion
期待どおりの応答があります
PHP cURL のドキュメントにはこう書かれています。
--socks5-hostname
Use the specified SOCKS5 proxy (and let the proxy resolve the Host name).
コマンドラインから動作するのは、Tor(プロキシ)が.onionホスト名を解決しているためです。上記のPHPコードを実行すると、cURLまたはPHPが.onionホスト名を解決しようとしていて、それを認識できないと考えられます。プロキシにホスト名を解決させるようにcURL/PHPに指示する方法を探しましたが、方法が見つかりません。
非常によく似たスタックオーバーフローの質問があります。Socks5プロキシを使用するcURLリクエストはPHPを使用すると失敗しますが、コマンドラインを通じて機能します。
CURLPROXY_SOCKS5_HOSTNAME
はPHPでは定義されていないようですが、その値を明示的に使用することができます。これは7に相当します。
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
私は Privoxy とTorのページをスクレーピングするためにcURLを使います。
<?php
$ch = curl_init('http://jhiwjjlqpyawmpjx.onion'); // Tormail URL
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_setopt($ch, CURLOPT_PROXY, "localhost:8118"); // Default privoxy port
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_exec($ch);
curl_close($ch);
?>
Privoxyをインストールした後、この行を設定ファイル(/etc/privoxy/config
)に追加する必要があります。スペースと「。」に注意してください。行末.
forward-socks4a / localhost:9050 .
その後、Privoxyを再起動してください。
/etc/init.d/privoxy restart
これを追加してみてください。
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
TL; DR:最新のPHPを使用している場合はCURLOPT_PROXYTYPE
を使用するようにCURLPROXY_SOCKS5_HOSTNAME
を設定し、そうでない場合は7
の値を設定するか、CURLOPT_PROXY
の値を修正します。
正しく推測すると、通常のDNSシステムでは.onion
ドメインを解決できません。これは Tor専用の予約トップレベルドメイン であり、そのようなドメインには設計するIPアドレスがないためです。
CURLPROXY_SOCKS5
を使用すると、cURLコマンドがそのトラフィックをプロキシに送信するように指示されますが、ドメイン名の解決ではnot同じことを行います。送信されるbeforecURLがOnionサイトとの実際の接続を確立しようとするDNS要求は、システムの通常のDNSリゾルバーに送信されます。これらのDNS要求は確実に失敗します。システムの通常のDNSリゾルバーは、.onion
アドレスをどう処理するかわからないからです。
CURLPROXY_SOCKS5
の代わりに、 CURLPROXY_SOCKS5_HOSTNAME
を使用する必要があります。または、CURLPROXY_SOCKS4A
を使用することもできますが、SOCKS5の方がはるかに優先されます。これらのプロキシタイプのいずれかは、cURLにDNSルックアップとプロキシを介した実際のデータ転送の両方を実行するよう通知します。これは、.onion
ドメインを正常に解決するために必要です。
また、元の質問のコードには、以前のコメント作成者によってまだ修正されていない2つの追加エラーがあります。これらは:
変更を示すコメント付きの完全な正しいコードを次に示します。
<?php
$url = 'http://jhiwjjlqpyawmpjx.onion/'; // Note the addition of a semicolon.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, "127.0.0.1:9050"); // Note the address here is just `IP:port`, not an HTTP URL.
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME); // Note use of `CURLPROXY_SOCKS5_HOSTNAME`.
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);
print_r($output);
print_r($curl_error);
CURLOPT_PROXYTYPE
値を変更してCURLOPT_PROXY
プレフィックスを含めることで、socks5h://
の設定を完全に省略することもできます。
// Note no trailing slash, as this is a SOCKS address, not an HTTP URL.
curl_setopt(CURLOPT_PROXY, 'socks5h://127.0.0.1:9050');