0

I have a WebSocket Client which was connected to WebSocket Server directly. WS_Server <--> WS_Client

I need a forward proxy to intercept the data between client and server. WS_Server <--> Proxy <--> WS_Client

I was experimenting with different implementations for Proxy Servers. This is what I have thus far. I am using nhooyr.io/websocket It is a simple HTTP server that WS client dials to. The Proxy Server accepts the WS connection and then itself dials to the target WS server. Once these connections are established, then it just copies data between these two connections. The WS_Client to Proxy connection is not TLS encrypted but the proxy to WS server conn is TLS encrypted.

...

import (

    ...
    "nhooyr.io/websocket"
)

func main() {
    http.HandleFunc("/rest/v1/client/proxy", handleWebSocketConnection)
    err := http.ListenAndServe(":8081", nil)
    if err != nil {
        log.Fatalf("Failed to start proxy server: %v", err)
    }
}

func handleWebSocketConnection(w http.ResponseWriter, r *http.Request) {
    // Accept WebSocket conn from Client
    connA, err := websocket.Accept(w, r, nil)
    if err != nil {
        log.Printf("Failed to accept WebSocket connection: %v", err)
        return
    }
    defer connA.Close(200, "Closing connectionA")

    // Connect to Dest Server
    caCert, err := os.ReadFile(caCertPath)
    caPool := x509.NewCertPool()
    if !caPool.AppendCertsFromPEM(caCert) {
        log.Fatalf("Failed to append CA certificate")
    }
    tlsConfig := &tls.Config{
        RootCAs: caPool,
    }
    httpClient := &http.Client{
        Transport: &http.Transport{
            TLSClientConfig: tlsConfig,
        },
    }
    // Dial to dest 
    connB, _, err := websocket.Dial(r.Context(), DestWsAddr, &websocket.DialOptions{
        HTTPClient: httpClient,
    })
    if err != nil {
        log.Printf("Failed to connect to Dest: %v", err)
        return
    }
    defer connB.Close(200, "Closing connectionB")

    // Start goroutines to forward messages between client and agg
    go forwardMessages(connA, connB)
    go forwardMessages(connB, connA)

    // Keep the connection open indefinitely
    select {}
}

func forwardMessages(src, dst *websocket.Conn) {
    ctx := context.Background()
    for {
        // Read messages from the source connection
        msgType, msg, err := src.Read(ctx)
        log.Printf(" : [%v]", string(msg))
        if err != nil {
            log.Printf("Failed to read message: %v", err)
            return
        }

        // Write the message to the destination connection
        err = dst.Write(ctx, msgType, msg)
        if err != nil {
            log.Printf("Failed to write message: %v", err)
            return
        }
    }
}

This seems to be working fine, and I am able to intercept the data (msg). Some (very little data makes sense but most of it is gibberish. How can I make sense of this info? Why am I understand some data but not all of it? I verified this in Wireshark as well, but I see the same info there after unmasking that Wireshark does.

Another point that might be useful is that it is not just a simple WS connection. Once the WS is established, then we also do multiplexing on top of this WS conn using yamux

...
...
2024/11/13 06:13:56 : [HTTP/1.1 200 OK
]
2024/11/13 06:13:56 : []
2024/11/13 06:13:56 : [Content-Length: 0
]
2024/11/13 06:13:56 : []
2024/11/13 06:13:56 : [
]
2024/11/13 06:13:56 : []
2024/11/13 06:13:56 : [��p�    V�Cd^너+�Cn2A�/�RS�x�e8 �W��R����c;E�.�ى�+D2td>�K�,*'internalServer.server.abc.xyz.com
�+3&$ ����,�-)��b�a(�%/�s�L����9]
2024/11/13 06:13:56 : [�]
0��M&�� �3 06:13:56 : [zv�-ee�j�N�=���&�m8T[���=��P �W��R����c;E�.�ى�+D2td>�K.+3$ ��{6�
         `�N���NAw��^X��y,R5`��i_���>K4�6Y��aɂ�w;vSѰ]
                                                     �n��[���`���ab�+J��%�=���bu���O�p�iUSV�/_���9�U������[Z�~cn-�l�v��i>X���}U�I�ds�Z�v�?&�r������<�����Y�T��λ���T܌

Any pointers would be very useful. Thanks!

2
  • 1
    Websockets support transmitting arbitrary data, including binary. So your question can be rephrased as "how do I make sense of arbitrary data". This cannot be answered. You have to have knowledge of the protocol being spoken to be able to decode it. Commented Nov 13, 2024 at 13:17
  • 1
    I suppose you can at least decode the websocket frames. Maybe that's all you wanted to know. The framing is specified here: datatracker.ietf.org/doc/html/rfc6455#section-5. I would assume Wireshark can do this directly, or there is a plugin available. Commented Nov 13, 2024 at 13:22

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.