From cf69a5d1187ee4f634865c41f4d0860e8e3244a2 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Wed, 29 Oct 2025 20:53:17 -0500 Subject: [PATCH 1/5] Minimum set of changes to get working with the new nebula cert apis --- .../defined/mobile_nebula/NebulaVpnService.kt | 4 +-- .../kotlin/net/defined/mobile_nebula/Sites.kt | 4 +-- .../PacketTunnelProvider.swift | 2 +- ios/NebulaNetworkExtension/Site.swift | 8 ++--- ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 3 +- lib/components/SimplePage.dart | 2 +- lib/models/Certificate.dart | 12 +++---- .../siteConfig/CertificateDetailsScreen.dart | 15 ++++++--- nebula/api.go | 20 ++++++++++-- nebula/control.go | 2 +- nebula/go.mod | 30 ++++++++++-------- nebula/go.sum | 31 +++++++++++++++++++ nebula/mobileNebula.go | 20 ++++++------ 14 files changed, 107 insertions(+), 48 deletions(-) diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt index da264ec9..4feacbb2 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt @@ -100,7 +100,7 @@ class NebulaVpnService : VpnService() { val ipNet: CIDR try { - ipNet = mobileNebula.MobileNebula.parseCIDR(site!!.cert!!.cert.details.ips[0]) + ipNet = mobileNebula.MobileNebula.parseCIDR(site!!.cert!!.cert.details.networks[0]) } catch (err: Exception) { return announceExit(site!!.id, err.message ?: "$err") } @@ -214,7 +214,7 @@ class NebulaVpnService : VpnService() { } private fun registerReloadReceiver() { - ContextCompat.registerReceiver(this, reloadReceiver, IntentFilter(ACTION_RELOAD), RECEIVER_NOT_EXPORTED) + ContextCompat.registerReceiver(this, reloadReceiver, IntentFilter(ACTION_RELOAD), ContextCompat.RECEIVER_NOT_EXPORTED) } private fun unregisterReloadReceiver() { diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt index 66ede6c7..406aeed2 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt @@ -165,8 +165,8 @@ data class CertificateDetails( val notAfter: String, val publicKey: String, val groups: List, - val ips: List, - val subnets: List, + val networks: List, + val unsafeNetworks: List, val isCa: Boolean, val issuer: String ) diff --git a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift index be9ac5d2..73f1ff84 100644 --- a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift +++ b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift @@ -87,7 +87,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // Make sure our ip is routed to the tun device var err: NSError? - let ipNet = MobileNebulaParseCIDR(_site.cert!.cert.details.ips[0], &err) + let ipNet = MobileNebulaParseCIDR(_site.cert!.cert.details.networks[0], &err) if err != nil { throw err! } diff --git a/ios/NebulaNetworkExtension/Site.swift b/ios/NebulaNetworkExtension/Site.swift index 52bfec56..52a95ec5 100644 --- a/ios/NebulaNetworkExtension/Site.swift +++ b/ios/NebulaNetworkExtension/Site.swift @@ -102,8 +102,8 @@ struct CertificateDetails: Codable { var notAfter: String var publicKey: String var groups: [String] - var ips: [String] - var subnets: [String] + var networks: [String] + var unsafeNetworks: [String] var isCa: Bool var issuer: String @@ -114,8 +114,8 @@ struct CertificateDetails: Codable { notAfter = "" publicKey = "" groups = [] - ips = ["ERROR"] - subnets = [] + networks = ["ERROR"] + unsafeNetworks = [] isCa = false issuer = "" } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a53cf3ea..79ad53b2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -288,7 +288,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1140; - LastUpgradeCheck = 1600; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 43AA89532444DA6500EDC39C = { diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c22d0a1b..2194383c 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/lib/components/SimplePage.dart b/lib/components/SimplePage.dart index 76c466f6..101b0cf4 100644 --- a/lib/components/SimplePage.dart +++ b/lib/components/SimplePage.dart @@ -79,7 +79,7 @@ class SimplePage extends StatelessWidget { } if (addScrollbar) { - realChild = Scrollbar(child: realChild); + realChild = Scrollbar(controller: scrollController, child: realChild); } if (alignment != null) { diff --git a/lib/models/Certificate.dart b/lib/models/Certificate.dart index 61571b0a..8672ef37 100644 --- a/lib/models/Certificate.dart +++ b/lib/models/Certificate.dart @@ -36,8 +36,8 @@ class CertificateDetails { DateTime notAfter; String publicKey; List groups; - List ips; - List subnets; + List networks; + List unsafeNetworks; bool isCa; String issuer; @@ -47,8 +47,8 @@ class CertificateDetails { notAfter = DateTime.now(), publicKey = "", groups = [], - ips = [], - subnets = [], + networks = [], + unsafeNetworks = [], isCa = false, issuer = "DEBUG"; @@ -58,8 +58,8 @@ class CertificateDetails { notAfter = DateTime.parse(json['notAfter']), publicKey = json['publicKey'], groups = List.from(json['groups']), - ips = List.from(json['ips']), - subnets = List.from(json['subnets']), + networks = List.from(json['networks']), + unsafeNetworks = List.from(json['unsafeNetworks']), isCa = json['isCa'], issuer = json['issuer']; } diff --git a/lib/screens/siteConfig/CertificateDetailsScreen.dart b/lib/screens/siteConfig/CertificateDetailsScreen.dart index 9a9c9b5b..07fac9dc 100644 --- a/lib/screens/siteConfig/CertificateDetailsScreen.dart +++ b/lib/screens/siteConfig/CertificateDetailsScreen.dart @@ -124,12 +124,19 @@ class _CertificateDetailsScreenState extends State { items.add(ConfigItem(label: Text('Groups'), content: SelectableText(certInfo.cert.details.groups.join(', ')))); } - if (certInfo.cert.details.ips.isNotEmpty) { - items.add(ConfigItem(label: Text('IPs'), content: SelectableText(certInfo.cert.details.ips.join(', ')))); + if (certInfo.cert.details.networks.isNotEmpty) { + items.add( + ConfigItem(label: Text('Networks'), content: SelectableText(certInfo.cert.details.networks.join(', '))), + ); } - if (certInfo.cert.details.subnets.isNotEmpty) { - items.add(ConfigItem(label: Text('Subnets'), content: SelectableText(certInfo.cert.details.subnets.join(', ')))); + if (certInfo.cert.details.unsafeNetworks.isNotEmpty) { + items.add( + ConfigItem( + label: Text('Unsafe Networks'), + content: SelectableText(certInfo.cert.details.unsafeNetworks.join(', ')), + ), + ); } return items.isNotEmpty diff --git a/nebula/api.go b/nebula/api.go index cab297e4..03ca84eb 100644 --- a/nebula/api.go +++ b/nebula/api.go @@ -2,6 +2,9 @@ package mobileNebula import ( "context" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" "encoding/json" "errors" "fmt" @@ -144,12 +147,25 @@ func unmarshalHostPrivateKey(b []byte) (keys.PrivateKey, []byte, error) { k, r, err := keys.UnmarshalHostPrivateKey(b) if err != nil { // We used to use a Nebula PEM header for these keys, so try that as a fallback - k, r, err := cert.UnmarshalEd25519PrivateKey(b) + k, r, c, err := cert.UnmarshalSigningPrivateKeyFromPEM(b) if err != nil { return nil, r, fmt.Errorf("failed fallback unmarshal: %w", err) } - pk, err := keys.NewPrivateKey(k) + var rk any + switch c { + case cert.Curve_CURVE25519: + rk = ed25519.PrivateKey(k) + case cert.Curve_P256: + rk, err = ecdsa.ParseRawPrivateKey(elliptic.P256(), k) + if err != nil { + return nil, r, fmt.Errorf("failed to parse P256 private key: %s", err) + } + default: + return nil, r, fmt.Errorf("unsupported private key type: %s", c.String()) + } + + pk, err := keys.NewPrivateKey(rk) if err != nil { return nil, r, err } diff --git a/nebula/control.go b/nebula/control.go index cbc2a34c..09ea311c 100644 --- a/nebula/control.go +++ b/nebula/control.go @@ -112,7 +112,7 @@ func (n *Nebula) GetHostInfoByVpnIp(vpnIp string, pending bool) (string, error) return "", err } - b, err := json.Marshal(n.c.GetHostInfoByVpnIp(netVpnIp, pending)) + b, err := json.Marshal(n.c.GetHostInfoByVpnAddr(netVpnIp, pending)) if err != nil { return "", err } diff --git a/nebula/go.mod b/nebula/go.mod index e669b0d5..9488ace8 100644 --- a/nebula/go.mod +++ b/nebula/go.mod @@ -13,7 +13,7 @@ require ( ) require ( - dario.cat/mergo v1.0.1 // indirect + dario.cat/mergo v1.0.2 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -21,21 +21,24 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 // indirect github.com/flynn/noise v1.1.0 // indirect - github.com/gaissmai/bart v0.13.0 // indirect + github.com/gaissmai/bart v0.26.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/miekg/dns v1.1.68 // indirect + github.com/miekg/pkcs11 v1.1.2-0.20231115102856-9078ad6b9d4b // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f // indirect - github.com/prometheus/client_golang v1.20.5 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.60.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.2 // indirect + github.com/prometheus/procfs v0.19.1 // indirect + github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect - github.com/vishvananda/netlink v1.3.0 // indirect - github.com/vishvananda/netns v0.0.4 // indirect + github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect + github.com/vishvananda/netlink v1.3.1 // indirect + github.com/vishvananda/netns v0.0.5 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect @@ -44,7 +47,8 @@ require ( golang.org/x/term v0.37.0 // indirect golang.org/x/tools v0.39.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect - golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect + golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/protobuf v1.35.2 // indirect + google.golang.org/protobuf v1.36.10 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/nebula/go.sum b/nebula/go.sum index 00d8892b..b6d97c0d 100644 --- a/nebula/go.sum +++ b/nebula/go.sum @@ -30,6 +30,8 @@ github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/gaissmai/bart v0.13.0 h1:pItEhXDVVebUa+i978FfQ7ye8xZc1FrMgs8nJPPWAgA= github.com/gaissmai/bart v0.13.0/go.mod h1:qSes2fnJ8hB410BW0ymHUN/eQkuGpTYyJcN8sKMYpJU= +github.com/gaissmai/bart v0.26.0 h1:xOZ57E9hJLBiQaSyeZa9wgWhGuzfGACgqp4BE77OkO0= +github.com/gaissmai/bart v0.26.0/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -57,6 +59,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= @@ -70,6 +73,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -85,6 +89,10 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +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/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= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -106,24 +114,34 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8= +github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/procfs v0.19.1 h1:QVtROpTkphuXuNlnCv3m1ut3JytkXHtQ3xvck/YmzMM= +github.com/prometheus/procfs v0.19.1/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -135,6 +153,8 @@ github.com/slackhq/nebula v1.9.7 h1:v5u46efIyYHGdfjFnozQbRRhMdaB9Ma1SSTcUcE2lfE= github.com/slackhq/nebula v1.9.7/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= +github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw= +github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -143,12 +163,19 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= +github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= +github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -224,6 +251,8 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= +golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+ZbWg+4sHnLp52d5yiIPUxMBSt4X9A= +golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -236,6 +265,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/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= diff --git a/nebula/mobileNebula.go b/nebula/mobileNebula.go index 54cb1f73..7eef4bd1 100644 --- a/nebula/mobileNebula.go +++ b/nebula/mobileNebula.go @@ -37,7 +37,7 @@ type Validity struct { type RawCert struct { RawCert string - Cert *cert.NebulaCertificate + Cert cert.Certificate Validity Validity } @@ -186,17 +186,17 @@ func ParseCIDR(cidr string) (*CIDR, error) { // Returns a JSON representation of 1 or more certificates func ParseCerts(rawStringCerts string) (string, error) { var certs []RawCert - var c *cert.NebulaCertificate + var c cert.Certificate var err error rawCerts := []byte(rawStringCerts) for { - c, rawCerts, err = cert.UnmarshalNebulaCertificateFromPEM(rawCerts) + c, rawCerts, err = cert.UnmarshalCertificateFromPEM(rawCerts) if err != nil { return "", err } - rawCert, err := c.MarshalToPEM() + rawCert, err := c.MarshalPEM() if err != nil { return "", err } @@ -214,7 +214,7 @@ func ParseCerts(rawStringCerts string) (string, error) { rc.Validity.Reason = "Certificate is expired" } - if rc.Validity.Valid && c.Details.IsCA && !c.CheckSignature(c.Details.PublicKey) { + if rc.Validity.Valid && c.IsCA() && !c.CheckSignature(c.PublicKey()) { rc.Validity.Valid = false rc.Validity.Reason = "Certificate signature did not match" } @@ -241,8 +241,8 @@ func GenerateKeyPair() (string, error) { } kp := KeyPair{} - kp.PublicKey = string(cert.MarshalX25519PublicKey(pub)) - kp.PrivateKey = string(cert.MarshalX25519PrivateKey(priv)) + kp.PublicKey = string(cert.MarshalPublicKeyToPEM(cert.Curve_CURVE25519, pub)) + kp.PrivateKey = string(cert.MarshalPrivateKeyToPEM(cert.Curve_CURVE25519, priv)) rawJson, err := json.Marshal(kp) if err != nil { @@ -262,17 +262,17 @@ func x25519Keypair() ([]byte, []byte, error) { } func VerifyCertAndKey(rawCert string, pemPrivateKey string) (bool, error) { - rawKey, _, err := cert.UnmarshalX25519PrivateKey([]byte(pemPrivateKey)) + rawKey, _, c, err := cert.UnmarshalPrivateKeyFromPEM([]byte(pemPrivateKey)) if err != nil { return false, fmt.Errorf("error while unmarshaling private key: %s", err) } - nebulaCert, _, err := cert.UnmarshalNebulaCertificateFromPEM([]byte(rawCert)) + nebulaCert, _, err := cert.UnmarshalCertificateFromPEM([]byte(rawCert)) if err != nil { return false, fmt.Errorf("error while unmarshaling cert: %s", err) } - if err = nebulaCert.VerifyPrivateKey(nebulaCert.Details.Curve, rawKey); err != nil { + if err = nebulaCert.VerifyPrivateKey(c, rawKey); err != nil { return false, err } From 64ae352c2be48662641dfa45b12aae139e0334ba Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Wed, 29 Oct 2025 21:57:11 -0500 Subject: [PATCH 2/5] Flatten the cert structure and include the new cert v2 properties --- .../defined/mobile_nebula/NebulaVpnService.kt | 2 +- .../kotlin/net/defined/mobile_nebula/Sites.kt | 20 +++---- .../PacketTunnelProvider.swift | 2 +- ios/NebulaNetworkExtension/Site.swift | 37 +++++------- lib/models/Certificate.dart | 58 +++++++++---------- lib/screens/HostInfoScreen.dart | 2 +- lib/screens/SiteTunnelsScreen.dart | 2 +- .../siteConfig/AddCertificateScreen.dart | 2 +- lib/screens/siteConfig/CAListScreen.dart | 4 +- .../siteConfig/CertificateDetailsScreen.dart | 43 +++++--------- lib/screens/siteConfig/SiteConfigScreen.dart | 2 +- nebula/mobileNebula.go | 29 ++++++++-- 12 files changed, 98 insertions(+), 105 deletions(-) diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt index 4feacbb2..35a98681 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt @@ -100,7 +100,7 @@ class NebulaVpnService : VpnService() { val ipNet: CIDR try { - ipNet = mobileNebula.MobileNebula.parseCIDR(site!!.cert!!.cert.details.networks[0]) + ipNet = mobileNebula.MobileNebula.parseCIDR(site!!.cert!!.cert.networks[0]) } catch (err: Exception) { return announceExit(site!!.id, err.message ?: "$err") } diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt index 406aeed2..65bb9510 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/Sites.kt @@ -154,21 +154,19 @@ data class CertificateInfo( ) data class Certificate( - val fingerprint: String, - val signature: String, - val details: CertificateDetails -) - -data class CertificateDetails( + val version: Int, val name: String, - val notBefore: String, - val notAfter: String, - val publicKey: String, - val groups: List, val networks: List, val unsafeNetworks: List, + val groups: List, val isCa: Boolean, - val issuer: String + val notBefore: String, + val notAfter: String, + val issuer: String, + val publicKey: String, + val curve: String, + val fingerprint: String, + val signature: String, ) data class CertificateValidity( diff --git a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift index 73f1ff84..45e489c6 100644 --- a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift +++ b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift @@ -87,7 +87,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // Make sure our ip is routed to the tun device var err: NSError? - let ipNet = MobileNebulaParseCIDR(_site.cert!.cert.details.networks[0], &err) + let ipNet = MobileNebulaParseCIDR(_site.cert!.cert.networks[0], &err) if err != nil { throw err! } diff --git a/ios/NebulaNetworkExtension/Site.swift b/ios/NebulaNetworkExtension/Site.swift index 52a95ec5..1254b157 100644 --- a/ios/NebulaNetworkExtension/Site.swift +++ b/ios/NebulaNetworkExtension/Site.swift @@ -84,40 +84,35 @@ struct CertificateInfo: Codable { } struct Certificate: Codable { - var fingerprint: String - var signature: String - var details: CertificateDetails - - /// An empty initializer to make error reporting easier - init() { - fingerprint = "" - signature = "" - details = CertificateDetails() - } -} - -struct CertificateDetails: Codable { + var version: Int var name: String - var notBefore: String - var notAfter: String - var publicKey: String - var groups: [String] var networks: [String] var unsafeNetworks: [String] + var groups: [String] var isCa: Bool + var notBefore: String + var notAfter: String var issuer: String + var publicKey: String + var curve: String + var fingerprint: String + var signature: String /// An empty initializer to make error reporting easier init() { + version = 0 name = "" + networks = ["ERROR"] + unsafeNetworks = [] + groups = [] notBefore = "" notAfter = "" + issuer = "" publicKey = "" - groups = [] - networks = ["ERROR"] - unsafeNetworks = [] + curve = "" isCa = false - issuer = "" + fingerprint = "" + signature = "" } } diff --git a/lib/models/Certificate.dart b/lib/models/Certificate.dart index 8672ef37..2a17168e 100644 --- a/lib/models/Certificate.dart +++ b/lib/models/Certificate.dart @@ -18,50 +18,46 @@ class CertificateInfo { } class Certificate { - CertificateDetails details; - String fingerprint; - String signature; - - Certificate.debug() : details = CertificateDetails.debug(), fingerprint = "DEBUG", signature = "DEBUG"; - - Certificate.fromJson(Map json) - : details = CertificateDetails.fromJson(json['details']), - fingerprint = json['fingerprint'], - signature = json['signature']; -} - -class CertificateDetails { + int version; String name; - DateTime notBefore; - DateTime notAfter; - String publicKey; - List groups; List networks; List unsafeNetworks; + List groups; bool isCa; + DateTime notBefore; + DateTime notAfter; String issuer; + String publicKey; + String fingerprint; + String signature; - CertificateDetails.debug() - : name = "DEBUG", - notBefore = DateTime.now(), - notAfter = DateTime.now(), - publicKey = "", - groups = [], + Certificate.debug() + : version = 2, + name = "DEBUG", networks = [], unsafeNetworks = [], + groups = [], isCa = false, - issuer = "DEBUG"; + notBefore = DateTime.now(), + notAfter = DateTime.now(), + issuer = "DEBUG", + publicKey = "", + fingerprint = "DEBUG", + signature = "DEBUG"; - CertificateDetails.fromJson(Map json) - : name = json['name'], - notBefore = DateTime.parse(json['notBefore']), - notAfter = DateTime.parse(json['notAfter']), - publicKey = json['publicKey'], - groups = List.from(json['groups']), + Certificate.fromJson(Map json) + : version = json["version"], + name = json['name'], networks = List.from(json['networks']), unsafeNetworks = List.from(json['unsafeNetworks']), + groups = List.from(json['groups']), isCa = json['isCa'], - issuer = json['issuer']; + notBefore = DateTime.parse(json['notBefore']), + notAfter = DateTime.parse(json['notAfter']), + issuer = json['issuer'], + publicKey = json['publicKey'], + fingerprint = json['fingerprint'], + signature = json['signature']; } class CertificateValidity { diff --git a/lib/screens/HostInfoScreen.dart b/lib/screens/HostInfoScreen.dart index 3408b230..7bebdd3f 100644 --- a/lib/screens/HostInfoScreen.dart +++ b/lib/screens/HostInfoScreen.dart @@ -73,7 +73,7 @@ class _HostInfoScreenState extends State { ? ConfigPageItem( label: Text('Certificate'), labelWidth: 150, - content: Text(hostInfo.cert!.details.name), + content: Text(hostInfo.cert!.name), onPressed: () => Utils.openPage( context, diff --git a/lib/screens/SiteTunnelsScreen.dart b/lib/screens/SiteTunnelsScreen.dart index 114bfa62..b192d5d0 100644 --- a/lib/screens/SiteTunnelsScreen.dart +++ b/lib/screens/SiteTunnelsScreen.dart @@ -80,7 +80,7 @@ class _SiteTunnelsScreenState extends State { children: [Padding(padding: EdgeInsets.only(right: 10), child: icon), Text(hostInfo.vpnIp)], ), labelWidth: ipWidth, - content: Container(alignment: Alignment.centerRight, child: Text(hostInfo.cert?.details.name ?? "")), + content: Container(alignment: Alignment.centerRight, child: Text(hostInfo.cert?.name ?? "")), )); }).toList(); diff --git a/lib/screens/siteConfig/AddCertificateScreen.dart b/lib/screens/siteConfig/AddCertificateScreen.dart index 3dde5ec2..5d23a671 100644 --- a/lib/screens/siteConfig/AddCertificateScreen.dart +++ b/lib/screens/siteConfig/AddCertificateScreen.dart @@ -247,7 +247,7 @@ class _AddCertificateScreenState extends State { List certs = jsonDecode(rawCerts); if (certs.isNotEmpty) { var tryCertInfo = CertificateInfo.fromJson(certs.first); - if (tryCertInfo.cert.details.isCa) { + if (tryCertInfo.cert.isCa) { return Utils.popError( context, 'Error loading certificate content', diff --git a/lib/screens/siteConfig/CAListScreen.dart b/lib/screens/siteConfig/CAListScreen.dart index b37de676..290ff21d 100644 --- a/lib/screens/siteConfig/CAListScreen.dart +++ b/lib/screens/siteConfig/CAListScreen.dart @@ -81,7 +81,7 @@ class _CAListScreenState extends State { cas.forEach((key, ca) { items.add( ConfigPageItem( - content: Text(ca.cert.details.name), + content: Text(ca.cert.name), onPressed: () { Utils.openPage(context, (context) { return CertificateDetailsScreen( @@ -117,7 +117,7 @@ class _CAListScreenState extends State { List certs = jsonDecode(rawCerts); for (var rawCert in certs) { final info = CertificateInfo.fromJson(rawCert); - if (!info.cert.details.isCa) { + if (!info.cert.isCa) { ignored++; continue; } diff --git a/lib/screens/siteConfig/CertificateDetailsScreen.dart b/lib/screens/siteConfig/CertificateDetailsScreen.dart index 07fac9dc..fc12fb3c 100644 --- a/lib/screens/siteConfig/CertificateDetailsScreen.dart +++ b/lib/screens/siteConfig/CertificateDetailsScreen.dart @@ -85,11 +85,8 @@ class _CertificateDetailsScreenState extends State { Widget _buildID() { return ConfigSection( children: [ - ConfigItem(label: Text('Name'), content: SelectableText(certInfo.cert.details.name)), - ConfigItem( - label: Text('Type'), - content: Text(certInfo.cert.details.isCa ? 'CA certificate' : 'Client certificate'), - ), + ConfigItem(label: Text('Name'), content: SelectableText(certInfo.cert.name)), + ConfigItem(label: Text('Type'), content: Text(certInfo.cert.isCa ? 'CA certificate' : 'Client certificate')), ], ); } @@ -106,41 +103,30 @@ class _CertificateDetailsScreenState extends State { label: 'VALIDITY', children: [ ConfigItem(label: Text('Valid?'), content: valid), - ConfigItem( - label: Text('Created'), - content: SelectableText(certInfo.cert.details.notBefore.toLocal().toString()), - ), - ConfigItem( - label: Text('Expires'), - content: SelectableText(certInfo.cert.details.notAfter.toLocal().toString()), - ), + ConfigItem(label: Text('Created'), content: SelectableText(certInfo.cert.notBefore.toLocal().toString())), + ConfigItem(label: Text('Expires'), content: SelectableText(certInfo.cert.notAfter.toLocal().toString())), ], ); } Widget _buildFilters() { List items = []; - if (certInfo.cert.details.groups.isNotEmpty) { - items.add(ConfigItem(label: Text('Groups'), content: SelectableText(certInfo.cert.details.groups.join(', ')))); + if (certInfo.cert.groups.isNotEmpty) { + items.add(ConfigItem(label: Text('Groups'), content: SelectableText(certInfo.cert.groups.join(', ')))); } - if (certInfo.cert.details.networks.isNotEmpty) { - items.add( - ConfigItem(label: Text('Networks'), content: SelectableText(certInfo.cert.details.networks.join(', '))), - ); + if (certInfo.cert.networks.isNotEmpty) { + items.add(ConfigItem(label: Text('Networks'), content: SelectableText(certInfo.cert.networks.join(', ')))); } - if (certInfo.cert.details.unsafeNetworks.isNotEmpty) { + if (certInfo.cert.unsafeNetworks.isNotEmpty) { items.add( - ConfigItem( - label: Text('Unsafe Networks'), - content: SelectableText(certInfo.cert.details.unsafeNetworks.join(', ')), - ), + ConfigItem(label: Text('Unsafe Networks'), content: SelectableText(certInfo.cert.unsafeNetworks.join(', '))), ); } return items.isNotEmpty - ? ConfigSection(label: certInfo.cert.details.isCa ? 'FILTERS' : 'DETAILS', children: items) + ? ConfigSection(label: certInfo.cert.isCa ? 'FILTERS' : 'DETAILS', children: items) : Container(); } @@ -154,10 +140,7 @@ class _CertificateDetailsScreenState extends State { ), ConfigItem( label: Text('Public Key'), - content: SelectableText( - certInfo.cert.details.publicKey, - style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14), - ), + content: SelectableText(certInfo.cert.publicKey, style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)), crossAxisAlignment: CrossAxisAlignment.start, ), certInfo.rawCert != null @@ -210,7 +193,7 @@ class _CertificateDetailsScreenState extends State { return Container(); } - var title = certInfo.cert.details.isCa ? 'Delete CA?' : 'Delete cert?'; + var title = certInfo.cert.isCa ? 'Delete CA?' : 'Delete cert?'; return Padding( padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10), diff --git a/lib/screens/siteConfig/SiteConfigScreen.dart b/lib/screens/siteConfig/SiteConfigScreen.dart index 0a406cc1..148a9461 100644 --- a/lib/screens/siteConfig/SiteConfigScreen.dart +++ b/lib/screens/siteConfig/SiteConfigScreen.dart @@ -186,7 +186,7 @@ class _SiteConfigScreenState extends State { child: Icon(Icons.error, color: CupertinoColors.systemRed.resolveFrom(context), size: 20), ) : Container(), - certError ? Text('Needs attention') : Text(site.certInfo?.cert.details.name ?? 'Unknown certificate'), + certError ? Text('Needs attention') : Text(site.certInfo?.cert.name ?? 'Unknown certificate'), ], ), onPressed: () { diff --git a/nebula/mobileNebula.go b/nebula/mobileNebula.go index 7eef4bd1..06e265a0 100644 --- a/nebula/mobileNebula.go +++ b/nebula/mobileNebula.go @@ -21,7 +21,7 @@ import ( "gopkg.in/yaml.v2" ) -type m map[string]interface{} +type m map[string]any type CIDR struct { Ip string @@ -37,7 +37,7 @@ type Validity struct { type RawCert struct { RawCert string - Cert cert.Certificate + Cert m Validity Validity } @@ -183,7 +183,7 @@ func ParseCIDR(cidr string) (*CIDR, error) { }, nil } -// Returns a JSON representation of 1 or more certificates +// ParseCerts Returns a JSON representation of 1 or more certificates func ParseCerts(rawStringCerts string) (string, error) { var certs []RawCert var c cert.Certificate @@ -203,7 +203,7 @@ func ParseCerts(rawStringCerts string) (string, error) { rc := RawCert{ RawCert: string(rawCert), - Cert: c, + Cert: certToFlatJson(c), Validity: Validity{ Valid: true, }, @@ -234,6 +234,27 @@ func ParseCerts(rawStringCerts string) (string, error) { return string(rawJson), nil } +// certToFlatJson creates a flat version agnostic representation of a certificate +func certToFlatJson(c cert.Certificate) m { + cm := m{} + + cm["version"] = c.Version() + cm["name"] = c.Name() + cm["networks"] = c.Networks() + cm["unsafeNetworks"] = c.UnsafeNetworks() + cm["groups"] = c.Groups() + cm["isCa"] = c.IsCA() + cm["notBefore"] = c.NotBefore() + cm["notAfter"] = c.NotAfter() + cm["issuer"] = c.Issuer() + cm["publicKey"] = c.PublicKey() + cm["curve"] = c.Curve().String() + cm["fingerprint"], _ = c.Fingerprint() + cm["signature"] = c.Signature() + + return cm +} + func GenerateKeyPair() (string, error) { pub, priv, err := x25519Keypair() if err != nil { From 3f8126318fc5f848f027ec006b848c3a68e23de3 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 31 Oct 2025 23:15:06 -0500 Subject: [PATCH 3/5] Mostly complete support for ipv6 overlay and display fixes --- .../net/defined/mobile_nebula/MainActivity.kt | 21 +++++ .../defined/mobile_nebula/NebulaVpnService.kt | 52 +++++++---- .../PacketTunnelProvider.swift | 92 ++++++++++++++----- ios/Runner/AppDelegate.swift | 2 + lib/models/Certificate.dart | 71 +++++++++++--- lib/models/HostInfo.dart | 14 ++- lib/models/Site.dart | 2 +- lib/screens/HostInfoScreen.dart | 13 ++- lib/screens/MainScreen.dart | 33 ++++++- lib/screens/SiteTunnelsScreen.dart | 38 +++++--- .../siteConfig/CertificateDetailsScreen.dart | 28 +++++- lib/services/utils.dart | 5 - nebula/api.go | 4 +- nebula/control.go | 10 ++ nebula/go.mod | 5 - nebula/go.sum | 42 ++------- nebula/mobileNebula.go | 57 +++++++++--- 17 files changed, 349 insertions(+), 140 deletions(-) diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt index 6f502ecb..3826999b 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt @@ -83,6 +83,7 @@ class MainActivity: FlutterActivity() { "stopSite" -> stopSite() "active.listHostmap" -> activeListHostmap(call, result) + "active.listIndexes" -> activeListIndexes(call, result) "active.listPendingHostmap" -> activeListPendingHostmap(call, result) "active.getHostInfo" -> activeGetHostInfo(call, result) "active.setRemoteForTunnel" -> activeSetRemoteForTunnel(call, result) @@ -301,6 +302,26 @@ class MainActivity: FlutterActivity() { outMessenger?.send(msg) } + private fun activeListIndexes(call: MethodCall, result: MethodChannel.Result) { + val id = call.argument("id") + if (id == "") { + return result.error("required_argument", "id is a required argument", null) + } + + if (outMessenger == null || activeSiteId == null || activeSiteId != id) { + return result.success(null) + } + + val msg = Message.obtain() + msg.what = NebulaVpnService.MSG_LIST_INDEXES + msg.replyTo = Messenger(object: Handler(Looper.getMainLooper()) { + override fun handleMessage(msg: Message) { + result.success(msg.data.getString("data")) + } + }) + outMessenger?.send(msg) + } + private fun activeListPendingHostmap(call: MethodCall, result: MethodChannel.Result) { val id = call.argument("id") if (id == "") { diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt index 35a98681..4457a9ab 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/NebulaVpnService.kt @@ -28,6 +28,7 @@ class NebulaVpnService : VpnService() { const val MSG_UNREGISTER_CLIENT = 2 const val MSG_IS_RUNNING = 3 const val MSG_LIST_HOSTMAP = 4 + const val MSG_LIST_INDEXES = 10 const val MSG_LIST_PENDING_HOSTMAP = 5 const val MSG_GET_HOSTINFO = 6 const val MSG_SET_REMOTE_FOR_TUNNEL = 7 @@ -92,27 +93,40 @@ class NebulaVpnService : VpnService() { workManager!!.enqueue(workRequest) // We don't actually start here. In order to properly capture boot errors we wait until an IPC connection is made - return super.onStartCommand(intent, flags, startId) } private fun startVpn() { - val ipNet: CIDR - - try { - ipNet = mobileNebula.MobileNebula.parseCIDR(site!!.cert!!.cert.networks[0]) - } catch (err: Exception) { - return announceExit(site!!.id, err.message ?: "$err") - } - val builder = Builder() - .addAddress(ipNet.ip, ipNet.maskSize.toInt()) - .addRoute(ipNet.network, ipNet.maskSize.toInt()) .setMtu(site!!.mtu) .setSession(TAG) .allowFamily(OsConstants.AF_INET) .allowFamily(OsConstants.AF_INET6) + try { + site!!.cert!!.cert.networks.forEach { network -> + val cidr = mobileNebula.MobileNebula.parseCIDR(network) + builder.addAddress(cidr.address, cidr.prefixLength.toInt()) + builder.addRoute(cidr.maskedAddress, cidr.prefixLength.toInt()) + } + } catch (err: Exception) { + Log.e(TAG, "Got an error setting up vpn networks $err") + announceExit(site!!.id, err.message) + return stopSelf() + } + + // Add our unsafe routes + try { + site!!.unsafeRoutes.forEach { unsafeRoute -> + val unsafeCidr = mobileNebula.MobileNebula.parseCIDR(unsafeRoute.route) + builder.addRoute(unsafeCidr.maskedAddress, unsafeCidr.prefixLength.toInt()) + } + } catch (err: Exception) { + Log.e(TAG, "Got an error setting up unsafe routes $err") + announceExit(site!!.id, err.message) + return stopSelf() + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { builder.setMetered(false) } @@ -129,12 +143,6 @@ class NebulaVpnService : VpnService() { // RCS / Jibe disallowApp(builder, "com.google.android.apps.messaging") - // Add our unsafe routes - site!!.unsafeRoutes.forEach { unsafeRoute -> - val unsafeIPNet = mobileNebula.MobileNebula.parseCIDR(unsafeRoute.route) - builder.addRoute(unsafeIPNet.network, unsafeIPNet.maskSize.toInt()) - } - try { vpnInterface = builder.establish() nebula = mobileNebula.MobileNebula.newNebula(site!!.config, site!!.getKey(this), site!!.logFile, vpnInterface!!.detachFd().toLong()) @@ -285,6 +293,7 @@ class NebulaVpnService : VpnService() { MSG_UNREGISTER_CLIENT -> mClients.remove(msg.replyTo) MSG_IS_RUNNING -> isRunning() MSG_LIST_HOSTMAP -> listHostmap(msg) + MSG_LIST_INDEXES -> listIndexes(msg) MSG_LIST_PENDING_HOSTMAP -> listHostmap(msg) MSG_GET_HOSTINFO -> getHostInfo(msg) MSG_CLOSE_TUNNEL -> closeTunnel(msg) @@ -322,6 +331,15 @@ class NebulaVpnService : VpnService() { msg.replyTo.send(m) } + private fun listIndexes(msg: Message) { + if (protect(msg)) { return } + + val res = nebula!!.listIndexes(false) + val m = Message.obtain(null, msg.what) + m.data.putString("data", res) + msg.replyTo.send(m) + } + private fun getHostInfo(msg: Message) { if (protect(msg)) { return } diff --git a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift index 45e489c6..5c4e1390 100644 --- a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift +++ b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift @@ -84,29 +84,15 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // This is set to 127.0.0.1 because it has to be something.. let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") - - // Make sure our ip is routed to the tun device - var err: NSError? - let ipNet = MobileNebulaParseCIDR(_site.cert!.cert.networks[0], &err) - if err != nil { - throw err! - } - tunnelNetworkSettings.ipv4Settings = NEIPv4Settings( - addresses: [ipNet!.ip], subnetMasks: [ipNet!.maskCIDR]) - var routes: [NEIPv4Route] = [ - NEIPv4Route(destinationAddress: ipNet!.network, subnetMask: ipNet!.maskCIDR) - ] - - // Add our unsafe routes - try _site.unsafeRoutes.forEach { unsafeRoute in - let ipNet = MobileNebulaParseCIDR(unsafeRoute.route, &err) - if err != nil { - throw err! - } - routes.append(NEIPv4Route(destinationAddress: ipNet!.network, subnetMask: ipNet!.maskCIDR)) - } - - tunnelNetworkSettings.ipv4Settings!.includedRoutes = routes + + // Set up all ipv4/6 networks and unsafe routes + var (v4Settings, v6Settings) = try getNetworkAddressesAndRoutes( + networks: _site.cert!.cert.networks, + unsafeRoutes: _site.unsafeRoutes + ); + + tunnelNetworkSettings.ipv4Settings = v4Settings + tunnelNetworkSettings.ipv6Settings = v6Settings tunnelNetworkSettings.mtu = _site.mtu as NSNumber try await self.setTunnelNetworkSettings(tunnelNetworkSettings) @@ -123,6 +109,59 @@ class PacketTunnelProvider: NEPacketTunnelProvider { self.nebula!.start() self.dnUpdater.updateSingleLoop(site: self.site!, onUpdate: self.handleDNUpdate) } + + private func getNetworkAddressesAndRoutes(networks: [String], unsafeRoutes: [UnsafeRoute]) throws -> (NEIPv4Settings, NEIPv6Settings) { + var err: NSError? + var v4Addresses: [String] = [] + var v4Netmasks: [String] = [] + var v4Routes: [NEIPv4Route] = [] + + var v6Addresses: [String] = [] + var v6PrefixLengths: [NSNumber] = [] + var v6Routes: [NEIPv6Route] = [] + + for rawNetwork in networks { + let network = MobileNebulaParseCIDR(rawNetwork, &err) + if err != nil { + throw err! + } + + if network!.ipLen == 4 { + v4Addresses.append(network!.address) + v4Netmasks.append(network!.subnetMask) + v4Routes.append(NEIPv4Route(destinationAddress: network!.maskedAddress, subnetMask: network!.subnetMask)) + } else { + v6Addresses.append(network!.address) + v6PrefixLengths.append(network!.prefixLength as NSNumber) + v6Routes.append(NEIPv6Route(destinationAddress: network!.maskedAddress, networkPrefixLength: network!.prefixLength as NSNumber)) + } + } + + for unsafeRoute in unsafeRoutes { + let network = MobileNebulaParseCIDR(unsafeRoute.route, &err) + if err != nil { + throw err! + } + + if network!.ipLen == 4 { + v4Addresses.append(network!.address) + v4Netmasks.append(network!.subnetMask) + v4Routes.append(NEIPv4Route(destinationAddress: network!.maskedAddress, subnetMask: network!.subnetMask)) + } else { + v6Addresses.append(network!.address) + v6PrefixLengths.append(network!.prefixLength as NSNumber) + v6Routes.append(NEIPv6Route(destinationAddress: network!.maskedAddress, networkPrefixLength: network!.prefixLength as NSNumber)) + } + } + + let v4Settings = NEIPv4Settings(addresses: v4Addresses, subnetMasks: v4Netmasks) + v4Settings.includedRoutes = v4Routes + + let v6Settings = NEIPv6Settings(addresses: v6Addresses, networkPrefixLengths: v6PrefixLengths) + v6Settings.includedRoutes = v6Routes + + return (v4Settings, v6Settings) + } private func handleDNUpdate(newSite: Site) { do { @@ -246,6 +285,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { //TODO: try catch over all this switch call.command { case "listHostmap": (data, error) = listHostmap(pending: false) + case "listIndexes": (data, error) = listIndexes(pending: false) case "listPendingHostmap": (data, error) = listHostmap(pending: true) case "getHostInfo": (data, error) = getHostInfo(args: call.arguments!) case "setRemoteForTunnel": (data, error) = setRemoteForTunnel(args: call.arguments!) @@ -269,6 +309,12 @@ class PacketTunnelProvider: NEPacketTunnelProvider { let res = nebula!.listHostmap(pending, error: &err) return (JSON(res), err) } + + private func listIndexes(pending: Bool) -> (JSON?, (any Error)?) { + var err: NSError? + let res = nebula!.listIndexes(pending, error: &err) + return (JSON(res), err) + } private func getHostInfo(args: JSON) -> (JSON?, (any Error)?) { var err: NSError? diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 885fffcd..5ea07705 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -62,6 +62,8 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError { case "active.listHostmap": self.vpnRequest(command: "listHostmap", arguments: call.arguments, result: result) + case "active.listIndexes": + self.vpnRequest(command: "listIndexes", arguments: call.arguments, result: result) case "active.listPendingHostmap": self.vpnRequest(command: "listPendingHostmap", arguments: call.arguments, result: result) case "active.getHostInfo": diff --git a/lib/models/Certificate.dart b/lib/models/Certificate.dart index 2a17168e..c085125c 100644 --- a/lib/models/Certificate.dart +++ b/lib/models/Certificate.dart @@ -28,6 +28,7 @@ class Certificate { DateTime notAfter; String issuer; String publicKey; + String curve; String fingerprint; String signature; @@ -42,22 +43,66 @@ class Certificate { notAfter = DateTime.now(), issuer = "DEBUG", publicKey = "", + curve = "", fingerprint = "DEBUG", signature = "DEBUG"; - Certificate.fromJson(Map json) - : version = json["version"], - name = json['name'], - networks = List.from(json['networks']), - unsafeNetworks = List.from(json['unsafeNetworks']), - groups = List.from(json['groups']), - isCa = json['isCa'], - notBefore = DateTime.parse(json['notBefore']), - notAfter = DateTime.parse(json['notAfter']), - issuer = json['issuer'], - publicKey = json['publicKey'], - fingerprint = json['fingerprint'], - signature = json['signature']; + factory Certificate.fromJson(Map json) { + Map details = json; + String publicKey; + if (json.containsKey("details")) { + details = json["details"]; + //TODO: currently swift and kotlin flatten the certificate structure but + // nebula outputs cert json in the nested format + switch (json["version"]) { + case 1: + // In V1 the public key was under details + publicKey = details["publicKey"]; + break; + case 2: + // In V2 the public key moved to the top level + publicKey = json["publicKey"]; + break; + default: + throw Exception('Unknown certificate version'); + } + } else { + // This is a flattened certificate format, publicKey is at the top + publicKey = json["publicKey"]; + } + + return Certificate( + json["version"], + details["name"], + List.from(details['networks'] ?? []), + List.from(details['unsafeNetworks'] ?? []), + List.from(details['groups']), + details['isCa'], + DateTime.parse(details['notBefore']), + DateTime.parse(details['notAfter']), + details['issuer'], + publicKey, + json['curve'], + json['fingerprint'], + json['signature'], + ); + } + + Certificate( + this.version, + this.name, + this.networks, + this.unsafeNetworks, + this.groups, + this.isCa, + this.notBefore, + this.notAfter, + this.issuer, + this.publicKey, + this.curve, + this.fingerprint, + this.signature, + ); } class CertificateValidity { diff --git a/lib/models/HostInfo.dart b/lib/models/HostInfo.dart index d9c14c02..4c3b07cb 100644 --- a/lib/models/HostInfo.dart +++ b/lib/models/HostInfo.dart @@ -1,7 +1,7 @@ import 'package:mobile_nebula/models/Certificate.dart'; class HostInfo { - String vpnIp; + List vpnAddrs; int localIndex; int remoteIndex; List remoteAddresses; @@ -10,7 +10,7 @@ class HostInfo { int messageCounter; HostInfo({ - required this.vpnIp, + required this.vpnAddrs, required this.localIndex, required this.remoteIndex, required this.remoteAddresses, @@ -36,8 +36,16 @@ class HostInfo { remoteAddresses.add(UDPAddress.fromJson(val)); }); + addrs = json['vpnAddrs']; + List vpnAddrs = []; + addrs?.forEach((val) { + if (val is String) { + vpnAddrs.add(val); + } + }); + return HostInfo( - vpnIp: json['vpnIp'], + vpnAddrs: vpnAddrs, localIndex: json['localIndex'], remoteIndex: json['remoteIndex'], remoteAddresses: remoteAddresses, diff --git a/lib/models/Site.dart b/lib/models/Site.dart index 21da4da5..11523657 100644 --- a/lib/models/Site.dart +++ b/lib/models/Site.dart @@ -275,7 +275,7 @@ class Site { Future> listHostmap() async { try { - var ret = await platform.invokeMethod("active.listHostmap", {"id": id}); + var ret = await platform.invokeMethod("active.listIndexes", {"id": id}); if (ret == null || ret == "null") { return []; } diff --git a/lib/screens/HostInfoScreen.dart b/lib/screens/HostInfoScreen.dart index 7bebdd3f..8a6cf37f 100644 --- a/lib/screens/HostInfoScreen.dart +++ b/lib/screens/HostInfoScreen.dart @@ -68,7 +68,12 @@ class _HostInfoScreenState extends State { Widget _buildMain() { return ConfigSection( children: [ - ConfigItem(label: Text('VPN IP'), labelWidth: 150, content: SelectableText(hostInfo.vpnIp)), + ConfigItem( + label: Text('VPN Addresses'), + labelWidth: 150, + crossAxisAlignment: CrossAxisAlignment.start, + content: SelectableText(hostInfo.vpnAddrs.join('\n')), + ), hostInfo.cert != null ? ConfigPageItem( label: Text('Certificate'), @@ -138,7 +143,7 @@ class _HostInfoScreenState extends State { } try { - final h = await widget.site.setRemoteForTunnel(hostInfo.vpnIp, remote); + final h = await widget.site.setRemoteForTunnel(hostInfo.vpnAddrs[0], remote); if (h != null) { _setHostInfo(h); } @@ -184,7 +189,7 @@ class _HostInfoScreenState extends State { onPressed: () => Utils.confirmDelete(context, 'Close Tunnel?', () async { try { - await widget.site.closeTunnel(hostInfo.vpnIp); + await widget.site.closeTunnel(hostInfo.vpnAddrs[0]); if (widget.onChanged != null) { widget.onChanged!(); } @@ -200,7 +205,7 @@ class _HostInfoScreenState extends State { _getHostInfo() async { try { - final h = await widget.site.getHostInfo(hostInfo.vpnIp, widget.pending); + final h = await widget.site.getHostInfo(hostInfo.vpnAddrs[0], widget.pending); if (h == null) { return Utils.popError(context, '', 'The tunnel for this host no longer exists'); } diff --git a/lib/screens/MainScreen.dart b/lib/screens/MainScreen.dart index bfd82d0a..52a07369 100644 --- a/lib/screens/MainScreen.dart +++ b/lib/screens/MainScreen.dart @@ -21,7 +21,7 @@ import 'package:mobile_nebula/services/utils.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:uuid/uuid.dart'; -/// Contains an expired CA and certificate +/// Contains an expired v1 CA and certificate const badDebugSave = { 'name': 'Bad Site', 'cert': '''-----BEGIN NEBULA CERTIFICATE----- @@ -40,7 +40,7 @@ mUOcsdFcCZiXrj7ryQIG1+WfqA46w71A/lV4nAc= -----END NEBULA CERTIFICATE-----''', }; -/// Contains an expired CA and certificate +/// Contains a non-expired v1 CA and certificate const goodDebugSave = { 'name': 'Good Site', 'cert': '''-----BEGIN NEBULA CERTIFICATE----- @@ -59,6 +59,29 @@ MAIH7gzreMGgrH/yR6rZpIHR3DxJ3E0aHtEI -----END NEBULA CERTIFICATE-----''', }; +/// Contains a non-expired v2 CA and certificate +const goodDebugSaveV2 = { + 'name': 'Good Site V2', + 'cert': '''-----BEGIN NEBULA CERTIFICATE V2----- +MIIBHKCBtYAMVjIgVGVzdCBIb3N0oTQEBQoBAAIQBAXAqAECGAQR/ZgAAAAAAAAA +AAAAAAAAAkAEEf2Z7u7u7u7uqqq7u8zM//JAohoEBQAAAAAABBEAAAAAAAAAAAAA +AAAAAAAAAKMlDAt0ZXN0LWdyb3VwMQwLdGVzdC1ncm91cDIMCWZvb2JhcmJheoUE +aQUSxIYEauZGOYcganAHTUvQcytewZBsfkiAhruIuQgoJ0vSpRK180ipgQuCIG06 +ZRKG32WKsCKEls5eENf5QkUO6pzaGGgCdLl3rbRJg0Db4EhAHpvtNbumzMs2lamb +zkFjSWHl6qTvhA/3ZaKuD09wp9NEHhkL8l9uwz9KfSB6wHsZDC55i/HBo9YKCPIB +-----END NEBULA CERTIFICATE V2-----''', + 'key': '''-----BEGIN NEBULA X25519 PRIVATE KEY----- +QyQYT2IxfdtDGUirKjhUMIT5O6W8CE/JzJquqQRZhFU= +-----END NEBULA X25519 PRIVATE KEY-----''', + 'ca': '''-----BEGIN NEBULA CERTIFICATE V2----- +MIHeoHiAClYyIFRlc3QgQ0GhNAQFCgEAABAEBcCoAQAYBBH9mAAAAAAAAAAAAAAA +AAABQAQR/Znu7u7u7u4AAAAAAAAAAECjJQwLdGVzdC1ncm91cDEMC3Rlc3QtZ3Jv +dXAyDAlmb29iYXJiYXqEAf+FBGkFErqGBGrmRjqCIB1M/UJegMPjdpCkNV4spaH6 +48Zrc6EF6PgB0dmTjsGug0DHOiCTMm/fRkD1R3E+gtI53eTJk/gaRyphMvSJUuyJ +Yd6DdoCpAMXb7cpgDfW8PGkU/77HWjLhu5HM28YHlioC +-----END NEBULA CERTIFICATE V2-----''', +}; + class MainScreen extends StatefulWidget { const MainScreen(this.dnEnrollStream, {super.key}); @@ -114,9 +137,9 @@ class _MainScreenState extends State { Widget? debugSite; if (kDebugMode) { - debugSite = Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [_debugSave(badDebugSave), _debugSave(goodDebugSave), _debugClearKeys()], + debugSite = Wrap( + alignment: WrapAlignment.center, + children: [_debugSave(badDebugSave), _debugSave(goodDebugSave), _debugSave(goodDebugSaveV2), _debugClearKeys()], ); } diff --git a/lib/screens/SiteTunnelsScreen.dart b/lib/screens/SiteTunnelsScreen.dart index b192d5d0..ce5edf24 100644 --- a/lib/screens/SiteTunnelsScreen.dart +++ b/lib/screens/SiteTunnelsScreen.dart @@ -51,11 +51,9 @@ class _SiteTunnelsScreenState extends State { @override Widget build(BuildContext context) { - final double ipWidth = Utils.textSize("000.000.000.000", CupertinoTheme.of(context).textTheme.textStyle).width + 32; - final List children = tunnels.map((hostInfo) { - final isLh = site.staticHostmap[hostInfo.vpnIp]?.lighthouse ?? false; + final isLh = _isLighthouse(hostInfo.vpnAddrs); final icon = switch (isLh) { true => Icon(Icons.lightbulb_outline, color: CupertinoColors.placeholderText.resolveFrom(context)), false => Icon(Icons.computer, color: CupertinoColors.placeholderText.resolveFrom(context)), @@ -76,11 +74,15 @@ class _SiteTunnelsScreenState extends State { supportsQRScanning: widget.supportsQRScanning, ), ), - label: Row( - children: [Padding(padding: EdgeInsets.only(right: 10), child: icon), Text(hostInfo.vpnIp)], + content: Container( + alignment: Alignment.centerLeft, + child: Row( + children: [ + Padding(padding: EdgeInsets.only(right: 10), child: icon), + Text(hostInfo.cert?.name ?? hostInfo.vpnAddrs[0]), + ], + ), ), - labelWidth: ipWidth, - content: Container(alignment: Alignment.centerRight, child: Text(hostInfo.cert?.name ?? "")), )); }).toList(); @@ -104,7 +106,7 @@ class _SiteTunnelsScreenState extends State { _sortTunnels() { tunnels.sort((a, b) { - final aLh = _isLighthouse(a.vpnIp), bLh = _isLighthouse(b.vpnIp); + final aLh = _isLighthouse(a.vpnAddrs), bLh = _isLighthouse(b.vpnAddrs); if (aLh && !bLh) { return -1; @@ -112,12 +114,26 @@ class _SiteTunnelsScreenState extends State { return 1; } - return Utils.ip2int(a.vpnIp) - Utils.ip2int(b.vpnIp); + final aName = a.cert?.name ?? ""; + final bName = b.cert?.name ?? ""; + final name = aName.compareTo(bName); + if (name != 0) { + return name; + } + + return a.vpnAddrs[0].compareTo(b.vpnAddrs[0]); }); } - bool _isLighthouse(String vpnIp) { - return site.staticHostmap[vpnIp]?.lighthouse ?? false; + bool _isLighthouse(List vpnAddrs) { + var isLh = false; + for (var vpnAddr in vpnAddrs) { + if (site.staticHostmap[vpnAddr]?.lighthouse ?? false) { + isLh = true; + break; + } + } + return isLh; } _listHostmap() async { diff --git a/lib/screens/siteConfig/CertificateDetailsScreen.dart b/lib/screens/siteConfig/CertificateDetailsScreen.dart index fc12fb3c..067090fe 100644 --- a/lib/screens/siteConfig/CertificateDetailsScreen.dart +++ b/lib/screens/siteConfig/CertificateDetailsScreen.dart @@ -86,6 +86,7 @@ class _CertificateDetailsScreenState extends State { return ConfigSection( children: [ ConfigItem(label: Text('Name'), content: SelectableText(certInfo.cert.name)), + ConfigItem(label: Text('Version'), content: Text(certInfo.cert.version.toString())), ConfigItem(label: Text('Type'), content: Text(certInfo.cert.isCa ? 'CA certificate' : 'Client certificate')), ], ); @@ -112,16 +113,32 @@ class _CertificateDetailsScreenState extends State { Widget _buildFilters() { List items = []; if (certInfo.cert.groups.isNotEmpty) { - items.add(ConfigItem(label: Text('Groups'), content: SelectableText(certInfo.cert.groups.join(', ')))); + items.add( + ConfigItem( + label: Text('Groups'), + content: SelectableText(certInfo.cert.groups.join('\n')), + crossAxisAlignment: CrossAxisAlignment.start, + ), + ); } if (certInfo.cert.networks.isNotEmpty) { - items.add(ConfigItem(label: Text('Networks'), content: SelectableText(certInfo.cert.networks.join(', ')))); + items.add( + ConfigItem( + label: Text('Networks'), + content: SelectableText(certInfo.cert.networks.join('\n')), + crossAxisAlignment: CrossAxisAlignment.start, + ), + ); } if (certInfo.cert.unsafeNetworks.isNotEmpty) { items.add( - ConfigItem(label: Text('Unsafe Networks'), content: SelectableText(certInfo.cert.unsafeNetworks.join(', '))), + ConfigItem( + label: Text('Unsafe Networks'), + content: SelectableText(certInfo.cert.unsafeNetworks.join('\n')), + crossAxisAlignment: CrossAxisAlignment.start, + ), ); } @@ -133,6 +150,11 @@ class _CertificateDetailsScreenState extends State { Widget _buildAdvanced() { return ConfigSection( children: [ + ConfigItem( + label: Text('Curve'), + content: SelectableText(certInfo.cert.curve), + crossAxisAlignment: CrossAxisAlignment.start, + ), ConfigItem( label: Text('Fingerprint'), content: SelectableText(certInfo.cert.fingerprint, style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)), diff --git a/lib/services/utils.dart b/lib/services/utils.dart index b625b7bf..21b6c038 100644 --- a/lib/services/utils.dart +++ b/lib/services/utils.dart @@ -170,11 +170,6 @@ class Utils { } } - static int ip2int(String ip) { - final parts = ip.split('.'); - return int.parse(parts[3]) | int.parse(parts[2]) << 8 | int.parse(parts[1]) << 16 | int.parse(parts[0]) << 24; - } - static Future pickFile(BuildContext context) async { await FilePicker.platform.clearTemporaryFiles(); final result = await FilePicker.platform.pickFiles(allowMultiple: false); diff --git a/nebula/api.go b/nebula/api.go index 03ca84eb..702d4aa8 100644 --- a/nebula/api.go +++ b/nebula/api.go @@ -109,7 +109,7 @@ func (c *APIClient) TryUpdate(siteName string, hostID string, privateKey string, defer cancel() updateAvailable, err := c.c.CheckForUpdate(ctx, creds) switch { - case errors.As(err, &dnapi.ErrInvalidCredentials): + case errors.Is(err, dnapi.ErrInvalidCredentials): return nil, InvalidCredentialsError{} case err != nil: return nil, fmt.Errorf("CheckForUpdate error: %s", err) @@ -124,7 +124,7 @@ func (c *APIClient) TryUpdate(siteName string, hostID string, privateKey string, defer updateCancel() cfg, pkey, newCreds, _, err := c.c.DoUpdate(updateCtx, creds) switch { - case errors.As(err, &dnapi.ErrInvalidCredentials): + case errors.Is(err, dnapi.ErrInvalidCredentials): return nil, InvalidCredentialsError{} case err != nil: return nil, fmt.Errorf("DoUpdate error: %s", err) diff --git a/nebula/control.go b/nebula/control.go index 09ea311c..1eec1aa7 100644 --- a/nebula/control.go +++ b/nebula/control.go @@ -106,6 +106,16 @@ func (n *Nebula) ListHostmap(pending bool) (string, error) { return string(b), nil } +func (n *Nebula) ListIndexes(pending bool) (string, error) { + indexes := n.c.ListHostmapIndexes(pending) + b, err := json.Marshal(indexes) + if err != nil { + return "", err + } + + return string(b), nil +} + func (n *Nebula) GetHostInfoByVpnIp(vpnIp string, pending bool) (string, error) { netVpnIp, err := netip.ParseAddr(vpnIp) if err != nil { diff --git a/nebula/go.mod b/nebula/go.mod index 9488ace8..0390a8ea 100644 --- a/nebula/go.mod +++ b/nebula/go.mod @@ -17,16 +17,13 @@ require ( github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.14.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/gaissmai/bart v0.26.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/klauspost/compress v1.18.0 // indirect github.com/miekg/dns v1.1.68 // indirect - github.com/miekg/pkcs11 v1.1.2-0.20231115102856-9078ad6b9d4b // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f // indirect github.com/prometheus/client_golang v1.23.2 // indirect @@ -35,7 +32,6 @@ require ( github.com/prometheus/procfs v0.19.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect - github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect github.com/vishvananda/netlink v1.3.1 // indirect github.com/vishvananda/netns v0.0.5 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect @@ -50,5 +46,4 @@ require ( golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/nebula/go.sum b/nebula/go.sum index b6d97c0d..5d4611b2 100644 --- a/nebula/go.sum +++ b/nebula/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/DefinedNet/dnapi v0.0.0-20251117181834-1112b1c2813b h1:qqhoqcZnsLhCsZNFCgAYehtXwX4eyfO/moyMGeD9fpg= github.com/DefinedNet/dnapi v0.0.0-20251117181834-1112b1c2813b/go.mod h1:N6BTss8f8BEoNdO+rQZJZjIOu3lIbwMgm8B2D2o3fUk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -16,8 +16,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA= -github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -28,8 +26,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= -github.com/gaissmai/bart v0.13.0 h1:pItEhXDVVebUa+i978FfQ7ye8xZc1FrMgs8nJPPWAgA= -github.com/gaissmai/bart v0.13.0/go.mod h1:qSes2fnJ8hB410BW0ymHUN/eQkuGpTYyJcN8sKMYpJU= github.com/gaissmai/bart v0.26.0 h1:xOZ57E9hJLBiQaSyeZa9wgWhGuzfGACgqp4BE77OkO0= github.com/gaissmai/bart v0.26.0/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -57,9 +53,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= @@ -71,8 +66,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -87,12 +81,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.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= 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/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= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -112,33 +102,24 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= -github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8= github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.19.1 h1:QVtROpTkphuXuNlnCv3m1ut3JytkXHtQ3xvck/YmzMM= github.com/prometheus/procfs v0.19.1/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -153,27 +134,22 @@ github.com/slackhq/nebula v1.9.7 h1:v5u46efIyYHGdfjFnozQbRRhMdaB9Ma1SSTcUcE2lfE= github.com/slackhq/nebula v1.9.7/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= -github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw= -github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= -github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= -github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= -github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -249,8 +225,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= -golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= -golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+ZbWg+4sHnLp52d5yiIPUxMBSt4X9A= golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= @@ -263,8 +237,6 @@ 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.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/nebula/mobileNebula.go b/nebula/mobileNebula.go index 06e265a0..39ef2132 100644 --- a/nebula/mobileNebula.go +++ b/nebula/mobileNebula.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "net" + "net/netip" "strings" "time" @@ -24,10 +25,11 @@ import ( type m map[string]any type CIDR struct { - Ip string - MaskCIDR string - MaskSize int - Network string + IPLen int // The number of bytes in the address family, 4 for ipv4, 16 for ipv6 + Address string // Apple and Android wants the string of the ip address + MaskedAddress string // Apple wants the address masked by SubnetMask for routes + SubnetMask string // Apple wants the old style subnet mask for ipv4 (255.255.255.0), this will be empty for ipv6 CIDRs + PrefixLength int // Apple wants the prefix length from the cidr notation when dealing with ipv6 and Android always wants it } type Validity struct { @@ -169,17 +171,26 @@ func GetConfigSetting(configData string, setting string) string { } func ParseCIDR(cidr string) (*CIDR, error) { - ip, ipNet, err := net.ParseCIDR(cidr) + p, err := netip.ParsePrefix(cidr) if err != nil { return nil, err } - size, _ := ipNet.Mask.Size() + + if p.Addr().Is4() { + return &CIDR{ + IPLen: net.IPv6len, + Address: p.Addr().String(), + SubnetMask: net.IP(net.CIDRMask(p.Bits(), net.IPv4len)).String(), + PrefixLength: p.Bits(), + MaskedAddress: p.Masked().Addr().String(), + }, nil + } return &CIDR{ - Ip: ip.String(), - MaskCIDR: fmt.Sprintf("%d.%d.%d.%d", ipNet.Mask[0], ipNet.Mask[1], ipNet.Mask[2], ipNet.Mask[3]), - MaskSize: size, - Network: ipNet.IP.String(), + IPLen: net.IPv6len, + Address: p.Addr().String(), + PrefixLength: p.Bits(), + MaskedAddress: p.Masked().Addr().String(), }, nil } @@ -240,9 +251,29 @@ func certToFlatJson(c cert.Certificate) m { cm["version"] = c.Version() cm["name"] = c.Name() - cm["networks"] = c.Networks() - cm["unsafeNetworks"] = c.UnsafeNetworks() - cm["groups"] = c.Groups() + + // Force list types to not print null + networks := c.Networks() + if len(networks) == 0 { + cm["networks"] = []netip.Prefix{} + } else { + cm["networks"] = networks + } + + unsafeNetworks := c.UnsafeNetworks() + if len(unsafeNetworks) == 0 { + cm["unsafeNetworks"] = []netip.Prefix{} + } else { + cm["unsafeNetworks"] = unsafeNetworks + } + + groups := c.Groups() + if len(groups) == 0 { + cm["groups"] = []string{} + } else { + cm["groups"] = groups + } + cm["isCa"] = c.IsCA() cm["notBefore"] = c.NotBefore() cm["notAfter"] = c.NotAfter() From 2f8ce412b6e2d220d282b20b93b28b6d40d9d45b Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 31 Oct 2025 23:20:01 -0500 Subject: [PATCH 4/5] Swift fmt fix --- .../PacketTunnelProvider.swift | 60 +++++++++++++------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift index 5c4e1390..0777763b 100644 --- a/ios/NebulaNetworkExtension/PacketTunnelProvider.swift +++ b/ios/NebulaNetworkExtension/PacketTunnelProvider.swift @@ -84,13 +84,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider { // This is set to 127.0.0.1 because it has to be something.. let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") - + // Set up all ipv4/6 networks and unsafe routes - var (v4Settings, v6Settings) = try getNetworkAddressesAndRoutes( + let (v4Settings, v6Settings) = try getNetworkAddressesAndRoutes( networks: _site.cert!.cert.networks, unsafeRoutes: _site.unsafeRoutes - ); - + ) + tunnelNetworkSettings.ipv4Settings = v4Settings tunnelNetworkSettings.ipv6Settings = v6Settings tunnelNetworkSettings.mtu = _site.mtu as NSNumber @@ -109,57 +109,79 @@ class PacketTunnelProvider: NEPacketTunnelProvider { self.nebula!.start() self.dnUpdater.updateSingleLoop(site: self.site!, onUpdate: self.handleDNUpdate) } - - private func getNetworkAddressesAndRoutes(networks: [String], unsafeRoutes: [UnsafeRoute]) throws -> (NEIPv4Settings, NEIPv6Settings) { + + private func getNetworkAddressesAndRoutes(networks: [String], unsafeRoutes: [UnsafeRoute]) throws + -> (NEIPv4Settings, NEIPv6Settings) + { var err: NSError? var v4Addresses: [String] = [] var v4Netmasks: [String] = [] var v4Routes: [NEIPv4Route] = [] - + var v6Addresses: [String] = [] var v6PrefixLengths: [NSNumber] = [] var v6Routes: [NEIPv6Route] = [] - + for rawNetwork in networks { let network = MobileNebulaParseCIDR(rawNetwork, &err) if err != nil { throw err! } - + if network!.ipLen == 4 { v4Addresses.append(network!.address) v4Netmasks.append(network!.subnetMask) - v4Routes.append(NEIPv4Route(destinationAddress: network!.maskedAddress, subnetMask: network!.subnetMask)) + v4Routes.append( + NEIPv4Route( + destinationAddress: network!.maskedAddress, + subnetMask: network!.subnetMask + ) + ) } else { v6Addresses.append(network!.address) v6PrefixLengths.append(network!.prefixLength as NSNumber) - v6Routes.append(NEIPv6Route(destinationAddress: network!.maskedAddress, networkPrefixLength: network!.prefixLength as NSNumber)) + v6Routes.append( + NEIPv6Route( + destinationAddress: network!.maskedAddress, + networkPrefixLength: network!.prefixLength as NSNumber + ) + ) } } - + for unsafeRoute in unsafeRoutes { let network = MobileNebulaParseCIDR(unsafeRoute.route, &err) if err != nil { throw err! } - + if network!.ipLen == 4 { v4Addresses.append(network!.address) v4Netmasks.append(network!.subnetMask) - v4Routes.append(NEIPv4Route(destinationAddress: network!.maskedAddress, subnetMask: network!.subnetMask)) + v4Routes.append( + NEIPv4Route( + destinationAddress: network!.maskedAddress, + subnetMask: network!.subnetMask + ) + ) } else { v6Addresses.append(network!.address) v6PrefixLengths.append(network!.prefixLength as NSNumber) - v6Routes.append(NEIPv6Route(destinationAddress: network!.maskedAddress, networkPrefixLength: network!.prefixLength as NSNumber)) + v6Routes.append( + NEIPv6Route( + destinationAddress: network!.maskedAddress, + networkPrefixLength: network!.prefixLength as NSNumber + ) + ) } } - + let v4Settings = NEIPv4Settings(addresses: v4Addresses, subnetMasks: v4Netmasks) v4Settings.includedRoutes = v4Routes - + let v6Settings = NEIPv6Settings(addresses: v6Addresses, networkPrefixLengths: v6PrefixLengths) v6Settings.includedRoutes = v6Routes - + return (v4Settings, v6Settings) } @@ -309,7 +331,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { let res = nebula!.listHostmap(pending, error: &err) return (JSON(res), err) } - + private func listIndexes(pending: Bool) -> (JSON?, (any Error)?) { var err: NSError? let res = nebula!.listIndexes(pending, error: &err) From a2cd4f59aef5c4bcb03ec3c500cda298a8cd02cb Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Thu, 4 Dec 2025 13:57:37 -0600 Subject: [PATCH 5/5] Point to the actual v1.10 release --- nebula/go.mod | 17 +++++++++-------- nebula/go.sum | 30 ++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/nebula/go.mod b/nebula/go.mod index 0390a8ea..b0364d67 100644 --- a/nebula/go.mod +++ b/nebula/go.mod @@ -5,10 +5,10 @@ go 1.25 // replace github.com/slackhq/nebula => /Volumes/T7/nate/src/github.com/slackhq/nebula require ( - github.com/DefinedNet/dnapi v0.0.0-20251117181834-1112b1c2813b + github.com/DefinedNet/dnapi v0.0.0-20251210211559-8ae1e6743199 github.com/sirupsen/logrus v1.9.3 - github.com/slackhq/nebula v1.9.7 - golang.org/x/crypto v0.44.0 + github.com/slackhq/nebula v1.10.1-0.20251210163936-3ec527e42cec + golang.org/x/crypto v0.46.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -24,6 +24,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/miekg/dns v1.1.68 // indirect + github.com/miekg/pkcs11 v1.1.2-0.20231115102856-9078ad6b9d4b // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f // indirect github.com/prometheus/client_golang v1.23.2 // indirect @@ -31,16 +32,16 @@ require ( github.com/prometheus/common v0.67.2 // indirect github.com/prometheus/procfs v0.19.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect - github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect + github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect github.com/vishvananda/netlink v1.3.1 // indirect github.com/vishvananda/netns v0.0.5 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect golang.org/x/tools v0.39.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect diff --git a/nebula/go.sum b/nebula/go.sum index 5d4611b2..bd1bbc6a 100644 --- a/nebula/go.sum +++ b/nebula/go.sum @@ -3,6 +3,8 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/DefinedNet/dnapi v0.0.0-20251117181834-1112b1c2813b h1:qqhoqcZnsLhCsZNFCgAYehtXwX4eyfO/moyMGeD9fpg= github.com/DefinedNet/dnapi v0.0.0-20251117181834-1112b1c2813b/go.mod h1:N6BTss8f8BEoNdO+rQZJZjIOu3lIbwMgm8B2D2o3fUk= +github.com/DefinedNet/dnapi v0.0.0-20251210211559-8ae1e6743199 h1:sYdbeQcXjUyFrlR3KE7rbhPLrSrq0tVAxaHQnfUxaMs= +github.com/DefinedNet/dnapi v0.0.0-20251210211559-8ae1e6743199/go.mod h1:vmEciuymyw9SGuI2c7FjNtrp9zSMjux9eFiF8tYPjdc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -83,6 +85,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ 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/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= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -130,10 +134,12 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd 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/slackhq/nebula v1.9.7 h1:v5u46efIyYHGdfjFnozQbRRhMdaB9Ma1SSTcUcE2lfE= -github.com/slackhq/nebula v1.9.7/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= -github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= -github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= +github.com/slackhq/nebula v1.10.0 h1:uhu4Cpzw3pXyDJ8G1fMSppsvG7aE9XCt4UaauggHax0= +github.com/slackhq/nebula v1.10.0/go.mod h1:PmYcyoGhAX4X8lCzJjGv7aLTBbFbPy7QeWbpwWvJf+Y= +github.com/slackhq/nebula v1.10.1-0.20251210163936-3ec527e42cec h1:F251X4hgG3Fen49ouS7yUVcwYkvvCjb5bmRFAbMnm+c= +github.com/slackhq/nebula v1.10.1-0.20251210163936-3ec527e42cec/go.mod h1:mqXWEQjg+I1r5KeCqji83gA0rZPCY9yvP25USUBFGxc= +github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw= +github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -152,15 +158,17 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= -golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +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.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 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= @@ -188,6 +196,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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= @@ -206,9 +216,13 @@ 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=