From 14a1af132e7748f113fc69301282ce04c66ee607 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 22:17:50 -0600 Subject: [PATCH 01/19] Bump Apple-Actions/import-codesign-certs from 5 to 6 (#1549) Bumps [Apple-Actions/import-codesign-certs](https://github.com/apple-actions/import-codesign-certs) from 5 to 6. - [Release notes](https://github.com/apple-actions/import-codesign-certs/releases) - [Commits](https://github.com/apple-actions/import-codesign-certs/compare/v5...v6) --- updated-dependencies: - dependency-name: Apple-Actions/import-codesign-certs dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 35d72dea..b6921c65 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,7 +75,7 @@ jobs: - name: Import certificates if: env.HAS_SIGNING_CREDS == 'true' - uses: Apple-Actions/import-codesign-certs@v5 + uses: Apple-Actions/import-codesign-certs@v6 with: p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} From 48406f85da00baf7dd8a03be66d95855b92fe592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 22:19:53 -0600 Subject: [PATCH 02/19] Bump the golang-x-dependencies group with 3 updates (#1550) Bumps the golang-x-dependencies group with 3 updates: [golang.org/x/sync](https://github.com/golang/sync), [golang.org/x/sys](https://github.com/golang/sys) and [golang.org/x/term](https://github.com/golang/term). Updates `golang.org/x/sync` from 0.18.0 to 0.19.0 - [Commits](https://github.com/golang/sync/compare/v0.18.0...v0.19.0) Updates `golang.org/x/sys` from 0.38.0 to 0.39.0 - [Commits](https://github.com/golang/sys/compare/v0.38.0...v0.39.0) Updates `golang.org/x/term` from 0.37.0 to 0.38.0 - [Commits](https://github.com/golang/term/compare/v0.37.0...v0.38.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-version: 0.19.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies - dependency-name: golang.org/x/sys dependency-version: 0.39.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies - dependency-name: golang.org/x/term dependency-version: 0.38.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index e927eb8b..7999c641 100644 --- a/go.mod +++ b/go.mod @@ -26,9 +26,9 @@ require ( golang.org/x/crypto v0.45.0 golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 golang.org/x/net v0.47.0 - golang.org/x/sync v0.18.0 - golang.org/x/sys v0.38.0 - golang.org/x/term v0.37.0 + golang.org/x/sync v0.19.0 + golang.org/x/sys v0.39.0 + golang.org/x/term v0.38.0 golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b golang.zx2c4.com/wireguard/windows v0.5.3 diff --git a/go.sum b/go.sum index 3679fac6..1e1c9d8f 100644 --- a/go.sum +++ b/go.sum @@ -191,8 +191,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -209,11 +209,11 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From cba294ffa4c52c1dda05c8421493854e382b6c4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 22:25:48 -0600 Subject: [PATCH 03/19] Bump actions/checkout from 5 to 6 (#1541) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gofmt.yml | 2 +- .github/workflows/release.yml | 10 +++++----- .github/workflows/smoke-extra.yml | 2 +- .github/workflows/smoke.yml | 2 +- .github/workflows/test.yml | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/gofmt.yml b/.github/workflows/gofmt.yml index 51575623..4d57c7b2 100644 --- a/.github/workflows/gofmt.yml +++ b/.github/workflows/gofmt.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b6921c65..9a6d8650 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: name: Build Linux/BSD All runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: @@ -33,7 +33,7 @@ jobs: name: Build Windows runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: @@ -66,7 +66,7 @@ jobs: HAS_SIGNING_CREDS: ${{ secrets.AC_USERNAME != '' }} runs-on: macos-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: @@ -124,7 +124,7 @@ jobs: # be overwritten - name: Checkout code if: ${{ env.HAS_DOCKER_CREDS == 'true' }} - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Download artifacts if: ${{ env.HAS_DOCKER_CREDS == 'true' }} @@ -160,7 +160,7 @@ jobs: needs: [build-linux, build-darwin, build-windows] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Download artifacts uses: actions/download-artifact@v6 diff --git a/.github/workflows/smoke-extra.yml b/.github/workflows/smoke-extra.yml index 966bddd2..24f899ab 100644 --- a/.github/workflows/smoke-extra.yml +++ b/.github/workflows/smoke-extra.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 43438bbd..66913326 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 050a68e4..a6b577a3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: @@ -56,7 +56,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: @@ -98,7 +98,7 @@ jobs: os: [windows-latest, macos-latest] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: From 2d169402323f5ca01628357afbcf90d618533ac7 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Tue, 9 Dec 2025 23:29:26 -0500 Subject: [PATCH 04/19] Slight improvement to hot path benchmark, add a relay hot path benchmark (#1539) --- e2e/helpers_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/helpers_test.go b/e2e/helpers_test.go index 7a802c99..39843efe 100644 --- a/e2e/helpers_test.go +++ b/e2e/helpers_test.go @@ -304,7 +304,7 @@ func assertTunnel(t testing.TB, vpnIpA, vpnIpB netip.Addr, controlA, controlB *n assertUdpPacket(t, []byte("Hello from A"), aPacket, vpnIpA, vpnIpB, 90, 80) } -func assertHostInfoPair(t *testing.T, addrA, addrB netip.AddrPort, vpnNetsA, vpnNetsB []netip.Prefix, controlA, controlB *nebula.Control) { +func assertHostInfoPair(t testing.TB, addrA, addrB netip.AddrPort, vpnNetsA, vpnNetsB []netip.Prefix, controlA, controlB *nebula.Control) { // Get both host infos //TODO: CERT-V2 we may want to loop over each vpnAddr and assert all the things hBinA := controlA.GetHostInfoByVpnAddr(vpnNetsB[0].Addr(), false) From 3ec527e42cecfcf17b31d201eb4ce349c2e32067 Mon Sep 17 00:00:00 2001 From: Jack Doan Date: Wed, 10 Dec 2025 10:39:36 -0600 Subject: [PATCH 05/19] cert.MarshalSigningPublicKeyToPEM should emit the 'ECDSA' variant of the banner (#1552) * cert.MarshalSigningPublicKeyToPEM should emit the 'ECDSA' variant of the banner * oof owie ouch my tests --- cert/cert_v1_test.go | 8 +++++++- cert/cert_v2_test.go | 9 ++++++++- cert/pem.go | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cert/cert_v1_test.go b/cert/cert_v1_test.go index 3b7d5859..ea5805a9 100644 --- a/cert/cert_v1_test.go +++ b/cert/cert_v1_test.go @@ -99,13 +99,19 @@ func TestCertificateV1_PublicKeyPem(t *testing.T) { AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAA= -----END NEBULA P256 PUBLIC KEY----- +`) + + pubP256KeyPemCA := []byte(`-----BEGIN NEBULA ECDSA P256 PUBLIC KEY----- +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAA= +-----END NEBULA ECDSA P256 PUBLIC KEY----- `) pubP256Key, _, _, err := UnmarshalPublicKeyFromPEM(pubP256KeyPem) require.NoError(t, err) nc.details.curve = Curve_P256 nc.details.publicKey = pubP256Key assert.Equal(t, Curve_P256, nc.Curve()) - assert.Equal(t, string(nc.MarshalPublicKeyPEM()), string(pubP256KeyPem)) + assert.Equal(t, string(nc.MarshalPublicKeyPEM()), string(pubP256KeyPemCA)) assert.True(t, nc.IsCA()) nc.details.isCA = false diff --git a/cert/cert_v2_test.go b/cert/cert_v2_test.go index 84362efe..ee7c26c3 100644 --- a/cert/cert_v2_test.go +++ b/cert/cert_v2_test.go @@ -114,12 +114,19 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAA= -----END NEBULA P256 PUBLIC KEY----- `) + + pubP256KeyPemCA := []byte(`-----BEGIN NEBULA ECDSA P256 PUBLIC KEY----- +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAA= +-----END NEBULA ECDSA P256 PUBLIC KEY----- +`) + pubP256Key, _, _, err := UnmarshalPublicKeyFromPEM(pubP256KeyPem) require.NoError(t, err) nc.curve = Curve_P256 nc.publicKey = pubP256Key assert.Equal(t, Curve_P256, nc.Curve()) - assert.Equal(t, string(nc.MarshalPublicKeyPEM()), string(pubP256KeyPem)) + assert.Equal(t, string(nc.MarshalPublicKeyPEM()), string(pubP256KeyPemCA)) assert.True(t, nc.IsCA()) nc.details.isCA = false diff --git a/cert/pem.go b/cert/pem.go index a5aabdce..8942c23a 100644 --- a/cert/pem.go +++ b/cert/pem.go @@ -86,7 +86,7 @@ func MarshalSigningPublicKeyToPEM(curve Curve, b []byte) []byte { case Curve_CURVE25519: return pem.EncodeToMemory(&pem.Block{Type: Ed25519PublicKeyBanner, Bytes: b}) case Curve_P256: - return pem.EncodeToMemory(&pem.Block{Type: P256PublicKeyBanner, Bytes: b}) + return pem.EncodeToMemory(&pem.Block{Type: ECDSAP256PublicKeyBanner, Bytes: b}) default: return nil } From 2f71d6b22d5678db3fd6f93c9820b59cee1f4584 Mon Sep 17 00:00:00 2001 From: brad-defined <77982333+brad-defined@users.noreply.github.com> Date: Fri, 9 Jan 2026 09:52:03 -0500 Subject: [PATCH 06/19] Ensure pubkey coherency when rehydrating a handshake cert (#1566) * Ensure pubkey coherency when rehydrating a handshake cert * Include a check during handshakes after cert verification that the noise pubkey matches the cert pubkey. --- cert/cert.go | 1 + cert/cert_v1.go | 15 ++++++++---- cert/cert_v1_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++ cert/cert_v2.go | 8 ++++++- cert/cert_v2_test.go | 52 ++++++++++++++++++++++++++++++++++++++++ cert/errors.go | 1 + handshake_ix.go | 14 +++++++++++ 7 files changed, 142 insertions(+), 5 deletions(-) diff --git a/cert/cert.go b/cert/cert.go index 855815a7..9d40e625 100644 --- a/cert/cert.go +++ b/cert/cert.go @@ -119,6 +119,7 @@ func (cc *CachedCertificate) String() string { // Recombine will attempt to unmarshal a certificate received in a handshake. // Handshakes save space by placing the peers public key in a different part of the packet, we have to // reassemble the actual certificate structure with that in mind. +// Implementations MUST assert the public key is not in the raw certificate bytes if the passed in public key is not empty. func Recombine(v Version, rawCertBytes, publicKey []byte, curve Curve) (Certificate, error) { if publicKey == nil { return nil, ErrNoPeerStaticKey diff --git a/cert/cert_v1.go b/cert/cert_v1.go index 09a181d6..c32f409a 100644 --- a/cert/cert_v1.go +++ b/cert/cert_v1.go @@ -426,7 +426,7 @@ func unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1, error) unsafeNetworks: make([]netip.Prefix, len(rc.Details.Subnets)/2), notBefore: time.Unix(rc.Details.NotBefore, 0), notAfter: time.Unix(rc.Details.NotAfter, 0), - publicKey: make([]byte, len(rc.Details.PublicKey)), + publicKey: nil, isCA: rc.Details.IsCA, curve: rc.Details.Curve, }, @@ -437,12 +437,19 @@ func unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1, error) copy(nc.details.groups, rc.Details.Groups) nc.details.issuer = hex.EncodeToString(rc.Details.Issuer) + // If a public key is passed in as an argument, the certificate pubkey must be empty + // and the passed-in pubkey copied into the cert. if len(publicKey) > 0 { - nc.details.publicKey = publicKey + if len(rc.Details.PublicKey) != 0 { + return nil, ErrCertPubkeyPresent + } + nc.details.publicKey = make([]byte, len(publicKey)) + copy(nc.details.publicKey, publicKey) + } else { + nc.details.publicKey = make([]byte, len(rc.Details.PublicKey)) + copy(nc.details.publicKey, rc.Details.PublicKey) } - copy(nc.details.publicKey, rc.Details.PublicKey) - var ip netip.Addr for i, rawIp := range rc.Details.Ips { if i%2 == 0 { diff --git a/cert/cert_v1_test.go b/cert/cert_v1_test.go index ea5805a9..6e374634 100644 --- a/cert/cert_v1_test.go +++ b/cert/cert_v1_test.go @@ -62,6 +62,62 @@ func TestCertificateV1_Marshal(t *testing.T) { assert.Equal(t, nc.Groups(), nc2.Groups()) } +func TestCertificateV1_Unmarshal(t *testing.T) { + t.Parallel() + before := time.Now().Add(time.Second * -60).Round(time.Second) + after := time.Now().Add(time.Second * 60).Round(time.Second) + pubKey := []byte("1234567890abcedfghij1234567890ab") + invalidPubkey := []byte("00000000000000000000000000000000") + + nc := certificateV1{ + details: detailsV1{ + name: "testing", + networks: []netip.Prefix{ + mustParsePrefixUnmapped("10.1.1.1/24"), + mustParsePrefixUnmapped("10.1.1.2/16"), + }, + unsafeNetworks: []netip.Prefix{ + mustParsePrefixUnmapped("9.1.1.2/24"), + mustParsePrefixUnmapped("9.1.1.3/16"), + }, + groups: []string{"test-group1", "test-group2", "test-group3"}, + notBefore: before, + notAfter: after, + publicKey: pubKey, + isCA: false, + issuer: "1234567890abcedfghij1234567890ab", + }, + signature: []byte("1234567890abcedfghij1234567890ab"), + } + + // This certificate has a pubkey included + certWithPubkey, err := nc.Marshal() + require.NoError(t, err) + + // This certificate is missing the pubkey section + certWithoutPubkey, err := nc.MarshalForHandshakes() + require.NoError(t, err) + + // Cert has no pubkey and no pubkey passed in must fail to validate + isNil, err := unmarshalCertificateV1(certWithoutPubkey, nil) + require.Error(t, err) + + // Cert has different pubkey than one passed in must fail + isNil, err = unmarshalCertificateV1(certWithPubkey, invalidPubkey) + require.Nil(t, isNil) + require.Error(t, err) + + // Cert has pubkey and no pubkey argument works ok + _, err = unmarshalCertificateV1(certWithPubkey, nil) + require.NoError(t, err) + + // Cert has no pubkey and valid, correctly signed pubkey passed in + nc2, err := unmarshalCertificateV1(certWithoutPubkey, pubKey) + require.NoError(t, err) + + assert.Equal(t, pubKey, nc2.PublicKey()) +} + func TestCertificateV1_PublicKeyPem(t *testing.T) { t.Parallel() before := time.Now().Add(time.Second * -60).Round(time.Second) diff --git a/cert/cert_v2.go b/cert/cert_v2.go index ac21cb13..4648c496 100644 --- a/cert/cert_v2.go +++ b/cert/cert_v2.go @@ -592,7 +592,13 @@ func unmarshalCertificateV2(b []byte, publicKey []byte, curve Curve) (*certifica // Maybe grab the public key var rawPublicKey cryptobyte.String if len(publicKey) > 0 { - rawPublicKey = publicKey + // If a public key is passed in, then the handshake certificate must + // not have a public key present + if input.PeekASN1Tag(TagCertPublicKey) { + return nil, ErrCertPubkeyPresent + } + rawPublicKey = make(cryptobyte.String, len(publicKey)) + copy(rawPublicKey, publicKey) } else if !input.ReadOptionalASN1(&rawPublicKey, nil, TagCertPublicKey) { return nil, ErrBadFormat } diff --git a/cert/cert_v2_test.go b/cert/cert_v2_test.go index ee7c26c3..e2a6b98d 100644 --- a/cert/cert_v2_test.go +++ b/cert/cert_v2_test.go @@ -76,6 +76,58 @@ func TestCertificateV2_Marshal(t *testing.T) { assert.Equal(t, nc.Groups(), nc2.Groups()) } +func TestCertificateV2_Unmarshal(t *testing.T) { + t.Parallel() + before := time.Now().Add(time.Second * -60).Round(time.Second) + after := time.Now().Add(time.Second * 60).Round(time.Second) + pubKey := []byte("1234567890abcedfghij1234567890ab") + + nc := certificateV2{ + details: detailsV2{ + name: "testing", + networks: []netip.Prefix{ + mustParsePrefixUnmapped("10.1.1.2/16"), + mustParsePrefixUnmapped("10.1.1.1/24"), + }, + unsafeNetworks: []netip.Prefix{ + mustParsePrefixUnmapped("9.1.1.3/16"), + mustParsePrefixUnmapped("9.1.1.2/24"), + }, + groups: []string{"test-group1", "test-group2", "test-group3"}, + notBefore: before, + notAfter: after, + isCA: false, + issuer: "1234567890abcdef1234567890abcdef", + }, + signature: []byte("1234567890abcdef1234567890abcdef"), + publicKey: pubKey, + } + + db, err := nc.details.Marshal() + require.NoError(t, err) + nc.rawDetails = db + + certWithPubkey, err := nc.Marshal() + require.NoError(t, err) + //t.Log("Cert size:", len(b)) + certWithoutPubkey, err := nc.MarshalForHandshakes() + require.NoError(t, err) + + // Cert must not have a pubkey if one is passed in as an argument + _, err = unmarshalCertificateV2(certWithPubkey, pubKey, Curve_CURVE25519) + require.ErrorIs(t, err, ErrCertPubkeyPresent) + + // Certs must have pubkeys + _, err = unmarshalCertificateV2(certWithoutPubkey, nil, Curve_CURVE25519) + require.ErrorIs(t, err, ErrBadFormat) + + // Ensure proper unmarshal if a pubkey is passed in + nc2, err := unmarshalCertificateV2(certWithoutPubkey, pubKey, Curve_CURVE25519) + require.NoError(t, err) + + assert.Equal(t, nc.PublicKey(), nc2.PublicKey()) +} + func TestCertificateV2_PublicKeyPem(t *testing.T) { t.Parallel() before := time.Now().Add(time.Second * -60).Round(time.Second) diff --git a/cert/errors.go b/cert/errors.go index 99006756..8c480a14 100644 --- a/cert/errors.go +++ b/cert/errors.go @@ -21,6 +21,7 @@ var ( ErrPrivateKeyEncrypted = errors.New("private key must be decrypted") ErrCaNotFound = errors.New("could not find ca for the certificate") ErrUnknownVersion = errors.New("certificate version unrecognized") + ErrCertPubkeyPresent = errors.New("certificate has unexpected pubkey present") ErrInvalidPEMBlock = errors.New("input did not contain a valid PEM encoded block") ErrInvalidPEMCertificateBanner = errors.New("bytes did not contain a proper certificate banner") diff --git a/handshake_ix.go b/handshake_ix.go index 17f2c15b..4e04f450 100644 --- a/handshake_ix.go +++ b/handshake_ix.go @@ -1,6 +1,7 @@ package nebula import ( + "bytes" "net/netip" "time" @@ -166,6 +167,13 @@ func ixHandshakeStage1(f *Interface, via ViaSender, packet []byte, h *header.H) return } + if !bytes.Equal(remoteCert.Certificate.PublicKey(), ci.H.PeerStatic()) { + f.l.WithField("from", via). + WithField("handshake", m{"stage": 1, "style": "ix_psk0"}). + WithField("cert", remoteCert).Info("public key mismatch between certificate and handshake") + return + } + if remoteCert.Certificate.Version() != ci.myCert.Version() { // We started off using the wrong certificate version, lets see if we can match the version that was sent to us myCertOtherVersion := cs.getCertificate(remoteCert.Certificate.Version()) @@ -535,6 +543,12 @@ func ixHandshakeStage2(f *Interface, via ViaSender, hh *HandshakeHostInfo, packe e.Info("Invalid certificate from host") return true } + if !bytes.Equal(remoteCert.Certificate.PublicKey(), ci.H.PeerStatic()) { + f.l.WithField("from", via). + WithField("handshake", m{"stage": 2, "style": "ix_psk0"}). + WithField("cert", remoteCert).Info("public key mismatch between certificate and handshake") + return true + } if len(remoteCert.Certificate.Networks()) == 0 { f.l.WithError(err).WithField("from", via). From 69259e6307b017fec7f29edc8f55ad632d898a98 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 9 Jan 2026 10:35:09 -0600 Subject: [PATCH 07/19] Quietly log error on UDP_NETRESET ioctl on Windows. (#1453) (#1568) Co-authored-by: brad-defined <77982333+brad-defined@users.noreply.github.com> --- udp/udp_generic.go | 16 ++++++++++++++-- udp/udp_rio_windows.go | 33 +++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/udp/udp_generic.go b/udp/udp_generic.go index 3cefc904..e9dad6c5 100644 --- a/udp/udp_generic.go +++ b/udp/udp_generic.go @@ -10,9 +10,11 @@ package udp import ( "context" + "errors" "fmt" "net" "net/netip" + "time" "github.com/sirupsen/logrus" "github.com/slackhq/nebula/config" @@ -74,12 +76,22 @@ type rawMessage struct { func (u *GenericConn) ListenOut(r EncReader) { buffer := make([]byte, MTU) + var lastRecvErr time.Time + for { // Just read one packet at a time n, rua, err := u.ReadFromUDPAddrPort(buffer) if err != nil { - u.l.WithError(err).Debug("udp socket is closed, exiting read loop") - return + if errors.Is(err, net.ErrClosed) { + u.l.WithError(err).Debug("udp socket is closed, exiting read loop") + return + } + // Dampen unexpected message warns to once per minute + if lastRecvErr.IsZero() || time.Since(lastRecvErr) > time.Minute { + lastRecvErr = time.Now() + u.l.WithError(err).Warn("unexpected udp socket receive error") + } + continue } r(netip.AddrPortFrom(rua.Addr().Unmap(), rua.Port()), buffer[:n]) diff --git a/udp/udp_rio_windows.go b/udp/udp_rio_windows.go index 1d602d01..3d60f34c 100644 --- a/udp/udp_rio_windows.go +++ b/udp/udp_rio_windows.go @@ -14,6 +14,7 @@ import ( "sync" "sync/atomic" "syscall" + "time" "unsafe" "github.com/sirupsen/logrus" @@ -66,7 +67,7 @@ func NewRIOListener(l *logrus.Logger, addr netip.Addr, port int) (*RIOConn, erro u := &RIOConn{l: l} - err := u.bind(&windows.SockaddrInet6{Addr: addr.As16(), Port: port}) + err := u.bind(l, &windows.SockaddrInet6{Addr: addr.As16(), Port: port}) if err != nil { return nil, fmt.Errorf("bind: %w", err) } @@ -82,11 +83,11 @@ func NewRIOListener(l *logrus.Logger, addr netip.Addr, port int) (*RIOConn, erro return u, nil } -func (u *RIOConn) bind(sa windows.Sockaddr) error { +func (u *RIOConn) bind(l *logrus.Logger, sa windows.Sockaddr) error { var err error u.sock, err = winrio.Socket(windows.AF_INET6, windows.SOCK_DGRAM, windows.IPPROTO_UDP) if err != nil { - return err + return fmt.Errorf("winrio.Socket error: %w", err) } // Enable v4 for this socket @@ -100,35 +101,40 @@ func (u *RIOConn) bind(sa windows.Sockaddr) error { size := uint32(unsafe.Sizeof(flag)) err = syscall.WSAIoctl(syscall.Handle(u.sock), syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) if err != nil { - return err + // This is a best-effort to prevent errors from being returned by the udp recv operation. + // Quietly log a failure and continue. + l.WithError(err).Debug("failed to set UDP_CONNRESET ioctl") } + ret = 0 flag = 0 size = uint32(unsafe.Sizeof(flag)) SIO_UDP_NETRESET := uint32(syscall.IOC_IN | syscall.IOC_VENDOR | 15) err = syscall.WSAIoctl(syscall.Handle(u.sock), SIO_UDP_NETRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) if err != nil { - return err + // This is a best-effort to prevent errors from being returned by the udp recv operation. + // Quietly log a failure and continue. + l.WithError(err).Debug("failed to set UDP_NETRESET ioctl") } err = u.rx.Open() if err != nil { - return err + return fmt.Errorf("error rx.Open(): %w", err) } err = u.tx.Open() if err != nil { - return err + return fmt.Errorf("error tx.Open(): %w", err) } u.rq, err = winrio.CreateRequestQueue(u.sock, packetsPerRing, 1, packetsPerRing, 1, u.rx.cq, u.tx.cq, 0) if err != nil { - return err + return fmt.Errorf("error CreateRequestQueue: %w", err) } err = windows.Bind(u.sock, sa) if err != nil { - return err + return fmt.Errorf("error windows.Bind(): %w", err) } return nil @@ -137,15 +143,22 @@ func (u *RIOConn) bind(sa windows.Sockaddr) error { func (u *RIOConn) ListenOut(r EncReader) { buffer := make([]byte, MTU) + var lastRecvErr time.Time + for { // Just read one packet at a time n, rua, err := u.receive(buffer) + if err != nil { if errors.Is(err, net.ErrClosed) { u.l.WithError(err).Debug("udp socket is closed, exiting read loop") return } - u.l.WithError(err).Error("unexpected udp socket receive error") + // Dampen unexpected message warns to once per minute + if lastRecvErr.IsZero() || time.Since(lastRecvErr) > time.Minute { + lastRecvErr = time.Now() + u.l.WithError(err).Warn("unexpected udp socket receive error") + } continue } From d7a3f01465614dd92be7595acc189a334fad94f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 15:35:34 -0500 Subject: [PATCH 08/19] Bump the golang-x-dependencies group across 1 directory with 4 updates (#1570) Bumps the golang-x-dependencies group with 1 update in the / directory: [golang.org/x/crypto](https://github.com/golang/crypto). Updates `golang.org/x/crypto` from 0.45.0 to 0.47.0 - [Commits](https://github.com/golang/crypto/compare/v0.45.0...v0.47.0) Updates `golang.org/x/net` from 0.47.0 to 0.48.0 - [Commits](https://github.com/golang/net/compare/v0.47.0...v0.48.0) Updates `golang.org/x/sys` from 0.39.0 to 0.40.0 - [Commits](https://github.com/golang/sys/compare/v0.39.0...v0.40.0) Updates `golang.org/x/term` from 0.38.0 to 0.39.0 - [Commits](https://github.com/golang/term/compare/v0.38.0...v0.39.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.47.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies - dependency-name: golang.org/x/net dependency-version: 0.48.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies - dependency-name: golang.org/x/sys dependency-version: 0.40.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies - dependency-name: golang.org/x/term dependency-version: 0.39.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 7999c641..bf5524c3 100644 --- a/go.mod +++ b/go.mod @@ -23,12 +23,12 @@ require ( github.com/stretchr/testify v1.11.1 github.com/vishvananda/netlink v1.3.1 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.45.0 + golang.org/x/crypto v0.47.0 golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 - golang.org/x/net v0.47.0 + golang.org/x/net v0.48.0 golang.org/x/sync v0.19.0 - golang.org/x/sys v0.39.0 - golang.org/x/term v0.38.0 + golang.org/x/sys v0.40.0 + golang.org/x/term v0.39.0 golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b golang.zx2c4.com/wireguard/windows v0.5.3 diff --git a/go.sum b/go.sum index 1e1c9d8f..a3119940 100644 --- a/go.sum +++ b/go.sum @@ -162,8 +162,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -182,8 +182,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -209,11 +209,11 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From 9933970e67dbf4cc06d5f13e6879f92b2b0e62bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 15:40:13 -0500 Subject: [PATCH 09/19] Bump actions/upload-artifact from 5 to 6 (#1558) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/test.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9a6d8650..e65a826e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: mv build/*.tar.gz release - name: Upload artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: linux-latest path: release @@ -55,7 +55,7 @@ jobs: mv dist\windows\wintun build\dist\windows\ - name: Upload artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: windows-latest path: build @@ -104,7 +104,7 @@ jobs: fi - name: Upload artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: darwin-latest path: ./release/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a6b577a3..aeaea294 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,7 +45,7 @@ jobs: - name: Build test mobile run: make build-test-mobile - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6 with: name: e2e packet flow linux-latest path: e2e/mermaid/linux-latest @@ -125,7 +125,7 @@ jobs: - name: End 2 end run: make e2evv - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6 with: name: e2e packet flow ${{ matrix.os }} path: e2e/mermaid/${{ matrix.os }} From 1b2d639b145470cf73bcc2800fd49c1a51e8d07d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 15:40:47 -0500 Subject: [PATCH 10/19] Bump actions/download-artifact from 6 to 7 (#1557) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e65a826e..9ce1d5e3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,7 +128,7 @@ jobs: - name: Download artifacts if: ${{ env.HAS_DOCKER_CREDS == 'true' }} - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: name: linux-latest path: artifacts @@ -163,7 +163,7 @@ jobs: - uses: actions/checkout@v6 - name: Download artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: path: artifacts From a4a6143b6a7680acb689b96fe91be156d8b83d31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:16:01 -0500 Subject: [PATCH 11/19] Bump google.golang.org/protobuf in the protobuf-dependencies group (#1560) Bumps the protobuf-dependencies group with 1 update: google.golang.org/protobuf. Updates `google.golang.org/protobuf` from 1.36.10 to 1.36.11 --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-version: 1.36.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: protobuf-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bf5524c3..6a2bc392 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b golang.zx2c4.com/wireguard/windows v0.5.3 - google.golang.org/protobuf v1.36.10 + google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 gvisor.dev/gvisor v0.0.0-20240423190808-9d7a357edefe ) diff --git a/go.sum b/go.sum index a3119940..d5d1d113 100644 --- a/go.sum +++ b/go.sum @@ -244,8 +244,8 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 523209ec0b0d487b7d3934bef2a848300069726e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:16:42 -0500 Subject: [PATCH 12/19] Bump github.com/miekg/dns from 1.1.68 to 1.1.69 (#1561) Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.68 to 1.1.69. - [Commits](https://github.com/miekg/dns/compare/v1.1.68...v1.1.69) --- updated-dependencies: - dependency-name: github.com/miekg/dns dependency-version: 1.1.69 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 6a2bc392..452a5d11 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/google/gopacket v1.1.19 github.com/kardianos/service v1.2.4 - github.com/miekg/dns v1.1.68 + github.com/miekg/dns v1.1.70 github.com/miekg/pkcs11 v1.1.2-0.20231115102856-9078ad6b9d4b github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f github.com/prometheus/client_golang v1.23.2 @@ -49,7 +49,7 @@ require ( github.com/prometheus/procfs v0.16.1 // indirect github.com/vishvananda/netns v0.0.5 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/mod v0.24.0 // indirect + golang.org/x/mod v0.31.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.33.0 // indirect + golang.org/x/tools v0.40.0 // indirect ) diff --git a/go.sum b/go.sum index d5d1d113..0eee9f7c 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= -github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= +github.com/miekg/dns v1.1.70 h1:DZ4u2AV35VJxdD9Fo9fIWm119BsQL5cZU1cQ9s0LkqA= +github.com/miekg/dns v1.1.70/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/miekg/pkcs11 v1.1.2-0.20231115102856-9078ad6b9d4b h1:J/AzCvg5z0Hn1rqZUJjpbzALUmkKX0Zwbc/i4fw7Sfk= github.com/miekg/pkcs11 v1.1.2-0.20231115102856-9078ad6b9d4b/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -170,8 +170,8 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -224,8 +224,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 1283ff0db4e231efb874fcac1f31dd80702050a6 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Tue, 13 Jan 2026 00:00:27 -0600 Subject: [PATCH 13/19] Add option to control accepting recv_error (#1569) --- examples/config.yml | 4 +++ interface.go | 64 +++++++++++++++++++++++++++++++-------------- main.go | 1 + outside.go | 9 ++++++- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/examples/config.yml b/examples/config.yml index 3ba9ce4e..f81baab6 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -144,6 +144,10 @@ listen: # valid values: always, never, private # This setting is reloadable. #send_recv_error: always + # Similar to send_recv_error, this option lets you configure if you want to accept "recv_error" packets from remote hosts. + # valid values: always, never, private + # This setting is reloadable. + #accept_recv_error: always # The so_sock option is a Linux-specific feature that allows all outgoing Nebula packets to be tagged with a specific identifier. # This tagging enables IP rule-based filtering. For example, it supports 0.0.0.0/0 unsafe_routes, # allowing for more precise routing decisions based on the packet tags. Default is 0 meaning no mark is set. diff --git a/interface.go b/interface.go index 9f83d183..f69ed062 100644 --- a/interface.go +++ b/interface.go @@ -77,7 +77,8 @@ type Interface struct { reQueryEvery atomic.Uint32 reQueryWait atomic.Int64 - sendRecvErrorConfig sendRecvErrorConfig + sendRecvErrorConfig recvErrorConfig + acceptRecvErrorConfig recvErrorConfig // rebindCount is used to decide if an active tunnel should trigger a punch notification through a lighthouse rebindCount int8 @@ -110,34 +111,34 @@ type EncWriter interface { GetCertState() *CertState } -type sendRecvErrorConfig uint8 +type recvErrorConfig uint8 const ( - sendRecvErrorAlways sendRecvErrorConfig = iota - sendRecvErrorNever - sendRecvErrorPrivate + recvErrorAlways recvErrorConfig = iota + recvErrorNever + recvErrorPrivate ) -func (s sendRecvErrorConfig) ShouldSendRecvError(endpoint netip.AddrPort) bool { +func (s recvErrorConfig) ShouldRecvError(endpoint netip.AddrPort) bool { switch s { - case sendRecvErrorPrivate: + case recvErrorPrivate: return endpoint.Addr().IsPrivate() - case sendRecvErrorAlways: + case recvErrorAlways: return true - case sendRecvErrorNever: + case recvErrorNever: return false default: - panic(fmt.Errorf("invalid sendRecvErrorConfig value: %d", s)) + panic(fmt.Errorf("invalid recvErrorConfig value: %d", s)) } } -func (s sendRecvErrorConfig) String() string { +func (s recvErrorConfig) String() string { switch s { - case sendRecvErrorAlways: + case recvErrorAlways: return "always" - case sendRecvErrorNever: + case recvErrorNever: return "never" - case sendRecvErrorPrivate: + case recvErrorPrivate: return "private" default: return fmt.Sprintf("invalid(%d)", s) @@ -312,6 +313,7 @@ func (f *Interface) listenIn(reader io.ReadWriteCloser, i int) { func (f *Interface) RegisterConfigChangeCallbacks(c *config.C) { c.RegisterReloadCallback(f.reloadFirewall) c.RegisterReloadCallback(f.reloadSendRecvError) + c.RegisterReloadCallback(f.reloadAcceptRecvError) c.RegisterReloadCallback(f.reloadDisconnectInvalid) c.RegisterReloadCallback(f.reloadMisc) @@ -375,16 +377,16 @@ func (f *Interface) reloadSendRecvError(c *config.C) { switch stringValue { case "always": - f.sendRecvErrorConfig = sendRecvErrorAlways + f.sendRecvErrorConfig = recvErrorAlways case "never": - f.sendRecvErrorConfig = sendRecvErrorNever + f.sendRecvErrorConfig = recvErrorNever case "private": - f.sendRecvErrorConfig = sendRecvErrorPrivate + f.sendRecvErrorConfig = recvErrorPrivate default: if c.GetBool("listen.send_recv_error", true) { - f.sendRecvErrorConfig = sendRecvErrorAlways + f.sendRecvErrorConfig = recvErrorAlways } else { - f.sendRecvErrorConfig = sendRecvErrorNever + f.sendRecvErrorConfig = recvErrorNever } } @@ -393,6 +395,30 @@ func (f *Interface) reloadSendRecvError(c *config.C) { } } +func (f *Interface) reloadAcceptRecvError(c *config.C) { + if c.InitialLoad() || c.HasChanged("listen.accept_recv_error") { + stringValue := c.GetString("listen.accept_recv_error", "always") + + switch stringValue { + case "always": + f.acceptRecvErrorConfig = recvErrorAlways + case "never": + f.acceptRecvErrorConfig = recvErrorNever + case "private": + f.acceptRecvErrorConfig = recvErrorPrivate + default: + if c.GetBool("listen.accept_recv_error", true) { + f.acceptRecvErrorConfig = recvErrorAlways + } else { + f.acceptRecvErrorConfig = recvErrorNever + } + } + + f.l.WithField("acceptRecvError", f.acceptRecvErrorConfig.String()). + Info("Loaded accept_recv_error config") + } +} + func (f *Interface) reloadMisc(c *config.C) { if c.HasChanged("counters.try_promote") { n := c.GetUint32("counters.try_promote", defaultPromoteEvery) diff --git a/main.go b/main.go index 7b326616..17aaa548 100644 --- a/main.go +++ b/main.go @@ -265,6 +265,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg ifce.RegisterConfigChangeCallbacks(c) ifce.reloadDisconnectInvalid(c) ifce.reloadSendRecvError(c) + ifce.reloadAcceptRecvError(c) handshakeManager.f = ifce go handshakeManager.Run(ctx) diff --git a/outside.go b/outside.go index b1a28e57..172c3e83 100644 --- a/outside.go +++ b/outside.go @@ -516,7 +516,7 @@ func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint64, out } func (f *Interface) maybeSendRecvError(endpoint netip.AddrPort, index uint32) { - if f.sendRecvErrorConfig.ShouldSendRecvError(endpoint) { + if f.sendRecvErrorConfig.ShouldRecvError(endpoint) { f.sendRecvError(endpoint, index) } } @@ -534,6 +534,13 @@ func (f *Interface) sendRecvError(endpoint netip.AddrPort, index uint32) { } func (f *Interface) handleRecvError(addr netip.AddrPort, h *header.H) { + if !f.acceptRecvErrorConfig.ShouldRecvError(addr) { + f.l.WithField("index", h.RemoteIndex). + WithField("udpAddr", addr). + Debug("Recv error received, ignoring") + return + } + if f.l.Level >= logrus.DebugLevel { f.l.WithField("index", h.RemoteIndex). WithField("udpAddr", addr). From 88379b89f5c681344d9919703a7dd7315132499e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 00:02:44 -0600 Subject: [PATCH 14/19] Bump golang.org/x/net in the golang-x-dependencies group (#1571) Bumps the golang-x-dependencies group with 1 update: [golang.org/x/net](https://github.com/golang/net). Updates `golang.org/x/net` from 0.48.0 to 0.49.0 - [Commits](https://github.com/golang/net/compare/v0.48.0...v0.49.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-version: 0.49.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang-x-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 452a5d11..dd75c94e 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.47.0 golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 - golang.org/x/net v0.48.0 + golang.org/x/net v0.49.0 golang.org/x/sync v0.19.0 golang.org/x/sys v0.40.0 golang.org/x/term v0.39.0 diff --git a/go.sum b/go.sum index 0eee9f7c..1888b073 100644 --- a/go.sum +++ b/go.sum @@ -182,8 +182,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From ac3bd9cdd0831ad3fbc2b57dda73a1ecd69e94f5 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Thu, 15 Jan 2026 13:48:17 -0600 Subject: [PATCH 15/19] Avoid losing system originated unsafe routes on reload (#1573) --- overlay/tun_linux.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/overlay/tun_linux.go b/overlay/tun_linux.go index 32bf51f5..917765d9 100644 --- a/overlay/tun_linux.go +++ b/overlay/tun_linux.go @@ -10,6 +10,7 @@ import ( "net/netip" "os" "strings" + "sync" "sync/atomic" "time" "unsafe" @@ -40,6 +41,11 @@ type tun struct { useSystemRoutes bool useSystemRoutesBufferSize int + // These are routes learned from `tun.use_system_route_table` + // stored here to make it easier to restore them after a reload + routesFromSystem map[netip.Prefix]routing.Gateways + routesFromSystemLock sync.Mutex + l *logrus.Logger } @@ -164,6 +170,13 @@ func (t *tun) reload(c *config.C, initial bool) error { return err } + // Bring along any routes learned from the system route table on reload + t.routesFromSystemLock.Lock() + for dst, gw := range t.routesFromSystem { + routeTree.Insert(dst, gw) + } + t.routesFromSystemLock.Unlock() + oldDefaultMTU := t.DefaultMTU oldMaxMTU := t.MaxMTU newDefaultMTU := c.GetInt("tun.mtu", DefaultMTU) @@ -673,14 +686,18 @@ func (t *tun) updateRoutes(r netlink.RouteUpdate) { newTree := t.routeTree.Load().Clone() + t.routesFromSystemLock.Lock() if r.Type == unix.RTM_NEWROUTE { t.l.WithField("destination", dst).WithField("via", gateways).Info("Adding route") + t.routesFromSystem[dst] = gateways newTree.Insert(dst, gateways) } else { t.l.WithField("destination", dst).WithField("via", gateways).Info("Removing route") + delete(t.routesFromSystem, dst) newTree.Delete(dst) } + t.routesFromSystemLock.Unlock() t.routeTree.Store(newTree) } From 72a40007ea873d914a099b77916e4933befc85b6 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 16 Jan 2026 09:33:54 -0600 Subject: [PATCH 16/19] v1.10.1 (#1575) Update CHANGELOG for Nebula v1.10.1 --- CHANGELOG.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0efa7959..104b52e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.10.1] - 2026-01-16 + +See the [v1.10.1](https://github.com/slackhq/nebula/milestone/26?closed=1) milestone for a complete list of changes. + +### Fixed + +- Fix a bug where an unsafe route derived from the system route table could be lost on a config reload. (#1573) +- Fix the PEM banner for ECDSA P256 public keys. (#1552) +- Fix a regression on Windows from 1.9.x where nebula could fall back to a less performant UDP listener if + non-critical ioctls failed. (#1568) +- Fix a bug in handshake processing when a peer sends an unexpected public key. (#1566) + +### Added + +- Add a config option to control accepting `recv_error` packets which defaults to `always`. (#1569) + +### Changed + +- Various dependency updates. (#1541, #1549, #1550, #1557, #1558, #1560, #1561, #1570, #1571) + ## [1.10.0] - 2025-12-04 See the [v1.10.0](https://github.com/slackhq/nebula/milestone/16?closed=1) milestone for a complete list of changes. @@ -744,7 +764,8 @@ created.) - Initial public release. -[Unreleased]: https://github.com/slackhq/nebula/compare/v1.10.0...HEAD +[Unreleased]: https://github.com/slackhq/nebula/compare/v1.10.1...HEAD +[1.10.1]: https://github.com/slackhq/nebula/releases/tag/v1.10.1 [1.10.0]: https://github.com/slackhq/nebula/releases/tag/v1.10.0 [1.9.7]: https://github.com/slackhq/nebula/releases/tag/v1.9.7 [1.9.6]: https://github.com/slackhq/nebula/releases/tag/v1.9.6 From bf49e78243d15ee822cb6901b91e265ca997cc57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 10:40:24 -0500 Subject: [PATCH 17/19] Bump github.com/sirupsen/logrus from 1.9.3 to 1.9.4 (#1581) Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.9.3 to 1.9.4. - [Release notes](https://github.com/sirupsen/logrus/releases) - [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md) - [Commits](https://github.com/sirupsen/logrus/compare/v1.9.3...v1.9.4) --- updated-dependencies: - dependency-name: github.com/sirupsen/logrus dependency-version: 1.9.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index dd75c94e..1c564d03 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f github.com/prometheus/client_golang v1.23.2 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 - github.com/sirupsen/logrus v1.9.3 + github.com/sirupsen/logrus v1.9.4 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 1888b073..c4613e01 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,8 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw= @@ -206,7 +206,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= From e5f60fa54f106d15211db2ae1425a2d5539326c1 Mon Sep 17 00:00:00 2001 From: zhetaicheleba Date: Wed, 21 Jan 2026 01:03:31 +0900 Subject: [PATCH 18/19] chore: fix some typos in comments (#1582) Signed-off-by: zhetaicheleba --- cert/crypto_test.go | 2 +- cert/pem_test.go | 10 +++++----- cmd/nebula-cert/ca_test.go | 2 +- noiseutil/boring.go | 2 +- routing/gateway.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cert/crypto_test.go b/cert/crypto_test.go index 174b2419..bf6e0654 100644 --- a/cert/crypto_test.go +++ b/cert/crypto_test.go @@ -79,7 +79,7 @@ qrlJ69wer3ZUHFXA assert.Nil(t, k) assert.Equal(t, rest, invalidPem) - // Fail due to ivalid PEM format, because + // Fail due to invalid PEM format, because // it's missing the requisite pre-encapsulation boundary. curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest) require.EqualError(t, err, "input did not contain a valid PEM encoded block") diff --git a/cert/pem_test.go b/cert/pem_test.go index ff4410ce..310c57a3 100644 --- a/cert/pem_test.go +++ b/cert/pem_test.go @@ -44,7 +44,7 @@ bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB assert.Equal(t, rest, invalidPem) require.EqualError(t, err, "bytes did not contain a proper certificate banner") - // Fail due to ivalid PEM format, because + // Fail due to invalid PEM format, because // it's missing the requisite pre-encapsulation boundary. cert, rest, err = UnmarshalCertificateFromPEM(rest) assert.Nil(t, cert) @@ -106,7 +106,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA assert.Equal(t, rest, invalidPem) require.EqualError(t, err, "bytes did not contain a proper Ed25519/ECDSA private key banner") - // Fail due to ivalid PEM format, because + // Fail due to invalid PEM format, because // it's missing the requisite pre-encapsulation boundary. k, rest, curve, err = UnmarshalSigningPrivateKeyFromPEM(rest) assert.Nil(t, k) @@ -168,7 +168,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= assert.Equal(t, rest, invalidPem) require.EqualError(t, err, "bytes did not contain a proper private key banner") - // Fail due to ivalid PEM format, because + // Fail due to invalid PEM format, because // it's missing the requisite pre-encapsulation boundary. k, rest, curve, err = UnmarshalPrivateKeyFromPEM(rest) assert.Nil(t, k) @@ -221,7 +221,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= require.EqualError(t, err, "bytes did not contain a proper public key banner") assert.Equal(t, rest, invalidPem) - // Fail due to ivalid PEM format, because + // Fail due to invalid PEM format, because // it's missing the requisite pre-encapsulation boundary. k, rest, curve, err = UnmarshalPublicKeyFromPEM(rest) assert.Nil(t, k) @@ -299,7 +299,7 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= require.EqualError(t, err, "bytes did not contain a proper public key banner") assert.Equal(t, rest, invalidPem) - // Fail due to ivalid PEM format, because + // Fail due to invalid PEM format, because // it's missing the requisite pre-encapsulation boundary. k, rest, curve, err = UnmarshalPublicKeyFromPEM(rest) assert.Nil(t, k) diff --git a/cmd/nebula-cert/ca_test.go b/cmd/nebula-cert/ca_test.go index cd3f0bf9..779d3a2d 100644 --- a/cmd/nebula-cert/ca_test.go +++ b/cmd/nebula-cert/ca_test.go @@ -200,7 +200,7 @@ func Test_ca(t *testing.T) { assert.Empty(t, b) assert.Len(t, lKey, 64) - // test when reading passsword results in an error + // test when reading password results in an error os.Remove(keyF.Name()) os.Remove(crtF.Name()) ob.Reset() diff --git a/noiseutil/boring.go b/noiseutil/boring.go index e9ad19bb..2129af71 100644 --- a/noiseutil/boring.go +++ b/noiseutil/boring.go @@ -22,7 +22,7 @@ const EncryptLockNeeded = true // NewGCMTLS is no longer exposed in go1.19+, so we need to link it in // See: https://github.com/golang/go/issues/56326 // -// NewGCMTLS is the internal method used with boringcrypto that provices a +// NewGCMTLS is the internal method used with boringcrypto that provides a // validated mode of AES-GCM which enforces the nonce is strictly // monotonically increasing. This is the TLS 1.2 specification for nonce // generation (which also matches the method used by the Noise Protocol) diff --git a/routing/gateway.go b/routing/gateway.go index 59d38a91..88cf0933 100644 --- a/routing/gateway.go +++ b/routing/gateway.go @@ -6,7 +6,7 @@ import ( ) const ( - // Sentinal value + // Sentinel value BucketNotCalculated = -1 ) From e1e92f017ce272c2eea0b588c775059d0a8ece1c Mon Sep 17 00:00:00 2001 From: Wade Simmons Date: Tue, 20 Jan 2026 11:15:20 -0500 Subject: [PATCH 19/19] initialize routesFromSystem (#1580) This is a regression introduced by #1573. We need to initialize this map. Fixes: #1579 --- overlay/tun_linux.go | 1 + 1 file changed, 1 insertion(+) diff --git a/overlay/tun_linux.go b/overlay/tun_linux.go index 917765d9..ea666f86 100644 --- a/overlay/tun_linux.go +++ b/overlay/tun_linux.go @@ -137,6 +137,7 @@ func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetworks []n TXQueueLen: c.GetInt("tun.tx_queue", 500), useSystemRoutes: c.GetBool("tun.use_system_route_table", false), useSystemRoutesBufferSize: c.GetInt("tun.use_system_route_table_buffer_size", 0), + routesFromSystem: map[netip.Prefix]routing.Gateways{}, l: l, }