mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 01:26:52 +01:00
handshake: lower log level for blocklisted certificates (#1969)
smoke-extra / freebsd-amd64 (push) Failing after 23s
smoke-extra / linux-amd64-ipv6disable (push) Failing after 14s
smoke-extra / netbsd-amd64 (push) Failing after 12s
smoke-extra / openbsd-amd64 (push) Failing after 11s
smoke-extra / linux-386 (push) Failing after 13s
smoke / Run multi node smoke test (push) Failing after 1m42s
Build and test / Static checks (push) Successful in 2m15s
Build and test / Test linux (push) Failing after 2m17s
Build and test / Test linux-pkcs11 (push) Failing after 2m10s
Build and test / Test linux-boringcrypto (push) Failing after 2m58s
Build and test / Test linux-fips140 (push) Failing after 2m54s
Build and test / Cross-build linux-arm (push) Successful in 3m6s
Build and test / Cross-build linux-mips (push) Successful in 3m46s
Build and test / Cross-build linux-other (push) Successful in 3m10s
Build and test / Cross-build windows (push) Successful in 1m3s
Build and test / Cross-build freebsd (push) Successful in 1m33s
Build and test / Cross-build netbsd (push) Successful in 1m34s
Build and test / Cross-build openbsd (push) Successful in 1m33s
Build and test / Cross-build mobile (push) Successful in 3m28s
smoke-extra / Run windows smoke test (push) Canceled after 0s
smoke / Run self traffic smoke test on macOS (push) Canceled after 0s
Build and test / Test macos (push) Canceled after 0s
Build and test / Test windows (push) Canceled after 0s
Build and test / CI status (push) Canceled after 0s
smoke-extra / freebsd-amd64 (push) Failing after 23s
smoke-extra / linux-amd64-ipv6disable (push) Failing after 14s
smoke-extra / netbsd-amd64 (push) Failing after 12s
smoke-extra / openbsd-amd64 (push) Failing after 11s
smoke-extra / linux-386 (push) Failing after 13s
smoke / Run multi node smoke test (push) Failing after 1m42s
Build and test / Static checks (push) Successful in 2m15s
Build and test / Test linux (push) Failing after 2m17s
Build and test / Test linux-pkcs11 (push) Failing after 2m10s
Build and test / Test linux-boringcrypto (push) Failing after 2m58s
Build and test / Test linux-fips140 (push) Failing after 2m54s
Build and test / Cross-build linux-arm (push) Successful in 3m6s
Build and test / Cross-build linux-mips (push) Successful in 3m46s
Build and test / Cross-build linux-other (push) Successful in 3m10s
Build and test / Cross-build windows (push) Successful in 1m3s
Build and test / Cross-build freebsd (push) Successful in 1m33s
Build and test / Cross-build netbsd (push) Successful in 1m34s
Build and test / Cross-build openbsd (push) Successful in 1m33s
Build and test / Cross-build mobile (push) Successful in 3m28s
smoke-extra / Run windows smoke test (push) Canceled after 0s
smoke / Run self traffic smoke test on macOS (push) Canceled after 0s
Build and test / Test macos (push) Canceled after 0s
Build and test / Test windows (push) Canceled after 0s
Build and test / CI status (push) Canceled after 0s
This commit is contained in:
1 parent
b04d71d96a
commit
f552cebc51
2 files changed
+121
-23
No files matched your search
+33
-23
@@ -61,16 +61,17 @@ type HandshakeManager struct {
|
||||
vpnIps map[netip.Addr]*HandshakeHostInfo
|
||||
indexes map[uint32]*HandshakeHostInfo
|
||||
|
||||
mainHostMap *HostMap
|
||||
lightHouse *LightHouse
|
||||
outside udp.Conn
|
||||
config HandshakeConfig
|
||||
OutboundHandshakeTimer *LockingTimerWheel[netip.Addr]
|
||||
messageMetrics *MessageMetrics
|
||||
metricInitiated metrics.Counter
|
||||
metricTimedOut metrics.Counter
|
||||
f *Interface
|
||||
l *slog.Logger
|
||||
mainHostMap *HostMap
|
||||
lightHouse *LightHouse
|
||||
outside udp.Conn
|
||||
config HandshakeConfig
|
||||
OutboundHandshakeTimer *LockingTimerWheel[netip.Addr]
|
||||
messageMetrics *MessageMetrics
|
||||
metricInitiated metrics.Counter
|
||||
metricTimedOut metrics.Counter
|
||||
metricRejectedBlocklisted metrics.Counter
|
||||
f *Interface
|
||||
l *slog.Logger
|
||||
|
||||
// can be used to trigger outbound handshake for the given vpnIp
|
||||
trigger chan netip.Addr
|
||||
@@ -118,18 +119,19 @@ func (hh *HandshakeHostInfo) cachePacket(l *slog.Logger, t header.MessageType, s
|
||||
|
||||
func NewHandshakeManager(l *slog.Logger, mainHostMap *HostMap, lightHouse *LightHouse, outside udp.Conn, config HandshakeConfig) *HandshakeManager {
|
||||
return &HandshakeManager{
|
||||
vpnIps: map[netip.Addr]*HandshakeHostInfo{},
|
||||
indexes: map[uint32]*HandshakeHostInfo{},
|
||||
mainHostMap: mainHostMap,
|
||||
lightHouse: lightHouse,
|
||||
outside: outside,
|
||||
config: config,
|
||||
trigger: make(chan netip.Addr, config.triggerBuffer),
|
||||
OutboundHandshakeTimer: NewLockingTimerWheel[netip.Addr](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
|
||||
messageMetrics: config.messageMetrics,
|
||||
metricInitiated: metrics.GetOrRegisterCounter("handshake_manager.initiated", nil),
|
||||
metricTimedOut: metrics.GetOrRegisterCounter("handshake_manager.timed_out", nil),
|
||||
l: l,
|
||||
vpnIps: map[netip.Addr]*HandshakeHostInfo{},
|
||||
indexes: map[uint32]*HandshakeHostInfo{},
|
||||
mainHostMap: mainHostMap,
|
||||
lightHouse: lightHouse,
|
||||
outside: outside,
|
||||
config: config,
|
||||
trigger: make(chan netip.Addr, config.triggerBuffer),
|
||||
OutboundHandshakeTimer: NewLockingTimerWheel[netip.Addr](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
|
||||
messageMetrics: config.messageMetrics,
|
||||
metricInitiated: metrics.GetOrRegisterCounter("handshake_manager.initiated", nil),
|
||||
metricTimedOut: metrics.GetOrRegisterCounter("handshake_manager.timed_out", nil),
|
||||
metricRejectedBlocklisted: metrics.GetOrRegisterCounter("handshake_manager.rejected.blocklisted", nil),
|
||||
l: l,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,7 +719,12 @@ func (hm *HandshakeManager) beginHandshake(via ViaSender, packet []byte, h *head
|
||||
|
||||
response, result, err := machine.ProcessPacket(nil, packet)
|
||||
if err != nil {
|
||||
f.l.Error("Failed to process handshake packet", "from", via, "error", err)
|
||||
level := slog.LevelError
|
||||
if errors.Is(err, cert.ErrBlockListed) {
|
||||
level = slog.LevelDebug
|
||||
hm.metricRejectedBlocklisted.Inc(1)
|
||||
}
|
||||
f.l.Log(context.Background(), level, "Failed to process handshake packet", "from", via, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -849,6 +856,9 @@ func (hm *HandshakeManager) continueHandshake(via ViaSender, hh *HandshakeHostIn
|
||||
|
||||
response, result, err := machine.ProcessPacket(nil, packet)
|
||||
if err != nil {
|
||||
if errors.Is(err, cert.ErrBlockListed) {
|
||||
hm.metricRejectedBlocklisted.Inc(1)
|
||||
}
|
||||
// Recoverable errors are routine noise, log at Debug. Fatal errors get a Warn.
|
||||
if machine.Failed() {
|
||||
f.l.Warn("Failed to process handshake packet, abandoning",
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package nebula
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/gaissmai/bart"
|
||||
"github.com/rcrowley/go-metrics"
|
||||
"github.com/slackhq/nebula/cert"
|
||||
ct "github.com/slackhq/nebula/cert_test"
|
||||
"github.com/slackhq/nebula/handshake"
|
||||
"github.com/slackhq/nebula/header"
|
||||
"github.com/slackhq/nebula/test"
|
||||
"github.com/slackhq/nebula/udp"
|
||||
@@ -235,6 +240,89 @@ func TestHandleIncomingDispatch(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlocklistedHandshakeLogLevelAndCounter(t *testing.T) {
|
||||
ca, _, caKey, _ := ct.NewTestCaCert(cert.Version2, cert.Curve_CURVE25519, time.Time{}, time.Time{}, nil, nil, nil)
|
||||
pool := ct.NewTestCAPool(ca)
|
||||
|
||||
newCredential := func(name, network string) (cert.Certificate, *handshake.Credential) {
|
||||
c, _, rawKey, _ := ct.NewTestCert(cert.Version2, cert.Curve_CURVE25519, ca, caKey,
|
||||
name, ca.NotBefore(), ca.NotAfter(), []netip.Prefix{netip.MustParsePrefix(network)}, nil, nil)
|
||||
privateKey, _, _, err := cert.UnmarshalPrivateKeyFromPEM(rawKey)
|
||||
require.NoError(t, err)
|
||||
certBytes, err := c.MarshalForHandshakes()
|
||||
require.NoError(t, err)
|
||||
cipherSuite := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256)
|
||||
return c, handshake.NewCredential(c, certBytes, privateKey, cipherSuite)
|
||||
}
|
||||
|
||||
initiatorCert, initiatorCredential := newCredential("initiator", "10.0.0.1/24")
|
||||
responderCert, responderCredential := newCredential("responder", "10.0.0.2/24")
|
||||
fingerprint, err := initiatorCert.Fingerprint()
|
||||
require.NoError(t, err)
|
||||
pool.BlocklistFingerprint(fingerprint)
|
||||
|
||||
initiator, err := handshake.NewMachine(cert.Version2,
|
||||
func(cert.Version) *handshake.Credential { return initiatorCredential },
|
||||
func(c cert.Certificate) (*cert.CachedCertificate, error) {
|
||||
return pool.VerifyCertificate(time.Now(), c)
|
||||
},
|
||||
func() (uint32, error) { return 1, nil }, true, header.HandshakeIXPSK0)
|
||||
require.NoError(t, err)
|
||||
packet, err := initiator.Initiate(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := &capturingHandler{}
|
||||
logger := slog.New(handler)
|
||||
pki := &PKI{}
|
||||
pki.cs.Store(&CertState{initiatingVersion: cert.Version2, v2Credential: responderCredential})
|
||||
pki.caPool.Store(pool)
|
||||
hm := NewHandshakeManager(logger, nil, nil, nil, defaultHandshakeConfig)
|
||||
hm.metricRejectedBlocklisted = metrics.NewCounter()
|
||||
hm.f = &Interface{pki: pki, l: logger}
|
||||
via := ViaSender{UdpAddr: netip.MustParseAddrPort("198.51.100.7:4242")}
|
||||
|
||||
hm.beginHandshake(via, packet, nil)
|
||||
entry := findEntry(t, handler.entries, "Failed to process handshake packet")
|
||||
assert.Equal(t, slog.LevelDebug, entry.Level)
|
||||
require.ErrorIs(t, entry.Attrs["error"].(error), cert.ErrBlockListed)
|
||||
assert.Equal(t, int64(1), hm.metricRejectedBlocklisted.Count())
|
||||
|
||||
handler.entries = nil
|
||||
hm.beginHandshake(via, nil, nil)
|
||||
entry = findEntry(t, handler.entries, "Failed to process handshake packet")
|
||||
assert.Equal(t, slog.LevelError, entry.Level)
|
||||
assert.Equal(t, int64(1), hm.metricRejectedBlocklisted.Count())
|
||||
|
||||
// The initiator sees the same rejection in continueHandshake, after a
|
||||
// responder has accepted its first packet and sent a valid reply.
|
||||
cleanPool := ct.NewTestCAPool(ca)
|
||||
responder, err := handshake.NewMachine(cert.Version2,
|
||||
func(cert.Version) *handshake.Credential { return responderCredential },
|
||||
func(c cert.Certificate) (*cert.CachedCertificate, error) {
|
||||
return cleanPool.VerifyCertificate(time.Now(), c)
|
||||
},
|
||||
func() (uint32, error) { return 2, nil }, false, header.HandshakeIXPSK0)
|
||||
require.NoError(t, err)
|
||||
response, _, err := responder.ProcessPacket(nil, packet)
|
||||
require.NoError(t, err)
|
||||
|
||||
responderFingerprint, err := responderCert.Fingerprint()
|
||||
require.NoError(t, err)
|
||||
pool.BlocklistFingerprint(responderFingerprint)
|
||||
|
||||
initiatingHM := NewHandshakeManager(logger, nil, nil, nil, defaultHandshakeConfig)
|
||||
initiatingHM.metricRejectedBlocklisted = metrics.NewCounter()
|
||||
initiatingHM.f = &Interface{l: logger}
|
||||
hh := &HandshakeHostInfo{
|
||||
machine: initiator,
|
||||
hostinfo: &HostInfo{localIndexId: 1, vpnAddrs: []netip.Addr{netip.MustParseAddr("10.0.0.2")}},
|
||||
}
|
||||
initiatingHM.indexes[1] = hh
|
||||
via.IsRelayed = true // skip the remote allow list before certificate validation
|
||||
initiatingHM.continueHandshake(via, hh, response)
|
||||
assert.Equal(t, int64(1), initiatingHM.metricRejectedBlocklisted.Count())
|
||||
}
|
||||
|
||||
// Test_PendingHandshakeHasRemotes covers create-tunnel -address: a pending hostinfo must already
|
||||
// carry its RemoteList when StartHandshake runs its callback, so SetRemote there, before the
|
||||
// handshake loop has run, is safe and the address becomes one the handshake is sent to.
|
||||
|
||||
Reference in new issue
Block a user