haga-rak / fluxzy.core

Fast and fully streamed Man-On-The-Middle engine and a CLI app to intercept, record and alter HTTP/1.1, H2, websocket traffic over plain or secure channels.
https://docs.fluxzy.io
Other
120 stars 9 forks source link

Possibly no connect support? #268

Closed Groovin-Dev closed 3 months ago

Groovin-Dev commented 4 months ago

Describe the bug I'm not 100% sure what the issue is and I'm really not the best with networking but I believe there is an issue with the CONNECT method.

When using Fluxzy.Core and Fluxzy.Desktop (1.26.2-alpha) there is an application that will fail to load because it gets stuck in a loop of getting the gateways (the repeated requests are from the server trying again not Fluxzy)

Describe the tool and the environment Fluxzy.Core and Fluxzy.Desktop (1.26.2-alpha)

To Reproduce Steps to reproduce the behavior:

  1. Download Predecessor (I'm not 100% sure how to remake this)
  2. Run Fluxzy.Desktop with a filter looking for any URL containing "omeda"
  3. It will not get past the login screen
  4. Close game and disable proxy
  5. Launch game and you can get it

Screenshot image

Expected behavior The requests should go though as normal. In this case, 2 CONNECT requests followed by 2 GET requests that then upgrade to WS

Additional context The WS fix in 1.26.2-alpha did work for testing on echo.websocket.org/.ws but does not seem to help with this issue. I'm not the best at this so if you would like any more info please let me know and I'll do the best I can to get it for you. Also, Omeda (the devs of Predecessor) are aware of my actions using a proxy on their game and have allowed it just in case you were worried about that

haga-rak commented 4 months ago

I will try to reproduce this problem when I have access to a Windows machine

Groovin-Dev commented 4 months ago

Ok, I have written a small Python script to imitate the situation I'm in.

The gist is here: https://gist.github.com/Groovin-Dev/634ebf9b7069e6ec4d6223d979e418b7

Running this script without the proxy allows it to print everything and get to the WebSocket messages. Running with the proxy will cause it to fail when it makes the CONNECT request

haga-rak commented 4 months ago

I still haven't test the Wiindows yet but I took some time to test the python script you provide and bring some minor changes and fixes to the library. To cut the story short, the fact that the requests in the gist is all plain HTTP leads to a lot of issue and, likely, this will not solve the problem you're facing when using it with HTTPS. Additionally, there are several HTTP flow irregularities in the script.

First request:

gateway_status = make_http_request('http://127.0.0.1:9999/v1/gateway')
if gateway_status != 200:
    sys.exit(1)

No problem here.

Second request:

connect_status = make_http_request('http://127.0.0.1:9999/connect', 'CONNECT')
if connect_status != 200:
    sys.exit(1)

The CONNECT method is also used to establish a tunnel through a proxy. When this request lands, we must figure out if the client wants a tunnel to the host or send a CONNECT request to the host in plain HTTP. Here we added a fix that detects if the request_path in an absolute URI and treats the CONNECT method like any other HTTP method.

Third request

rpc_status = make_http_request('http://127.0.0.1:9999/v1/rpc?gateway=1')
if rpc_status != 101:
    sys.exit(1)

Makes flask produce this answer:

GET /v1/rpc?gateway=1 HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: python-requests/2.32.2
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

HTTP/1.1 101 SWITCHING PROTOCOLS
Server: Werkzeug/3.0.3 Python/3.12.3
Date: Wed, 29 May 2024 09:09:20 GMT
Content-Type: application/json
Connection: close

Even if you can put an explicit status code and a response body in flask, this is not a common HTTP flow and most client will not expect reading a response body. Moreover, there's no hint that tells the client in what protocol the server wants to switch to (no Upgrade header). You will notice that this request will fail under curl.

Fourth request

 make_websocket_request()

There is a fix we set to proceed correctly websocket over plain text #274