Как я могу подключиться к скрытой службе Tor, используя cURL в PHP?

  Примечание для персонала: Этот вопрос и связанные с ним ответы были заблокированы, чтобы предотвратить обсуждение не по теме события, связанного с рассматриваемым вопросом. С вопросами об этом событии можно ознакомиться на нашем мета-сайте. Спасибо!

Я пытаюсь подключиться к скрытому сервису Tor, используя следующий код PHP:

$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, чтобы прокси разрешал имя хоста, но я не могу найти способ.

Существует очень похожий вопрос Qaru: cURL-запрос с использованием прокси socks5 не выполняется при использовании PHP, но он работает через командную строку.

Ответ 2

Я использую Privoxy и cURL для очистки страниц Tor:

<?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). Обратите внимание на пробел и '.' a конец строки.

forward-socks4a / localhost:9050 .

Затем перезапустите Privoxy.

/etc/init.d/privoxy restart

Ответ 3

Попробуйте добавить это:

curl_setopt($ch, CURLOPT_HEADER, 1); 
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); 

Ответ 4

TL; DR: установите CURLOPT_PROXYTYPE на использование CURLPROXY_SOCKS5_HOSTNAME, если у вас современный PHP, в противном случае значение 7 и/или исправьте значение CURLOPT_PROXY.

Как вы правильно поняли, вы не можете разрешить домены .onion через обычную систему DNS, потому что это зарезервированный домен верхнего уровня, специально предназначенный для использования Tor, и такие домены по своей конструкции не имеют IP-адресов для сопоставления с.

Использование CURLPROXY_SOCKS5 заставит команду cURL отправлять свой трафик на прокси, но не будет делать то же самое для разрешения доменного имени. Запросы DNS, которые отправляются до того, как cURL попытается установить фактическое соединение с сайтом Onion, будут по-прежнему отправляться системному обычному преобразователю DNS. Эти DNS-запросы, несомненно, будут терпеть неудачу, потому что обычный системный DNS-распознаватель не будет знать, что делать с адресом .onion, если он также не будет специально направлять такие запросы в Tor.

Вместо CURLPROXY_SOCKS5 вы должны использовать CURLPROXY_SOCKS5_HOSTNAME. Кроме того, вы также можете использовать CURLPROXY_SOCKS4A, но SOCKS5 гораздо предпочтительнее. Любой из этих типов прокси информирует cURL о выполнении поиска DNS и фактической передачи данных через прокси. Это необходимо для успешного разрешения любого домена .onion.

В исходном вопросе также есть две дополнительные ошибки в коде, которые еще не были исправлены предыдущими комментаторами. Это:

  • Отсутствует точка с запятой в конце строки 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');