首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cURL作为代理,处理HTTPS/CONNECT方法

cURL作为代理,处理HTTPS/CONNECT方法
EN

Stack Overflow用户
提问于 2013-06-05 07:54:35
回答 1查看 6.2K关注 0票数 8

此脚本在IP/端口上侦听,并打算充当HTTP(S)代理。

对HTTP的请求可以正常工作,但我不知道如何处理HTTPS请求,更具体地说,在客户端向代理发送连接请求之后进行SSLv3握手。

我最接近的答案是:

  • 用于在客户端和目标服务器之间传输数据的CURLOPT_HTTPPROXYTUNNEL libcurl选项
  • stream_socket_enable_crypto()可能对加密数据“做一些事情”

我真的不太确定,所以我们非常希望能提供一个如何处理这个问题的指针。

下面是一个示例请求:http://pastebin.com/xkWhGyjW

代码语言:javascript
复制
<?php

class proxy {

    static $server;
    static $client;

    static function headers($str) { // Parses HTTP headers into an array
        $tmp = preg_split("'\r?\n'",$str);
        $output = array();
        $output[] = explode(' ',array_shift($tmp));
        $post = ($output[0][0] == 'POST' ? true : false);

            foreach($tmp as $i => $header) {
                if($post && !trim($header)) {
                    $output['POST'] = $tmp[$i+1];
                    break;
                }
                else {
                    $l = explode(':',$header,2);
                    $output[$l[0]] = $l[0].': '.ltrim($l[1]);
                }
            }
        return $output;
    }

    public function output($curl,$data) {
        socket_write(proxy::$client,$data);
        return strlen($data);
    }
}




$ip = "127.0.0.1";
$port = 50000;

proxy::$server = socket_create(AF_INET,SOCK_STREAM, SOL_TCP);
socket_set_option(proxy::$server,SOL_SOCKET,SO_REUSEADDR,1);
socket_bind(proxy::$server,$ip,50000);
socket_getsockname(proxy::$server,$ip,$port);
socket_listen(proxy::$server);

while(proxy::$client = socket_accept(proxy::$server)) {

    $input = socket_read(proxy::$client,4096);
    preg_match("'^([^\s]+)\s([^\s]+)\s([^\r\n]+)'ims",$input,$request);
    $headers = proxy::headers($input);

        echo $input,"\n\n";
            if(preg_match("'^CONNECT '",$input)) { // HTTPS
                // Tell the client we can deal with this
                socket_write(proxy::$client,"HTTP/1.1 200 Connection Established\r\n\r\n");
                // Client sends binary data here (SSLv3, TLS handshake, Client hello?)
                // socket_read(proxy::$client,4096);
                // ?
            }
            else { // HTTP

                        $input = preg_replace("'^([^\s]+)\s([a-z]+://)?[a-z0-9\.\-]+'","\\1 ",$input);
                        $curl = curl_init($request[2]);
                        curl_setopt($curl,CURLOPT_HEADER,1);
                        curl_setopt($curl,CURLOPT_HTTPHEADER,$headers);
                        curl_setopt($curl,CURLOPT_TIMEOUT,15);
                        curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
                        curl_setopt($curl,CURLOPT_NOPROGRESS,1);
                        curl_setopt($curl,CURLOPT_VERBOSE,1);
                        curl_setopt($curl,CURLOPT_AUTOREFERER,true);
                        curl_setopt($curl,CURLOPT_FOLLOWLOCATION,1);
                        curl_setopt($curl,CURLOPT_WRITEFUNCTION, array("proxy","output"));
                        curl_exec($curl);
                        curl_close($curl);
            }
    socket_close(proxy::$client);
}
socket_close(proxy::$server);


?>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-11 09:09:19

如果我正确理解,您将使用PHP编写HTTP代理服务器。当您想要使用PHP cURL库连接到代理服务器并使用CONNECT而不是GET时,将使用CONNECT选项。在这种情况下,这是不相关的。

当代理服务器(代理)接收到CONNECT请求时,它应该使用socket_createsocket_connect连接到指定的主机(端点)。一旦建立了连接,通过发送HTTP/1.1 200 Connection Established让客户端(客户端)知道。在此之后,您将希望将端点发送到代理的所有数据复制到客户端,以及将客户端发送到代理的所有数据复制到端点。

在您的示例中使用cURL将创建多个连接。为了处理多个连接,我使用了pcntl_fork,它在每个CONNECT请求上分叉一个新进程。

下面是一个有用的例子:

代码语言:javascript
复制
<?php

class proxy {

    static $server;
    static $client;

    static function headers($str) { // Parses HTTP headers into an array
        $tmp = preg_split("'\r?\n'",$str);
        $output = array();
        $output[] = explode(' ',array_shift($tmp));
        $post = ($output[0][0] == 'POST' ? true : false);

            foreach($tmp as $i => $header) {
                if($post && !trim($header)) {
                    $output['POST'] = $tmp[$i+1];
                    break;
                }
                else {
                    $l = explode(':',$header,2);
                    $output[$l[0]] = $l[0].': '.ltrim($l[1]);
                }
            }
        return $output;
    }

    public function output($curl,$data) {
        socket_write(proxy::$client,$data);
        return strlen($data);
    }
}




$ip = "127.0.0.1";
$port = 50000;

proxy::$server = socket_create(AF_INET,SOCK_STREAM, SOL_TCP);
socket_set_option(proxy::$server,SOL_SOCKET,SO_REUSEADDR,1);
socket_bind(proxy::$server,$ip,50000);
socket_getsockname(proxy::$server,$ip,$port);
socket_listen(proxy::$server);

while(proxy::$client = socket_accept(proxy::$server)) {

    $input = socket_read(proxy::$client,4096);
    preg_match("'^([^\s]+)\s([^\s]+)\s([^\r\n]+)'ims",$input,$request);
    $headers = proxy::headers($input);

        echo $input,"\n\n";
            if(preg_match("'^CONNECT ([^ ]+):(\d+) '",$input,$match)) { // HTTPS
                // fork to allow multiple connections
                if(pcntl_fork())
                    continue;

                $connect_host = $match[1];
                $connect_port = $match[2];

                // connect to endpoint
                $connection = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                if(!socket_connect($connection, gethostbyname($connect_host), $connect_port))
                    exit;

                // let the client know that we're connected
                socket_write(proxy::$client,"HTTP/1.1 200 Connection Established\r\n\r\n");

                // proxy data
                $all_sockets = array($connection, proxy::$client);
                $null = null;
                while(($sockets = $all_sockets)
                      && false !== socket_select($sockets, $null, $null, 10)
                ) {
                    // can we read from the client without blocking?
                    if(in_array(proxy::$client, $sockets)) {
                        $buf = null;
                        socket_recv(proxy::$client, $buf, 8192, MSG_DONTWAIT);
                        echo "CLIENT => ENDPOINT (" . strlen($buf) . " bytes)\n";
                        if($buf === null)
                            exit;
                        socket_send($connection, $buf, strlen($buf), 0);
                    }

                    // can we read from the endpoint without blocking?
                    if(in_array($connection, $sockets)) {
                        $buf = null;
                        socket_recv($connection, $buf, 8192, MSG_DONTWAIT);
                        echo "ENDPOINT => CLIENT (" . strlen($buf) . " bytes)\n";
                        if($buf === null)
                            exit;
                        socket_send(proxy::$client, $buf, strlen($buf), 0);
                    }
                }

                exit;
            }
            else { // HTTP

                        $input = preg_replace("'^([^\s]+)\s([a-z]+://)?[a-z0-9\.\-]+'","\\1 ",$input);
                        $curl = curl_init($request[2]);
                        curl_setopt($curl,CURLOPT_HEADER,1);
                        curl_setopt($curl,CURLOPT_HTTPHEADER,$headers);
                        curl_setopt($curl,CURLOPT_TIMEOUT,15);
                        curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
                        curl_setopt($curl,CURLOPT_NOPROGRESS,1);
                        curl_setopt($curl,CURLOPT_VERBOSE,1);
                        curl_setopt($curl,CURLOPT_AUTOREFERER,true);
                        curl_setopt($curl,CURLOPT_FOLLOWLOCATION,1);
                        curl_setopt($curl,CURLOPT_WRITEFUNCTION, array("proxy","output"));
                        curl_exec($curl);
                        curl_close($curl);
            }
    socket_close(proxy::$client);
}
socket_close(proxy::$server);
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16934409

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档