Compare commits

..

3 Commits

Author SHA1 Message Date
Zoltan Papp
0c4c2a8cb2 Listen on all address 2023-12-13 22:39:12 +01:00
Zoltan Papp
9c6c944e46 Add socks5 proxy 2023-12-13 16:58:31 +01:00
Zoltan Papp
cec4232860 Netstack poc 2023-12-12 17:35:16 +01:00
155 changed files with 1864 additions and 4772 deletions

View File

@@ -1,4 +1,4 @@
FROM golang:1.21-bullseye
FROM golang:1.20-bullseye
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends\

View File

@@ -7,7 +7,7 @@
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/go:1": {
"version": "1.21"
"version": "1.20"
}
},
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",

View File

@@ -19,16 +19,9 @@ jobs:
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
go-version: "1.20.x"
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
cmdline-tools-version: 8512546
- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: "11"
distribution: "adopt"
uses: android-actions/setup-android@v2
- name: NDK Cache
id: ndk-cache
uses: actions/cache@v3
@@ -36,7 +29,7 @@ jobs:
path: /usr/local/lib/android/sdk/ndk
key: ndk-cache-23.1.7779620
- name: Setup NDK
run: /usr/local/lib/android/sdk/cmdline-tools/7.0/bin/sdkmanager --install "ndk;23.1.7779620"
run: /usr/local/lib/android/sdk/tools/bin/sdkmanager --install "ndk;23.1.7779620"
- name: install gomobile
run: go install golang.org/x/mobile/cmd/gomobile@v0.0.0-20230531173138-3c911d8e3eda
- name: gomobile init
@@ -45,4 +38,4 @@ jobs:
run: PATH=$PATH:$(go env GOPATH) gomobile bind -o $GITHUB_WORKSPACE/netbird.aar -javapkg=io.netbird.gomobile -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/io.netbird.client/cache/wireguard -X github.com/netbirdio/netbird/version.version=buildtest" $GITHUB_WORKSPACE/client/android
env:
CGO_ENABLED: 0
ANDROID_NDK_HOME: /usr/local/lib/android/sdk/ndk/23.1.7779620
ANDROID_NDK_HOME: /usr/local/lib/android/sdk/ndk/23.1.7779620

View File

@@ -20,7 +20,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
go-version: "1.20.x"
- name: Checkout code
uses: actions/checkout@v3

View File

@@ -21,7 +21,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
go-version: "1.20.x"
- name: Cache Go modules
@@ -50,7 +50,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
go-version: "1.20.x"
- name: Cache Go modules
uses: actions/cache@v3

View File

@@ -23,13 +23,13 @@ jobs:
uses: actions/setup-go@v4
id: go
with:
go-version: "1.21.x"
go-version: "1.20.x"
- name: Download wintun
uses: carlosperate/download-file-action@v2
id: download-wintun
with:
file-url: https://pkgs.netbird.io/wintun/wintun-0.14.1.zip
file-url: https://www.wintun.net/builds/wintun-0.14.1.zip
file-name: wintun.zip
location: ${{ env.downloadPath }}
sha256: '07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51'
@@ -49,4 +49,4 @@ jobs:
run: PsExec64 -s -w ${{ github.workspace }} cmd.exe /c "C:\hostedtoolcache\windows\go\${{ steps.go.outputs.go-version }}\x64\bin\go.exe test -timeout 5m -p 1 ./... > test-out.txt 2>&1"
- name: test output
if: ${{ always() }}
run: Get-Content test-out.txt
run: Get-Content test-out.txt

View File

@@ -1,7 +1,7 @@
name: golangci-lint
on: [pull_request]
permissions:
permissions:
contents: read
pull-requests: read
@@ -36,7 +36,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
go-version: "1.20.x"
cache: false
- name: Install dependencies
if: matrix.os == 'ubuntu-latest'

View File

@@ -20,7 +20,7 @@ on:
- 'client/ui/**'
env:
SIGN_PIPE_VER: "v0.0.11"
SIGN_PIPE_VER: "v0.0.10"
GORELEASER_VER: "v1.14.1"
concurrency:
@@ -44,18 +44,15 @@ jobs:
name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.21"
cache: false
go-version: "1.20"
-
name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-releaser-${{ hashFiles('**/go.sum') }}
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-releaser-
${{ runner.os }}-go-
-
name: Install modules
run: go mod tidy
@@ -120,17 +117,14 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.21"
cache: false
go-version: "1.20"
- name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-ui-go-releaser-${{ hashFiles('**/go.sum') }}
path: ~/go/pkg/mod
key: ${{ runner.os }}-ui-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-ui-go-releaser-
${{ runner.os }}-ui-go-
- name: Install modules
run: go mod tidy
@@ -175,18 +169,15 @@ jobs:
name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.21"
cache: false
go-version: "1.20"
-
name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-ui-go-releaser-darwin-${{ hashFiles('**/go.sum') }}
path: ~/go/pkg/mod
key: ${{ runner.os }}-ui-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-ui-go-releaser-darwin-
${{ runner.os }}-ui-go-
-
name: Install modules
run: go mod tidy

View File

@@ -28,7 +28,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v4
with:
go-version: "1.21.x"
go-version: "1.20.x"
- name: Cache Go modules
uses: actions/cache@v3
@@ -62,7 +62,7 @@ jobs:
CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH: false
- name: check values
working-directory: infrastructure_files/artifacts
working-directory: infrastructure_files
env:
CI_NETBIRD_DOMAIN: localhost
CI_NETBIRD_AUTH_CLIENT_ID: testing.client.id
@@ -87,10 +87,8 @@ jobs:
CI_NETBIRD_SIGNAL_PORT: 12345
CI_NETBIRD_STORE_CONFIG_ENGINE: "sqlite"
CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH: false
CI_NETBIRD_TURN_EXTERNAL_IP: "1.2.3.4"
run: |
set -x
grep AUTH_CLIENT_ID docker-compose.yml | grep $CI_NETBIRD_AUTH_CLIENT_ID
grep AUTH_CLIENT_SECRET docker-compose.yml | grep $CI_NETBIRD_AUTH_CLIENT_SECRET
grep AUTH_AUTHORITY docker-compose.yml | grep $CI_NETBIRD_AUTH_AUTHORITY
@@ -109,7 +107,7 @@ jobs:
grep Engine management.json | grep "$CI_NETBIRD_STORE_CONFIG_ENGINE"
grep IdpSignKeyRefreshEnabled management.json | grep "$CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH"
grep UseIDToken management.json | grep false
grep -A 1 IdpManagerConfig management.json | grep ManagerType | grep $CI_NETBIRD_MGMT_IDP
grep -A 1 IdpManagerConfig management.json | grep ManagerType | grep $CI_NETBIRD_MGMT_IDP
grep -A 3 IdpManagerConfig management.json | grep -A 1 ClientConfig | grep Issuer | grep $CI_NETBIRD_AUTH_AUTHORITY
grep -A 4 IdpManagerConfig management.json | grep -A 2 ClientConfig | grep TokenEndpoint | grep $CI_NETBIRD_AUTH_TOKEN_ENDPOINT
grep -A 5 IdpManagerConfig management.json | grep -A 3 ClientConfig | grep ClientID | grep $CI_NETBIRD_IDP_MGMT_CLIENT_ID
@@ -122,7 +120,6 @@ jobs:
grep -A 10 PKCEAuthorizationFlow management.json | grep -A 10 ProviderConfig | grep TokenEndpoint | grep $CI_NETBIRD_AUTH_TOKEN_ENDPOINT
grep -A 10 PKCEAuthorizationFlow management.json | grep -A 10 ProviderConfig | grep Scope | grep "$CI_NETBIRD_AUTH_SUPPORTED_SCOPES"
grep -A 10 PKCEAuthorizationFlow management.json | grep -A 10 ProviderConfig | grep -A 3 RedirectURLs | grep "http://localhost:53000"
grep "external-ip" turnserver.conf | grep $CI_NETBIRD_TURN_EXTERNAL_IP
- name: Install modules
run: go mod tidy
@@ -146,7 +143,7 @@ jobs:
docker build -t netbirdio/signal:latest .
- name: run docker compose up
working-directory: infrastructure_files/artifacts
working-directory: infrastructure_files
run: |
docker-compose up -d
sleep 5
@@ -155,9 +152,9 @@ jobs:
- name: test running containers
run: |
count=$(docker compose ps --format json | jq '. | select(.Name | contains("artifacts")) | .State' | grep -c running)
count=$(docker compose ps --format json | jq '. | select(.Name | contains("infrastructure_files")) | .State' | grep -c running)
test $count -eq 4
working-directory: infrastructure_files/artifacts
working-directory: infrastructure_files
test-getting-started-script:
runs-on: ubuntu-latest
@@ -178,11 +175,8 @@ jobs:
- name: test management.json file gen
run: test -f management.json
- name: test turnserver.conf file gen
run: |
set -x
test -f turnserver.conf
grep external-ip turnserver.conf
run: test -f turnserver.conf
- name: test zitadel.env file gen
run: test -f zitadel.env
- name: test dashboard.env file gen
run: test -f dashboard.env
run: test -f dashboard.env

19
.gitignore vendored
View File

@@ -6,20 +6,11 @@ bin/
.env
conf.json
http-cmds.sh
setup.env
infrastructure_files/**/Caddyfile
infrastructure_files/**/dashboard.env
infrastructure_files/**/zitadel.env
infrastructure_files/**/management.json
infrastructure_files/**/management-*.json
infrastructure_files/**/docker-compose.yml
infrastructure_files/**/openid-configuration.json
infrastructure_files/**/turnserver.conf
infrastructure_files/**/management.json.bkp.**
infrastructure_files/**/management-*.json.bkp.**
infrastructure_files/**/docker-compose.yml.bkp.**
infrastructure_files/**/openid-configuration.json.bkp.**
infrastructure_files/**/turnserver.conf.bkp.**
infrastructure_files/management.json
infrastructure_files/management-*.json
infrastructure_files/docker-compose.yml
infrastructure_files/openid-configuration.json
infrastructure_files/turnserver.conf
management/management
client/client
client/client.exe

View File

@@ -189,8 +189,6 @@ CGO_ENABLED=0 go build .
> Windows clients have a Wireguard driver requirement. You can download the wintun driver from https://www.wintun.net/builds/wintun-0.14.1.zip, after decompressing, you can copy the file `windtun\bin\ARCH\wintun.dll` to the same path as your binary file or to `C:\Windows\System32\wintun.dll`.
> To test the client GUI application on Windows machines with RDP or vituralized environments (e.g. virtualbox or cloud), you need to download and extract the opengl32.dll from https://fdossena.com/?p=mesa/index.frag next to the built application.
To start NetBird the client in the foreground:
```

View File

@@ -48,17 +48,17 @@ https://user-images.githubusercontent.com/700848/197345890-2e2cded5-7b7a-436f-a4
### Key features
| Connectivity | Management | Automation | Platforms |
|---------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|----------------------------------------------------------------------------|---------------------------------------|
| <ul><li> - \[x] Kernel WireGuard </ul></li> | <ul><li> - \[x] [Admin Web UI](https://github.com/netbirdio/dashboard) </ul></li> | <ul><li> - \[x] [Public API](https://docs.netbird.io/api) </ul></li> | <ul><li> - \[x] Linux </ul></li> |
| <ul><li> - \[x] Peer-to-peer connections </ul></li> | <ul><li> - \[x] Auto peer discovery and configuration </ul></li> | <ul><li> - \[x] [Setup keys for bulk network provisioning](https://docs.netbird.io/how-to/register-machines-using-setup-keys) </ul></li> | <ul><li> - \[x] Mac </ul></li> |
| <ul><li> - \[x] Peer-to-peer encryption </ul></li> | <ul><li> - \[x] [IdP integrations](https://docs.netbird.io/selfhosted/identity-providers) </ul></li> | <ul><li> - \[x] [Self-hosting quickstart script](https://docs.netbird.io/selfhosted/selfhosted-quickstart) </ul></li> | <ul><li> - \[x] Windows </ul></li> |
| <ul><li> - \[x] Connection relay fallback </ul></li> | <ul><li> - \[x] [SSO & MFA support](https://docs.netbird.io/how-to/installation#running-net-bird-with-sso-login) </ul></li> | <ul><li> - \[x] IdP groups sync with JWT </ul></li> | <ul><li> - \[x] Android </ul></li> |
| <ul><li> - \[x] [Routes to external networks](https://docs.netbird.io/how-to/routing-traffic-to-private-networks) </ul></li> | <ul><li> - \[x] [Access control - groups & rules](https://docs.netbird.io/how-to/manage-network-access) </ul></li> | | <ul><li> - \[x] iOS </ul></li> |
| <ul><li> - \[x] NAT traversal with BPF </ul></li> | <ul><li> - \[x] [Private DNS](https://docs.netbird.io/how-to/manage-dns-in-your-network) </ul></li> | | <ul><li> - \[x] Docker </ul></li> |
| <ul><li> - \[x] Post-quantum-secure connection through [Rosenpass](https://rosenpass.eu) </ul></li> | <ul><li> - \[x] [Multiuser support](https://docs.netbird.io/how-to/add-users-to-your-network) </ul></li> | | <ul><li> - \[x] OpenWRT </ul></li> |
| | <ul><li> - \[x] [Activity logging](https://docs.netbird.io/how-to/monitor-system-and-network-activity) </ul></li> | | |
| | <ul><li> - \[x] SSH access management </ul></li> | | |
| Connectivity | Management | Automation | Platforms |
|-------------------------------------------------------------------|--------------------------------------------------------------------------|----------------------------------------------------------------------------|---------------------------------------|
| <ul><li> - \[x] Kernel WireGuard </ul></li> | <ul><li> - \[x] [Admin Web UI](https://github.com/netbirdio/dashboard) </ul></li> | <ul><li> - \[x] [Public API](https://docs.netbird.io/api) </ul></li> | <ul><li> - \[x] Linux </ul></li> |
| <ul><li> - \[x] Peer-to-peer connections </ul></li> | <ul><li> - \[x] Auto peer discovery and configuration </ul></li> | <ul><li> - \[x] [Setup keys for bulk network provisioning](https://docs.netbird.io/how-to/register-machines-using-setup-keys) </ul></li> | <ul><li> - \[x] Mac </ul></li> |
| <ul><li> - \[x] Peer-to-peer encryption </ul></li> | <ul><li> - \[x] [IdP integrations](https://docs.netbird.io/selfhosted/identity-providers) </ul></li> | <ul><li> - \[x] [Self-hosting quickstart script](https://docs.netbird.io/selfhosted/selfhosted-quickstart) </ul></li> | <ul><li> - \[x] Windows </ul></li> |
| <ul><li> - \[x] Connection relay fallback </ul></li> | <ul><li> - \[x] [SSO & MFA support](https://docs.netbird.io/how-to/installation#running-net-bird-with-sso-login) </ul></li> | <ul><li> - \[x] IdP groups sync with JWT </ul></li> | <ul><li> - \[x] Android </ul></li> |
| <ul><li> - \[x] [Routes to external networks](https://docs.netbird.io/how-to/routing-traffic-to-private-networks) </ul></li> | <ul><li> - \[x] [Access control - groups & rules](https://docs.netbird.io/how-to/manage-network-access) </ul></li> | | <ul><li> - \[ ] iOS </ul></li> |
| <ul><li> - \[x] NAT traversal with BPF </ul></li> | <ul><li> - \[x] [Private DNS](https://docs.netbird.io/how-to/manage-dns-in-your-network) </ul></li> | | <ul><li> - \[x] Docker </ul></li> |
| | <ul><li> - \[x] [Multiuser support](https://docs.netbird.io/how-to/add-users-to-your-network) </ul></li> | | <ul><li> - \[x] OpenWRT </ul></li> |
| | <ul><li> - \[x] [Activity logging](https://docs.netbird.io/how-to/monitor-system-and-network-activity) </ul></li> | | |
| | <ul><li> - \[x] SSH access management </ul></li> | | |
### Quickstart with NetBird Cloud

View File

@@ -1,4 +1,4 @@
FROM alpine:3.18.5
FROM alpine:3
RUN apk add --no-cache ca-certificates iptables ip6tables
ENV NB_FOREGROUND_MODE=true
ENTRYPOINT [ "/go/bin/netbird","up"]

View File

@@ -51,7 +51,7 @@ var loginCmd = &cobra.Command{
AdminURL: adminURL,
ConfigPath: configPath,
}
if rootCmd.PersistentFlags().Changed(preSharedKeyFlag) {
if preSharedKey != "" {
ic.PreSharedKey = &preSharedKey
}
@@ -60,7 +60,7 @@ var loginCmd = &cobra.Command{
return fmt.Errorf("get config file: %v", err)
}
config, _ = internal.UpdateOldManagementURL(ctx, config, configPath)
config, _ = internal.UpdateOldManagementPort(ctx, config, configPath)
err = foregroundLogin(ctx, cmd, config, setupKey)
if err != nil {
@@ -151,21 +151,13 @@ func foregroundLogin(ctx context.Context, cmd *cobra.Command, config *internal.C
jwtToken = tokenInfo.GetTokenToUse()
}
var lastError error
err = WithBackOff(func() error {
err := internal.Login(ctx, config, setupKey, jwtToken)
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
lastError = err
return nil
}
return err
})
if lastError != nil {
return fmt.Errorf("login failed: %v", lastError)
}
if err != nil {
return fmt.Errorf("backoff cycle failed: %v", err)
}

View File

@@ -25,12 +25,8 @@ import (
)
const (
externalIPMapFlag = "external-ip-map"
dnsResolverAddress = "dns-resolver-address"
enableRosenpassFlag = "enable-rosenpass"
preSharedKeyFlag = "preshared-key"
interfaceNameFlag = "interface-name"
wireguardPortFlag = "wireguard-port"
externalIPMapFlag = "external-ip-map"
dnsResolverAddress = "dns-resolver-address"
)
var (
@@ -53,9 +49,6 @@ var (
preSharedKey string
natExternalIPs []string
customDNSAddress string
rosenpassEnabled bool
interfaceName string
wireguardPort uint16
rootCmd = &cobra.Command{
Use: "netbird",
Short: "",
@@ -101,7 +94,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "sets Netbird log level")
rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Netbird log path. If console is specified the log will be output to stdout")
rootCmd.PersistentFlags().StringVarP(&setupKey, "setup-key", "k", "", "Setup key obtained from the Management Service Dashboard (used to register peer)")
rootCmd.PersistentFlags().StringVar(&preSharedKey, preSharedKeyFlag, "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.")
rootCmd.PersistentFlags().StringVar(&preSharedKey, "preshared-key", "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.")
rootCmd.PersistentFlags().StringVarP(&hostName, "hostname", "n", "", "Sets a custom hostname for the device")
rootCmd.AddCommand(serviceCmd)
rootCmd.AddCommand(upCmd)
@@ -125,7 +118,6 @@ func init() {
`An empty string "" clears the previous configuration. `+
`E.g. --dns-resolver-address 127.0.0.1:5053 or --dns-resolver-address ""`,
)
upCmd.PersistentFlags().BoolVar(&rosenpassEnabled, enableRosenpassFlag, false, "[Experimental] Enable Rosenpass feature. If enabled, the connection will be post-quantum secured via Rosenpass.")
}
// SetupCloseHandler handles SIGTERM signal and exits with success

View File

@@ -66,15 +66,13 @@ type statusOutputOverview struct {
}
var (
detailFlag bool
ipv4Flag bool
jsonFlag bool
yamlFlag bool
ipsFilter []string
prefixNamesFilter []string
statusFilter string
ipsFilterMap map[string]struct{}
prefixNamesFilterMap map[string]struct{}
detailFlag bool
ipv4Flag bool
jsonFlag bool
yamlFlag bool
ipsFilter []string
statusFilter string
ipsFilterMap map[string]struct{}
)
var statusCmd = &cobra.Command{
@@ -85,14 +83,12 @@ var statusCmd = &cobra.Command{
func init() {
ipsFilterMap = make(map[string]struct{})
prefixNamesFilterMap = make(map[string]struct{})
statusCmd.PersistentFlags().BoolVarP(&detailFlag, "detail", "d", false, "display detailed status information in human-readable format")
statusCmd.PersistentFlags().BoolVar(&jsonFlag, "json", false, "display detailed status information in json format")
statusCmd.PersistentFlags().BoolVar(&yamlFlag, "yaml", false, "display detailed status information in yaml format")
statusCmd.PersistentFlags().BoolVar(&ipv4Flag, "ipv4", false, "display only NetBird IPv4 of this peer, e.g., --ipv4 will output 100.64.0.33")
statusCmd.MarkFlagsMutuallyExclusive("detail", "json", "yaml", "ipv4")
statusCmd.PersistentFlags().StringSliceVar(&ipsFilter, "filter-by-ips", []string{}, "filters the detailed output by a list of one or more IPs, e.g., --filter-by-ips 100.64.0.100,100.64.0.200")
statusCmd.PersistentFlags().StringSliceVar(&prefixNamesFilter, "filter-by-names", []string{}, "filters the detailed output by a list of one or more peer FQDN or hostnames, e.g., --filter-by-names peer-a,peer-b.netbird.cloud")
statusCmd.PersistentFlags().StringVar(&statusFilter, "filter-by-status", "", "filters the detailed output by connection status(connected|disconnected), e.g., --filter-by-status connected")
}
@@ -176,12 +172,8 @@ func getStatus(ctx context.Context, cmd *cobra.Command) (*proto.StatusResponse,
}
func parseFilters() error {
switch strings.ToLower(statusFilter) {
case "", "disconnected", "connected":
if strings.ToLower(statusFilter) != "" {
enableDetailFlagWhenFilterFlag()
}
default:
return fmt.Errorf("wrong status filter, should be one of connected|disconnected, got: %s", statusFilter)
}
@@ -193,26 +185,11 @@ func parseFilters() error {
return fmt.Errorf("got an invalid IP address in the filter: address %s, error %s", addr, err)
}
ipsFilterMap[addr] = struct{}{}
enableDetailFlagWhenFilterFlag()
}
}
if len(prefixNamesFilter) > 0 {
for _, name := range prefixNamesFilter {
prefixNamesFilterMap[strings.ToLower(name)] = struct{}{}
}
enableDetailFlagWhenFilterFlag()
}
return nil
}
func enableDetailFlagWhenFilterFlag() {
if !detailFlag && !jsonFlag && !yamlFlag {
detailFlag = true
}
}
func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverview {
pbFullStatus := resp.GetFullStatus()
@@ -438,7 +415,6 @@ func parsePeers(peers peersStateOutput) string {
func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool {
statusEval := false
ipEval := false
nameEval := false
if statusFilter != "" {
lowerStatusFilter := strings.ToLower(statusFilter)
@@ -455,15 +431,5 @@ func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool {
ipEval = true
}
}
if len(prefixNamesFilter) > 0 {
for prefixNameFilter := range prefixNamesFilterMap {
if !strings.HasPrefix(peerState.Fqdn, prefixNameFilter) {
nameEval = true
break
}
}
}
return statusEval || ipEval || nameEval
return statusEval || ipEval
}

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"net"
"net/netip"
"runtime"
"strings"
log "github.com/sirupsen/logrus"
@@ -17,7 +16,6 @@ import (
"github.com/netbirdio/netbird/client/internal/peer"
"github.com/netbirdio/netbird/client/proto"
"github.com/netbirdio/netbird/client/system"
"github.com/netbirdio/netbird/iface"
"github.com/netbirdio/netbird/util"
)
@@ -38,8 +36,6 @@ var (
func init() {
upCmd.PersistentFlags().BoolVarP(&foregroundMode, "foreground-mode", "F", false, "start service in foreground")
upCmd.PersistentFlags().StringVar(&interfaceName, interfaceNameFlag, iface.WgInterfaceDefault, "Wireguard interface name")
upCmd.PersistentFlags().Uint16Var(&wireguardPort, wireguardPortFlag, iface.DefaultWgPort, "Wireguard interface listening port")
}
func upFunc(cmd *cobra.Command, args []string) error {
@@ -89,24 +85,7 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {
NATExternalIPs: natExternalIPs,
CustomDNSAddress: customDNSAddressConverted,
}
if cmd.Flag(enableRosenpassFlag).Changed {
ic.RosenpassEnabled = &rosenpassEnabled
}
if cmd.Flag(interfaceNameFlag).Changed {
if err := parseInterfaceName(interfaceName); err != nil {
return err
}
ic.InterfaceName = &interfaceName
}
if cmd.Flag(wireguardPortFlag).Changed {
p := int(wireguardPort)
ic.WireguardPort = &p
}
if rootCmd.PersistentFlags().Changed(preSharedKeyFlag) {
if preSharedKey != "" {
ic.PreSharedKey = &preSharedKey
}
@@ -115,7 +94,7 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {
return fmt.Errorf("get config file: %v", err)
}
config, _ = internal.UpdateOldManagementURL(ctx, config, configPath)
config, _ = internal.UpdateOldManagementPort(ctx, config, configPath)
err = foregroundLogin(ctx, cmd, config, setupKey)
if err != nil {
@@ -173,22 +152,6 @@ func runInDaemonMode(ctx context.Context, cmd *cobra.Command) error {
Hostname: hostName,
}
if cmd.Flag(enableRosenpassFlag).Changed {
loginRequest.RosenpassEnabled = &rosenpassEnabled
}
if cmd.Flag(interfaceNameFlag).Changed {
if err := parseInterfaceName(interfaceName); err != nil {
return err
}
loginRequest.InterfaceName = &interfaceName
}
if cmd.Flag(wireguardPortFlag).Changed {
wp := int64(wireguardPort)
loginRequest.WireguardPort = &wp
}
var loginErr error
var loginResp *proto.LoginResponse
@@ -260,18 +223,6 @@ func validateNATExternalIPs(list []string) error {
return nil
}
func parseInterfaceName(name string) error {
if runtime.GOOS != "darwin" {
return nil
}
if strings.HasPrefix(name, "utun") {
return nil
}
return fmt.Errorf("invalid interface name %s. Please use the prefix utun followed by a number on MacOS. e.g., utun1 or utun199", name)
}
func validateElement(element string) (int, error) {
if isValidIP(element) {
return ipInputType, nil

View File

@@ -58,7 +58,6 @@ type AclManager struct {
type iFaceMapper interface {
Name() string
Address() iface.WGAddress
IsUserspaceBind() bool
}
func newAclManager(table *nftables.Table, wgIface iFaceMapper, routeingFwChainName string) (*AclManager, error) {
@@ -199,81 +198,6 @@ func (m *AclManager) DeleteRule(rule firewall.Rule) error {
return nil
}
// createDefaultAllowRules In case if the USP firewall manager can use the native firewall manager we must to create allow rules for
// input and output chains
func (m *AclManager) createDefaultAllowRules() error {
expIn := []expr.Any{
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 12,
Len: 4,
},
// mask
&expr.Bitwise{
SourceRegister: 1,
DestRegister: 1,
Len: 4,
Mask: []byte{0x00, 0x00, 0x00, 0x00},
Xor: zeroXor,
},
// net address
&expr.Cmp{
Register: 1,
Data: []byte{0x00, 0x00, 0x00, 0x00},
},
&expr.Verdict{
Kind: expr.VerdictAccept,
},
}
_ = m.rConn.InsertRule(&nftables.Rule{
Table: m.workTable,
Chain: m.chainInputRules,
Position: 0,
Exprs: expIn,
})
expOut := []expr.Any{
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 16,
Len: 4,
},
// mask
&expr.Bitwise{
SourceRegister: 1,
DestRegister: 1,
Len: 4,
Mask: []byte{0x00, 0x00, 0x00, 0x00},
Xor: zeroXor,
},
// net address
&expr.Cmp{
Register: 1,
Data: []byte{0x00, 0x00, 0x00, 0x00},
},
&expr.Verdict{
Kind: expr.VerdictAccept,
},
}
_ = m.rConn.InsertRule(&nftables.Rule{
Table: m.workTable,
Chain: m.chainOutputRules,
Position: 0,
Exprs: expOut,
})
err := m.rConn.Flush()
if err != nil {
log.Debugf("failed to create default allow rules: %s", err)
return err
}
return nil
}
// Flush rule/chain/set operations from the buffer
//
// Method also get all rules after flush and refreshes handle values in the rulesets
@@ -811,6 +735,7 @@ func (m *AclManager) createPreroutingMangle() *nftables.Chain {
Chain: chain,
Exprs: expressions,
})
chain = m.rConn.AddChain(chain)
return chain
}

View File

@@ -106,19 +106,11 @@ func (m *Manager) RemoveRoutingRules(pair firewall.RouterPair) error {
}
// AllowNetbird allows netbird interface traffic
// todo review this method usage
func (m *Manager) AllowNetbird() error {
if !m.wgIface.IsUserspaceBind() {
return nil
}
m.mutex.Lock()
defer m.mutex.Unlock()
err := m.aclManager.createDefaultAllowRules()
if err != nil {
return fmt.Errorf("failed to create default allow rules: %v", err)
}
chains, err := m.rConn.ListChainsOfTableFamily(nftables.TableFamilyIPv4)
if err != nil {
return fmt.Errorf("list of chains: %w", err)
@@ -153,7 +145,6 @@ func (m *Manager) AllowNetbird() error {
if err != nil {
return fmt.Errorf("failed to flush allow input netbird rules: %v", err)
}
return nil
}

View File

@@ -37,8 +37,6 @@ func (i *iFaceMock) Address() iface.WGAddress {
panic("AddressFunc is not set")
}
func (i *iFaceMock) IsUserspaceBind() bool { return false }
func TestNftablesManager(t *testing.T) {
mock := &iFaceMock{
NameFunc: func() string {

View File

@@ -193,7 +193,6 @@ Sleep 3000
Delete "$INSTDIR\${UI_APP_EXE}"
Delete "$INSTDIR\${MAIN_APP_EXE}"
Delete "$INSTDIR\wintun.dll"
Delete "$INSTDIR\opengl32.dll"
RmDir /r "$INSTDIR"
SetShellVarContext all

View File

@@ -38,7 +38,7 @@ func TestDefaultManager(t *testing.T) {
defer ctrl.Finish()
ifaceMock := mocks.NewMockIFaceMapper(ctrl)
ifaceMock.EXPECT().IsUserspaceBind().Return(true).AnyTimes()
ifaceMock.EXPECT().IsUserspaceBind().Return(true)
ifaceMock.EXPECT().SetFilter(gomock.Any())
ip, network, err := net.ParseCIDR("172.0.0.1/32")
if err != nil {
@@ -331,7 +331,7 @@ func TestDefaultManagerEnableSSHRules(t *testing.T) {
defer ctrl.Finish()
ifaceMock := mocks.NewMockIFaceMapper(ctrl)
ifaceMock.EXPECT().IsUserspaceBind().Return(true).AnyTimes()
ifaceMock.EXPECT().IsUserspaceBind().Return(true)
ifaceMock.EXPECT().SetFilter(gomock.Any())
ip, network, err := net.ParseCIDR("172.0.0.1/32")
if err != nil {

View File

@@ -1,7 +1,6 @@
package internal
import (
"context"
"fmt"
"net/url"
"os"
@@ -13,19 +12,16 @@ import (
"github.com/netbirdio/netbird/client/ssh"
"github.com/netbirdio/netbird/iface"
mgm "github.com/netbirdio/netbird/management/client"
"github.com/netbirdio/netbird/util"
)
const (
// managementLegacyPortString is the port that was used before by the Management gRPC server.
// ManagementLegacyPort is the port that was used before by the Management gRPC server.
// It is used for backward compatibility now.
// NB: hardcoded from github.com/netbirdio/netbird/management/cmd to avoid import
managementLegacyPortString = "33073"
ManagementLegacyPort = 33073
// DefaultManagementURL points to the NetBird's cloud management endpoint
DefaultManagementURL = "https://api.netbird.io:443"
// oldDefaultManagementURL points to the NetBird's old cloud management endpoint
oldDefaultManagementURL = "https://api.wiretrustee.com:443"
DefaultManagementURL = "https://api.wiretrustee.com:443"
// DefaultAdminURL points to NetBird's cloud management console
DefaultAdminURL = "https://app.netbird.io:443"
)
@@ -41,9 +37,6 @@ type ConfigInput struct {
PreSharedKey *string
NATExternalIPs []string
CustomDNSAddress []byte
RosenpassEnabled *bool
InterfaceName *string
WireguardPort *int
}
// Config Configuration type
@@ -57,11 +50,10 @@ type Config struct {
WgPort int
IFaceBlackList []string
DisableIPv6Discovery bool
RosenpassEnabled bool
// SSHKey is a private SSH key in a PEM format
SSHKey string
// ExternalIP mappings, if different from the host interface IP
// ExternalIP mappings, if different than the host interface IP
//
// External IP must not be behind a CGNAT and port-forwarding for incoming UDP packets from WgPort on ExternalIP
// to WgPort on host interface IP must be present. This can take form of single port-forwarding rule, 1:1 DNAT
@@ -144,10 +136,11 @@ func createNewConfig(input ConfigInput) (*Config, error) {
if err != nil {
return nil, err
}
config := &Config{
SSHKey: string(pem),
PrivateKey: wgKey,
WgIface: iface.WgInterfaceDefault,
WgPort: iface.DefaultWgPort,
IFaceBlackList: []string{},
DisableIPv6Discovery: false,
NATExternalIPs: input.NATExternalIPs,
@@ -168,24 +161,10 @@ func createNewConfig(input ConfigInput) (*Config, error) {
config.ManagementURL = URL
}
config.WgPort = iface.DefaultWgPort
if input.WireguardPort != nil {
config.WgPort = *input.WireguardPort
}
config.WgIface = iface.WgInterfaceDefault
if input.InterfaceName != nil {
config.WgIface = *input.InterfaceName
}
if input.PreSharedKey != nil {
config.PreSharedKey = *input.PreSharedKey
}
if input.RosenpassEnabled != nil {
config.RosenpassEnabled = *input.RosenpassEnabled
}
defaultAdminURL, err := parseURL("Admin URL", DefaultAdminURL)
if err != nil {
return nil, err
@@ -236,9 +215,12 @@ func update(input ConfigInput) (*Config, error) {
}
if input.PreSharedKey != nil && config.PreSharedKey != *input.PreSharedKey {
log.Infof("new pre-shared key provided, replacing old key")
config.PreSharedKey = *input.PreSharedKey
refresh = true
if *input.PreSharedKey != "" {
log.Infof("new pre-shared key provides, updated to %s (old value %s)",
*input.PreSharedKey, config.PreSharedKey)
config.PreSharedKey = *input.PreSharedKey
refresh = true
}
}
if config.SSHKey == "" {
@@ -254,17 +236,6 @@ func update(input ConfigInput) (*Config, error) {
config.WgPort = iface.DefaultWgPort
refresh = true
}
if input.WireguardPort != nil {
config.WgPort = *input.WireguardPort
refresh = true
}
if input.InterfaceName != nil {
config.WgIface = *input.InterfaceName
refresh = true
}
if input.NATExternalIPs != nil && len(config.NATExternalIPs) != len(input.NATExternalIPs) {
config.NATExternalIPs = input.NATExternalIPs
refresh = true
@@ -275,11 +246,6 @@ func update(input ConfigInput) (*Config, error) {
refresh = true
}
if input.RosenpassEnabled != nil {
config.RosenpassEnabled = *input.RosenpassEnabled
refresh = true
}
if refresh {
// since we have new management URL, we need to update config file
if err := util.WriteJson(input.ConfigPath, config); err != nil {
@@ -339,86 +305,3 @@ func configFileIsExists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// UpdateOldManagementURL checks whether client can switch to the new Management URL with port 443 and the management domain.
// If it can switch, then it updates the config and returns a new one. Otherwise, it returns the provided config.
// The check is performed only for the NetBird's managed version.
func UpdateOldManagementURL(ctx context.Context, config *Config, configPath string) (*Config, error) {
defaultManagementURL, err := parseURL("Management URL", DefaultManagementURL)
if err != nil {
return nil, err
}
parsedOldDefaultManagementURL, err := parseURL("Management URL", oldDefaultManagementURL)
if err != nil {
return nil, err
}
if config.ManagementURL.Hostname() != defaultManagementURL.Hostname() &&
config.ManagementURL.Hostname() != parsedOldDefaultManagementURL.Hostname() {
// only do the check for the NetBird's managed version
return config, nil
}
var mgmTlsEnabled bool
if config.ManagementURL.Scheme == "https" {
mgmTlsEnabled = true
}
if !mgmTlsEnabled {
// only do the check for HTTPs scheme (the hosted version of the Management service is always HTTPs)
return config, nil
}
if config.ManagementURL.Port() != managementLegacyPortString &&
config.ManagementURL.Hostname() == defaultManagementURL.Hostname() {
return config, nil
}
newURL, err := parseURL("Management URL", fmt.Sprintf("%s://%s:%d",
config.ManagementURL.Scheme, defaultManagementURL.Hostname(), 443))
if err != nil {
return nil, err
}
// here we check whether we could switch from the legacy 33073 port to the new 443
log.Infof("attempting to switch from the legacy Management URL %s to the new one %s",
config.ManagementURL.String(), newURL.String())
key, err := wgtypes.ParseKey(config.PrivateKey)
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return config, err
}
client, err := mgm.NewClient(ctx, newURL.Host, key, mgmTlsEnabled)
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return config, err
}
defer func() {
err = client.Close()
if err != nil {
log.Warnf("failed to close the Management service client %v", err)
}
}()
// gRPC check
_, err = client.GetServerPublicKey()
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return nil, err
}
// everything is alright => update the config
newConfig, err := UpdateConfig(ConfigInput{
ManagementURL: newURL.String(),
ConfigPath: configPath,
})
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return config, fmt.Errorf("failed updating config file: %v", err)
}
log.Infof("successfully switched to the new Management URL: %s", newURL.String())
return newConfig, nil
}

View File

@@ -1,16 +1,13 @@
package internal
import (
"context"
"errors"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/netbirdio/netbird/util"
"github.com/stretchr/testify/assert"
)
func TestGetConfig(t *testing.T) {
@@ -63,7 +60,22 @@ func TestGetConfig(t *testing.T) {
assert.Equal(t, config.ManagementURL.String(), managementURL)
assert.Equal(t, config.PreSharedKey, preSharedKey)
// case 4: existing config, but new managementURL has been provided -> update config
// case 4: new empty pre-shared key config -> fetch it
newPreSharedKey := ""
config, err = UpdateOrCreateConfig(ConfigInput{
ManagementURL: managementURL,
AdminURL: adminURL,
ConfigPath: path,
PreSharedKey: &newPreSharedKey,
})
if err != nil {
return
}
assert.Equal(t, config.ManagementURL.String(), managementURL)
assert.Equal(t, config.PreSharedKey, preSharedKey)
// case 5: existing config, but new managementURL has been provided -> update config
newManagementURL := "https://test.newManagement.url:33071"
config, err = UpdateOrCreateConfig(ConfigInput{
ManagementURL: newManagementURL,
@@ -122,60 +134,3 @@ func TestHiddenPreSharedKey(t *testing.T) {
})
}
}
func TestUpdateOldManagementURL(t *testing.T) {
tests := []struct {
name string
previousManagementURL string
expectedManagementURL string
fileShouldNotChange bool
}{
{
name: "Update old management URL with legacy port",
previousManagementURL: "https://api.wiretrustee.com:33073",
expectedManagementURL: DefaultManagementURL,
},
{
name: "Update old management URL",
previousManagementURL: oldDefaultManagementURL,
expectedManagementURL: DefaultManagementURL,
},
{
name: "No update needed when management URL is up to date",
previousManagementURL: DefaultManagementURL,
expectedManagementURL: DefaultManagementURL,
fileShouldNotChange: true,
},
{
name: "No update needed when not using cloud management",
previousManagementURL: "https://netbird.example.com:33073",
expectedManagementURL: "https://netbird.example.com:33073",
fileShouldNotChange: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "config.json")
config, err := UpdateOrCreateConfig(ConfigInput{
ManagementURL: tt.previousManagementURL,
ConfigPath: configPath,
})
require.NoError(t, err, "failed to create testing config")
previousStats, err := os.Stat(configPath)
require.NoError(t, err, "failed to create testing config stats")
resultConfig, err := UpdateOldManagementURL(context.TODO(), config, configPath)
require.NoError(t, err, "got error when updating old management url")
require.Equal(t, tt.expectedManagementURL, resultConfig.ManagementURL.String())
newStats, err := os.Stat(configPath)
require.NoError(t, err, "failed to create testing config stats")
switch tt.fileShouldNotChange {
case true:
require.Equal(t, previousStats.ModTime(), newStats.ModTime(), "file should not change")
case false:
require.NotEqual(t, previousStats.ModTime(), newStats.ModTime(), "file should have changed")
}
})
}
}

View File

@@ -43,15 +43,6 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S
return runClient(ctx, config, statusRecorder, mobileDependency)
}
func RunClientiOS(ctx context.Context, config *Config, statusRecorder *peer.Status, fileDescriptor int32, networkChangeListener listener.NetworkChangeListener, dnsManager dns.IosDnsManager) error {
mobileDependency := MobileDependency{
FileDescriptor: fileDescriptor,
NetworkChangeListener: networkChangeListener,
DnsManager: dnsManager,
}
return runClient(ctx, config, statusRecorder, mobileDependency)
}
func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, mobileDependency MobileDependency) error {
log.Infof("starting NetBird client version %s", version.NetbirdVersion())
@@ -235,7 +226,6 @@ func createEngineConfig(key wgtypes.Key, config *Config, peerConfig *mgmProto.Pe
SSHKey: []byte(config.SSHKey),
NATExternalIPs: config.NATExternalIPs,
CustomDNSAddress: config.CustomDNSAddress,
RosenpassEnabled: config.RosenpassEnabled,
}
if config.PreSharedKey != "" {
@@ -284,6 +274,83 @@ func loginToManagement(ctx context.Context, client mgm.Client, pubSSHKey []byte)
return loginResp, nil
}
// UpdateOldManagementPort checks whether client can switch to the new Management port 443.
// If it can switch, then it updates the config and returns a new one. Otherwise, it returns the provided config.
// The check is performed only for the NetBird's managed version.
func UpdateOldManagementPort(ctx context.Context, config *Config, configPath string) (*Config, error) {
defaultManagementURL, err := parseURL("Management URL", DefaultManagementURL)
if err != nil {
return nil, err
}
if config.ManagementURL.Hostname() != defaultManagementURL.Hostname() {
// only do the check for the NetBird's managed version
return config, nil
}
var mgmTlsEnabled bool
if config.ManagementURL.Scheme == "https" {
mgmTlsEnabled = true
}
if !mgmTlsEnabled {
// only do the check for HTTPs scheme (the hosted version of the Management service is always HTTPs)
return config, nil
}
if mgmTlsEnabled && config.ManagementURL.Port() == fmt.Sprintf("%d", ManagementLegacyPort) {
newURL, err := parseURL("Management URL", fmt.Sprintf("%s://%s:%d",
config.ManagementURL.Scheme, config.ManagementURL.Hostname(), 443))
if err != nil {
return nil, err
}
// here we check whether we could switch from the legacy 33073 port to the new 443
log.Infof("attempting to switch from the legacy Management URL %s to the new one %s",
config.ManagementURL.String(), newURL.String())
key, err := wgtypes.ParseKey(config.PrivateKey)
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return config, err
}
client, err := mgm.NewClient(ctx, newURL.Host, key, mgmTlsEnabled)
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return config, err
}
defer func() {
err = client.Close()
if err != nil {
log.Warnf("failed to close the Management service client %v", err)
}
}()
// gRPC check
_, err = client.GetServerPublicKey()
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return nil, err
}
// everything is alright => update the config
newConfig, err := UpdateConfig(ConfigInput{
ManagementURL: newURL.String(),
ConfigPath: configPath,
})
if err != nil {
log.Infof("couldn't switch to the new Management %s", newURL.String())
return config, fmt.Errorf("failed updating config file: %v", err)
}
log.Infof("successfully switched to the new Management URL: %s", newURL.String())
return newConfig, nil
}
return config, nil
}
func statusRecorderToMgmConnStateNotifier(statusRecorder *peer.Status) mgm.ConnStateNotifier {
var sri interface{} = statusRecorder
mgmNotifier, _ := sri.(mgm.ConnStateNotifier)

View File

@@ -35,14 +35,14 @@ func (f *fileConfigurator) supportCustomPort() bool {
return false
}
func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error {
func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error {
backupFileExist := false
_, err := os.Stat(fileDefaultResolvConfBackupLocation)
if err == nil {
backupFileExist = true
}
if !config.RouteAll {
if !config.routeAll {
if backupFileExist {
err = f.restore()
if err != nil {
@@ -70,7 +70,7 @@ func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error {
buf := prepareResolvConfContent(
searchDomainList,
append([]string{config.ServerIP}, nameServers...),
append([]string{config.serverIP}, nameServers...),
others)
log.Debugf("creating managed file %s", defaultResolvConfPath)
@@ -138,14 +138,14 @@ func prepareResolvConfContent(searchDomains, nameServers, others []string) bytes
return buf
}
func searchDomains(config HostDNSConfig) []string {
func searchDomains(config hostDNSConfig) []string {
listOfDomains := make([]string, 0)
for _, dConf := range config.Domains {
if dConf.MatchOnly || dConf.Disabled {
for _, dConf := range config.domains {
if dConf.matchOnly || dConf.disabled {
continue
}
listOfDomains = append(listOfDomains, dConf.Domain)
listOfDomains = append(listOfDomains, dConf.domain)
}
return listOfDomains
}
@@ -214,7 +214,7 @@ func originalDNSConfigs(resolvconfFile string) (searchDomains, nameServers, othe
return
}
// merge search Domains lists and cut off the list if it is too long
// merge search domains lists and cut off the list if it is too long
func mergeSearchDomains(searchDomains []string, originalSearchDomains []string) []string {
lineSize := len("search")
searchDomainsList := make([]string, 0, len(searchDomains)+len(originalSearchDomains))
@@ -225,14 +225,14 @@ func mergeSearchDomains(searchDomains []string, originalSearchDomains []string)
return searchDomainsList
}
// validateAndFillSearchDomains checks if the search Domains list is not too long and if the line is not too long
// validateAndFillSearchDomains checks if the search domains list is not too long and if the line is not too long
// extend s slice with vs elements
// return with the number of characters in the searchDomains line
func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string) int {
for _, sd := range vs {
tmpCharsNumber := initialLineChars + 1 + len(sd)
if tmpCharsNumber > fileMaxLineCharsLimit {
// lets log all skipped Domains
// lets log all skipped domains
log.Infof("search list line is larger than %d characters. Skipping append of %s domain", fileMaxLineCharsLimit, sd)
continue
}
@@ -240,7 +240,7 @@ func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string
initialLineChars = tmpCharsNumber
if len(*s) >= fileMaxNumberOfSearchDomains {
// lets log all skipped Domains
// lets log all skipped domains
log.Infof("already appended %d domains to search list. Skipping append of %s domain", fileMaxNumberOfSearchDomains, sd)
continue
}

View File

@@ -8,31 +8,31 @@ import (
)
type hostManager interface {
applyDNSConfig(config HostDNSConfig) error
applyDNSConfig(config hostDNSConfig) error
restoreHostDNS() error
supportCustomPort() bool
}
type HostDNSConfig struct {
Domains []DomainConfig `json:"domains"`
RouteAll bool `json:"routeAll"`
ServerIP string `json:"serverIP"`
ServerPort int `json:"serverPort"`
type hostDNSConfig struct {
domains []domainConfig
routeAll bool
serverIP string
serverPort int
}
type DomainConfig struct {
Disabled bool `json:"disabled"`
Domain string `json:"domain"`
MatchOnly bool `json:"matchOnly"`
type domainConfig struct {
disabled bool
domain string
matchOnly bool
}
type mockHostConfigurator struct {
applyDNSConfigFunc func(config HostDNSConfig) error
applyDNSConfigFunc func(config hostDNSConfig) error
restoreHostDNSFunc func() error
supportCustomPortFunc func() bool
}
func (m *mockHostConfigurator) applyDNSConfig(config HostDNSConfig) error {
func (m *mockHostConfigurator) applyDNSConfig(config hostDNSConfig) error {
if m.applyDNSConfigFunc != nil {
return m.applyDNSConfigFunc(config)
}
@@ -55,38 +55,38 @@ func (m *mockHostConfigurator) supportCustomPort() bool {
func newNoopHostMocker() hostManager {
return &mockHostConfigurator{
applyDNSConfigFunc: func(config HostDNSConfig) error { return nil },
applyDNSConfigFunc: func(config hostDNSConfig) error { return nil },
restoreHostDNSFunc: func() error { return nil },
supportCustomPortFunc: func() bool { return true },
}
}
func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) HostDNSConfig {
config := HostDNSConfig{
RouteAll: false,
ServerIP: ip,
ServerPort: port,
func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig {
config := hostDNSConfig{
routeAll: false,
serverIP: ip,
serverPort: port,
}
for _, nsConfig := range dnsConfig.NameServerGroups {
if len(nsConfig.NameServers) == 0 {
continue
}
if nsConfig.Primary {
config.RouteAll = true
config.routeAll = true
}
for _, domain := range nsConfig.Domains {
config.Domains = append(config.Domains, DomainConfig{
Domain: strings.TrimSuffix(domain, "."),
MatchOnly: !nsConfig.SearchDomainsEnabled,
config.domains = append(config.domains, domainConfig{
domain: strings.TrimSuffix(domain, "."),
matchOnly: !nsConfig.SearchDomainsEnabled,
})
}
}
for _, customZone := range dnsConfig.CustomZones {
config.Domains = append(config.Domains, DomainConfig{
Domain: strings.TrimSuffix(customZone.Domain, "."),
MatchOnly: false,
config.domains = append(config.domains, domainConfig{
domain: strings.TrimSuffix(customZone.Domain, "."),
matchOnly: false,
})
}

View File

@@ -7,7 +7,7 @@ func newHostManager(wgInterface WGIface) (hostManager, error) {
return &androidHostManager{}, nil
}
func (a androidHostManager) applyDNSConfig(config HostDNSConfig) error {
func (a androidHostManager) applyDNSConfig(config hostDNSConfig) error {
return nil
}

View File

@@ -1,5 +1,3 @@
//go:build !ios
package dns
import (
@@ -44,11 +42,11 @@ func (s *systemConfigurator) supportCustomPort() bool {
return true
}
func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error {
func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error {
var err error
if config.RouteAll {
err = s.addDNSSetupForAll(config.ServerIP, config.ServerPort)
if config.routeAll {
err = s.addDNSSetupForAll(config.serverIP, config.serverPort)
if err != nil {
return err
}
@@ -58,7 +56,7 @@ func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error {
return err
}
s.primaryServiceID = ""
log.Infof("removed %s:%d as main DNS resolver for this peer", config.ServerIP, config.ServerPort)
log.Infof("removed %s:%d as main DNS resolver for this peer", config.serverIP, config.serverPort)
}
var (
@@ -66,20 +64,20 @@ func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error {
matchDomains []string
)
for _, dConf := range config.Domains {
if dConf.Disabled {
for _, dConf := range config.domains {
if dConf.disabled {
continue
}
if dConf.MatchOnly {
matchDomains = append(matchDomains, dConf.Domain)
if dConf.matchOnly {
matchDomains = append(matchDomains, dConf.domain)
continue
}
searchDomains = append(searchDomains, dConf.Domain)
searchDomains = append(searchDomains, dConf.domain)
}
matchKey := getKeyWithInput(netbirdDNSStateKeyFormat, matchSuffix)
if len(matchDomains) != 0 {
err = s.addMatchDomains(matchKey, strings.Join(matchDomains, " "), config.ServerIP, config.ServerPort)
err = s.addMatchDomains(matchKey, strings.Join(matchDomains, " "), config.serverIP, config.serverPort)
} else {
log.Infof("removing match domains from the system")
err = s.removeKeyFromSystemConfig(matchKey)
@@ -90,7 +88,7 @@ func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error {
searchKey := getKeyWithInput(netbirdDNSStateKeyFormat, searchSuffix)
if len(searchDomains) != 0 {
err = s.addSearchDomains(searchKey, strings.Join(searchDomains, " "), config.ServerIP, config.ServerPort)
err = s.addSearchDomains(searchKey, strings.Join(searchDomains, " "), config.serverIP, config.serverPort)
} else {
log.Infof("removing search domains from the system")
err = s.removeKeyFromSystemConfig(searchKey)

View File

@@ -1,37 +0,0 @@
package dns
import (
"encoding/json"
log "github.com/sirupsen/logrus"
)
type iosHostManager struct {
dnsManager IosDnsManager
config HostDNSConfig
}
func newHostManager(dnsManager IosDnsManager) (hostManager, error) {
return &iosHostManager{
dnsManager: dnsManager,
}, nil
}
func (a iosHostManager) applyDNSConfig(config HostDNSConfig) error {
jsonData, err := json.Marshal(config)
if err != nil {
return err
}
jsonString := string(jsonData)
log.Debugf("Applying DNS settings: %s", jsonString)
a.dnsManager.ApplyDns(jsonString)
return nil
}
func (a iosHostManager) restoreHostDNS() error {
return nil
}
func (a iosHostManager) supportCustomPort() bool {
return false
}

View File

@@ -43,10 +43,10 @@ func (s *registryConfigurator) supportCustomPort() bool {
return false
}
func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error {
func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error {
var err error
if config.RouteAll {
err = r.addDNSSetupForAll(config.ServerIP)
if config.routeAll {
err = r.addDNSSetupForAll(config.serverIP)
if err != nil {
return err
}
@@ -56,7 +56,7 @@ func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error {
return err
}
r.routingAll = false
log.Infof("removed %s as main DNS forwarder for this peer", config.ServerIP)
log.Infof("removed %s as main DNS forwarder for this peer", config.serverIP)
}
var (
@@ -64,18 +64,18 @@ func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error {
matchDomains []string
)
for _, dConf := range config.Domains {
if dConf.Disabled {
for _, dConf := range config.domains {
if dConf.disabled {
continue
}
if !dConf.MatchOnly {
searchDomains = append(searchDomains, dConf.Domain)
if !dConf.matchOnly {
searchDomains = append(searchDomains, dConf.domain)
}
matchDomains = append(matchDomains, "."+dConf.Domain)
matchDomains = append(matchDomains, "."+dConf.domain)
}
if len(matchDomains) != 0 {
err = r.addDNSMatchPolicy(matchDomains, config.ServerIP)
err = r.addDNSMatchPolicy(matchDomains, config.serverIP)
} else {
err = removeRegistryKeyFromDNSPolicyConfig(dnsPolicyConfigMatchPath)
}

View File

@@ -1,12 +1,10 @@
package dns
import (
"github.com/miekg/dns"
nbdns "github.com/netbirdio/netbird/dns"
"strings"
"testing"
"github.com/miekg/dns"
nbdns "github.com/netbirdio/netbird/dns"
)
func TestLocalResolver_ServeDNS(t *testing.T) {

View File

@@ -33,7 +33,7 @@ func (m *MockServer) DnsIP() string {
}
func (m *MockServer) OnUpdatedHostDNSServer(strings []string) {
// TODO implement me
//TODO implement me
panic("implement me")
}

View File

@@ -12,9 +12,8 @@ import (
"github.com/godbus/dbus/v5"
"github.com/hashicorp/go-version"
"github.com/miekg/dns"
log "github.com/sirupsen/logrus"
nbversion "github.com/netbirdio/netbird/version"
log "github.com/sirupsen/logrus"
)
const (
@@ -94,7 +93,7 @@ func (n *networkManagerDbusConfigurator) supportCustomPort() bool {
return false
}
func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) error {
connSettings, configVersion, err := n.getAppliedConnectionSettings()
if err != nil {
return fmt.Errorf("got an error while retrieving the applied connection settings, error: %s", err)
@@ -102,7 +101,7 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) er
connSettings.cleanDeprecatedSettings()
dnsIP, err := netip.ParseAddr(config.ServerIP)
dnsIP, err := netip.ParseAddr(config.serverIP)
if err != nil {
return fmt.Errorf("unable to parse ip address, error: %s", err)
}
@@ -112,33 +111,33 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) er
searchDomains []string
matchDomains []string
)
for _, dConf := range config.Domains {
if dConf.Disabled {
for _, dConf := range config.domains {
if dConf.disabled {
continue
}
if dConf.MatchOnly {
matchDomains = append(matchDomains, "~."+dns.Fqdn(dConf.Domain))
if dConf.matchOnly {
matchDomains = append(matchDomains, "~."+dns.Fqdn(dConf.domain))
continue
}
searchDomains = append(searchDomains, dns.Fqdn(dConf.Domain))
searchDomains = append(searchDomains, dns.Fqdn(dConf.domain))
}
newDomainList := append(searchDomains, matchDomains...) //nolint:gocritic
priority := networkManagerDbusSearchDomainOnlyPriority
switch {
case config.RouteAll:
case config.routeAll:
priority = networkManagerDbusPrimaryDNSPriority
newDomainList = append(newDomainList, "~.")
if !n.routingAll {
log.Infof("configured %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort)
log.Infof("configured %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort)
}
case len(matchDomains) > 0:
priority = networkManagerDbusWithMatchDomainPriority
}
if priority != networkManagerDbusPrimaryDNSPriority && n.routingAll {
log.Infof("removing %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort)
log.Infof("removing %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort)
n.routingAll = false
}

View File

@@ -52,6 +52,6 @@ func (n *notifier) notify() {
}
go func(l listener.NetworkChangeListener) {
l.OnNetworkChanged("")
l.OnNetworkChanged()
}(n.listener)
}

View File

@@ -39,9 +39,9 @@ func (r *resolvconf) supportCustomPort() bool {
return false
}
func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error {
func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error {
var err error
if !config.RouteAll {
if !config.routeAll {
err = r.restoreHostDNS()
if err != nil {
log.Error(err)
@@ -54,7 +54,7 @@ func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error {
buf := prepareResolvConfContent(
searchDomainList,
append([]string{config.ServerIP}, r.originalNameServers...),
append([]string{config.serverIP}, r.originalNameServers...),
r.othersConfigs)
err = r.applyConfig(buf)

View File

@@ -19,11 +19,6 @@ type ReadyListener interface {
OnReady()
}
// IosDnsManager is a dns manager interface for iOS
type IosDnsManager interface {
ApplyDns(string)
}
// Server is a dns server interface
type Server interface {
Initialize() error
@@ -48,7 +43,7 @@ type DefaultServer struct {
hostManager hostManager
updateSerial uint64
previousConfigHash uint64
currentConfig HostDNSConfig
currentConfig hostDNSConfig
// permanent related properties
permanent bool
@@ -57,7 +52,6 @@ type DefaultServer struct {
// make sense on mobile only
searchDomainNotifier *notifier
iosDnsManager IosDnsManager
}
type handlerWithStop interface {
@@ -105,13 +99,6 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface,
return ds
}
// NewDefaultServerIos returns a new dns server. It optimized for ios
func NewDefaultServerIos(ctx context.Context, wgInterface WGIface, iosDnsManager IosDnsManager) *DefaultServer {
ds := newDefaultServer(ctx, wgInterface, newServiceViaMemory(wgInterface))
ds.iosDnsManager = iosDnsManager
return ds
}
func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service) *DefaultServer {
ctx, stop := context.WithCancel(ctx)
defaultServer := &DefaultServer{
@@ -144,8 +131,8 @@ func (s *DefaultServer) Initialize() (err error) {
}
}
s.hostManager, err = s.initialize()
return err
s.hostManager, err = newHostManager(s.wgInterface)
return
}
// DnsIP returns the DNS resolver server IP address
@@ -236,20 +223,20 @@ func (s *DefaultServer) UpdateDNSServer(serial uint64, update nbdns.Config) erro
func (s *DefaultServer) SearchDomains() []string {
var searchDomains []string
for _, dConf := range s.currentConfig.Domains {
if dConf.Disabled {
for _, dConf := range s.currentConfig.domains {
if dConf.disabled {
continue
}
if dConf.MatchOnly {
if dConf.matchOnly {
continue
}
searchDomains = append(searchDomains, dConf.Domain)
searchDomains = append(searchDomains, dConf.domain)
}
return searchDomains
}
func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
// is the service should be Disabled, we stop the listener or fake resolver
// is the service should be disabled, we stop the listener or fake resolver
// and proceed with a regular update to clean up the handlers and records
if update.ServiceEnable {
_ = s.service.Listen()
@@ -275,7 +262,7 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
if s.service.RuntimePort() != defaultPort && !s.hostManager.supportCustomPort() {
log.Warnf("the DNS manager of this peer doesn't support custom port. Disabling primary DNS setup. " +
"Learn more at: https://docs.netbird.io/how-to/manage-dns-in-your-network#local-resolver")
hostUpdate.RouteAll = false
hostUpdate.routeAll = false
}
if err = s.hostManager.applyDNSConfig(hostUpdate); err != nil {
@@ -325,10 +312,7 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam
continue
}
handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP, s.wgInterface.Address().Network)
if err != nil {
return nil, fmt.Errorf("unable to create a new upstream resolver, error: %v", err)
}
handler := newUpstreamResolver(s.ctx)
for _, ns := range nsGroup.NameServers {
if ns.NSType != nbdns.UDPNameServerType {
log.Warnf("skipping nameserver %s with type %s, this peer supports only %s",
@@ -461,14 +445,14 @@ func (s *DefaultServer) upstreamCallbacks(
}
if nsGroup.Primary {
removeIndex[nbdns.RootZone] = -1
s.currentConfig.RouteAll = false
s.currentConfig.routeAll = false
}
for i, item := range s.currentConfig.Domains {
if _, found := removeIndex[item.Domain]; found {
s.currentConfig.Domains[i].Disabled = true
s.service.DeregisterMux(item.Domain)
removeIndex[item.Domain] = i
for i, item := range s.currentConfig.domains {
if _, found := removeIndex[item.domain]; found {
s.currentConfig.domains[i].disabled = true
s.service.DeregisterMux(item.domain)
removeIndex[item.domain] = i
}
}
if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil {
@@ -480,32 +464,28 @@ func (s *DefaultServer) upstreamCallbacks(
defer s.mux.Unlock()
for domain, i := range removeIndex {
if i == -1 || i >= len(s.currentConfig.Domains) || s.currentConfig.Domains[i].Domain != domain {
if i == -1 || i >= len(s.currentConfig.domains) || s.currentConfig.domains[i].domain != domain {
continue
}
s.currentConfig.Domains[i].Disabled = false
s.currentConfig.domains[i].disabled = false
s.service.RegisterMux(domain, handler)
}
l := log.WithField("nameservers", nsGroup.NameServers)
l.Debug("reactivate temporary Disabled nameserver group")
l.Debug("reactivate temporary disabled nameserver group")
if nsGroup.Primary {
s.currentConfig.RouteAll = true
s.currentConfig.routeAll = true
}
if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil {
l.WithError(err).Error("reactivate temporary Disabled nameserver group, DNS update apply")
l.WithError(err).Error("reactivate temporary disabled nameserver group, DNS update apply")
}
}
return
}
func (s *DefaultServer) addHostRootZone() {
handler, err := newUpstreamResolver(s.ctx, s.wgInterface.Name(), s.wgInterface.Address().IP, s.wgInterface.Address().Network)
if err != nil {
log.Errorf("unable to create a new upstream resolver, error: %v", err)
return
}
handler := newUpstreamResolver(s.ctx)
handler.upstreamServers = make([]string, len(s.hostsDnsList))
for n, ua := range s.hostsDnsList {
a, err := netip.ParseAddr(ua)

View File

@@ -1,5 +0,0 @@
package dns
func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}

View File

@@ -1,7 +0,0 @@
//go:build !ios
package dns
func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}

View File

@@ -1,5 +0,0 @@
package dns
func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.iosDnsManager)
}

View File

@@ -1,7 +0,0 @@
//go:build !android
package dns
func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}

View File

@@ -12,7 +12,6 @@ import (
"github.com/golang/mock/gomock"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/netbirdio/netbird/client/firewall/uspfilter"
"github.com/netbirdio/netbird/client/internal/stdnet"
@@ -251,12 +250,11 @@ func TestUpdateDNSServer(t *testing.T) {
for n, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
privKey, _ := wgtypes.GenerateKey()
newNet, err := stdnet.NewNet(nil)
if err != nil {
t.Fatal(err)
}
wgIface, err := iface.NewWGIFace(fmt.Sprintf("utun230%d", n), fmt.Sprintf("100.66.100.%d/32", n+1), 33100, privKey.String(), iface.DefaultMTU, newNet, nil)
wgIface, err := iface.NewWGIFace(fmt.Sprintf("utun230%d", n), fmt.Sprintf("100.66.100.%d/32", n+1), iface.DefaultMTU, nil, newNet)
if err != nil {
t.Fatal(err)
}
@@ -333,8 +331,7 @@ func TestDNSFakeResolverHandleUpdates(t *testing.T) {
return
}
privKey, _ := wgtypes.GeneratePrivateKey()
wgIface, err := iface.NewWGIFace("utun2301", "100.66.100.1/32", 33100, privKey.String(), iface.DefaultMTU, newNet, nil)
wgIface, err := iface.NewWGIFace("utun2301", "100.66.100.1/32", iface.DefaultMTU, nil, newNet)
if err != nil {
t.Errorf("build interface wireguard: %v", err)
return
@@ -530,8 +527,8 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
registeredMap: make(registrationMap),
},
hostManager: hostManager,
currentConfig: HostDNSConfig{
Domains: []DomainConfig{
currentConfig: hostDNSConfig{
domains: []domainConfig{
{false, "domain0", false},
{false, "domain1", false},
{false, "domain2", false},
@@ -540,13 +537,13 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
}
var domainsUpdate string
hostManager.applyDNSConfigFunc = func(config HostDNSConfig) error {
hostManager.applyDNSConfigFunc = func(config hostDNSConfig) error {
domains := []string{}
for _, item := range config.Domains {
if item.Disabled {
for _, item := range config.domains {
if item.disabled {
continue
}
domains = append(domains, item.Domain)
domains = append(domains, item.domain)
}
domainsUpdate = strings.Join(domains, ",")
return nil
@@ -562,11 +559,11 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
deactivate()
expected := "domain0,domain2"
domains := []string{}
for _, item := range server.currentConfig.Domains {
if item.Disabled {
for _, item := range server.currentConfig.domains {
if item.disabled {
continue
}
domains = append(domains, item.Domain)
domains = append(domains, item.domain)
}
got := strings.Join(domains, ",")
if expected != got {
@@ -576,11 +573,11 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
reactivate()
expected = "domain0,domain1,domain2"
domains = []string{}
for _, item := range server.currentConfig.Domains {
if item.Disabled {
for _, item := range server.currentConfig.domains {
if item.disabled {
continue
}
domains = append(domains, item.Domain)
domains = append(domains, item.domain)
}
got = strings.Join(domains, ",")
if expected != got {
@@ -785,8 +782,7 @@ func createWgInterfaceWithBind(t *testing.T) (*iface.WGIface, error) {
return nil, err
}
privKey, _ := wgtypes.GeneratePrivateKey()
wgIface, err := iface.NewWGIFace("utun2301", "100.66.100.2/24", 33100, privKey.String(), iface.DefaultMTU, newNet, nil)
wgIface, err := iface.NewWGIFace("utun2301", "100.66.100.2/24", iface.DefaultMTU, nil, newNet)
if err != nil {
t.Fatalf("build interface wireguard: %v", err)
return nil, err

View File

@@ -1,5 +0,0 @@
package dns
func (s *DefaultServer) initialize() (manager hostManager, err error) {
return newHostManager(s.wgInterface)
}

View File

@@ -81,8 +81,8 @@ func (s *systemdDbusConfigurator) supportCustomPort() bool {
return true
}
func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
parsedIP, err := netip.ParseAddr(config.ServerIP)
func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error {
parsedIP, err := netip.ParseAddr(config.serverIP)
if err != nil {
return fmt.Errorf("unable to parse ip address, error: %s", err)
}
@@ -93,7 +93,7 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
}
err = s.callLinkMethod(systemdDbusSetDNSMethodSuffix, []systemdDbusDNSInput{defaultLinkInput})
if err != nil {
return fmt.Errorf("setting the interface DNS server %s:%d failed with error: %s", config.ServerIP, config.ServerPort, err)
return fmt.Errorf("setting the interface DNS server %s:%d failed with error: %s", config.serverIP, config.serverPort, err)
}
var (
@@ -101,24 +101,24 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
matchDomains []string
domainsInput []systemdDbusLinkDomainsInput
)
for _, dConf := range config.Domains {
if dConf.Disabled {
for _, dConf := range config.domains {
if dConf.disabled {
continue
}
domainsInput = append(domainsInput, systemdDbusLinkDomainsInput{
Domain: dns.Fqdn(dConf.Domain),
MatchOnly: dConf.MatchOnly,
Domain: dns.Fqdn(dConf.domain),
MatchOnly: dConf.matchOnly,
})
if dConf.MatchOnly {
matchDomains = append(matchDomains, dConf.Domain)
if dConf.matchOnly {
matchDomains = append(matchDomains, dConf.domain)
continue
}
searchDomains = append(searchDomains, dConf.Domain)
searchDomains = append(searchDomains, dConf.domain)
}
if config.RouteAll {
log.Infof("configured %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort)
if config.routeAll {
log.Infof("configured %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort)
err = s.callLinkMethod(systemdDbusSetDefaultRouteMethodSuffix, true)
if err != nil {
return fmt.Errorf("setting link as default dns router, failed with error: %s", err)
@@ -129,7 +129,7 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
})
s.routingAll = true
} else if s.routingAll {
log.Infof("removing %s:%d as main DNS forwarder for this peer", config.ServerIP, config.ServerPort)
log.Infof("removing %s:%d as main DNS forwarder for this peer", config.serverIP, config.serverPort)
}
log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains)

View File

@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"net"
"runtime"
"sync"
"sync/atomic"
"time"
@@ -22,15 +21,10 @@ const (
)
type upstreamClient interface {
exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error)
ExchangeContext(ctx context.Context, m *dns.Msg, a string) (r *dns.Msg, rtt time.Duration, err error)
}
type UpstreamResolver interface {
serveDNS(r *dns.Msg) (*dns.Msg, time.Duration, error)
upstreamExchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error)
}
type upstreamResolverBase struct {
type upstreamResolver struct {
ctx context.Context
cancel context.CancelFunc
upstreamClient upstreamClient
@@ -46,25 +40,25 @@ type upstreamResolverBase struct {
reactivate func()
}
func newUpstreamResolverBase(parentCTX context.Context) *upstreamResolverBase {
func newUpstreamResolver(parentCTX context.Context) *upstreamResolver {
ctx, cancel := context.WithCancel(parentCTX)
return &upstreamResolverBase{
return &upstreamResolver{
ctx: ctx,
cancel: cancel,
upstreamClient: &dns.Client{},
upstreamTimeout: upstreamTimeout,
reactivatePeriod: reactivatePeriod,
failsTillDeact: failsTillDeact,
}
}
func (u *upstreamResolverBase) stop() {
func (u *upstreamResolver) stop() {
log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers)
u.cancel()
}
// ServeDNS handles a DNS request
func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
defer u.checkUpstreamFails()
log.WithField("question", r.Question[0]).Trace("received an upstream question")
@@ -76,8 +70,10 @@ func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
}
for _, upstream := range u.upstreamServers {
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
rm, t, err := u.upstreamClient.ExchangeContext(ctx, r, upstream)
rm, t, err := u.upstreamClient.exchange(upstream, r)
cancel()
if err != nil {
if err == context.DeadlineExceeded || isTimeout(err) {
@@ -87,19 +83,7 @@ func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
}
u.failsCount.Add(1)
log.WithError(err).WithField("upstream", upstream).
Error("got other error while querying the upstream")
return
}
if rm == nil {
log.WithError(err).WithField("upstream", upstream).
Warn("no response from upstream")
return
}
// those checks need to be independent of each other due to memory address issues
if !rm.Response {
log.WithError(err).WithField("upstream", upstream).
Warn("no response from upstream")
Error("got an error while querying the upstream")
return
}
@@ -122,7 +106,7 @@ func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
// If fails count is greater that failsTillDeact, upstream resolving
// will be disabled for reactivatePeriod, after that time period fails counter
// will be reset and upstream will be reactivated.
func (u *upstreamResolverBase) checkUpstreamFails() {
func (u *upstreamResolver) checkUpstreamFails() {
u.mutex.Lock()
defer u.mutex.Unlock()
@@ -134,18 +118,15 @@ func (u *upstreamResolverBase) checkUpstreamFails() {
case <-u.ctx.Done():
return
default:
// todo test the deactivation logic, it seems to affect the client
if runtime.GOOS != "ios" {
log.Warnf("upstream resolving is Disabled for %v", reactivatePeriod)
u.deactivate()
u.disabled = true
go u.waitUntilResponse()
}
log.Warnf("upstream resolving is disabled for %v", reactivatePeriod)
u.deactivate()
u.disabled = true
go u.waitUntilResponse()
}
}
// waitUntilResponse retries, in an exponential interval, querying the upstream servers until it gets a positive response
func (u *upstreamResolverBase) waitUntilResponse() {
func (u *upstreamResolver) waitUntilResponse() {
exponentialBackOff := &backoff.ExponentialBackOff{
InitialInterval: 500 * time.Millisecond,
RandomizationFactor: 0.5,
@@ -167,7 +148,10 @@ func (u *upstreamResolverBase) waitUntilResponse() {
var err error
for _, upstream := range u.upstreamServers {
_, _, err = u.upstreamClient.exchange(upstream, r)
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
_, _, err = u.upstreamClient.ExchangeContext(ctx, r, upstream)
cancel()
if err == nil {
return nil

View File

@@ -1,93 +0,0 @@
//go:build ios
package dns
import (
"context"
"net"
"syscall"
"time"
"github.com/miekg/dns"
log "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
type upstreamResolverIOS struct {
*upstreamResolverBase
lIP net.IP
lNet *net.IPNet
iIndex int
}
func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP, net *net.IPNet) (*upstreamResolverIOS, error) {
upstreamResolverBase := newUpstreamResolverBase(parentCTX)
index, err := getInterfaceIndex(interfaceName)
if err != nil {
log.Debugf("unable to get interface index for %s: %s", interfaceName, err)
return nil, err
}
ios := &upstreamResolverIOS{
upstreamResolverBase: upstreamResolverBase,
lIP: ip,
lNet: net,
iIndex: index,
}
ios.upstreamClient = ios
return ios, nil
}
func (u *upstreamResolverIOS) exchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) {
client := &dns.Client{}
upstreamHost, _, err := net.SplitHostPort(upstream)
if err != nil {
log.Errorf("error while parsing upstream host: %s", err)
}
upstreamIP := net.ParseIP(upstreamHost)
if u.lNet.Contains(upstreamIP) || net.IP.IsPrivate(upstreamIP) {
log.Debugf("using private client to query upstream: %s", upstream)
client = u.getClientPrivate()
}
return client.Exchange(r, upstream)
}
// getClientPrivate returns a new DNS client bound to the local IP address of the Netbird interface
// This method is needed for iOS
func (u *upstreamResolverIOS) getClientPrivate() *dns.Client {
dialer := &net.Dialer{
LocalAddr: &net.UDPAddr{
IP: u.lIP,
Port: 0, // Let the OS pick a free port
},
Timeout: upstreamTimeout,
Control: func(network, address string, c syscall.RawConn) error {
var operr error
fn := func(s uintptr) {
operr = unix.SetsockoptInt(int(s), unix.IPPROTO_IP, unix.IP_BOUND_IF, u.iIndex)
}
if err := c.Control(fn); err != nil {
return err
}
if operr != nil {
log.Errorf("error while setting socket option: %s", operr)
}
return operr
},
}
client := &dns.Client{
Dialer: dialer,
}
return client
}
func getInterfaceIndex(interfaceName string) (int, error) {
iface, err := net.InterfaceByName(interfaceName)
return iface.Index, err
}

View File

@@ -1,32 +0,0 @@
//go:build !ios
package dns
import (
"context"
"net"
"time"
"github.com/miekg/dns"
)
type upstreamResolverNonIOS struct {
*upstreamResolverBase
}
func newUpstreamResolver(parentCTX context.Context, interfaceName string, ip net.IP, net *net.IPNet) (*upstreamResolverNonIOS, error) {
upstreamResolverBase := newUpstreamResolverBase(parentCTX)
nonIOS := &upstreamResolverNonIOS{
upstreamResolverBase: upstreamResolverBase,
}
upstreamResolverBase.upstreamClient = nonIOS
return nonIOS, nil
}
func (u *upstreamResolverNonIOS) exchange(upstream string, r *dns.Msg) (rm *dns.Msg, t time.Duration, err error) {
upstreamExchangeClient := &dns.Client{}
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
rm, t, err = upstreamExchangeClient.ExchangeContext(ctx, r, upstream)
cancel()
return rm, t, err
}

View File

@@ -2,7 +2,6 @@ package dns
import (
"context"
"net"
"strings"
"testing"
"time"
@@ -50,6 +49,15 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) {
timeout: upstreamTimeout,
responseShouldBeNil: true,
},
//{
// name: "Should Resolve CNAME Record",
// inputMSG: new(dns.Msg).SetQuestion("one.one.one.one", dns.TypeCNAME),
//},
//{
// name: "Should Not Write When Not Found A Record",
// inputMSG: new(dns.Msg).SetQuestion("not.found.com", dns.TypeA),
// responseShouldBeNil: true,
//},
}
// should resolve if first upstream times out
// should not write when both fails
@@ -58,7 +66,7 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.TODO())
resolver, _ := newUpstreamResolver(ctx, "", net.IP{}, &net.IPNet{})
resolver := newUpstreamResolver(ctx)
resolver.upstreamServers = testCase.InputServers
resolver.upstreamTimeout = testCase.timeout
if testCase.cancelCTX {
@@ -106,12 +114,12 @@ type mockUpstreamResolver struct {
}
// ExchangeContext mock implementation of ExchangeContext from upstreamResolver
func (c mockUpstreamResolver) exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error) {
func (c mockUpstreamResolver) ExchangeContext(_ context.Context, _ *dns.Msg, _ string) (r *dns.Msg, rtt time.Duration, err error) {
return c.r, c.rtt, c.err
}
func TestUpstreamResolver_DeactivationReactivation(t *testing.T) {
resolver := &upstreamResolverBase{
resolver := &upstreamResolver{
ctx: context.TODO(),
upstreamClient: &mockUpstreamResolver{
err: nil,
@@ -148,7 +156,7 @@ func TestUpstreamResolver_DeactivationReactivation(t *testing.T) {
}
if !resolver.disabled {
t.Errorf("resolver should be Disabled")
t.Errorf("resolver should be disabled")
return
}

View File

@@ -1,5 +1,6 @@
// Code generated by bpf2go; DO NOT EDIT.
//go:build arm64be || armbe || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64
// +build arm64be armbe mips mips64 mips64p32 ppc64 s390 s390x sparc sparc64
package ebpf

View File

@@ -1,5 +1,6 @@
// Code generated by bpf2go; DO NOT EDIT.
//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64
//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64
// +build 386 amd64 amd64p32 arm arm64 mips64le mips64p32le mipsle ppc64le riscv64
package ebpf

View File

@@ -46,8 +46,8 @@ int xdp_dns_fwd(struct iphdr *ip, struct udphdr *udp) {
if(!read_settings()){
return XDP_PASS;
}
// bpf_printk("dns port: %d", ntohs(dns_port));
// bpf_printk("dns ip: %d", ntohl(dns_ip));
bpf_printk("dns port: %d", ntohs(dns_port));
bpf_printk("dns ip: %d", ntohl(dns_ip));
}
if (udp->dest == GENERAL_DNS_PORT && ip->daddr == dns_ip) {
@@ -61,4 +61,4 @@ int xdp_dns_fwd(struct iphdr *ip, struct udphdr *udp) {
}
return XDP_PASS;
}
}

View File

@@ -8,6 +8,12 @@
#include "dns_fwd.c"
#include "wg_proxy.c"
#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
const __u16 flag_feature_wg_proxy = 0b01;
const __u16 flag_feature_dns_fwd = 0b10;
@@ -57,4 +63,4 @@ int nb_xdp_prog(struct xdp_md *ctx) {
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
char _license[] SEC("license") = "GPL";

View File

@@ -1,12 +0,0 @@
# Debug
The CONFIG_BPF_EVENTS kernel module is required for bpf_printk.
Apply this code to use bpf_printk
```
#define bpf_printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
```

View File

@@ -34,7 +34,7 @@ int xdp_wg_proxy(struct iphdr *ip, struct udphdr *udp) {
if (!read_port_settings()){
return XDP_PASS;
}
// bpf_printk("proxy port: %d, wg port: %d", proxy_port, wg_port);
bpf_printk("proxy port: %d, wg port: %d", proxy_port, wg_port);
}
// 2130706433 = 127.0.0.1
@@ -51,4 +51,4 @@ int xdp_wg_proxy(struct iphdr *ip, struct udphdr *udp) {
udp->dest = new_dst_port;
udp->source = new_src_port;
return XDP_PASS;
}
}

View File

@@ -3,6 +3,7 @@ package internal
import (
"context"
"fmt"
"io"
"math/rand"
"net"
"net/netip"
@@ -12,8 +13,7 @@ import (
"sync"
"time"
"github.com/pion/ice/v3"
"github.com/pion/stun/v2"
"github.com/pion/ice/v2"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -22,7 +22,6 @@ import (
"github.com/netbirdio/netbird/client/internal/acl"
"github.com/netbirdio/netbird/client/internal/dns"
"github.com/netbirdio/netbird/client/internal/peer"
"github.com/netbirdio/netbird/client/internal/rosenpass"
"github.com/netbirdio/netbird/client/internal/routemanager"
"github.com/netbirdio/netbird/client/internal/wgproxy"
nbssh "github.com/netbirdio/netbird/client/ssh"
@@ -32,6 +31,7 @@ import (
mgm "github.com/netbirdio/netbird/management/client"
mgmProto "github.com/netbirdio/netbird/management/proto"
"github.com/netbirdio/netbird/route"
"github.com/netbirdio/netbird/sharedsock"
signal "github.com/netbirdio/netbird/signal/client"
sProto "github.com/netbirdio/netbird/signal/proto"
"github.com/netbirdio/netbird/util"
@@ -77,8 +77,6 @@ type EngineConfig struct {
NATExternalIPs []string
CustomDNSAddress string
RosenpassEnabled bool
}
// Engine is a mechanism responsible for reacting on Signal and Management stream events and managing connections to the remote peers.
@@ -89,8 +87,6 @@ type Engine struct {
mgmClient mgm.Client
// peerConns is a map that holds all the peers that are known to this peer
peerConns map[string]*peer.Conn
// rpManager is a Rosenpass manager
rpManager *rosenpass.Manager
// syncMsgMux is used to guarantee sequential Management Service message processing
syncMsgMux *sync.Mutex
@@ -99,9 +95,9 @@ type Engine struct {
mobileDep MobileDependency
// STUNs is a list of STUN servers used by ICE
STUNs []*stun.URI
STUNs []*ice.URL
// TURNs is a list of STUN servers used by ICE
TURNs []*stun.URI
TURNs []*ice.URL
cancel context.CancelFunc
@@ -110,7 +106,8 @@ type Engine struct {
wgInterface *iface.WGIface
wgProxyFactory *wgproxy.Factory
udpMux *bind.UniversalUDPMuxDefault
udpMux *bind.UniversalUDPMuxDefault
udpMuxConn io.Closer
// networkSerial is the latest CurrentSerial (state ID) of the network sent by the Management service
networkSerial uint64
@@ -149,8 +146,8 @@ func NewEngine(
syncMsgMux: &sync.Mutex{},
config: config,
mobileDep: mobileDep,
STUNs: []*stun.URI{},
TURNs: []*stun.URI{},
STUNs: []*ice.URL{},
TURNs: []*ice.URL{},
networkSerial: 0,
sshServerFunc: nbssh.DefaultSSHServer,
statusRecorder: statusRecorder,
@@ -183,38 +180,56 @@ func (e *Engine) Start() error {
e.syncMsgMux.Lock()
defer e.syncMsgMux.Unlock()
wgIface, err := e.newWgIface()
wgIFaceName := e.config.WgIfaceName
wgAddr := e.config.WgAddr
myPrivateKey := e.config.WgPrivateKey
var err error
transportNet, err := e.newStdNet()
if err != nil {
log.Errorf("failed creating wireguard interface instance %s: [%s]", e.config.WgIfaceName, err.Error())
log.Errorf("failed to create pion's stdnet: %s", err)
}
e.wgInterface, err = iface.NewWGIFace(wgIFaceName, wgAddr, iface.DefaultMTU, e.mobileDep.TunAdapter, transportNet)
if err != nil {
log.Errorf("failed creating wireguard interface instance %s: [%s]", wgIFaceName, err.Error())
return err
}
e.wgInterface = wgIface
if e.config.RosenpassEnabled {
log.Infof("rosenpass is enabled")
e.rpManager, err = rosenpass.NewManager(e.config.PreSharedKey, e.config.WgIfaceName)
var routes []*route.Route
if runtime.GOOS == "android" {
var dnsConfig *nbdns.Config
routes, dnsConfig, err = e.readInitialSettings()
if err != nil {
return err
}
err := e.rpManager.Run()
if e.dnsServer == nil {
e.dnsServer = dns.NewDefaultServerPermanentUpstream(e.ctx, e.wgInterface, e.mobileDep.HostDNSAddresses, *dnsConfig, e.mobileDep.NetworkChangeListener)
go e.mobileDep.DnsReadyListener.OnReady()
}
} else if e.dnsServer == nil {
// todo fix custom address
e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress)
if err != nil {
e.close()
return err
}
}
initialRoutes, dnsServer, err := e.newDnsServer()
if err != nil {
e.close()
return err
}
e.dnsServer = dnsServer
e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, initialRoutes)
e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes)
e.routeManager.SetRouteChangeListener(e.mobileDep.NetworkChangeListener)
err = e.wgInterfaceCreate()
if runtime.GOOS == "android" {
err = e.wgInterface.CreateOnMobile(iface.MobileIFaceArguments{
Routes: e.routeManager.InitialRouteRange(),
Dns: e.dnsServer.DnsIP(),
SearchDomains: e.dnsServer.SearchDomains(),
})
} else {
err = e.wgInterface.Create()
}
if err != nil {
log.Errorf("failed creating tunnel interface %s: [%s]", e.config.WgIfaceName, err.Error())
log.Errorf("failed creating tunnel interface %s: [%s]", wgIFaceName, err.Error())
e.close()
return err
}
@@ -232,13 +247,33 @@ func (e *Engine) Start() error {
}
}
e.udpMux, err = e.wgInterface.Up()
err = e.wgInterface.Configure(myPrivateKey.String(), e.config.WgPort)
if err != nil {
log.Errorf("failed to pull up wgInterface [%s]: %s", e.wgInterface.Name(), err.Error())
log.Errorf("failed configuring Wireguard interface [%s]: %s", wgIFaceName, err.Error())
e.close()
return err
}
if e.wgInterface.IsUserspaceBind() {
iceBind := e.wgInterface.GetBind()
udpMux, err := iceBind.GetICEMux()
if err != nil {
e.close()
return err
}
e.udpMux = udpMux
log.Infof("using userspace bind mode %s", udpMux.LocalAddr().String())
} else {
rawSock, err := sharedsock.Listen(e.config.WgPort, sharedsock.NewIncomingSTUNFilter())
if err != nil {
return err
}
mux := bind.NewUniversalUDPMuxDefault(bind.UniversalUDPMuxParams{UDPConn: rawSock, Net: transportNet})
go mux.ReadFromConn(e.ctx)
e.udpMuxConn = rawSock
e.udpMux = mux
}
if e.firewall != nil {
e.acl = acl.NewDefaultManager(e.firewall)
}
@@ -380,8 +415,7 @@ func sendSignal(message *sProto.Message, s signal.Client) error {
}
// SignalOfferAnswer signals either an offer or an answer to remote peer
func SignalOfferAnswer(offerAnswer peer.OfferAnswer, myKey wgtypes.Key, remoteKey wgtypes.Key, s signal.Client,
isAnswer bool) error {
func SignalOfferAnswer(offerAnswer peer.OfferAnswer, myKey wgtypes.Key, remoteKey wgtypes.Key, s signal.Client, isAnswer bool) error {
var t sProto.Body_Type
if isAnswer {
t = sProto.Body_ANSWER
@@ -392,7 +426,7 @@ func SignalOfferAnswer(offerAnswer peer.OfferAnswer, myKey wgtypes.Key, remoteKe
msg, err := signal.MarshalCredential(myKey, offerAnswer.WgListenPort, remoteKey, &signal.Credential{
UFrag: offerAnswer.IceCredentials.UFrag,
Pwd: offerAnswer.IceCredentials.Pwd,
}, t, offerAnswer.RosenpassPubKey, offerAnswer.RosenpassAddr)
}, t)
if err != nil {
return err
}
@@ -446,7 +480,7 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
}
// start SSH server if it wasn't running
if isNil(e.sshServer) {
// nil sshServer means it has not yet been started
//nil sshServer means it has not yet been started
var err error
e.sshServer, err = e.sshServerFunc(e.config.SSHKey,
fmt.Sprintf("%s:%d", e.wgInterface.Address().IP.String(), nbssh.DefaultSSHPort))
@@ -494,7 +528,7 @@ func (e *Engine) updateConfig(conf *mgmProto.PeerConfig) error {
if conf.GetSshConfig() != nil {
err := e.updateSSH(conf.GetSshConfig())
if err != nil {
log.Warnf("failed handling SSH server setup %v", err)
log.Warnf("failed handling SSH server setup %v", e)
}
}
@@ -531,10 +565,10 @@ func (e *Engine) updateSTUNs(stuns []*mgmProto.HostConfig) error {
if len(stuns) == 0 {
return nil
}
var newSTUNs []*stun.URI
var newSTUNs []*ice.URL
log.Debugf("got STUNs update from Management Service, updating")
for _, s := range stuns {
url, err := stun.ParseURI(s.Uri)
for _, stun := range stuns {
url, err := ice.ParseURL(stun.Uri)
if err != nil {
return err
}
@@ -549,10 +583,10 @@ func (e *Engine) updateTURNs(turns []*mgmProto.ProtectedHostConfig) error {
if len(turns) == 0 {
return nil
}
var newTURNs []*stun.URI
var newTURNs []*ice.URL
log.Debugf("got TURNs update from Management Service, updating")
for _, turn := range turns {
url, err := stun.ParseURI(turn.HostConfig.Uri)
url, err := ice.ParseURL(turn.HostConfig.Uri)
if err != nil {
return err
}
@@ -645,7 +679,6 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
e.acl.ApplyFiltering(networkMap)
}
e.networkSerial = serial
return nil
}
@@ -803,7 +836,7 @@ func (e *Engine) peerExists(peerKey string) bool {
func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, error) {
log.Debugf("creating peer connection %s", pubKey)
var stunTurn []*stun.URI
var stunTurn []*ice.URL
stunTurn = append(stunTurn, e.STUNs...)
stunTurn = append(stunTurn, e.TURNs...)
@@ -815,26 +848,6 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, e
PreSharedKey: e.config.PreSharedKey,
}
if e.config.RosenpassEnabled {
lk := []byte(e.config.WgPrivateKey.PublicKey().String())
rk := []byte(wgConfig.RemoteKey)
var keyInput []byte
if string(lk) > string(rk) {
//nolint:gocritic
keyInput = append(lk[:16], rk[:16]...)
} else {
//nolint:gocritic
keyInput = append(rk[:16], lk[:16]...)
}
key, err := wgtypes.NewKey(keyInput)
if err != nil {
return nil, err
}
wgConfig.PreSharedKey = &key
}
// randomize connection timeout
timeout := time.Duration(rand.Intn(PeerConnectionTimeoutMax-PeerConnectionTimeoutMin)+PeerConnectionTimeoutMin) * time.Millisecond
config := peer.ConnConfig{
@@ -850,8 +863,6 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, e
LocalWgPort: e.config.WgPort,
NATExternalIPs: e.parseNATExternalIPMappings(),
UserspaceBind: e.wgInterface.IsUserspaceBind(),
RosenpassPubKey: e.getRosenpassPubKey(),
RosenpassAddr: e.getRosenpassAddr(),
}
peerConn, err := peer.NewConn(config, e.statusRecorder, e.wgProxyFactory, e.mobileDep.TunAdapter, e.mobileDep.IFaceDiscover)
@@ -883,12 +894,6 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, e
return sendSignal(message, e.signal)
})
if e.rpManager != nil {
peerConn.SetOnConnected(e.rpManager.OnConnected)
peerConn.SetOnDisconnected(e.rpManager.OnDisconnected)
}
return peerConn, nil
}
@@ -914,21 +919,13 @@ func (e *Engine) receiveSignalEvents() {
conn.RegisterProtoSupportMeta(msg.Body.GetFeaturesSupported())
var rosenpassPubKey []byte
rosenpassAddr := ""
if msg.GetBody().GetRosenpassConfig() != nil {
rosenpassPubKey = msg.GetBody().GetRosenpassConfig().GetRosenpassPubKey()
rosenpassAddr = msg.GetBody().GetRosenpassConfig().GetRosenpassServerAddr()
}
conn.OnRemoteOffer(peer.OfferAnswer{
IceCredentials: peer.IceCredentials{
UFrag: remoteCred.UFrag,
Pwd: remoteCred.Pwd,
},
WgListenPort: int(msg.GetBody().GetWgListenPort()),
Version: msg.GetBody().GetNetBirdVersion(),
RosenpassPubKey: rosenpassPubKey,
RosenpassAddr: rosenpassAddr,
WgListenPort: int(msg.GetBody().GetWgListenPort()),
Version: msg.GetBody().GetNetBirdVersion(),
})
case sProto.Body_ANSWER:
remoteCred, err := signal.UnMarshalCredential(msg)
@@ -936,23 +933,15 @@ func (e *Engine) receiveSignalEvents() {
return err
}
conn.RegisterProtoSupportMeta(msg.GetBody().GetFeaturesSupported())
conn.RegisterProtoSupportMeta(msg.Body.GetFeaturesSupported())
var rosenpassPubKey []byte
rosenpassAddr := ""
if msg.GetBody().GetRosenpassConfig() != nil {
rosenpassPubKey = msg.GetBody().GetRosenpassConfig().GetRosenpassPubKey()
rosenpassAddr = msg.GetBody().GetRosenpassConfig().GetRosenpassServerAddr()
}
conn.OnRemoteAnswer(peer.OfferAnswer{
IceCredentials: peer.IceCredentials{
UFrag: remoteCred.UFrag,
Pwd: remoteCred.Pwd,
},
WgListenPort: int(msg.GetBody().GetWgListenPort()),
Version: msg.GetBody().GetNetBirdVersion(),
RosenpassPubKey: rosenpassPubKey,
RosenpassAddr: rosenpassAddr,
WgListenPort: int(msg.GetBody().GetWgListenPort()),
Version: msg.GetBody().GetNetBirdVersion(),
})
case sProto.Body_CANDIDATE:
candidate, err := ice.UnmarshalCandidate(msg.GetBody().Payload)
@@ -1042,6 +1031,18 @@ func (e *Engine) close() {
}
}
if e.udpMux != nil {
if err := e.udpMux.Close(); err != nil {
log.Debugf("close udp mux: %v", err)
}
}
if e.udpMuxConn != nil {
if err := e.udpMuxConn.Close(); err != nil {
log.Debugf("close udp mux connection: %v", err)
}
}
if !isNil(e.sshServer) {
err := e.sshServer.Stop()
if err != nil {
@@ -1063,10 +1064,6 @@ func (e *Engine) close() {
log.Warnf("failed to reset firewall: %s", err)
}
}
if e.rpManager != nil {
_ = e.rpManager.Close()
}
}
func (e *Engine) readInitialSettings() ([]*route.Route, *nbdns.Config, error) {
@@ -1079,68 +1076,6 @@ func (e *Engine) readInitialSettings() ([]*route.Route, *nbdns.Config, error) {
return routes, &dnsCfg, nil
}
func (e *Engine) newWgIface() (*iface.WGIface, error) {
transportNet, err := e.newStdNet()
if err != nil {
log.Errorf("failed to create pion's stdnet: %s", err)
}
var mArgs *iface.MobileIFaceArguments
switch runtime.GOOS {
case "android":
mArgs = &iface.MobileIFaceArguments{
TunAdapter: e.mobileDep.TunAdapter,
TunFd: int(e.mobileDep.FileDescriptor),
}
case "ios":
mArgs = &iface.MobileIFaceArguments{
TunFd: int(e.mobileDep.FileDescriptor),
}
default:
}
return iface.NewWGIFace(e.config.WgIfaceName, e.config.WgAddr, e.config.WgPort, e.config.WgPrivateKey.String(), iface.DefaultMTU, transportNet, mArgs)
}
func (e *Engine) wgInterfaceCreate() (err error) {
switch runtime.GOOS {
case "android":
err = e.wgInterface.CreateOnAndroid(e.routeManager.InitialRouteRange(), e.dnsServer.DnsIP(), e.dnsServer.SearchDomains())
case "ios":
e.mobileDep.NetworkChangeListener.SetInterfaceIP(e.config.WgAddr)
err = e.wgInterface.Create()
default:
err = e.wgInterface.Create()
}
return err
}
func (e *Engine) newDnsServer() ([]*route.Route, dns.Server, error) {
// due to tests where we are using a mocked version of the DNS server
if e.dnsServer != nil {
return nil, e.dnsServer, nil
}
switch runtime.GOOS {
case "android":
routes, dnsConfig, err := e.readInitialSettings()
if err != nil {
return nil, nil, err
}
dnsServer := dns.NewDefaultServerPermanentUpstream(e.ctx, e.wgInterface, e.mobileDep.HostDNSAddresses, *dnsConfig, e.mobileDep.NetworkChangeListener)
go e.mobileDep.DnsReadyListener.OnReady()
return routes, dnsServer, nil
case "ios":
dnsServer := dns.NewDefaultServerIos(e.ctx, e.wgInterface, e.mobileDep.DnsManager)
return nil, dnsServer, nil
default:
dnsServer, err := dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress)
if err != nil {
return nil, nil, err
}
return nil, dnsServer, nil
}
}
func findIPFromInterfaceName(ifaceName string) (net.IP, error) {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
@@ -1161,17 +1096,3 @@ func findIPFromInterface(iface *net.Interface) (net.IP, error) {
}
return nil, fmt.Errorf("interface %s don't have an ipv4 address", iface.Name)
}
func (e *Engine) getRosenpassPubKey() []byte {
if e.rpManager != nil {
return e.rpManager.GetPubKey()
}
return nil
}
func (e *Engine) getRosenpassAddr() string {
if e.rpManager != nil {
return e.rpManager.GetAddress().String()
}
return ""
}

View File

@@ -13,7 +13,7 @@ import (
"testing"
"time"
"github.com/pion/transport/v3/stdnet"
"github.com/pion/transport/v2/stdnet"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -213,7 +213,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
if err != nil {
t.Fatal(err)
}
engine.wgInterface, err = iface.NewWGIFace("utun102", "100.64.0.1/24", engine.config.WgPort, key.String(), iface.DefaultMTU, newNet, nil)
engine.wgInterface, err = iface.NewWGIFace("utun102", "100.64.0.1/24", iface.DefaultMTU, nil, newNet)
if err != nil {
t.Fatal(err)
}
@@ -567,7 +567,7 @@ func TestEngine_UpdateNetworkMapWithRoutes(t *testing.T) {
if err != nil {
t.Fatal(err)
}
engine.wgInterface, err = iface.NewWGIFace(wgIfaceName, wgAddr, engine.config.WgPort, key.String(), iface.DefaultMTU, newNet, nil)
engine.wgInterface, err = iface.NewWGIFace(wgIfaceName, wgAddr, iface.DefaultMTU, nil, newNet)
assert.NoError(t, err, "shouldn't return error")
input := struct {
inputSerial uint64
@@ -736,7 +736,7 @@ func TestEngine_UpdateNetworkMapWithDNSUpdate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
engine.wgInterface, err = iface.NewWGIFace(wgIfaceName, wgAddr, 33100, key.String(), iface.DefaultMTU, newNet, nil)
engine.wgInterface, err = iface.NewWGIFace(wgIfaceName, wgAddr, iface.DefaultMTU, nil, newNet)
assert.NoError(t, err, "shouldn't return error")
mockRouteManager := &routemanager.MockManager{

View File

@@ -3,6 +3,5 @@ package listener
// NetworkChangeListener is a callback interface for mobile system
type NetworkChangeListener interface {
// OnNetworkChanged invoke when network settings has been changed
OnNetworkChanged(string)
SetInterfaceIP(string)
OnNetworkChanged()
}

View File

@@ -9,14 +9,9 @@ import (
// MobileDependency collect all dependencies for mobile platform
type MobileDependency struct {
// Android only
TunAdapter iface.TunAdapter
IFaceDiscover stdnet.ExternalIFaceDiscover
NetworkChangeListener listener.NetworkChangeListener
HostDNSAddresses []string
DnsReadyListener dns.ReadyListener
// iOS only
DnsManager dns.IosDnsManager
FileDescriptor int32
}

View File

@@ -4,13 +4,11 @@ import (
"context"
"fmt"
"net"
"runtime"
"strings"
"sync"
"time"
"github.com/pion/ice/v3"
"github.com/pion/stun/v2"
"github.com/pion/ice/v2"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -47,7 +45,7 @@ type ConnConfig struct {
LocalKey string
// StunTurn is a list of STUN and TURN URLs
StunTurn []*stun.URI
StunTurn []*ice.URL
// InterfaceBlackList is a list of machine interfaces that should be filtered out by ICE Candidate gathering
// (e.g. if eth0 is in the list, host candidate of this interface won't be used)
@@ -67,11 +65,6 @@ type ConnConfig struct {
// UsesBind indicates whether the WireGuard interface is userspace and uses bind.ICEBind
UserspaceBind bool
// RosenpassPubKey is this peer's Rosenpass public key
RosenpassPubKey []byte
// RosenpassPubKey is this peer's RosenpassAddr server address (IP:port)
RosenpassAddr string
}
// OfferAnswer represents a session establishment offer or answer
@@ -84,12 +77,6 @@ type OfferAnswer struct {
// Version of NetBird Agent
Version string
// RosenpassPubKey is the Rosenpass public key of the remote peer when receiving this message
// This value is the local Rosenpass server public key when sending the message
RosenpassPubKey []byte
// RosenpassAddr is the Rosenpass server address (IP:port) of the remote peer when receiving this message
// This value is the local Rosenpass server address when sending the message
RosenpassAddr string
}
// IceCredentials ICE protocol credentials struct
@@ -108,8 +95,6 @@ type Conn struct {
signalOffer func(OfferAnswer) error
signalAnswer func(OfferAnswer) error
sendSignalMessage func(message *sProto.Message) error
onConnected func(remoteWireGuardKey string, remoteRosenpassPubKey []byte, wireGuardIP string, remoteRosenpassAddr string)
onDisconnected func(remotePeer string, wgIP string)
// remoteOffersCh is a channel used to wait for remote credentials to proceed with the connection
remoteOffersCh chan OfferAnswer
@@ -156,7 +141,7 @@ func (conn *Conn) WgConfig() WgConfig {
}
// UpdateStunTurn update the turn and stun addresses
func (conn *Conn) UpdateStunTurn(turnStun []*stun.URI) {
func (conn *Conn) UpdateStunTurn(turnStun []*ice.URL) {
conn.config.StunTurn = turnStun
}
@@ -240,10 +225,6 @@ func (conn *Conn) candidateTypes() []ice.CandidateType {
if hasICEForceRelayConn() {
return []ice.CandidateType{ice.CandidateTypeRelay}
}
// TODO: remove this once we have refactored userspace proxy into the bind package
if runtime.GOOS == "ios" {
return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive}
}
return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive, ice.CandidateTypeRelay}
}
@@ -348,8 +329,7 @@ func (conn *Conn) Open() error {
remoteWgPort = remoteOfferAnswer.WgListenPort
}
// the ice connection has been established successfully so we are ready to start the proxy
remoteAddr, err := conn.configureConnection(remoteConn, remoteWgPort, remoteOfferAnswer.RosenpassPubKey,
remoteOfferAnswer.RosenpassAddr)
remoteAddr, err := conn.configureConnection(remoteConn, remoteWgPort)
if err != nil {
return err
}
@@ -372,7 +352,7 @@ func isRelayCandidate(candidate ice.Candidate) bool {
}
// configureConnection starts proxying traffic from/to local Wireguard and sets connection status to StatusConnected
func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int, remoteRosenpassPubKey []byte, remoteRosenpassAddr string) (net.Addr, error) {
func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int) (net.Addr, error) {
conn.mu.Lock()
defer conn.mu.Unlock()
@@ -390,7 +370,7 @@ func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int, rem
return nil, err
}
} else {
// To support old version's with direct mode we attempt to punch an additional role with the remote WireGuard port
// To support old version's with direct mode we attempt to punch an additional role with the remote wireguard port
go conn.punchRemoteWGPort(pair, remoteWgPort)
endpoint = remoteConn.RemoteAddr()
}
@@ -424,15 +404,6 @@ func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int, rem
log.Warnf("unable to save peer's state, got error: %v", err)
}
_, ipNet, err := net.ParseCIDR(conn.config.WgConfig.AllowedIps)
if err != nil {
return nil, err
}
if conn.onConnected != nil {
conn.onConnected(conn.config.Key, remoteRosenpassPubKey, ipNet.IP.String(), remoteRosenpassAddr)
}
return endpoint, nil
}
@@ -483,10 +454,6 @@ func (conn *Conn) cleanup() error {
conn.notifyDisconnected = nil
}
if conn.status == StatusConnected && conn.onDisconnected != nil {
conn.onDisconnected(conn.config.WgConfig.RemoteKey, conn.config.WgConfig.AllowedIps)
}
conn.status = StatusDisconnected
peerState := State{
@@ -497,7 +464,7 @@ func (conn *Conn) cleanup() error {
err := conn.statusRecorder.UpdatePeerState(peerState)
if err != nil {
// pretty common error because by that time Engine can already remove the peer and status won't be available.
// todo rethink status updates
//todo rethink status updates
log.Debugf("error while updating peer's %s state, err: %v", conn.config.Key, err)
}
@@ -516,16 +483,6 @@ func (conn *Conn) SetSignalOffer(handler func(offer OfferAnswer) error) {
conn.signalOffer = handler
}
// SetOnConnected sets a handler function to be triggered by Conn when a new connection to a remote peer established
func (conn *Conn) SetOnConnected(handler func(remoteWireGuardKey string, remoteRosenpassPubKey []byte, wireGuardIP string, remoteRosenpassAddr string)) {
conn.onConnected = handler
}
// SetOnDisconnected sets a handler function to be triggered by Conn when a connection to a remote disconnected
func (conn *Conn) SetOnDisconnected(handler func(remotePeer string, wgIP string)) {
conn.onDisconnected = handler
}
// SetSignalAnswer sets a handler function to be triggered by Conn when a new connection answer has to be signalled to the remote peer
func (conn *Conn) SetSignalAnswer(handler func(answer OfferAnswer) error) {
conn.signalAnswer = handler
@@ -580,11 +537,9 @@ func (conn *Conn) sendAnswer() error {
log.Debugf("sending answer to %s", conn.config.Key)
err = conn.signalAnswer(OfferAnswer{
IceCredentials: IceCredentials{localUFrag, localPwd},
WgListenPort: conn.config.LocalWgPort,
Version: version.NetbirdVersion(),
RosenpassPubKey: conn.config.RosenpassPubKey,
RosenpassAddr: conn.config.RosenpassAddr,
IceCredentials: IceCredentials{localUFrag, localPwd},
WgListenPort: conn.config.LocalWgPort,
Version: version.NetbirdVersion(),
})
if err != nil {
return err
@@ -603,11 +558,9 @@ func (conn *Conn) sendOffer() error {
return err
}
err = conn.signalOffer(OfferAnswer{
IceCredentials: IceCredentials{localUFrag, localPwd},
WgListenPort: conn.config.LocalWgPort,
Version: version.NetbirdVersion(),
RosenpassPubKey: conn.config.RosenpassPubKey,
RosenpassAddr: conn.config.RosenpassAddr,
IceCredentials: IceCredentials{localUFrag, localPwd},
WgListenPort: conn.config.LocalWgPort,
Version: version.NetbirdVersion(),
})
if err != nil {
return err

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/magiconair/properties/assert"
"github.com/pion/stun/v2"
"github.com/pion/ice/v2"
"github.com/netbirdio/netbird/client/internal/stdnet"
"github.com/netbirdio/netbird/client/internal/wgproxy"
@@ -16,7 +16,7 @@ import (
var connConf = ConnConfig{
Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
StunTurn: []*stun.URI{},
StunTurn: []*ice.URL{},
InterfaceBlackList: nil,
Timeout: time.Second,
LocalWgPort: 51820,

View File

@@ -1,204 +0,0 @@
package rosenpass
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"log/slog"
"net"
"os"
"strconv"
"strings"
"sync"
rp "cunicu.li/go-rosenpass"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
func hashRosenpassKey(key []byte) string {
hasher := sha256.New()
hasher.Write(key)
return hex.EncodeToString(hasher.Sum(nil))
}
type Manager struct {
ifaceName string
spk []byte
ssk []byte
rpKeyHash string
preSharedKey *[32]byte
rpPeerIDs map[string]*rp.PeerID
rpWgHandler *NetbirdHandler
server *rp.Server
lock sync.Mutex
port int
}
// NewManager creates a new Rosenpass manager
func NewManager(preSharedKey *wgtypes.Key, wgIfaceName string) (*Manager, error) {
public, secret, err := rp.GenerateKeyPair()
if err != nil {
return nil, err
}
rpKeyHash := hashRosenpassKey(public)
log.Debugf("generated new rosenpass key pair with public key %s", rpKeyHash)
return &Manager{ifaceName: wgIfaceName, rpKeyHash: rpKeyHash, spk: public, ssk: secret, preSharedKey: (*[32]byte)(preSharedKey), rpPeerIDs: make(map[string]*rp.PeerID), lock: sync.Mutex{}}, nil
}
func (m *Manager) GetPubKey() []byte {
return m.spk
}
// GetAddress returns the address of the Rosenpass server
func (m *Manager) GetAddress() *net.UDPAddr {
return &net.UDPAddr{Port: m.port}
}
// addPeer adds a new peer to the Rosenpass server
func (m *Manager) addPeer(rosenpassPubKey []byte, rosenpassAddr string, wireGuardIP string, wireGuardPubKey string) error {
var err error
pcfg := rp.PeerConfig{PublicKey: rosenpassPubKey}
if m.preSharedKey != nil {
pcfg.PresharedKey = *m.preSharedKey
}
if bytes.Compare(m.spk, rosenpassPubKey) == 1 {
_, strPort, err := net.SplitHostPort(rosenpassAddr)
if err != nil {
return fmt.Errorf("failed to parse rosenpass address: %w", err)
}
peerAddr := fmt.Sprintf("%s:%s", wireGuardIP, strPort)
if pcfg.Endpoint, err = net.ResolveUDPAddr("udp", peerAddr); err != nil {
return fmt.Errorf("failed to resolve peer endpoint address: %w", err)
}
}
peerID, err := m.server.AddPeer(pcfg)
if err != nil {
return err
}
key, err := wgtypes.ParseKey(wireGuardPubKey)
if err != nil {
return err
}
m.rpWgHandler.AddPeer(peerID, m.ifaceName, rp.Key(key))
m.rpPeerIDs[wireGuardPubKey] = &peerID
return nil
}
// removePeer removes a peer from the Rosenpass server
func (m *Manager) removePeer(wireGuardPubKey string) error {
err := m.server.RemovePeer(*m.rpPeerIDs[wireGuardPubKey])
if err != nil {
return err
}
m.rpWgHandler.RemovePeer(*m.rpPeerIDs[wireGuardPubKey])
return nil
}
func (m *Manager) generateConfig() (rp.Config, error) {
opts := &slog.HandlerOptions{
Level: slog.LevelDebug,
}
logger := slog.New(slog.NewTextHandler(os.Stdout, opts))
cfg := rp.Config{Logger: logger}
cfg.PublicKey = m.spk
cfg.SecretKey = m.ssk
cfg.Peers = []rp.PeerConfig{}
m.rpWgHandler, _ = NewNetbirdHandler(m.preSharedKey, m.ifaceName)
cfg.Handlers = []rp.Handler{m.rpWgHandler}
port, err := findRandomAvailableUDPPort()
if err != nil {
log.Errorf("could not determine a random port for rosenpass server. Error: %s", err)
return rp.Config{}, err
}
m.port = port
cfg.ListenAddrs = []*net.UDPAddr{m.GetAddress()}
return cfg, nil
}
func (m *Manager) OnDisconnected(peerKey string, wgIP string) {
m.lock.Lock()
defer m.lock.Unlock()
if _, ok := m.rpPeerIDs[peerKey]; !ok {
// if we didn't have this peer yet, just skip
return
}
err := m.removePeer(peerKey)
if err != nil {
log.Error("failed to remove rosenpass peer", err)
}
delete(m.rpPeerIDs, peerKey)
}
// Run starts the Rosenpass server
func (m *Manager) Run() error {
conf, err := m.generateConfig()
if err != nil {
return err
}
m.server, err = rp.NewUDPServer(conf)
if err != nil {
return err
}
log.Infof("starting rosenpass server on port %d", m.port)
return m.server.Run()
}
// Close closes the Rosenpass server
func (m *Manager) Close() error {
if m.server != nil {
err := m.server.Close()
if err != nil {
log.Errorf("failed closing local rosenpass server")
}
m.server = nil
}
return nil
}
// OnConnected is a handler function that is triggered when a connection to a remote peer establishes
func (m *Manager) OnConnected(remoteWireGuardKey string, remoteRosenpassPubKey []byte, wireGuardIP string, remoteRosenpassAddr string) {
m.lock.Lock()
defer m.lock.Unlock()
if remoteRosenpassPubKey == nil {
log.Warnf("remote peer with public key %s does not support rosenpass", remoteWireGuardKey)
return
}
rpKeyHash := hashRosenpassKey(remoteRosenpassPubKey)
log.Debugf("received remote rosenpass key %s, my key %s", rpKeyHash, m.rpKeyHash)
err := m.addPeer(remoteRosenpassPubKey, remoteRosenpassAddr, wireGuardIP, remoteWireGuardKey)
if err != nil {
log.Errorf("failed to add rosenpass peer: %s", err)
return
}
}
func findRandomAvailableUDPPort() (int, error) {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
if err != nil {
return 0, fmt.Errorf("could not find an available UDP port: %w", err)
}
defer conn.Close()
splitAddress := strings.Split(conn.LocalAddr().String(), ":")
return strconv.Atoi(splitAddress[len(splitAddress)-1])
}

View File

@@ -1,126 +0,0 @@
package rosenpass
import (
"fmt"
"log/slog"
rp "cunicu.li/go-rosenpass"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
type wireGuardPeer struct {
Interface string
PublicKey rp.Key
}
type NetbirdHandler struct {
ifaceName string
client *wgctrl.Client
peers map[rp.PeerID]wireGuardPeer
presharedKey [32]byte
}
func NewNetbirdHandler(preSharedKey *[32]byte, wgIfaceName string) (hdlr *NetbirdHandler, err error) {
hdlr = &NetbirdHandler{
ifaceName: wgIfaceName,
peers: map[rp.PeerID]wireGuardPeer{},
}
if preSharedKey != nil {
hdlr.presharedKey = *preSharedKey
}
if hdlr.client, err = wgctrl.New(); err != nil {
return nil, fmt.Errorf("failed to creat WireGuard client: %w", err)
}
return hdlr, nil
}
func (h *NetbirdHandler) AddPeer(pid rp.PeerID, intf string, pk rp.Key) {
h.peers[pid] = wireGuardPeer{
Interface: intf,
PublicKey: pk,
}
}
func (h *NetbirdHandler) RemovePeer(pid rp.PeerID) {
delete(h.peers, pid)
}
func (h *NetbirdHandler) HandshakeCompleted(pid rp.PeerID, key rp.Key) {
log.Debug("Handshake complete")
h.outputKey(rp.KeyOutputReasonStale, pid, key)
}
func (h *NetbirdHandler) HandshakeExpired(pid rp.PeerID) {
key, _ := rp.GeneratePresharedKey()
log.Debug("Handshake expired")
h.outputKey(rp.KeyOutputReasonStale, pid, key)
}
func (h *NetbirdHandler) outputKey(_ rp.KeyOutputReason, pid rp.PeerID, psk rp.Key) {
wg, ok := h.peers[pid]
if !ok {
return
}
device, err := h.client.Device(h.ifaceName)
if err != nil {
log.Errorf("Failed to get WireGuard device: %v", err)
return
}
config := []wgtypes.PeerConfig{
{
UpdateOnly: true,
PublicKey: wgtypes.Key(wg.PublicKey),
PresharedKey: (*wgtypes.Key)(&psk),
},
}
for _, peer := range device.Peers {
if peer.PublicKey == wgtypes.Key(wg.PublicKey) {
if publicKeyEmpty(peer.PresharedKey) || peer.PresharedKey == h.presharedKey {
log.Debugf("Restart wireguard connection to peer %s", peer.PublicKey)
config = []wgtypes.PeerConfig{
{
PublicKey: wgtypes.Key(wg.PublicKey),
PresharedKey: (*wgtypes.Key)(&psk),
Endpoint: peer.Endpoint,
AllowedIPs: peer.AllowedIPs,
},
}
err = h.client.ConfigureDevice(wg.Interface, wgtypes.Config{
Peers: []wgtypes.PeerConfig{
{
Remove: true,
PublicKey: wgtypes.Key(wg.PublicKey),
},
},
})
if err != nil {
slog.Debug("Failed to remove peer")
return
}
}
}
}
if err = h.client.ConfigureDevice(wg.Interface, wgtypes.Config{
Peers: config,
}); err != nil {
log.Errorf("Failed to apply rosenpass key: %v", err)
}
}
func publicKeyEmpty(key wgtypes.Key) bool {
for _, b := range key {
if b != 0 {
return false
}
}
return true
}

View File

@@ -7,8 +7,7 @@ import (
"runtime"
"testing"
"github.com/pion/transport/v3/stdnet"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/pion/transport/v2/stdnet"
"github.com/stretchr/testify/require"
@@ -400,12 +399,12 @@ func TestManagerUpdateRoutes(t *testing.T) {
for n, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
peerPrivateKey, _ := wgtypes.GeneratePrivateKey()
newNet, err := stdnet.NewNet()
if err != nil {
t.Fatal(err)
}
wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun43%d", n), "100.65.65.2/24", 33100, peerPrivateKey.String(), iface.DefaultMTU, newNet, nil)
wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun43%d", n), "100.65.65.2/24", iface.DefaultMTU, nil, newNet)
require.NoError(t, err, "should create testing WGIface interface")
defer wgInterface.Close()

View File

@@ -2,7 +2,6 @@ package routemanager
import (
"sort"
"strings"
"sync"
"github.com/netbirdio/netbird/client/internal/listener"
@@ -45,12 +44,15 @@ func (n *notifier) onNewRoutes(idMap map[string][]*route.Route) {
}
sort.Strings(newNets)
if !n.hasDiff(n.initialRouteRangers, newNets) {
if !n.hasDiff(n.routeRangers, newNets) {
return
}
n.routeRangers = newNets
if !n.hasDiff(n.initialRouteRangers, newNets) {
return
}
n.notify()
}
@@ -62,7 +64,7 @@ func (n *notifier) notify() {
}
go func(l listener.NetworkChangeListener) {
l.OnNetworkChanged(strings.Join(n.routeRangers, ","))
l.OnNetworkChanged()
}(n.listener)
}

View File

@@ -1,5 +1,3 @@
//go:build android
package routemanager
import (

View File

@@ -1,15 +0,0 @@
//go:build ios
package routemanager
import (
"net/netip"
)
func addToRouteTableIfNoExists(prefix netip.Prefix, addr string) error {
return nil
}
func removeFromRouteTableIfNonSystem(prefix netip.Prefix, addr string) error {
return nil
}

View File

@@ -1,4 +1,4 @@
//go:build !android && !ios
//go:build !android
package routemanager

View File

@@ -11,10 +11,9 @@ import (
"strings"
"testing"
"github.com/pion/transport/v3/stdnet"
"github.com/pion/transport/v2/stdnet"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/netbirdio/netbird/iface"
)
@@ -42,12 +41,11 @@ func TestAddRemoveRoutes(t *testing.T) {
for n, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
peerPrivateKey, _ := wgtypes.GeneratePrivateKey()
newNet, err := stdnet.NewNet()
if err != nil {
t.Fatal(err)
}
wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", 33100, peerPrivateKey.String(), iface.DefaultMTU, newNet, nil)
wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet)
require.NoError(t, err, "should create testing WGIface interface")
defer wgInterface.Close()
@@ -177,12 +175,11 @@ func TestAddExistAndRemoveRouteNonAndroid(t *testing.T) {
log.SetOutput(os.Stderr)
}()
t.Run(testCase.name, func(t *testing.T) {
peerPrivateKey, _ := wgtypes.GeneratePrivateKey()
newNet, err := stdnet.NewNet()
if err != nil {
t.Fatal(err)
}
wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", 33100, peerPrivateKey.String(), iface.DefaultMTU, newNet, nil)
wgInterface, err := iface.NewWGIFace(fmt.Sprintf("utun53%d", n), "100.65.75.2/24", iface.DefaultMTU, nil, newNet)
require.NoError(t, err, "should create testing WGIface interface")
defer wgInterface.Close()

View File

@@ -1,6 +1,6 @@
package stdnet
import "github.com/pion/transport/v3"
import "github.com/pion/transport/v2"
// ExternalIFaceDiscover provide an option for external services (mobile)
// to collect network interface information

View File

@@ -5,7 +5,7 @@ import (
"net"
"strings"
"github.com/pion/transport/v3"
"github.com/pion/transport/v2"
log "github.com/sirupsen/logrus"
)

View File

@@ -3,7 +3,7 @@ package stdnet
import (
"net"
"github.com/pion/transport/v3"
"github.com/pion/transport/v2"
)
type pionDiscover struct {

View File

@@ -6,8 +6,8 @@ package stdnet
import (
"fmt"
"github.com/pion/transport/v3"
"github.com/pion/transport/v3/stdnet"
"github.com/pion/transport/v2"
"github.com/pion/transport/v2/stdnet"
)
// Net is an implementation of the net.Net interface

View File

@@ -1,224 +0,0 @@
package NetBirdSDK
import (
"context"
"sync"
"time"
log "github.com/sirupsen/logrus"
"github.com/netbirdio/netbird/client/internal"
"github.com/netbirdio/netbird/client/internal/auth"
"github.com/netbirdio/netbird/client/internal/dns"
"github.com/netbirdio/netbird/client/internal/listener"
"github.com/netbirdio/netbird/client/internal/peer"
"github.com/netbirdio/netbird/client/system"
"github.com/netbirdio/netbird/formatter"
)
// ConnectionListener export internal Listener for mobile
type ConnectionListener interface {
peer.Listener
}
// RouteListener export internal RouteListener for mobile
type NetworkChangeListener interface {
listener.NetworkChangeListener
}
// DnsManager export internal dns Manager for mobile
type DnsManager interface {
dns.IosDnsManager
}
// CustomLogger export internal CustomLogger for mobile
type CustomLogger interface {
Debug(message string)
Info(message string)
Error(message string)
}
func init() {
formatter.SetLogcatFormatter(log.StandardLogger())
}
// Client struct manage the life circle of background service
type Client struct {
cfgFile string
recorder *peer.Status
ctxCancel context.CancelFunc
ctxCancelLock *sync.Mutex
deviceName string
osName string
osVersion string
networkChangeListener listener.NetworkChangeListener
onHostDnsFn func([]string)
dnsManager dns.IosDnsManager
loginComplete bool
}
// NewClient instantiate a new Client
func NewClient(cfgFile, deviceName string, osVersion string, osName string, networkChangeListener NetworkChangeListener, dnsManager DnsManager) *Client {
return &Client{
cfgFile: cfgFile,
deviceName: deviceName,
osName: osName,
osVersion: osVersion,
recorder: peer.NewRecorder(""),
ctxCancelLock: &sync.Mutex{},
networkChangeListener: networkChangeListener,
dnsManager: dnsManager,
}
}
// Run start the internal client. It is a blocker function
func (c *Client) Run(fd int32, interfaceName string) error {
log.Infof("Starting NetBird client")
log.Debugf("Tunnel uses interface: %s", interfaceName)
cfg, err := internal.UpdateOrCreateConfig(internal.ConfigInput{
ConfigPath: c.cfgFile,
})
if err != nil {
return err
}
c.recorder.UpdateManagementAddress(cfg.ManagementURL.String())
var ctx context.Context
//nolint
ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName)
//nolint
ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName)
//nolint
ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion)
c.ctxCancelLock.Lock()
ctx, c.ctxCancel = context.WithCancel(ctxWithValues)
defer c.ctxCancel()
c.ctxCancelLock.Unlock()
auth := NewAuthWithConfig(ctx, cfg)
err = auth.Login()
if err != nil {
return err
}
log.Infof("Auth successful")
// todo do not throw error in case of cancelled context
ctx = internal.CtxInitState(ctx)
c.onHostDnsFn = func([]string) {}
cfg.WgIface = interfaceName
return internal.RunClientiOS(ctx, cfg, c.recorder, fd, c.networkChangeListener, c.dnsManager)
}
// Stop the internal client and free the resources
func (c *Client) Stop() {
c.ctxCancelLock.Lock()
defer c.ctxCancelLock.Unlock()
if c.ctxCancel == nil {
return
}
c.ctxCancel()
}
// ÏSetTraceLogLevel configure the logger to trace level
func (c *Client) SetTraceLogLevel() {
log.SetLevel(log.TraceLevel)
}
// getStatusDetails return with the list of the PeerInfos
func (c *Client) GetStatusDetails() *StatusDetails {
fullStatus := c.recorder.GetFullStatus()
peerInfos := make([]PeerInfo, len(fullStatus.Peers))
for n, p := range fullStatus.Peers {
pi := PeerInfo{
p.IP,
p.FQDN,
p.ConnStatus.String(),
}
peerInfos[n] = pi
}
return &StatusDetails{items: peerInfos, fqdn: fullStatus.LocalPeerState.FQDN, ip: fullStatus.LocalPeerState.IP}
}
// SetConnectionListener set the network connection listener
func (c *Client) SetConnectionListener(listener ConnectionListener) {
c.recorder.SetConnectionListener(listener)
}
// RemoveConnectionListener remove connection listener
func (c *Client) RemoveConnectionListener() {
c.recorder.RemoveConnectionListener()
}
func (c *Client) IsLoginRequired() bool {
var ctx context.Context
//nolint
ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName)
//nolint
ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName)
//nolint
ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion)
c.ctxCancelLock.Lock()
defer c.ctxCancelLock.Unlock()
ctx, c.ctxCancel = context.WithCancel(ctxWithValues)
cfg, _ := internal.UpdateOrCreateConfig(internal.ConfigInput{
ConfigPath: c.cfgFile,
})
needsLogin, _ := internal.IsLoginRequired(ctx, cfg.PrivateKey, cfg.ManagementURL, cfg.SSHKey)
return needsLogin
}
func (c *Client) LoginForMobile() string {
var ctx context.Context
//nolint
ctxWithValues := context.WithValue(context.Background(), system.DeviceNameCtxKey, c.deviceName)
//nolint
ctxWithValues = context.WithValue(ctxWithValues, system.OsNameCtxKey, c.osName)
//nolint
ctxWithValues = context.WithValue(ctxWithValues, system.OsVersionCtxKey, c.osVersion)
c.ctxCancelLock.Lock()
defer c.ctxCancelLock.Unlock()
ctx, c.ctxCancel = context.WithCancel(ctxWithValues)
cfg, _ := internal.UpdateOrCreateConfig(internal.ConfigInput{
ConfigPath: c.cfgFile,
})
oAuthFlow, err := auth.NewOAuthFlow(ctx, cfg, false)
if err != nil {
return err.Error()
}
flowInfo, err := oAuthFlow.RequestAuthInfo(context.TODO())
if err != nil {
return err.Error()
}
// This could cause a potential race condition with loading the extension which need to be handled on swift side
go func() {
waitTimeout := time.Duration(flowInfo.ExpiresIn) * time.Second
waitCTX, cancel := context.WithTimeout(ctx, waitTimeout)
defer cancel()
tokenInfo, err := oAuthFlow.WaitToken(waitCTX, flowInfo)
if err != nil {
return
}
jwtToken := tokenInfo.GetTokenToUse()
_ = internal.Login(ctx, cfg, "", jwtToken)
c.loginComplete = true
}()
return flowInfo.VerificationURIComplete
}
func (c *Client) IsLoginComplete() bool {
return c.loginComplete
}
func (c *Client) ClearLoginComplete() {
c.loginComplete = false
}

View File

@@ -1,5 +0,0 @@
package NetBirdSDK
import _ "golang.org/x/mobile/bind"
// to keep our CI/CD that checks go.mod and go.sum files happy, we need to import the package above

View File

@@ -1,10 +0,0 @@
package NetBirdSDK
import (
"github.com/netbirdio/netbird/util"
)
// InitializeLog initializes the log file.
func InitializeLog(logLevel string, filePath string) error {
return util.InitLog(logLevel, filePath)
}

View File

@@ -1,159 +0,0 @@
package NetBirdSDK
import (
"context"
"fmt"
"time"
"github.com/cenkalti/backoff/v4"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
gstatus "google.golang.org/grpc/status"
"github.com/netbirdio/netbird/client/cmd"
"github.com/netbirdio/netbird/client/internal"
"github.com/netbirdio/netbird/client/system"
)
// SSOListener is async listener for mobile framework
type SSOListener interface {
OnSuccess(bool)
OnError(error)
}
// ErrListener is async listener for mobile framework
type ErrListener interface {
OnSuccess()
OnError(error)
}
// URLOpener it is a callback interface. The Open function will be triggered if
// the backend want to show an url for the user
type URLOpener interface {
Open(string)
}
// Auth can register or login new client
type Auth struct {
ctx context.Context
config *internal.Config
cfgPath string
}
// NewAuth instantiate Auth struct and validate the management URL
func NewAuth(cfgPath string, mgmURL string) (*Auth, error) {
inputCfg := internal.ConfigInput{
ManagementURL: mgmURL,
}
cfg, err := internal.CreateInMemoryConfig(inputCfg)
if err != nil {
return nil, err
}
return &Auth{
ctx: context.Background(),
config: cfg,
cfgPath: cfgPath,
}, nil
}
// NewAuthWithConfig instantiate Auth based on existing config
func NewAuthWithConfig(ctx context.Context, config *internal.Config) *Auth {
return &Auth{
ctx: ctx,
config: config,
}
}
// SaveConfigIfSSOSupported test the connectivity with the management server by retrieving the server device flow info.
// If it returns a flow info than save the configuration and return true. If it gets a codes.NotFound, it means that SSO
// is not supported and returns false without saving the configuration. For other errors return false.
func (a *Auth) SaveConfigIfSSOSupported() (bool, error) {
supportsSSO := true
err := a.withBackOff(a.ctx, func() (err error) {
_, err = internal.GetDeviceAuthorizationFlowInfo(a.ctx, a.config.PrivateKey, a.config.ManagementURL)
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.NotFound || s.Code() == codes.Unimplemented) {
_, err = internal.GetPKCEAuthorizationFlowInfo(a.ctx, a.config.PrivateKey, a.config.ManagementURL)
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.NotFound || s.Code() == codes.Unimplemented) {
supportsSSO = false
err = nil
}
return err
}
return err
})
if !supportsSSO {
return false, nil
}
if err != nil {
return false, fmt.Errorf("backoff cycle failed: %v", err)
}
err = internal.WriteOutConfig(a.cfgPath, a.config)
return true, err
}
// LoginWithSetupKeyAndSaveConfig test the connectivity with the management server with the setup key.
func (a *Auth) LoginWithSetupKeyAndSaveConfig(setupKey string, deviceName string) error {
//nolint
ctxWithValues := context.WithValue(a.ctx, system.DeviceNameCtxKey, deviceName)
err := a.withBackOff(a.ctx, func() error {
backoffErr := internal.Login(ctxWithValues, a.config, setupKey, "")
if s, ok := gstatus.FromError(backoffErr); ok && (s.Code() == codes.PermissionDenied) {
// we got an answer from management, exit backoff earlier
return backoff.Permanent(backoffErr)
}
return backoffErr
})
if err != nil {
return fmt.Errorf("backoff cycle failed: %v", err)
}
return internal.WriteOutConfig(a.cfgPath, a.config)
}
func (a *Auth) Login() error {
var needsLogin bool
// check if we need to generate JWT token
err := a.withBackOff(a.ctx, func() (err error) {
needsLogin, err = internal.IsLoginRequired(a.ctx, a.config.PrivateKey, a.config.ManagementURL, a.config.SSHKey)
return
})
if err != nil {
return fmt.Errorf("backoff cycle failed: %v", err)
}
jwtToken := ""
if needsLogin {
return fmt.Errorf("Not authenticated")
}
err = a.withBackOff(a.ctx, func() error {
err := internal.Login(a.ctx, a.config, "", jwtToken)
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
return nil
}
return err
})
if err != nil {
return fmt.Errorf("backoff cycle failed: %v", err)
}
return nil
}
func (a *Auth) withBackOff(ctx context.Context, bf func() error) error {
return backoff.RetryNotify(
bf,
backoff.WithContext(cmd.CLIBackOffSettings, ctx),
func(err error, duration time.Duration) {
log.Warnf("retrying Login to the Management service in %v due to error %v", duration, err)
})
}

View File

@@ -1,50 +0,0 @@
package NetBirdSDK
// PeerInfo describe information about the peers. It designed for the UI usage
type PeerInfo struct {
IP string
FQDN string
ConnStatus string // Todo replace to enum
}
// PeerInfoCollection made for Java layer to get non default types as collection
type PeerInfoCollection interface {
Add(s string) PeerInfoCollection
Get(i int) string
Size() int
GetFQDN() string
GetIP() string
}
// StatusDetails is the implementation of the PeerInfoCollection
type StatusDetails struct {
items []PeerInfo
fqdn string
ip string
}
// Add new PeerInfo to the collection
func (array StatusDetails) Add(s PeerInfo) StatusDetails {
array.items = append(array.items, s)
return array
}
// Get return an element of the collection
func (array StatusDetails) Get(i int) *PeerInfo {
return &array.items[i]
}
// Size return with the size of the collection
func (array StatusDetails) Size() int {
return len(array.items)
}
// GetFQDN return with the FQDN of the local peer
func (array StatusDetails) GetFQDN() string {
return array.fqdn
}
// GetIP return with the IP of the local peer
func (array StatusDetails) GetIP() string {
return array.ip
}

View File

@@ -1,78 +0,0 @@
package NetBirdSDK
import (
"github.com/netbirdio/netbird/client/internal"
)
// Preferences export a subset of the internal config for gomobile
type Preferences struct {
configInput internal.ConfigInput
}
// NewPreferences create new Preferences instance
func NewPreferences(configPath string) *Preferences {
ci := internal.ConfigInput{
ConfigPath: configPath,
}
return &Preferences{ci}
}
// GetManagementURL read url from config file
func (p *Preferences) GetManagementURL() (string, error) {
if p.configInput.ManagementURL != "" {
return p.configInput.ManagementURL, nil
}
cfg, err := internal.ReadConfig(p.configInput.ConfigPath)
if err != nil {
return "", err
}
return cfg.ManagementURL.String(), err
}
// SetManagementURL store the given url and wait for commit
func (p *Preferences) SetManagementURL(url string) {
p.configInput.ManagementURL = url
}
// GetAdminURL read url from config file
func (p *Preferences) GetAdminURL() (string, error) {
if p.configInput.AdminURL != "" {
return p.configInput.AdminURL, nil
}
cfg, err := internal.ReadConfig(p.configInput.ConfigPath)
if err != nil {
return "", err
}
return cfg.AdminURL.String(), err
}
// SetAdminURL store the given url and wait for commit
func (p *Preferences) SetAdminURL(url string) {
p.configInput.AdminURL = url
}
// GetPreSharedKey read preshared key from config file
func (p *Preferences) GetPreSharedKey() (string, error) {
if p.configInput.PreSharedKey != nil {
return *p.configInput.PreSharedKey, nil
}
cfg, err := internal.ReadConfig(p.configInput.ConfigPath)
if err != nil {
return "", err
}
return cfg.PreSharedKey, err
}
// SetPreSharedKey store the given key and wait for commit
func (p *Preferences) SetPreSharedKey(key string) {
p.configInput.PreSharedKey = &key
}
// Commit write out the changes into config file
func (p *Preferences) Commit() error {
_, err := internal.UpdateOrCreateConfig(p.configInput)
return err
}

View File

@@ -1,120 +0,0 @@
package NetBirdSDK
import (
"path/filepath"
"testing"
"github.com/netbirdio/netbird/client/internal"
)
func TestPreferences_DefaultValues(t *testing.T) {
cfgFile := filepath.Join(t.TempDir(), "netbird.json")
p := NewPreferences(cfgFile)
defaultVar, err := p.GetAdminURL()
if err != nil {
t.Fatalf("failed to read default value: %s", err)
}
if defaultVar != internal.DefaultAdminURL {
t.Errorf("invalid default admin url: %s", defaultVar)
}
defaultVar, err = p.GetManagementURL()
if err != nil {
t.Fatalf("failed to read default management URL: %s", err)
}
if defaultVar != internal.DefaultManagementURL {
t.Errorf("invalid default management url: %s", defaultVar)
}
var preSharedKey string
preSharedKey, err = p.GetPreSharedKey()
if err != nil {
t.Fatalf("failed to read default preshared key: %s", err)
}
if preSharedKey != "" {
t.Errorf("invalid preshared key: %s", preSharedKey)
}
}
func TestPreferences_ReadUncommitedValues(t *testing.T) {
exampleString := "exampleString"
cfgFile := filepath.Join(t.TempDir(), "netbird.json")
p := NewPreferences(cfgFile)
p.SetAdminURL(exampleString)
resp, err := p.GetAdminURL()
if err != nil {
t.Fatalf("failed to read admin url: %s", err)
}
if resp != exampleString {
t.Errorf("unexpected admin url: %s", resp)
}
p.SetManagementURL(exampleString)
resp, err = p.GetManagementURL()
if err != nil {
t.Fatalf("failed to read management url: %s", err)
}
if resp != exampleString {
t.Errorf("unexpected management url: %s", resp)
}
p.SetPreSharedKey(exampleString)
resp, err = p.GetPreSharedKey()
if err != nil {
t.Fatalf("failed to read preshared key: %s", err)
}
if resp != exampleString {
t.Errorf("unexpected preshared key: %s", resp)
}
}
func TestPreferences_Commit(t *testing.T) {
exampleURL := "https://myurl.com:443"
examplePresharedKey := "topsecret"
cfgFile := filepath.Join(t.TempDir(), "netbird.json")
p := NewPreferences(cfgFile)
p.SetAdminURL(exampleURL)
p.SetManagementURL(exampleURL)
p.SetPreSharedKey(examplePresharedKey)
err := p.Commit()
if err != nil {
t.Fatalf("failed to save changes: %s", err)
}
p = NewPreferences(cfgFile)
resp, err := p.GetAdminURL()
if err != nil {
t.Fatalf("failed to read admin url: %s", err)
}
if resp != exampleURL {
t.Errorf("unexpected admin url: %s", resp)
}
resp, err = p.GetManagementURL()
if err != nil {
t.Fatalf("failed to read management url: %s", err)
}
if resp != exampleURL {
t.Errorf("unexpected management url: %s", resp)
}
resp, err = p.GetPreSharedKey()
if err != nil {
t.Fatalf("failed to read preshared key: %s", err)
}
if resp != examplePresharedKey {
t.Errorf("unexpected preshared key: %s", resp)
}
}

View File

@@ -20,7 +20,6 @@
<Shortcut Id="NetbirdStartMenuShortcut" Directory="StartMenuFolder" Name="NetBird" WorkingDirectory="NetbirdInstallDir" Icon="NetbirdIcon" />
</File>
<File ProcessorArchitecture="x64" Source=".\dist\netbird_windows_amd64\wintun.dll" />
<File ProcessorArchitecture="x64" Source=".\dist\netbird_windows_amd64\opengl32.dll" />
<ServiceInstall
Id="NetBirdService"

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.9
// protoc v4.23.4
// source: daemon.proto
package proto
@@ -40,13 +40,10 @@ type LoginRequest struct {
// cleanNATExternalIPs clean map list of external IPs.
// This is needed because the generated code
// omits initialized empty slices due to omitempty tags
CleanNATExternalIPs bool `protobuf:"varint,6,opt,name=cleanNATExternalIPs,proto3" json:"cleanNATExternalIPs,omitempty"`
CustomDNSAddress []byte `protobuf:"bytes,7,opt,name=customDNSAddress,proto3" json:"customDNSAddress,omitempty"`
IsLinuxDesktopClient bool `protobuf:"varint,8,opt,name=isLinuxDesktopClient,proto3" json:"isLinuxDesktopClient,omitempty"`
Hostname string `protobuf:"bytes,9,opt,name=hostname,proto3" json:"hostname,omitempty"`
RosenpassEnabled *bool `protobuf:"varint,10,opt,name=rosenpassEnabled,proto3,oneof" json:"rosenpassEnabled,omitempty"`
InterfaceName *string `protobuf:"bytes,11,opt,name=interfaceName,proto3,oneof" json:"interfaceName,omitempty"`
WireguardPort *int64 `protobuf:"varint,12,opt,name=wireguardPort,proto3,oneof" json:"wireguardPort,omitempty"`
CleanNATExternalIPs bool `protobuf:"varint,6,opt,name=cleanNATExternalIPs,proto3" json:"cleanNATExternalIPs,omitempty"`
CustomDNSAddress []byte `protobuf:"bytes,7,opt,name=customDNSAddress,proto3" json:"customDNSAddress,omitempty"`
IsLinuxDesktopClient bool `protobuf:"varint,8,opt,name=isLinuxDesktopClient,proto3" json:"isLinuxDesktopClient,omitempty"`
Hostname string `protobuf:"bytes,9,opt,name=hostname,proto3" json:"hostname,omitempty"`
}
func (x *LoginRequest) Reset() {
@@ -144,27 +141,6 @@ func (x *LoginRequest) GetHostname() string {
return ""
}
func (x *LoginRequest) GetRosenpassEnabled() bool {
if x != nil && x.RosenpassEnabled != nil {
return *x.RosenpassEnabled
}
return false
}
func (x *LoginRequest) GetInterfaceName() string {
if x != nil && x.InterfaceName != nil {
return *x.InterfaceName
}
return ""
}
func (x *LoginRequest) GetWireguardPort() int64 {
if x != nil && x.WireguardPort != nil {
return *x.WireguardPort
}
return 0
}
type LoginResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1091,7 +1067,7 @@ var file_daemon_proto_rawDesc = []byte{
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa6, 0x04, 0x0a, 0x0c, 0x4c, 0x6f,
0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe6, 0x02, 0x0a, 0x0c, 0x4c, 0x6f,
0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65,
0x74, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65,
0x74, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x53, 0x68, 0x61,
@@ -1114,19 +1090,7 @@ var file_daemon_proto_rawDesc = []byte{
0x52, 0x14, 0x69, 0x73, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70,
0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x10, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x45,
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x10,
0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0d, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x29,
0x0a, 0x0d, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x03, 0x48, 0x02, 0x52, 0x0d, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61,
0x72, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x88, 0x01, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x72, 0x6f,
0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x10,
0x0a, 0x0e, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x50, 0x6f,
0x72, 0x74, 0x22, 0xb5, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6d, 0x65, 0x22, 0xb5, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x53, 0x53, 0x4f,
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x65, 0x65,
0x64, 0x73, 0x53, 0x53, 0x4f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
@@ -1522,7 +1486,6 @@ func file_daemon_proto_init() {
}
}
}
file_daemon_proto_msgTypes[0].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{

View File

@@ -54,13 +54,6 @@ message LoginRequest {
bool isLinuxDesktopClient = 8;
string hostname = 9;
optional bool rosenpassEnabled = 10;
optional string interfaceName = 11;
optional int64 wireguardPort = 12;
}
message LoginResponse {

View File

@@ -94,7 +94,7 @@ func (s *Server) Start() error {
}
// if configuration exists, we just start connections.
config, _ = internal.UpdateOldManagementURL(ctx, config, s.latestConfigInput.ConfigPath)
config, _ = internal.UpdateOldManagementPort(ctx, config, s.latestConfigInput.ConfigPath)
s.config = config
@@ -187,22 +187,6 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
ctx = context.WithValue(ctx, system.DeviceNameCtxKey, msg.Hostname)
}
if msg.RosenpassEnabled != nil {
inputConfig.RosenpassEnabled = msg.RosenpassEnabled
s.latestConfigInput.RosenpassEnabled = msg.RosenpassEnabled
}
if msg.InterfaceName != nil {
inputConfig.InterfaceName = msg.InterfaceName
s.latestConfigInput.InterfaceName = msg.InterfaceName
}
if msg.WireguardPort != nil {
port := int(*msg.WireguardPort)
inputConfig.WireguardPort = &port
s.latestConfigInput.WireguardPort = &port
}
s.mutex.Unlock()
inputConfig.PreSharedKey = &msg.PreSharedKey
@@ -213,7 +197,7 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
}
if msg.ManagementUrl == "" {
config, _ = internal.UpdateOldManagementURL(ctx, config, s.latestConfigInput.ConfigPath)
config, _ = internal.UpdateOldManagementPort(ctx, config, s.latestConfigInput.ConfigPath)
s.config = config
s.latestConfigInput.ManagementURL = config.ManagementURL.String()
}

View File

@@ -12,12 +12,6 @@ import (
// DeviceNameCtxKey context key for device name
const DeviceNameCtxKey = "deviceName"
// OsVersionCtxKey context key for operating system version
const OsVersionCtxKey = "OsVersion"
// OsNameCtxKey context key for operating system name
const OsNameCtxKey = "OsName"
// Info is an object that contains machine information
// Most of the code is taken from https://github.com/matishsiao/goInfo
type Info struct {

View File

@@ -1,6 +1,3 @@
//go:build !ios
// +build !ios
package system
import (

View File

@@ -1,44 +0,0 @@
//go:build ios
// +build ios
package system
import (
"context"
"runtime"
"github.com/netbirdio/netbird/version"
)
// GetInfo retrieves and parses the system information
func GetInfo(ctx context.Context) *Info {
// Convert fixed-size byte arrays to Go strings
sysName := extractOsName(ctx, "sysName")
swVersion := extractOsVersion(ctx, "swVersion")
gio := &Info{Kernel: sysName, OSVersion: swVersion, Core: swVersion, Platform: "unknown", OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()}
gio.Hostname = extractDeviceName(ctx, "hostname")
gio.WiretrusteeVersion = version.NetbirdVersion()
gio.UIVersion = extractUserAgent(ctx)
return gio
}
// extractOsVersion extracts operating system version from context or returns the default
func extractOsVersion(ctx context.Context, defaultName string) string {
v, ok := ctx.Value(OsVersionCtxKey).(string)
if !ok {
return defaultName
}
return v
}
// extractOsName extracts operating system name from context or returns the default
func extractOsName(ctx context.Context, defaultName string) string {
v, ok := ctx.Value(OsNameCtxKey).(string)
if !ok {
return defaultName
}
return v
}

View File

@@ -36,8 +36,7 @@ func getOSNameAndVersion() (string, string) {
query := wmi.CreateQuery(&dst, "")
err := wmi.Query(query, &dst)
if err != nil {
log.Error(err)
return "Windows", getBuildVersion()
log.Fatal(err)
}
if len(dst) == 0 {

View File

@@ -563,8 +563,8 @@ func (s *serviceClient) getSrvClient(timeout time.Duration) (proto.DaemonService
// getSrvConfig from the service to show it in the settings window.
func (s *serviceClient) getSrvConfig() {
s.managementURL = internal.DefaultManagementURL
s.adminURL = internal.DefaultAdminURL
s.managementURL = "https://api.wiretrustee.com:33073"
s.adminURL = "https://app.netbird.io"
conn, err := s.getSrvClient(failFastTimeout)
if err != nil {

66
go.mod
View File

@@ -1,30 +1,26 @@
module github.com/netbirdio/netbird
go 1.21
toolchain go1.21.0
go 1.20
require (
cunicu.li/go-rosenpass v0.4.0
github.com/cenkalti/backoff/v4 v4.1.3
github.com/cloudflare/circl v1.3.3 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.1
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.18.1
github.com/pion/ice/v3 v3.0.2
github.com/pion/ice/v2 v2.3.1
github.com/rs/cors v1.8.0
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
github.com/vishvananda/netlink v1.1.0
golang.org/x/crypto v0.14.0
golang.org/x/sys v0.13.0
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20211215182854-7a385b3431de
golang.zx2c4.com/wireguard/windows v0.5.3
google.golang.org/grpc v1.56.3
google.golang.org/protobuf v1.30.0
@@ -34,8 +30,9 @@ require (
require (
fyne.io/fyne/v2 v2.1.4
github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
github.com/c-robinson/iplib v1.0.3
github.com/cilium/ebpf v0.11.0
github.com/cilium/ebpf v0.10.0
github.com/coreos/go-iptables v0.7.0
github.com/creack/pty v1.1.18
github.com/eko/gocache/v3 v3.1.1
@@ -51,33 +48,32 @@ require (
github.com/libp2p/go-netroute v0.2.0
github.com/magiconair/properties v1.8.5
github.com/mattn/go-sqlite3 v1.14.17
github.com/mdlayher/socket v0.4.1
github.com/mdlayher/socket v0.4.0
github.com/miekg/dns v1.1.43
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/nadoo/ipset v0.5.0
github.com/netbirdio/management-integrations/additions v0.0.0-20231230192609-a9dcce34ff86
github.com/netbirdio/management-integrations/integrations v0.0.0-20231230192609-a9dcce34ff86
github.com/netbirdio/management-integrations/additions v0.0.0-20231205113053-c462587ae695
github.com/netbirdio/management-integrations/integrations v0.0.0-20231205113053-c462587ae695
github.com/okta/okta-sdk-golang/v2 v2.18.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pion/logging v0.2.2
github.com/pion/stun/v2 v2.0.0
github.com/pion/transport/v3 v3.0.1
github.com/pion/stun v0.4.0
github.com/pion/transport/v2 v2.0.2
github.com/prometheus/client_golang v1.14.0
github.com/rs/xid v1.3.0
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/stretchr/testify v1.8.4
github.com/things-go/go-socks5 v0.0.4
github.com/stretchr/testify v1.8.1
github.com/yusufpapurcu/wmi v1.2.3
go.opentelemetry.io/otel v1.11.1
go.opentelemetry.io/otel/exporters/prometheus v0.33.0
go.opentelemetry.io/otel/metric v0.33.0
go.opentelemetry.io/otel/sdk/metric v0.33.0
goauthentik.io/api/v3 v3.2023051.3
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090
golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028
golang.org/x/net v0.17.0
golang.org/x/oauth2 v0.8.0
golang.org/x/sync v0.3.0
golang.org/x/sync v0.2.0
golang.org/x/term v0.13.0
google.golang.org/api v0.126.0
gopkg.in/yaml.v3 v3.0.1
@@ -118,24 +114,23 @@ require (
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.10.0 // indirect
github.com/gopacket/gopacket v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/josharian/native v1.0.0 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/genetlink v1.1.0 // indirect
github.com/mdlayher/netlink v1.7.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/pegasus-kv/thrift v0.13.0 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/mdns v0.0.9 // indirect
github.com/pion/dtls/v2 v2.2.6 // indirect
github.com/pion/mdns v0.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/transport/v2 v2.2.1 // indirect
github.com/pion/turn/v3 v3.0.1 // indirect
github.com/pion/turn/v2 v2.1.0 // indirect
github.com/pion/udp/v2 v2.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
@@ -149,8 +144,10 @@ require (
go.opentelemetry.io/otel/sdk v1.11.1 // indirect
go.opentelemetry.io/otel/trace v1.11.1 // indirect
golang.org/x/image v0.10.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.6.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
@@ -159,14 +156,13 @@ require (
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 // indirect
k8s.io/apimachinery v0.23.16 // indirect
gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0 // indirect
honnef.co/go/tools v0.2.2 // indirect
k8s.io/apimachinery v0.23.5 // indirect
)
replace github.com/kardianos/service => github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0
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-20240105182236-6c340dd55aed
replace github.com/cloudflare/circl => github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
replace golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20230524172305-5a498a82b33f

437
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ import (
"runtime"
"sync"
"github.com/pion/stun/v2"
"github.com/pion/transport/v3"
"github.com/pion/stun"
"github.com/pion/transport/v2"
log "github.com/sirupsen/logrus"
"golang.org/x/net/ipv4"
wgConn "golang.zx2c4.com/wireguard/conn"

View File

@@ -7,12 +7,13 @@ import (
"strings"
"sync"
"github.com/pion/ice/v3"
"github.com/pion/logging"
"github.com/pion/stun/v2"
"github.com/pion/transport/v3"
"github.com/pion/transport/v3/stdnet"
"github.com/pion/ice/v2"
"github.com/pion/stun"
"github.com/pion/transport/v2/stdnet"
log "github.com/sirupsen/logrus"
"github.com/pion/logging"
"github.com/pion/transport/v2"
)
/*
@@ -223,10 +224,6 @@ func (m *UDPMuxDefault) GetListenAddresses() []net.Addr {
// GetConn returns a PacketConn given the connection's ufrag and network address
// creates the connection if an existing one can't be found
func (m *UDPMuxDefault) GetConn(ufrag string, addr net.Addr) (net.PacketConn, error) {
// don't check addr for mux using unspecified address
if len(m.localAddrsForUnspecified) == 0 && m.params.UDPConn.LocalAddr().String() != addr.String() {
return nil, fmt.Errorf("invalid address %s", addr.String())
}
var isIPv6 bool
if udpAddr, _ := addr.(*net.UDPAddr); udpAddr != nil && udpAddr.IP.To4() == nil {
@@ -285,7 +282,15 @@ func (m *UDPMuxDefault) RemoveConnByUfrag(ufrag string) {
for _, c := range removedConns {
addresses := c.getAddresses()
for _, addr := range addresses {
delete(m.addressMap, addr)
if connList, ok := m.addressMap[addr]; ok {
var newList []*udpMuxedConn
for _, conn := range connList {
if conn.params.Key != ufrag {
newList = append(newList, conn)
}
}
m.addressMap[addr] = newList
}
}
}
}

View File

@@ -13,8 +13,8 @@ import (
log "github.com/sirupsen/logrus"
"github.com/pion/logging"
"github.com/pion/stun/v2"
"github.com/pion/transport/v3"
"github.com/pion/stun"
"github.com/pion/transport/v2"
)
// UniversalUDPMuxDefault handles STUN and TURN servers packets by wrapping the original UDPConn
@@ -80,13 +80,13 @@ func (m *UniversalUDPMuxDefault) ReadFromConn(ctx context.Context) {
log.Debugf("stopped reading from the UDPConn due to finished context")
return
default:
n, a, err := m.params.UDPConn.ReadFrom(buf)
_, a, err := m.params.UDPConn.ReadFrom(buf)
if err != nil {
log.Errorf("error while reading packet: %s", err)
continue
}
msg := &stun.Message{
Raw: append([]byte{}, buf[:n]...),
Raw: buf,
}
err = msg.Decode()
if err != nil {

View File

@@ -12,7 +12,7 @@ import (
"time"
"github.com/pion/logging"
"github.com/pion/transport/v3/packetio"
"github.com/pion/transport/v2/packetio"
)
type udpMuxedConnParams struct {

View File

@@ -6,10 +6,10 @@ import (
"sync"
"time"
"github.com/netbirdio/netbird/iface/bind"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/netbirdio/netbird/iface/bind"
)
const (
@@ -19,12 +19,11 @@ const (
// WGIface represents a interface instance
type WGIface struct {
tun wgTunDevice
userspaceBind bool
tun *tunDevice
configurer wGConfigurer
mu sync.Mutex
configurer wgConfigurer
filter PacketFilter
userspaceBind bool
filter PacketFilter
}
// IsUserspaceBind indicates whether this interfaces is userspace with bind.ICEBind
@@ -32,6 +31,11 @@ func (w *WGIface) IsUserspaceBind() bool {
return w.userspaceBind
}
// GetBind returns a userspace implementation of WireGuard Bind interface
func (w *WGIface) GetBind() *bind.ICEBind {
return w.tun.iceBind
}
// Name returns the interface name
func (w *WGIface) Name() string {
return w.tun.DeviceName()
@@ -42,13 +46,13 @@ func (w *WGIface) Address() WGAddress {
return w.tun.WgAddress()
}
// Up configures a Wireguard interface
// Configure configures a Wireguard interface
// The interface must exist before calling this method (e.g. call interface.Create() before)
func (w *WGIface) Up() (*bind.UniversalUDPMuxDefault, error) {
func (w *WGIface) Configure(privateKey string, port int) error {
w.mu.Lock()
defer w.mu.Unlock()
return w.tun.Up()
log.Debugf("configuring Wireguard interface %s", w.tun.DeviceName())
return w.configurer.configureInterface(privateKey, port)
}
// UpdateAddr updates address of the interface
@@ -70,7 +74,7 @@ func (w *WGIface) UpdatePeer(peerKey string, allowedIps string, keepAlive time.D
w.mu.Lock()
defer w.mu.Unlock()
log.Debugf("updating interface %s peer %s, endpoint %s", w.tun.DeviceName(), peerKey, endpoint)
log.Debugf("updating interface %s peer %s, endpoint %s ", w.tun.DeviceName(), peerKey, endpoint)
return w.configurer.updatePeer(peerKey, allowedIps, keepAlive, endpoint, preSharedKey)
}
@@ -113,14 +117,14 @@ func (w *WGIface) SetFilter(filter PacketFilter) error {
w.mu.Lock()
defer w.mu.Unlock()
if w.tun.Wrapper() == nil {
if w.tun.wrapper == nil {
return fmt.Errorf("userspace packet filtering not handled on this device")
}
w.filter = filter
w.filter.SetNetwork(w.tun.WgAddress().Network)
w.filter.SetNetwork(w.tun.address.Network)
w.tun.Wrapper().SetFilter(filter)
w.tun.wrapper.SetFilter(filter)
return nil
}
@@ -137,5 +141,5 @@ func (w *WGIface) GetDevice() *DeviceWrapper {
w.mu.Lock()
defer w.mu.Unlock()
return w.tun.Wrapper()
return w.tun.wrapper
}

View File

@@ -2,39 +2,41 @@ package iface
import (
"fmt"
"sync"
"github.com/pion/transport/v3"
"github.com/pion/transport/v2"
)
// NewWGIFace Creates a new WireGuard interface instance
func NewWGIFace(iFaceName string, address string, wgPort int, wgPrivKey string, mtu int, transportNet transport.Net, args *MobileIFaceArguments) (*WGIface, error) {
wgAddress, err := parseWGAddress(address)
if err != nil {
return nil, err
func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter, transportNet transport.Net) (*WGIface, error) {
wgIFace := &WGIface{
mu: sync.Mutex{},
}
wgIFace := &WGIface{
tun: newTunDevice(wgAddress, wgPort, wgPrivKey, mtu, transportNet, args.TunAdapter),
userspaceBind: true,
wgAddress, err := parseWGAddress(address)
if err != nil {
return wgIFace, err
}
tun := newTunDevice(wgAddress, mtu, tunAdapter, transportNet)
wgIFace.tun = tun
wgIFace.configurer = newWGConfigurer(tun)
wgIFace.userspaceBind = !WireGuardModuleIsLoaded()
return wgIFace, nil
}
// CreateOnAndroid creates a new Wireguard interface, sets a given IP and brings it up.
// CreateOnMobile creates a new Wireguard interface, sets a given IP and brings it up.
// Will reuse an existing one.
func (w *WGIface) CreateOnAndroid(routes []string, dns string, searchDomains []string) error {
func (w *WGIface) CreateOnMobile(mIFaceArgs MobileIFaceArguments) error {
w.mu.Lock()
defer w.mu.Unlock()
cfgr, err := w.tun.Create(routes, dns, searchDomains)
if err != nil {
return err
}
w.configurer = cfgr
return nil
return w.tun.Create(mIFaceArgs)
}
// Create this function make sense on mobile only
func (w *WGIface) Create() error {
return fmt.Errorf("this function has not implemented on this platform")
return fmt.Errorf("this function has not implemented on mobile")
}

View File

@@ -1,20 +0,0 @@
//go:build !android
// +build !android
package iface
// Create creates a new Wireguard interface, sets a given IP and brings it up.
// Will reuse an existing one.
// this function is different on Android
func (w *WGIface) Create() error {
w.mu.Lock()
defer w.mu.Unlock()
cfgr, err := w.tun.Create()
if err != nil {
return err
}
w.configurer = cfgr
return nil
}

View File

@@ -1,38 +0,0 @@
//go:build !ios
// +build !ios
package iface
import (
"fmt"
"github.com/pion/transport/v3"
"github.com/netbirdio/netbird/iface/netstack"
)
// NewWGIFace Creates a new WireGuard interface instance
func NewWGIFace(iFaceName string, address string, wgPort int, wgPrivKey string, mtu int, transportNet transport.Net, args *MobileIFaceArguments) (*WGIface, error) {
wgAddress, err := parseWGAddress(address)
if err != nil {
return nil, err
}
wgIFace := &WGIface{
userspaceBind: true,
}
if netstack.IsEnabled() {
wgIFace.tun = newTunNetstackDevice(iFaceName, wgAddress, wgPort, wgPrivKey, mtu, transportNet, netstack.ListenAddr())
return wgIFace, nil
}
wgIFace.tun = newTunDevice(iFaceName, wgAddress, wgPort, wgPrivKey, mtu, transportNet)
return wgIFace, nil
}
// CreateOnAndroid this function make sense on mobile only
func (w *WGIface) CreateOnAndroid([]string, string, []string) error {
return fmt.Errorf("this function has not implemented on this platform")
}

Some files were not shown because too many files have changed in this diff Show More