mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-07 01:10:03 +00:00
Compare commits
10 Commits
poc/netsta
...
v0.25.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc3d647d6b | ||
|
|
7060b63838 | ||
|
|
3168b80ad0 | ||
|
|
818c6b885f | ||
|
|
01f28baec7 | ||
|
|
56896794b3 | ||
|
|
f73a2e2848 | ||
|
|
19fa071a93 | ||
|
|
cba3c549e9 | ||
|
|
65247de48d |
27
.github/workflows/release.yml
vendored
27
.github/workflows/release.yml
vendored
@@ -45,14 +45,17 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.20"
|
go-version: "1.20"
|
||||||
|
cache: false
|
||||||
-
|
-
|
||||||
name: Cache Go modules
|
name: Cache Go modules
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: |
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
~/go/pkg/mod
|
||||||
|
~/.cache/go-build
|
||||||
|
key: ${{ runner.os }}-go-releaser-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-go-
|
${{ runner.os }}-go-releaser-
|
||||||
-
|
-
|
||||||
name: Install modules
|
name: Install modules
|
||||||
run: go mod tidy
|
run: go mod tidy
|
||||||
@@ -118,13 +121,16 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.20"
|
go-version: "1.20"
|
||||||
|
cache: false
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: |
|
||||||
key: ${{ runner.os }}-ui-go-${{ hashFiles('**/go.sum') }}
|
~/go/pkg/mod
|
||||||
|
~/.cache/go-build
|
||||||
|
key: ${{ runner.os }}-ui-go-releaser-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-ui-go-
|
${{ runner.os }}-ui-go-releaser-
|
||||||
|
|
||||||
- name: Install modules
|
- name: Install modules
|
||||||
run: go mod tidy
|
run: go mod tidy
|
||||||
@@ -170,14 +176,17 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.20"
|
go-version: "1.20"
|
||||||
|
cache: false
|
||||||
-
|
-
|
||||||
name: Cache Go modules
|
name: Cache Go modules
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: |
|
||||||
key: ${{ runner.os }}-ui-go-${{ hashFiles('**/go.sum') }}
|
~/go/pkg/mod
|
||||||
|
~/.cache/go-build
|
||||||
|
key: ${{ runner.os }}-ui-go-releaser-darwin-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-ui-go-
|
${{ runner.os }}-ui-go-releaser-darwin-
|
||||||
-
|
-
|
||||||
name: Install modules
|
name: Install modules
|
||||||
run: go mod tidy
|
run: go mod tidy
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH: false
|
CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH: false
|
||||||
|
|
||||||
- name: check values
|
- name: check values
|
||||||
working-directory: infrastructure_files
|
working-directory: infrastructure_files/artifacts
|
||||||
env:
|
env:
|
||||||
CI_NETBIRD_DOMAIN: localhost
|
CI_NETBIRD_DOMAIN: localhost
|
||||||
CI_NETBIRD_AUTH_CLIENT_ID: testing.client.id
|
CI_NETBIRD_AUTH_CLIENT_ID: testing.client.id
|
||||||
@@ -143,7 +143,7 @@ jobs:
|
|||||||
docker build -t netbirdio/signal:latest .
|
docker build -t netbirdio/signal:latest .
|
||||||
|
|
||||||
- name: run docker compose up
|
- name: run docker compose up
|
||||||
working-directory: infrastructure_files
|
working-directory: infrastructure_files/artifacts
|
||||||
run: |
|
run: |
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
sleep 5
|
sleep 5
|
||||||
@@ -152,9 +152,9 @@ jobs:
|
|||||||
|
|
||||||
- name: test running containers
|
- name: test running containers
|
||||||
run: |
|
run: |
|
||||||
count=$(docker compose ps --format json | jq '. | select(.Name | contains("infrastructure_files")) | .State' | grep -c running)
|
count=$(docker compose ps --format json | jq '. | select(.Name | contains("artifacts")) | .State' | grep -c running)
|
||||||
test $count -eq 4
|
test $count -eq 4
|
||||||
working-directory: infrastructure_files
|
working-directory: infrastructure_files/artifacts
|
||||||
|
|
||||||
test-getting-started-script:
|
test-getting-started-script:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -6,11 +6,20 @@ bin/
|
|||||||
.env
|
.env
|
||||||
conf.json
|
conf.json
|
||||||
http-cmds.sh
|
http-cmds.sh
|
||||||
infrastructure_files/management.json
|
setup.env
|
||||||
infrastructure_files/management-*.json
|
infrastructure_files/**/Caddyfile
|
||||||
infrastructure_files/docker-compose.yml
|
infrastructure_files/**/dashboard.env
|
||||||
infrastructure_files/openid-configuration.json
|
infrastructure_files/**/zitadel.env
|
||||||
infrastructure_files/turnserver.conf
|
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.**
|
||||||
management/management
|
management/management
|
||||||
client/client
|
client/client
|
||||||
client/client.exe
|
client/client.exe
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3
|
FROM alpine:3.18.5
|
||||||
RUN apk add --no-cache ca-certificates iptables ip6tables
|
RUN apk add --no-cache ca-certificates iptables ip6tables
|
||||||
ENV NB_FOREGROUND_MODE=true
|
ENV NB_FOREGROUND_MODE=true
|
||||||
ENTRYPOINT [ "/go/bin/netbird","up"]
|
ENTRYPOINT [ "/go/bin/netbird","up"]
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ var loginCmd = &cobra.Command{
|
|||||||
AdminURL: adminURL,
|
AdminURL: adminURL,
|
||||||
ConfigPath: configPath,
|
ConfigPath: configPath,
|
||||||
}
|
}
|
||||||
if preSharedKey != "" {
|
if rootCmd.PersistentFlags().Changed(preSharedKeyFlag) {
|
||||||
ic.PreSharedKey = &preSharedKey
|
ic.PreSharedKey = &preSharedKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,13 +151,21 @@ func foregroundLogin(ctx context.Context, cmd *cobra.Command, config *internal.C
|
|||||||
jwtToken = tokenInfo.GetTokenToUse()
|
jwtToken = tokenInfo.GetTokenToUse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lastError error
|
||||||
|
|
||||||
err = WithBackOff(func() error {
|
err = WithBackOff(func() error {
|
||||||
err := internal.Login(ctx, config, setupKey, jwtToken)
|
err := internal.Login(ctx, config, setupKey, jwtToken)
|
||||||
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
|
if s, ok := gstatus.FromError(err); ok && (s.Code() == codes.InvalidArgument || s.Code() == codes.PermissionDenied) {
|
||||||
|
lastError = err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if lastError != nil {
|
||||||
|
return fmt.Errorf("login failed: %v", lastError)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("backoff cycle failed: %v", err)
|
return fmt.Errorf("backoff cycle failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
externalIPMapFlag = "external-ip-map"
|
externalIPMapFlag = "external-ip-map"
|
||||||
|
preSharedKeyFlag = "preshared-key"
|
||||||
dnsResolverAddress = "dns-resolver-address"
|
dnsResolverAddress = "dns-resolver-address"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "l", "info", "sets Netbird log level")
|
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().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().StringVarP(&setupKey, "setup-key", "k", "", "Setup key obtained from the Management Service Dashboard (used to register peer)")
|
||||||
rootCmd.PersistentFlags().StringVar(&preSharedKey, "preshared-key", "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.")
|
rootCmd.PersistentFlags().StringVar(&preSharedKey, preSharedKeyFlag, "", "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.PersistentFlags().StringVarP(&hostName, "hostname", "n", "", "Sets a custom hostname for the device")
|
||||||
rootCmd.AddCommand(serviceCmd)
|
rootCmd.AddCommand(serviceCmd)
|
||||||
rootCmd.AddCommand(upCmd)
|
rootCmd.AddCommand(upCmd)
|
||||||
|
|||||||
@@ -71,8 +71,10 @@ var (
|
|||||||
jsonFlag bool
|
jsonFlag bool
|
||||||
yamlFlag bool
|
yamlFlag bool
|
||||||
ipsFilter []string
|
ipsFilter []string
|
||||||
|
prefixNamesFilter []string
|
||||||
statusFilter string
|
statusFilter string
|
||||||
ipsFilterMap map[string]struct{}
|
ipsFilterMap map[string]struct{}
|
||||||
|
prefixNamesFilterMap map[string]struct{}
|
||||||
)
|
)
|
||||||
|
|
||||||
var statusCmd = &cobra.Command{
|
var statusCmd = &cobra.Command{
|
||||||
@@ -83,12 +85,14 @@ var statusCmd = &cobra.Command{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ipsFilterMap = make(map[string]struct{})
|
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().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(&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(&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.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.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(&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")
|
statusCmd.PersistentFlags().StringVar(&statusFilter, "filter-by-status", "", "filters the detailed output by connection status(connected|disconnected), e.g., --filter-by-status connected")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,8 +176,12 @@ func getStatus(ctx context.Context, cmd *cobra.Command) (*proto.StatusResponse,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseFilters() error {
|
func parseFilters() error {
|
||||||
|
|
||||||
switch strings.ToLower(statusFilter) {
|
switch strings.ToLower(statusFilter) {
|
||||||
case "", "disconnected", "connected":
|
case "", "disconnected", "connected":
|
||||||
|
if strings.ToLower(statusFilter) != "" {
|
||||||
|
enableDetailFlagWhenFilterFlag()
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("wrong status filter, should be one of connected|disconnected, got: %s", statusFilter)
|
return fmt.Errorf("wrong status filter, should be one of connected|disconnected, got: %s", statusFilter)
|
||||||
}
|
}
|
||||||
@@ -185,11 +193,26 @@ func parseFilters() error {
|
|||||||
return fmt.Errorf("got an invalid IP address in the filter: address %s, error %s", addr, err)
|
return fmt.Errorf("got an invalid IP address in the filter: address %s, error %s", addr, err)
|
||||||
}
|
}
|
||||||
ipsFilterMap[addr] = struct{}{}
|
ipsFilterMap[addr] = struct{}{}
|
||||||
|
enableDetailFlagWhenFilterFlag()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(prefixNamesFilter) > 0 {
|
||||||
|
for _, name := range prefixNamesFilter {
|
||||||
|
prefixNamesFilterMap[strings.ToLower(name)] = struct{}{}
|
||||||
|
}
|
||||||
|
enableDetailFlagWhenFilterFlag()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enableDetailFlagWhenFilterFlag() {
|
||||||
|
if !detailFlag && !jsonFlag && !yamlFlag {
|
||||||
|
detailFlag = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverview {
|
func convertToStatusOutputOverview(resp *proto.StatusResponse) statusOutputOverview {
|
||||||
pbFullStatus := resp.GetFullStatus()
|
pbFullStatus := resp.GetFullStatus()
|
||||||
|
|
||||||
@@ -415,6 +438,7 @@ func parsePeers(peers peersStateOutput) string {
|
|||||||
func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool {
|
func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool {
|
||||||
statusEval := false
|
statusEval := false
|
||||||
ipEval := false
|
ipEval := false
|
||||||
|
nameEval := false
|
||||||
|
|
||||||
if statusFilter != "" {
|
if statusFilter != "" {
|
||||||
lowerStatusFilter := strings.ToLower(statusFilter)
|
lowerStatusFilter := strings.ToLower(statusFilter)
|
||||||
@@ -431,5 +455,15 @@ func skipDetailByFilters(peerState *proto.PeerState, isConnected bool) bool {
|
|||||||
ipEval = true
|
ipEval = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return statusEval || ipEval
|
|
||||||
|
if len(prefixNamesFilter) > 0 {
|
||||||
|
for prefixNameFilter := range prefixNamesFilterMap {
|
||||||
|
if !strings.HasPrefix(peerState.Fqdn, prefixNameFilter) {
|
||||||
|
nameEval = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return statusEval || ipEval || nameEval
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {
|
|||||||
NATExternalIPs: natExternalIPs,
|
NATExternalIPs: natExternalIPs,
|
||||||
CustomDNSAddress: customDNSAddressConverted,
|
CustomDNSAddress: customDNSAddressConverted,
|
||||||
}
|
}
|
||||||
if preSharedKey != "" {
|
|
||||||
|
if rootCmd.PersistentFlags().Changed(preSharedKeyFlag) {
|
||||||
ic.PreSharedKey = &preSharedKey
|
ic.PreSharedKey = &preSharedKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -215,13 +215,10 @@ func update(input ConfigInput) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if input.PreSharedKey != nil && config.PreSharedKey != *input.PreSharedKey {
|
if input.PreSharedKey != nil && config.PreSharedKey != *input.PreSharedKey {
|
||||||
if *input.PreSharedKey != "" {
|
log.Infof("new pre-shared key provided, replacing old key")
|
||||||
log.Infof("new pre-shared key provides, updated to %s (old value %s)",
|
|
||||||
*input.PreSharedKey, config.PreSharedKey)
|
|
||||||
config.PreSharedKey = *input.PreSharedKey
|
config.PreSharedKey = *input.PreSharedKey
|
||||||
refresh = true
|
refresh = true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if config.SSHKey == "" {
|
if config.SSHKey == "" {
|
||||||
pem, err := ssh.GeneratePrivateKey(ssh.ED25519)
|
pem, err := ssh.GeneratePrivateKey(ssh.ED25519)
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/util"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetConfig(t *testing.T) {
|
func TestGetConfig(t *testing.T) {
|
||||||
@@ -60,22 +61,7 @@ func TestGetConfig(t *testing.T) {
|
|||||||
assert.Equal(t, config.ManagementURL.String(), managementURL)
|
assert.Equal(t, config.ManagementURL.String(), managementURL)
|
||||||
assert.Equal(t, config.PreSharedKey, preSharedKey)
|
assert.Equal(t, config.PreSharedKey, preSharedKey)
|
||||||
|
|
||||||
// case 4: new empty pre-shared key config -> fetch it
|
// case 4: existing config, but new managementURL has been provided -> update config
|
||||||
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"
|
newManagementURL := "https://test.newManagement.url:33071"
|
||||||
config, err = UpdateOrCreateConfig(ConfigInput{
|
config, err = UpdateOrCreateConfig(ConfigInput{
|
||||||
ManagementURL: newManagementURL,
|
ManagementURL: newManagementURL,
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ func RunClientMobile(ctx context.Context, config *Config, statusRecorder *peer.S
|
|||||||
return runClient(ctx, config, statusRecorder, mobileDependency)
|
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 {
|
func runClient(ctx context.Context, config *Config, statusRecorder *peer.Status, mobileDependency MobileDependency) error {
|
||||||
log.Infof("starting NetBird client version %s", version.NetbirdVersion())
|
log.Infof("starting NetBird client version %s", version.NetbirdVersion())
|
||||||
|
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ func (f *fileConfigurator) supportCustomPort() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
func (f *fileConfigurator) applyDNSConfig(config HostDNSConfig) error {
|
||||||
backupFileExist := false
|
backupFileExist := false
|
||||||
_, err := os.Stat(fileDefaultResolvConfBackupLocation)
|
_, err := os.Stat(fileDefaultResolvConfBackupLocation)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
backupFileExist = true
|
backupFileExist = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.routeAll {
|
if !config.RouteAll {
|
||||||
if backupFileExist {
|
if backupFileExist {
|
||||||
err = f.restore()
|
err = f.restore()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -70,7 +70,7 @@ func (f *fileConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
|
|
||||||
buf := prepareResolvConfContent(
|
buf := prepareResolvConfContent(
|
||||||
searchDomainList,
|
searchDomainList,
|
||||||
append([]string{config.serverIP}, nameServers...),
|
append([]string{config.ServerIP}, nameServers...),
|
||||||
others)
|
others)
|
||||||
|
|
||||||
log.Debugf("creating managed file %s", defaultResolvConfPath)
|
log.Debugf("creating managed file %s", defaultResolvConfPath)
|
||||||
@@ -138,14 +138,14 @@ func prepareResolvConfContent(searchDomains, nameServers, others []string) bytes
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchDomains(config hostDNSConfig) []string {
|
func searchDomains(config HostDNSConfig) []string {
|
||||||
listOfDomains := make([]string, 0)
|
listOfDomains := make([]string, 0)
|
||||||
for _, dConf := range config.domains {
|
for _, dConf := range config.Domains {
|
||||||
if dConf.matchOnly || dConf.disabled {
|
if dConf.MatchOnly || dConf.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
listOfDomains = append(listOfDomains, dConf.domain)
|
listOfDomains = append(listOfDomains, dConf.Domain)
|
||||||
}
|
}
|
||||||
return listOfDomains
|
return listOfDomains
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ func originalDNSConfigs(resolvconfFile string) (searchDomains, nameServers, othe
|
|||||||
return
|
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 {
|
func mergeSearchDomains(searchDomains []string, originalSearchDomains []string) []string {
|
||||||
lineSize := len("search")
|
lineSize := len("search")
|
||||||
searchDomainsList := make([]string, 0, len(searchDomains)+len(originalSearchDomains))
|
searchDomainsList := make([]string, 0, len(searchDomains)+len(originalSearchDomains))
|
||||||
@@ -225,14 +225,14 @@ func mergeSearchDomains(searchDomains []string, originalSearchDomains []string)
|
|||||||
return searchDomainsList
|
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
|
// extend s slice with vs elements
|
||||||
// return with the number of characters in the searchDomains line
|
// return with the number of characters in the searchDomains line
|
||||||
func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string) int {
|
func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string) int {
|
||||||
for _, sd := range vs {
|
for _, sd := range vs {
|
||||||
tmpCharsNumber := initialLineChars + 1 + len(sd)
|
tmpCharsNumber := initialLineChars + 1 + len(sd)
|
||||||
if tmpCharsNumber > fileMaxLineCharsLimit {
|
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)
|
log.Infof("search list line is larger than %d characters. Skipping append of %s domain", fileMaxLineCharsLimit, sd)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ func validateAndFillSearchDomains(initialLineChars int, s *[]string, vs []string
|
|||||||
initialLineChars = tmpCharsNumber
|
initialLineChars = tmpCharsNumber
|
||||||
|
|
||||||
if len(*s) >= fileMaxNumberOfSearchDomains {
|
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)
|
log.Infof("already appended %d domains to search list. Skipping append of %s domain", fileMaxNumberOfSearchDomains, sd)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,31 +8,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type hostManager interface {
|
type hostManager interface {
|
||||||
applyDNSConfig(config hostDNSConfig) error
|
applyDNSConfig(config HostDNSConfig) error
|
||||||
restoreHostDNS() error
|
restoreHostDNS() error
|
||||||
supportCustomPort() bool
|
supportCustomPort() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type hostDNSConfig struct {
|
type HostDNSConfig struct {
|
||||||
domains []domainConfig
|
Domains []DomainConfig `json:"domains"`
|
||||||
routeAll bool
|
RouteAll bool `json:"routeAll"`
|
||||||
serverIP string
|
ServerIP string `json:"serverIP"`
|
||||||
serverPort int
|
ServerPort int `json:"serverPort"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type domainConfig struct {
|
type DomainConfig struct {
|
||||||
disabled bool
|
Disabled bool `json:"disabled"`
|
||||||
domain string
|
Domain string `json:"domain"`
|
||||||
matchOnly bool
|
MatchOnly bool `json:"matchOnly"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockHostConfigurator struct {
|
type mockHostConfigurator struct {
|
||||||
applyDNSConfigFunc func(config hostDNSConfig) error
|
applyDNSConfigFunc func(config HostDNSConfig) error
|
||||||
restoreHostDNSFunc func() error
|
restoreHostDNSFunc func() error
|
||||||
supportCustomPortFunc func() bool
|
supportCustomPortFunc func() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockHostConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
func (m *mockHostConfigurator) applyDNSConfig(config HostDNSConfig) error {
|
||||||
if m.applyDNSConfigFunc != nil {
|
if m.applyDNSConfigFunc != nil {
|
||||||
return m.applyDNSConfigFunc(config)
|
return m.applyDNSConfigFunc(config)
|
||||||
}
|
}
|
||||||
@@ -55,38 +55,38 @@ func (m *mockHostConfigurator) supportCustomPort() bool {
|
|||||||
|
|
||||||
func newNoopHostMocker() hostManager {
|
func newNoopHostMocker() hostManager {
|
||||||
return &mockHostConfigurator{
|
return &mockHostConfigurator{
|
||||||
applyDNSConfigFunc: func(config hostDNSConfig) error { return nil },
|
applyDNSConfigFunc: func(config HostDNSConfig) error { return nil },
|
||||||
restoreHostDNSFunc: func() error { return nil },
|
restoreHostDNSFunc: func() error { return nil },
|
||||||
supportCustomPortFunc: func() bool { return true },
|
supportCustomPortFunc: func() bool { return true },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) hostDNSConfig {
|
func dnsConfigToHostDNSConfig(dnsConfig nbdns.Config, ip string, port int) HostDNSConfig {
|
||||||
config := hostDNSConfig{
|
config := HostDNSConfig{
|
||||||
routeAll: false,
|
RouteAll: false,
|
||||||
serverIP: ip,
|
ServerIP: ip,
|
||||||
serverPort: port,
|
ServerPort: port,
|
||||||
}
|
}
|
||||||
for _, nsConfig := range dnsConfig.NameServerGroups {
|
for _, nsConfig := range dnsConfig.NameServerGroups {
|
||||||
if len(nsConfig.NameServers) == 0 {
|
if len(nsConfig.NameServers) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if nsConfig.Primary {
|
if nsConfig.Primary {
|
||||||
config.routeAll = true
|
config.RouteAll = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, domain := range nsConfig.Domains {
|
for _, domain := range nsConfig.Domains {
|
||||||
config.domains = append(config.domains, domainConfig{
|
config.Domains = append(config.Domains, DomainConfig{
|
||||||
domain: strings.TrimSuffix(domain, "."),
|
Domain: strings.TrimSuffix(domain, "."),
|
||||||
matchOnly: !nsConfig.SearchDomainsEnabled,
|
MatchOnly: !nsConfig.SearchDomainsEnabled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, customZone := range dnsConfig.CustomZones {
|
for _, customZone := range dnsConfig.CustomZones {
|
||||||
config.domains = append(config.domains, domainConfig{
|
config.Domains = append(config.Domains, DomainConfig{
|
||||||
domain: strings.TrimSuffix(customZone.Domain, "."),
|
Domain: strings.TrimSuffix(customZone.Domain, "."),
|
||||||
matchOnly: false,
|
MatchOnly: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ func newHostManager(wgInterface WGIface) (hostManager, error) {
|
|||||||
return &androidHostManager{}, nil
|
return &androidHostManager{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a androidHostManager) applyDNSConfig(config hostDNSConfig) error {
|
func (a androidHostManager) applyDNSConfig(config HostDNSConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !ios
|
||||||
|
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -42,11 +44,11 @@ func (s *systemConfigurator) supportCustomPort() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
func (s *systemConfigurator) applyDNSConfig(config HostDNSConfig) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if config.routeAll {
|
if config.RouteAll {
|
||||||
err = s.addDNSSetupForAll(config.serverIP, config.serverPort)
|
err = s.addDNSSetupForAll(config.ServerIP, config.ServerPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.primaryServiceID = ""
|
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 (
|
var (
|
||||||
@@ -64,20 +66,20 @@ func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
matchDomains []string
|
matchDomains []string
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, dConf := range config.domains {
|
for _, dConf := range config.Domains {
|
||||||
if dConf.disabled {
|
if dConf.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if dConf.matchOnly {
|
if dConf.MatchOnly {
|
||||||
matchDomains = append(matchDomains, dConf.domain)
|
matchDomains = append(matchDomains, dConf.Domain)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
searchDomains = append(searchDomains, dConf.domain)
|
searchDomains = append(searchDomains, dConf.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
matchKey := getKeyWithInput(netbirdDNSStateKeyFormat, matchSuffix)
|
matchKey := getKeyWithInput(netbirdDNSStateKeyFormat, matchSuffix)
|
||||||
if len(matchDomains) != 0 {
|
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 {
|
} else {
|
||||||
log.Infof("removing match domains from the system")
|
log.Infof("removing match domains from the system")
|
||||||
err = s.removeKeyFromSystemConfig(matchKey)
|
err = s.removeKeyFromSystemConfig(matchKey)
|
||||||
@@ -88,7 +90,7 @@ func (s *systemConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
|
|
||||||
searchKey := getKeyWithInput(netbirdDNSStateKeyFormat, searchSuffix)
|
searchKey := getKeyWithInput(netbirdDNSStateKeyFormat, searchSuffix)
|
||||||
if len(searchDomains) != 0 {
|
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 {
|
} else {
|
||||||
log.Infof("removing search domains from the system")
|
log.Infof("removing search domains from the system")
|
||||||
err = s.removeKeyFromSystemConfig(searchKey)
|
err = s.removeKeyFromSystemConfig(searchKey)
|
||||||
|
|||||||
37
client/internal/dns/host_ios.go
Normal file
37
client/internal/dns/host_ios.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -43,10 +43,10 @@ func (s *registryConfigurator) supportCustomPort() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig) error {
|
||||||
var err error
|
var err error
|
||||||
if config.routeAll {
|
if config.RouteAll {
|
||||||
err = r.addDNSSetupForAll(config.serverIP)
|
err = r.addDNSSetupForAll(config.ServerIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.routingAll = false
|
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 (
|
var (
|
||||||
@@ -64,18 +64,18 @@ func (r *registryConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
matchDomains []string
|
matchDomains []string
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, dConf := range config.domains {
|
for _, dConf := range config.Domains {
|
||||||
if dConf.disabled {
|
if dConf.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !dConf.matchOnly {
|
if !dConf.MatchOnly {
|
||||||
searchDomains = append(searchDomains, dConf.domain)
|
searchDomains = append(searchDomains, dConf.Domain)
|
||||||
}
|
}
|
||||||
matchDomains = append(matchDomains, "."+dConf.domain)
|
matchDomains = append(matchDomains, "."+dConf.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matchDomains) != 0 {
|
if len(matchDomains) != 0 {
|
||||||
err = r.addDNSMatchPolicy(matchDomains, config.serverIP)
|
err = r.addDNSMatchPolicy(matchDomains, config.ServerIP)
|
||||||
} else {
|
} else {
|
||||||
err = removeRegistryKeyFromDNSPolicyConfig(dnsPolicyConfigMatchPath)
|
err = removeRegistryKeyFromDNSPolicyConfig(dnsPolicyConfigMatchPath)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/miekg/dns"
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalResolver_ServeDNS(t *testing.T) {
|
func TestLocalResolver_ServeDNS(t *testing.T) {
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import (
|
|||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
nbversion "github.com/netbirdio/netbird/version"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
nbversion "github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -93,7 +94,7 @@ func (n *networkManagerDbusConfigurator) supportCustomPort() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
func (n *networkManagerDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
|
||||||
connSettings, configVersion, err := n.getAppliedConnectionSettings()
|
connSettings, configVersion, err := n.getAppliedConnectionSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("got an error while retrieving the applied connection settings, error: %s", err)
|
return fmt.Errorf("got an error while retrieving the applied connection settings, error: %s", err)
|
||||||
@@ -101,7 +102,7 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) er
|
|||||||
|
|
||||||
connSettings.cleanDeprecatedSettings()
|
connSettings.cleanDeprecatedSettings()
|
||||||
|
|
||||||
dnsIP, err := netip.ParseAddr(config.serverIP)
|
dnsIP, err := netip.ParseAddr(config.ServerIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse ip address, error: %s", err)
|
return fmt.Errorf("unable to parse ip address, error: %s", err)
|
||||||
}
|
}
|
||||||
@@ -111,33 +112,33 @@ func (n *networkManagerDbusConfigurator) applyDNSConfig(config hostDNSConfig) er
|
|||||||
searchDomains []string
|
searchDomains []string
|
||||||
matchDomains []string
|
matchDomains []string
|
||||||
)
|
)
|
||||||
for _, dConf := range config.domains {
|
for _, dConf := range config.Domains {
|
||||||
if dConf.disabled {
|
if dConf.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if dConf.matchOnly {
|
if dConf.MatchOnly {
|
||||||
matchDomains = append(matchDomains, "~."+dns.Fqdn(dConf.domain))
|
matchDomains = append(matchDomains, "~."+dns.Fqdn(dConf.Domain))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
searchDomains = append(searchDomains, dns.Fqdn(dConf.domain))
|
searchDomains = append(searchDomains, dns.Fqdn(dConf.Domain))
|
||||||
}
|
}
|
||||||
|
|
||||||
newDomainList := append(searchDomains, matchDomains...) //nolint:gocritic
|
newDomainList := append(searchDomains, matchDomains...) //nolint:gocritic
|
||||||
|
|
||||||
priority := networkManagerDbusSearchDomainOnlyPriority
|
priority := networkManagerDbusSearchDomainOnlyPriority
|
||||||
switch {
|
switch {
|
||||||
case config.routeAll:
|
case config.RouteAll:
|
||||||
priority = networkManagerDbusPrimaryDNSPriority
|
priority = networkManagerDbusPrimaryDNSPriority
|
||||||
newDomainList = append(newDomainList, "~.")
|
newDomainList = append(newDomainList, "~.")
|
||||||
if !n.routingAll {
|
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:
|
case len(matchDomains) > 0:
|
||||||
priority = networkManagerDbusWithMatchDomainPriority
|
priority = networkManagerDbusWithMatchDomainPriority
|
||||||
}
|
}
|
||||||
|
|
||||||
if priority != networkManagerDbusPrimaryDNSPriority && n.routingAll {
|
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
|
n.routingAll = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,6 @@ func (n *notifier) notify() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func(l listener.NetworkChangeListener) {
|
go func(l listener.NetworkChangeListener) {
|
||||||
l.OnNetworkChanged()
|
l.OnNetworkChanged("")
|
||||||
}(n.listener)
|
}(n.listener)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ func (r *resolvconf) supportCustomPort() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error {
|
func (r *resolvconf) applyDNSConfig(config HostDNSConfig) error {
|
||||||
var err error
|
var err error
|
||||||
if !config.routeAll {
|
if !config.RouteAll {
|
||||||
err = r.restoreHostDNS()
|
err = r.restoreHostDNS()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -54,7 +54,7 @@ func (r *resolvconf) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
|
|
||||||
buf := prepareResolvConfContent(
|
buf := prepareResolvConfContent(
|
||||||
searchDomainList,
|
searchDomainList,
|
||||||
append([]string{config.serverIP}, r.originalNameServers...),
|
append([]string{config.ServerIP}, r.originalNameServers...),
|
||||||
r.othersConfigs)
|
r.othersConfigs)
|
||||||
|
|
||||||
err = r.applyConfig(buf)
|
err = r.applyConfig(buf)
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ type ReadyListener interface {
|
|||||||
OnReady()
|
OnReady()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IosDnsManager is a dns manager interface for iOS
|
||||||
|
type IosDnsManager interface {
|
||||||
|
ApplyDns(string)
|
||||||
|
}
|
||||||
|
|
||||||
// Server is a dns server interface
|
// Server is a dns server interface
|
||||||
type Server interface {
|
type Server interface {
|
||||||
Initialize() error
|
Initialize() error
|
||||||
@@ -43,7 +48,7 @@ type DefaultServer struct {
|
|||||||
hostManager hostManager
|
hostManager hostManager
|
||||||
updateSerial uint64
|
updateSerial uint64
|
||||||
previousConfigHash uint64
|
previousConfigHash uint64
|
||||||
currentConfig hostDNSConfig
|
currentConfig HostDNSConfig
|
||||||
|
|
||||||
// permanent related properties
|
// permanent related properties
|
||||||
permanent bool
|
permanent bool
|
||||||
@@ -52,6 +57,7 @@ type DefaultServer struct {
|
|||||||
|
|
||||||
// make sense on mobile only
|
// make sense on mobile only
|
||||||
searchDomainNotifier *notifier
|
searchDomainNotifier *notifier
|
||||||
|
iosDnsManager IosDnsManager
|
||||||
}
|
}
|
||||||
|
|
||||||
type handlerWithStop interface {
|
type handlerWithStop interface {
|
||||||
@@ -99,6 +105,13 @@ func NewDefaultServerPermanentUpstream(ctx context.Context, wgInterface WGIface,
|
|||||||
return ds
|
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 {
|
func newDefaultServer(ctx context.Context, wgInterface WGIface, dnsService service) *DefaultServer {
|
||||||
ctx, stop := context.WithCancel(ctx)
|
ctx, stop := context.WithCancel(ctx)
|
||||||
defaultServer := &DefaultServer{
|
defaultServer := &DefaultServer{
|
||||||
@@ -131,8 +144,8 @@ func (s *DefaultServer) Initialize() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.hostManager, err = newHostManager(s.wgInterface)
|
s.hostManager, err = s.initialize()
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DnsIP returns the DNS resolver server IP address
|
// DnsIP returns the DNS resolver server IP address
|
||||||
@@ -223,20 +236,20 @@ func (s *DefaultServer) UpdateDNSServer(serial uint64, update nbdns.Config) erro
|
|||||||
func (s *DefaultServer) SearchDomains() []string {
|
func (s *DefaultServer) SearchDomains() []string {
|
||||||
var searchDomains []string
|
var searchDomains []string
|
||||||
|
|
||||||
for _, dConf := range s.currentConfig.domains {
|
for _, dConf := range s.currentConfig.Domains {
|
||||||
if dConf.disabled {
|
if dConf.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if dConf.matchOnly {
|
if dConf.MatchOnly {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
searchDomains = append(searchDomains, dConf.domain)
|
searchDomains = append(searchDomains, dConf.Domain)
|
||||||
}
|
}
|
||||||
return searchDomains
|
return searchDomains
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
|
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
|
// and proceed with a regular update to clean up the handlers and records
|
||||||
if update.ServiceEnable {
|
if update.ServiceEnable {
|
||||||
_ = s.service.Listen()
|
_ = s.service.Listen()
|
||||||
@@ -262,7 +275,7 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
|
|||||||
if s.service.RuntimePort() != defaultPort && !s.hostManager.supportCustomPort() {
|
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. " +
|
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")
|
"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 {
|
if err = s.hostManager.applyDNSConfig(hostUpdate); err != nil {
|
||||||
@@ -312,7 +325,10 @@ func (s *DefaultServer) buildUpstreamHandlerUpdate(nameServerGroups []*nbdns.Nam
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := newUpstreamResolver(s.ctx)
|
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)
|
||||||
|
}
|
||||||
for _, ns := range nsGroup.NameServers {
|
for _, ns := range nsGroup.NameServers {
|
||||||
if ns.NSType != nbdns.UDPNameServerType {
|
if ns.NSType != nbdns.UDPNameServerType {
|
||||||
log.Warnf("skipping nameserver %s with type %s, this peer supports only %s",
|
log.Warnf("skipping nameserver %s with type %s, this peer supports only %s",
|
||||||
@@ -445,14 +461,14 @@ func (s *DefaultServer) upstreamCallbacks(
|
|||||||
}
|
}
|
||||||
if nsGroup.Primary {
|
if nsGroup.Primary {
|
||||||
removeIndex[nbdns.RootZone] = -1
|
removeIndex[nbdns.RootZone] = -1
|
||||||
s.currentConfig.routeAll = false
|
s.currentConfig.RouteAll = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, item := range s.currentConfig.domains {
|
for i, item := range s.currentConfig.Domains {
|
||||||
if _, found := removeIndex[item.domain]; found {
|
if _, found := removeIndex[item.Domain]; found {
|
||||||
s.currentConfig.domains[i].disabled = true
|
s.currentConfig.Domains[i].Disabled = true
|
||||||
s.service.DeregisterMux(item.domain)
|
s.service.DeregisterMux(item.Domain)
|
||||||
removeIndex[item.domain] = i
|
removeIndex[item.Domain] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil {
|
if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil {
|
||||||
@@ -464,28 +480,32 @@ func (s *DefaultServer) upstreamCallbacks(
|
|||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
for domain, i := range removeIndex {
|
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
|
continue
|
||||||
}
|
}
|
||||||
s.currentConfig.domains[i].disabled = false
|
s.currentConfig.Domains[i].Disabled = false
|
||||||
s.service.RegisterMux(domain, handler)
|
s.service.RegisterMux(domain, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.WithField("nameservers", nsGroup.NameServers)
|
l := log.WithField("nameservers", nsGroup.NameServers)
|
||||||
l.Debug("reactivate temporary disabled nameserver group")
|
l.Debug("reactivate temporary Disabled nameserver group")
|
||||||
|
|
||||||
if nsGroup.Primary {
|
if nsGroup.Primary {
|
||||||
s.currentConfig.routeAll = true
|
s.currentConfig.RouteAll = true
|
||||||
}
|
}
|
||||||
if err := s.hostManager.applyDNSConfig(s.currentConfig); err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultServer) addHostRootZone() {
|
func (s *DefaultServer) addHostRootZone() {
|
||||||
handler := newUpstreamResolver(s.ctx)
|
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.upstreamServers = make([]string, len(s.hostsDnsList))
|
handler.upstreamServers = make([]string, len(s.hostsDnsList))
|
||||||
for n, ua := range s.hostsDnsList {
|
for n, ua := range s.hostsDnsList {
|
||||||
a, err := netip.ParseAddr(ua)
|
a, err := netip.ParseAddr(ua)
|
||||||
|
|||||||
5
client/internal/dns/server_android.go
Normal file
5
client/internal/dns/server_android.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
func (s *DefaultServer) initialize() (manager hostManager, err error) {
|
||||||
|
return newHostManager(s.wgInterface)
|
||||||
|
}
|
||||||
7
client/internal/dns/server_darwin.go
Normal file
7
client/internal/dns/server_darwin.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build !ios
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
func (s *DefaultServer) initialize() (manager hostManager, err error) {
|
||||||
|
return newHostManager(s.wgInterface)
|
||||||
|
}
|
||||||
5
client/internal/dns/server_ios.go
Normal file
5
client/internal/dns/server_ios.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
func (s *DefaultServer) initialize() (manager hostManager, err error) {
|
||||||
|
return newHostManager(s.iosDnsManager)
|
||||||
|
}
|
||||||
7
client/internal/dns/server_linux.go
Normal file
7
client/internal/dns/server_linux.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build !android
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
func (s *DefaultServer) initialize() (manager hostManager, err error) {
|
||||||
|
return newHostManager(s.wgInterface)
|
||||||
|
}
|
||||||
@@ -527,8 +527,8 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
|
|||||||
registeredMap: make(registrationMap),
|
registeredMap: make(registrationMap),
|
||||||
},
|
},
|
||||||
hostManager: hostManager,
|
hostManager: hostManager,
|
||||||
currentConfig: hostDNSConfig{
|
currentConfig: HostDNSConfig{
|
||||||
domains: []domainConfig{
|
Domains: []DomainConfig{
|
||||||
{false, "domain0", false},
|
{false, "domain0", false},
|
||||||
{false, "domain1", false},
|
{false, "domain1", false},
|
||||||
{false, "domain2", false},
|
{false, "domain2", false},
|
||||||
@@ -537,13 +537,13 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var domainsUpdate string
|
var domainsUpdate string
|
||||||
hostManager.applyDNSConfigFunc = func(config hostDNSConfig) error {
|
hostManager.applyDNSConfigFunc = func(config HostDNSConfig) error {
|
||||||
domains := []string{}
|
domains := []string{}
|
||||||
for _, item := range config.domains {
|
for _, item := range config.Domains {
|
||||||
if item.disabled {
|
if item.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
domains = append(domains, item.domain)
|
domains = append(domains, item.Domain)
|
||||||
}
|
}
|
||||||
domainsUpdate = strings.Join(domains, ",")
|
domainsUpdate = strings.Join(domains, ",")
|
||||||
return nil
|
return nil
|
||||||
@@ -559,11 +559,11 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
|
|||||||
deactivate()
|
deactivate()
|
||||||
expected := "domain0,domain2"
|
expected := "domain0,domain2"
|
||||||
domains := []string{}
|
domains := []string{}
|
||||||
for _, item := range server.currentConfig.domains {
|
for _, item := range server.currentConfig.Domains {
|
||||||
if item.disabled {
|
if item.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
domains = append(domains, item.domain)
|
domains = append(domains, item.Domain)
|
||||||
}
|
}
|
||||||
got := strings.Join(domains, ",")
|
got := strings.Join(domains, ",")
|
||||||
if expected != got {
|
if expected != got {
|
||||||
@@ -573,11 +573,11 @@ func TestDNSServerUpstreamDeactivateCallback(t *testing.T) {
|
|||||||
reactivate()
|
reactivate()
|
||||||
expected = "domain0,domain1,domain2"
|
expected = "domain0,domain1,domain2"
|
||||||
domains = []string{}
|
domains = []string{}
|
||||||
for _, item := range server.currentConfig.domains {
|
for _, item := range server.currentConfig.Domains {
|
||||||
if item.disabled {
|
if item.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
domains = append(domains, item.domain)
|
domains = append(domains, item.Domain)
|
||||||
}
|
}
|
||||||
got = strings.Join(domains, ",")
|
got = strings.Join(domains, ",")
|
||||||
if expected != got {
|
if expected != got {
|
||||||
|
|||||||
5
client/internal/dns/server_windows.go
Normal file
5
client/internal/dns/server_windows.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
func (s *DefaultServer) initialize() (manager hostManager, err error) {
|
||||||
|
return newHostManager(s.wgInterface)
|
||||||
|
}
|
||||||
@@ -81,8 +81,8 @@ func (s *systemdDbusConfigurator) supportCustomPort() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
func (s *systemdDbusConfigurator) applyDNSConfig(config HostDNSConfig) error {
|
||||||
parsedIP, err := netip.ParseAddr(config.serverIP)
|
parsedIP, err := netip.ParseAddr(config.ServerIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse ip address, error: %s", err)
|
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})
|
err = s.callLinkMethod(systemdDbusSetDNSMethodSuffix, []systemdDbusDNSInput{defaultLinkInput})
|
||||||
if err != nil {
|
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 (
|
var (
|
||||||
@@ -101,24 +101,24 @@ func (s *systemdDbusConfigurator) applyDNSConfig(config hostDNSConfig) error {
|
|||||||
matchDomains []string
|
matchDomains []string
|
||||||
domainsInput []systemdDbusLinkDomainsInput
|
domainsInput []systemdDbusLinkDomainsInput
|
||||||
)
|
)
|
||||||
for _, dConf := range config.domains {
|
for _, dConf := range config.Domains {
|
||||||
if dConf.disabled {
|
if dConf.Disabled {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
domainsInput = append(domainsInput, systemdDbusLinkDomainsInput{
|
domainsInput = append(domainsInput, systemdDbusLinkDomainsInput{
|
||||||
Domain: dns.Fqdn(dConf.domain),
|
Domain: dns.Fqdn(dConf.Domain),
|
||||||
MatchOnly: dConf.matchOnly,
|
MatchOnly: dConf.MatchOnly,
|
||||||
})
|
})
|
||||||
|
|
||||||
if dConf.matchOnly {
|
if dConf.MatchOnly {
|
||||||
matchDomains = append(matchDomains, dConf.domain)
|
matchDomains = append(matchDomains, dConf.Domain)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
searchDomains = append(searchDomains, dConf.domain)
|
searchDomains = append(searchDomains, dConf.Domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.routeAll {
|
if config.RouteAll {
|
||||||
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)
|
||||||
err = s.callLinkMethod(systemdDbusSetDefaultRouteMethodSuffix, true)
|
err = s.callLinkMethod(systemdDbusSetDefaultRouteMethodSuffix, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("setting link as default dns router, failed with error: %s", err)
|
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
|
s.routingAll = true
|
||||||
} else if s.routingAll {
|
} 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)
|
log.Infof("adding %d search domains and %d match domains. Search list: %s , Match list: %s", len(searchDomains), len(matchDomains), searchDomains, matchDomains)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -21,10 +22,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type upstreamClient interface {
|
type upstreamClient interface {
|
||||||
ExchangeContext(ctx context.Context, m *dns.Msg, a string) (r *dns.Msg, rtt time.Duration, err error)
|
exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type upstreamResolver struct {
|
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 {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
upstreamClient upstreamClient
|
upstreamClient upstreamClient
|
||||||
@@ -40,25 +46,25 @@ type upstreamResolver struct {
|
|||||||
reactivate func()
|
reactivate func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUpstreamResolver(parentCTX context.Context) *upstreamResolver {
|
func newUpstreamResolverBase(parentCTX context.Context) *upstreamResolverBase {
|
||||||
ctx, cancel := context.WithCancel(parentCTX)
|
ctx, cancel := context.WithCancel(parentCTX)
|
||||||
return &upstreamResolver{
|
|
||||||
|
return &upstreamResolverBase{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
upstreamClient: &dns.Client{},
|
|
||||||
upstreamTimeout: upstreamTimeout,
|
upstreamTimeout: upstreamTimeout,
|
||||||
reactivatePeriod: reactivatePeriod,
|
reactivatePeriod: reactivatePeriod,
|
||||||
failsTillDeact: failsTillDeact,
|
failsTillDeact: failsTillDeact,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *upstreamResolver) stop() {
|
func (u *upstreamResolverBase) stop() {
|
||||||
log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers)
|
log.Debugf("stopping serving DNS for upstreams %s", u.upstreamServers)
|
||||||
u.cancel()
|
u.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeDNS handles a DNS request
|
// ServeDNS handles a DNS request
|
||||||
func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
func (u *upstreamResolverBase) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
defer u.checkUpstreamFails()
|
defer u.checkUpstreamFails()
|
||||||
|
|
||||||
log.WithField("question", r.Question[0]).Trace("received an upstream question")
|
log.WithField("question", r.Question[0]).Trace("received an upstream question")
|
||||||
@@ -70,10 +76,8 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, upstream := range u.upstreamServers {
|
for _, upstream := range u.upstreamServers {
|
||||||
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
|
|
||||||
rm, t, err := u.upstreamClient.ExchangeContext(ctx, r, upstream)
|
|
||||||
|
|
||||||
cancel()
|
rm, t, err := u.upstreamClient.exchange(upstream, r)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == context.DeadlineExceeded || isTimeout(err) {
|
if err == context.DeadlineExceeded || isTimeout(err) {
|
||||||
@@ -83,7 +87,19 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
}
|
}
|
||||||
u.failsCount.Add(1)
|
u.failsCount.Add(1)
|
||||||
log.WithError(err).WithField("upstream", upstream).
|
log.WithError(err).WithField("upstream", upstream).
|
||||||
Error("got an error while querying the 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")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +122,7 @@ func (u *upstreamResolver) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|||||||
// If fails count is greater that failsTillDeact, upstream resolving
|
// If fails count is greater that failsTillDeact, upstream resolving
|
||||||
// will be disabled for reactivatePeriod, after that time period fails counter
|
// will be disabled for reactivatePeriod, after that time period fails counter
|
||||||
// will be reset and upstream will be reactivated.
|
// will be reset and upstream will be reactivated.
|
||||||
func (u *upstreamResolver) checkUpstreamFails() {
|
func (u *upstreamResolverBase) checkUpstreamFails() {
|
||||||
u.mutex.Lock()
|
u.mutex.Lock()
|
||||||
defer u.mutex.Unlock()
|
defer u.mutex.Unlock()
|
||||||
|
|
||||||
@@ -118,15 +134,18 @@ func (u *upstreamResolver) checkUpstreamFails() {
|
|||||||
case <-u.ctx.Done():
|
case <-u.ctx.Done():
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
log.Warnf("upstream resolving is disabled for %v", reactivatePeriod)
|
// 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.deactivate()
|
||||||
u.disabled = true
|
u.disabled = true
|
||||||
go u.waitUntilResponse()
|
go u.waitUntilResponse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// waitUntilResponse retries, in an exponential interval, querying the upstream servers until it gets a positive response
|
// waitUntilResponse retries, in an exponential interval, querying the upstream servers until it gets a positive response
|
||||||
func (u *upstreamResolver) waitUntilResponse() {
|
func (u *upstreamResolverBase) waitUntilResponse() {
|
||||||
exponentialBackOff := &backoff.ExponentialBackOff{
|
exponentialBackOff := &backoff.ExponentialBackOff{
|
||||||
InitialInterval: 500 * time.Millisecond,
|
InitialInterval: 500 * time.Millisecond,
|
||||||
RandomizationFactor: 0.5,
|
RandomizationFactor: 0.5,
|
||||||
@@ -148,10 +167,7 @@ func (u *upstreamResolver) waitUntilResponse() {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
for _, upstream := range u.upstreamServers {
|
for _, upstream := range u.upstreamServers {
|
||||||
ctx, cancel := context.WithTimeout(u.ctx, u.upstreamTimeout)
|
_, _, err = u.upstreamClient.exchange(upstream, r)
|
||||||
_, _, err = u.upstreamClient.ExchangeContext(ctx, r, upstream)
|
|
||||||
|
|
||||||
cancel()
|
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
93
client/internal/dns/upstream_ios.go
Normal file
93
client/internal/dns/upstream_ios.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
32
client/internal/dns/upstream_nonios.go
Normal file
32
client/internal/dns/upstream_nonios.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -49,15 +50,6 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) {
|
|||||||
timeout: upstreamTimeout,
|
timeout: upstreamTimeout,
|
||||||
responseShouldBeNil: true,
|
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 resolve if first upstream times out
|
||||||
// should not write when both fails
|
// should not write when both fails
|
||||||
@@ -66,7 +58,7 @@ func TestUpstreamResolver_ServeDNS(t *testing.T) {
|
|||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.TODO())
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
resolver := newUpstreamResolver(ctx)
|
resolver, _ := newUpstreamResolver(ctx, "", net.IP{}, &net.IPNet{})
|
||||||
resolver.upstreamServers = testCase.InputServers
|
resolver.upstreamServers = testCase.InputServers
|
||||||
resolver.upstreamTimeout = testCase.timeout
|
resolver.upstreamTimeout = testCase.timeout
|
||||||
if testCase.cancelCTX {
|
if testCase.cancelCTX {
|
||||||
@@ -114,12 +106,12 @@ type mockUpstreamResolver struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExchangeContext mock implementation of ExchangeContext from upstreamResolver
|
// ExchangeContext mock implementation of ExchangeContext from upstreamResolver
|
||||||
func (c mockUpstreamResolver) ExchangeContext(_ context.Context, _ *dns.Msg, _ string) (r *dns.Msg, rtt time.Duration, err error) {
|
func (c mockUpstreamResolver) exchange(upstream string, r *dns.Msg) (*dns.Msg, time.Duration, error) {
|
||||||
return c.r, c.rtt, c.err
|
return c.r, c.rtt, c.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpstreamResolver_DeactivationReactivation(t *testing.T) {
|
func TestUpstreamResolver_DeactivationReactivation(t *testing.T) {
|
||||||
resolver := &upstreamResolver{
|
resolver := &upstreamResolverBase{
|
||||||
ctx: context.TODO(),
|
ctx: context.TODO(),
|
||||||
upstreamClient: &mockUpstreamResolver{
|
upstreamClient: &mockUpstreamResolver{
|
||||||
err: nil,
|
err: nil,
|
||||||
@@ -156,7 +148,7 @@ func TestUpstreamResolver_DeactivationReactivation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !resolver.disabled {
|
if !resolver.disabled {
|
||||||
t.Errorf("resolver should be disabled")
|
t.Errorf("resolver should be Disabled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/ice/v2"
|
"github.com/pion/ice/v3"
|
||||||
|
"github.com/pion/stun/v2"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
@@ -95,9 +96,9 @@ type Engine struct {
|
|||||||
mobileDep MobileDependency
|
mobileDep MobileDependency
|
||||||
|
|
||||||
// STUNs is a list of STUN servers used by ICE
|
// STUNs is a list of STUN servers used by ICE
|
||||||
STUNs []*ice.URL
|
STUNs []*stun.URI
|
||||||
// TURNs is a list of STUN servers used by ICE
|
// TURNs is a list of STUN servers used by ICE
|
||||||
TURNs []*ice.URL
|
TURNs []*stun.URI
|
||||||
|
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
||||||
@@ -146,8 +147,8 @@ func NewEngine(
|
|||||||
syncMsgMux: &sync.Mutex{},
|
syncMsgMux: &sync.Mutex{},
|
||||||
config: config,
|
config: config,
|
||||||
mobileDep: mobileDep,
|
mobileDep: mobileDep,
|
||||||
STUNs: []*ice.URL{},
|
STUNs: []*stun.URI{},
|
||||||
TURNs: []*ice.URL{},
|
TURNs: []*stun.URI{},
|
||||||
networkSerial: 0,
|
networkSerial: 0,
|
||||||
sshServerFunc: nbssh.DefaultSSHServer,
|
sshServerFunc: nbssh.DefaultSSHServer,
|
||||||
statusRecorder: statusRecorder,
|
statusRecorder: statusRecorder,
|
||||||
@@ -197,7 +198,8 @@ func (e *Engine) Start() error {
|
|||||||
|
|
||||||
var routes []*route.Route
|
var routes []*route.Route
|
||||||
|
|
||||||
if runtime.GOOS == "android" {
|
switch runtime.GOOS {
|
||||||
|
case "android":
|
||||||
var dnsConfig *nbdns.Config
|
var dnsConfig *nbdns.Config
|
||||||
routes, dnsConfig, err = e.readInitialSettings()
|
routes, dnsConfig, err = e.readInitialSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -207,25 +209,34 @@ func (e *Engine) Start() error {
|
|||||||
e.dnsServer = dns.NewDefaultServerPermanentUpstream(e.ctx, e.wgInterface, e.mobileDep.HostDNSAddresses, *dnsConfig, e.mobileDep.NetworkChangeListener)
|
e.dnsServer = dns.NewDefaultServerPermanentUpstream(e.ctx, e.wgInterface, e.mobileDep.HostDNSAddresses, *dnsConfig, e.mobileDep.NetworkChangeListener)
|
||||||
go e.mobileDep.DnsReadyListener.OnReady()
|
go e.mobileDep.DnsReadyListener.OnReady()
|
||||||
}
|
}
|
||||||
} else if e.dnsServer == nil {
|
case "ios":
|
||||||
// todo fix custom address
|
if e.dnsServer == nil {
|
||||||
|
e.dnsServer = dns.NewDefaultServerIos(e.ctx, e.wgInterface, e.mobileDep.DnsManager)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if e.dnsServer == nil {
|
||||||
e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress)
|
e.dnsServer, err = dns.NewDefaultServer(e.ctx, e.wgInterface, e.config.CustomDNSAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.close()
|
e.close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes)
|
e.routeManager = routemanager.NewManager(e.ctx, e.config.WgPrivateKey.PublicKey().String(), e.wgInterface, e.statusRecorder, routes)
|
||||||
e.routeManager.SetRouteChangeListener(e.mobileDep.NetworkChangeListener)
|
e.routeManager.SetRouteChangeListener(e.mobileDep.NetworkChangeListener)
|
||||||
|
|
||||||
if runtime.GOOS == "android" {
|
switch runtime.GOOS {
|
||||||
err = e.wgInterface.CreateOnMobile(iface.MobileIFaceArguments{
|
case "android":
|
||||||
|
err = e.wgInterface.CreateOnAndroid(iface.MobileIFaceArguments{
|
||||||
Routes: e.routeManager.InitialRouteRange(),
|
Routes: e.routeManager.InitialRouteRange(),
|
||||||
Dns: e.dnsServer.DnsIP(),
|
Dns: e.dnsServer.DnsIP(),
|
||||||
SearchDomains: e.dnsServer.SearchDomains(),
|
SearchDomains: e.dnsServer.SearchDomains(),
|
||||||
})
|
})
|
||||||
} else {
|
case "ios":
|
||||||
|
e.mobileDep.NetworkChangeListener.SetInterfaceIP(wgAddr)
|
||||||
|
err = e.wgInterface.CreateOniOS(e.mobileDep.FileDescriptor)
|
||||||
|
default:
|
||||||
err = e.wgInterface.Create()
|
err = e.wgInterface.Create()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -565,10 +576,10 @@ func (e *Engine) updateSTUNs(stuns []*mgmProto.HostConfig) error {
|
|||||||
if len(stuns) == 0 {
|
if len(stuns) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var newSTUNs []*ice.URL
|
var newSTUNs []*stun.URI
|
||||||
log.Debugf("got STUNs update from Management Service, updating")
|
log.Debugf("got STUNs update from Management Service, updating")
|
||||||
for _, stun := range stuns {
|
for _, s := range stuns {
|
||||||
url, err := ice.ParseURL(stun.Uri)
|
url, err := stun.ParseURI(s.Uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -583,10 +594,10 @@ func (e *Engine) updateTURNs(turns []*mgmProto.ProtectedHostConfig) error {
|
|||||||
if len(turns) == 0 {
|
if len(turns) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var newTURNs []*ice.URL
|
var newTURNs []*stun.URI
|
||||||
log.Debugf("got TURNs update from Management Service, updating")
|
log.Debugf("got TURNs update from Management Service, updating")
|
||||||
for _, turn := range turns {
|
for _, turn := range turns {
|
||||||
url, err := ice.ParseURL(turn.HostConfig.Uri)
|
url, err := stun.ParseURI(turn.HostConfig.Uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -836,7 +847,7 @@ func (e *Engine) peerExists(peerKey string) bool {
|
|||||||
|
|
||||||
func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, error) {
|
func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, error) {
|
||||||
log.Debugf("creating peer connection %s", pubKey)
|
log.Debugf("creating peer connection %s", pubKey)
|
||||||
var stunTurn []*ice.URL
|
var stunTurn []*stun.URI
|
||||||
stunTurn = append(stunTurn, e.STUNs...)
|
stunTurn = append(stunTurn, e.STUNs...)
|
||||||
stunTurn = append(stunTurn, e.TURNs...)
|
stunTurn = append(stunTurn, e.TURNs...)
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/transport/v2/stdnet"
|
"github.com/pion/transport/v3/stdnet"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ package listener
|
|||||||
// NetworkChangeListener is a callback interface for mobile system
|
// NetworkChangeListener is a callback interface for mobile system
|
||||||
type NetworkChangeListener interface {
|
type NetworkChangeListener interface {
|
||||||
// OnNetworkChanged invoke when network settings has been changed
|
// OnNetworkChanged invoke when network settings has been changed
|
||||||
OnNetworkChanged()
|
OnNetworkChanged(string)
|
||||||
|
SetInterfaceIP(string)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,4 +14,6 @@ type MobileDependency struct {
|
|||||||
NetworkChangeListener listener.NetworkChangeListener
|
NetworkChangeListener listener.NetworkChangeListener
|
||||||
HostDNSAddresses []string
|
HostDNSAddresses []string
|
||||||
DnsReadyListener dns.ReadyListener
|
DnsReadyListener dns.ReadyListener
|
||||||
|
DnsManager dns.IosDnsManager
|
||||||
|
FileDescriptor int32
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/ice/v2"
|
"github.com/pion/ice/v3"
|
||||||
|
"github.com/pion/stun/v2"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
@@ -45,7 +47,7 @@ type ConnConfig struct {
|
|||||||
LocalKey string
|
LocalKey string
|
||||||
|
|
||||||
// StunTurn is a list of STUN and TURN URLs
|
// StunTurn is a list of STUN and TURN URLs
|
||||||
StunTurn []*ice.URL
|
StunTurn []*stun.URI
|
||||||
|
|
||||||
// InterfaceBlackList is a list of machine interfaces that should be filtered out by ICE Candidate gathering
|
// 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)
|
// (e.g. if eth0 is in the list, host candidate of this interface won't be used)
|
||||||
@@ -141,7 +143,7 @@ func (conn *Conn) WgConfig() WgConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStunTurn update the turn and stun addresses
|
// UpdateStunTurn update the turn and stun addresses
|
||||||
func (conn *Conn) UpdateStunTurn(turnStun []*ice.URL) {
|
func (conn *Conn) UpdateStunTurn(turnStun []*stun.URI) {
|
||||||
conn.config.StunTurn = turnStun
|
conn.config.StunTurn = turnStun
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +227,10 @@ func (conn *Conn) candidateTypes() []ice.CandidateType {
|
|||||||
if hasICEForceRelayConn() {
|
if hasICEForceRelayConn() {
|
||||||
return []ice.CandidateType{ice.CandidateTypeRelay}
|
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}
|
return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive, ice.CandidateTypeRelay}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/magiconair/properties/assert"
|
"github.com/magiconair/properties/assert"
|
||||||
"github.com/pion/ice/v2"
|
"github.com/pion/stun/v2"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
"github.com/netbirdio/netbird/client/internal/wgproxy"
|
"github.com/netbirdio/netbird/client/internal/wgproxy"
|
||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
var connConf = ConnConfig{
|
var connConf = ConnConfig{
|
||||||
Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
||||||
LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
||||||
StunTurn: []*ice.URL{},
|
StunTurn: []*stun.URI{},
|
||||||
InterfaceBlackList: nil,
|
InterfaceBlackList: nil,
|
||||||
Timeout: time.Second,
|
Timeout: time.Second,
|
||||||
LocalWgPort: 51820,
|
LocalWgPort: 51820,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pion/transport/v2/stdnet"
|
"github.com/pion/transport/v3/stdnet"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package routemanager
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal/listener"
|
"github.com/netbirdio/netbird/client/internal/listener"
|
||||||
@@ -50,9 +51,6 @@ func (n *notifier) onNewRoutes(idMap map[string][]*route.Route) {
|
|||||||
|
|
||||||
n.routeRangers = newNets
|
n.routeRangers = newNets
|
||||||
|
|
||||||
if !n.hasDiff(n.initialRouteRangers, newNets) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n.notify()
|
n.notify()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +62,7 @@ func (n *notifier) notify() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func(l listener.NetworkChangeListener) {
|
go func(l listener.NetworkChangeListener) {
|
||||||
l.OnNetworkChanged()
|
l.OnNetworkChanged(strings.Join(n.routeRangers, ","))
|
||||||
}(n.listener)
|
}(n.listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build android
|
||||||
|
|
||||||
package routemanager
|
package routemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
15
client/internal/routemanager/systemops_ios.go
Normal file
15
client/internal/routemanager/systemops_ios.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !android
|
//go:build !android && !ios
|
||||||
|
|
||||||
package routemanager
|
package routemanager
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pion/transport/v2/stdnet"
|
"github.com/pion/transport/v3/stdnet"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package stdnet
|
package stdnet
|
||||||
|
|
||||||
import "github.com/pion/transport/v2"
|
import "github.com/pion/transport/v3"
|
||||||
|
|
||||||
// ExternalIFaceDiscover provide an option for external services (mobile)
|
// ExternalIFaceDiscover provide an option for external services (mobile)
|
||||||
// to collect network interface information
|
// to collect network interface information
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package stdnet
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pionDiscover struct {
|
type pionDiscover struct {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ package stdnet
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
"github.com/pion/transport/v2/stdnet"
|
"github.com/pion/transport/v3/stdnet"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Net is an implementation of the net.Net interface
|
// Net is an implementation of the net.Net interface
|
||||||
|
|||||||
224
client/ios/NetBirdSDK/client.go
Normal file
224
client/ios/NetBirdSDK/client.go
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
5
client/ios/NetBirdSDK/gomobile.go
Normal file
5
client/ios/NetBirdSDK/gomobile.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
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
|
||||||
10
client/ios/NetBirdSDK/logger.go
Normal file
10
client/ios/NetBirdSDK/logger.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
159
client/ios/NetBirdSDK/login.go
Normal file
159
client/ios/NetBirdSDK/login.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
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 {
|
||||||
|
_, err = internal.GetPKCEAuthorizationFlowInfo(a.ctx, a.config.PrivateKey, a.config.ManagementURL)
|
||||||
|
if s, ok := gstatus.FromError(err); ok && s.Code() == codes.NotFound {
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
50
client/ios/NetBirdSDK/peer_notifier.go
Normal file
50
client/ios/NetBirdSDK/peer_notifier.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
78
client/ios/NetBirdSDK/preferences.go
Normal file
78
client/ios/NetBirdSDK/preferences.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
120
client/ios/NetBirdSDK/preferences_test.go
Normal file
120
client/ios/NetBirdSDK/preferences_test.go
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,12 @@ import (
|
|||||||
// DeviceNameCtxKey context key for device name
|
// DeviceNameCtxKey context key for device name
|
||||||
const DeviceNameCtxKey = "deviceName"
|
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
|
// Info is an object that contains machine information
|
||||||
// Most of the code is taken from https://github.com/matishsiao/goInfo
|
// Most of the code is taken from https://github.com/matishsiao/goInfo
|
||||||
type Info struct {
|
type Info struct {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build !ios
|
||||||
|
// +build !ios
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
44
client/system/info_ios.go
Normal file
44
client/system/info_ios.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
18
go.mod
18
go.mod
@@ -6,12 +6,12 @@ require (
|
|||||||
github.com/cenkalti/backoff/v4 v4.1.3
|
github.com/cenkalti/backoff/v4 v4.1.3
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/golang/protobuf v1.5.3
|
github.com/golang/protobuf v1.5.3
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7
|
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7
|
||||||
github.com/onsi/ginkgo v1.16.5
|
github.com/onsi/ginkgo v1.16.5
|
||||||
github.com/onsi/gomega v1.18.1
|
github.com/onsi/gomega v1.18.1
|
||||||
github.com/pion/ice/v2 v2.3.1
|
github.com/pion/ice/v3 v3.0.2
|
||||||
github.com/rs/cors v1.8.0
|
github.com/rs/cors v1.8.0
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
github.com/spf13/cobra v1.6.1
|
github.com/spf13/cobra v1.6.1
|
||||||
@@ -56,12 +56,13 @@ require (
|
|||||||
github.com/okta/okta-sdk-golang/v2 v2.18.0
|
github.com/okta/okta-sdk-golang/v2 v2.18.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/pion/logging v0.2.2
|
github.com/pion/logging v0.2.2
|
||||||
github.com/pion/stun v0.4.0
|
github.com/pion/stun/v2 v2.0.0
|
||||||
github.com/pion/transport/v2 v2.0.2
|
github.com/pion/transport/v2 v2.2.1
|
||||||
|
github.com/pion/transport/v3 v3.0.1
|
||||||
github.com/prometheus/client_golang v1.14.0
|
github.com/prometheus/client_golang v1.14.0
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/yusufpapurcu/wmi v1.2.3
|
github.com/yusufpapurcu/wmi v1.2.3
|
||||||
go.opentelemetry.io/otel v1.11.1
|
go.opentelemetry.io/otel v1.11.1
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.33.0
|
go.opentelemetry.io/otel/exporters/prometheus v0.33.0
|
||||||
@@ -124,11 +125,10 @@ require (
|
|||||||
github.com/nxadm/tail v1.4.8 // indirect
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
|
||||||
github.com/pegasus-kv/thrift v0.13.0 // indirect
|
github.com/pegasus-kv/thrift v0.13.0 // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.6 // indirect
|
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||||
github.com/pion/mdns v0.0.7 // indirect
|
github.com/pion/mdns v0.0.9 // indirect
|
||||||
github.com/pion/randutil v0.1.0 // indirect
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
github.com/pion/turn/v2 v2.1.0 // indirect
|
github.com/pion/turn/v3 v3.0.1 // indirect
|
||||||
github.com/pion/udp/v2 v2.0.1 // indirect
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_model v0.3.0 // indirect
|
github.com/prometheus/client_model v0.3.0 // indirect
|
||||||
github.com/prometheus/common v0.37.0 // indirect
|
github.com/prometheus/common v0.37.0 // indirect
|
||||||
|
|||||||
59
go.sum
59
go.sum
@@ -340,8 +340,8 @@ github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkj
|
|||||||
github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
@@ -545,25 +545,24 @@ github.com/pegasus-kv/thrift v0.13.0 h1:4ESwaNoHImfbHa9RUGJiJZ4hrxorihZHk5aarYwY
|
|||||||
github.com/pegasus-kv/thrift v0.13.0/go.mod h1:Gl9NT/WHG6ABm6NsrbfE8LiJN0sAyneCrvB4qN4NPqQ=
|
github.com/pegasus-kv/thrift v0.13.0/go.mod h1:Gl9NT/WHG6ABm6NsrbfE8LiJN0sAyneCrvB4qN4NPqQ=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=
|
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
|
||||||
github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
|
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||||
github.com/pion/ice/v2 v2.3.1 h1:FQCmUfZe2Jpe7LYStVBOP6z1DiSzbIateih3TztgTjc=
|
github.com/pion/ice/v3 v3.0.2 h1:dNQnKsjLvOWz+PaI4tw1VnLYTp9adihC1HIASFGajmI=
|
||||||
github.com/pion/ice/v2 v2.3.1/go.mod h1:aq2kc6MtYNcn4XmMhobAv6hTNJiHzvD0yXRz80+bnP8=
|
github.com/pion/ice/v3 v3.0.2/go.mod h1:q3BDzTsxbqP0ySMSHrFuw2MYGUx/AC3WQfRGC5F/0Is=
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||||
github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
|
github.com/pion/mdns v0.0.9 h1:7Ue5KZsqq8EuqStnpPWV33vYYEH0+skdDN5L7EiEsI4=
|
||||||
github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
|
github.com/pion/mdns v0.0.9/go.mod h1:2JA5exfxwzXiCihmxpTKgFUpiQws2MnipoPK09vecIc=
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
github.com/pion/stun v0.4.0 h1:vgRrbBE2htWHy7l3Zsxckk7rkjnjOsSM7PHZnBwo8rk=
|
github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
|
||||||
github.com/pion/stun v0.4.0/go.mod h1:QPsh1/SbXASntw3zkkrIk3ZJVKz4saBY2G7S10P3wCw=
|
github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
|
||||||
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
|
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
|
||||||
github.com/pion/transport/v2 v2.0.2 h1:St+8o+1PEzPT51O9bv+tH/KYYLMNR5Vwm5Z3Qkjsywg=
|
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||||
github.com/pion/transport/v2 v2.0.2/go.mod h1:vrz6bUbFr/cjdwbnxq8OdDDzHf7JJfGsIRkxfpZoTA0=
|
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
|
||||||
github.com/pion/turn/v2 v2.1.0 h1:5wGHSgGhJhP/RpabkUb/T9PdsAjkGLS6toYz5HNzoSI=
|
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||||
github.com/pion/turn/v2 v2.1.0/go.mod h1:yrT5XbXSGX1VFSF31A3c1kCNB5bBZgk/uu5LET162qs=
|
github.com/pion/turn/v3 v3.0.1 h1:wLi7BTQr6/Q20R0vt/lHbjv6y4GChFtC33nkYbasoT8=
|
||||||
github.com/pion/udp/v2 v2.0.1 h1:xP0z6WNux1zWEjhC7onRA3EwwSliXqu1ElUZAQhUP54=
|
github.com/pion/turn/v3 v3.0.1/go.mod h1:MrJDKgqryDyWy1/4NT9TWfXWGMC7UHT6pJIv1+gMeNE=
|
||||||
github.com/pion/udp/v2 v2.0.1/go.mod h1:B7uvTMP00lzWdyMr/1PVZXtV3wpPIxBRd4Wl6AksXn8=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
@@ -661,8 +660,10 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
||||||
@@ -730,8 +731,10 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
|
|||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -836,11 +839,12 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -961,20 +965,22 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.1-0.20230222185716-a3b23cc77e89/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.1-0.20230222185716-a3b23cc77e89/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -987,11 +993,10 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pion/stun"
|
"github.com/pion/stun/v2"
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
wgConn "golang.zx2c4.com/wireguard/conn"
|
wgConn "golang.zx2c4.com/wireguard/conn"
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pion/ice/v2"
|
"github.com/pion/ice/v3"
|
||||||
"github.com/pion/stun"
|
|
||||||
"github.com/pion/transport/v2/stdnet"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/pion/logging"
|
"github.com/pion/logging"
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/stun/v2"
|
||||||
|
"github.com/pion/transport/v3"
|
||||||
|
"github.com/pion/transport/v3/stdnet"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -224,6 +223,10 @@ func (m *UDPMuxDefault) GetListenAddresses() []net.Addr {
|
|||||||
// GetConn returns a PacketConn given the connection's ufrag and network address
|
// GetConn returns a PacketConn given the connection's ufrag and network address
|
||||||
// creates the connection if an existing one can't be found
|
// creates the connection if an existing one can't be found
|
||||||
func (m *UDPMuxDefault) GetConn(ufrag string, addr net.Addr) (net.PacketConn, error) {
|
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
|
var isIPv6 bool
|
||||||
if udpAddr, _ := addr.(*net.UDPAddr); udpAddr != nil && udpAddr.IP.To4() == nil {
|
if udpAddr, _ := addr.(*net.UDPAddr); udpAddr != nil && udpAddr.IP.To4() == nil {
|
||||||
@@ -282,15 +285,7 @@ func (m *UDPMuxDefault) RemoveConnByUfrag(ufrag string) {
|
|||||||
for _, c := range removedConns {
|
for _, c := range removedConns {
|
||||||
addresses := c.getAddresses()
|
addresses := c.getAddresses()
|
||||||
for _, addr := range addresses {
|
for _, addr := range addresses {
|
||||||
if connList, ok := m.addressMap[addr]; ok {
|
delete(m.addressMap, addr)
|
||||||
var newList []*udpMuxedConn
|
|
||||||
for _, conn := range connList {
|
|
||||||
if conn.params.Key != ufrag {
|
|
||||||
newList = append(newList, conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.addressMap[addr] = newList
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/pion/logging"
|
"github.com/pion/logging"
|
||||||
"github.com/pion/stun"
|
"github.com/pion/stun/v2"
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UniversalUDPMuxDefault handles STUN and TURN servers packets by wrapping the original UDPConn
|
// 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")
|
log.Debugf("stopped reading from the UDPConn due to finished context")
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
_, a, err := m.params.UDPConn.ReadFrom(buf)
|
n, a, err := m.params.UDPConn.ReadFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error while reading packet: %s", err)
|
log.Errorf("error while reading packet: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msg := &stun.Message{
|
msg := &stun.Message{
|
||||||
Raw: buf,
|
Raw: append([]byte{}, buf[:n]...),
|
||||||
}
|
}
|
||||||
err = msg.Decode()
|
err = msg.Decode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/logging"
|
"github.com/pion/logging"
|
||||||
"github.com/pion/transport/v2/packetio"
|
"github.com/pion/transport/v3/packetio"
|
||||||
)
|
)
|
||||||
|
|
||||||
type udpMuxedConnParams struct {
|
type udpMuxedConnParams struct {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
@@ -28,14 +28,20 @@ func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter
|
|||||||
return wgIFace, nil
|
return wgIFace, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOnMobile creates a new Wireguard interface, sets a given IP and brings it up.
|
// CreateOnAndroid creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
// Will reuse an existing one.
|
// Will reuse an existing one.
|
||||||
func (w *WGIface) CreateOnMobile(mIFaceArgs MobileIFaceArguments) error {
|
func (w *WGIface) CreateOnAndroid(mIFaceArgs MobileIFaceArguments) error {
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
defer w.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
return w.tun.Create(mIFaceArgs)
|
return w.tun.Create(mIFaceArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateOniOS creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
|
// Will reuse an existing one.
|
||||||
|
func (w *WGIface) CreateOniOS(tunFd int32) error {
|
||||||
|
return fmt.Errorf("this function has not implemented on mobile")
|
||||||
|
}
|
||||||
|
|
||||||
// Create this function make sense on mobile only
|
// Create this function make sense on mobile only
|
||||||
func (w *WGIface) Create() error {
|
func (w *WGIface) Create() error {
|
||||||
return fmt.Errorf("this function has not implemented on mobile")
|
return fmt.Errorf("this function has not implemented on mobile")
|
||||||
|
|||||||
51
iface/iface_ios.go
Normal file
51
iface/iface_ios.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//go:build ios
|
||||||
|
// +build ios
|
||||||
|
|
||||||
|
package iface
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pion/transport/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
|
func NewWGIFace(ifaceName string, address string, mtu int, tunAdapter TunAdapter, transportNet transport.Net) (*WGIface, error) {
|
||||||
|
wgIFace := &WGIface{
|
||||||
|
mu: sync.Mutex{},
|
||||||
|
}
|
||||||
|
|
||||||
|
wgAddress, err := parseWGAddress(address)
|
||||||
|
if err != nil {
|
||||||
|
return wgIFace, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tun := newTunDevice(ifaceName, wgAddress, mtu, tunAdapter, transportNet)
|
||||||
|
wgIFace.tun = tun
|
||||||
|
|
||||||
|
wgIFace.configurer = newWGConfigurer(tun)
|
||||||
|
|
||||||
|
wgIFace.userspaceBind = !WireGuardModuleIsLoaded()
|
||||||
|
|
||||||
|
return wgIFace, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOniOS creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
|
// Will reuse an existing one.
|
||||||
|
func (w *WGIface) CreateOniOS(tunFd int32) error {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
return w.tun.Create(tunFd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOnAndroid creates a new Wireguard interface, sets a given IP and brings it up.
|
||||||
|
// Will reuse an existing one.
|
||||||
|
func (w *WGIface) CreateOnAndroid(mIFaceArgs MobileIFaceArguments) error {
|
||||||
|
return fmt.Errorf("this function has not implemented on mobile")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create this function make sense on mobile only
|
||||||
|
func (w *WGIface) Create() error {
|
||||||
|
return fmt.Errorf("this function has not implemented on mobile")
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build !android
|
//go:build !android && !ios
|
||||||
|
// +build !android,!ios
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
@@ -6,7 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWGIFace Creates a new WireGuard interface instance
|
// NewWGIFace Creates a new WireGuard interface instance
|
||||||
@@ -27,8 +28,13 @@ func NewWGIFace(iFaceName string, address string, mtu int, tunAdapter TunAdapter
|
|||||||
return wgIFace, nil
|
return wgIFace, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOnMobile this function make sense on mobile only
|
// CreateOnAndroid this function make sense on mobile only
|
||||||
func (w *WGIface) CreateOnMobile(mIFaceArgs MobileIFaceArguments) error {
|
func (w *WGIface) CreateOnAndroid(mIFaceArgs MobileIFaceArguments) error {
|
||||||
|
return fmt.Errorf("this function has not implemented on non mobile")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOniOS this function make sense on mobile only
|
||||||
|
func (w *WGIface) CreateOniOS(tunFd int32) error {
|
||||||
return fmt.Errorf("this function has not implemented on non mobile")
|
return fmt.Errorf("this function has not implemented on non mobile")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/transport/v2/stdnet"
|
"github.com/pion/transport/v3/stdnet"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build android || ios
|
||||||
|
// +build android ios
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
//go:build android
|
||||||
|
// +build android
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"golang.zx2c4.com/wireguard/device"
|
"golang.zx2c4.com/wireguard/device"
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build !ios
|
||||||
|
// +build !ios
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
101
iface/tun_ios.go
Normal file
101
iface/tun_ios.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
//go:build ios
|
||||||
|
// +build ios
|
||||||
|
|
||||||
|
package iface
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pion/transport/v2"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"golang.zx2c4.com/wireguard/device"
|
||||||
|
"golang.zx2c4.com/wireguard/tun"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/iface/bind"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tunDevice struct {
|
||||||
|
address WGAddress
|
||||||
|
mtu int
|
||||||
|
tunAdapter TunAdapter
|
||||||
|
iceBind *bind.ICEBind
|
||||||
|
|
||||||
|
fd int
|
||||||
|
name string
|
||||||
|
device *device.Device
|
||||||
|
wrapper *DeviceWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTunDevice(name string, address WGAddress, mtu int, tunAdapter TunAdapter, transportNet transport.Net) *tunDevice {
|
||||||
|
return &tunDevice{
|
||||||
|
name: name,
|
||||||
|
address: address,
|
||||||
|
mtu: mtu,
|
||||||
|
tunAdapter: tunAdapter,
|
||||||
|
iceBind: bind.NewICEBind(transportNet),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) Create(tunFd int32) error {
|
||||||
|
log.Infof("create tun interface")
|
||||||
|
|
||||||
|
dupTunFd, err := unix.Dup(int(tunFd))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to dup tun fd: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unix.SetNonblock(dupTunFd, true)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to set tun fd as non blocking: %v", err)
|
||||||
|
unix.Close(dupTunFd)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tun, err := tun.CreateTUNFromFile(os.NewFile(uintptr(dupTunFd), "/dev/tun"), 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Unable to create new tun device from fd: %v", err)
|
||||||
|
unix.Close(dupTunFd)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.wrapper = newDeviceWrapper(tun)
|
||||||
|
log.Debug("Attaching to interface")
|
||||||
|
t.device = device.NewDevice(t.wrapper, t.iceBind, device.NewLogger(device.LogLevelSilent, "[wiretrustee] "))
|
||||||
|
// without this property mobile devices can discover remote endpoints if the configured one was wrong.
|
||||||
|
// this helps with support for the older NetBird clients that had a hardcoded direct mode
|
||||||
|
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
|
||||||
|
|
||||||
|
err = t.device.Up()
|
||||||
|
if err != nil {
|
||||||
|
t.device.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debugf("device is ready to use: %s", t.name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) Device() *device.Device {
|
||||||
|
return t.device
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) DeviceName() string {
|
||||||
|
return t.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) WgAddress() WGAddress {
|
||||||
|
return t.address
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) UpdateAddr(addr WGAddress) error {
|
||||||
|
// todo implement
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tunDevice) Close() (err error) {
|
||||||
|
if t.device != nil {
|
||||||
|
t.device.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build (linux || darwin) && !android
|
//go:build (linux || darwin) && !android && !ios
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
"golang.zx2c4.com/wireguard/ipc"
|
"golang.zx2c4.com/wireguard/ipc"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/iface/bind"
|
"github.com/netbirdio/netbird/iface/bind"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/pion/transport/v2"
|
"github.com/pion/transport/v3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
"golang.zx2c4.com/wireguard/device"
|
"golang.zx2c4.com/wireguard/device"
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
|
//go:build ios || android
|
||||||
|
// +build ios android
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,6 +114,52 @@ func (c *wGConfigurer) addAllowedIP(peerKey string, allowedIP string) error {
|
|||||||
return c.tunDevice.Device().IpcSet(toWgUserspaceString(config))
|
return c.tunDevice.Device().IpcSet(toWgUserspaceString(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *wGConfigurer) removeAllowedIP(peerKey string, allowedIP string) error {
|
func (c *wGConfigurer) removeAllowedIP(peerKey string, ip string) error {
|
||||||
return errFuncNotImplemented
|
ipc, err := c.tunDevice.Device().IpcGet()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
||||||
|
hexKey := hex.EncodeToString(peerKeyParsed[:])
|
||||||
|
|
||||||
|
lines := strings.Split(ipc, "\n")
|
||||||
|
|
||||||
|
output := ""
|
||||||
|
foundPeer := false
|
||||||
|
removedAllowedIP := false
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
// If we're within the details of the found peer and encounter another public key,
|
||||||
|
// this means we're starting another peer's details. So, reset the flag.
|
||||||
|
if strings.HasPrefix(line, "public_key=") && foundPeer {
|
||||||
|
foundPeer = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify the peer with the specific public key
|
||||||
|
if line == fmt.Sprintf("public_key=%s", hexKey) {
|
||||||
|
foundPeer = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're within the details of the found peer and find the specific allowed IP, skip this line
|
||||||
|
if foundPeer && line == "allowed_ip="+ip {
|
||||||
|
removedAllowedIP = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the line to the output string
|
||||||
|
if strings.HasPrefix(line, "private_key=") || strings.HasPrefix(line, "listen_port=") ||
|
||||||
|
strings.HasPrefix(line, "public_key=") || strings.HasPrefix(line, "preshared_key=") ||
|
||||||
|
strings.HasPrefix(line, "endpoint=") || strings.HasPrefix(line, "persistent_keepalive_interval=") ||
|
||||||
|
strings.HasPrefix(line, "allowed_ip=") {
|
||||||
|
output += line + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !removedAllowedIP {
|
||||||
|
return fmt.Errorf("allowedIP not found")
|
||||||
|
} else {
|
||||||
|
return c.tunDevice.Device().IpcSet(output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !android
|
//go:build !android && !ios
|
||||||
|
|
||||||
package iface
|
package iface
|
||||||
|
|
||||||
0
infrastructure_files/artifacts/.gitkeep
Normal file
0
infrastructure_files/artifacts/.gitkeep
Normal file
@@ -20,6 +20,9 @@ NETBIRD_MGMT_IDP_SIGNKEY_REFRESH=${NETBIRD_MGMT_IDP_SIGNKEY_REFRESH:-false}
|
|||||||
NETBIRD_SIGNAL_PROTOCOL="http"
|
NETBIRD_SIGNAL_PROTOCOL="http"
|
||||||
NETBIRD_SIGNAL_PORT=${NETBIRD_SIGNAL_PORT:-10000}
|
NETBIRD_SIGNAL_PORT=${NETBIRD_SIGNAL_PORT:-10000}
|
||||||
|
|
||||||
|
# Turn
|
||||||
|
TURN_DOMAIN=${NETBIRD_TURN_DOMAIN:-$NETBIRD_DOMAIN}
|
||||||
|
|
||||||
# Turn credentials
|
# Turn credentials
|
||||||
# User
|
# User
|
||||||
TURN_USER=self
|
TURN_USER=self
|
||||||
@@ -59,8 +62,16 @@ NETBIRD_DASH_AUTH_AUDIENCE=$NETBIRD_AUTH_AUDIENCE
|
|||||||
# Store config
|
# Store config
|
||||||
NETBIRD_STORE_CONFIG_ENGINE=${NETBIRD_STORE_CONFIG_ENGINE:-"jsonfile"}
|
NETBIRD_STORE_CONFIG_ENGINE=${NETBIRD_STORE_CONFIG_ENGINE:-"jsonfile"}
|
||||||
|
|
||||||
|
# Image tags
|
||||||
|
NETBIRD_DASHBOARD_TAG=${NETBIRD_DASHBOARD_TAG:-"latest"}
|
||||||
|
NETBIRD_SIGNAL_TAG=${NETBIRD_SIGNAL_TAG:-"latest"}
|
||||||
|
NETBIRD_MANAGEMENT_TAG=${NETBIRD_MANAGEMENT_TAG:-"latest"}
|
||||||
|
COTURN_TAG=${COTURN_TAG:-"latest"}
|
||||||
|
|
||||||
|
|
||||||
# exports
|
# exports
|
||||||
export NETBIRD_DOMAIN
|
export NETBIRD_DOMAIN
|
||||||
|
export NETBIRD_TURN_DOMAIN
|
||||||
export NETBIRD_AUTH_CLIENT_ID
|
export NETBIRD_AUTH_CLIENT_ID
|
||||||
export NETBIRD_AUTH_CLIENT_SECRET
|
export NETBIRD_AUTH_CLIENT_SECRET
|
||||||
export NETBIRD_AUTH_AUDIENCE
|
export NETBIRD_AUTH_AUDIENCE
|
||||||
@@ -79,6 +90,7 @@ export NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID
|
|||||||
export NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT
|
export NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT
|
||||||
export NETBIRD_AUTH_REDIRECT_URI
|
export NETBIRD_AUTH_REDIRECT_URI
|
||||||
export NETBIRD_AUTH_SILENT_REDIRECT_URI
|
export NETBIRD_AUTH_SILENT_REDIRECT_URI
|
||||||
|
export TURN_DOMAIN
|
||||||
export TURN_USER
|
export TURN_USER
|
||||||
export TURN_PASSWORD
|
export TURN_PASSWORD
|
||||||
export TURN_MIN_PORT
|
export TURN_MIN_PORT
|
||||||
@@ -104,3 +116,7 @@ export NETBIRD_AUTH_PKCE_AUDIENCE
|
|||||||
export NETBIRD_DASH_AUTH_USE_AUDIENCE
|
export NETBIRD_DASH_AUTH_USE_AUDIENCE
|
||||||
export NETBIRD_DASH_AUTH_AUDIENCE
|
export NETBIRD_DASH_AUTH_AUDIENCE
|
||||||
export NETBIRD_STORE_CONFIG_ENGINE
|
export NETBIRD_STORE_CONFIG_ENGINE
|
||||||
|
export NETBIRD_DASHBOARD_TAG
|
||||||
|
export NETBIRD_SIGNAL_TAG
|
||||||
|
export NETBIRD_MANAGEMENT_TAG
|
||||||
|
export COTURN_TAG
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ if [[ "x-$TURN_PASSWORD" == "x-" ]]; then
|
|||||||
export TURN_PASSWORD=$(openssl rand -base64 32 | sed 's/=//g')
|
export TURN_PASSWORD=$(openssl rand -base64 32 | sed 's/=//g')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
artifacts_path="./artifacts"
|
||||||
|
mkdir -p $artifacts_path
|
||||||
|
|
||||||
MGMT_VOLUMENAME="${VOLUME_PREFIX}${MGMT_VOLUMESUFFIX}"
|
MGMT_VOLUMENAME="${VOLUME_PREFIX}${MGMT_VOLUMESUFFIX}"
|
||||||
SIGNAL_VOLUMENAME="${VOLUME_PREFIX}${SIGNAL_VOLUMESUFFIX}"
|
SIGNAL_VOLUMENAME="${VOLUME_PREFIX}${SIGNAL_VOLUMESUFFIX}"
|
||||||
LETSENCRYPT_VOLUMENAME="${VOLUME_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"
|
LETSENCRYPT_VOLUMENAME="${VOLUME_PREFIX}${LETSENCRYPT_VOLUMESUFFIX}"
|
||||||
@@ -94,13 +97,13 @@ if [[ -z "${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT}" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "loading OpenID configuration from ${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT} to the openid-configuration.json file"
|
echo "loading OpenID configuration from ${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT} to the openid-configuration.json file"
|
||||||
curl "${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT}" -q -o openid-configuration.json
|
curl "${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT}" -q -o ${artifacts_path}/openid-configuration.json
|
||||||
|
|
||||||
export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' openid-configuration.json)
|
export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' ${artifacts_path}/openid-configuration.json)
|
||||||
export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' openid-configuration.json)
|
export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' ${artifacts_path}/openid-configuration.json)
|
||||||
export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' openid-configuration.json)
|
export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' ${artifacts_path}/openid-configuration.json)
|
||||||
export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' openid-configuration.json)
|
export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' ${artifacts_path}/openid-configuration.json)
|
||||||
export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' openid-configuration.json)
|
export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' ${artifacts_path}/openid-configuration.json)
|
||||||
|
|
||||||
if [[ ! -z "${NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID}" ]]; then
|
if [[ ! -z "${NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID}" ]]; then
|
||||||
# user enabled Device Authorization Grant feature
|
# user enabled Device Authorization Grant feature
|
||||||
@@ -185,17 +188,17 @@ fi
|
|||||||
env | grep NETBIRD
|
env | grep NETBIRD
|
||||||
|
|
||||||
bkp_postfix="$(date +%s)"
|
bkp_postfix="$(date +%s)"
|
||||||
if test -f 'docker-compose.yml'; then
|
if test -f "${artifacts_path}/docker-compose.yml"; then
|
||||||
cp docker-compose.yml "docker-compose.yml.bkp.${bkp_postfix}"
|
cp $artifacts_path/docker-compose.yml "${artifacts_path}/docker-compose.yml.bkp.${bkp_postfix}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -f 'management.json'; then
|
if test -f "${artifacts_path}/management.json"; then
|
||||||
cp management.json "management.json.bkp.${bkp_postfix}"
|
cp $artifacts_path/management.json "${artifacts_path}/management.json.bkp.${bkp_postfix}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -f 'turnserver.conf'; then
|
if test -f "${artifacts_path}/turnserver.conf"; then
|
||||||
cp turnserver.conf "turnserver.conf.bpk.${bkp_postfix}"
|
cp ${artifacts_path}/turnserver.conf "${artifacts_path}/turnserver.conf.bkp.${bkp_postfix}"
|
||||||
fi
|
fi
|
||||||
envsubst <docker-compose.yml.tmpl >docker-compose.yml
|
envsubst <docker-compose.yml.tmpl >$artifacts_path/docker-compose.yml
|
||||||
envsubst <management.json.tmpl | jq . >management.json
|
envsubst <management.json.tmpl | jq . >$artifacts_path/management.json
|
||||||
envsubst <turnserver.conf.tmpl >turnserver.conf
|
envsubst <turnserver.conf.tmpl >$artifacts_path/turnserver.conf
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ version: "3"
|
|||||||
services:
|
services:
|
||||||
#UI dashboard
|
#UI dashboard
|
||||||
dashboard:
|
dashboard:
|
||||||
image: wiretrustee/dashboard:latest
|
image: wiretrustee/dashboard:$NETBIRD_DASHBOARD_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
@@ -31,7 +31,7 @@ services:
|
|||||||
|
|
||||||
# Signal
|
# Signal
|
||||||
signal:
|
signal:
|
||||||
image: netbirdio/signal:latest
|
image: netbirdio/signal:$NETBIRD_SIGNAL_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
||||||
@@ -43,7 +43,7 @@ services:
|
|||||||
|
|
||||||
# Management
|
# Management
|
||||||
management:
|
management:
|
||||||
image: netbirdio/management:latest
|
image: netbirdio/management:$NETBIRD_MANAGEMENT_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- dashboard
|
- dashboard
|
||||||
@@ -65,9 +65,9 @@ services:
|
|||||||
|
|
||||||
# Coturn
|
# Coturn
|
||||||
coturn:
|
coturn:
|
||||||
image: coturn/coturn
|
image: coturn/coturn:$COTURN_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
domainname: $NETBIRD_DOMAIN
|
domainname: $TURN_DOMAIN
|
||||||
volumes:
|
volumes:
|
||||||
- ./turnserver.conf:/etc/turnserver.conf:ro
|
- ./turnserver.conf:/etc/turnserver.conf:ro
|
||||||
# - ./privkey.pem:/etc/coturn/private/privkey.pem:ro
|
# - ./privkey.pem:/etc/coturn/private/privkey.pem:ro
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ version: "3"
|
|||||||
services:
|
services:
|
||||||
#UI dashboard
|
#UI dashboard
|
||||||
dashboard:
|
dashboard:
|
||||||
image: wiretrustee/dashboard:latest
|
image: wiretrustee/dashboard:$NETBIRD_DASHBOARD_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
#ports:
|
#ports:
|
||||||
# - 80:80
|
# - 80:80
|
||||||
@@ -35,7 +35,7 @@ services:
|
|||||||
|
|
||||||
# Signal
|
# Signal
|
||||||
signal:
|
signal:
|
||||||
image: netbirdio/signal:latest
|
image: netbirdio/signal:$NETBIRD_SIGNAL_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
||||||
@@ -52,7 +52,7 @@ services:
|
|||||||
|
|
||||||
# Management
|
# Management
|
||||||
management:
|
management:
|
||||||
image: netbirdio/management:latest
|
image: netbirdio/management:$NETBIRD_MANAGEMENT_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- dashboard
|
- dashboard
|
||||||
@@ -84,9 +84,9 @@ services:
|
|||||||
|
|
||||||
# Coturn
|
# Coturn
|
||||||
coturn:
|
coturn:
|
||||||
image: coturn/coturn
|
image: coturn/coturn:$COTURN_TAG
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
domainname: $NETBIRD_DOMAIN
|
domainname: $TURN_DOMAIN
|
||||||
volumes:
|
volumes:
|
||||||
- ./turnserver.conf:/etc/turnserver.conf:ro
|
- ./turnserver.conf:/etc/turnserver.conf:ro
|
||||||
# - ./privkey.pem:/etc/coturn/private/privkey.pem:ro
|
# - ./privkey.pem:/etc/coturn/private/privkey.pem:ro
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"Stuns": [
|
"Stuns": [
|
||||||
{
|
{
|
||||||
"Proto": "udp",
|
"Proto": "udp",
|
||||||
"URI": "stun:$NETBIRD_DOMAIN:3478",
|
"URI": "stun:$TURN_DOMAIN:3478",
|
||||||
"Username": "",
|
"Username": "",
|
||||||
"Password": null
|
"Password": null
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"Turns": [
|
"Turns": [
|
||||||
{
|
{
|
||||||
"Proto": "udp",
|
"Proto": "udp",
|
||||||
"URI": "turn:$NETBIRD_DOMAIN:3478",
|
"URI": "turn:$TURN_DOMAIN:3478",
|
||||||
"Username": "$TURN_USER",
|
"Username": "$TURN_USER",
|
||||||
"Password": "$TURN_PASSWORD"
|
"Password": "$TURN_PASSWORD"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,20 @@
|
|||||||
## example file, you can copy this file to setup.env and update its values
|
## example file, you can copy this file to setup.env and update its values
|
||||||
##
|
##
|
||||||
|
|
||||||
|
# Image tags
|
||||||
|
# you can force specific tags for each component; will be set to latest if empty
|
||||||
|
NETBIRD_DASHBOARD_TAG=""
|
||||||
|
NETBIRD_SIGNAL_TAG=""
|
||||||
|
NETBIRD_MANAGEMENT_TAG=""
|
||||||
|
COTURN_TAG=""
|
||||||
|
|
||||||
# Dashboard domain. e.g. app.mydomain.com
|
# Dashboard domain. e.g. app.mydomain.com
|
||||||
NETBIRD_DOMAIN=""
|
NETBIRD_DOMAIN=""
|
||||||
|
|
||||||
|
# TURN server domain. e.g. turn.mydomain.com
|
||||||
|
# if not specified it will assume NETBIRD_DOMAIN
|
||||||
|
NETBIRD_TURN_DOMAIN=""
|
||||||
|
|
||||||
# -------------------------------------------
|
# -------------------------------------------
|
||||||
# OIDC
|
# OIDC
|
||||||
# e.g., https://example.eu.auth0.com/.well-known/openid-configuration
|
# e.g., https://example.eu.auth0.com/.well-known/openid-configuration
|
||||||
|
|||||||
@@ -17,11 +17,12 @@ import (
|
|||||||
|
|
||||||
"github.com/eko/gocache/v3/cache"
|
"github.com/eko/gocache/v3/cache"
|
||||||
cacheStore "github.com/eko/gocache/v3/store"
|
cacheStore "github.com/eko/gocache/v3/store"
|
||||||
"github.com/netbirdio/management-integrations/additions"
|
|
||||||
gocache "github.com/patrickmn/go-cache"
|
gocache "github.com/patrickmn/go-cache"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/netbirdio/management-integrations/additions"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/base62"
|
"github.com/netbirdio/netbird/base62"
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/server/account"
|
"github.com/netbirdio/netbird/management/server/account"
|
||||||
@@ -66,6 +67,7 @@ type AccountManager interface {
|
|||||||
GetSetupKey(accountID, userID, keyID string) (*SetupKey, error)
|
GetSetupKey(accountID, userID, keyID string) (*SetupKey, error)
|
||||||
GetAccountByUserOrAccountID(userID, accountID, domain string) (*Account, error)
|
GetAccountByUserOrAccountID(userID, accountID, domain string) (*Account, error)
|
||||||
GetAccountFromToken(claims jwtclaims.AuthorizationClaims) (*Account, *User, error)
|
GetAccountFromToken(claims jwtclaims.AuthorizationClaims) (*Account, *User, error)
|
||||||
|
CheckUserAccessByJWTGroups(claims jwtclaims.AuthorizationClaims) error
|
||||||
GetAccountFromPAT(pat string) (*Account, *User, *PersonalAccessToken, error)
|
GetAccountFromPAT(pat string) (*Account, *User, *PersonalAccessToken, error)
|
||||||
DeleteAccount(accountID, userID string) error
|
DeleteAccount(accountID, userID string) error
|
||||||
MarkPATUsed(tokenID string) error
|
MarkPATUsed(tokenID string) error
|
||||||
@@ -1697,6 +1699,39 @@ func (am *DefaultAccountManager) GetDNSDomain() string {
|
|||||||
return am.dnsDomain
|
return am.dnsDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUserAccessByJWTGroups checks if the user has access, particularly in cases where the admin enabled JWT
|
||||||
|
// group propagation and set the list of groups with access permissions.
|
||||||
|
func (am *DefaultAccountManager) CheckUserAccessByJWTGroups(claims jwtclaims.AuthorizationClaims) error {
|
||||||
|
account, _, err := am.GetAccountFromToken(claims)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures JWT group synchronization to the management is enabled before,
|
||||||
|
// filtering access based on the allowed groups.
|
||||||
|
if account.Settings != nil && account.Settings.JWTGroupsEnabled {
|
||||||
|
if allowedGroups := account.Settings.JWTAllowGroups; len(allowedGroups) > 0 {
|
||||||
|
userJWTGroups := make([]string, 0)
|
||||||
|
|
||||||
|
if claim, ok := claims.Raw[account.Settings.JWTGroupsClaimName]; ok {
|
||||||
|
if claimGroups, ok := claim.([]interface{}); ok {
|
||||||
|
for _, g := range claimGroups {
|
||||||
|
if group, ok := g.(string); ok {
|
||||||
|
userJWTGroups = append(userJWTGroups, group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !userHasAllowedGroup(allowedGroups, userJWTGroups) {
|
||||||
|
return fmt.Errorf("user does not belong to any of the allowed JWT groups")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// addAllGroup to account object if it doesn't exists
|
// addAllGroup to account object if it doesn't exists
|
||||||
func addAllGroup(account *Account) error {
|
func addAllGroup(account *Account) error {
|
||||||
if len(account.Groups) == 0 {
|
if len(account.Groups) == 0 {
|
||||||
@@ -1768,3 +1803,15 @@ func newAccountWithId(accountID, userID, domain string) *Account {
|
|||||||
}
|
}
|
||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// userHasAllowedGroup checks if a user belongs to any of the allowed groups.
|
||||||
|
func userHasAllowedGroup(allowedGroups []string, userGroups []string) bool {
|
||||||
|
for _, userGroup := range userGroups {
|
||||||
|
for _, allowedGroup := range allowedGroups {
|
||||||
|
if userGroup == allowedGroup {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -220,6 +220,10 @@ func (s *GRPCServer) validateToken(jwtToken string) (string, error) {
|
|||||||
return "", status.Errorf(codes.Internal, "unable to fetch account with claims, err: %v", err)
|
return "", status.Errorf(codes.Internal, "unable to fetch account with claims, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := s.accountManager.CheckUserAccessByJWTGroups(claims); err != nil {
|
||||||
|
return "", status.Errorf(codes.PermissionDenied, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return claims.UserId, nil
|
return claims.UserId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +316,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p
|
|||||||
userID, err = s.validateToken(loginReq.GetJwtToken())
|
userID, err = s.validateToken(loginReq.GetJwtToken())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed validating JWT token sent from peer %s", peerKey)
|
log.Warnf("failed validating JWT token sent from peer %s", peerKey)
|
||||||
return nil, mapError(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sshKey []byte
|
var sshKey []byte
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func APIHandler(accountManager s.AccountManager, jwtValidator jwtclaims.JWTValid
|
|||||||
accountManager.GetAccountFromPAT,
|
accountManager.GetAccountFromPAT,
|
||||||
jwtValidator.ValidateAndParse,
|
jwtValidator.ValidateAndParse,
|
||||||
accountManager.MarkPATUsed,
|
accountManager.MarkPATUsed,
|
||||||
accountManager.GetAccountFromToken,
|
accountManager.CheckUserAccessByJWTGroups,
|
||||||
claimsExtractor,
|
claimsExtractor,
|
||||||
authCfg.Audience,
|
authCfg.Audience,
|
||||||
authCfg.UserIDClaim,
|
authCfg.UserIDClaim,
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ type ValidateAndParseTokenFunc func(token string) (*jwt.Token, error)
|
|||||||
// MarkPATUsedFunc function
|
// MarkPATUsedFunc function
|
||||||
type MarkPATUsedFunc func(token string) error
|
type MarkPATUsedFunc func(token string) error
|
||||||
|
|
||||||
// GetAccountFromTokenFunc function
|
// CheckUserAccessByJWTGroupsFunc function
|
||||||
type GetAccountFromTokenFunc func(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error)
|
type CheckUserAccessByJWTGroupsFunc func(claims jwtclaims.AuthorizationClaims) error
|
||||||
|
|
||||||
// AuthMiddleware middleware to verify personal access tokens (PAT) and JWT tokens
|
// AuthMiddleware middleware to verify personal access tokens (PAT) and JWT tokens
|
||||||
type AuthMiddleware struct {
|
type AuthMiddleware struct {
|
||||||
getAccountFromPAT GetAccountFromPATFunc
|
getAccountFromPAT GetAccountFromPATFunc
|
||||||
validateAndParseToken ValidateAndParseTokenFunc
|
validateAndParseToken ValidateAndParseTokenFunc
|
||||||
markPATUsed MarkPATUsedFunc
|
markPATUsed MarkPATUsedFunc
|
||||||
getAccountFromToken GetAccountFromTokenFunc
|
checkUserAccessByJWTGroups CheckUserAccessByJWTGroupsFunc
|
||||||
claimsExtractor *jwtclaims.ClaimsExtractor
|
claimsExtractor *jwtclaims.ClaimsExtractor
|
||||||
audience string
|
audience string
|
||||||
userIDClaim string
|
userIDClaim string
|
||||||
@@ -46,7 +46,7 @@ const (
|
|||||||
|
|
||||||
// NewAuthMiddleware instance constructor
|
// NewAuthMiddleware instance constructor
|
||||||
func NewAuthMiddleware(getAccountFromPAT GetAccountFromPATFunc, validateAndParseToken ValidateAndParseTokenFunc,
|
func NewAuthMiddleware(getAccountFromPAT GetAccountFromPATFunc, validateAndParseToken ValidateAndParseTokenFunc,
|
||||||
markPATUsed MarkPATUsedFunc, getAccountFromToken GetAccountFromTokenFunc, claimsExtractor *jwtclaims.ClaimsExtractor,
|
markPATUsed MarkPATUsedFunc, checkUserAccessByJWTGroups CheckUserAccessByJWTGroupsFunc, claimsExtractor *jwtclaims.ClaimsExtractor,
|
||||||
audience string, userIdClaim string) *AuthMiddleware {
|
audience string, userIdClaim string) *AuthMiddleware {
|
||||||
if userIdClaim == "" {
|
if userIdClaim == "" {
|
||||||
userIdClaim = jwtclaims.UserIDClaim
|
userIdClaim = jwtclaims.UserIDClaim
|
||||||
@@ -56,7 +56,7 @@ func NewAuthMiddleware(getAccountFromPAT GetAccountFromPATFunc, validateAndParse
|
|||||||
getAccountFromPAT: getAccountFromPAT,
|
getAccountFromPAT: getAccountFromPAT,
|
||||||
validateAndParseToken: validateAndParseToken,
|
validateAndParseToken: validateAndParseToken,
|
||||||
markPATUsed: markPATUsed,
|
markPATUsed: markPATUsed,
|
||||||
getAccountFromToken: getAccountFromToken,
|
checkUserAccessByJWTGroups: checkUserAccessByJWTGroups,
|
||||||
claimsExtractor: claimsExtractor,
|
claimsExtractor: claimsExtractor,
|
||||||
audience: audience,
|
audience: audience,
|
||||||
userIDClaim: userIdClaim,
|
userIDClaim: userIdClaim,
|
||||||
@@ -134,34 +134,7 @@ func (m *AuthMiddleware) checkJWTFromRequest(w http.ResponseWriter, r *http.Requ
|
|||||||
// group propagation and designated certain groups with access permissions.
|
// group propagation and designated certain groups with access permissions.
|
||||||
func (m *AuthMiddleware) verifyUserAccess(validatedToken *jwt.Token) error {
|
func (m *AuthMiddleware) verifyUserAccess(validatedToken *jwt.Token) error {
|
||||||
authClaims := m.claimsExtractor.FromToken(validatedToken)
|
authClaims := m.claimsExtractor.FromToken(validatedToken)
|
||||||
account, _, err := m.getAccountFromToken(authClaims)
|
return m.checkUserAccessByJWTGroups(authClaims)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get the account from token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures JWT group synchronization to the management is enabled before,
|
|
||||||
// filtering access based on the allowed groups.
|
|
||||||
if account.Settings != nil && account.Settings.JWTGroupsEnabled {
|
|
||||||
if allowedGroups := account.Settings.JWTAllowGroups; len(allowedGroups) > 0 {
|
|
||||||
userJWTGroups := make([]string, 0)
|
|
||||||
|
|
||||||
if claim, ok := authClaims.Raw[account.Settings.JWTGroupsClaimName]; ok {
|
|
||||||
if claimGroups, ok := claim.([]interface{}); ok {
|
|
||||||
for _, g := range claimGroups {
|
|
||||||
if group, ok := g.(string); ok {
|
|
||||||
userJWTGroups = append(userJWTGroups, group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !userHasAllowedGroup(allowedGroups, userJWTGroups) {
|
|
||||||
return fmt.Errorf("user does not belong to any of the allowed JWT groups")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckPATFromRequest checks if the PAT is valid
|
// CheckPATFromRequest checks if the PAT is valid
|
||||||
@@ -217,15 +190,3 @@ func getTokenFromPATRequest(authHeaderParts []string) (string, error) {
|
|||||||
|
|
||||||
return authHeaderParts[1], nil
|
return authHeaderParts[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// userHasAllowedGroup checks if a user belongs to any of the allowed groups.
|
|
||||||
func userHasAllowedGroup(allowedGroups []string, userGroups []string) bool {
|
|
||||||
for _, userGroup := range userGroups {
|
|
||||||
for _, allowedGroup := range allowedGroups {
|
|
||||||
if userGroup == allowedGroup {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -73,17 +73,16 @@ func mockMarkPATUsed(token string) error {
|
|||||||
return fmt.Errorf("Should never get reached")
|
return fmt.Errorf("Should never get reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockGetAccountFromToken(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error) {
|
func mockCheckUserAccessByJWTGroups(claims jwtclaims.AuthorizationClaims) error {
|
||||||
if testAccount.Id != claims.AccountId {
|
if testAccount.Id != claims.AccountId {
|
||||||
return nil, nil, fmt.Errorf("account with id %s does not exist", claims.AccountId)
|
return fmt.Errorf("account with id %s does not exist", claims.AccountId)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, ok := testAccount.Users[claims.UserId]
|
if _, ok := testAccount.Users[claims.UserId]; !ok {
|
||||||
if !ok {
|
return fmt.Errorf("user with id %s does not exist", claims.UserId)
|
||||||
return nil, nil, fmt.Errorf("user with id %s does not exist", claims.UserId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return testAccount, user, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthMiddleware_Handler(t *testing.T) {
|
func TestAuthMiddleware_Handler(t *testing.T) {
|
||||||
@@ -137,7 +136,7 @@ func TestAuthMiddleware_Handler(t *testing.T) {
|
|||||||
mockGetAccountFromPAT,
|
mockGetAccountFromPAT,
|
||||||
mockValidateAndParseToken,
|
mockValidateAndParseToken,
|
||||||
mockMarkPATUsed,
|
mockMarkPATUsed,
|
||||||
mockGetAccountFromToken,
|
mockCheckUserAccessByJWTGroups,
|
||||||
claimsExtractor,
|
claimsExtractor,
|
||||||
audience,
|
audience,
|
||||||
userIDClaim,
|
userIDClaim,
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ type MockAccountManager struct {
|
|||||||
ListNameServerGroupsFunc func(accountID string) ([]*nbdns.NameServerGroup, error)
|
ListNameServerGroupsFunc func(accountID string) ([]*nbdns.NameServerGroup, error)
|
||||||
CreateUserFunc func(accountID, userID string, key *server.UserInfo) (*server.UserInfo, error)
|
CreateUserFunc func(accountID, userID string, key *server.UserInfo) (*server.UserInfo, error)
|
||||||
GetAccountFromTokenFunc func(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error)
|
GetAccountFromTokenFunc func(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error)
|
||||||
|
CheckUserAccessByJWTGroupsFunc func(claims jwtclaims.AuthorizationClaims) error
|
||||||
DeleteAccountFunc func(accountID, userID string) error
|
DeleteAccountFunc func(accountID, userID string) error
|
||||||
GetDNSDomainFunc func() string
|
GetDNSDomainFunc func() string
|
||||||
StoreEventFunc func(initiatorID, targetID, accountID string, activityID activity.Activity, meta map[string]any)
|
StoreEventFunc func(initiatorID, targetID, accountID string, activityID activity.Activity, meta map[string]any)
|
||||||
@@ -543,6 +544,13 @@ func (am *MockAccountManager) GetAccountFromToken(claims jwtclaims.Authorization
|
|||||||
return nil, nil, status.Errorf(codes.Unimplemented, "method GetAccountFromToken is not implemented")
|
return nil, nil, status.Errorf(codes.Unimplemented, "method GetAccountFromToken is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (am *MockAccountManager) CheckUserAccessByJWTGroups(claims jwtclaims.AuthorizationClaims) error {
|
||||||
|
if am.CheckUserAccessByJWTGroupsFunc != nil {
|
||||||
|
return am.CheckUserAccessByJWTGroupsFunc(claims)
|
||||||
|
}
|
||||||
|
return status.Errorf(codes.Unimplemented, "method CheckUserAccessByJWTGroups is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
// GetPeers mocks GetPeers of the AccountManager interface
|
// GetPeers mocks GetPeers of the AccountManager interface
|
||||||
func (am *MockAccountManager) GetPeers(accountID, userID string) ([]*nbpeer.Peer, error) {
|
func (am *MockAccountManager) GetPeers(accountID, userID string) ([]*nbpeer.Peer, error) {
|
||||||
if am.GetPeersFunc != nil {
|
if am.GetPeersFunc != nil {
|
||||||
|
|||||||
@@ -493,7 +493,11 @@ func getAllPeersFromGroups(account *Account, groups []string, peerID string) ([]
|
|||||||
|
|
||||||
for _, p := range group.Peers {
|
for _, p := range group.Peers {
|
||||||
peer, ok := account.Peers[p]
|
peer, ok := account.Peers[p]
|
||||||
if ok && peer != nil && peer.ID == peerID {
|
if !ok || peer == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if peer.ID == peerID {
|
||||||
peerInGroups = true
|
peerInGroups = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/stun"
|
"github.com/pion/stun/v2"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|||||||
Reference in New Issue
Block a user