web-dev-qa-db-ja.com

PHPでcURLを使ってTorの隠しサービスに接続するにはどうすればいいですか?

私は以下の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を使用すると失敗しますが、コマンドラインを通じて機能します。

322
frosty

CURLPROXY_SOCKS5_HOSTNAMEはPHPでは定義されていないようですが、その値を明示的に使用することができます。これは7に相当します。

curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
95
dr.scre

私は 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
19
FattyPotatoes

これを追加してみてください。

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つの追加エラーがあります。これらは:

  • 1行目の終わりにセミコロンがありません。
  • プロキシアドレス値はHTTP URLに設定されますが、そのタイプはSOCKSです。これらは互換性がありません。 SOCKSプロキシの場合、値はスキーム/プロトコル/プレフィックスなしのIPまたはドメイン名とポート番号の組み合わせである必要があります。

変更を示すコメント付きの完全な正しいコードを次に示します。

<?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');
3
Meitar