Skip to content

Commit a81effe

Browse files
committed
[FIXED] LeafNode with "wss://.." url was not always initiating TLS
If the remote did not have any TLS configuration, the URL scheme "wss://" was not used as the indicating that the connection should be attempted as a TLS connection, causing "invalid websocket connection" in the server attempting to create the remote leafnode connection. Signed-off-by: Ivan Kozlovic <[email protected]>
1 parent eb8aeb2 commit a81effe

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

server/leafnode.go

+13-4
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,11 @@ func newLeafNodeCfg(remote *RemoteLeafOpts) *leafNodeCfg {
406406
for _, u := range cfg.urls {
407407
cfg.saveTLSHostname(u)
408408
cfg.saveUserPassword(u)
409+
// If the url(s) have the "wss://" scheme, and we don't have a TLS
410+
// config, mark that we should be using TLS anyway.
411+
if !cfg.TLS && isWSURL(u) && strings.HasPrefix(u.Scheme, wsSchemePrefixTLS) {
412+
cfg.TLS = true
413+
}
409414
}
410415
return cfg
411416
}
@@ -1136,10 +1141,14 @@ func (c *client) updateLeafNodeURLs(info *Info) {
11361141
// We have ensured that if a remote has a WS scheme, then all are.
11371142
// So check if first is WS, then add WS URLs, otherwise, add non WS ones.
11381143
if len(cfg.URLs) > 0 && isWSURL(cfg.URLs[0]) {
1139-
// We use wsSchemePrefix. It does not matter if TLS or not since
1140-
// the distinction is done when creating the LN connection based
1141-
// on presence of TLS config, etc..
1142-
c.doUpdateLNURLs(cfg, wsSchemePrefix, info.WSConnectURLs)
1144+
// It does not really matter if we use "ws://" or "wss://" here since
1145+
// we will have already marked that the remote should use TLS anyway.
1146+
// But use proper scheme for log statements, etc...
1147+
proto := wsSchemePrefix
1148+
if cfg.TLS {
1149+
proto = wsSchemePrefixTLS
1150+
}
1151+
c.doUpdateLNURLs(cfg, proto, info.WSConnectURLs)
11431152
return
11441153
}
11451154
c.doUpdateLNURLs(cfg, "nats-leaf", info.LeafNodeURLs)

server/leafnode_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -3172,6 +3172,55 @@ func TestLeafNodeWSNoBufferCorruption(t *testing.T) {
31723172
checkMsgRcv(sub)
31733173
}
31743174

3175+
func TestLeafNodeWSRemoteNoTLSBlockWithWSSProto(t *testing.T) {
3176+
o := testDefaultLeafNodeWSOptions()
3177+
o.Websocket.NoTLS = false
3178+
tc := &TLSConfigOpts{
3179+
CertFile: "../test/configs/certs/server-cert.pem",
3180+
KeyFile: "../test/configs/certs/server-key.pem",
3181+
CaFile: "../test/configs/certs/ca.pem",
3182+
}
3183+
tlsConf, err := GenTLSConfig(tc)
3184+
if err != nil {
3185+
t.Fatalf("Error generating TLS config: %v", err)
3186+
}
3187+
o.Websocket.TLSConfig = tlsConf
3188+
s := RunServer(o)
3189+
defer s.Shutdown()
3190+
3191+
// The test will make sure that if the protocol is "wss://", a TLS handshake must
3192+
// be initiated, regardless of the presence of a TLS config block in config file
3193+
// or here directly.
3194+
// A bug was causing the absence of TLS config block to initiate a non TLS connection
3195+
// even if "wss://" proto was specified, which would lead to "invalid websocket connection"
3196+
// errors in the log.
3197+
// With the fix, the connection will fail because the remote will fail to verify
3198+
// the root CA, but at least, we will make sure that this is not an "invalid websocket connection"
3199+
3200+
u, _ := url.Parse(fmt.Sprintf("wss://127.0.0.1:%d/some/path", o.Websocket.Port))
3201+
lo := DefaultOptions()
3202+
lo.Cluster.Name = "LN"
3203+
remote := &RemoteLeafOpts{URLs: []*url.URL{u}}
3204+
lo.LeafNode.Remotes = []*RemoteLeafOpts{remote}
3205+
lo.LeafNode.ReconnectInterval = 100 * time.Millisecond
3206+
ln := RunServer(lo)
3207+
defer ln.Shutdown()
3208+
3209+
l := &captureErrorLogger{errCh: make(chan string, 10)}
3210+
ln.SetLogger(l, false, false)
3211+
3212+
select {
3213+
case e := <-l.errCh:
3214+
if strings.Contains(e, "invalid websocket connection") {
3215+
t.Fatalf("The remote did not try to create a TLS connection: %v", e)
3216+
}
3217+
// OK!
3218+
return
3219+
case <-time.After(2 * time.Second):
3220+
t.Fatal("Connection should fail")
3221+
}
3222+
}
3223+
31753224
func TestLeafNodeStreamImport(t *testing.T) {
31763225
o1 := DefaultOptions()
31773226
o1.LeafNode.Port = -1

0 commit comments

Comments
 (0)