代码之家  ›  专栏  ›  技术社区  ›  John

如何将HTTPS流量从SOCKS代理转发到HTTP代理

  •  1
  • John  · 技术社区  · 10 年前

    我已经编写了一个SOCKS代理,如果链接关闭,它可以同时处理HTTP和HTTPS流量。

    如果启用了链接,并且转发主机和端口属于过滤HTTP代理,则只有HTTP流量可以流动。HTTPS流量不流动,并报告SSL错误。

    请注意,当请求直接来自浏览器而不是SOCKS服务器时,HTTP代理会处理HTTPS流量。

    例如,如果我向 https://www.google.com 发生以下情况:

    1) 客户发送SOCKS 5问候语,让我们知道哪些授权方法是可接受的。

    2) 服务器响应NO_AUTH

    3) 客户端发送连接请求(包括预期的目标主机和端口)。

    4) 服务器创建一个套接字并将其连接到HTTP代理服务器,并用GRANTED响应客户端

    5) SOCKS服务器随后收到以下请求(不可见/控制字符已全部替换为其字符代码,因此您可以看到发生了什么):

    \u0016\u0003\u0001\u0000Ñ\u0001\u0000\u0000Í\u0003\u0003áp¥@Ia¹\u0001„Ä\u0006 É;š‰‰4\u001dýà•J>Ü6¢Þ\fö\u001c%\u0000\u0000(À+À/\u0000žÌ\u0014Ì\u0013À\nÀ\tÀ\u0013À\u0014À\u0007À\u0011\u00003\u00002\u00009\u0000œ\u0000/\u00005\u0000\n\u0000\u0005\u0000\u0004\u0001\u0000\u0000|\u0000\u0000\u0000\u0013\u0000\u0011\u0000\u0000\u000ewww.google.comÿ\u0001\u0000\u0001\u0000\u0000\n\u0000\b\u0000\u0006\u0000\u0017\u0000\u0018\u0000\u0019\u0000\u000b\u0000\u0002\u0001\u0000\u0000#\u0000\u00003t\u0000\u0000\u0000\u0010\u0000\u001b\u0000\u0019\u0006spdy/3\bspdy/3.1\bhttp/1.1uP\u0000\u0000\u0000\u0005\u0000\u0005\u0001\u0000\u0000\u0000\u0000\u0000\u0012\u0000\u0000\u0000\r\u0000\u0012\u0000\u0010\u0004\u0001\u0005\u0001\u0002\u0001\u0004\u0003\u0005\u0003\u0002\u0003\u0004\u0002\u0002\u0002
    

    如您所见,它完全不可读,但我们已经知道用户打算从初始SOCKS连接消息(步骤3)转到何处,因此我们可以创建并发出以下连接请求:

    CONNECT www.google.com:443 HTTP/1.1\r\nUser-Agent: MySocksServer\r\nProxy-Connection: keep-alive\r\nHost: www.google.com\r\n\r\n
    

    6) 这个新构造的CONNECT被发送到我们链接到的HTTP代理,该代理检查其过滤规则并响应:

    HTTP/1.1 200 Connection Established\r\nVia: 1.1 HTTPserverName\r\nX-WebMarshal-RequestID: AN_ID_STRING\r\n\r\n
    

    7) 这在我们的SOCKS服务器中接收,并转发(未修改)给客户端。在我的调试中,我直接在发送请求之前监视套接字,可以看到客户端套接字已连接。

    8) 引发的下一个事件是一个错误,错误为SOCKET_NOT_CONNECTED,在套接字上运行另一个检查以确认客户端套接字确实不再连接。

    为什么我的插座会在第7步和第8步之间关闭?我没有正确遵守协议吗?我看不出我错过了什么。我想我在某种程度上处理CONNECT方法是错误的?

    如果我没有修改SOCKS服务器接收到的请求(即将其转换为CONNECT请求),而是将不可读数据直接转发给HTTP代理,则HTTP代理的日志显示:

    Badly formated request: \u0016\u0003\u001
    Bad request received.
    

    Failed to read request: Client closed connection. (0)
    1Request took 0 ms + 23 ms idle time
    
    2 回复  |  直到 10 年前
        1
  •  6
  •   Remy Lebeau    10 年前

    正确的顺序是:

    1. 客户端连接到SOCKS代理,根据需要进行身份验证。

    2. 客户端发送SOCKS连接请求以创建隧道 www.google.com:443 .

    3. SOCKS代理连接到HTTP代理

    4. SOCKS代理发送HTTP CONNECT 请求创建到 www.google.com:443 .

    5. SOCKS代理从HTTP代理接收回复。

    6. SOCKS代理向客户端发送适当的SOCKS应答。

    7. 若HTTP代理成功,则在客户端和HTTP代理之间传递未修改的数据,直到其中一个断开连接。

    8. 关闭客户端连接和HTTP代理连接。

    当您链接代理时,必须先协商隧道,然后才能开始通过它们传递应用程序数据。在下一个代理首先回复其隧道状态之前,不要向客户端发送隧道回复。

        2
  •  2
  •   Steffen Ullrich    10 年前

    6) 这个新构造的CONNECT被发送到HTTP代理。。。此代理。。。回复如下:

    7) 这在我们的SOCKS服务器中接收,并转发(未修改)给客户端。。。

    这是错误的。您在SOCKS代理中生成CONNECT请求,因此您应该将对该请求的响应保留给自己,而不是转发给客户端。您应该做什么:

    • 如果您从客户端接收到SSL握手的开始(“\x16\x03…”),则应该对其进行缓冲。
    • 然后创建CONNECT请求并将其发送到代理。主机头和代理连接头对于CONNECT没有意义,因此不需要添加它们。
    • 读取代理对CONNECT请求的响应。如果状态代码不是200,则有问题,您应该关闭与客户端的连接。没有简单的方法将错误信息传输到客户端。
    • 如果状态代码为200,则通过代理将缓冲的ClientHello从客户端转发到服务器,然后在客户端和服务器之间转发所有内容(通过代理隧道)。