From 9950d1225d1284ed8f47da3f027bb1444954c0d2 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 1 Aug 2024 21:53:48 +0100 Subject: [PATCH] Improve link and handshake errors --- src/core/link.go | 10 ++++++---- src/core/version.go | 23 ++++++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/core/link.go b/src/core/link.go index f45c2cee..ee2ad06f 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -140,7 +140,7 @@ const ErrLinkAlreadyConfigured = linkError("peer is already configured") const ErrLinkNotConfigured = linkError("peer is not configured") const ErrLinkPriorityInvalid = linkError("priority value is invalid") const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid") -const ErrLinkPasswordInvalid = linkError("password is invalid") +const ErrLinkPasswordInvalid = linkError("invalid password supplied") const ErrLinkUnrecognisedSchema = linkError("link schema unknown") const ErrLinkMaxBackoffInvalid = linkError("max backoff duration invalid") @@ -363,9 +363,11 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error { _ = lc.Close() phony.Block(l, func() { state._conn = nil - if state._err = err; state._err != nil { - state._errtime = time.Now() + if err == nil { + err = fmt.Errorf("remote side closed the connection") } + state._err = err + state._errtime = time.Now() }) // If the link is persistently configured, back off if needed @@ -647,7 +649,7 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s l.core.log.Infof("Disconnected %s: %s, source %s; error: %s", dir, remoteStr, localStr, err) } - return nil + return err } func urlForLinkInfo(u url.URL) url.URL { diff --git a/src/core/version.go b/src/core/version.go index 28b16430..bb3b9538 100644 --- a/src/core/version.go +++ b/src/core/version.go @@ -8,7 +8,6 @@ import ( "bytes" "crypto/ed25519" "encoding/binary" - "fmt" "io" "golang.org/x/crypto/blake2b" @@ -38,6 +37,16 @@ const ( metaPriority // uint8 ) +type handshakeError string + +func (e handshakeError) Error() string { return string(e) } + +const ErrHandshakeInvalidPreamble = handshakeError("invalid handshake, remote side is not Yggdrasil") +const ErrHandshakeInvalidLength = handshakeError("invalid handshake length, possible version mismatch") +const ErrHandshakeInvalidPassword = handshakeError("invalid password supplied, check your config") +const ErrHandshakeHashFailure = handshakeError("invalid hash length") +const ErrHandshakeIncorrectPassword = handshakeError("password does not match remote side") + // Gets a base metadata with no keys set, but with the correct version numbers. func version_getBaseMetadata() version_metadata { return version_metadata{ @@ -77,7 +86,7 @@ func (m *version_metadata) encode(privateKey ed25519.PrivateKey, password []byte return nil, err } if n != ed25519.PublicKeySize { - return nil, fmt.Errorf("hash writer only wrote %d bytes", n) + return nil, ErrHandshakeHashFailure } hash := hasher.Sum(nil) bs = append(bs, ed25519.Sign(privateKey, hash)...) @@ -94,11 +103,11 @@ func (m *version_metadata) decode(r io.Reader, password []byte) error { } meta := [4]byte{'m', 'e', 't', 'a'} if !bytes.Equal(bh[:4], meta[:]) { - return fmt.Errorf("invalid handshake preamble") + return ErrHandshakeInvalidPreamble } hl := binary.BigEndian.Uint16(bh[4:6]) if hl < ed25519.SignatureSize { - return fmt.Errorf("invalid handshake length") + return ErrHandshakeInvalidLength } bs := make([]byte, hl) if _, err := io.ReadFull(r, bs); err != nil { @@ -132,15 +141,15 @@ func (m *version_metadata) decode(r io.Reader, password []byte) error { hasher, err := blake2b.New512(password) if err != nil { - return fmt.Errorf("invalid password supplied") + return ErrHandshakeInvalidPassword } n, err := hasher.Write(m.publicKey) if err != nil || n != ed25519.PublicKeySize { - return fmt.Errorf("failed to generate hash") + return ErrHandshakeHashFailure } hash := hasher.Sum(nil) if !ed25519.Verify(m.publicKey, hash, sig) { - return fmt.Errorf("password is incorrect") + return ErrHandshakeIncorrectPassword } return nil }