diff --git a/p2p/transport/websocket/websocket.go b/p2p/transport/websocket/websocket.go index 6c5799d46e..d97334a1e8 100644 --- a/p2p/transport/websocket/websocket.go +++ b/p2p/transport/websocket/websocket.go @@ -160,6 +160,8 @@ func (t *WebsocketTransport) Resolve(_ context.Context, maddr ma.Multiaddr) ([]m return []ma.Multiaddr{parsed.toMultiaddr()}, nil } +// Dial will dial the given multiaddr and expect the given peer. If an +// HTTPS_PROXY env is set, it will use that for the dial out. func (t *WebsocketTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (transport.CapableConn, error) { connScope, err := t.rcmgr.OpenConnection(network.DirOutbound, true, raddr) if err != nil { diff --git a/p2p/transport/websocket/websocket_test.go b/p2p/transport/websocket/websocket_test.go index 9ca03775a2..a7c9c8be1e 100644 --- a/p2p/transport/websocket/websocket_test.go +++ b/p2p/transport/websocket/websocket_test.go @@ -1,6 +1,7 @@ package websocket import ( + "bytes" "context" "crypto/ecdsa" "crypto/elliptic" @@ -15,6 +16,7 @@ import ( "math/big" "net" "net/http" + "os" "strings" "testing" "time" @@ -548,3 +550,72 @@ func TestResolveMultiaddr(t *testing.T) { }) } } + +func TestHTTPSProxyDoesSocks(t *testing.T) { + proxyServer, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + proxyServerErr := make(chan error, 1) + + go func() { + defer proxyServer.Close() + c, err := proxyServer.Accept() + if err != nil { + proxyServerErr <- err + return + } + fmt.Println("c", c) + defer c.Close() + + req := [32]byte{} + _, err = io.ReadFull(c, req[:3]) + if err != nil { + proxyServerErr <- err + return + } + + // Handshake a SOCKS5 client: https://www.rfc-editor.org/rfc/rfc1928.html#section-3 + if !bytes.Equal([]byte{0x05, 0x01, 0x00}, req[:3]) { + t.Log("expected SOCKS5 connect request") + proxyServerErr <- err + return + } + _, err = c.Write([]byte{0x05, 0x00}) + if err != nil { + proxyServerErr <- err + return + } + + expectedBytes := "\x05\x01\x00\x03\x0bexample.com" + _, err = io.ReadFull(c, req[:len(expectedBytes)]) + if err != nil { + proxyServerErr <- err + return + } + if !bytes.Equal([]byte(expectedBytes), req[:len(expectedBytes)]) { + t.Log("expected SOCKS5 connect request") + proxyServerErr <- err + return + } + + proxyServerErr <- nil + }() + + origEnv := os.Getenv("HTTPS_PROXY") + defer os.Setenv("HTTPS_PROXY", origEnv) + + os.Setenv("HTTPS_PROXY", "socks5://"+proxyServer.Addr().String()) + + tlsConfig := &tls.Config{InsecureSkipVerify: true} // Our test server doesn't have a cert signed by a CA + _, u := newSecureUpgrader(t) + tpt, err := New(u, &network.NullResourceManager{}, nil, WithTLSClientConfig(tlsConfig)) + require.NoError(t, err) + + // This can be any wss address. We aren't actually going to dial it. + maToDial := ma.StringCast("/ip4/127.0.0.1/tcp/1/tls/sni/example.com/ws") + _, err = tpt.Dial(context.Background(), maToDial, "") + require.Error(t, err, "This should error as we don't have a real socks server") + + if err := <-proxyServerErr; err != nil { + t.Fatal(err) + } +}