Skip to content

Commit

Permalink
Merge branch 'master' into marco/bring-go-nat-home
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoPolo authored Jan 28, 2025
2 parents f8bd11c + fde0e3a commit a740446
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 15 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ require (
github.com/pion/webrtc/v4 v4.0.7
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
github.com/quic-go/quic-go v0.48.2
github.com/quic-go/quic-go v0.49.0
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66
github.com/raulk/go-watchdog v1.3.0
github.com/stretchr/testify v1.10.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg=
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
Expand Down
8 changes: 6 additions & 2 deletions p2p/transport/quic/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ type stream struct {
var _ network.MuxedStream = &stream{}

func (s *stream) Read(b []byte) (n int, err error) {
var streamErr *quic.StreamError

n, err = s.Stream.Read(b)
if err != nil && errors.Is(err, &quic.StreamError{}) {
if err != nil && errors.As(err, &streamErr) {
err = network.ErrReset
}
return n, err
}

func (s *stream) Write(b []byte) (n int, err error) {
var streamErr *quic.StreamError

n, err = s.Stream.Write(b)
if err != nil && errors.Is(err, &quic.StreamError{}) {
if err != nil && errors.As(err, &streamErr) {
err = network.ErrReset
}
return n, err
Expand Down
22 changes: 17 additions & 5 deletions p2p/transport/websocket/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -191,7 +193,11 @@ func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (ma
return nil, err
}
isWss := wsurl.Scheme == "wss"
dialer := ws.Dialer{HandshakeTimeout: 30 * time.Second}
dialer := ws.Dialer{
HandshakeTimeout: 30 * time.Second,
// Inherit the default proxy behavior
Proxy: ws.DefaultDialer.Proxy,
}
if isWss {
sni := ""
sni, err = raddr.ValueForProtocol(ma.P_SNI)
Expand All @@ -203,17 +209,23 @@ func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (ma
copytlsClientConf := t.tlsClientConf.Clone()
copytlsClientConf.ServerName = sni
dialer.TLSClientConfig = copytlsClientConf
ipAddr := wsurl.Host
// Setting the NetDial because we already have the resolved IP address, so we don't want to do another resolution.
ipPortAddr := wsurl.Host
// We set the `.Host` to the sni field so that the host header gets properly set.
wsurl.Host = sni + ":" + wsurl.Port()
// Setting the NetDial because we already have the resolved IP address, so we can avoid another resolution.
dialer.NetDial = func(network, address string) (net.Conn, error) {
tcpAddr, err := net.ResolveTCPAddr(network, ipAddr)
var tcpAddr *net.TCPAddr
var err error
if address == wsurl.Host {
tcpAddr, err = net.ResolveTCPAddr(network, ipPortAddr) // Use our already resolved IP address
} else {
tcpAddr, err = net.ResolveTCPAddr(network, address)
}
if err != nil {
return nil, err
}
return net.DialTCP("tcp", nil, tcpAddr)
}
wsurl.Host = sni + ":" + wsurl.Port()
} else {
dialer.TLSClientConfig = t.tlsClientConf
}
Expand Down
75 changes: 75 additions & 0 deletions p2p/transport/websocket/websocket_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package websocket

import (
"bytes"
"context"
"crypto/ecdsa"
"crypto/elliptic"
Expand All @@ -15,10 +16,12 @@ import (
"math/big"
"net"
"net/http"
"net/url"
"strings"
"testing"
"time"

gws "github.com/gorilla/websocket"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
Expand Down Expand Up @@ -548,3 +551,75 @@ func TestResolveMultiaddr(t *testing.T) {
})
}
}

func TestSocksProxy(t *testing.T) {
testCases := []string{
"/ip4/1.2.3.4/tcp/1/ws", // No TLS
"/ip4/1.2.3.4/tcp/1/tls/ws", // TLS no SNI
"/ip4/1.2.3.4/tcp/1/tls/sni/example.com/ws", // TLS with an SNI
}

for _, tc := range testCases {
t.Run(tc, func(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
}
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
}

proxyServerErr <- nil
}()

orig := gws.DefaultDialer.Proxy
defer func() { gws.DefaultDialer.Proxy = orig }()

proxyUrl, err := url.Parse("socks5://" + proxyServer.Addr().String())
require.NoError(t, err)
gws.DefaultDialer.Proxy = http.ProxyURL(proxyUrl)

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(tc)
_, err = tpt.Dial(context.Background(), maToDial, "")
require.ErrorContains(t, err, "failed to read connect reply from SOCKS5 proxy", "This should error as we don't have a real socks server")

select {
case <-time.After(1 * time.Second):
case err := <-proxyServerErr:
if err != nil {
t.Fatal(err)
}
}
})
}
}
11 changes: 10 additions & 1 deletion p2p/transport/webtransport/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ func generateCert(key ic.PrivKey, start, end time.Time) (*x509.Certificate, *ecd
return ca, caPrivateKey, nil
}

type ErrCertHashMismatch struct {
Expected []byte
Actual [][]byte
}

func (e ErrCertHashMismatch) Error() string {
return fmt.Sprintf("cert hash not found: %x (expected: %#x)", e.Expected, e.Actual)
}

func verifyRawCerts(rawCerts [][]byte, certHashes []multihash.DecodedMultihash) error {
if len(rawCerts) < 1 {
return errors.New("no cert")
Expand All @@ -105,7 +114,7 @@ func verifyRawCerts(rawCerts [][]byte, certHashes []multihash.DecodedMultihash)
for _, h := range certHashes {
digests = append(digests, h.Digest)
}
return fmt.Errorf("cert hash not found: %#x (expected: %#x)", hash, digests)
return ErrCertHashMismatch{Expected: hash[:], Actual: digests}
}

cert, err := x509.ParseCertificate(leaf)
Expand Down
6 changes: 5 additions & 1 deletion p2p/transport/webtransport/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,11 @@ func TestHashVerification(t *testing.T) {
var trErr *quic.TransportError
require.ErrorAs(t, err, &trErr)
require.Equal(t, quic.TransportErrorCode(0x12a), trErr.ErrorCode)
require.Contains(t, errors.Unwrap(trErr).Error(), "cert hash not found")
var errMismatchHash libp2pwebtransport.ErrCertHashMismatch
require.ErrorAs(t, err, &errMismatchHash)

e := sha256.Sum256([]byte("foobar"))
require.EqualValues(t, e[:], errMismatchHash.Actual[0])
})

t.Run("fails when adding a wrong hash", func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion test-plans/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ require (
github.com/prometheus/common v0.61.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.48.2 // indirect
github.com/quic-go/quic-go v0.49.0 // indirect
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions test-plans/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg=
github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
Expand Down

0 comments on commit a740446

Please sign in to comment.