Fix resetting TLS name from solicited remotes

In +Go 1.20, the x509.HostnameError changed to be wrapped in a
tls.CertificateVerificationError so sometimes the name would not
be reset causing tests to be extra flaky.

Signed-off-by: Waldemar Quevedo <wally@nats.io>
This commit is contained in:
Waldemar Quevedo
2023-08-28 10:09:46 -07:00
parent f50b772a14
commit d366027bbf
2 changed files with 88 additions and 78 deletions

View File

@@ -18,6 +18,7 @@ import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"math/rand" "math/rand"
@@ -33,7 +34,6 @@ import (
"time" "time"
"github.com/klauspost/compress/s2" "github.com/klauspost/compress/s2"
"github.com/nats-io/jwt/v2" "github.com/nats-io/jwt/v2"
) )
@@ -5502,7 +5502,10 @@ func (c *client) doTLSHandshake(typ string, solicit bool, url *url.URL, tlsConfi
if solicit { if solicit {
// Based on type of error, possibly clear the saved tlsName // Based on type of error, possibly clear the saved tlsName
// See: https://github.com/nats-io/nats-server/issues/1256 // See: https://github.com/nats-io/nats-server/issues/1256
if _, ok := err.(x509.HostnameError); ok { // NOTE: As of Go 1.20, the HostnameError is wrapped so cannot
// type assert to check directly.
var hostnameErr x509.HostnameError
if errors.As(err, &hostnameErr) {
if host == tlsName { if host == tlsName {
resetTLSName = true resetTLSName = true
} }

View File

@@ -605,89 +605,96 @@ func TestGatewayTLSMixedIPAndDNS(t *testing.T) {
server.SetGatewaysSolicitDelay(5 * time.Millisecond) server.SetGatewaysSolicitDelay(5 * time.Millisecond)
defer server.ResetGatewaysSolicitDelay() defer server.ResetGatewaysSolicitDelay()
confA1 := createConfFile(t, []byte(` // Run this test extra times to make sure not flaky since it
listen: 127.0.0.1:-1 // on solicit time.
gateway { for i := 0; i < 10; i++ {
name: "A" t.Run("", func(t *testing.T) {
listen: "127.0.0.1:-1" confA1 := createConfFile(t, []byte(`
tls { listen: 127.0.0.1:-1
cert_file: "./configs/certs/server-iponly.pem" server_name: A1
key_file: "./configs/certs/server-key-iponly.pem" gateway {
ca_file: "./configs/certs/ca.pem" name: "A"
timeout: 2 listen: "127.0.0.1:-1"
tls {
cert_file: "./configs/certs/server-iponly.pem"
key_file: "./configs/certs/server-key-iponly.pem"
ca_file: "./configs/certs/ca.pem"
timeout: 2
}
} }
} cluster {
cluster { listen: "127.0.0.1:-1"
listen: "127.0.0.1:-1" }`))
} srvA1, optsA1 := RunServerWithConfig(confA1)
`)) defer srvA1.Shutdown()
srvA1, optsA1 := RunServerWithConfig(confA1)
defer srvA1.Shutdown()
confA2Template := ` confA2Template := `
listen: 127.0.0.1:-1 listen: 127.0.0.1:-1
gateway { server_name: A2
name: "A" gateway {
listen: "localhost:-1" name: "A"
tls { listen: "localhost:-1"
cert_file: "./configs/certs/server-cert.pem" tls {
key_file: "./configs/certs/server-key.pem" cert_file: "./configs/certs/server-cert.pem"
ca_file: "./configs/certs/ca.pem" key_file: "./configs/certs/server-key.pem"
timeout: 2 ca_file: "./configs/certs/ca.pem"
timeout: 2
}
} }
} cluster {
cluster { listen: "127.0.0.1:-1"
listen: "127.0.0.1:-1" routes [
routes [ "nats://%s:%d"
"nats://%s:%d" ]
] }`
} confA2 := createConfFile(t, []byte(fmt.Sprintf(confA2Template,
` optsA1.Cluster.Host, optsA1.Cluster.Port)))
confA2 := createConfFile(t, []byte(fmt.Sprintf(confA2Template, srvA2, optsA2 := RunServerWithConfig(confA2)
optsA1.Cluster.Host, optsA1.Cluster.Port))) defer srvA2.Shutdown()
srvA2, optsA2 := RunServerWithConfig(confA2)
defer srvA2.Shutdown()
checkClusterFormed(t, srvA1, srvA2) checkClusterFormed(t, srvA1, srvA2)
// Create a GW connection to cluster "A". Don't use the helper since we need verification etc. // Create a GW connection to cluster "A". Don't use the helper since we need verification etc.
o := DefaultTestOptions o := DefaultTestOptions
o.Port = -1 o.Port = -1
o.Gateway.Name = "B" o.ServerName = "B1"
o.Gateway.Host = "127.0.0.1" o.Gateway.Name = "B"
o.Gateway.Port = -1 o.Gateway.Host = "127.0.0.1"
o.Gateway.Port = -1
tc := &server.TLSConfigOpts{} tc := &server.TLSConfigOpts{}
tc.CertFile = "./configs/certs/server-cert.pem" tc.CertFile = "./configs/certs/server-cert.pem"
tc.KeyFile = "./configs/certs/server-key.pem" tc.KeyFile = "./configs/certs/server-key.pem"
tc.CaFile = "./configs/certs/ca.pem" tc.CaFile = "./configs/certs/ca.pem"
tc.Timeout = 2.0 tc.Timeout = 2.0
tlsConfig, err := server.GenTLSConfig(tc) tlsConfig, err := server.GenTLSConfig(tc)
if err != nil { if err != nil {
t.Fatalf("Error generating TLS config: %v", err) t.Fatalf("Error generating TLS config: %v", err)
}
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
tlsConfig.RootCAs = tlsConfig.ClientCAs
o.Gateway.TLSConfig = tlsConfig.Clone()
rurl, _ := url.Parse(fmt.Sprintf("nats://%s:%d", optsA2.Gateway.Host, optsA2.Gateway.Port))
remote := &server.RemoteGatewayOpts{Name: "A", URLs: []*url.URL{rurl}}
remote.TLSConfig = tlsConfig.Clone()
o.Gateway.Gateways = []*server.RemoteGatewayOpts{remote}
srvB := RunServer(&o)
defer srvB.Shutdown()
waitForOutboundGateways(t, srvB, 1, 10*time.Second)
waitForOutboundGateways(t, srvA1, 1, 10*time.Second)
waitForOutboundGateways(t, srvA2, 1, 10*time.Second)
// Now kill off srvA2 and force serverB to connect to srvA1.
srvA2.Shutdown()
// Make sure this works.
waitForOutboundGateways(t, srvB, 1, 30*time.Second)
})
} }
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
tlsConfig.RootCAs = tlsConfig.ClientCAs
o.Gateway.TLSConfig = tlsConfig.Clone()
rurl, _ := url.Parse(fmt.Sprintf("nats://%s:%d", optsA2.Gateway.Host, optsA2.Gateway.Port))
remote := &server.RemoteGatewayOpts{Name: "A", URLs: []*url.URL{rurl}}
remote.TLSConfig = tlsConfig.Clone()
o.Gateway.Gateways = []*server.RemoteGatewayOpts{remote}
srvB := RunServer(&o)
defer srvB.Shutdown()
waitForOutboundGateways(t, srvB, 1, 10*time.Second)
waitForOutboundGateways(t, srvA1, 1, 10*time.Second)
waitForOutboundGateways(t, srvA2, 1, 10*time.Second)
// Now kill off srvA2 and force serverB to connect to srvA1.
srvA2.Shutdown()
// Make sure this works.
waitForOutboundGateways(t, srvB, 1, 10*time.Second)
} }
func TestGatewayAdvertiseInCluster(t *testing.T) { func TestGatewayAdvertiseInCluster(t *testing.T) {