Reputation: 5567
I'm trying to connect to a Tor hidden service using the following PHP code:
$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);
When I run it, I get the following error:
Couldn't resolve host name
However, when I run the following command from my command line in Ubuntu:
curl -v --socks5-hostname localhost:9050 http://jhiwjjlqpyawmpjx.onion
I get a response as expected.
The PHP cURL documentation says this:
--socks5-hostname
Use the specified SOCKS5 proxy (and let the proxy resolve the host name).
I believe the reason it works from the command line is because Tor (the proxy) is resolving the .onion hostname, which it recognizes. When running the PHP code above, my guess is that cURL or PHP is trying to resolve the .onion hostname and doesn't recognize it. I've searched for a way to tell cURL/PHP to let the proxy resolve the hostname, but I can't find a way.
There is a very similar Stack Overflow question, cURL request using socks5 proxy fails when using PHP, but it works through the command line.
Upvotes: 552
Views: 313595
Reputation: 369
Here is a simple function to help you. Tho to save time first of all you need to make sure that you check if the proxy is valid to not with simple check with fsocketopen()
try {
$fp = fsockopen($ip, $port, $errno, $errstr, 10);
fclose($fp);
return true;
} catch (\Throwable $th) {
return false;
}
If socket returns true then go for requestUrl function
private function requestUrl($url, $proxy)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_PROXY, $proxy);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$contents = curl_exec($curl);
//Check for errors.
// if (curl_errno($curl)) {
// return new \Exception(curl_error($curl));
// }
curl_close($curl);
return $contents;
}
Upvotes: 1
Reputation: 857
TL;DR: Set CURLOPT_PROXYTYPE
to use CURLPROXY_SOCKS5_HOSTNAME
if you have a modern PHP, the value 7
otherwise, and/or correct the CURLOPT_PROXY
value.
As you correctly deduced, you cannot resolve .onion
domains via the normal DNS system, because this is a reserved top-level domain specifically for use by Tor and such domains by design have no IP addresses to map to.
Using CURLPROXY_SOCKS5
will direct the cURL command to send its traffic to the proxy, but will not do the same for domain name resolution. The DNS requests, which are emitted before cURL attempts to establish the actual connection with the Onion site, will still be sent to the system's normal DNS resolver. These DNS requests will surely fail, because the system's normal DNS resolver will not know what to do with a .onion
address unless it, too, is specifically forwarding such queries to Tor.
Instead of CURLPROXY_SOCKS5
, you must use CURLPROXY_SOCKS5_HOSTNAME
. Alternatively, you can also use CURLPROXY_SOCKS4A
, but SOCKS5 is much preferred. Either of these proxy types informs cURL to perform both its DNS lookups and its actual data transfer via the proxy. This is required to successfully resolve any .onion
domain.
There is also an additional error in the code in the original question. The proxy address value is set to an HTTP URL, but its type is SOCKS; these are incompatible. For SOCKS proxies, the value must be an IP or domain name and port number combination without a scheme/protocol/prefix.
Here is the correct code in full, with comments to indicate the changes.
<?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, "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);
You can also omit setting CURLOPT_PROXYTYPE
entirely by changing the CURLOPT_PROXY
value to include the socks5h://
prefix:
// Note no trailing slash, as this is a SOCKS address, not an HTTP URL.
curl_setopt(CURLOPT_PROXY, 'socks5h://127.0.0.1:9050');
Upvotes: 13
Reputation: 206
$url = 'http://jhiwjjlqpyawmpjx.onion/';
$curl = new Curl();
$curl->setProxy('127.0.0.1', 9050, CURLPROXY_SOCKS5_HOSTNAME);
$curl->get($url);
if ($curl->error) {
echo 'Error: ' . $curl->errorCode . ': ' . $curl->errorMessage;
} else {
echo $curl->response;
}
Upvotes: -4
Reputation: 2377
You need to set the CURLOPT_PROXYTYPE
option to CURLPROXY_SOCKS5_HOSTNAME
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
CURLPROXY_SOCKS5_HOSTNAME
is defined starting with PHP 5.6.10. If you're using an older version you can explicitly use its value, 7
:
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
Upvotes: 126
Reputation: 873
I use Privoxy and cURL to scrape Tor pages:
<?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);
?>
After installing Privoxy you need to add this line to the configuration file (/etc/privoxy/config
). Note the space and '.' a the end of line.
forward-socks4a / localhost:9050 .
Then restart Privoxy.
/etc/init.d/privoxy restart
Upvotes: 26
Reputation: 3721
Try to add this:
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
Upvotes: 11