ProxymanApp / Proxyman

Modern. Native. Delightful Web Debugging Proxy for macOS, iOS, and Android ⚡️
https://proxyman.io
5.72k stars 189 forks source link

SOCKS Proxy in Proxyman routes traffic to the Host header instead of the specified SOCKS destination #2107

Open hunmar opened 3 months ago

hunmar commented 3 months ago

Description

When using a SOCKS5 proxy with Proxyman, the traffic is incorrectly routed based on the Host header rather than the destination specified by the SOCKS proxy. This leads to incorrect proxy behavior, where traffic is not directed to the intended target but instead to whatever is specified in the Host header. This behavior undermines the purpose of using a SOCKS proxy and could result in incorrect routing and potential security issues.

Steps to Reproduce:

  1. Configure Proxyman to use a SOCKS5 proxy.
  2. Initiate traffic that should be routed through the SOCKS proxy.
  3. Observe that traffic is routed to the address in the Host header instead of the SOCKS destination.
  4. Expected Behavior:
  5. Traffic should be routed through the SOCKS proxy to the correct destination as specified, not the Host header.

Environment

NghiaTranUIT commented 3 months ago

I'm not sure how to implement this logic. Currently, I'm using this logic: https://github.com/purkylin/proxy-nio/blob/92fbd9564b90b6bd7c270596bb03d53df7cf8b34/Sources/proxy-nio/socks5/SocksHandler.swift#L55

Can you guide me on how to do it? because I don't have experience on SOCKS

hunmar commented 3 months ago

Current Behavior When running a command like curl -x socks5://localhost:{proxyman port} google.com -H 'Host: foobar.com', Proxyman attempts to route the request based on the Host header (foobar.com). If foobar.com is not reachable, the connection fails.

Expected Behavior The request should be routed to the destination specified in the SOCKS5 proxy request (google.com), regardless of what is in the Host header.

Ideas To get the expected behavior, you should make sure the routing uses the address provided by the SOCKS5 proxy (request.addr.host! and request.port) instead of anything in the Host header.

I guess it'll look something like this

case .command(let request):
    logger.debug("receive command")
    switch request.cmd {
    case .connect:
        // Route to the SOCKS-provided host and port, not the HTTP Host header
        connectTo(host: request.addr.host!, port: request.port, context: context)
    case .bind:
        // Handle unsupported BIND command
        let response = SocksResponse.command(type: .unsupported, addr: SocksAddress.zero(for: .v4), port: 0)
        context.write(self.wrapOutboundOut(response), promise: nil)
    case .udp:
        // Handle UDP if needed
        beginUDP(context: context)
    }

This way, the traffic should go to the correct destination, like google.com in the example, and not to whatever is in the Host header.

NghiaTranUIT commented 3 months ago

@hunmar I assume you're talking about the External Proxy with SOCKS Proxy, right?

It means:

Your Remote SOCKS Server can define the SOCKS Destination, and Proxyman should follow it, instead of using the Host.


Or you're talking about the SOCKS Proxy in Proxyman (Tools menu -> Proxy Setting -> SOCKS Proxy).

If it's how can I defined the SOCKS Destination?

ignatovSA commented 3 months ago

Or you're talking about the SOCKS Proxy in Proxyman (Tools menu -> Proxy Setting -> SOCKS Proxy).

yes, that's the case.

In other words, in case of calling curl -x socks5://localhost:{proxyman port} google.com -H 'Host: foobar.com' Proxyman uses value described in Host header, and goes to foobar.com And we expect Proxyman to go to google.com and just forward Host header

NghiaTranUIT commented 3 months ago

Tested with curl -v -x socks5://localhost:8889 https://httpbin.org/get?id=123 -H 'Host: www.google.com and Proxyman SOCKS Server works as expected behavior.

Screenshot 2024-08-22 at 8 27 44 AM


However, if it's HTTP, curl -v -x socks5://localhost:8889 httpbin.org/get?id=123 -H 'Host: www.google.com, Proxyman will send the request to www.google.com.

From what I debug, the problem is cURL doesn't send the entire URL (httpbin.org/get?id=123), instead, it sends /get?id=123 -> Proxyman gets the Host Header and connects to this server.

KasyanDiGris commented 2 months ago

From what I debug, the problem is cURL doesn't send the entire URL (httpbin.org/get?id=123), instead, it sends /get?id=123 -> Proxyman gets the Host Header and connects to this server.

The entire URL will not necessarily be sent according to HTTP protocol. Any way the target IP will be send by SOCKS5 request message. See RFC.

acelost commented 4 weeks ago

Tested with curl -v -x socks5://localhost:8889 https://httpbin.org/get?id=123 -H 'Host: www.google.com and Proxyman SOCKS Server works as expected behavior.

* Please note that the URL is `HTTPS://httpbin.org/get?id=123` and the Host is [www.google.com](http://www.google.com)

Screenshot 2024-08-22 at 8 27 44 AM

However, if it's HTTP, curl -v -x socks5://localhost:8889 httpbin.org/get?id=123 -H 'Host: www.google.com, Proxyman will send the request to www.google.com.

From what I debug, the problem is cURL doesn't send the entire URL (httpbin.org/get?id=123), instead, it sends /get?id=123 -> Proxyman gets the Host Header and connects to this server.

Hi! This issue is still actual. RFC assumes that the address of the target server will be transmitted as part of the message (not as a "Host" header). Please let me know if this problem cannot be fixed due to technical reasons 🙏

NghiaTranUIT commented 3 weeks ago

@acelost not sure how to fix it. Proxyman is using this code (https://github.com/purkylin/proxy-nio/blob/92fbd9564b90b6bd7c270596bb03d53df7cf8b34/Sources/proxy-nio/socks5/SocksHandler.swift#L55) when making a SOCKS connection.

The code actually uses the DST.ADDR from SOCKS Requests.

Ref: https://github.com/purkylin/proxy-nio/blob/92fbd9564b90b6bd7c270596bb03d53df7cf8b34/Sources/proxy-nio/socks5/SocksRequest.swift#L91

NghiaTranUIT commented 3 weeks ago

Good news: I'm able to reproduce the bug. I'm fixing it now 👍

NghiaTranUIT commented 3 weeks ago

@acelost @KasyanDiGris @ignatovSA @hunmar It's fixed with this Beta build: https://download.proxyman.io/beta/Proxyman_5.10.0_Fix_SOCKS5_issue.dmg

Screenshot 2024-11-10 at 09 51 58

NghiaTranUIT commented 3 weeks ago

Here is the v2: https://download.proxyman.io/beta/Proxyman_5.10.0_Fix_SOCKS_issue_v2.dmg

Changelog

acelost commented 2 weeks ago

https://download.proxyman.io/beta/Proxyman_5.10.0_Fix_SOCKS_issue_v2.dmg

@NghiaTranUIT It works as expected! Thank you very much! I'm really looking forward to the official release :)