mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-27 14:59:09 +01:00
Merge branch 'main' into feature/migrate-auto-groups-to-table
# Conflicts: # management/server/migration/migration.go # management/server/store/store.go
This commit is contained in:
@@ -1,15 +1,15 @@
|
|||||||
FROM golang:1.23-bullseye
|
FROM golang:1.25-bookworm
|
||||||
|
|
||||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
&& apt-get -y install --no-install-recommends\
|
&& apt-get -y install --no-install-recommends\
|
||||||
gettext-base=0.21-4 \
|
gettext-base=0.21-12 \
|
||||||
iptables=1.8.7-1 \
|
iptables=1.8.9-2 \
|
||||||
libgl1-mesa-dev=20.3.5-1 \
|
libgl1-mesa-dev=22.3.6-1+deb12u1 \
|
||||||
xorg-dev=1:7.7+22 \
|
xorg-dev=1:7.7+23 \
|
||||||
libayatana-appindicator3-dev=0.5.5-2+deb11u2 \
|
libayatana-appindicator3-dev=0.5.92-1 \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& go install -v golang.org/x/tools/gopls@v0.18.1
|
&& go install -v golang.org/x/tools/gopls@latest
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
release: "14.2"
|
release: "14.2"
|
||||||
prepare: |
|
prepare: |
|
||||||
pkg install -y curl pkgconf xorg
|
pkg install -y curl pkgconf xorg
|
||||||
GO_TARBALL="go1.24.10.freebsd-amd64.tar.gz"
|
GO_TARBALL="go1.25.3.freebsd-amd64.tar.gz"
|
||||||
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
||||||
curl -vLO "$GO_URL"
|
curl -vLO "$GO_URL"
|
||||||
tar -C /usr/local -vxzf "$GO_TARBALL"
|
tar -C /usr/local -vxzf "$GO_TARBALL"
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ jobs:
|
|||||||
-e GOCACHE=${CONTAINER_GOCACHE} \
|
-e GOCACHE=${CONTAINER_GOCACHE} \
|
||||||
-e GOMODCACHE=${CONTAINER_GOMODCACHE} \
|
-e GOMODCACHE=${CONTAINER_GOMODCACHE} \
|
||||||
-e CONTAINER=${CONTAINER} \
|
-e CONTAINER=${CONTAINER} \
|
||||||
golang:1.24-alpine \
|
golang:1.25-alpine \
|
||||||
sh -c ' \
|
sh -c ' \
|
||||||
apk update; apk add --no-cache \
|
apk update; apk add --no-cache \
|
||||||
ca-certificates iptables ip6tables dbus dbus-dev libpcap-dev build-base; \
|
ca-certificates iptables ip6tables dbus dbus-dev libpcap-dev build-base; \
|
||||||
@@ -259,7 +259,7 @@ jobs:
|
|||||||
CGO_ENABLED=1 GOARCH=${{ matrix.arch }} \
|
CGO_ENABLED=1 GOARCH=${{ matrix.arch }} \
|
||||||
go test ${{ matrix.raceFlag }} \
|
go test ${{ matrix.raceFlag }} \
|
||||||
-exec 'sudo' \
|
-exec 'sudo' \
|
||||||
-timeout 10m ./relay/... ./shared/relay/...
|
-timeout 10m -p 1 ./relay/... ./shared/relay/...
|
||||||
|
|
||||||
test_signal:
|
test_signal:
|
||||||
name: "Signal / Unit"
|
name: "Signal / Unit"
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ jobs:
|
|||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev libpcap-dev
|
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev libpcap-dev
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: --timeout=12m --out-format colored-line-number
|
skip-cache: true
|
||||||
|
skip-save-cache: true
|
||||||
|
cache-invalidation-interval: 0
|
||||||
|
args: --timeout=12m
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
pkg install -y git curl portlint go
|
pkg install -y git curl portlint go
|
||||||
|
|
||||||
# Install Go for building
|
# Install Go for building
|
||||||
GO_TARBALL="go1.24.10.freebsd-amd64.tar.gz"
|
GO_TARBALL="go1.25.5.freebsd-amd64.tar.gz"
|
||||||
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
||||||
curl -LO "$GO_URL"
|
curl -LO "$GO_URL"
|
||||||
tar -C /usr/local -xzf "$GO_TARBALL"
|
tar -C /usr/local -xzf "$GO_TARBALL"
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ jobs:
|
|||||||
js_lint:
|
js_lint:
|
||||||
name: "JS / Lint"
|
name: "JS / Lint"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GOOS: js
|
||||||
|
GOARCH: wasm
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -24,16 +27,14 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev libpcap-dev
|
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev libpcap-dev
|
||||||
- name: Install golangci-lint
|
- name: Install golangci-lint
|
||||||
uses: golangci/golangci-lint-action@d6238b002a20823d52840fda27e2d4891c5952dc
|
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
install-mode: binary
|
install-mode: binary
|
||||||
skip-cache: true
|
skip-cache: true
|
||||||
skip-pkg-cache: true
|
skip-save-cache: true
|
||||||
skip-build-cache: true
|
cache-invalidation-interval: 0
|
||||||
- name: Run golangci-lint for WASM
|
working-directory: ./client
|
||||||
run: |
|
|
||||||
GOOS=js GOARCH=wasm golangci-lint run --timeout=12m --out-format colored-line-number ./client/...
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
js_build:
|
js_build:
|
||||||
|
|||||||
+120
-135
@@ -1,139 +1,124 @@
|
|||||||
run:
|
version: "2"
|
||||||
# Timeout for analysis, e.g. 30s, 5m.
|
|
||||||
# Default: 1m
|
|
||||||
timeout: 6m
|
|
||||||
|
|
||||||
# This file contains only configs which differ from defaults.
|
|
||||||
# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
|
|
||||||
linters-settings:
|
|
||||||
errcheck:
|
|
||||||
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
|
|
||||||
# Such cases aren't reported by default.
|
|
||||||
# Default: false
|
|
||||||
check-type-assertions: false
|
|
||||||
|
|
||||||
gosec:
|
|
||||||
includes:
|
|
||||||
- G101 # Look for hard coded credentials
|
|
||||||
#- G102 # Bind to all interfaces
|
|
||||||
- G103 # Audit the use of unsafe block
|
|
||||||
- G104 # Audit errors not checked
|
|
||||||
- G106 # Audit the use of ssh.InsecureIgnoreHostKey
|
|
||||||
#- G107 # Url provided to HTTP request as taint input
|
|
||||||
- G108 # Profiling endpoint automatically exposed on /debug/pprof
|
|
||||||
- G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32
|
|
||||||
- G110 # Potential DoS vulnerability via decompression bomb
|
|
||||||
- G111 # Potential directory traversal
|
|
||||||
#- G112 # Potential slowloris attack
|
|
||||||
- G113 # Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772)
|
|
||||||
#- G114 # Use of net/http serve function that has no support for setting timeouts
|
|
||||||
- G201 # SQL query construction using format string
|
|
||||||
- G202 # SQL query construction using string concatenation
|
|
||||||
- G203 # Use of unescaped data in HTML templates
|
|
||||||
#- G204 # Audit use of command execution
|
|
||||||
- G301 # Poor file permissions used when creating a directory
|
|
||||||
- G302 # Poor file permissions used with chmod
|
|
||||||
- G303 # Creating tempfile using a predictable path
|
|
||||||
- G304 # File path provided as taint input
|
|
||||||
- G305 # File traversal when extracting zip/tar archive
|
|
||||||
- G306 # Poor file permissions used when writing to a new file
|
|
||||||
- G307 # Poor file permissions used when creating a file with os.Create
|
|
||||||
#- G401 # Detect the usage of DES, RC4, MD5 or SHA1
|
|
||||||
#- G402 # Look for bad TLS connection settings
|
|
||||||
- G403 # Ensure minimum RSA key length of 2048 bits
|
|
||||||
#- G404 # Insecure random number source (rand)
|
|
||||||
#- G501 # Import blocklist: crypto/md5
|
|
||||||
- G502 # Import blocklist: crypto/des
|
|
||||||
- G503 # Import blocklist: crypto/rc4
|
|
||||||
- G504 # Import blocklist: net/http/cgi
|
|
||||||
#- G505 # Import blocklist: crypto/sha1
|
|
||||||
- G601 # Implicit memory aliasing of items from a range statement
|
|
||||||
- G602 # Slice access out of bounds
|
|
||||||
|
|
||||||
gocritic:
|
|
||||||
disabled-checks:
|
|
||||||
- commentFormatting
|
|
||||||
- captLocal
|
|
||||||
- deprecatedComment
|
|
||||||
|
|
||||||
govet:
|
|
||||||
# Enable all analyzers.
|
|
||||||
# Default: false
|
|
||||||
enable-all: false
|
|
||||||
enable:
|
|
||||||
- nilness
|
|
||||||
|
|
||||||
revive:
|
|
||||||
rules:
|
|
||||||
- name: exported
|
|
||||||
severity: warning
|
|
||||||
disabled: false
|
|
||||||
arguments:
|
|
||||||
- "checkPrivateReceivers"
|
|
||||||
- "sayRepetitiveInsteadOfStutters"
|
|
||||||
tenv:
|
|
||||||
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
|
|
||||||
# Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
|
|
||||||
# Default: false
|
|
||||||
all: true
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
default: none
|
||||||
enable:
|
enable:
|
||||||
## enabled by default
|
- bodyclose
|
||||||
- errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases
|
- dupword
|
||||||
- gosimple # specializes in simplifying a code
|
- durationcheck
|
||||||
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
- errcheck
|
||||||
- ineffassign # detects when assignments to existing variables are not used
|
- forbidigo
|
||||||
- staticcheck # is a go vet on steroids, applying a ton of static analysis checks
|
- gocritic
|
||||||
- tenv # Tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17.
|
- gosec
|
||||||
- typecheck # like the front-end of a Go compiler, parses and type-checks Go code
|
- govet
|
||||||
- unused # checks for unused constants, variables, functions and types
|
- ineffassign
|
||||||
## disable by default but the have interesting results so lets add them
|
- mirror
|
||||||
- bodyclose # checks whether HTTP response body is closed successfully
|
- misspell
|
||||||
- dupword # dupword checks for duplicate words in the source code
|
- nilerr
|
||||||
- durationcheck # durationcheck checks for two durations multiplied together
|
- nilnil
|
||||||
- forbidigo # forbidigo forbids identifiers
|
- predeclared
|
||||||
- gocritic # provides diagnostics that check for bugs, performance and style issues
|
- revive
|
||||||
- gosec # inspects source code for security problems
|
- sqlclosecheck
|
||||||
- mirror # mirror reports wrong mirror patterns of bytes/strings usage
|
- staticcheck
|
||||||
- misspell # misspess finds commonly misspelled English words in comments
|
- unused
|
||||||
- nilerr # finds the code that returns nil even if it checks that the error is not nil
|
- wastedassign
|
||||||
- nilnil # checks that there is no simultaneous return of nil error and an invalid value
|
settings:
|
||||||
- predeclared # predeclared finds code that shadows one of Go's predeclared identifiers
|
errcheck:
|
||||||
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
|
check-type-assertions: false
|
||||||
- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed
|
gocritic:
|
||||||
# - thelper # thelper detects Go test helpers without t.Helper() call and checks the consistency of test helpers.
|
disabled-checks:
|
||||||
- wastedassign # wastedassign finds wasted assignment statements
|
- commentFormatting
|
||||||
|
- captLocal
|
||||||
|
- deprecatedComment
|
||||||
|
gosec:
|
||||||
|
includes:
|
||||||
|
- G101
|
||||||
|
- G103
|
||||||
|
- G104
|
||||||
|
- G106
|
||||||
|
- G108
|
||||||
|
- G109
|
||||||
|
- G110
|
||||||
|
- G111
|
||||||
|
- G201
|
||||||
|
- G202
|
||||||
|
- G203
|
||||||
|
- G301
|
||||||
|
- G302
|
||||||
|
- G303
|
||||||
|
- G304
|
||||||
|
- G305
|
||||||
|
- G306
|
||||||
|
- G307
|
||||||
|
- G403
|
||||||
|
- G502
|
||||||
|
- G503
|
||||||
|
- G504
|
||||||
|
- G601
|
||||||
|
- G602
|
||||||
|
govet:
|
||||||
|
enable:
|
||||||
|
- nilness
|
||||||
|
enable-all: false
|
||||||
|
revive:
|
||||||
|
rules:
|
||||||
|
- name: exported
|
||||||
|
arguments:
|
||||||
|
- checkPrivateReceivers
|
||||||
|
- sayRepetitiveInsteadOfStutters
|
||||||
|
severity: warning
|
||||||
|
disabled: false
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
rules:
|
||||||
|
- linters:
|
||||||
|
- forbidigo
|
||||||
|
path: management/cmd/root\.go
|
||||||
|
- linters:
|
||||||
|
- forbidigo
|
||||||
|
path: signal/cmd/root\.go
|
||||||
|
- linters:
|
||||||
|
- unused
|
||||||
|
path: sharedsock/filter\.go
|
||||||
|
- linters:
|
||||||
|
- unused
|
||||||
|
path: client/firewall/iptables/rule\.go
|
||||||
|
- linters:
|
||||||
|
- gosec
|
||||||
|
- mirror
|
||||||
|
path: test\.go
|
||||||
|
- linters:
|
||||||
|
- nilnil
|
||||||
|
path: mock\.go
|
||||||
|
- linters:
|
||||||
|
- staticcheck
|
||||||
|
text: grpc.DialContext is deprecated
|
||||||
|
- linters:
|
||||||
|
- staticcheck
|
||||||
|
text: grpc.WithBlock is deprecated
|
||||||
|
- linters:
|
||||||
|
- staticcheck
|
||||||
|
text: "QF1001"
|
||||||
|
- linters:
|
||||||
|
- staticcheck
|
||||||
|
text: "QF1008"
|
||||||
|
- linters:
|
||||||
|
- staticcheck
|
||||||
|
text: "QF1012"
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
issues:
|
issues:
|
||||||
# Maximum count of issues with the same text.
|
|
||||||
# Set to 0 to disable.
|
|
||||||
# Default: 3
|
|
||||||
max-same-issues: 5
|
max-same-issues: 5
|
||||||
|
formatters:
|
||||||
exclude-rules:
|
exclusions:
|
||||||
# allow fmt
|
generated: lax
|
||||||
- path: management/cmd/root\.go
|
paths:
|
||||||
linters: forbidigo
|
- third_party$
|
||||||
- path: signal/cmd/root\.go
|
- builtin$
|
||||||
linters: forbidigo
|
- examples$
|
||||||
- path: sharedsock/filter\.go
|
|
||||||
linters:
|
|
||||||
- unused
|
|
||||||
- path: client/firewall/iptables/rule\.go
|
|
||||||
linters:
|
|
||||||
- unused
|
|
||||||
- path: test\.go
|
|
||||||
linters:
|
|
||||||
- mirror
|
|
||||||
- gosec
|
|
||||||
- path: mock\.go
|
|
||||||
linters:
|
|
||||||
- nilnil
|
|
||||||
# Exclude specific deprecation warnings for grpc methods
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "grpc.DialContext is deprecated"
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "grpc.WithBlock is deprecated"
|
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ func setLogLevel(cmd *cobra.Command, args []string) error {
|
|||||||
client := proto.NewDaemonServiceClient(conn)
|
client := proto.NewDaemonServiceClient(conn)
|
||||||
level := server.ParseLogLevel(args[0])
|
level := server.ParseLogLevel(args[0])
|
||||||
if level == proto.LogLevel_UNKNOWN {
|
if level == proto.LogLevel_UNKNOWN {
|
||||||
|
//nolint
|
||||||
return fmt.Errorf("unknown log level: %s. Available levels are: panic, fatal, error, warn, info, debug, trace\n", args[0])
|
return fmt.Errorf("unknown log level: %s. Available levels are: panic, fatal, error, warn, info, debug, trace\n", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ var loginCmd = &cobra.Command{
|
|||||||
func doDaemonLogin(ctx context.Context, cmd *cobra.Command, providedSetupKey string, activeProf *profilemanager.Profile, username string, pm *profilemanager.ProfileManager) error {
|
func doDaemonLogin(ctx context.Context, cmd *cobra.Command, providedSetupKey string, activeProf *profilemanager.Profile, username string, pm *profilemanager.ProfileManager) error {
|
||||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
//nolint
|
||||||
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
||||||
"If the daemon is not running please run: "+
|
"If the daemon is not running please run: "+
|
||||||
"\nnetbird service install \nnetbird service start\n", err)
|
"\nnetbird service install \nnetbird service start\n", err)
|
||||||
@@ -206,6 +207,7 @@ func switchProfileOnDaemon(ctx context.Context, pm *profilemanager.ProfileManage
|
|||||||
func switchProfile(ctx context.Context, profileName string, username string) error {
|
func switchProfile(ctx context.Context, profileName string, username string) error {
|
||||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
//nolint
|
||||||
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
||||||
"If the daemon is not running please run: "+
|
"If the daemon is not running please run: "+
|
||||||
"\nnetbird service install \nnetbird service start\n", err)
|
"\nnetbird service install \nnetbird service start\n", err)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build pprof
|
//go:build pprof
|
||||||
// +build pprof
|
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
|
|||||||
@@ -390,6 +390,7 @@ func getClient(cmd *cobra.Command) (*grpc.ClientConn, error) {
|
|||||||
|
|
||||||
conn, err := DialClientGRPCServer(cmd.Context(), daemonAddr)
|
conn, err := DialClientGRPCServer(cmd.Context(), daemonAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
//nolint
|
||||||
return nil, fmt.Errorf("failed to connect to daemon error: %v\n"+
|
return nil, fmt.Errorf("failed to connect to daemon error: %v\n"+
|
||||||
"If the daemon is not running please run: "+
|
"If the daemon is not running please run: "+
|
||||||
"\nnetbird service install \nnetbird service start\n", err)
|
"\nnetbird service install \nnetbird service start\n", err)
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ func statusFunc(cmd *cobra.Command, args []string) error {
|
|||||||
func getStatus(ctx context.Context, shouldRunProbes bool) (*proto.StatusResponse, error) {
|
func getStatus(ctx context.Context, shouldRunProbes bool) (*proto.StatusResponse, error) {
|
||||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
//nolint
|
||||||
return nil, fmt.Errorf("failed to connect to daemon error: %v\n"+
|
return nil, fmt.Errorf("failed to connect to daemon error: %v\n"+
|
||||||
"If the daemon is not running please run: "+
|
"If the daemon is not running please run: "+
|
||||||
"\nnetbird service install \nnetbird service start\n", err)
|
"\nnetbird service install \nnetbird service start\n", err)
|
||||||
|
|||||||
@@ -89,9 +89,6 @@ func startManagement(t *testing.T, config *config.Config, testFile string) (*grp
|
|||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
|
|
||||||
eventStore := &activity.InMemoryEventStore{}
|
eventStore := &activity.InMemoryEventStore{}
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ func runInDaemonMode(ctx context.Context, cmd *cobra.Command, pm *profilemanager
|
|||||||
|
|
||||||
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
conn, err := DialClientGRPCServer(ctx, daemonAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
//nolint
|
||||||
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
return fmt.Errorf("failed to connect to daemon error: %v\n"+
|
||||||
"If the daemon is not running please run: "+
|
"If the daemon is not running please run: "+
|
||||||
"\nnetbird service install \nnetbird service start\n", err)
|
"\nnetbird service install \nnetbird service start\n", err)
|
||||||
|
|||||||
@@ -386,11 +386,8 @@ func (m *aclManager) updateState() {
|
|||||||
|
|
||||||
// filterRuleSpecs returns the specs of a filtering rule
|
// filterRuleSpecs returns the specs of a filtering rule
|
||||||
func filterRuleSpecs(ip net.IP, protocol string, sPort, dPort *firewall.Port, action firewall.Action, ipsetName string) (specs []string) {
|
func filterRuleSpecs(ip net.IP, protocol string, sPort, dPort *firewall.Port, action firewall.Action, ipsetName string) (specs []string) {
|
||||||
matchByIP := true
|
|
||||||
// don't use IP matching if IP is 0.0.0.0
|
// don't use IP matching if IP is 0.0.0.0
|
||||||
if ip.IsUnspecified() {
|
matchByIP := !ip.IsUnspecified()
|
||||||
matchByIP = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if matchByIP {
|
if matchByIP {
|
||||||
if ipsetName != "" {
|
if ipsetName != "" {
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ func TestIptablesManagerDenyRules(t *testing.T) {
|
|||||||
t.Logf(" [%d] %s", i, rule)
|
t.Logf(" [%d] %s", i, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
var denyRuleIndex, acceptRuleIndex int = -1, -1
|
var denyRuleIndex, acceptRuleIndex = -1, -1
|
||||||
for i, rule := range rules {
|
for i, rule := range rules {
|
||||||
if strings.Contains(rule, "DROP") {
|
if strings.Contains(rule, "DROP") {
|
||||||
t.Logf("Found DROP rule at index %d: %s", i, rule)
|
t.Logf("Found DROP rule at index %d: %s", i, rule)
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ func TestNftablesManagerRuleOrder(t *testing.T) {
|
|||||||
t.Logf("Found %d rules in nftables chain", len(rules))
|
t.Logf("Found %d rules in nftables chain", len(rules))
|
||||||
|
|
||||||
// Find the accept and deny rules and verify deny comes before accept
|
// Find the accept and deny rules and verify deny comes before accept
|
||||||
var acceptRuleIndex, denyRuleIndex int = -1, -1
|
var acceptRuleIndex, denyRuleIndex = -1, -1
|
||||||
for i, rule := range rules {
|
for i, rule := range rules {
|
||||||
hasAcceptHTTPSet := false
|
hasAcceptHTTPSet := false
|
||||||
hasDenyHTTPSet := false
|
hasDenyHTTPSet := false
|
||||||
@@ -208,11 +208,13 @@ func TestNftablesManagerRuleOrder(t *testing.T) {
|
|||||||
for _, e := range rule.Exprs {
|
for _, e := range rule.Exprs {
|
||||||
// Check for set lookup
|
// Check for set lookup
|
||||||
if lookup, ok := e.(*expr.Lookup); ok {
|
if lookup, ok := e.(*expr.Lookup); ok {
|
||||||
if lookup.SetName == "accept-http" {
|
switch lookup.SetName {
|
||||||
|
case "accept-http":
|
||||||
hasAcceptHTTPSet = true
|
hasAcceptHTTPSet = true
|
||||||
} else if lookup.SetName == "deny-http" {
|
case "deny-http":
|
||||||
hasDenyHTTPSet = true
|
hasDenyHTTPSet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Check for port 80
|
// Check for port 80
|
||||||
if cmp, ok := e.(*expr.Cmp); ok {
|
if cmp, ok := e.(*expr.Cmp); ok {
|
||||||
@@ -222,9 +224,10 @@ func TestNftablesManagerRuleOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// Check for verdict
|
// Check for verdict
|
||||||
if verdict, ok := e.(*expr.Verdict); ok {
|
if verdict, ok := e.(*expr.Verdict); ok {
|
||||||
if verdict.Kind == expr.VerdictAccept {
|
switch verdict.Kind {
|
||||||
|
case expr.VerdictAccept:
|
||||||
action = "ACCEPT"
|
action = "ACCEPT"
|
||||||
} else if verdict.Kind == expr.VerdictDrop {
|
case expr.VerdictDrop:
|
||||||
action = "DROP"
|
action = "DROP"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
layerTypeAll = 0
|
layerTypeAll = 255
|
||||||
|
|
||||||
// ipTCPHeaderMinSize represents minimum IP (20) + TCP (20) header size for MSS calculation
|
// ipTCPHeaderMinSize represents minimum IP (20) + TCP (20) header size for MSS calculation
|
||||||
ipTCPHeaderMinSize = 40
|
ipTCPHeaderMinSize = 40
|
||||||
@@ -262,10 +262,7 @@ func create(iface common.IFaceMapper, nativeFirewall firewall.Manager, disableSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) blockInvalidRouted(iface common.IFaceMapper) (firewall.Rule, error) {
|
func (m *Manager) blockInvalidRouted(iface common.IFaceMapper) (firewall.Rule, error) {
|
||||||
wgPrefix, err := netip.ParsePrefix(iface.Address().Network.String())
|
wgPrefix := iface.Address().Network
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("parse wireguard network: %w", err)
|
|
||||||
}
|
|
||||||
log.Debugf("blocking invalid routed traffic for %s", wgPrefix)
|
log.Debugf("blocking invalid routed traffic for %s", wgPrefix)
|
||||||
|
|
||||||
rule, err := m.addRouteFiltering(
|
rule, err := m.addRouteFiltering(
|
||||||
@@ -439,19 +436,7 @@ func (m *Manager) AddPeerFiltering(
|
|||||||
r.sPort = sPort
|
r.sPort = sPort
|
||||||
r.dPort = dPort
|
r.dPort = dPort
|
||||||
|
|
||||||
switch proto {
|
r.protoLayer = protoToLayer(proto, r.ipLayer)
|
||||||
case firewall.ProtocolTCP:
|
|
||||||
r.protoLayer = layers.LayerTypeTCP
|
|
||||||
case firewall.ProtocolUDP:
|
|
||||||
r.protoLayer = layers.LayerTypeUDP
|
|
||||||
case firewall.ProtocolICMP:
|
|
||||||
r.protoLayer = layers.LayerTypeICMPv4
|
|
||||||
if r.ipLayer == layers.LayerTypeIPv6 {
|
|
||||||
r.protoLayer = layers.LayerTypeICMPv6
|
|
||||||
}
|
|
||||||
case firewall.ProtocolALL:
|
|
||||||
r.protoLayer = layerTypeAll
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
var targetMap map[netip.Addr]RuleSet
|
var targetMap map[netip.Addr]RuleSet
|
||||||
@@ -496,16 +481,17 @@ func (m *Manager) addRouteFiltering(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ruleID := uuid.New().String()
|
ruleID := uuid.New().String()
|
||||||
|
|
||||||
rule := RouteRule{
|
rule := RouteRule{
|
||||||
// TODO: consolidate these IDs
|
// TODO: consolidate these IDs
|
||||||
id: ruleID,
|
id: ruleID,
|
||||||
mgmtId: id,
|
mgmtId: id,
|
||||||
sources: sources,
|
sources: sources,
|
||||||
dstSet: destination.Set,
|
dstSet: destination.Set,
|
||||||
proto: proto,
|
protoLayer: protoToLayer(proto, layers.LayerTypeIPv4),
|
||||||
srcPort: sPort,
|
srcPort: sPort,
|
||||||
dstPort: dPort,
|
dstPort: dPort,
|
||||||
action: action,
|
action: action,
|
||||||
}
|
}
|
||||||
if destination.IsPrefix() {
|
if destination.IsPrefix() {
|
||||||
rule.destinations = []netip.Prefix{destination.Prefix}
|
rule.destinations = []netip.Prefix{destination.Prefix}
|
||||||
@@ -795,7 +781,7 @@ func (m *Manager) recalculateTCPChecksum(packetData []byte, d *decoder, tcpHeade
|
|||||||
pseudoSum += uint32(d.ip4.Protocol)
|
pseudoSum += uint32(d.ip4.Protocol)
|
||||||
pseudoSum += uint32(tcpLength)
|
pseudoSum += uint32(tcpLength)
|
||||||
|
|
||||||
var sum uint32 = pseudoSum
|
var sum = pseudoSum
|
||||||
for i := 0; i < tcpLength-1; i += 2 {
|
for i := 0; i < tcpLength-1; i += 2 {
|
||||||
sum += uint32(tcpLayer[i])<<8 | uint32(tcpLayer[i+1])
|
sum += uint32(tcpLayer[i])<<8 | uint32(tcpLayer[i+1])
|
||||||
}
|
}
|
||||||
@@ -945,7 +931,7 @@ func (m *Manager) filterInbound(packetData []byte, size int) bool {
|
|||||||
func (m *Manager) handleLocalTraffic(d *decoder, srcIP, dstIP netip.Addr, packetData []byte, size int) bool {
|
func (m *Manager) handleLocalTraffic(d *decoder, srcIP, dstIP netip.Addr, packetData []byte, size int) bool {
|
||||||
ruleID, blocked := m.peerACLsBlock(srcIP, d, packetData)
|
ruleID, blocked := m.peerACLsBlock(srcIP, d, packetData)
|
||||||
if blocked {
|
if blocked {
|
||||||
_, pnum := getProtocolFromPacket(d)
|
pnum := getProtocolFromPacket(d)
|
||||||
srcPort, dstPort := getPortsFromPacket(d)
|
srcPort, dstPort := getPortsFromPacket(d)
|
||||||
|
|
||||||
m.logger.Trace6("Dropping local packet (ACL denied): rule_id=%s proto=%v src=%s:%d dst=%s:%d",
|
m.logger.Trace6("Dropping local packet (ACL denied): rule_id=%s proto=%v src=%s:%d dst=%s:%d",
|
||||||
@@ -1010,20 +996,22 @@ func (m *Manager) handleRoutedTraffic(d *decoder, srcIP, dstIP netip.Addr, packe
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
proto, pnum := getProtocolFromPacket(d)
|
protoLayer := d.decoded[1]
|
||||||
srcPort, dstPort := getPortsFromPacket(d)
|
srcPort, dstPort := getPortsFromPacket(d)
|
||||||
|
|
||||||
ruleID, pass := m.routeACLsPass(srcIP, dstIP, proto, srcPort, dstPort)
|
ruleID, pass := m.routeACLsPass(srcIP, dstIP, protoLayer, srcPort, dstPort)
|
||||||
if !pass {
|
if !pass {
|
||||||
|
proto := getProtocolFromPacket(d)
|
||||||
|
|
||||||
m.logger.Trace6("Dropping routed packet (ACL denied): rule_id=%s proto=%v src=%s:%d dst=%s:%d",
|
m.logger.Trace6("Dropping routed packet (ACL denied): rule_id=%s proto=%v src=%s:%d dst=%s:%d",
|
||||||
ruleID, pnum, srcIP, srcPort, dstIP, dstPort)
|
ruleID, proto, srcIP, srcPort, dstIP, dstPort)
|
||||||
|
|
||||||
m.flowLogger.StoreEvent(nftypes.EventFields{
|
m.flowLogger.StoreEvent(nftypes.EventFields{
|
||||||
FlowID: uuid.New(),
|
FlowID: uuid.New(),
|
||||||
Type: nftypes.TypeDrop,
|
Type: nftypes.TypeDrop,
|
||||||
RuleID: ruleID,
|
RuleID: ruleID,
|
||||||
Direction: nftypes.Ingress,
|
Direction: nftypes.Ingress,
|
||||||
Protocol: pnum,
|
Protocol: proto,
|
||||||
SourceIP: srcIP,
|
SourceIP: srcIP,
|
||||||
DestIP: dstIP,
|
DestIP: dstIP,
|
||||||
SourcePort: srcPort,
|
SourcePort: srcPort,
|
||||||
@@ -1052,16 +1040,33 @@ func (m *Manager) handleRoutedTraffic(d *decoder, srcIP, dstIP netip.Addr, packe
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProtocolFromPacket(d *decoder) (firewall.Protocol, nftypes.Protocol) {
|
func protoToLayer(proto firewall.Protocol, ipLayer gopacket.LayerType) gopacket.LayerType {
|
||||||
|
switch proto {
|
||||||
|
case firewall.ProtocolTCP:
|
||||||
|
return layers.LayerTypeTCP
|
||||||
|
case firewall.ProtocolUDP:
|
||||||
|
return layers.LayerTypeUDP
|
||||||
|
case firewall.ProtocolICMP:
|
||||||
|
if ipLayer == layers.LayerTypeIPv6 {
|
||||||
|
return layers.LayerTypeICMPv6
|
||||||
|
}
|
||||||
|
return layers.LayerTypeICMPv4
|
||||||
|
case firewall.ProtocolALL:
|
||||||
|
return layerTypeAll
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProtocolFromPacket(d *decoder) nftypes.Protocol {
|
||||||
switch d.decoded[1] {
|
switch d.decoded[1] {
|
||||||
case layers.LayerTypeTCP:
|
case layers.LayerTypeTCP:
|
||||||
return firewall.ProtocolTCP, nftypes.TCP
|
return nftypes.TCP
|
||||||
case layers.LayerTypeUDP:
|
case layers.LayerTypeUDP:
|
||||||
return firewall.ProtocolUDP, nftypes.UDP
|
return nftypes.UDP
|
||||||
case layers.LayerTypeICMPv4, layers.LayerTypeICMPv6:
|
case layers.LayerTypeICMPv4, layers.LayerTypeICMPv6:
|
||||||
return firewall.ProtocolICMP, nftypes.ICMP
|
return nftypes.ICMP
|
||||||
default:
|
default:
|
||||||
return firewall.ProtocolALL, nftypes.ProtocolUnknown
|
return nftypes.ProtocolUnknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1233,19 +1238,30 @@ func validateRule(ip netip.Addr, packetData []byte, rules map[string]PeerRule, d
|
|||||||
}
|
}
|
||||||
|
|
||||||
// routeACLsPass returns true if the packet is allowed by the route ACLs
|
// routeACLsPass returns true if the packet is allowed by the route ACLs
|
||||||
func (m *Manager) routeACLsPass(srcIP, dstIP netip.Addr, proto firewall.Protocol, srcPort, dstPort uint16) ([]byte, bool) {
|
func (m *Manager) routeACLsPass(srcIP, dstIP netip.Addr, protoLayer gopacket.LayerType, srcPort, dstPort uint16) ([]byte, bool) {
|
||||||
m.mutex.RLock()
|
m.mutex.RLock()
|
||||||
defer m.mutex.RUnlock()
|
defer m.mutex.RUnlock()
|
||||||
|
|
||||||
for _, rule := range m.routeRules {
|
for _, rule := range m.routeRules {
|
||||||
if matches := m.ruleMatches(rule, srcIP, dstIP, proto, srcPort, dstPort); matches {
|
if matches := m.ruleMatches(rule, srcIP, dstIP, protoLayer, srcPort, dstPort); matches {
|
||||||
return rule.mgmtId, rule.action == firewall.ActionAccept
|
return rule.mgmtId, rule.action == firewall.ActionAccept
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) ruleMatches(rule *RouteRule, srcAddr, dstAddr netip.Addr, proto firewall.Protocol, srcPort, dstPort uint16) bool {
|
func (m *Manager) ruleMatches(rule *RouteRule, srcAddr, dstAddr netip.Addr, protoLayer gopacket.LayerType, srcPort, dstPort uint16) bool {
|
||||||
|
// TODO: handle ipv6 vs ipv4 icmp rules
|
||||||
|
if rule.protoLayer != layerTypeAll && rule.protoLayer != protoLayer {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if protoLayer == layers.LayerTypeTCP || protoLayer == layers.LayerTypeUDP {
|
||||||
|
if !portsMatch(rule.srcPort, srcPort) || !portsMatch(rule.dstPort, dstPort) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
destMatched := false
|
destMatched := false
|
||||||
for _, dst := range rule.destinations {
|
for _, dst := range rule.destinations {
|
||||||
if dst.Contains(dstAddr) {
|
if dst.Contains(dstAddr) {
|
||||||
@@ -1264,21 +1280,8 @@ func (m *Manager) ruleMatches(rule *RouteRule, srcAddr, dstAddr netip.Addr, prot
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !sourceMatched {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule.proto != firewall.ProtocolALL && rule.proto != proto {
|
return sourceMatched
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if proto == firewall.ProtocolTCP || proto == firewall.ProtocolUDP {
|
|
||||||
if !portsMatch(rule.srcPort, srcPort) || !portsMatch(rule.dstPort, dstPort) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUDPPacketHook calls hook when UDP packet from given direction matched
|
// AddUDPPacketHook calls hook when UDP packet from given direction matched
|
||||||
|
|||||||
@@ -955,7 +955,7 @@ func BenchmarkRouteACLs(b *testing.B) {
|
|||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
srcIP := netip.MustParseAddr(tc.srcIP)
|
srcIP := netip.MustParseAddr(tc.srcIP)
|
||||||
dstIP := netip.MustParseAddr(tc.dstIP)
|
dstIP := netip.MustParseAddr(tc.dstIP)
|
||||||
manager.routeACLsPass(srcIP, dstIP, tc.proto, 0, tc.dstPort)
|
manager.routeACLsPass(srcIP, dstIP, protoToLayer(tc.proto, layers.LayerTypeIPv4), 0, tc.dstPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1259,7 +1259,7 @@ func TestRouteACLFiltering(t *testing.T) {
|
|||||||
|
|
||||||
// testing routeACLsPass only and not FilterInbound, as routed packets are dropped after being passed
|
// testing routeACLsPass only and not FilterInbound, as routed packets are dropped after being passed
|
||||||
// to the forwarder
|
// to the forwarder
|
||||||
_, isAllowed := manager.routeACLsPass(srcIP, dstIP, tc.proto, tc.srcPort, tc.dstPort)
|
_, isAllowed := manager.routeACLsPass(srcIP, dstIP, protoToLayer(tc.proto, layers.LayerTypeIPv4), tc.srcPort, tc.dstPort)
|
||||||
require.Equal(t, tc.shouldPass, isAllowed)
|
require.Equal(t, tc.shouldPass, isAllowed)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1445,7 +1445,7 @@ func TestRouteACLOrder(t *testing.T) {
|
|||||||
srcIP := netip.MustParseAddr(p.srcIP)
|
srcIP := netip.MustParseAddr(p.srcIP)
|
||||||
dstIP := netip.MustParseAddr(p.dstIP)
|
dstIP := netip.MustParseAddr(p.dstIP)
|
||||||
|
|
||||||
_, isAllowed := manager.routeACLsPass(srcIP, dstIP, p.proto, p.srcPort, p.dstPort)
|
_, isAllowed := manager.routeACLsPass(srcIP, dstIP, protoToLayer(p.proto, layers.LayerTypeIPv4), p.srcPort, p.dstPort)
|
||||||
require.Equal(t, p.shouldPass, isAllowed, "packet %d failed", i)
|
require.Equal(t, p.shouldPass, isAllowed, "packet %d failed", i)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1488,13 +1488,13 @@ func TestRouteACLSet(t *testing.T) {
|
|||||||
dstIP := netip.MustParseAddr("192.168.1.100")
|
dstIP := netip.MustParseAddr("192.168.1.100")
|
||||||
|
|
||||||
// Check that traffic is dropped (empty set shouldn't match anything)
|
// Check that traffic is dropped (empty set shouldn't match anything)
|
||||||
_, isAllowed := manager.routeACLsPass(srcIP, dstIP, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed := manager.routeACLsPass(srcIP, dstIP, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
require.False(t, isAllowed, "Empty set should not allow any traffic")
|
require.False(t, isAllowed, "Empty set should not allow any traffic")
|
||||||
|
|
||||||
err = manager.UpdateSet(set, []netip.Prefix{netip.MustParsePrefix("192.168.1.0/24")})
|
err = manager.UpdateSet(set, []netip.Prefix{netip.MustParsePrefix("192.168.1.0/24")})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Now the packet should be allowed
|
// Now the packet should be allowed
|
||||||
_, isAllowed = manager.routeACLsPass(srcIP, dstIP, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed = manager.routeACLsPass(srcIP, dstIP, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
require.True(t, isAllowed, "After set update, traffic to the added network should be allowed")
|
require.True(t, isAllowed, "After set update, traffic to the added network should be allowed")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -767,9 +767,9 @@ func TestUpdateSetMerge(t *testing.T) {
|
|||||||
dstIP2 := netip.MustParseAddr("192.168.1.100")
|
dstIP2 := netip.MustParseAddr("192.168.1.100")
|
||||||
dstIP3 := netip.MustParseAddr("172.16.0.100")
|
dstIP3 := netip.MustParseAddr("172.16.0.100")
|
||||||
|
|
||||||
_, isAllowed1 := manager.routeACLsPass(srcIP, dstIP1, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed1 := manager.routeACLsPass(srcIP, dstIP1, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
_, isAllowed2 := manager.routeACLsPass(srcIP, dstIP2, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed2 := manager.routeACLsPass(srcIP, dstIP2, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
_, isAllowed3 := manager.routeACLsPass(srcIP, dstIP3, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed3 := manager.routeACLsPass(srcIP, dstIP3, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
|
|
||||||
require.True(t, isAllowed1, "Traffic to 10.0.0.100 should be allowed")
|
require.True(t, isAllowed1, "Traffic to 10.0.0.100 should be allowed")
|
||||||
require.True(t, isAllowed2, "Traffic to 192.168.1.100 should be allowed")
|
require.True(t, isAllowed2, "Traffic to 192.168.1.100 should be allowed")
|
||||||
@@ -784,8 +784,8 @@ func TestUpdateSetMerge(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that all original prefixes are still included
|
// Check that all original prefixes are still included
|
||||||
_, isAllowed1 = manager.routeACLsPass(srcIP, dstIP1, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed1 = manager.routeACLsPass(srcIP, dstIP1, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
_, isAllowed2 = manager.routeACLsPass(srcIP, dstIP2, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed2 = manager.routeACLsPass(srcIP, dstIP2, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
require.True(t, isAllowed1, "Traffic to 10.0.0.100 should still be allowed after update")
|
require.True(t, isAllowed1, "Traffic to 10.0.0.100 should still be allowed after update")
|
||||||
require.True(t, isAllowed2, "Traffic to 192.168.1.100 should still be allowed after update")
|
require.True(t, isAllowed2, "Traffic to 192.168.1.100 should still be allowed after update")
|
||||||
|
|
||||||
@@ -793,8 +793,8 @@ func TestUpdateSetMerge(t *testing.T) {
|
|||||||
dstIP4 := netip.MustParseAddr("172.16.1.100")
|
dstIP4 := netip.MustParseAddr("172.16.1.100")
|
||||||
dstIP5 := netip.MustParseAddr("10.1.0.50")
|
dstIP5 := netip.MustParseAddr("10.1.0.50")
|
||||||
|
|
||||||
_, isAllowed4 := manager.routeACLsPass(srcIP, dstIP4, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed4 := manager.routeACLsPass(srcIP, dstIP4, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
_, isAllowed5 := manager.routeACLsPass(srcIP, dstIP5, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed5 := manager.routeACLsPass(srcIP, dstIP5, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
|
|
||||||
require.True(t, isAllowed4, "Traffic to new prefix 172.16.0.0/16 should be allowed")
|
require.True(t, isAllowed4, "Traffic to new prefix 172.16.0.0/16 should be allowed")
|
||||||
require.True(t, isAllowed5, "Traffic to new prefix 10.1.0.0/24 should be allowed")
|
require.True(t, isAllowed5, "Traffic to new prefix 10.1.0.0/24 should be allowed")
|
||||||
@@ -922,7 +922,7 @@ func TestUpdateSetDeduplication(t *testing.T) {
|
|||||||
|
|
||||||
srcIP := netip.MustParseAddr("100.10.0.1")
|
srcIP := netip.MustParseAddr("100.10.0.1")
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
_, isAllowed := manager.routeACLsPass(srcIP, tc.dstIP, fw.ProtocolTCP, 12345, 80)
|
_, isAllowed := manager.routeACLsPass(srcIP, tc.dstIP, protoToLayer(fw.ProtocolTCP, layers.LayerTypeIPv4), 12345, 80)
|
||||||
require.Equal(t, tc.expected, isAllowed, tc.desc)
|
require.Equal(t, tc.expected, isAllowed, tc.desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forwarder
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
@@ -16,7 +17,7 @@ type endpoint struct {
|
|||||||
logger *nblog.Logger
|
logger *nblog.Logger
|
||||||
dispatcher stack.NetworkDispatcher
|
dispatcher stack.NetworkDispatcher
|
||||||
device *wgdevice.Device
|
device *wgdevice.Device
|
||||||
mtu uint32
|
mtu atomic.Uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||||
@@ -28,7 +29,7 @@ func (e *endpoint) IsAttached() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *endpoint) MTU() uint32 {
|
func (e *endpoint) MTU() uint32 {
|
||||||
return e.mtu
|
return e.mtu.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities {
|
func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||||
@@ -82,6 +83,22 @@ func (e *endpoint) ParseHeader(*stack.PacketBuffer) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) Close() {
|
||||||
|
// Endpoint cleanup - nothing to do as device is managed externally
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) SetLinkAddress(tcpip.LinkAddress) {
|
||||||
|
// Link address is not used for this endpoint type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) SetMTU(mtu uint32) {
|
||||||
|
e.mtu.Store(mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *endpoint) SetOnCloseAction(func()) {
|
||||||
|
// No action needed on close
|
||||||
|
}
|
||||||
|
|
||||||
type epID stack.TransportEndpointID
|
type epID stack.TransportEndpointID
|
||||||
|
|
||||||
func (i epID) String() string {
|
func (i epID) String() string {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gvisor.dev/gvisor/pkg/buffer"
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
@@ -35,14 +36,16 @@ type Forwarder struct {
|
|||||||
logger *nblog.Logger
|
logger *nblog.Logger
|
||||||
flowLogger nftypes.FlowLogger
|
flowLogger nftypes.FlowLogger
|
||||||
// ruleIdMap is used to store the rule ID for a given connection
|
// ruleIdMap is used to store the rule ID for a given connection
|
||||||
ruleIdMap sync.Map
|
ruleIdMap sync.Map
|
||||||
stack *stack.Stack
|
stack *stack.Stack
|
||||||
endpoint *endpoint
|
endpoint *endpoint
|
||||||
udpForwarder *udpForwarder
|
udpForwarder *udpForwarder
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
ip tcpip.Address
|
ip tcpip.Address
|
||||||
netstack bool
|
netstack bool
|
||||||
|
hasRawICMPAccess bool
|
||||||
|
pingSemaphore chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(iface common.IFaceMapper, logger *nblog.Logger, flowLogger nftypes.FlowLogger, netstack bool, mtu uint16) (*Forwarder, error) {
|
func New(iface common.IFaceMapper, logger *nblog.Logger, flowLogger nftypes.FlowLogger, netstack bool, mtu uint16) (*Forwarder, error) {
|
||||||
@@ -60,8 +63,8 @@ func New(iface common.IFaceMapper, logger *nblog.Logger, flowLogger nftypes.Flow
|
|||||||
endpoint := &endpoint{
|
endpoint := &endpoint{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
device: iface.GetWGDevice(),
|
device: iface.GetWGDevice(),
|
||||||
mtu: uint32(mtu),
|
|
||||||
}
|
}
|
||||||
|
endpoint.mtu.Store(uint32(mtu))
|
||||||
|
|
||||||
if err := s.CreateNIC(nicID, endpoint); err != nil {
|
if err := s.CreateNIC(nicID, endpoint); err != nil {
|
||||||
return nil, fmt.Errorf("create NIC: %v", err)
|
return nil, fmt.Errorf("create NIC: %v", err)
|
||||||
@@ -103,15 +106,16 @@ func New(iface common.IFaceMapper, logger *nblog.Logger, flowLogger nftypes.Flow
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
f := &Forwarder{
|
f := &Forwarder{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
flowLogger: flowLogger,
|
flowLogger: flowLogger,
|
||||||
stack: s,
|
stack: s,
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
udpForwarder: newUDPForwarder(mtu, logger, flowLogger),
|
udpForwarder: newUDPForwarder(mtu, logger, flowLogger),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
netstack: netstack,
|
netstack: netstack,
|
||||||
ip: tcpip.AddrFromSlice(iface.Address().IP.AsSlice()),
|
ip: tcpip.AddrFromSlice(iface.Address().IP.AsSlice()),
|
||||||
|
pingSemaphore: make(chan struct{}, 3),
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveWindow := defaultReceiveWindow
|
receiveWindow := defaultReceiveWindow
|
||||||
@@ -129,6 +133,8 @@ func New(iface common.IFaceMapper, logger *nblog.Logger, flowLogger nftypes.Flow
|
|||||||
|
|
||||||
s.SetTransportProtocolHandler(icmp.ProtocolNumber4, f.handleICMP)
|
s.SetTransportProtocolHandler(icmp.ProtocolNumber4, f.handleICMP)
|
||||||
|
|
||||||
|
f.checkICMPCapability()
|
||||||
|
|
||||||
log.Debugf("forwarder: Initialization complete with NIC %d", nicID)
|
log.Debugf("forwarder: Initialization complete with NIC %d", nicID)
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
@@ -198,3 +204,24 @@ func buildKey(srcIP, dstIP netip.Addr, srcPort, dstPort uint16) conntrack.ConnKe
|
|||||||
DstPort: dstPort,
|
DstPort: dstPort,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkICMPCapability tests whether we have raw ICMP socket access at startup.
|
||||||
|
func (f *Forwarder) checkICMPCapability() {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
lc := net.ListenConfig{}
|
||||||
|
conn, err := lc.ListenPacket(ctx, "ip4:icmp", "0.0.0.0")
|
||||||
|
if err != nil {
|
||||||
|
f.hasRawICMPAccess = false
|
||||||
|
f.logger.Debug("forwarder: No raw ICMP socket access, will use ping binary fallback")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.Close(); err != nil {
|
||||||
|
f.logger.Debug1("forwarder: Failed to close ICMP capability test socket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.hasRawICMPAccess = true
|
||||||
|
f.logger.Debug("forwarder: Raw ICMP socket access available")
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ package forwarder
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -14,30 +17,95 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// handleICMP handles ICMP packets from the network stack
|
// handleICMP handles ICMP packets from the network stack
|
||||||
func (f *Forwarder) handleICMP(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) bool {
|
func (f *Forwarder) handleICMP(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
|
||||||
icmpHdr := header.ICMPv4(pkt.TransportHeader().View().AsSlice())
|
icmpHdr := header.ICMPv4(pkt.TransportHeader().View().AsSlice())
|
||||||
icmpType := uint8(icmpHdr.Type())
|
|
||||||
icmpCode := uint8(icmpHdr.Code())
|
|
||||||
|
|
||||||
if header.ICMPv4Type(icmpType) == header.ICMPv4EchoReply {
|
|
||||||
// dont process our own replies
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
flowID := uuid.New()
|
flowID := uuid.New()
|
||||||
f.sendICMPEvent(nftypes.TypeStart, flowID, id, icmpType, icmpCode, 0, 0)
|
f.sendICMPEvent(nftypes.TypeStart, flowID, id, uint8(icmpHdr.Type()), uint8(icmpHdr.Code()), 0, 0)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(f.ctx, 5*time.Second)
|
// For Echo Requests, send and wait for response
|
||||||
|
if icmpHdr.Type() == header.ICMPv4Echo {
|
||||||
|
return f.handleICMPEcho(flowID, id, pkt, uint8(icmpHdr.Type()), uint8(icmpHdr.Code()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// For other ICMP types (Time Exceeded, Destination Unreachable, etc), forward without waiting
|
||||||
|
if !f.hasRawICMPAccess {
|
||||||
|
f.logger.Debug2("forwarder: Cannot handle ICMP type %v without raw socket access for %v", icmpHdr.Type(), epID(id))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
icmpData := stack.PayloadSince(pkt.TransportHeader()).AsSlice()
|
||||||
|
conn, err := f.forwardICMPPacket(id, icmpData, uint8(icmpHdr.Type()), uint8(icmpHdr.Code()), 100*time.Millisecond)
|
||||||
|
if err != nil {
|
||||||
|
f.logger.Error2("forwarder: Failed to forward ICMP packet for %v: %v", epID(id), err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err := conn.Close(); err != nil {
|
||||||
|
f.logger.Debug1("forwarder: Failed to close ICMP socket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleICMPEcho handles ICMP echo requests asynchronously with rate limiting.
|
||||||
|
func (f *Forwarder) handleICMPEcho(flowID uuid.UUID, id stack.TransportEndpointID, pkt *stack.PacketBuffer, icmpType, icmpCode uint8) bool {
|
||||||
|
select {
|
||||||
|
case f.pingSemaphore <- struct{}{}:
|
||||||
|
icmpData := stack.PayloadSince(pkt.TransportHeader()).ToSlice()
|
||||||
|
rxBytes := pkt.Size()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() { <-f.pingSemaphore }()
|
||||||
|
|
||||||
|
if f.hasRawICMPAccess {
|
||||||
|
f.handleICMPViaSocket(flowID, id, icmpType, icmpCode, icmpData, rxBytes)
|
||||||
|
} else {
|
||||||
|
f.handleICMPViaPing(flowID, id, icmpType, icmpCode, icmpData, rxBytes)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
default:
|
||||||
|
f.logger.Debug3("forwarder: ICMP rate limit exceeded for %v type %v code %v",
|
||||||
|
epID(id), icmpType, icmpCode)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// forwardICMPPacket creates a raw ICMP socket and sends the packet, returning the connection.
|
||||||
|
// The caller is responsible for closing the returned connection.
|
||||||
|
func (f *Forwarder) forwardICMPPacket(id stack.TransportEndpointID, payload []byte, icmpType, icmpCode uint8, timeout time.Duration) (net.PacketConn, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(f.ctx, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
lc := net.ListenConfig{}
|
lc := net.ListenConfig{}
|
||||||
// TODO: support non-root
|
|
||||||
conn, err := lc.ListenPacket(ctx, "ip4:icmp", "0.0.0.0")
|
conn, err := lc.ListenPacket(ctx, "ip4:icmp", "0.0.0.0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.logger.Error2("forwarder: Failed to create ICMP socket for %v: %v", epID(id), err)
|
return nil, fmt.Errorf("create ICMP socket: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// This will make netstack reply on behalf of the original destination, that's ok for now
|
dstIP := f.determineDialAddr(id.LocalAddress)
|
||||||
return false
|
dst := &net.IPAddr{IP: dstIP}
|
||||||
|
|
||||||
|
if _, err = conn.WriteTo(payload, dst); err != nil {
|
||||||
|
if closeErr := conn.Close(); closeErr != nil {
|
||||||
|
f.logger.Debug1("forwarder: Failed to close ICMP socket: %v", closeErr)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("write ICMP packet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.logger.Trace3("forwarder: Forwarded ICMP packet %v type %v code %v",
|
||||||
|
epID(id), icmpType, icmpCode)
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleICMPViaSocket handles ICMP echo requests using raw sockets.
|
||||||
|
func (f *Forwarder) handleICMPViaSocket(flowID uuid.UUID, id stack.TransportEndpointID, icmpType, icmpCode uint8, icmpData []byte, rxBytes int) {
|
||||||
|
sendTime := time.Now()
|
||||||
|
|
||||||
|
conn, err := f.forwardICMPPacket(id, icmpData, icmpType, icmpCode, 5*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
f.logger.Error2("forwarder: Failed to send ICMP packet for %v: %v", epID(id), err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := conn.Close(); err != nil {
|
if err := conn.Close(); err != nil {
|
||||||
@@ -45,38 +113,22 @@ func (f *Forwarder) handleICMP(id stack.TransportEndpointID, pkt stack.PacketBuf
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
dstIP := f.determineDialAddr(id.LocalAddress)
|
txBytes := f.handleEchoResponse(conn, id)
|
||||||
dst := &net.IPAddr{IP: dstIP}
|
rtt := time.Since(sendTime).Round(10 * time.Microsecond)
|
||||||
|
|
||||||
fullPacket := stack.PayloadSince(pkt.TransportHeader())
|
f.logger.Trace4("forwarder: Forwarded ICMP echo reply %v type %v code %v (rtt=%v, raw socket)",
|
||||||
payload := fullPacket.AsSlice()
|
epID(id), icmpType, icmpCode, rtt)
|
||||||
|
|
||||||
if _, err = conn.WriteTo(payload, dst); err != nil {
|
f.sendICMPEvent(nftypes.TypeEnd, flowID, id, icmpType, icmpCode, uint64(rxBytes), uint64(txBytes))
|
||||||
f.logger.Error2("forwarder: Failed to write ICMP packet for %v: %v", epID(id), err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
f.logger.Trace3("forwarder: Forwarded ICMP packet %v type %v code %v",
|
|
||||||
epID(id), icmpHdr.Type(), icmpHdr.Code())
|
|
||||||
|
|
||||||
// For Echo Requests, send and handle response
|
|
||||||
if header.ICMPv4Type(icmpType) == header.ICMPv4Echo {
|
|
||||||
rxBytes := pkt.Size()
|
|
||||||
txBytes := f.handleEchoResponse(icmpHdr, conn, id)
|
|
||||||
f.sendICMPEvent(nftypes.TypeEnd, flowID, id, icmpType, icmpCode, uint64(rxBytes), uint64(txBytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
// For other ICMP types (Time Exceeded, Destination Unreachable, etc) do nothing
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Forwarder) handleEchoResponse(icmpHdr header.ICMPv4, conn net.PacketConn, id stack.TransportEndpointID) int {
|
func (f *Forwarder) handleEchoResponse(conn net.PacketConn, id stack.TransportEndpointID) int {
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
||||||
f.logger.Error1("forwarder: Failed to set read deadline for ICMP response: %v", err)
|
f.logger.Error1("forwarder: Failed to set read deadline for ICMP response: %v", err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
response := make([]byte, f.endpoint.mtu)
|
response := make([]byte, f.endpoint.mtu.Load())
|
||||||
n, _, err := conn.ReadFrom(response)
|
n, _, err := conn.ReadFrom(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !isTimeout(err) {
|
if !isTimeout(err) {
|
||||||
@@ -85,31 +137,7 @@ func (f *Forwarder) handleEchoResponse(icmpHdr header.ICMPv4, conn net.PacketCon
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ipHdr := make([]byte, header.IPv4MinimumSize)
|
return f.injectICMPReply(id, response[:n])
|
||||||
ip := header.IPv4(ipHdr)
|
|
||||||
ip.Encode(&header.IPv4Fields{
|
|
||||||
TotalLength: uint16(header.IPv4MinimumSize + n),
|
|
||||||
TTL: 64,
|
|
||||||
Protocol: uint8(header.ICMPv4ProtocolNumber),
|
|
||||||
SrcAddr: id.LocalAddress,
|
|
||||||
DstAddr: id.RemoteAddress,
|
|
||||||
})
|
|
||||||
ip.SetChecksum(^ip.CalculateChecksum())
|
|
||||||
|
|
||||||
fullPacket := make([]byte, 0, len(ipHdr)+n)
|
|
||||||
fullPacket = append(fullPacket, ipHdr...)
|
|
||||||
fullPacket = append(fullPacket, response[:n]...)
|
|
||||||
|
|
||||||
if err := f.InjectIncomingPacket(fullPacket); err != nil {
|
|
||||||
f.logger.Error1("forwarder: Failed to inject ICMP response: %v", err)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
f.logger.Trace3("forwarder: Forwarded ICMP echo reply for %v type %v code %v",
|
|
||||||
epID(id), icmpHdr.Type(), icmpHdr.Code())
|
|
||||||
|
|
||||||
return len(fullPacket)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendICMPEvent stores flow events for ICMP packets
|
// sendICMPEvent stores flow events for ICMP packets
|
||||||
@@ -152,3 +180,95 @@ func (f *Forwarder) sendICMPEvent(typ nftypes.Type, flowID uuid.UUID, id stack.T
|
|||||||
|
|
||||||
f.flowLogger.StoreEvent(fields)
|
f.flowLogger.StoreEvent(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleICMPViaPing handles ICMP echo requests by executing the system ping binary.
|
||||||
|
// This is used as a fallback when raw socket access is not available.
|
||||||
|
func (f *Forwarder) handleICMPViaPing(flowID uuid.UUID, id stack.TransportEndpointID, icmpType, icmpCode uint8, icmpData []byte, rxBytes int) {
|
||||||
|
ctx, cancel := context.WithTimeout(f.ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
dstIP := f.determineDialAddr(id.LocalAddress)
|
||||||
|
cmd := buildPingCommand(ctx, dstIP, 5*time.Second)
|
||||||
|
|
||||||
|
pingStart := time.Now()
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
f.logger.Warn4("forwarder: Ping binary failed for %v type %v code %v: %v", epID(id),
|
||||||
|
icmpType, icmpCode, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rtt := time.Since(pingStart).Round(10 * time.Microsecond)
|
||||||
|
|
||||||
|
f.logger.Trace3("forwarder: Forwarded ICMP echo request %v type %v code %v",
|
||||||
|
epID(id), icmpType, icmpCode)
|
||||||
|
|
||||||
|
txBytes := f.synthesizeEchoReply(id, icmpData)
|
||||||
|
|
||||||
|
f.logger.Trace4("forwarder: Forwarded ICMP echo reply %v type %v code %v (rtt=%v, ping binary)",
|
||||||
|
epID(id), icmpType, icmpCode, rtt)
|
||||||
|
|
||||||
|
f.sendICMPEvent(nftypes.TypeEnd, flowID, id, icmpType, icmpCode, uint64(rxBytes), uint64(txBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildPingCommand creates a platform-specific ping command.
|
||||||
|
func buildPingCommand(ctx context.Context, target net.IP, timeout time.Duration) *exec.Cmd {
|
||||||
|
timeoutSec := int(timeout.Seconds())
|
||||||
|
if timeoutSec < 1 {
|
||||||
|
timeoutSec = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux", "android":
|
||||||
|
return exec.CommandContext(ctx, "ping", "-c", "1", "-W", fmt.Sprintf("%d", timeoutSec), "-q", target.String())
|
||||||
|
case "darwin", "ios":
|
||||||
|
return exec.CommandContext(ctx, "ping", "-c", "1", "-t", fmt.Sprintf("%d", timeoutSec), "-q", target.String())
|
||||||
|
case "freebsd":
|
||||||
|
return exec.CommandContext(ctx, "ping", "-c", "1", "-t", fmt.Sprintf("%d", timeoutSec), target.String())
|
||||||
|
case "openbsd", "netbsd":
|
||||||
|
return exec.CommandContext(ctx, "ping", "-c", "1", "-w", fmt.Sprintf("%d", timeoutSec), target.String())
|
||||||
|
case "windows":
|
||||||
|
return exec.CommandContext(ctx, "ping", "-n", "1", "-w", fmt.Sprintf("%d", timeoutSec*1000), target.String())
|
||||||
|
default:
|
||||||
|
return exec.CommandContext(ctx, "ping", "-c", "1", target.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// synthesizeEchoReply creates an ICMP echo reply from raw ICMP data and injects it back into the network stack.
|
||||||
|
// Returns the size of the injected packet.
|
||||||
|
func (f *Forwarder) synthesizeEchoReply(id stack.TransportEndpointID, icmpData []byte) int {
|
||||||
|
replyICMP := make([]byte, len(icmpData))
|
||||||
|
copy(replyICMP, icmpData)
|
||||||
|
|
||||||
|
replyICMPHdr := header.ICMPv4(replyICMP)
|
||||||
|
replyICMPHdr.SetType(header.ICMPv4EchoReply)
|
||||||
|
replyICMPHdr.SetChecksum(0)
|
||||||
|
replyICMPHdr.SetChecksum(header.ICMPv4Checksum(replyICMPHdr, 0))
|
||||||
|
|
||||||
|
return f.injectICMPReply(id, replyICMP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// injectICMPReply wraps an ICMP payload in an IP header and injects it into the network stack.
|
||||||
|
// Returns the total size of the injected packet, or 0 if injection failed.
|
||||||
|
func (f *Forwarder) injectICMPReply(id stack.TransportEndpointID, icmpPayload []byte) int {
|
||||||
|
ipHdr := make([]byte, header.IPv4MinimumSize)
|
||||||
|
ip := header.IPv4(ipHdr)
|
||||||
|
ip.Encode(&header.IPv4Fields{
|
||||||
|
TotalLength: uint16(header.IPv4MinimumSize + len(icmpPayload)),
|
||||||
|
TTL: 64,
|
||||||
|
Protocol: uint8(header.ICMPv4ProtocolNumber),
|
||||||
|
SrcAddr: id.LocalAddress,
|
||||||
|
DstAddr: id.RemoteAddress,
|
||||||
|
})
|
||||||
|
ip.SetChecksum(^ip.CalculateChecksum())
|
||||||
|
|
||||||
|
fullPacket := make([]byte, 0, len(ipHdr)+len(icmpPayload))
|
||||||
|
fullPacket = append(fullPacket, ipHdr...)
|
||||||
|
fullPacket = append(fullPacket, icmpPayload...)
|
||||||
|
|
||||||
|
// Bypass netstack and send directly to peer to avoid looping through our ICMP handler
|
||||||
|
if err := f.endpoint.device.CreateOutboundPacket(fullPacket, id.RemoteAddress.AsSlice()); err != nil {
|
||||||
|
f.logger.Error1("forwarder: Failed to send ICMP reply to peer: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(fullPacket)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -131,10 +132,10 @@ func (f *udpForwarder) cleanup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleUDP is called by the UDP forwarder for new packets
|
// handleUDP is called by the UDP forwarder for new packets
|
||||||
func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) {
|
func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) bool {
|
||||||
if f.ctx.Err() != nil {
|
if f.ctx.Err() != nil {
|
||||||
f.logger.Trace("forwarder: context done, dropping UDP packet")
|
f.logger.Trace("forwarder: context done, dropping UDP packet")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
id := r.ID()
|
id := r.ID()
|
||||||
@@ -144,7 +145,7 @@ func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) {
|
|||||||
f.udpForwarder.RUnlock()
|
f.udpForwarder.RUnlock()
|
||||||
if exists {
|
if exists {
|
||||||
f.logger.Trace1("forwarder: existing UDP connection for %v", epID(id))
|
f.logger.Trace1("forwarder: existing UDP connection for %v", epID(id))
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
flowID := uuid.New()
|
flowID := uuid.New()
|
||||||
@@ -162,7 +163,7 @@ func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
f.logger.Debug2("forwarder: UDP dial error for %v: %v", epID(id), err)
|
f.logger.Debug2("forwarder: UDP dial error for %v: %v", epID(id), err)
|
||||||
// TODO: Send ICMP error message
|
// TODO: Send ICMP error message
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create wait queue for blocking syscalls
|
// Create wait queue for blocking syscalls
|
||||||
@@ -173,10 +174,10 @@ func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) {
|
|||||||
if err := outConn.Close(); err != nil {
|
if err := outConn.Close(); err != nil {
|
||||||
f.logger.Debug2("forwarder: UDP outConn close error for %v: %v", epID(id), err)
|
f.logger.Debug2("forwarder: UDP outConn close error for %v: %v", epID(id), err)
|
||||||
}
|
}
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
inConn := gonet.NewUDPConn(f.stack, &wq, ep)
|
inConn := gonet.NewUDPConn(&wq, ep)
|
||||||
connCtx, connCancel := context.WithCancel(f.ctx)
|
connCtx, connCancel := context.WithCancel(f.ctx)
|
||||||
|
|
||||||
pConn := &udpPacketConn{
|
pConn := &udpPacketConn{
|
||||||
@@ -199,7 +200,7 @@ func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) {
|
|||||||
if err := outConn.Close(); err != nil {
|
if err := outConn.Close(); err != nil {
|
||||||
f.logger.Debug2("forwarder: UDP outConn close error for %v: %v", epID(id), err)
|
f.logger.Debug2("forwarder: UDP outConn close error for %v: %v", epID(id), err)
|
||||||
}
|
}
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
f.udpForwarder.conns[id] = pConn
|
f.udpForwarder.conns[id] = pConn
|
||||||
f.udpForwarder.Unlock()
|
f.udpForwarder.Unlock()
|
||||||
@@ -208,6 +209,7 @@ func (f *Forwarder) handleUDP(r *udp.ForwarderRequest) {
|
|||||||
f.logger.Trace1("forwarder: established UDP connection %v", epID(id))
|
f.logger.Trace1("forwarder: established UDP connection %v", epID(id))
|
||||||
|
|
||||||
go f.proxyUDP(connCtx, pConn, id, ep)
|
go f.proxyUDP(connCtx, pConn, id, ep)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Forwarder) proxyUDP(ctx context.Context, pConn *udpPacketConn, id stack.TransportEndpointID, ep tcpip.Endpoint) {
|
func (f *Forwarder) proxyUDP(ctx context.Context, pConn *udpPacketConn, id stack.TransportEndpointID, ep tcpip.Endpoint) {
|
||||||
@@ -348,7 +350,7 @@ func (c *udpPacketConn) copy(ctx context.Context, dst net.Conn, src net.Conn, bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isClosedError(err error) bool {
|
func isClosedError(err error) bool {
|
||||||
return errors.Is(err, net.ErrClosed) || errors.Is(err, context.Canceled)
|
return errors.Is(err, net.ErrClosed) || errors.Is(err, context.Canceled) || errors.Is(err, io.EOF)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTimeout(err error) bool {
|
func isTimeout(err error) bool {
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ func (m *localIPManager) UpdateLocalIPs(iface common.IFaceMapper) (err error) {
|
|||||||
// 127.0.0.0/8
|
// 127.0.0.0/8
|
||||||
newIPv4Bitmap[127] = &ipv4LowBitmap{}
|
newIPv4Bitmap[127] = &ipv4LowBitmap{}
|
||||||
for i := 0; i < 8192; i++ {
|
for i := 0; i < 8192; i++ {
|
||||||
|
// #nosec G602 -- bitmap is defined as [8192]uint32, loop range is correct
|
||||||
newIPv4Bitmap[127].bitmap[i] = 0xFFFFFFFF
|
newIPv4Bitmap[127].bitmap[i] = 0xFFFFFFFF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ func BenchmarkIPChecks(b *testing.B) {
|
|||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// nolint:gosimple
|
// nolint:gosimple
|
||||||
_, _ = mapManager.localIPs[ip.String()]
|
_ = mapManager.localIPs[ip.String()]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ func BenchmarkIPChecks(b *testing.B) {
|
|||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// nolint:gosimple
|
// nolint:gosimple
|
||||||
_, _ = mapManager.localIPs[ip.String()]
|
_ = mapManager.localIPs[ip.String()]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,15 @@ func (l *Logger) Warn3(format string, arg1, arg2, arg3 any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Warn4(format string, arg1, arg2, arg3, arg4 any) {
|
||||||
|
if l.level.Load() >= uint32(LevelWarn) {
|
||||||
|
select {
|
||||||
|
case l.msgChannel <- logMessage{level: LevelWarn, format: format, arg1: arg1, arg2: arg2, arg3: arg3, arg4: arg4}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Logger) Debug1(format string, arg1 any) {
|
func (l *Logger) Debug1(format string, arg1 any) {
|
||||||
if l.level.Load() >= uint32(LevelDebug) {
|
if l.level.Load() >= uint32(LevelDebug) {
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -234,9 +234,10 @@ func TestInboundPortDNATNegative(t *testing.T) {
|
|||||||
require.False(t, translated, "Packet should NOT be translated for %s", tc.name)
|
require.False(t, translated, "Packet should NOT be translated for %s", tc.name)
|
||||||
|
|
||||||
d = parsePacket(t, packet)
|
d = parsePacket(t, packet)
|
||||||
if tc.protocol == layers.IPProtocolTCP {
|
switch tc.protocol {
|
||||||
|
case layers.IPProtocolTCP:
|
||||||
require.Equal(t, tc.dstPort, uint16(d.tcp.DstPort), "Port should remain unchanged")
|
require.Equal(t, tc.dstPort, uint16(d.tcp.DstPort), "Port should remain unchanged")
|
||||||
} else if tc.protocol == layers.IPProtocolUDP {
|
case layers.IPProtocolUDP:
|
||||||
require.Equal(t, tc.dstPort, uint16(d.udp.DstPort), "Port should remain unchanged")
|
require.Equal(t, tc.dstPort, uint16(d.udp.DstPort), "Port should remain unchanged")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type RouteRule struct {
|
|||||||
sources []netip.Prefix
|
sources []netip.Prefix
|
||||||
dstSet firewall.Set
|
dstSet firewall.Set
|
||||||
destinations []netip.Prefix
|
destinations []netip.Prefix
|
||||||
proto firewall.Protocol
|
protoLayer gopacket.LayerType
|
||||||
srcPort *firewall.Port
|
srcPort *firewall.Port
|
||||||
dstPort *firewall.Port
|
dstPort *firewall.Port
|
||||||
action firewall.Action
|
action firewall.Action
|
||||||
|
|||||||
@@ -379,9 +379,9 @@ func (m *Manager) handleNativeRouter(trace *PacketTrace) *PacketTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) handleRouteACLs(trace *PacketTrace, d *decoder, srcIP, dstIP netip.Addr) *PacketTrace {
|
func (m *Manager) handleRouteACLs(trace *PacketTrace, d *decoder, srcIP, dstIP netip.Addr) *PacketTrace {
|
||||||
proto, _ := getProtocolFromPacket(d)
|
protoLayer := d.decoded[1]
|
||||||
srcPort, dstPort := getPortsFromPacket(d)
|
srcPort, dstPort := getPortsFromPacket(d)
|
||||||
id, allowed := m.routeACLsPass(srcIP, dstIP, proto, srcPort, dstPort)
|
id, allowed := m.routeACLsPass(srcIP, dstIP, protoLayer, srcPort, dstPort)
|
||||||
|
|
||||||
strId := string(id)
|
strId := string(id)
|
||||||
if id == nil {
|
if id == nil {
|
||||||
|
|||||||
@@ -27,8 +27,23 @@ type receiverCreator struct {
|
|||||||
iceBind *ICEBind
|
iceBind *ICEBind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc receiverCreator) CreateIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, rxOffload bool, msgPool *sync.Pool) wgConn.ReceiveFunc {
|
func (rc receiverCreator) CreateReceiverFn(pc wgConn.BatchReader, conn *net.UDPConn, rxOffload bool, msgPool *sync.Pool) wgConn.ReceiveFunc {
|
||||||
return rc.iceBind.createIPv4ReceiverFn(pc, conn, rxOffload, msgPool)
|
if ipv4PC, ok := pc.(*ipv4.PacketConn); ok {
|
||||||
|
return rc.iceBind.createIPv4ReceiverFn(ipv4PC, conn, rxOffload, msgPool)
|
||||||
|
}
|
||||||
|
// IPv6 is currently not supported in the udpmux, this is a stub for compatibility with the
|
||||||
|
// wireguard-go ReceiverCreator interface which is called for both IPv4 and IPv6.
|
||||||
|
return func(bufs [][]byte, sizes []int, eps []wgConn.Endpoint) (n int, err error) {
|
||||||
|
buf := bufs[0]
|
||||||
|
size, ep, err := conn.ReadFromUDPAddrPort(buf)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
sizes[0] = size
|
||||||
|
stdEp := &wgConn.StdNetEndpoint{AddrPort: ep}
|
||||||
|
eps[0] = stdEp
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICEBind is a bind implementation with two main features:
|
// ICEBind is a bind implementation with two main features:
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
//go:build ios
|
|
||||||
// +build ios
|
|
||||||
|
|
||||||
package device
|
package device
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -507,15 +507,13 @@ func formatPayloadWithCmp(p *expr.Payload, cmp *expr.Cmp) string {
|
|||||||
if p.Base == expr.PayloadBaseNetworkHeader {
|
if p.Base == expr.PayloadBaseNetworkHeader {
|
||||||
switch p.Offset {
|
switch p.Offset {
|
||||||
case 12:
|
case 12:
|
||||||
if p.Len == 4 {
|
switch p.Len {
|
||||||
return fmt.Sprintf("ip saddr %s %s", formatCmpOp(cmp.Op), formatIPBytes(cmp.Data))
|
case 4, 2:
|
||||||
} else if p.Len == 2 {
|
|
||||||
return fmt.Sprintf("ip saddr %s %s", formatCmpOp(cmp.Op), formatIPBytes(cmp.Data))
|
return fmt.Sprintf("ip saddr %s %s", formatCmpOp(cmp.Op), formatIPBytes(cmp.Data))
|
||||||
}
|
}
|
||||||
case 16:
|
case 16:
|
||||||
if p.Len == 4 {
|
switch p.Len {
|
||||||
return fmt.Sprintf("ip daddr %s %s", formatCmpOp(cmp.Op), formatIPBytes(cmp.Data))
|
case 4, 2:
|
||||||
} else if p.Len == 2 {
|
|
||||||
return fmt.Sprintf("ip daddr %s %s", formatCmpOp(cmp.Op), formatIPBytes(cmp.Data))
|
return fmt.Sprintf("ip daddr %s %s", formatCmpOp(cmp.Op), formatIPBytes(cmp.Data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,8 @@ func (r *SysOps) refreshLocalSubnetsCache() {
|
|||||||
func (r *SysOps) genericAddVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
|
func (r *SysOps) genericAddVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
|
||||||
nextHop := Nexthop{netip.Addr{}, intf}
|
nextHop := Nexthop{netip.Addr{}, intf}
|
||||||
|
|
||||||
if prefix == vars.Defaultv4 {
|
switch prefix {
|
||||||
|
case vars.Defaultv4:
|
||||||
if err := r.addToRouteTable(splitDefaultv4_1, nextHop); err != nil {
|
if err := r.addToRouteTable(splitDefaultv4_1, nextHop); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -233,7 +234,7 @@ func (r *SysOps) genericAddVPNRoute(prefix netip.Prefix, intf *net.Interface) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
} else if prefix == vars.Defaultv6 {
|
case vars.Defaultv6:
|
||||||
if err := r.addToRouteTable(splitDefaultv6_1, nextHop); err != nil {
|
if err := r.addToRouteTable(splitDefaultv6_1, nextHop); err != nil {
|
||||||
return fmt.Errorf("add unreachable route split 1: %w", err)
|
return fmt.Errorf("add unreachable route split 1: %w", err)
|
||||||
}
|
}
|
||||||
@@ -255,7 +256,8 @@ func (r *SysOps) genericAddVPNRoute(prefix netip.Prefix, intf *net.Interface) er
|
|||||||
func (r *SysOps) genericRemoveVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
|
func (r *SysOps) genericRemoveVPNRoute(prefix netip.Prefix, intf *net.Interface) error {
|
||||||
nextHop := Nexthop{netip.Addr{}, intf}
|
nextHop := Nexthop{netip.Addr{}, intf}
|
||||||
|
|
||||||
if prefix == vars.Defaultv4 {
|
switch prefix {
|
||||||
|
case vars.Defaultv4:
|
||||||
var result *multierror.Error
|
var result *multierror.Error
|
||||||
if err := r.removeFromRouteTable(splitDefaultv4_1, nextHop); err != nil {
|
if err := r.removeFromRouteTable(splitDefaultv4_1, nextHop); err != nil {
|
||||||
result = multierror.Append(result, err)
|
result = multierror.Append(result, err)
|
||||||
@@ -273,7 +275,7 @@ func (r *SysOps) genericRemoveVPNRoute(prefix netip.Prefix, intf *net.Interface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nberrors.FormatErrorOrNil(result)
|
return nberrors.FormatErrorOrNil(result)
|
||||||
} else if prefix == vars.Defaultv6 {
|
case vars.Defaultv6:
|
||||||
var result *multierror.Error
|
var result *multierror.Error
|
||||||
if err := r.removeFromRouteTable(splitDefaultv6_1, nextHop); err != nil {
|
if err := r.removeFromRouteTable(splitDefaultv6_1, nextHop); err != nil {
|
||||||
result = multierror.Append(result, err)
|
result = multierror.Append(result, err)
|
||||||
@@ -283,9 +285,9 @@ func (r *SysOps) genericRemoveVPNRoute(prefix netip.Prefix, intf *net.Interface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nberrors.FormatErrorOrNil(result)
|
return nberrors.FormatErrorOrNil(result)
|
||||||
|
default:
|
||||||
|
return r.removeFromRouteTable(prefix, nextHop)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.removeFromRouteTable(prefix, nextHop)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SysOps) setupHooks(initAddresses []net.IP, stateManager *statemanager.Manager) error {
|
func (r *SysOps) setupHooks(initAddresses []net.IP, stateManager *statemanager.Manager) error {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ type Client struct {
|
|||||||
loginComplete bool
|
loginComplete bool
|
||||||
connectClient *internal.ConnectClient
|
connectClient *internal.ConnectClient
|
||||||
// preloadedConfig holds config loaded from JSON (used on tvOS where file writes are blocked)
|
// preloadedConfig holds config loaded from JSON (used on tvOS where file writes are blocked)
|
||||||
preloadedConfig *profilemanager.Config
|
preloadedConfig *profilemanager.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient instantiate a new Client
|
// NewClient instantiate a new Client
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package server
|
package server
|
||||||
|
|
||||||
|
|||||||
@@ -602,12 +602,13 @@ func TestJWTAuthentication(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var authMethods []cryptossh.AuthMethod
|
var authMethods []cryptossh.AuthMethod
|
||||||
if tc.token == "valid" {
|
switch tc.token {
|
||||||
|
case "valid":
|
||||||
token := generateValidJWT(t, privateKey, issuer, audience)
|
token := generateValidJWT(t, privateKey, issuer, audience)
|
||||||
authMethods = []cryptossh.AuthMethod{
|
authMethods = []cryptossh.AuthMethod{
|
||||||
cryptossh.Password(token),
|
cryptossh.Password(token),
|
||||||
}
|
}
|
||||||
} else if tc.token == "invalid" {
|
case "invalid":
|
||||||
invalidToken := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.invalid"
|
invalidToken := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.invalid"
|
||||||
authMethods = []cryptossh.AuthMethod{
|
authMethods = []cryptossh.AuthMethod{
|
||||||
cryptossh.Password(invalidToken),
|
cryptossh.Password(invalidToken),
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
//go:build android
|
|
||||||
// +build android
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !ios
|
//go:build !ios
|
||||||
// +build !ios
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
//go:build ios
|
|
||||||
// +build ios
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -510,7 +510,7 @@ func (s *serviceClient) saveSettings() {
|
|||||||
// Continue with default behavior if features can't be retrieved
|
// Continue with default behavior if features can't be retrieved
|
||||||
} else if features != nil && features.DisableUpdateSettings {
|
} else if features != nil && features.DisableUpdateSettings {
|
||||||
log.Warn("Configuration updates are disabled by daemon")
|
log.Warn("Configuration updates are disabled by daemon")
|
||||||
dialog.ShowError(fmt.Errorf("Configuration updates are disabled by daemon"), s.wSettings)
|
dialog.ShowError(fmt.Errorf("configuration updates are disabled by daemon"), s.wSettings)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +540,7 @@ func (s *serviceClient) saveSettings() {
|
|||||||
func (s *serviceClient) validateSettings() error {
|
func (s *serviceClient) validateSettings() error {
|
||||||
if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != censoredPreSharedKey {
|
if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != censoredPreSharedKey {
|
||||||
if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil {
|
if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil {
|
||||||
return fmt.Errorf("Invalid Pre-shared Key Value")
|
return fmt.Errorf("invalid pre-shared key value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -549,10 +549,10 @@ func (s *serviceClient) validateSettings() error {
|
|||||||
func (s *serviceClient) parseNumericSettings() (int64, int64, error) {
|
func (s *serviceClient) parseNumericSettings() (int64, int64, error) {
|
||||||
port, err := strconv.ParseInt(s.iInterfacePort.Text, 10, 64)
|
port, err := strconv.ParseInt(s.iInterfacePort.Text, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, errors.New("Invalid interface port")
|
return 0, 0, errors.New("invalid interface port")
|
||||||
}
|
}
|
||||||
if port < 1 || port > 65535 {
|
if port < 1 || port > 65535 {
|
||||||
return 0, 0, errors.New("Invalid interface port: out of range 1-65535")
|
return 0, 0, errors.New("invalid interface port: out of range 1-65535")
|
||||||
}
|
}
|
||||||
|
|
||||||
var mtu int64
|
var mtu int64
|
||||||
@@ -560,7 +560,7 @@ func (s *serviceClient) parseNumericSettings() (int64, int64, error) {
|
|||||||
if mtuText != "" {
|
if mtuText != "" {
|
||||||
mtu, err = strconv.ParseInt(mtuText, 10, 64)
|
mtu, err = strconv.ParseInt(mtuText, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, errors.New("Invalid MTU value")
|
return 0, 0, errors.New("invalid MTU value")
|
||||||
}
|
}
|
||||||
if mtu < iface.MinMTU || mtu > iface.MaxMTU {
|
if mtu < iface.MinMTU || mtu > iface.MaxMTU {
|
||||||
return 0, 0, fmt.Errorf("MTU must be between %d and %d bytes", iface.MinMTU, iface.MaxMTU)
|
return 0, 0, fmt.Errorf("MTU must be between %d and %d bytes", iface.MinMTU, iface.MaxMTU)
|
||||||
@@ -645,7 +645,7 @@ func (s *serviceClient) buildSetConfigRequest(iMngURL string, port, mtu int64) (
|
|||||||
if sshJWTCacheTTLText != "" {
|
if sshJWTCacheTTLText != "" {
|
||||||
sshJWTCacheTTL, err := strconv.ParseInt(sshJWTCacheTTLText, 10, 32)
|
sshJWTCacheTTL, err := strconv.ParseInt(sshJWTCacheTTLText, 10, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Invalid SSH JWT Cache TTL value")
|
return nil, errors.New("invalid SSH JWT Cache TTL value")
|
||||||
}
|
}
|
||||||
if sshJWTCacheTTL < 0 || sshJWTCacheTTL > maxSSHJWTCacheTTL {
|
if sshJWTCacheTTL < 0 || sshJWTCacheTTL > maxSSHJWTCacheTTL {
|
||||||
return nil, fmt.Errorf("SSH JWT Cache TTL must be between 0 and %d seconds", maxSSHJWTCacheTTL)
|
return nil, fmt.Errorf("SSH JWT Cache TTL must be between 0 and %d seconds", maxSSHJWTCacheTTL)
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func sendShowWindowSignal(pid int32) error {
|
|||||||
|
|
||||||
err = windows.SetEvent(eventHandle)
|
err = windows.SetEvent(eventHandle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error setting event: %w", err)
|
return fmt.Errorf("error setting event: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
module github.com/netbirdio/netbird
|
module github.com/netbirdio/netbird
|
||||||
|
|
||||||
go 1.24.10
|
go 1.25
|
||||||
|
|
||||||
|
toolchain go1.25.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cunicu.li/go-rosenpass v0.4.0
|
cunicu.li/go-rosenpass v0.4.0
|
||||||
@@ -40,7 +42,7 @@ require (
|
|||||||
github.com/cilium/ebpf v0.15.0
|
github.com/cilium/ebpf v0.15.0
|
||||||
github.com/coder/websocket v1.8.13
|
github.com/coder/websocket v1.8.13
|
||||||
github.com/coreos/go-iptables v0.7.0
|
github.com/coreos/go-iptables v0.7.0
|
||||||
github.com/creack/pty v1.1.18
|
github.com/creack/pty v1.1.24
|
||||||
github.com/dexidp/dex v0.0.0-00010101000000-000000000000
|
github.com/dexidp/dex v0.0.0-00010101000000-000000000000
|
||||||
github.com/dexidp/dex/api/v2 v2.4.0
|
github.com/dexidp/dex/api/v2 v2.4.0
|
||||||
github.com/eko/gocache/lib/v4 v4.2.0
|
github.com/eko/gocache/lib/v4 v4.2.0
|
||||||
@@ -81,7 +83,7 @@ require (
|
|||||||
github.com/pion/turn/v3 v3.0.1
|
github.com/pion/turn/v3 v3.0.1
|
||||||
github.com/pkg/sftp v1.13.9
|
github.com/pkg/sftp v1.13.9
|
||||||
github.com/prometheus/client_golang v1.23.2
|
github.com/prometheus/client_golang v1.23.2
|
||||||
github.com/quic-go/quic-go v0.49.1
|
github.com/quic-go/quic-go v0.55.0
|
||||||
github.com/redis/go-redis/v9 v9.7.3
|
github.com/redis/go-redis/v9 v9.7.3
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
github.com/shirou/gopsutil/v3 v3.24.4
|
github.com/shirou/gopsutil/v3 v3.24.4
|
||||||
@@ -103,7 +105,7 @@ require (
|
|||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0
|
go.opentelemetry.io/otel/exporters/prometheus v0.48.0
|
||||||
go.opentelemetry.io/otel/metric v1.38.0
|
go.opentelemetry.io/otel/metric v1.38.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0
|
go.opentelemetry.io/otel/sdk/metric v1.38.0
|
||||||
go.uber.org/mock v0.5.0
|
go.uber.org/mock v0.5.2
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
goauthentik.io/api/v3 v3.2023051.3
|
goauthentik.io/api/v3 v3.2023051.3
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
@@ -120,7 +122,7 @@ require (
|
|||||||
gorm.io/driver/postgres v1.5.7
|
gorm.io/driver/postgres v1.5.7
|
||||||
gorm.io/driver/sqlite v1.5.7
|
gorm.io/driver/sqlite v1.5.7
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
gvisor.dev/gvisor v0.0.0-20231020174304-b8a429915ff1
|
gvisor.dev/gvisor v0.0.0-20251031020517-ecfcdd2f171c
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -186,12 +188,10 @@ require (
|
|||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
|
||||||
github.com/go-text/render v0.2.0 // indirect
|
github.com/go-text/render v0.2.0 // indirect
|
||||||
github.com/go-text/typesetting v0.2.1 // indirect
|
github.com/go-text/typesetting v0.2.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
|
|
||||||
github.com/google/s2a-go v0.1.9 // indirect
|
github.com/google/s2a-go v0.1.9 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||||
@@ -285,7 +285,7 @@ replace github.com/kardianos/service => github.com/netbirdio/service v0.0.0-2024
|
|||||||
|
|
||||||
replace github.com/getlantern/systray => github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949
|
replace github.com/getlantern/systray => github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949
|
||||||
|
|
||||||
replace golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20241230120307-6a676aebaaf6
|
replace golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0
|
||||||
|
|
||||||
replace github.com/cloudflare/circl => github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
|
replace github.com/cloudflare/circl => github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
|
||||||
|
|
||||||
|
|||||||
@@ -101,9 +101,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
|
|||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
|
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
|
||||||
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
|
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
|
||||||
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
||||||
@@ -121,8 +118,8 @@ github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmr
|
|||||||
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
||||||
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6 h1:/DS5cDX3FJdl+XaN2D7XAwFpuanTxnp52DBLZAaJKx0=
|
github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6 h1:/DS5cDX3FJdl+XaN2D7XAwFpuanTxnp52DBLZAaJKx0=
|
||||||
github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
|
github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -286,7 +283,6 @@ github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
|||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
@@ -411,8 +407,8 @@ github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9ax
|
|||||||
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ=
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ=
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45/go.mod h1:5/sjFmLb8O96B5737VCqhHyGRzNFIaN/Bu7ZodXc3qQ=
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45/go.mod h1:5/sjFmLb8O96B5737VCqhHyGRzNFIaN/Bu7ZodXc3qQ=
|
||||||
github.com/netbirdio/wireguard-go v0.0.0-20241230120307-6a676aebaaf6 h1:X5h5QgP7uHAv78FWgHV8+WYLjHxK9v3ilkVXT1cpCrQ=
|
github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0 h1:h/QnNzm7xzHPm+gajcblYUOclrW2FeNeDlUNj6tTWKQ=
|
||||||
github.com/netbirdio/wireguard-go v0.0.0-20241230120307-6a676aebaaf6/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
||||||
@@ -491,8 +487,8 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z
|
|||||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
||||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||||
github.com/quic-go/quic-go v0.49.1 h1:e5JXpUyF0f2uFjckQzD8jTghZrOUK1xxDqqZhlwixo0=
|
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||||
github.com/quic-go/quic-go v0.49.1/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
@@ -622,8 +618,8 @@ go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lI
|
|||||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
@@ -717,7 +713,6 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -848,5 +843,5 @@ gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
|||||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
||||||
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||||
gvisor.dev/gvisor v0.0.0-20231020174304-b8a429915ff1 h1:qDCwdCWECGnwQSQC01Dpnp09fRHxJs9PbktotUqG+hs=
|
gvisor.dev/gvisor v0.0.0-20251031020517-ecfcdd2f171c h1:pfzmXIkkDgydR4ZRP+e1hXywZfYR21FA0Fbk6ptMkiA=
|
||||||
gvisor.dev/gvisor v0.0.0-20231020174304-b8a429915ff1/go.mod h1:8hmigyCdYtw5xJGfQDJzSH5Ju8XEIDBnpyi8+O6GRt8=
|
gvisor.dev/gvisor v0.0.0-20251031020517-ecfcdd2f171c/go.mod h1:/mc6CfwbOm5KKmqoV7Qx20Q+Ja8+vO4g7FuCdlVoAfQ=
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ var (
|
|||||||
config.HttpConfig.IdpSignKeyRefreshEnabled = idpSignKeyRefreshEnabled
|
config.HttpConfig.IdpSignKeyRefreshEnabled = idpSignKeyRefreshEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsEnabled := false
|
var tlsEnabled bool
|
||||||
if mgmtLetsencryptDomain != "" || (config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "") {
|
if mgmtLetsencryptDomain != "" || (config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "") {
|
||||||
tlsEnabled = true
|
tlsEnabled = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ func (s *LoginFilterTestSuite) TestBanDurationIncreasesExponentially() {
|
|||||||
s.True(s.filter.logged[pubKey].isBanned)
|
s.True(s.filter.logged[pubKey].isBanned)
|
||||||
s.Equal(2, s.filter.logged[pubKey].banLevel)
|
s.Equal(2, s.filter.logged[pubKey].banLevel)
|
||||||
secondBanDuration := s.filter.logged[pubKey].banExpiresAt.Sub(s.filter.logged[pubKey].lastSeen)
|
secondBanDuration := s.filter.logged[pubKey].banExpiresAt.Sub(s.filter.logged[pubKey].lastSeen)
|
||||||
|
// nolint
|
||||||
expectedSecondDuration := time.Duration(float64(baseBan) * math.Pow(2, 1))
|
expectedSecondDuration := time.Duration(float64(baseBan) * math.Pow(2, 1))
|
||||||
s.InDelta(expectedSecondDuration, secondBanDuration, float64(time.Millisecond))
|
s.InDelta(expectedSecondDuration, secondBanDuration, float64(time.Millisecond))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1006,7 +1006,7 @@ func (am *DefaultAccountManager) isCacheFresh(ctx context.Context, accountUsers
|
|||||||
for user, loggedInOnce := range accountUsers {
|
for user, loggedInOnce := range accountUsers {
|
||||||
if datum, ok := userDataMap[user]; ok {
|
if datum, ok := userDataMap[user]; ok {
|
||||||
// check if the matching user data has a pending invite and if the user has logged in once, forcing the cache to be refreshed
|
// check if the matching user data has a pending invite and if the user has logged in once, forcing the cache to be refreshed
|
||||||
if datum.AppMetadata.WTPendingInvite != nil && *datum.AppMetadata.WTPendingInvite && loggedInOnce == true { //nolint:gosimple
|
if datum.AppMetadata.WTPendingInvite != nil && *datum.AppMetadata.WTPendingInvite && loggedInOnce == true { //nolint
|
||||||
log.WithContext(ctx).Infof("user %s has a pending invite and has logged in once, cache invalid", user)
|
log.WithContext(ctx).Infof("user %s has a pending invite and has logged in once, cache invalid", user)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -753,7 +753,7 @@ func TestAccountManager_SetOrUpdateDomain(t *testing.T) {
|
|||||||
t.Fatalf("expected to create an account for a user %s", userId)
|
t.Fatalf("expected to create an account for a user %s", userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if account != nil && account.Domain != domain {
|
if account.Domain != domain {
|
||||||
t.Errorf("setting account domain failed, expected %s, got %s", domain, account.Domain)
|
t.Errorf("setting account domain failed, expected %s, got %s", domain, account.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,7 +768,7 @@ func TestAccountManager_SetOrUpdateDomain(t *testing.T) {
|
|||||||
t.Fatalf("expected to get an account for a user %s", userId)
|
t.Fatalf("expected to get an account for a user %s", userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if account != nil && account.Domain != domain {
|
if account.Domain != domain {
|
||||||
t.Errorf("updating domain. expected %s got %s", domain, account.Domain)
|
t.Errorf("updating domain. expected %s got %s", domain, account.Domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3479,11 +3479,11 @@ func TestPropagateUserGroupMemberships(t *testing.T) {
|
|||||||
account, err := manager.GetOrCreateAccountByUser(ctx, auth.UserAuth{UserId: initiatorId, Domain: domain})
|
account, err := manager.GetOrCreateAccountByUser(ctx, auth.UserAuth{UserId: initiatorId, Domain: domain})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
peer1 := &nbpeer.Peer{ID: "peer1", AccountID: account.Id, UserID: initiatorId, IP: net.IP{1, 1, 1, 1}, DNSLabel: "peer1.domain.test"}
|
peer1 := &nbpeer.Peer{ID: "peer1", AccountID: account.Id, Key: "key1", UserID: initiatorId, IP: net.IP{1, 1, 1, 1}, DNSLabel: "peer1.domain.test"}
|
||||||
err = manager.Store.AddPeerToAccount(ctx, peer1)
|
err = manager.Store.AddPeerToAccount(ctx, peer1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
peer2 := &nbpeer.Peer{ID: "peer2", AccountID: account.Id, UserID: initiatorId, IP: net.IP{2, 2, 2, 2}, DNSLabel: "peer2.domain.test"}
|
peer2 := &nbpeer.Peer{ID: "peer2", AccountID: account.Id, Key: "key2", UserID: initiatorId, IP: net.IP{2, 2, 2, 2}, DNSLabel: "peer2.domain.test"}
|
||||||
err = manager.Store.AddPeerToAccount(ctx, peer2)
|
err = manager.Store.AddPeerToAccount(ctx, peer2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -903,6 +903,7 @@ func Test_AddPeerAndAddToAll(t *testing.T) {
|
|||||||
peer := &peer2.Peer{
|
peer := &peer2.Peer{
|
||||||
ID: strconv.Itoa(i),
|
ID: strconv.Itoa(i),
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
|
Key: "key" + strconv.Itoa(i),
|
||||||
DNSLabel: "peer" + strconv.Itoa(i),
|
DNSLabel: "peer" + strconv.Itoa(i),
|
||||||
IP: uint32ToIP(uint32(i)),
|
IP: uint32ToIP(uint32(i)),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func initPostureChecksTestData(postureChecks ...*posture.Checks) *postureChecksH
|
|||||||
testPostureChecks[postureChecks.ID] = postureChecks
|
testPostureChecks[postureChecks.ID] = postureChecks
|
||||||
|
|
||||||
if err := postureChecks.Validate(); err != nil {
|
if err := postureChecks.Validate(); err != nil {
|
||||||
return nil, status.Errorf(status.InvalidArgument, "%s", err.Error()) //nolint
|
return nil, status.Errorf(status.InvalidArgument, "%v", err) //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
return postureChecks, nil
|
return postureChecks, nil
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build benchmark
|
//go:build benchmark
|
||||||
// +build benchmark
|
|
||||||
|
|
||||||
package benchmarks
|
package benchmarks
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build benchmark
|
//go:build benchmark
|
||||||
// +build benchmark
|
|
||||||
|
|
||||||
package benchmarks
|
package benchmarks
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build benchmark
|
//go:build benchmark
|
||||||
// +build benchmark
|
|
||||||
|
|
||||||
package benchmarks
|
package benchmarks
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func NewPocketIdManager(config PocketIdClientConfig, appMetrics telemetry.AppMet
|
|||||||
func (p *PocketIdManager) request(ctx context.Context, method, resource string, query *url.Values, body string) ([]byte, error) {
|
func (p *PocketIdManager) request(ctx context.Context, method, resource string, query *url.Values, body string) ([]byte, error) {
|
||||||
var MethodsWithBody = []string{http.MethodPost, http.MethodPut}
|
var MethodsWithBody = []string{http.MethodPost, http.MethodPut}
|
||||||
if !slices.Contains(MethodsWithBody, method) && body != "" {
|
if !slices.Contains(MethodsWithBody, method) && body != "" {
|
||||||
return nil, fmt.Errorf("Body provided to unsupported method: %s", method)
|
return nil, fmt.Errorf("body provided to unsupported method: %s", method)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqURL := fmt.Sprintf("%s/api/%s", p.managementEndpoint, resource)
|
reqURL := fmt.Sprintf("%s/api/%s", p.managementEndpoint, resource)
|
||||||
@@ -301,7 +301,7 @@ func (p *PocketIdManager) CreateUser(ctx context.Context, email, name, accountID
|
|||||||
if p.appMetrics != nil {
|
if p.appMetrics != nil {
|
||||||
p.appMetrics.IDPMetrics().CountCreateUser()
|
p.appMetrics.IDPMetrics().CountCreateUser()
|
||||||
}
|
}
|
||||||
var pending bool = true
|
pending := true
|
||||||
ret := &UserData{
|
ret := &UserData{
|
||||||
Email: email,
|
Email: email,
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ func (zm *ZitadelManager) CreateUser(ctx context.Context, email, name, accountID
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pending bool = true
|
pending := true
|
||||||
ret := &UserData{
|
ret := &UserData{
|
||||||
Email: email,
|
Email: email,
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ func CreateIndexIfNotExists[T any](ctx context.Context, db *gorm.DB, indexName s
|
|||||||
return fmt.Errorf("failed to parse model schema: %w", err)
|
return fmt.Errorf("failed to parse model schema: %w", err)
|
||||||
}
|
}
|
||||||
tableName := stmt.Schema.Table
|
tableName := stmt.Schema.Table
|
||||||
dialect := db.Dialector.Name()
|
dialect := db.Name()
|
||||||
|
|
||||||
if db.Migrator().HasIndex(&model, indexName) {
|
if db.Migrator().HasIndex(&model, indexName) {
|
||||||
log.WithContext(ctx).Infof("index %s already exists on table %s", indexName, tableName)
|
log.WithContext(ctx).Infof("index %s already exists on table %s", indexName, tableName)
|
||||||
@@ -404,10 +404,11 @@ func CreateIndexIfNotExists[T any](ctx context.Context, db *gorm.DB, indexName s
|
|||||||
if dialect == "mysql" {
|
if dialect == "mysql" {
|
||||||
var withLength []string
|
var withLength []string
|
||||||
for _, col := range columns {
|
for _, col := range columns {
|
||||||
if col == "ip" || col == "dns_label" {
|
quotedCol := fmt.Sprintf("`%s`", col)
|
||||||
withLength = append(withLength, fmt.Sprintf("%s(64)", col))
|
if col == "ip" || col == "dns_label" || col == "key" {
|
||||||
|
withLength = append(withLength, fmt.Sprintf("%s(64)", quotedCol))
|
||||||
} else {
|
} else {
|
||||||
withLength = append(withLength, col)
|
withLength = append(withLength, quotedCol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
columnClause = strings.Join(withLength, ", ")
|
columnClause = strings.Join(withLength, ", ")
|
||||||
@@ -488,6 +489,57 @@ func MigrateJsonToTable[T any](ctx context.Context, db *gorm.DB, columnName stri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RemoveDuplicatePeerKeys(ctx context.Context, db *gorm.DB) error {
|
||||||
|
if !db.Migrator().HasTable("peers") {
|
||||||
|
log.WithContext(ctx).Debug("peers table does not exist, skipping duplicate key cleanup")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
keyColumn := GetColumnName(db, "key")
|
||||||
|
|
||||||
|
var duplicates []struct {
|
||||||
|
Key string
|
||||||
|
Count int64
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Table("peers").
|
||||||
|
Select(keyColumn + ", COUNT(*) as count").
|
||||||
|
Group(keyColumn).
|
||||||
|
Having("COUNT(*) > 1").
|
||||||
|
Find(&duplicates).Error; err != nil {
|
||||||
|
return fmt.Errorf("find duplicate keys: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(duplicates) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithContext(ctx).Warnf("Found %d duplicate peer keys, cleaning up", len(duplicates))
|
||||||
|
|
||||||
|
for _, dup := range duplicates {
|
||||||
|
var peerIDs []string
|
||||||
|
if err := db.Table("peers").
|
||||||
|
Select("id").
|
||||||
|
Where(keyColumn+" = ?", dup.Key).
|
||||||
|
Order("peer_status_last_seen DESC").
|
||||||
|
Pluck("id", &peerIDs).Error; err != nil {
|
||||||
|
return fmt.Errorf("get peers for key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(peerIDs) <= 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
idsToDelete := peerIDs[1:]
|
||||||
|
|
||||||
|
if err := db.Table("peers").Where("id IN ?", idsToDelete).Delete(nil).Error; err != nil {
|
||||||
|
return fmt.Errorf("delete duplicate peers: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// CleanupOrphanedIDs removes non-existent IDs from the JSON array column.
|
// CleanupOrphanedIDs removes non-existent IDs from the JSON array column.
|
||||||
// T is the type of the model that contains the list.
|
// T is the type of the model that contains the list.
|
||||||
// This migration cleans up the lists field by removing IDs that no longer exist in the target table.
|
// This migration cleans up the lists field by removing IDs that no longer exist in the target table.
|
||||||
|
|||||||
@@ -340,3 +340,104 @@ func TestCreateIndexIfExists(t *testing.T) {
|
|||||||
exist = db.Migrator().HasIndex(&nbpeer.Peer{}, indexName)
|
exist = db.Migrator().HasIndex(&nbpeer.Peer{}, indexName)
|
||||||
assert.True(t, exist, "Should have the index")
|
assert.True(t, exist, "Should have the index")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type testPeer struct {
|
||||||
|
ID string `gorm:"primaryKey"`
|
||||||
|
Key string `gorm:"index"`
|
||||||
|
PeerStatusLastSeen time.Time
|
||||||
|
PeerStatusConnected bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (testPeer) TableName() string {
|
||||||
|
return "peers"
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupPeerTestDB(t *testing.T) *gorm.DB {
|
||||||
|
t.Helper()
|
||||||
|
db := setupDatabase(t)
|
||||||
|
_ = db.Migrator().DropTable(&testPeer{})
|
||||||
|
err := db.AutoMigrate(&testPeer{})
|
||||||
|
require.NoError(t, err, "Failed to auto-migrate tables")
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveDuplicatePeerKeys_NoDuplicates(t *testing.T) {
|
||||||
|
db := setupPeerTestDB(t)
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
peers := []testPeer{
|
||||||
|
{ID: "peer1", Key: "key1", PeerStatusLastSeen: now},
|
||||||
|
{ID: "peer2", Key: "key2", PeerStatusLastSeen: now},
|
||||||
|
{ID: "peer3", Key: "key3", PeerStatusLastSeen: now},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range peers {
|
||||||
|
err := db.Create(&p).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := migration.RemoveDuplicatePeerKeys(context.Background(), db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
db.Model(&testPeer{}).Count(&count)
|
||||||
|
assert.Equal(t, int64(len(peers)), count, "All peers should remain when no duplicates")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveDuplicatePeerKeys_WithDuplicates(t *testing.T) {
|
||||||
|
db := setupPeerTestDB(t)
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
peers := []testPeer{
|
||||||
|
{ID: "peer1", Key: "key1", PeerStatusLastSeen: now.Add(-2 * time.Hour)},
|
||||||
|
{ID: "peer2", Key: "key1", PeerStatusLastSeen: now.Add(-1 * time.Hour)},
|
||||||
|
{ID: "peer3", Key: "key1", PeerStatusLastSeen: now},
|
||||||
|
{ID: "peer4", Key: "key2", PeerStatusLastSeen: now},
|
||||||
|
{ID: "peer5", Key: "key3", PeerStatusLastSeen: now.Add(-1 * time.Hour)},
|
||||||
|
{ID: "peer6", Key: "key3", PeerStatusLastSeen: now},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range peers {
|
||||||
|
err := db.Create(&p).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := migration.RemoveDuplicatePeerKeys(context.Background(), db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
db.Model(&testPeer{}).Count(&count)
|
||||||
|
assert.Equal(t, int64(3), count, "Should have 3 peers after removing duplicates")
|
||||||
|
|
||||||
|
var remainingPeers []testPeer
|
||||||
|
err = db.Find(&remainingPeers).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
remainingIDs := make(map[string]bool)
|
||||||
|
for _, p := range remainingPeers {
|
||||||
|
remainingIDs[p.ID] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.True(t, remainingIDs["peer3"], "peer3 should remain (most recent for key1)")
|
||||||
|
assert.True(t, remainingIDs["peer4"], "peer4 should remain (only peer for key2)")
|
||||||
|
assert.True(t, remainingIDs["peer6"], "peer6 should remain (most recent for key3)")
|
||||||
|
|
||||||
|
assert.False(t, remainingIDs["peer1"], "peer1 should be deleted (older duplicate)")
|
||||||
|
assert.False(t, remainingIDs["peer2"], "peer2 should be deleted (older duplicate)")
|
||||||
|
assert.False(t, remainingIDs["peer5"], "peer5 should be deleted (older duplicate)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveDuplicatePeerKeys_EmptyTable(t *testing.T) {
|
||||||
|
db := setupPeerTestDB(t)
|
||||||
|
|
||||||
|
err := migration.RemoveDuplicatePeerKeys(context.Background(), db)
|
||||||
|
require.NoError(t, err, "Should not fail on empty table")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveDuplicatePeerKeys_NoTable(t *testing.T) {
|
||||||
|
db := setupDatabase(t)
|
||||||
|
_ = db.Migrator().DropTable(&testPeer{})
|
||||||
|
|
||||||
|
err := migration.RemoveDuplicatePeerKeys(context.Background(), db)
|
||||||
|
require.NoError(t, err, "Should not fail when table does not exist")
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
|
|
||||||
const domainPattern = `^(?i)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*[*.a-z]{1,}$`
|
const domainPattern = `^(?i)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*[*.a-z]{1,}$`
|
||||||
|
|
||||||
var invalidDomainName = errors.New("invalid domain name")
|
var errInvalidDomainName = errors.New("invalid domain name")
|
||||||
|
|
||||||
// GetNameServerGroup gets a nameserver group object from account and nameserver group IDs
|
// GetNameServerGroup gets a nameserver group object from account and nameserver group IDs
|
||||||
func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) {
|
func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) {
|
||||||
@@ -314,7 +314,7 @@ func validateDomain(domain string) error {
|
|||||||
|
|
||||||
_, valid := dns.IsDomainName(domain)
|
_, valid := dns.IsDomainName(domain)
|
||||||
if !valid {
|
if !valid {
|
||||||
return invalidDomainName
|
return errInvalidDomainName
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type Peer struct {
|
|||||||
// AccountID is a reference to Account that this object belongs
|
// AccountID is a reference to Account that this object belongs
|
||||||
AccountID string `json:"-" gorm:"index"`
|
AccountID string `json:"-" gorm:"index"`
|
||||||
// WireGuard public key
|
// WireGuard public key
|
||||||
Key string `gorm:"index"`
|
Key string // uniqueness index (check migrations)
|
||||||
// IP address of the Peer
|
// IP address of the Peer
|
||||||
IP net.IP `gorm:"serializer:json"` // uniqueness index per accountID (check migrations)
|
IP net.IP `gorm:"serializer:json"` // uniqueness index per accountID (check migrations)
|
||||||
// Meta is a Peer system meta data
|
// Meta is a Peer system meta data
|
||||||
|
|||||||
@@ -2129,12 +2129,14 @@ func Test_DeletePeer(t *testing.T) {
|
|||||||
"peer1": {
|
"peer1": {
|
||||||
ID: "peer1",
|
ID: "peer1",
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
|
Key: "key1",
|
||||||
IP: net.IP{1, 1, 1, 1},
|
IP: net.IP{1, 1, 1, 1},
|
||||||
DNSLabel: "peer1.test",
|
DNSLabel: "peer1.test",
|
||||||
},
|
},
|
||||||
"peer2": {
|
"peer2": {
|
||||||
ID: "peer2",
|
ID: "peer2",
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
|
Key: "key2",
|
||||||
IP: net.IP{2, 2, 2, 2},
|
IP: net.IP{2, 2, 2, 2},
|
||||||
DNSLabel: "peer2.test",
|
DNSLabel: "peer2.test",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ func arePostureCheckChangesAffectPeers(ctx context.Context, transaction store.St
|
|||||||
// validatePostureChecks validates the posture checks.
|
// validatePostureChecks validates the posture checks.
|
||||||
func validatePostureChecks(ctx context.Context, transaction store.Store, accountID string, postureChecks *posture.Checks) error {
|
func validatePostureChecks(ctx context.Context, transaction store.Store, accountID string, postureChecks *posture.Checks) error {
|
||||||
if err := postureChecks.Validate(); err != nil {
|
if err := postureChecks.Validate(); err != nil {
|
||||||
return status.Errorf(status.InvalidArgument, "%s", err.Error()) //nolint
|
return status.Errorf(status.InvalidArgument, "%v", err.Error()) //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the posture check already has an ID, verify its existence in the store.
|
// If the posture check already has an ID, verify its existence in the store.
|
||||||
|
|||||||
@@ -997,9 +997,10 @@ func TestGetAccount_ComprehensiveFieldValidation(t *testing.T) {
|
|||||||
// Find posture checks by ID
|
// Find posture checks by ID
|
||||||
var pc1, pc2 *posture.Checks
|
var pc1, pc2 *posture.Checks
|
||||||
for _, pc := range retrievedAccount.PostureChecks {
|
for _, pc := range retrievedAccount.PostureChecks {
|
||||||
if pc.ID == postureCheckID1 {
|
switch pc.ID {
|
||||||
|
case postureCheckID1:
|
||||||
pc1 = pc
|
pc1 = pc
|
||||||
} else if pc.ID == postureCheckID2 {
|
case postureCheckID2:
|
||||||
pc2 = pc
|
pc2 = pc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
"github.com/netbirdio/netbird/management/server/util"
|
"github.com/netbirdio/netbird/management/server/util"
|
||||||
nbroute "github.com/netbirdio/netbird/route"
|
nbroute "github.com/netbirdio/netbird/route"
|
||||||
route2 "github.com/netbirdio/netbird/route"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/status"
|
"github.com/netbirdio/netbird/shared/management/status"
|
||||||
"github.com/netbirdio/netbird/util/crypt"
|
"github.com/netbirdio/netbird/util/crypt"
|
||||||
)
|
)
|
||||||
@@ -110,12 +109,12 @@ func runLargeTest(t *testing.T, store Store) {
|
|||||||
AccountID: account.Id,
|
AccountID: account.Id,
|
||||||
}
|
}
|
||||||
account.Users[user.Id] = user
|
account.Users[user.Id] = user
|
||||||
route := &route2.Route{
|
route := &nbroute.Route{
|
||||||
ID: route2.ID(fmt.Sprintf("network-id-%d", n)),
|
ID: nbroute.ID(fmt.Sprintf("network-id-%d", n)),
|
||||||
Description: "base route",
|
Description: "base route",
|
||||||
NetID: route2.NetID(fmt.Sprintf("network-id-%d", n)),
|
NetID: nbroute.NetID(fmt.Sprintf("network-id-%d", n)),
|
||||||
Network: netip.MustParsePrefix(netIP.String() + "/24"),
|
Network: netip.MustParsePrefix(netIP.String() + "/24"),
|
||||||
NetworkType: route2.IPv4Network,
|
NetworkType: nbroute.IPv4Network,
|
||||||
Metric: 9999,
|
Metric: 9999,
|
||||||
Masquerade: false,
|
Masquerade: false,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -689,7 +688,7 @@ func TestMigrate(t *testing.T) {
|
|||||||
require.NoError(t, err, "Failed to insert Gob data")
|
require.NoError(t, err, "Failed to insert Gob data")
|
||||||
|
|
||||||
type route struct {
|
type route struct {
|
||||||
route2.Route
|
nbroute.Route
|
||||||
Network netip.Prefix `gorm:"serializer:gob"`
|
Network netip.Prefix `gorm:"serializer:gob"`
|
||||||
PeerGroups []string `gorm:"serializer:gob"`
|
PeerGroups []string `gorm:"serializer:gob"`
|
||||||
}
|
}
|
||||||
@@ -698,7 +697,7 @@ func TestMigrate(t *testing.T) {
|
|||||||
rt := &route{
|
rt := &route{
|
||||||
Network: prefix,
|
Network: prefix,
|
||||||
PeerGroups: []string{"group1", "group2"},
|
PeerGroups: []string{"group1", "group2"},
|
||||||
Route: route2.Route{ID: "route1"},
|
Route: nbroute.Route{ID: "route1"},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = store.(*SqlStore).db.Save(rt).Error
|
err = store.(*SqlStore).db.Save(rt).Error
|
||||||
@@ -714,7 +713,7 @@ func TestMigrate(t *testing.T) {
|
|||||||
require.NoError(t, err, "Failed to delete Gob data")
|
require.NoError(t, err, "Failed to delete Gob data")
|
||||||
|
|
||||||
prefix = netip.MustParsePrefix("12.0.0.0/24")
|
prefix = netip.MustParsePrefix("12.0.0.0/24")
|
||||||
nRT := &route2.Route{
|
nRT := &nbroute.Route{
|
||||||
Network: prefix,
|
Network: prefix,
|
||||||
ID: "route2",
|
ID: "route2",
|
||||||
Peer: "peer-id",
|
Peer: "peer-id",
|
||||||
@@ -969,6 +968,7 @@ func TestSqlite_GetTakenIPs(t *testing.T) {
|
|||||||
peer1 := &nbpeer.Peer{
|
peer1 := &nbpeer.Peer{
|
||||||
ID: "peer1",
|
ID: "peer1",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key1",
|
||||||
DNSLabel: "peer1",
|
DNSLabel: "peer1",
|
||||||
IP: net.IP{1, 1, 1, 1},
|
IP: net.IP{1, 1, 1, 1},
|
||||||
}
|
}
|
||||||
@@ -983,6 +983,7 @@ func TestSqlite_GetTakenIPs(t *testing.T) {
|
|||||||
peer2 := &nbpeer.Peer{
|
peer2 := &nbpeer.Peer{
|
||||||
ID: "peer1second",
|
ID: "peer1second",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key2",
|
||||||
DNSLabel: "peer1-1",
|
DNSLabel: "peer1-1",
|
||||||
IP: net.IP{2, 2, 2, 2},
|
IP: net.IP{2, 2, 2, 2},
|
||||||
}
|
}
|
||||||
@@ -1010,6 +1011,7 @@ func TestSqlite_GetPeerLabelsInAccount(t *testing.T) {
|
|||||||
peer1 := &nbpeer.Peer{
|
peer1 := &nbpeer.Peer{
|
||||||
ID: "peer1",
|
ID: "peer1",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key1",
|
||||||
DNSLabel: "peer1",
|
DNSLabel: "peer1",
|
||||||
IP: net.IP{1, 1, 1, 1},
|
IP: net.IP{1, 1, 1, 1},
|
||||||
}
|
}
|
||||||
@@ -1023,6 +1025,7 @@ func TestSqlite_GetPeerLabelsInAccount(t *testing.T) {
|
|||||||
peer2 := &nbpeer.Peer{
|
peer2 := &nbpeer.Peer{
|
||||||
ID: "peer1second",
|
ID: "peer1second",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key2",
|
||||||
DNSLabel: "peer1-1",
|
DNSLabel: "peer1-1",
|
||||||
IP: net.IP{2, 2, 2, 2},
|
IP: net.IP{2, 2, 2, 2},
|
||||||
}
|
}
|
||||||
@@ -1049,6 +1052,7 @@ func Test_AddPeerWithSameDnsLabel(t *testing.T) {
|
|||||||
peer1 := &nbpeer.Peer{
|
peer1 := &nbpeer.Peer{
|
||||||
ID: "peer1",
|
ID: "peer1",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key1",
|
||||||
DNSLabel: "peer1.domain.test",
|
DNSLabel: "peer1.domain.test",
|
||||||
}
|
}
|
||||||
err = store.AddPeerToAccount(context.Background(), peer1)
|
err = store.AddPeerToAccount(context.Background(), peer1)
|
||||||
@@ -1057,6 +1061,7 @@ func Test_AddPeerWithSameDnsLabel(t *testing.T) {
|
|||||||
peer2 := &nbpeer.Peer{
|
peer2 := &nbpeer.Peer{
|
||||||
ID: "peer1second",
|
ID: "peer1second",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key2",
|
||||||
DNSLabel: "peer1.domain.test",
|
DNSLabel: "peer1.domain.test",
|
||||||
}
|
}
|
||||||
err = store.AddPeerToAccount(context.Background(), peer2)
|
err = store.AddPeerToAccount(context.Background(), peer2)
|
||||||
@@ -1074,6 +1079,7 @@ func Test_AddPeerWithSameIP(t *testing.T) {
|
|||||||
peer1 := &nbpeer.Peer{
|
peer1 := &nbpeer.Peer{
|
||||||
ID: "peer1",
|
ID: "peer1",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key1",
|
||||||
IP: net.IP{1, 1, 1, 1},
|
IP: net.IP{1, 1, 1, 1},
|
||||||
}
|
}
|
||||||
err = store.AddPeerToAccount(context.Background(), peer1)
|
err = store.AddPeerToAccount(context.Background(), peer1)
|
||||||
@@ -1082,6 +1088,7 @@ func Test_AddPeerWithSameIP(t *testing.T) {
|
|||||||
peer2 := &nbpeer.Peer{
|
peer2 := &nbpeer.Peer{
|
||||||
ID: "peer1second",
|
ID: "peer1second",
|
||||||
AccountID: existingAccountID,
|
AccountID: existingAccountID,
|
||||||
|
Key: "key2",
|
||||||
IP: net.IP{1, 1, 1, 1},
|
IP: net.IP{1, 1, 1, 1},
|
||||||
}
|
}
|
||||||
err = store.AddPeerToAccount(context.Background(), peer2)
|
err = store.AddPeerToAccount(context.Background(), peer2)
|
||||||
@@ -3547,13 +3554,13 @@ func TestSqlStore_SaveRoute(t *testing.T) {
|
|||||||
|
|
||||||
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
accountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
|
|
||||||
route := &route2.Route{
|
route := &nbroute.Route{
|
||||||
ID: "route-id",
|
ID: "route-id",
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
Network: netip.MustParsePrefix("10.10.0.0/16"),
|
Network: netip.MustParsePrefix("10.10.0.0/16"),
|
||||||
NetID: "netID",
|
NetID: "netID",
|
||||||
PeerGroups: []string{"routeA"},
|
PeerGroups: []string{"routeA"},
|
||||||
NetworkType: route2.IPv4Network,
|
NetworkType: nbroute.IPv4Network,
|
||||||
Masquerade: true,
|
Masquerade: true,
|
||||||
Metric: 9999,
|
Metric: 9999,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -3700,6 +3707,7 @@ func BenchmarkGetAccountPeers(b *testing.B) {
|
|||||||
peer := &nbpeer.Peer{
|
peer := &nbpeer.Peer{
|
||||||
ID: fmt.Sprintf("peer-%d", i),
|
ID: fmt.Sprintf("peer-%d", i),
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
|
Key: fmt.Sprintf("key-%d", i),
|
||||||
DNSLabel: fmt.Sprintf("peer%d.example.com", i),
|
DNSLabel: fmt.Sprintf("peer%d.example.com", i),
|
||||||
IP: intToIPv4(uint32(i)),
|
IP: intToIPv4(uint32(i)),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,11 +352,16 @@ func getMigrationsPreAuto(ctx context.Context) []migrationFunc {
|
|||||||
func(db *gorm.DB) error {
|
func(db *gorm.DB) error {
|
||||||
return migration.MigrateNewField[types.User](ctx, db, "email", "")
|
return migration.MigrateNewField[types.User](ctx, db, "email", "")
|
||||||
},
|
},
|
||||||
|
func(db *gorm.DB) error {
|
||||||
|
return migration.RemoveDuplicatePeerKeys(ctx, db)
|
||||||
|
},
|
||||||
func(db *gorm.DB) error {
|
func(db *gorm.DB) error {
|
||||||
return migration.CleanupOrphanedIDs[types.User, types.Group](ctx, db, "auto_groups")
|
return migration.CleanupOrphanedIDs[types.User, types.Group](ctx, db, "auto_groups")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} // migratePostAuto migrates the SQLite database to the latest schema
|
}
|
||||||
|
|
||||||
|
// migratePostAuto migrates the SQLite database to the latest schema
|
||||||
func migratePostAuto(ctx context.Context, db *gorm.DB) error {
|
func migratePostAuto(ctx context.Context, db *gorm.DB) error {
|
||||||
migrations := getMigrationsPostAuto(ctx)
|
migrations := getMigrationsPostAuto(ctx)
|
||||||
|
|
||||||
@@ -386,6 +391,12 @@ func getMigrationsPostAuto(ctx context.Context) []migrationFunc {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
func(db *gorm.DB) error {
|
||||||
|
return migration.DropIndex[nbpeer.Peer](ctx, db, "idx_peers_key")
|
||||||
|
},
|
||||||
|
func(db *gorm.DB) error {
|
||||||
|
return migration.CreateIndexIfNotExists[nbpeer.Peer](ctx, db, "idx_peers_key_unique", "key")
|
||||||
|
},
|
||||||
func(db *gorm.DB) error {
|
func(db *gorm.DB) error {
|
||||||
return migration.MigrateJsonToTable[types.User](ctx, db, "auto_groups", func(accountID, id, value string) any {
|
return migration.MigrateJsonToTable[types.User](ctx, db, "auto_groups", func(accountID, id, value string) any {
|
||||||
return &types.GroupUser{
|
return &types.GroupUser{
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ CREATE TABLE `posture_checks` (`id` text,`name` text,`description` text,`account
|
|||||||
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
||||||
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
||||||
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
||||||
CREATE INDEX `idx_peers_key` ON `peers`(`key`);
|
CREATE UNIQUE INDEX `idx_peers_key_unique` ON `peers`(`key`);
|
||||||
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
||||||
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
||||||
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
||||||
|
|||||||
Vendored
+2
-2
@@ -18,7 +18,7 @@ CREATE TABLE `network_resources` (`id` text,`network_id` text,`account_id` text,
|
|||||||
CREATE TABLE `networks` (`id` text,`account_id` text,`name` text,`description` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_networks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
CREATE TABLE `networks` (`id` text,`account_id` text,`name` text,`description` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_networks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
||||||
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
||||||
CREATE INDEX `idx_peers_key` ON `peers`(`key`);
|
CREATE UNIQUE INDEX `idx_peers_key_unique` ON `peers`(`key`);
|
||||||
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
||||||
CREATE INDEX `idx_peers_account_id_ip` ON `peers`(`account_id`,`ip`);
|
CREATE INDEX `idx_peers_account_id_ip` ON `peers`(`account_id`,`ip`);
|
||||||
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
||||||
@@ -54,4 +54,4 @@ INSERT INTO policy_rules VALUES('cs387mkv2d4bgq41b6n0','cs1tnh0hhcjnqoiuebf0','D
|
|||||||
INSERT INTO network_routers VALUES('ctc20ji7qv9ck2sebc80','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','cs1tnh0hhcjnqoiuebeg',NULL,0,0);
|
INSERT INTO network_routers VALUES('ctc20ji7qv9ck2sebc80','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','cs1tnh0hhcjnqoiuebeg',NULL,0,0);
|
||||||
INSERT INTO network_resources VALUES ('ctc4nci7qv9061u6ilfg','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Host','192.168.1.1');
|
INSERT INTO network_resources VALUES ('ctc4nci7qv9061u6ilfg','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Host','192.168.1.1');
|
||||||
INSERT INTO networks VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Test Network','Test Network');
|
INSERT INTO networks VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Test Network','Test Network');
|
||||||
INSERT INTO peers VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','','','"192.168.0.0"','','','','','','','','','','','','','','','','','test','test','2023-01-01 00:00:00+00:00',0,0,0,'a23efe53-63fb-11ec-90d6-0242ac120003','',0,0,'2023-01-01 00:00:00+00:00','2023-01-01 00:00:00+00:00',0,'','','',0);
|
INSERT INTO peers VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','6kjbmVq1hmucVzvBXo5OucY5OYv+jSsB1jUTLq291Do=','','"192.168.0.0"','','','','','','','','','','','','','','','','','test','test','2023-01-01 00:00:00+00:00',0,0,0,'a23efe53-63fb-11ec-90d6-0242ac120003','',0,0,'2023-01-01 00:00:00+00:00','2023-01-01 00:00:00+00:00',0,'','','',0);
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ CREATE TABLE `posture_checks` (`id` text,`name` text,`description` text,`account
|
|||||||
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
||||||
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
||||||
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
||||||
CREATE INDEX `idx_peers_key` ON `peers`(`key`);
|
CREATE UNIQUE INDEX `idx_peers_key_unique` ON `peers`(`key`);
|
||||||
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
||||||
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
||||||
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
||||||
|
|||||||
+2
-2
@@ -14,7 +14,7 @@ CREATE TABLE `posture_checks` (`id` text,`name` text,`description` text,`account
|
|||||||
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
||||||
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
||||||
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
||||||
CREATE INDEX `idx_peers_key` ON `peers`(`key`);
|
CREATE UNIQUE INDEX `idx_peers_key_unique` ON `peers`(`key`);
|
||||||
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
||||||
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
||||||
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
||||||
@@ -30,7 +30,7 @@ INSERT INTO setup_keys VALUES('','bf1c8084-ba50-4ce7-9439-34653001fc3b','A2C8E62
|
|||||||
INSERT INTO peers VALUES('cfvprsrlo1hqoo49ohog','bf1c8084-ba50-4ce7-9439-34653001fc3b','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,0,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
INSERT INTO peers VALUES('cfvprsrlo1hqoo49ohog','bf1c8084-ba50-4ce7-9439-34653001fc3b','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,0,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
INSERT INTO peers VALUES('cg05lnblo1hkg2j514p0','bf1c8084-ba50-4ce7-9439-34653001fc3b','RlSy2vzoG2HyMBTUImXOiVhCBiiBa5qD5xzMxkiFDW4=','','"100.64.39.54"','expiredhost','linux','Linux','22.04','x86_64','Ubuntu','','development','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'expiredhost','expiredhost','2023-03-02 09:19:57.276717255+01:00',0,1,0,'edafee4e-63fb-11ec-90d6-0242ac120003','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMbK5ZXJsGOOWoBT4OmkPtgdPZe2Q7bDuS/zjn2CZxhK',0,1,0,'2023-03-02 09:14:21.791679181+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
INSERT INTO peers VALUES('cg05lnblo1hkg2j514p0','bf1c8084-ba50-4ce7-9439-34653001fc3b','RlSy2vzoG2HyMBTUImXOiVhCBiiBa5qD5xzMxkiFDW4=','','"100.64.39.54"','expiredhost','linux','Linux','22.04','x86_64','Ubuntu','','development','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'expiredhost','expiredhost','2023-03-02 09:19:57.276717255+01:00',0,1,0,'edafee4e-63fb-11ec-90d6-0242ac120003','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMbK5ZXJsGOOWoBT4OmkPtgdPZe2Q7bDuS/zjn2CZxhK',0,1,0,'2023-03-02 09:14:21.791679181+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
INSERT INTO peers VALUES('cg3161rlo1hs9cq94gdg','bf1c8084-ba50-4ce7-9439-34653001fc3b','mVABSKj28gv+JRsf7e0NEGKgSOGTfU/nPB2cpuG56HU=','','"100.64.117.96"','testhost','linux','Linux','22.04','x86_64','Ubuntu','','development','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'testhost','testhost','2023-03-06 18:21:27.252010027+01:00',0,0,0,'edafee4e-63fb-11ec-90d6-0242ac120003','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINWvvUkFFcrj48CWTkNUb/do/n52i1L5dH4DhGu+4ZuM',0,0,0,'2023-03-07 09:02:47.442857106+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
INSERT INTO peers VALUES('cg3161rlo1hs9cq94gdg','bf1c8084-ba50-4ce7-9439-34653001fc3b','mVABSKj28gv+JRsf7e0NEGKgSOGTfU/nPB2cpuG56HU=','','"100.64.117.96"','testhost','linux','Linux','22.04','x86_64','Ubuntu','','development','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'testhost','testhost','2023-03-06 18:21:27.252010027+01:00',0,0,0,'edafee4e-63fb-11ec-90d6-0242ac120003','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINWvvUkFFcrj48CWTkNUb/do/n52i1L5dH4DhGu+4ZuM',0,0,0,'2023-03-07 09:02:47.442857106+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
INSERT INTO peers VALUES('csrnkiq7qv9d8aitqd50','bf1c8084-ba50-4ce7-9439-34653001fc3b','mVABSKj28gv+JRsf7e0NEGKgSOGTfU/nPB2cpuG56HU=','','"100.64.117.97"','testhost','linux','Linux','22.04','x86_64','Ubuntu','','development','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'testhost','testhost-1','2023-03-06 18:21:27.252010027+01:00',0,0,0,'f4f6d672-63fb-11ec-90d6-0242ac120003','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINWvvUkFFcrj48CWTkNUb/do/n52i1L5dH4DhGu+4ZuM',0,0,1,'2023-03-07 09:02:47.442857106+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
INSERT INTO peers VALUES('csrnkiq7qv9d8aitqd50','bf1c8084-ba50-4ce7-9439-34653001fc3b','nVABSKj28gv+JRsf7e0NEGKgSOGTfU/nPB2cpuG56HX=','','"100.64.117.97"','testhost','linux','Linux','22.04','x86_64','Ubuntu','','development','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'testhost','testhost-1','2023-03-06 18:21:27.252010027+01:00',0,0,0,'f4f6d672-63fb-11ec-90d6-0242ac120003','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINWvvUkFFcrj48CWTkNUb/do/n52i1L5dH4DhGu+4ZuM',0,0,1,'2023-03-07 09:02:47.442857106+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
INSERT INTO users VALUES('f4f6d672-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','user',0,0,'','[]',0,NULL,'2024-10-02 17:00:32.528196+02:00','api',0,'');
|
INSERT INTO users VALUES('f4f6d672-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','user',0,0,'','[]',0,NULL,'2024-10-02 17:00:32.528196+02:00','api',0,'');
|
||||||
INSERT INTO users VALUES('edafee4e-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','admin',0,0,'','[]',0,NULL,'2024-10-02 17:00:32.528196+02:00','api',0,'');
|
INSERT INTO users VALUES('edafee4e-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','admin',0,0,'','[]',0,NULL,'2024-10-02 17:00:32.528196+02:00','api',0,'');
|
||||||
INSERT INTO installations VALUES(1,'');
|
INSERT INTO installations VALUES(1,'');
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ CREATE TABLE `posture_checks` (`id` text,`name` text,`description` text,`account
|
|||||||
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
CREATE TABLE `network_addresses` (`net_ip` text,`mac` text);
|
||||||
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
||||||
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
||||||
CREATE INDEX `idx_peers_key` ON `peers`(`key`);
|
CREATE UNIQUE INDEX `idx_peers_key_unique` ON `peers`(`key`);
|
||||||
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
||||||
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
||||||
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !ios
|
//go:build !ios
|
||||||
// +build !ios
|
|
||||||
|
|
||||||
package testutil
|
package testutil
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build ios
|
//go:build ios
|
||||||
// +build ios
|
|
||||||
|
|
||||||
package testutil
|
package testutil
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build pprof
|
//go:build pprof
|
||||||
// +build pprof
|
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
session quic.Connection
|
session *quic.Conn
|
||||||
closed bool
|
closed bool
|
||||||
closedMu sync.Mutex
|
closedMu sync.Mutex
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConn(session quic.Connection) *Conn {
|
func NewConn(session *quic.Conn) *Conn {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return &Conn{
|
return &Conn{
|
||||||
session: session,
|
session: session,
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func (c *Conn) Close() error {
|
|||||||
c.closedMu.Lock()
|
c.closedMu.Lock()
|
||||||
c.closed = true
|
c.closed = true
|
||||||
c.closedMu.Unlock()
|
c.closedMu.Unlock()
|
||||||
return c.Conn.CloseNow()
|
return c.CloseNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) isClosed() bool {
|
func (c *Conn) isClosed() bool {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Re
|
|||||||
func parseResponse[T any](resp *http.Response) (T, error) {
|
func parseResponse[T any](resp *http.Response) (T, error) {
|
||||||
var ret T
|
var ret T
|
||||||
if resp.Body == nil {
|
if resp.Body == nil {
|
||||||
return ret, fmt.Errorf("Body missing, HTTP Error code %d", resp.StatusCode)
|
return ret, fmt.Errorf("body missing, HTTP Error code %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
bs, err := io.ReadAll(resp.Body)
|
bs, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -169,7 +169,7 @@ func parseResponse[T any](resp *http.Response) (T, error) {
|
|||||||
}
|
}
|
||||||
err = json.Unmarshal(bs, &ret)
|
err = json.Unmarshal(bs, &ret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, fmt.Errorf("Error code %d, error unmarshalling body: %w", resp.StatusCode, err)
|
return ret, fmt.Errorf("error code %d, error unmarshalling body: %w", resp.StatusCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build integration
|
//go:build integration
|
||||||
// +build integration
|
|
||||||
|
|
||||||
package rest_test
|
package rest_test
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
hmacTokenStore = &hmac.TokenStore{}
|
hmacTokenStore = &hmac.TokenStore{}
|
||||||
serverListenAddr = "127.0.0.1:1234"
|
|
||||||
serverURL = "rel://127.0.0.1:1234"
|
|
||||||
serverCfg = server.Config{
|
|
||||||
Meter: otel.Meter(""),
|
|
||||||
ExposedAddress: serverURL,
|
|
||||||
TLSSupport: false,
|
|
||||||
AuthValidator: &allow.Auth{},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
@@ -36,8 +28,20 @@ func TestMain(m *testing.M) {
|
|||||||
os.Exit(code)
|
os.Exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newClientTestServerConfig creates a new server config for client testing with the given address
|
||||||
|
func newClientTestServerConfig(address string) server.Config {
|
||||||
|
return server.Config{
|
||||||
|
Meter: otel.Meter(""),
|
||||||
|
ExposedAddress: "rel://" + address,
|
||||||
|
TLSSupport: false,
|
||||||
|
AuthValidator: &allow.Auth{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestClient(t *testing.T) {
|
func TestClient(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50001"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,7 +68,7 @@ func TestClient(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
t.Log("alice connecting to server")
|
t.Log("alice connecting to server")
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -72,7 +76,7 @@ func TestClient(t *testing.T) {
|
|||||||
defer clientAlice.Close()
|
defer clientAlice.Close()
|
||||||
|
|
||||||
t.Log("placeholder connecting to server")
|
t.Log("placeholder connecting to server")
|
||||||
clientPlaceHolder := NewClient(serverURL, hmacTokenStore, "clientPlaceHolder", iface.DefaultMTU)
|
clientPlaceHolder := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "clientPlaceHolder", iface.DefaultMTU)
|
||||||
err = clientPlaceHolder.Connect(ctx)
|
err = clientPlaceHolder.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -80,7 +84,7 @@ func TestClient(t *testing.T) {
|
|||||||
defer clientPlaceHolder.Close()
|
defer clientPlaceHolder.Close()
|
||||||
|
|
||||||
t.Log("Bob connecting to server")
|
t.Log("Bob connecting to server")
|
||||||
clientBob := NewClient(serverURL, hmacTokenStore, "bob", iface.DefaultMTU)
|
clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU)
|
||||||
err = clientBob.Connect(ctx)
|
err = clientBob.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -120,6 +124,8 @@ func TestClient(t *testing.T) {
|
|||||||
|
|
||||||
func TestRegistration(t *testing.T) {
|
func TestRegistration(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50101"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -138,7 +144,7 @@ func TestRegistration(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = srv.Shutdown(ctx)
|
_ = srv.Shutdown(ctx)
|
||||||
@@ -157,7 +163,7 @@ func TestRegistration(t *testing.T) {
|
|||||||
func TestRegistrationTimeout(t *testing.T) {
|
func TestRegistrationTimeout(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
fakeUDPListener, err := net.ListenUDP("udp", &net.UDPAddr{
|
fakeUDPListener, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
Port: 1234,
|
Port: 50201,
|
||||||
IP: net.ParseIP("0.0.0.0"),
|
IP: net.ParseIP("0.0.0.0"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -168,7 +174,7 @@ func TestRegistrationTimeout(t *testing.T) {
|
|||||||
}(fakeUDPListener)
|
}(fakeUDPListener)
|
||||||
|
|
||||||
fakeTCPListener, err := net.ListenTCP("tcp", &net.TCPAddr{
|
fakeTCPListener, err := net.ListenTCP("tcp", &net.TCPAddr{
|
||||||
Port: 1234,
|
Port: 50201,
|
||||||
IP: net.ParseIP("0.0.0.0"),
|
IP: net.ParseIP("0.0.0.0"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -178,7 +184,7 @@ func TestRegistrationTimeout(t *testing.T) {
|
|||||||
_ = fakeTCPListener.Close()
|
_ = fakeTCPListener.Close()
|
||||||
}(fakeTCPListener)
|
}(fakeTCPListener)
|
||||||
|
|
||||||
clientAlice := NewClient("127.0.0.1:1234", hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient("127.0.0.1:50201", hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("failed to connect to server: %s", err)
|
t.Errorf("failed to connect to server: %s", err)
|
||||||
@@ -192,6 +198,8 @@ func TestRegistrationTimeout(t *testing.T) {
|
|||||||
|
|
||||||
func TestEcho(t *testing.T) {
|
func TestEcho(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50301"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
idAlice := "alice"
|
idAlice := "alice"
|
||||||
idBob := "bob"
|
idBob := "bob"
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
@@ -219,7 +227,7 @@ func TestEcho(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, idAlice, iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -231,7 +239,7 @@ func TestEcho(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
clientBob := NewClient(serverURL, hmacTokenStore, idBob, iface.DefaultMTU)
|
clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idBob, iface.DefaultMTU)
|
||||||
err = clientBob.Connect(ctx)
|
err = clientBob.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -282,6 +290,8 @@ func TestEcho(t *testing.T) {
|
|||||||
|
|
||||||
func TestBindToUnavailabePeer(t *testing.T) {
|
func TestBindToUnavailabePeer(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50401"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
@@ -309,7 +319,7 @@ func TestBindToUnavailabePeer(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to connect to server: %s", err)
|
t.Errorf("failed to connect to server: %s", err)
|
||||||
@@ -328,6 +338,8 @@ func TestBindToUnavailabePeer(t *testing.T) {
|
|||||||
|
|
||||||
func TestBindReconnect(t *testing.T) {
|
func TestBindReconnect(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50501"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
@@ -355,13 +367,13 @@ func TestBindReconnect(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientBob := NewClient(serverURL, hmacTokenStore, "bob", iface.DefaultMTU)
|
clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU)
|
||||||
err = clientBob.Connect(ctx)
|
err = clientBob.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to connect to server: %s", err)
|
t.Errorf("failed to connect to server: %s", err)
|
||||||
@@ -383,7 +395,7 @@ func TestBindReconnect(t *testing.T) {
|
|||||||
t.Errorf("failed to close client: %s", err)
|
t.Errorf("failed to close client: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice = NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice = NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to connect to server: %s", err)
|
t.Errorf("failed to connect to server: %s", err)
|
||||||
@@ -429,6 +441,8 @@ func TestBindReconnect(t *testing.T) {
|
|||||||
|
|
||||||
func TestCloseConn(t *testing.T) {
|
func TestCloseConn(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50601"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
@@ -456,13 +470,13 @@ func TestCloseConn(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bob := NewClient(serverURL, hmacTokenStore, "bob", iface.DefaultMTU)
|
bob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU)
|
||||||
err = bob.Connect(ctx)
|
err = bob.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to connect to server: %s", err)
|
t.Errorf("failed to connect to server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to connect to server: %s", err)
|
t.Errorf("failed to connect to server: %s", err)
|
||||||
@@ -492,6 +506,8 @@ func TestCloseConn(t *testing.T) {
|
|||||||
|
|
||||||
func TestCloseRelayConn(t *testing.T) {
|
func TestCloseRelayConn(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50701"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
@@ -518,13 +534,13 @@ func TestCloseRelayConn(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bob := NewClient(serverURL, hmacTokenStore, "bob", iface.DefaultMTU)
|
bob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "bob", iface.DefaultMTU)
|
||||||
err = bob.Connect(ctx)
|
err = bob.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, "alice", iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, "alice", iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -550,6 +566,8 @@ func TestCloseRelayConn(t *testing.T) {
|
|||||||
|
|
||||||
func TestCloseByServer(t *testing.T) {
|
func TestCloseByServer(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50801"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv1, err := server.NewServer(serverCfg)
|
srv1, err := server.NewServer(serverCfg)
|
||||||
@@ -572,7 +590,7 @@ func TestCloseByServer(t *testing.T) {
|
|||||||
|
|
||||||
idAlice := "alice"
|
idAlice := "alice"
|
||||||
log.Debugf("connect by alice")
|
log.Debugf("connect by alice")
|
||||||
relayClient := NewClient(serverURL, hmacTokenStore, idAlice, iface.DefaultMTU)
|
relayClient := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU)
|
||||||
if err = relayClient.Connect(ctx); err != nil {
|
if err = relayClient.Connect(ctx); err != nil {
|
||||||
log.Fatalf("failed to connect to server: %s", err)
|
log.Fatalf("failed to connect to server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -607,6 +625,8 @@ func TestCloseByServer(t *testing.T) {
|
|||||||
|
|
||||||
func TestCloseByClient(t *testing.T) {
|
func TestCloseByClient(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:50901"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(serverCfg)
|
||||||
@@ -628,7 +648,7 @@ func TestCloseByClient(t *testing.T) {
|
|||||||
|
|
||||||
idAlice := "alice"
|
idAlice := "alice"
|
||||||
log.Debugf("connect by alice")
|
log.Debugf("connect by alice")
|
||||||
relayClient := NewClient(serverURL, hmacTokenStore, idAlice, iface.DefaultMTU)
|
relayClient := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU)
|
||||||
err = relayClient.Connect(ctx)
|
err = relayClient.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to connect to server: %s", err)
|
log.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -652,6 +672,8 @@ func TestCloseByClient(t *testing.T) {
|
|||||||
|
|
||||||
func TestCloseNotDrainedChannel(t *testing.T) {
|
func TestCloseNotDrainedChannel(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
serverListenAddr := "127.0.0.1:51001"
|
||||||
|
serverCfg := newClientTestServerConfig(serverListenAddr)
|
||||||
idAlice := "alice"
|
idAlice := "alice"
|
||||||
idBob := "bob"
|
idBob := "bob"
|
||||||
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
srvCfg := server.ListenerConfig{Address: serverListenAddr}
|
||||||
@@ -679,7 +701,7 @@ func TestCloseNotDrainedChannel(t *testing.T) {
|
|||||||
t.Fatalf("failed to start server: %s", err)
|
t.Fatalf("failed to start server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAlice := NewClient(serverURL, hmacTokenStore, idAlice, iface.DefaultMTU)
|
clientAlice := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idAlice, iface.DefaultMTU)
|
||||||
err = clientAlice.Connect(ctx)
|
err = clientAlice.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
@@ -691,7 +713,7 @@ func TestCloseNotDrainedChannel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
clientBob := NewClient(serverURL, hmacTokenStore, idBob, iface.DefaultMTU)
|
clientBob := NewClient(serverCfg.ExposedAddress, hmacTokenStore, idBob, iface.DefaultMTU)
|
||||||
err = clientBob.Connect(ctx)
|
err = clientBob.Connect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to connect to server: %s", err)
|
t.Fatalf("failed to connect to server: %s", err)
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ func (a Addr) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
session quic.Connection
|
session *quic.Conn
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConn(session quic.Connection) net.Conn {
|
func NewConn(session *quic.Conn) net.Conn {
|
||||||
return &Conn{
|
return &Conn{
|
||||||
session: session,
|
session: session,
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ import (
|
|||||||
"github.com/netbirdio/netbird/shared/relay/auth/allow"
|
"github.com/netbirdio/netbird/shared/relay/auth/allow"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// newManagerTestServerConfig creates a new server config for manager testing with the given address
|
||||||
|
func newManagerTestServerConfig(address string) server.Config {
|
||||||
|
return server.Config{
|
||||||
|
Meter: otel.Meter(""),
|
||||||
|
ExposedAddress: address,
|
||||||
|
TLSSupport: false,
|
||||||
|
AuthValidator: &allow.Auth{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEmptyURL(t *testing.T) {
|
func TestEmptyURL(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -27,15 +37,10 @@ func TestForeignConn(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
lstCfg1 := server.ListenerConfig{
|
lstCfg1 := server.ListenerConfig{
|
||||||
Address: "localhost:1234",
|
Address: "localhost:52101",
|
||||||
}
|
}
|
||||||
|
|
||||||
srv1, err := server.NewServer(server.Config{
|
srv1, err := server.NewServer(newManagerTestServerConfig(lstCfg1.Address))
|
||||||
Meter: otel.Meter(""),
|
|
||||||
ExposedAddress: lstCfg1.Address,
|
|
||||||
TLSSupport: false,
|
|
||||||
AuthValidator: &allow.Auth{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -59,14 +64,9 @@ func TestForeignConn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srvCfg2 := server.ListenerConfig{
|
srvCfg2 := server.ListenerConfig{
|
||||||
Address: "localhost:2234",
|
Address: "localhost:52102",
|
||||||
}
|
}
|
||||||
srv2, err := server.NewServer(server.Config{
|
srv2, err := server.NewServer(newManagerTestServerConfig(srvCfg2.Address))
|
||||||
Meter: otel.Meter(""),
|
|
||||||
ExposedAddress: srvCfg2.Address,
|
|
||||||
TLSSupport: false,
|
|
||||||
AuthValidator: &allow.Auth{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -144,9 +144,9 @@ func TestForeginConnClose(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
srvCfg1 := server.ListenerConfig{
|
srvCfg1 := server.ListenerConfig{
|
||||||
Address: "localhost:1234",
|
Address: "localhost:52201",
|
||||||
}
|
}
|
||||||
srv1, err := server.NewServer(serverCfg)
|
srv1, err := server.NewServer(newManagerTestServerConfig(srvCfg1.Address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -170,9 +170,9 @@ func TestForeginConnClose(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srvCfg2 := server.ListenerConfig{
|
srvCfg2 := server.ListenerConfig{
|
||||||
Address: "localhost:2234",
|
Address: "localhost:52202",
|
||||||
}
|
}
|
||||||
srv2, err := server.NewServer(serverCfg)
|
srv2, err := server.NewServer(newManagerTestServerConfig(srvCfg2.Address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -225,9 +225,9 @@ func TestForeignAutoClose(t *testing.T) {
|
|||||||
keepUnusedServerTime = 2 * time.Second
|
keepUnusedServerTime = 2 * time.Second
|
||||||
|
|
||||||
srvCfg1 := server.ListenerConfig{
|
srvCfg1 := server.ListenerConfig{
|
||||||
Address: "localhost:1234",
|
Address: "localhost:52301",
|
||||||
}
|
}
|
||||||
srv1, err := server.NewServer(serverCfg)
|
srv1, err := server.NewServer(newManagerTestServerConfig(srvCfg1.Address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -252,9 +252,9 @@ func TestForeignAutoClose(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srvCfg2 := server.ListenerConfig{
|
srvCfg2 := server.ListenerConfig{
|
||||||
Address: "localhost:2234",
|
Address: "localhost:52302",
|
||||||
}
|
}
|
||||||
srv2, err := server.NewServer(serverCfg)
|
srv2, err := server.NewServer(newManagerTestServerConfig(srvCfg2.Address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -327,9 +327,9 @@ func TestAutoReconnect(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
srvCfg := server.ListenerConfig{
|
srvCfg := server.ListenerConfig{
|
||||||
Address: "localhost:1234",
|
Address: "localhost:52401",
|
||||||
}
|
}
|
||||||
srv, err := server.NewServer(serverCfg)
|
srv, err := server.NewServer(newManagerTestServerConfig(srvCfg.Address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
@@ -397,14 +397,9 @@ func TestNotifierDoubleAdd(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
listenerCfg1 := server.ListenerConfig{
|
listenerCfg1 := server.ListenerConfig{
|
||||||
Address: "localhost:1234",
|
Address: "localhost:52501",
|
||||||
}
|
}
|
||||||
srv, err := server.NewServer(server.Config{
|
srv, err := server.NewServer(newManagerTestServerConfig(listenerCfg1.Address))
|
||||||
Meter: otel.Meter(""),
|
|
||||||
ExposedAddress: listenerCfg1.Address,
|
|
||||||
TLSSupport: false,
|
|
||||||
AuthValidator: &allow.Auth{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create server: %s", err)
|
t.Fatalf("failed to create server: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -73,7 +73,7 @@ var (
|
|||||||
// detect whether user specified a port
|
// detect whether user specified a port
|
||||||
userPort := cmd.Flag("port").Changed
|
userPort := cmd.Flag("port").Changed
|
||||||
|
|
||||||
tlsEnabled := false
|
var tlsEnabled bool
|
||||||
if signalLetsencryptDomain != "" || (signalCertFile != "" && signalCertKey != "") {
|
if signalLetsencryptDomain != "" || (signalCertFile != "" && signalCertKey != "") {
|
||||||
tlsEnabled = true
|
tlsEnabled = true
|
||||||
}
|
}
|
||||||
@@ -259,8 +259,8 @@ func grpcHandlerFunc(grpcServer *grpc.Server, meter metric.Meter) http.Handler {
|
|||||||
wsProxy := wsproxyserver.New(grpcServer, wsproxyserver.WithOTelMeter(meter))
|
wsProxy := wsproxyserver.New(grpcServer, wsproxyserver.WithOTelMeter(meter))
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch {
|
switch r.URL.Path {
|
||||||
case r.URL.Path == wsproxy.ProxyPath+wsproxy.SignalComponent:
|
case wsproxy.ProxyPath + wsproxy.SignalComponent:
|
||||||
wsProxy.Handler().ServeHTTP(w, r)
|
wsProxy.Handler().ServeHTTP(w, r)
|
||||||
default:
|
default:
|
||||||
grpcServer.ServeHTTP(w, r)
|
grpcServer.ServeHTTP(w, r)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user