diff --git a/client/internal/peer/handshaker.go b/client/internal/peer/handshaker.go index c8dc7c905..1d44096b6 100644 --- a/client/internal/peer/handshaker.go +++ b/client/internal/peer/handshaker.go @@ -42,7 +42,7 @@ type OfferAnswer struct { // relay server address RelaySrvAddress string // RelaySrvIP is the IP the remote peer is connected to on its - // relay server. Used as a fallback dial target if DNS for RelaySrvAddress + // relay server. Used as a dial target if DNS for RelaySrvAddress // fails. Zero value if the peer did not advertise an IP. RelaySrvIP netip.Addr // SessionID is the unique identifier of the session, used to discard old messages @@ -222,9 +222,9 @@ func (h *Handshaker) buildOfferAnswer() OfferAnswer { answer.SessionID = &sid } - if addr, err := h.relay.RelayInstanceAddress(); err == nil { + if addr, ip, err := h.relay.RelayInstanceAddress(); err == nil { answer.RelaySrvAddress = addr - answer.RelaySrvIP = h.relay.RelayInstanceIP() + answer.RelaySrvIP = ip } return answer diff --git a/client/internal/peer/status.go b/client/internal/peer/status.go index abedc208e..7bd19b0e1 100644 --- a/client/internal/peer/status.go +++ b/client/internal/peer/status.go @@ -919,7 +919,7 @@ func (d *Status) GetRelayStates() []relay.ProbeResult { // if the server connection is not established then we will use the general address // in case of connection we will use the instance specific address - instanceAddr, err := d.relayMgr.RelayInstanceAddress() + instanceAddr, _, err := d.relayMgr.RelayInstanceAddress() if err != nil { // TODO add their status for _, r := range d.relayMgr.ServerURLs() { diff --git a/client/internal/peer/worker_relay.go b/client/internal/peer/worker_relay.go index e8c1d68cd..0402992c9 100644 --- a/client/internal/peer/worker_relay.go +++ b/client/internal/peer/worker_relay.go @@ -54,19 +54,19 @@ func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *OfferAnswer) { w.relaySupportedOnRemotePeer.Store(true) // the relayManager will return with error in case if the connection has lost with relay server - currentRelayAddress, err := w.relayManager.RelayInstanceAddress() + currentRelayAddress, _, err := w.relayManager.RelayInstanceAddress() if err != nil { w.log.Errorf("failed to handle new offer: %s", err) return } srv := w.preferredRelayServer(currentRelayAddress, remoteOfferAnswer.RelaySrvAddress) - var fallbackIP netip.Addr + var serverIP netip.Addr if srv == remoteOfferAnswer.RelaySrvAddress { - fallbackIP = remoteOfferAnswer.RelaySrvIP + serverIP = remoteOfferAnswer.RelaySrvIP } - relayedConn, err := w.relayManager.OpenConn(w.peerCtx, srv, w.config.Key, fallbackIP) + relayedConn, err := w.relayManager.OpenConn(w.peerCtx, srv, w.config.Key, serverIP) if err != nil { if errors.Is(err, relayClient.ErrConnAlreadyExists) { w.log.Debugf("handled offer by reusing existing relay connection") @@ -95,14 +95,10 @@ func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *OfferAnswer) { }) } -func (w *WorkerRelay) RelayInstanceAddress() (string, error) { +func (w *WorkerRelay) RelayInstanceAddress() (string, netip.Addr, error) { return w.relayManager.RelayInstanceAddress() } -func (w *WorkerRelay) RelayInstanceIP() netip.Addr { - return w.relayManager.RelayInstanceIP() -} - func (w *WorkerRelay) IsRelayConnectionSupportedWithPeer() bool { return w.relaySupportedOnRemotePeer.Load() && w.RelayIsSupportedLocally() } diff --git a/relay/test/benchmark_test.go b/relay/test/benchmark_test.go index 117a1e500..9dd189776 100644 --- a/relay/test/benchmark_test.go +++ b/relay/test/benchmark_test.go @@ -102,7 +102,7 @@ func transfer(t *testing.T, testData []byte, peerPairs int) { clientsSender := make([]*client.Client, peerPairs) for i := 0; i < cap(clientsSender); i++ { - c := client.NewClient(serverConnURL, netip.Addr{}, hmacTokenStore, "sender-"+fmt.Sprint(i), iface.DefaultMTU) + c := client.NewClient(serverConnURL, hmacTokenStore, "sender-"+fmt.Sprint(i), iface.DefaultMTU) err := c.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -112,7 +112,7 @@ func transfer(t *testing.T, testData []byte, peerPairs int) { clientsReceiver := make([]*client.Client, peerPairs) for i := 0; i < cap(clientsReceiver); i++ { - c := client.NewClient(serverConnURL, netip.Addr{}, hmacTokenStore, "receiver-"+fmt.Sprint(i), iface.DefaultMTU) + c := client.NewClient(serverConnURL, hmacTokenStore, "receiver-"+fmt.Sprint(i), iface.DefaultMTU) err := c.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) diff --git a/relay/testec2/relay.go b/relay/testec2/relay.go index 6b0c1cba6..e6924061f 100644 --- a/relay/testec2/relay.go +++ b/relay/testec2/relay.go @@ -6,7 +6,6 @@ import ( "context" "fmt" "net" - "net/netip" "sync" "time" @@ -72,7 +71,7 @@ func prepareConnsSender(serverConnURL string, peerPairs int) []net.Conn { ctx := context.Background() clientsSender := make([]*client.Client, peerPairs) for i := 0; i < cap(clientsSender); i++ { - c := client.NewClient(serverConnURL, netip.Addr{}, hmacTokenStore, "sender-"+fmt.Sprint(i), iface.DefaultMTU) + c := client.NewClient(serverConnURL, hmacTokenStore, "sender-"+fmt.Sprint(i), iface.DefaultMTU) if err := c.Connect(ctx); err != nil { log.Fatalf("failed to connect to server: %s", err) } @@ -158,7 +157,7 @@ func runReader(conn net.Conn) time.Duration { func prepareConnsReceiver(serverConnURL string, peerPairs int) []net.Conn { clientsReceiver := make([]*client.Client, peerPairs) for i := 0; i < cap(clientsReceiver); i++ { - c := client.NewClient(serverConnURL, netip.Addr{}, hmacTokenStore, "receiver-"+fmt.Sprint(i), iface.DefaultMTU) + c := client.NewClient(serverConnURL, hmacTokenStore, "receiver-"+fmt.Sprint(i), iface.DefaultMTU) err := c.Connect(context.Background()) if err != nil { log.Fatalf("failed to connect to server: %s", err) diff --git a/shared/relay/client/client.go b/shared/relay/client/client.go index 069665a32..e4b586ce6 100644 --- a/shared/relay/client/client.go +++ b/shared/relay/client/client.go @@ -150,7 +150,7 @@ func (cc *connContainer) close() { type Client struct { log *log.Entry connectionURL string - fallbackIP netip.Addr + serverIP netip.Addr authTokenStore *auth.TokenStore hashedID messages.PeerID @@ -175,16 +175,21 @@ type Client struct { } // NewClient creates a new client for the relay server. The client is not connected to the server until the Connect -// is called. fallbackIP, when valid, is used as a dial-time fallback if the FQDN-based dial fails. TLS -// verification still uses the FQDN from serverURL via SNI. -func NewClient(serverURL string, fallbackIP netip.Addr, authTokenStore *auth.TokenStore, peerID string, mtu uint16) *Client { +// is called. +func NewClient(serverURL string, authTokenStore *auth.TokenStore, peerID string, mtu uint16) *Client { + return NewClientWithServerIP(serverURL, netip.Addr{}, authTokenStore, peerID, mtu) +} + +// NewClientWithServerIP creates a new client for the relay server with a known server IP. serverIP, when valid, is +// used as a dial target if the FQDN-based dial fails. TLS verification still uses the FQDN from serverURL via SNI. +func NewClientWithServerIP(serverURL string, serverIP netip.Addr, authTokenStore *auth.TokenStore, peerID string, mtu uint16) *Client { hashedID := messages.HashID(peerID) relayLog := log.WithFields(log.Fields{"relay": serverURL}) c := &Client{ log: relayLog, connectionURL: serverURL, - fallbackIP: fallbackIP, + serverIP: serverIP, authTokenStore: authTokenStore, hashedID: hashedID, mtu: mtu, @@ -378,11 +383,11 @@ func (c *Client) connect(ctx context.Context) (*RelayAddr, error) { rd := dialer.NewRaceDial(c.log, dialer.DefaultConnectionTimeout, c.connectionURL, dialers...) conn, err := rd.Dial(ctx) if err != nil { - fallbackConn, fbErr := c.dialFallback(ctx, dialers) - if fbErr != nil { - return nil, fmt.Errorf("primary dial: %w; fallback dial: %w", err, fbErr) + directConn, dErr := c.dialDirect(ctx, dialers) + if dErr != nil { + return nil, fmt.Errorf("dial via FQDN: %w; dial via server IP: %w", err, dErr) } - conn = fallbackConn + conn = directConn } c.relayConn = conn @@ -398,22 +403,21 @@ func (c *Client) connect(ctx context.Context) (*RelayAddr, error) { return instanceURL, nil } -// dialFallback retries the dial against c.fallbackIP, preserving the -// original FQDN as the TLS ServerName for SNI. Returns an error if no -// fallback IP is configured or if the substituted URL is malformed. -func (c *Client) dialFallback(ctx context.Context, dialers []dialer.DialeFn) (net.Conn, error) { - if !c.fallbackIP.IsValid() || c.fallbackIP.IsUnspecified() { - return nil, errors.New("no usable fallback IP configured") +// dialDirect retries the dial against c.serverIP, preserving the original FQDN as the TLS ServerName for SNI. +// Returns an error if no usable server IP is configured or if the substituted URL is malformed. +func (c *Client) dialDirect(ctx context.Context, dialers []dialer.DialeFn) (net.Conn, error) { + if !c.serverIP.IsValid() || c.serverIP.IsUnspecified() { + return nil, errors.New("no usable server IP configured") } - fallbackURL, serverName, err := substituteHost(c.connectionURL, c.fallbackIP) + directURL, serverName, err := substituteHost(c.connectionURL, c.serverIP) if err != nil { return nil, fmt.Errorf("substitute host: %w", err) } - c.log.Infof("primary dial failed, retrying via fallback IP %s (SNI=%s)", c.fallbackIP, serverName) + c.log.Infof("FQDN dial failed, retrying via server IP %s (SNI=%s)", c.serverIP, serverName) - rd := dialer.NewRaceDial(c.log, dialer.DefaultConnectionTimeout, fallbackURL, dialers...). + rd := dialer.NewRaceDial(c.log, dialer.DefaultConnectionTimeout, directURL, dialers...). WithServerName(serverName) return rd.Dial(ctx) } @@ -431,7 +435,7 @@ func substituteHost(serverURL string, ip netip.Addr) (string, string, error) { return "", "", fmt.Errorf("invalid relay URL %q", serverURL) } if !ip.IsValid() { - return "", "", errors.New("invalid fallback IP") + return "", "", errors.New("invalid server IP") } origHost := u.Hostname() if _, err := netip.ParseAddr(origHost); err == nil { diff --git a/shared/relay/client/client_fallback_test.go b/shared/relay/client/client_serverip_test.go similarity index 88% rename from shared/relay/client/client_fallback_test.go rename to shared/relay/client/client_serverip_test.go index 677fc5189..7e699e37d 100644 --- a/shared/relay/client/client_fallback_test.go +++ b/shared/relay/client/client_serverip_test.go @@ -15,10 +15,10 @@ import ( "github.com/netbirdio/netbird/shared/relay/auth/allow" ) -// TestClient_FallbackIPRecoversFromUnresolvableFQDN verifies that when the +// TestClient_ServerIPRecoversFromUnresolvableFQDN verifies that when the // primary FQDN-based dial fails (unresolvable .invalid host), Connect -// recovers via the fallback IP and SNI still uses the FQDN. -func TestClient_FallbackIPRecoversFromUnresolvableFQDN(t *testing.T) { +// recovers via the server IP and SNI still uses the FQDN. +func TestClient_ServerIPRecoversFromUnresolvableFQDN(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() @@ -49,19 +49,19 @@ func TestClient_FallbackIPRecoversFromUnresolvableFQDN(t *testing.T) { t.Fatalf("server failed to start: %s", err) } - t.Run("no fallback IP, primary fails", func(t *testing.T) { - c := NewClient(srvCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice-nofallback", iface.DefaultMTU) + t.Run("no server IP, primary fails", func(t *testing.T) { + c := NewClient(srvCfg.ExposedAddress, hmacTokenStore, "alice-noip", iface.DefaultMTU) err := c.Connect(ctx) if err == nil { _ = c.Close() - t.Fatalf("expected connect to fail without fallback IP, got nil") + t.Fatalf("expected connect to fail without server IP, got nil") } }) - t.Run("fallback IP recovers", func(t *testing.T) { - c := NewClient(srvCfg.ExposedAddress, netip.MustParseAddr("127.0.0.1"), hmacTokenStore, "alice-fallback", iface.DefaultMTU) + t.Run("server IP recovers", func(t *testing.T) { + c := NewClientWithServerIP(srvCfg.ExposedAddress, netip.MustParseAddr("127.0.0.1"), hmacTokenStore, "alice-with-ip", iface.DefaultMTU) if err := c.Connect(ctx); err != nil { - t.Fatalf("connect with fallback IP: %s", err) + t.Fatalf("connect with server IP: %s", err) } t.Cleanup(func() { _ = c.Close() }) @@ -77,7 +77,7 @@ func TestClient_FallbackIPRecoversFromUnresolvableFQDN(t *testing.T) { // TestClient_ConnectedIPAfterFQDNDial verifies ConnectedIP returns the // resolved IP after a successful FQDN-based dial. The underlying socket's // RemoteAddr must be exposed through the dialer wrappers; if it returns -// the dial-time URL instead, ConnectedIP returns empty and the fallback +// the dial-time URL instead, ConnectedIP returns empty and the dial // IP we advertise to peers is empty too. func TestClient_ConnectedIPAfterFQDNDial(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) @@ -105,7 +105,7 @@ func TestClient_ConnectedIPAfterFQDNDial(t *testing.T) { t.Fatalf("server failed to start: %s", err) } - c := NewClient(srvCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice-fqdn", iface.DefaultMTU) + c := NewClient(srvCfg.ExposedAddress, hmacTokenStore, "alice-fqdn", iface.DefaultMTU) if err := c.Connect(ctx); err != nil { t.Fatalf("connect: %s", err) } @@ -141,7 +141,7 @@ func TestSubstituteHost(t *testing.T) { wantServerName: "relay.example.com", }, { - name: "ipv6 fallback bracketed", + name: "ipv6 server IP bracketed", serverURL: "rels://relay.example.com:443", ip: "2001:db8::1", wantURL: "rels://[2001:db8::1]:443", @@ -169,7 +169,7 @@ func TestSubstituteHost(t *testing.T) { wantServerName: "", }, { - name: "ipv6 fallback no port", + name: "ipv6 server IP no port", serverURL: "rels://relay.example.com", ip: "2001:db8::1", wantURL: "rels://[2001:db8::1]", @@ -215,7 +215,7 @@ func TestSubstituteHost(t *testing.T) { } func TestClient_ConnectedIPEmptyWhenNotConnected(t *testing.T) { - c := NewClient("rel://example.invalid:80", netip.Addr{}, hmacTokenStore, "x", iface.DefaultMTU) + c := NewClient("rel://example.invalid:80", hmacTokenStore, "x", iface.DefaultMTU) if got := c.ConnectedIP(); got.IsValid() { t.Fatalf("ConnectedIP on disconnected client = %q, want zero", got) } diff --git a/shared/relay/client/client_test.go b/shared/relay/client/client_test.go index 8043252e9..9820d642f 100644 --- a/shared/relay/client/client_test.go +++ b/shared/relay/client/client_test.go @@ -3,7 +3,6 @@ package client import ( "context" "net" - "net/netip" "os" "testing" "time" @@ -69,7 +68,7 @@ func TestClient(t *testing.T) { t.Fatalf("failed to start server: %s", err) } t.Log("alice connecting to server") - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -77,7 +76,7 @@ func TestClient(t *testing.T) { defer clientAlice.Close() t.Log("placeholder connecting to server") - clientPlaceHolder := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "clientPlaceHolder", iface.DefaultMTU) + clientPlaceHolder := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "clientPlaceHolder", iface.DefaultMTU) err = clientPlaceHolder.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -85,7 +84,7 @@ func TestClient(t *testing.T) { defer clientPlaceHolder.Close() t.Log("Bob connecting to server") - clientBob := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "bob", iface.DefaultMTU) + clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU) err = clientBob.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -145,7 +144,7 @@ func TestRegistration(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { _ = srv.Shutdown(ctx) @@ -185,7 +184,7 @@ func TestRegistrationTimeout(t *testing.T) { _ = fakeTCPListener.Close() }(fakeTCPListener) - clientAlice := NewClient("127.0.0.1:50201", netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient("127.0.0.1:50201", hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err == nil { t.Errorf("failed to connect to server: %s", err) @@ -228,7 +227,7 @@ func TestEcho(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, idAlice, iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -240,7 +239,7 @@ func TestEcho(t *testing.T) { } }() - clientBob := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, idBob, iface.DefaultMTU) + clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idBob, iface.DefaultMTU) err = clientBob.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -320,7 +319,7 @@ func TestBindToUnavailabePeer(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Errorf("failed to connect to server: %s", err) @@ -368,13 +367,13 @@ func TestBindReconnect(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) } - clientBob := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "bob", iface.DefaultMTU) + clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU) err = clientBob.Connect(ctx) if err != nil { t.Errorf("failed to connect to server: %s", err) @@ -396,7 +395,7 @@ func TestBindReconnect(t *testing.T) { t.Errorf("failed to close client: %s", err) } - clientAlice = NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice = NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Errorf("failed to connect to server: %s", err) @@ -471,13 +470,13 @@ func TestCloseConn(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - bob := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "bob", iface.DefaultMTU) + bob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU) err = bob.Connect(ctx) if err != nil { t.Errorf("failed to connect to server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Errorf("failed to connect to server: %s", err) @@ -535,13 +534,13 @@ func TestCloseRelayConn(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - bob := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "bob", iface.DefaultMTU) + bob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU) err = bob.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, "alice", iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -591,7 +590,7 @@ func TestCloseByServer(t *testing.T) { idAlice := "alice" log.Debugf("connect by alice") - relayClient := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, idAlice, iface.DefaultMTU) + relayClient := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU) if err = relayClient.Connect(ctx); err != nil { log.Fatalf("failed to connect to server: %s", err) } @@ -649,7 +648,7 @@ func TestCloseByClient(t *testing.T) { idAlice := "alice" log.Debugf("connect by alice") - relayClient := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, idAlice, iface.DefaultMTU) + relayClient := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU) err = relayClient.Connect(ctx) if err != nil { log.Fatalf("failed to connect to server: %s", err) @@ -702,7 +701,7 @@ func TestCloseNotDrainedChannel(t *testing.T) { t.Fatalf("failed to start server: %s", err) } - clientAlice := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, idAlice, iface.DefaultMTU) + clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU) err = clientAlice.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) @@ -714,7 +713,7 @@ func TestCloseNotDrainedChannel(t *testing.T) { } }() - clientBob := NewClient(serverCfg.ExposedAddress, netip.Addr{}, hmacTokenStore, idBob, iface.DefaultMTU) + clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idBob, iface.DefaultMTU) err = clientBob.Connect(ctx) if err != nil { t.Fatalf("failed to connect to server: %s", err) diff --git a/shared/relay/client/manager.go b/shared/relay/client/manager.go index e1732258a..6a219914f 100644 --- a/shared/relay/client/manager.go +++ b/shared/relay/client/manager.go @@ -132,9 +132,9 @@ func (m *Manager) Serve() error { // established via the relay server. If the peer is on a different relay server, the manager will establish a new // connection to the relay server. It returns back with a net.Conn what represent the remote peer connection. // -// fallbackIP, when valid and serverAddress is foreign, is used as a dial-time fallback if the FQDN-based -// dial fails. Ignored for the local home-server path. TLS verification still uses the FQDN via SNI. -func (m *Manager) OpenConn(ctx context.Context, serverAddress, peerKey string, fallbackIP netip.Addr) (net.Conn, error) { +// serverIP, when valid and serverAddress is foreign, is used as a dial target if the FQDN-based dial fails. +// Ignored for the local home-server path. TLS verification still uses the FQDN via SNI. +func (m *Manager) OpenConn(ctx context.Context, serverAddress, peerKey string, serverIP netip.Addr) (net.Conn, error) { m.relayClientMu.RLock() defer m.relayClientMu.RUnlock() @@ -155,7 +155,7 @@ func (m *Manager) OpenConn(ctx context.Context, serverAddress, peerKey string, f netConn, err = m.relayClient.OpenConn(ctx, peerKey) } else { log.Debugf("open peer connection via foreign server: %s", serverAddress) - netConn, err = m.openConnVia(ctx, serverAddress, peerKey, fallbackIP) + netConn, err = m.openConnVia(ctx, serverAddress, peerKey, serverIP) } if err != nil { return nil, err @@ -207,29 +207,22 @@ func (m *Manager) AddCloseListener(serverAddress string, onClosedListener OnServ return nil } -// RelayInstanceAddress returns the address of the permanent relay server. It could change if the network connection is -// lost. This address will be sent to the target peer to choose the common relay server for the communication. -func (m *Manager) RelayInstanceAddress() (string, error) { +// RelayInstanceAddress returns the address and resolved IP of the permanent relay server. It could change if the +// network connection is lost. The address is sent to the target peer to choose the common relay server for the +// communication; the IP is sent alongside so remote peers can dial directly without their own DNS lookup. Both +// values are read under the same lock so they cannot diverge across a reconnection. +func (m *Manager) RelayInstanceAddress() (string, netip.Addr, error) { m.relayClientMu.RLock() defer m.relayClientMu.RUnlock() if m.relayClient == nil { - return "", ErrRelayClientNotConnected + return "", netip.Addr{}, ErrRelayClientNotConnected } - return m.relayClient.ServerInstanceURL() -} - -// RelayInstanceIP returns the IP address of the live home relay connection. -// Zero value if not connected. Sent alongside RelayInstanceAddress so remote -// peers can dial directly without their own DNS lookup. -func (m *Manager) RelayInstanceIP() netip.Addr { - m.relayClientMu.RLock() - defer m.relayClientMu.RUnlock() - - if m.relayClient == nil { - return netip.Addr{} + addr, err := m.relayClient.ServerInstanceURL() + if err != nil { + return "", netip.Addr{}, err } - return m.relayClient.ConnectedIP() + return addr, m.relayClient.ConnectedIP(), nil } // ServerURLs returns the addresses of the relay servers. @@ -253,7 +246,7 @@ func (m *Manager) UpdateToken(token *relayAuth.Token) error { return m.tokenStore.UpdateToken(token) } -func (m *Manager) openConnVia(ctx context.Context, serverAddress, peerKey string, fallbackIP netip.Addr) (net.Conn, error) { +func (m *Manager) openConnVia(ctx context.Context, serverAddress, peerKey string, serverIP netip.Addr) (net.Conn, error) { // check if already has a connection to the desired relay server m.relayClientsMutex.RLock() rt, ok := m.relayClients[serverAddress] @@ -288,7 +281,7 @@ func (m *Manager) openConnVia(ctx context.Context, serverAddress, peerKey string m.relayClients[serverAddress] = rt m.relayClientsMutex.Unlock() - relayClient := NewClient(serverAddress, fallbackIP, m.tokenStore, m.peerID, m.mtu) + relayClient := NewClientWithServerIP(serverAddress, serverIP, m.tokenStore, m.peerID, m.mtu) err := relayClient.Connect(m.ctx) if err != nil { rt.err = err diff --git a/shared/relay/client/manager_fallback_test.go b/shared/relay/client/manager_serverip_test.go similarity index 83% rename from shared/relay/client/manager_fallback_test.go rename to shared/relay/client/manager_serverip_test.go index 97d4d6185..a4b91b1a0 100644 --- a/shared/relay/client/manager_fallback_test.go +++ b/shared/relay/client/manager_serverip_test.go @@ -10,12 +10,12 @@ import ( "github.com/netbirdio/netbird/relay/server" ) -// TestManager_ForeignRelayFallbackIP exercises the foreign-relay path +// TestManager_ForeignRelayServerIP exercises the foreign-relay path // end-to-end through Manager.OpenConn. Alice and Bob register on different // relay servers; Alice dials Bob's foreign relay using an unresolvable -// FQDN. Without a fallback IP the dial fails; with Bob's advertised IP it +// FQDN. Without a server IP the dial fails; with Bob's advertised IP it // recovers and a payload round-trips between the peers. -func TestManager_ForeignRelayFallbackIP(t *testing.T) { +func TestManager_ForeignRelayServerIP(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() @@ -66,14 +66,11 @@ func TestManager_ForeignRelayFallbackIP(t *testing.T) { t.Fatalf("bob manager serve: %s", err) } - // Bob's real relay URL (what mgrBob.RelayInstanceAddress returns). - bobRealAddr, err := mgrBob.RelayInstanceAddress() + // Bob's real relay URL and the IP that would ride along in signal as relayServerIP. + bobRealAddr, bobAdvertisedIP, err := mgrBob.RelayInstanceAddress() if err != nil { t.Fatalf("bob relay address: %s", err) } - // What Bob's RelayInstanceIP() reports — this is the field that - // would ride along in signal as relayServerIP. - bobAdvertisedIP := mgrBob.RelayInstanceIP() if !bobAdvertisedIP.IsValid() { t.Fatalf("expected valid RelayInstanceIP for bob, got zero") } @@ -84,16 +81,16 @@ func TestManager_ForeignRelayFallbackIP(t *testing.T) { t.Fatalf("broken FQDN must differ from bob's real address (%s)", bobRealAddr) } - t.Run("no fallback IP, dial fails", func(t *testing.T) { + t.Run("no server IP, dial fails", func(t *testing.T) { dialCtx, dialCancel := context.WithTimeout(ctx, 5*time.Second) defer dialCancel() _, err := mgrAlice.OpenConn(dialCtx, brokenFQDN, "bob", netip.Addr{}) if err == nil { - t.Fatalf("expected OpenConn to fail without fallback IP, got success") + t.Fatalf("expected OpenConn to fail without server IP, got success") } }) - t.Run("fallback IP recovers", func(t *testing.T) { + t.Run("server IP recovers", func(t *testing.T) { // Bob waits for Alice's incoming peer connection on his side. bobSideCh := make(chan error, 1) go func() { @@ -117,7 +114,7 @@ func TestManager_ForeignRelayFallbackIP(t *testing.T) { aliceConn, err := mgrAlice.OpenConn(ctx, brokenFQDN, "bob", bobAdvertisedIP) if err != nil { - t.Fatalf("alice OpenConn with fallback IP: %s", err) + t.Fatalf("alice OpenConn with server IP: %s", err) } t.Cleanup(func() { _ = aliceConn.Close() }) diff --git a/shared/relay/client/manager_test.go b/shared/relay/client/manager_test.go index 754dde4ac..9e964f688 100644 --- a/shared/relay/client/manager_test.go +++ b/shared/relay/client/manager_test.go @@ -2,8 +2,8 @@ package client import ( "context" - "net/netip" "fmt" + "net/netip" "testing" "time" @@ -102,7 +102,7 @@ func TestForeignConn(t *testing.T) { if err := clientBob.Serve(); err != nil { t.Fatalf("failed to serve manager: %s", err) } - bobsSrvAddr, err := clientBob.RelayInstanceAddress() + bobsSrvAddr, _, err := clientBob.RelayInstanceAddress() if err != nil { t.Fatalf("failed to get relay address: %s", err) } @@ -368,7 +368,7 @@ func TestAutoReconnect(t *testing.T) { if err != nil { t.Fatalf("failed to serve manager: %s", err) } - ra, err := clientAlice.RelayInstanceAddress() + ra, _, err := clientAlice.RelayInstanceAddress() if err != nil { t.Errorf("failed to get relay address: %s", err) } diff --git a/shared/relay/client/picker.go b/shared/relay/client/picker.go index e096a7a38..39d0ba072 100644 --- a/shared/relay/client/picker.go +++ b/shared/relay/client/picker.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "net/netip" "sync/atomic" "time" @@ -70,7 +69,7 @@ func (sp *ServerPicker) PickServer(parentCtx context.Context) (*Client, error) { func (sp *ServerPicker) startConnection(ctx context.Context, resultChan chan connResult, url string) { log.Infof("try to connecting to relay server: %s", url) - relayClient := NewClient(url, netip.Addr{}, sp.TokenStore, sp.PeerID, sp.MTU) + relayClient := NewClient(url, sp.TokenStore, sp.PeerID, sp.MTU) err := relayClient.Connect(ctx) resultChan <- connResult{ RelayClient: relayClient, diff --git a/shared/signal/client/client.go b/shared/signal/client/client.go index 8e5eb6b5a..9dc6ccd37 100644 --- a/shared/signal/client/client.go +++ b/shared/signal/client/client.go @@ -72,25 +72,26 @@ func UnMarshalCredential(msg *proto.Message) (*Credential, error) { // MarshalCredential marshal a Credential instance and returns a Message object func MarshalCredential(myKey wgtypes.Key, remoteKey string, p CredentialPayload) (*proto.Message, error) { - var relayIPBytes []byte + body := &proto.Body{ + Type: p.Type, + Payload: fmt.Sprintf("%s:%s", p.Credential.UFrag, p.Credential.Pwd), + WgListenPort: uint32(p.WgListenPort), + NetBirdVersion: version.NetbirdVersion(), + RosenpassConfig: &proto.RosenpassConfig{ + RosenpassPubKey: p.RosenpassPubKey, + RosenpassServerAddr: p.RosenpassAddr, + }, + SessionId: p.SessionID, + } + if p.RelaySrvAddress != "" { + body.RelayServerAddress = &p.RelaySrvAddress + } if p.RelaySrvIP.IsValid() { - relayIPBytes = p.RelaySrvIP.Unmap().AsSlice() + body.RelayServerIP = p.RelaySrvIP.Unmap().AsSlice() } return &proto.Message{ Key: myKey.PublicKey().String(), RemoteKey: remoteKey, - Body: &proto.Body{ - Type: p.Type, - Payload: fmt.Sprintf("%s:%s", p.Credential.UFrag, p.Credential.Pwd), - WgListenPort: uint32(p.WgListenPort), - NetBirdVersion: version.NetbirdVersion(), - RosenpassConfig: &proto.RosenpassConfig{ - RosenpassPubKey: p.RosenpassPubKey, - RosenpassServerAddr: p.RosenpassAddr, - }, - RelayServerAddress: p.RelaySrvAddress, - RelayServerIP: relayIPBytes, - SessionId: p.SessionID, - }, + Body: body, }, nil } diff --git a/shared/signal/proto/signalexchange.pb.go b/shared/signal/proto/signalexchange.pb.go index f7fe24bf8..9afa5d714 100644 --- a/shared/signal/proto/signalexchange.pb.go +++ b/shared/signal/proto/signalexchange.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.21.12 +// protoc v7.34.1 // source: signalexchange.proto package proto @@ -229,13 +229,13 @@ type Body struct { // RosenpassConfig is a Rosenpass config of the remote peer our peer tries to connect to RosenpassConfig *RosenpassConfig `protobuf:"bytes,7,opt,name=rosenpassConfig,proto3" json:"rosenpassConfig,omitempty"` // relayServerAddress is url of the relay server - RelayServerAddress string `protobuf:"bytes,8,opt,name=relayServerAddress,proto3" json:"relayServerAddress,omitempty"` - SessionId []byte `protobuf:"bytes,10,opt,name=sessionId,proto3,oneof" json:"sessionId,omitempty"` + RelayServerAddress *string `protobuf:"bytes,8,opt,name=relayServerAddress,proto3,oneof" json:"relayServerAddress,omitempty"` + SessionId []byte `protobuf:"bytes,10,opt,name=sessionId,proto3,oneof" json:"sessionId,omitempty"` // relayServerIP is the IP the sender is connected to on its relay server, // encoded as 4 bytes (IPv4) or 16 bytes (IPv6). Receivers may use it as a // fallback dial target when DNS resolution of relayServerAddress fails. // SNI/TLS verification still uses relayServerAddress. - RelayServerIP []byte `protobuf:"bytes,11,opt,name=relayServerIP,proto3" json:"relayServerIP,omitempty"` + RelayServerIP []byte `protobuf:"bytes,11,opt,name=relayServerIP,proto3,oneof" json:"relayServerIP,omitempty"` } func (x *Body) Reset() { @@ -320,8 +320,8 @@ func (x *Body) GetRosenpassConfig() *RosenpassConfig { } func (x *Body) GetRelayServerAddress() string { - if x != nil { - return x.RelayServerAddress + if x != nil && x.RelayServerAddress != nil { + return *x.RelayServerAddress } return "" } @@ -463,7 +463,7 @@ var file_signalexchange_proto_rawDesc = []byte{ 0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, - 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2d, + 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xc3, 0x04, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, @@ -483,43 +483,46 @@ var file_signalexchange_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x33, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x6c, - 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x50, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x50, 0x22, - 0x43, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x46, 0x46, 0x45, 0x52, - 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x53, 0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0d, - 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x44, 0x49, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, - 0x04, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x4f, 0x5f, 0x49, 0x44, - 0x4c, 0x45, 0x10, 0x05, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x2e, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, - 0x12, 0x1b, 0x0a, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x48, 0x00, 0x52, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, - 0x07, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x6d, 0x0a, 0x0f, 0x52, 0x6f, 0x73, 0x65, - 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x72, - 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, - 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, - 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x32, 0xb9, 0x01, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x04, 0x53, 0x65, - 0x6e, 0x64, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, - 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, + 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x29, + 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x50, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x49, 0x50, 0x88, 0x01, 0x01, 0x22, 0x43, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, + 0x41, 0x4e, 0x53, 0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x44, + 0x49, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4f, 0x44, 0x45, 0x10, + 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x4f, 0x5f, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x05, 0x42, 0x15, + 0x0a, 0x13, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x49, 0x50, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x2e, 0x0a, 0x04, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, + 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x6d, 0x0a, 0x0f, 0x52, + 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, + 0x0a, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, + 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x6f, 0x73, 0x65, + 0x6e, 0x70, 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x32, 0xb9, 0x01, 0x0a, 0x0e, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x4c, 0x0a, + 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0d, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x20, 0x2e, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, + 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, + 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/shared/signal/proto/signalexchange.proto b/shared/signal/proto/signalexchange.proto index 06817e658..96a4001e3 100644 --- a/shared/signal/proto/signalexchange.proto +++ b/shared/signal/proto/signalexchange.proto @@ -63,7 +63,7 @@ message Body { RosenpassConfig rosenpassConfig = 7; // relayServerAddress is url of the relay server - string relayServerAddress = 8; + optional string relayServerAddress = 8; reserved 9; @@ -73,7 +73,7 @@ message Body { // encoded as 4 bytes (IPv4) or 16 bytes (IPv6). Receivers may use it as a // fallback dial target when DNS resolution of relayServerAddress fails. // SNI/TLS verification still uses relayServerAddress. - bytes relayServerIP = 11; + optional bytes relayServerIP = 11; } // Mode indicates a connection mode