【问题标题】:How can I connect to a Tor hidden service using cURL in PHP?如何在 PHP 中使用 cURL 连接到 Tor 隐藏服务?
【发布时间】:2013-03-04 22:16:01
【问题描述】:

我正在尝试使用以下 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 让代理解析主机名,但我找不到方法。

有一个非常相似的 Stack Overflow 问题,cURL request using socks5 proxy fails when using PHP, but it works through the command line

【问题讨论】:

    标签: php curl proxy tor


    【解决方案1】:

    这里有一个简单的函数来帮助你。 为了节省时间,首先您需要确保通过 fsocketopen() 进行简单检查来检查代理是否有效

            try {
                $fp = fsockopen($ip, $port, $errno, $errstr, 10);
                fclose($fp);
                return true;
            } catch (\Throwable $th) {
                return false;
            }
    

    如果socket返回true,则使用requestUrl函数

        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;
        }
    

    【讨论】:

      【解决方案2】:

      您需要将选项CURLOPT_PROXYTYPE 设置为CURLPROXY_SOCKS5_HOSTNAME,可悲的是wasn't defined in old PHP versions, circa pre-5.6;如果你之前有,但你可以显式使用它的值,它等于7

      curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
      

      【讨论】:

        【解决方案3】:

        TL;DR:如果您有现代 PHP,请将CURLOPT_PROXYTYPE 设置为使用CURLPROXY_SOCKS5_HOSTNAME,否则设置为7,和/或更正CURLOPT_PROXY 的值。

        正如您正确推断的那样,您无法通过普通 DNS 系统解析 .onion 域,因为这是 a reserved top-level domain specifically for use by Tor 并且此类域在设计上没有可映射的 IP 地址。

        使用CURLPROXY_SOCKS5 将指示cURL 命令将其流量发送到代理,但不会对域名解析做同样的事情。在 cURL 尝试与 Onion 站点建立实际连接之前发出的 DNS 请求仍将发送到系统的正常 DNS 解析器。这些 DNS 请求肯定会失败,因为系统的普通 DNS 解析器不知道如何处理 .onion 地址,除非它也专门将此类查询转发到 Tor。

        您必须使用CURLPROXY_SOCKS5_HOSTNAME,而不是CURLPROXY_SOCKS5。或者,您也可以使用CURLPROXY_SOCKS4A,但更喜欢 SOCKS5。这些代理类型中的任何一种都会通知 cURL 执行其 DNS 查找和通过代理进行的实际数据传输。这是成功解析任何.onion 域所必需的。

        原始问题的代码中还有两个额外的错误尚未被之前的评论者纠正。它们是:

        • 第 1 行末尾缺少分号。
        • 代理地址值设置为HTTP URL,但其类型为SOCKS;这些是不相容的。对于 SOCKS 代理,该值必须是 IP 或域名和端口号组合,不带方案/协议/前缀。

        这是正确的完整代码,用 cmets 表示更改。

        <?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_PROXY 值以包含socks5h:// 前缀来完全省略设置CURLOPT_PROXYTYPE

        // Note no trailing slash, as this is a SOCKS address, not an HTTP URL.
        curl_setopt(CURLOPT_PROXY, 'socks5h://127.0.0.1:9050');
        

        【讨论】:

          【解决方案4】:

          我使用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)。注意空格和'.'行尾。

          forward-socks4a / localhost:9050 .
          

          然后重启 Privoxy。

          /etc/init.d/privoxy restart
          

          【讨论】:

          • 这行得通!在 Windows 10 和 CentOS 6 上测试,如果 Tor 使用 Socks 5 而不是 Socks 4,请使用:forward-socks5 / localhost:9150 .
          【解决方案5】:

          尝试添加这个:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多