WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit cb83b7c

Browse files
[relay] use exposed address for healthcheck TLS validation (#4872)
* fix(relay): use exposed address for healthcheck TLS validation Healthcheck was using listen address (0.0.0.0) instead of exposed address (domain name) for certificate validation, causing validation to always fail. Now correctly uses the exposed address where the TLS certificate is valid, matching real client connection behavior. * - store exposedAddress directly in Relay struct instead of parsing on every call - remove unused parseHostPort() function - remove unused ListenAddress() method from ServiceChecker interface - improve error logging with address context * [relay/healthcheck] Remove QUIC health check logic, update WebSocket validation flow Refactored health check logic by removing QUIC-specific connection validation and simplifying logic for WebSocket protocol. Adjusted certificate validation flow and improved handling of exposed addresses. * [relay/healthcheck] Fix certificate validation status during health check --------- Co-authored-by: Maycon Santos <[email protected]>
1 parent ddcd182 commit cb83b7c

File tree

5 files changed

+46
-76
lines changed

5 files changed

+46
-76
lines changed

relay/healthcheck/healthcheck.go

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import (
66
"errors"
77
"net"
88
"net/http"
9+
"strings"
910
"sync"
1011
"time"
1112

1213
log "github.com/sirupsen/logrus"
1314

1415
"github.com/netbirdio/netbird/relay/protocol"
15-
"github.com/netbirdio/netbird/relay/server/listener/quic"
16-
"github.com/netbirdio/netbird/relay/server/listener/ws"
1716
)
1817

1918
const (
@@ -27,7 +26,7 @@ const (
2726

2827
type ServiceChecker interface {
2928
ListenerProtocols() []protocol.Protocol
30-
ListenAddress() string
29+
ExposedAddress() string
3130
}
3231

3332
type HealthStatus struct {
@@ -135,7 +134,11 @@ func (s *Server) getHealthStatus(ctx context.Context) (*HealthStatus, bool) {
135134
}
136135
status.Listeners = listeners
137136

138-
if ok := s.validateCertificate(ctx); !ok {
137+
if !strings.HasPrefix(s.config.ServiceChecker.ExposedAddress(), "rels") {
138+
status.CertificateValid = false
139+
}
140+
141+
if ok := s.validateConnection(ctx); !ok {
139142
status.Status = statusUnhealthy
140143
status.CertificateValid = false
141144
healthy = false
@@ -152,32 +155,18 @@ func (s *Server) validateListeners() ([]protocol.Protocol, bool) {
152155
return listeners, true
153156
}
154157

155-
func (s *Server) validateCertificate(ctx context.Context) bool {
156-
listenAddress := s.config.ServiceChecker.ListenAddress()
157-
if listenAddress == "" {
158-
log.Warn("listen address is empty")
158+
func (s *Server) validateConnection(ctx context.Context) bool {
159+
exposedAddress := s.config.ServiceChecker.ExposedAddress()
160+
if exposedAddress == "" {
161+
log.Error("exposed address is empty, cannot validate certificate")
159162
return false
160163
}
161164

162-
dAddr := dialAddress(listenAddress)
163-
164-
for _, proto := range s.config.ServiceChecker.ListenerProtocols() {
165-
switch proto {
166-
case ws.Proto:
167-
if err := dialWS(ctx, dAddr); err != nil {
168-
log.Errorf("failed to dial WebSocket listener: %v", err)
169-
return false
170-
}
171-
case quic.Proto:
172-
if err := dialQUIC(ctx, dAddr); err != nil {
173-
log.Errorf("failed to dial QUIC listener: %v", err)
174-
return false
175-
}
176-
default:
177-
log.Warnf("unknown protocol for healthcheck: %s", proto)
178-
return false
179-
}
165+
if err := dialWS(ctx, exposedAddress); err != nil {
166+
log.Errorf("failed to dial WebSocket listener at %s: %v", exposedAddress, err)
167+
return false
180168
}
169+
181170
return true
182171
}
183172

@@ -187,8 +176,9 @@ func dialAddress(listenAddress string) string {
187176
return listenAddress // fallback, might be invalid for dialing
188177
}
189178

179+
// When listening on all interfaces, show localhost for better readability
190180
if host == "" || host == "::" || host == "0.0.0.0" {
191-
host = "0.0.0.0"
181+
host = "localhost"
192182
}
193183

194184
return net.JoinHostPort(host, port)

relay/healthcheck/quic.go

Lines changed: 0 additions & 31 deletions
This file was deleted.

relay/healthcheck/ws.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@ package healthcheck
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
"github.com/coder/websocket"
89

910
"github.com/netbirdio/netbird/shared/relay"
1011
)
1112

1213
func dialWS(ctx context.Context, address string) error {
13-
url := fmt.Sprintf("wss://%s%s", address, relay.WebSocketURLPath)
14+
addressSplit := strings.Split(address, "/")
15+
scheme := "ws"
16+
if addressSplit[0] == "rels:" {
17+
scheme = "wss"
18+
}
19+
url := fmt.Sprintf("%s://%s%s", scheme, addressSplit[2], relay.WebSocketURLPath)
1420

1521
conn, resp, err := websocket.Dial(ctx, url, nil)
1622
if resp != nil {
1723
defer func() {
18-
_ = resp.Body.Close()
24+
if resp.Body != nil {
25+
_ = resp.Body.Close()
26+
}
1927
}()
2028

2129
}

relay/server/relay.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ type Relay struct {
5151
metricsCancel context.CancelFunc
5252
validator Validator
5353

54-
store *store.Store
55-
notifier *store.PeerNotifier
56-
instanceURL string
57-
preparedMsg *preparedMsg
54+
store *store.Store
55+
notifier *store.PeerNotifier
56+
instanceURL string
57+
exposedAddress string
58+
preparedMsg *preparedMsg
5859

5960
closed bool
6061
closeMu sync.RWMutex
@@ -87,12 +88,13 @@ func NewRelay(config Config) (*Relay, error) {
8788
}
8889

8990
r := &Relay{
90-
metrics: m,
91-
metricsCancel: metricsCancel,
92-
validator: config.AuthValidator,
93-
instanceURL: config.instanceURL,
94-
store: store.NewStore(),
95-
notifier: store.NewPeerNotifier(),
91+
metrics: m,
92+
metricsCancel: metricsCancel,
93+
validator: config.AuthValidator,
94+
instanceURL: config.instanceURL,
95+
exposedAddress: config.ExposedAddress,
96+
store: store.NewStore(),
97+
notifier: store.NewPeerNotifier(),
9698
}
9799

98100
r.preparedMsg, err = newPreparedMsg(r.instanceURL)
@@ -178,3 +180,8 @@ func (r *Relay) Shutdown(ctx context.Context) {
178180
func (r *Relay) InstanceURL() string {
179181
return r.instanceURL
180182
}
183+
184+
// ExposedAddress returns the exposed address (domain:port) where clients connect
185+
func (r *Relay) ExposedAddress() string {
186+
return r.exposedAddress
187+
}

relay/server/server.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ type ListenerConfig struct {
2828
// It is the gate between the WebSocket listener and the Relay server logic.
2929
// In a new HTTP connection, the server will accept the connection and pass it to the Relay server via the Accept method.
3030
type Server struct {
31-
listenAddr string
32-
3331
relay *Relay
3432
listeners []listener.Listener
3533
listenerMux sync.Mutex
@@ -62,8 +60,6 @@ func NewServer(config Config) (*Server, error) {
6260

6361
// Listen starts the relay server.
6462
func (r *Server) Listen(cfg ListenerConfig) error {
65-
r.listenAddr = cfg.Address
66-
6763
wSListener := &ws.Listener{
6864
Address: cfg.Address,
6965
TLSConfig: cfg.TLSConfig,
@@ -139,6 +135,6 @@ func (r *Server) ListenerProtocols() []protocol.Protocol {
139135
return result
140136
}
141137

142-
func (r *Server) ListenAddress() string {
143-
return r.listenAddr
138+
func (r *Server) ExposedAddress() string {
139+
return r.relay.ExposedAddress()
144140
}

0 commit comments

Comments
 (0)