mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-27 12:46:39 +00:00
Compare commits
15 Commits
v0.48.0-de
...
set-comman
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
355bab9bb4 | ||
|
|
6922826919 | ||
|
|
56a1a75e3f | ||
|
|
d9402168ad | ||
|
|
dbdef04b9e | ||
|
|
29cbfe8467 | ||
|
|
6ce8643368 | ||
|
|
07d1ad35fc | ||
|
|
ef6cd36f1a | ||
|
|
c1c71b6d39 | ||
|
|
0480507a10 | ||
|
|
34ac4e4b5a | ||
|
|
52ff9d9602 | ||
|
|
1b73fae46e | ||
|
|
d897365abc |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
SIGN_PIPE_VER: "v0.0.18"
|
||||
SIGN_PIPE_VER: "v0.0.20"
|
||||
GORELEASER_VER: "v2.3.2"
|
||||
PRODUCT_NAME: "NetBird"
|
||||
COPYRIGHT: "NetBird GmbH"
|
||||
|
||||
@@ -134,6 +134,7 @@ jobs:
|
||||
NETBIRD_STORE_ENGINE_MYSQL_DSN: '${{ env.NETBIRD_STORE_ENGINE_MYSQL_DSN }}$'
|
||||
CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH: false
|
||||
CI_NETBIRD_TURN_EXTERNAL_IP: "1.2.3.4"
|
||||
CI_NETBIRD_MGMT_DISABLE_DEFAULT_POLICY: false
|
||||
|
||||
run: |
|
||||
set -x
|
||||
@@ -180,6 +181,7 @@ jobs:
|
||||
grep -A 7 Relay management.json | egrep '"Secret": ".+"'
|
||||
grep DisablePromptLogin management.json | grep 'true'
|
||||
grep LoginFlag management.json | grep 0
|
||||
grep DisableDefaultPolicy management.json | grep "$CI_NETBIRD_MGMT_DISABLE_DEFAULT_POLICY"
|
||||
|
||||
- name: Install modules
|
||||
run: go mod tidy
|
||||
|
||||
34
README.md
34
README.md
@@ -134,3 +134,37 @@ We use open-source technologies like [WireGuard®](https://www.wireguard.com/),
|
||||
### Legal
|
||||
_WireGuard_ and the _WireGuard_ logo are [registered trademarks](https://www.wireguard.com/trademark-policy/) of Jason A. Donenfeld.
|
||||
|
||||
## Configuration Management
|
||||
|
||||
Netbird now supports direct configuration management via CLI commands:
|
||||
|
||||
- You can use `netbird set` as a regular user if the daemon is running; it will securely update the config via the daemon.
|
||||
- If the daemon is not running, you need write access to the config file (typically requires root).
|
||||
|
||||
### Set a configuration value
|
||||
|
||||
```
|
||||
netbird set <setting> <value>
|
||||
# or using environment variables
|
||||
NB_INTERFACE_NAME=utun5 netbird set interface-name
|
||||
```
|
||||
|
||||
### Get a configuration value
|
||||
|
||||
```
|
||||
netbird get <setting>
|
||||
# or using environment variables
|
||||
NB_INTERFACE_NAME=utun5 netbird get interface-name
|
||||
```
|
||||
|
||||
### Show all configuration values
|
||||
|
||||
```
|
||||
netbird show
|
||||
```
|
||||
|
||||
- All settings support environment variable overrides: `NB_<SETTING>` or `WT_<SETTING>` (e.g. `NB_ENABLE_ROSENPASS=true`).
|
||||
- Supported settings: management-url, admin-url, interface-name, external-ip-map, extra-iface-blacklist, dns-resolver-address, extra-dns-labels, preshared-key, enable-rosenpass, rosenpass-permissive, allow-server-ssh, network-monitor, disable-auto-connect, disable-client-routes, disable-server-routes, disable-dns, disable-firewall, block-lan-access, block-inbound, enable-lazy-connection, wireguard-port, dns-router-interval.
|
||||
|
||||
See `netbird set --help`, `netbird get --help`, and `netbird show --help` for more details.
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/client/proto"
|
||||
"github.com/netbirdio/netbird/upload-server/types"
|
||||
)
|
||||
|
||||
@@ -87,6 +88,30 @@ var (
|
||||
Long: "",
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
getCmd = &cobra.Command{
|
||||
Use: "get <setting>",
|
||||
Short: "Get a configuration value from the config file",
|
||||
Long: `Get a configuration value from the Netbird config file. You can also use NB_<SETTING> or WT_<SETTING> environment variables to override the value (same as 'set').`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: getFunc,
|
||||
}
|
||||
|
||||
showCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show all configuration values",
|
||||
Long: `Show all configuration values from the Netbird config file, with environment variable overrides if present.`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: showFunc,
|
||||
}
|
||||
|
||||
reloadCmd = &cobra.Command{
|
||||
Use: "reload",
|
||||
Short: "Reload the configuration in the daemon (daemon mode)",
|
||||
Long: `Reload the configuration from disk in the running daemon. Use after 'set' to apply changes without restarting the service.`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: reloadFunc,
|
||||
}
|
||||
)
|
||||
|
||||
// Execute executes the root command.
|
||||
@@ -152,6 +177,9 @@ func init() {
|
||||
rootCmd.AddCommand(networksCMD)
|
||||
rootCmd.AddCommand(forwardingRulesCmd)
|
||||
rootCmd.AddCommand(debugCmd)
|
||||
rootCmd.AddCommand(getCmd)
|
||||
rootCmd.AddCommand(showCmd)
|
||||
rootCmd.AddCommand(reloadCmd)
|
||||
|
||||
serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd) // service control commands are subcommands of service
|
||||
serviceCmd.AddCommand(installCmd, uninstallCmd) // service installer commands are subcommands of service
|
||||
@@ -408,3 +436,167 @@ func getClient(cmd *cobra.Command) (*grpc.ClientConn, error) {
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func getFunc(cmd *cobra.Command, args []string) error {
|
||||
setting := args[0]
|
||||
upper := strings.ToUpper(strings.ReplaceAll(setting, "-", "_"))
|
||||
if v, ok := os.LookupEnv("NB_" + upper); ok {
|
||||
cmd.Println(v)
|
||||
return nil
|
||||
} else if v, ok := os.LookupEnv("WT_" + upper); ok {
|
||||
cmd.Println(v)
|
||||
return nil
|
||||
}
|
||||
config, err := internal.ReadConfig(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read config: %v", err)
|
||||
}
|
||||
switch setting {
|
||||
case "management-url":
|
||||
cmd.Println(config.ManagementURL.String())
|
||||
case "admin-url":
|
||||
cmd.Println(config.AdminURL.String())
|
||||
case "interface-name":
|
||||
cmd.Println(config.WgIface)
|
||||
case "external-ip-map":
|
||||
cmd.Println(strings.Join(config.NATExternalIPs, ","))
|
||||
case "extra-iface-blacklist":
|
||||
cmd.Println(strings.Join(config.IFaceBlackList, ","))
|
||||
case "dns-resolver-address":
|
||||
cmd.Println(config.CustomDNSAddress)
|
||||
case "extra-dns-labels":
|
||||
cmd.Println(config.DNSLabels.SafeString())
|
||||
case "preshared-key":
|
||||
cmd.Println(config.PreSharedKey)
|
||||
case "enable-rosenpass":
|
||||
cmd.Println(config.RosenpassEnabled)
|
||||
case "rosenpass-permissive":
|
||||
cmd.Println(config.RosenpassPermissive)
|
||||
case "allow-server-ssh":
|
||||
if config.ServerSSHAllowed != nil {
|
||||
cmd.Println(*config.ServerSSHAllowed)
|
||||
} else {
|
||||
cmd.Println(false)
|
||||
}
|
||||
case "network-monitor":
|
||||
if config.NetworkMonitor != nil {
|
||||
cmd.Println(*config.NetworkMonitor)
|
||||
} else {
|
||||
cmd.Println(false)
|
||||
}
|
||||
case "disable-auto-connect":
|
||||
cmd.Println(config.DisableAutoConnect)
|
||||
case "disable-client-routes":
|
||||
cmd.Println(config.DisableClientRoutes)
|
||||
case "disable-server-routes":
|
||||
cmd.Println(config.DisableServerRoutes)
|
||||
case "disable-dns":
|
||||
cmd.Println(config.DisableDNS)
|
||||
case "disable-firewall":
|
||||
cmd.Println(config.DisableFirewall)
|
||||
case "block-lan-access":
|
||||
cmd.Println(config.BlockLANAccess)
|
||||
case "block-inbound":
|
||||
cmd.Println(config.BlockInbound)
|
||||
case "enable-lazy-connection":
|
||||
cmd.Println(config.LazyConnectionEnabled)
|
||||
case "wireguard-port":
|
||||
cmd.Println(config.WgPort)
|
||||
case "dns-router-interval":
|
||||
cmd.Println(config.DNSRouteInterval)
|
||||
default:
|
||||
return fmt.Errorf("unknown setting: %s", setting)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func showFunc(cmd *cobra.Command, args []string) error {
|
||||
config, err := internal.ReadConfig(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read config: %v", err)
|
||||
}
|
||||
settings := []string{
|
||||
"management-url", "admin-url", "interface-name", "external-ip-map", "extra-iface-blacklist", "dns-resolver-address", "extra-dns-labels", "preshared-key", "enable-rosenpass", "rosenpass-permissive", "allow-server-ssh", "network-monitor", "disable-auto-connect", "disable-client-routes", "disable-server-routes", "disable-dns", "disable-firewall", "block-lan-access", "block-inbound", "enable-lazy-connection", "wireguard-port", "dns-router-interval",
|
||||
}
|
||||
for _, setting := range settings {
|
||||
upper := strings.ToUpper(strings.ReplaceAll(setting, "-", "_"))
|
||||
var val string
|
||||
if v, ok := os.LookupEnv("NB_" + upper); ok {
|
||||
val = v + " (from NB_ env)"
|
||||
} else if v, ok := os.LookupEnv("WT_" + upper); ok {
|
||||
val = v + " (from WT_ env)"
|
||||
} else {
|
||||
switch setting {
|
||||
case "management-url":
|
||||
val = config.ManagementURL.String()
|
||||
case "admin-url":
|
||||
val = config.AdminURL.String()
|
||||
case "interface-name":
|
||||
val = config.WgIface
|
||||
case "external-ip-map":
|
||||
val = strings.Join(config.NATExternalIPs, ",")
|
||||
case "extra-iface-blacklist":
|
||||
val = strings.Join(config.IFaceBlackList, ",")
|
||||
case "dns-resolver-address":
|
||||
val = config.CustomDNSAddress
|
||||
case "extra-dns-labels":
|
||||
val = config.DNSLabels.SafeString()
|
||||
case "preshared-key":
|
||||
val = config.PreSharedKey
|
||||
case "enable-rosenpass":
|
||||
val = fmt.Sprintf("%v", config.RosenpassEnabled)
|
||||
case "rosenpass-permissive":
|
||||
val = fmt.Sprintf("%v", config.RosenpassPermissive)
|
||||
case "allow-server-ssh":
|
||||
if config.ServerSSHAllowed != nil {
|
||||
val = fmt.Sprintf("%v", *config.ServerSSHAllowed)
|
||||
} else {
|
||||
val = "false"
|
||||
}
|
||||
case "network-monitor":
|
||||
if config.NetworkMonitor != nil {
|
||||
val = fmt.Sprintf("%v", *config.NetworkMonitor)
|
||||
} else {
|
||||
val = "false"
|
||||
}
|
||||
case "disable-auto-connect":
|
||||
val = fmt.Sprintf("%v", config.DisableAutoConnect)
|
||||
case "disable-client-routes":
|
||||
val = fmt.Sprintf("%v", config.DisableClientRoutes)
|
||||
case "disable-server-routes":
|
||||
val = fmt.Sprintf("%v", config.DisableServerRoutes)
|
||||
case "disable-dns":
|
||||
val = fmt.Sprintf("%v", config.DisableDNS)
|
||||
case "disable-firewall":
|
||||
val = fmt.Sprintf("%v", config.DisableFirewall)
|
||||
case "block-lan-access":
|
||||
val = fmt.Sprintf("%v", config.BlockLANAccess)
|
||||
case "block-inbound":
|
||||
val = fmt.Sprintf("%v", config.BlockInbound)
|
||||
case "enable-lazy-connection":
|
||||
val = fmt.Sprintf("%v", config.LazyConnectionEnabled)
|
||||
case "wireguard-port":
|
||||
val = fmt.Sprintf("%d", config.WgPort)
|
||||
case "dns-router-interval":
|
||||
val = config.DNSRouteInterval.String()
|
||||
}
|
||||
}
|
||||
cmd.Printf("%-22s: %s\n", setting, val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func reloadFunc(cmd *cobra.Command, args []string) error {
|
||||
conn, err := getClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
client := proto.NewDaemonServiceClient(conn)
|
||||
_, err = client.ReloadConfig(cmd.Context(), &proto.ReloadConfigRequest{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to reload config in daemon: %v", err)
|
||||
}
|
||||
cmd.Println("Configuration reloaded in daemon.")
|
||||
return nil
|
||||
}
|
||||
|
||||
475
client/cmd/set.go
Normal file
475
client/cmd/set.go
Normal file
@@ -0,0 +1,475 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
osuser "os/user"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/client/proto"
|
||||
"github.com/netbirdio/netbird/management/domain"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var setCmd = &cobra.Command{
|
||||
Use: "set <setting> <value>",
|
||||
Short: "Set a configuration value without running up",
|
||||
Long: `Set a configuration value in the Netbird config file without running 'up'.
|
||||
|
||||
You can also set values via environment variables NB_<SETTING> or WT_<SETTING> (e.g. NB_INTERFACE_NAME=utun5 netbird set interface-name).
|
||||
|
||||
Supported settings:
|
||||
management-url (string) e.g. https://api.netbird.io:443
|
||||
admin-url (string) e.g. https://app.netbird.io:443
|
||||
interface-name (string) e.g. utun5
|
||||
external-ip-map (list) comma-separated, e.g. 12.34.56.78,12.34.56.79/eth0
|
||||
extra-iface-blacklist (list) comma-separated, e.g. eth1,eth2
|
||||
dns-resolver-address (string) e.g. 127.0.0.1:5053
|
||||
extra-dns-labels (list) comma-separated, e.g. vpc1,mgmt1
|
||||
preshared-key (string)
|
||||
enable-rosenpass (bool) true/false
|
||||
rosenpass-permissive (bool) true/false
|
||||
allow-server-ssh (bool) true/false
|
||||
network-monitor (bool) true/false
|
||||
disable-auto-connect (bool) true/false
|
||||
disable-client-routes (bool) true/false
|
||||
disable-server-routes (bool) true/false
|
||||
disable-dns (bool) true/false
|
||||
disable-firewall (bool) true/false
|
||||
block-lan-access (bool) true/false
|
||||
block-inbound (bool) true/false
|
||||
enable-lazy-connection (bool) true/false
|
||||
wireguard-port (int) e.g. 51820
|
||||
dns-router-interval (duration) e.g. 1m, 30s
|
||||
|
||||
Examples:
|
||||
NB_INTERFACE_NAME=utun5 netbird set interface-name
|
||||
netbird set wireguard-port 51820
|
||||
netbird set external-ip-map 12.34.56.78,12.34.56.79/eth0
|
||||
netbird set enable-rosenpass true
|
||||
netbird set dns-router-interval 2m
|
||||
netbird set extra-dns-labels vpc1,mgmt1
|
||||
netbird set disable-firewall true
|
||||
`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: setFunc,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(setCmd)
|
||||
}
|
||||
|
||||
func setFunc(cmd *cobra.Command, args []string) error {
|
||||
setting := args[0]
|
||||
var value string
|
||||
|
||||
// Check environment variables first
|
||||
upper := strings.ToUpper(strings.ReplaceAll(setting, "-", "_"))
|
||||
if v, ok := os.LookupEnv("NB_" + upper); ok {
|
||||
value = v
|
||||
} else if v, ok := os.LookupEnv("WT_" + upper); ok {
|
||||
value = v
|
||||
} else {
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("missing value for setting %s", setting)
|
||||
}
|
||||
value = args[1]
|
||||
}
|
||||
|
||||
// If not root, try to use the daemon (only if cmd is not nil)
|
||||
if cmd != nil {
|
||||
if u, err := osuser.Current(); err == nil && u.Uid != "0" {
|
||||
conn, err := getClient(cmd)
|
||||
if err == nil {
|
||||
defer conn.Close()
|
||||
client := proto.NewDaemonServiceClient(conn)
|
||||
_, err = client.SetConfigValue(cmd.Context(), &proto.SetConfigValueRequest{Setting: setting, Value: value})
|
||||
if err == nil {
|
||||
if cmd != nil {
|
||||
cmd.Println("Configuration updated via daemon.")
|
||||
} else {
|
||||
fmt.Println("Configuration updated via daemon.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if s, ok := status.FromError(err); ok {
|
||||
return fmt.Errorf("daemon error: %v", s.Message())
|
||||
}
|
||||
return fmt.Errorf("failed to update config via daemon: %v", err)
|
||||
}
|
||||
// else: fall back to direct file write
|
||||
}
|
||||
}
|
||||
|
||||
switch setting {
|
||||
case "management-url":
|
||||
input := internal.ConfigInput{ConfigPath: configPath, ManagementURL: value}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set management-url: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set management-url to: %s\n", value)
|
||||
} else {
|
||||
fmt.Printf("Set management-url to: %s\n", value)
|
||||
}
|
||||
case "admin-url":
|
||||
input := internal.ConfigInput{ConfigPath: configPath, AdminURL: value}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set admin-url: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set admin-url to: %s\n", value)
|
||||
} else {
|
||||
fmt.Printf("Set admin-url to: %s\n", value)
|
||||
}
|
||||
case "interface-name":
|
||||
if err := parseInterfaceName(value); err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, InterfaceName: &value}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set interface-name: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set interface-name to: %s\n", value)
|
||||
} else {
|
||||
fmt.Printf("Set interface-name to: %s\n", value)
|
||||
}
|
||||
case "external-ip-map":
|
||||
var ips []string
|
||||
if value == "" {
|
||||
ips = []string{}
|
||||
} else {
|
||||
ips = strings.Split(value, ",")
|
||||
}
|
||||
if err := validateNATExternalIPs(ips); err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, NATExternalIPs: ips}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set external-ip-map: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set external-ip-map to: %v\n", ips)
|
||||
} else {
|
||||
fmt.Printf("Set external-ip-map to: %v\n", ips)
|
||||
}
|
||||
case "extra-iface-blacklist":
|
||||
var ifaces []string
|
||||
if value == "" {
|
||||
ifaces = []string{}
|
||||
} else {
|
||||
ifaces = strings.Split(value, ",")
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, ExtraIFaceBlackList: ifaces}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set extra-iface-blacklist: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set extra-iface-blacklist to: %v\n", ifaces)
|
||||
} else {
|
||||
fmt.Printf("Set extra-iface-blacklist to: %v\n", ifaces)
|
||||
}
|
||||
case "dns-resolver-address":
|
||||
if value != "" && !isValidAddrPort(value) {
|
||||
return fmt.Errorf("%s is invalid, it should be formatted as IP:Port string or as an empty string like \"\"", value)
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, CustomDNSAddress: []byte(value)}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set dns-resolver-address: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set dns-resolver-address to: %s\n", value)
|
||||
} else {
|
||||
fmt.Printf("Set dns-resolver-address to: %s\n", value)
|
||||
}
|
||||
case "extra-dns-labels":
|
||||
var labels []string
|
||||
if value == "" {
|
||||
labels = []string{}
|
||||
} else {
|
||||
labels = strings.Split(value, ",")
|
||||
}
|
||||
domains, err := domain.ValidateDomains(labels)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid DNS labels: %v", err)
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DNSLabels: domains}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set extra-dns-labels: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set extra-dns-labels to: %v\n", labels)
|
||||
} else {
|
||||
fmt.Printf("Set extra-dns-labels to: %v\n", labels)
|
||||
}
|
||||
case "preshared-key":
|
||||
input := internal.ConfigInput{ConfigPath: configPath, PreSharedKey: &value}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set preshared-key: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set preshared-key to: %s\n", value)
|
||||
} else {
|
||||
fmt.Printf("Set preshared-key to: %s\n", value)
|
||||
}
|
||||
case "hostname":
|
||||
// Hostname is not persisted in config, so just print a warning
|
||||
if cmd != nil {
|
||||
cmd.Printf("Warning: hostname is not persisted in config. Use --hostname with up command.\n")
|
||||
} else {
|
||||
fmt.Printf("Warning: hostname is not persisted in config. Use --hostname with up command.\n")
|
||||
}
|
||||
case "enable-rosenpass":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, RosenpassEnabled: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set enable-rosenpass: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set enable-rosenpass to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set enable-rosenpass to: %v\n", b)
|
||||
}
|
||||
case "rosenpass-permissive":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, RosenpassPermissive: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set rosenpass-permissive: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set rosenpass-permissive to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set rosenpass-permissive to: %v\n", b)
|
||||
}
|
||||
case "allow-server-ssh":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, ServerSSHAllowed: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set allow-server-ssh: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set allow-server-ssh to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set allow-server-ssh to: %v\n", b)
|
||||
}
|
||||
case "network-monitor":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, NetworkMonitor: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set network-monitor: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set network-monitor to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set network-monitor to: %v\n", b)
|
||||
}
|
||||
case "disable-auto-connect":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DisableAutoConnect: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set disable-auto-connect: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set disable-auto-connect to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set disable-auto-connect to: %v\n", b)
|
||||
}
|
||||
case "disable-client-routes":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DisableClientRoutes: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set disable-client-routes: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set disable-client-routes to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set disable-client-routes to: %v\n", b)
|
||||
}
|
||||
case "disable-server-routes":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DisableServerRoutes: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set disable-server-routes: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set disable-server-routes to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set disable-server-routes to: %v\n", b)
|
||||
}
|
||||
case "disable-dns":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DisableDNS: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set disable-dns: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set disable-dns to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set disable-dns to: %v\n", b)
|
||||
}
|
||||
case "disable-firewall":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DisableFirewall: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set disable-firewall: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set disable-firewall to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set disable-firewall to: %v\n", b)
|
||||
}
|
||||
case "block-lan-access":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, BlockLANAccess: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set block-lan-access: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set block-lan-access to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set block-lan-access to: %v\n", b)
|
||||
}
|
||||
case "block-inbound":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, BlockInbound: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set block-inbound: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set block-inbound to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set block-inbound to: %v\n", b)
|
||||
}
|
||||
case "enable-lazy-connection":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, LazyConnectionEnabled: &b}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set enable-lazy-connection: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set enable-lazy-connection to: %v\n", b)
|
||||
} else {
|
||||
fmt.Printf("Set enable-lazy-connection to: %v\n", b)
|
||||
}
|
||||
case "wireguard-port":
|
||||
p, err := parseUint16(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pi := int(p)
|
||||
input := internal.ConfigInput{ConfigPath: configPath, WireguardPort: &pi}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set wireguard-port: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set wireguard-port to: %d\n", p)
|
||||
} else {
|
||||
fmt.Printf("Set wireguard-port to: %d\n", p)
|
||||
}
|
||||
case "dns-router-interval":
|
||||
d, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration: %v", err)
|
||||
}
|
||||
input := internal.ConfigInput{ConfigPath: configPath, DNSRouteInterval: &d}
|
||||
_, err = internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set dns-router-interval: %v", err)
|
||||
}
|
||||
if cmd != nil {
|
||||
cmd.Printf("Set dns-router-interval to: %s\n", d)
|
||||
} else {
|
||||
fmt.Printf("Set dns-router-interval to: %s\n", d)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown setting: %s", setting)
|
||||
}
|
||||
|
||||
if cmd != nil {
|
||||
cmd.Println("Configuration updated successfully.")
|
||||
} else {
|
||||
fmt.Println("Configuration updated successfully.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseBool(val string) (bool, error) {
|
||||
v := strings.ToLower(val)
|
||||
if v == "true" || v == "1" {
|
||||
return true, nil
|
||||
}
|
||||
if v == "false" || v == "0" {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("invalid boolean value: %s", val)
|
||||
}
|
||||
|
||||
func parseUint16(val string) (uint16, error) {
|
||||
var p uint16
|
||||
_, err := fmt.Sscanf(val, "%d", &p)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid uint16 value: %s", val)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
162
client/cmd/set_test.go
Normal file
162
client/cmd/set_test.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSetCommand_AllSettings(t *testing.T) {
|
||||
tempFile, err := os.CreateTemp("", "config.json")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
// Write empty JSON object to the config file to avoid JSON parse errors
|
||||
_, err = tempFile.WriteString("{}")
|
||||
require.NoError(t, err)
|
||||
tempFile.Close()
|
||||
|
||||
configPath = tempFile.Name()
|
||||
|
||||
tests := []struct {
|
||||
setting string
|
||||
value string
|
||||
verify func(*testing.T, *internal.Config)
|
||||
wantErr bool
|
||||
}{
|
||||
{"management-url", "https://test.mgmt:443", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, "https://test.mgmt:443", c.ManagementURL.String())
|
||||
}, false},
|
||||
{"admin-url", "https://test.admin:443", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, "https://test.admin:443", c.AdminURL.String())
|
||||
}, false},
|
||||
{"interface-name", "utun99", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, "utun99", c.WgIface)
|
||||
}, false},
|
||||
{"external-ip-map", "12.34.56.78,12.34.56.79", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, []string{"12.34.56.78", "12.34.56.79"}, c.NATExternalIPs)
|
||||
}, false},
|
||||
{"extra-iface-blacklist", "eth1,eth2", func(t *testing.T, c *internal.Config) {
|
||||
require.Contains(t, c.IFaceBlackList, "eth1")
|
||||
require.Contains(t, c.IFaceBlackList, "eth2")
|
||||
}, false},
|
||||
{"dns-resolver-address", "127.0.0.1:5053", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, "127.0.0.1:5053", c.CustomDNSAddress)
|
||||
}, false},
|
||||
{"extra-dns-labels", "vpc1,mgmt1", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, strings.Contains(c.DNSLabels.SafeString(), "vpc1"))
|
||||
require.True(t, strings.Contains(c.DNSLabels.SafeString(), "mgmt1"))
|
||||
}, false},
|
||||
{"preshared-key", "testkey", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, "testkey", c.PreSharedKey)
|
||||
}, false},
|
||||
{"enable-rosenpass", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, c.RosenpassEnabled)
|
||||
}, false},
|
||||
{"rosenpass-permissive", "false", func(t *testing.T, c *internal.Config) {
|
||||
require.False(t, c.RosenpassPermissive)
|
||||
}, false},
|
||||
{"allow-server-ssh", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.NotNil(t, c.ServerSSHAllowed)
|
||||
require.True(t, *c.ServerSSHAllowed)
|
||||
}, false},
|
||||
{"network-monitor", "false", func(t *testing.T, c *internal.Config) {
|
||||
require.NotNil(t, c.NetworkMonitor)
|
||||
require.False(t, *c.NetworkMonitor)
|
||||
}, false},
|
||||
{"disable-auto-connect", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, c.DisableAutoConnect)
|
||||
}, false},
|
||||
{"disable-client-routes", "false", func(t *testing.T, c *internal.Config) {
|
||||
require.False(t, c.DisableClientRoutes)
|
||||
}, false},
|
||||
{"disable-server-routes", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, c.DisableServerRoutes)
|
||||
}, false},
|
||||
{"disable-dns", "false", func(t *testing.T, c *internal.Config) {
|
||||
require.False(t, c.DisableDNS)
|
||||
}, false},
|
||||
{"disable-firewall", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, c.DisableFirewall)
|
||||
}, false},
|
||||
{"block-lan-access", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, c.BlockLANAccess)
|
||||
}, false},
|
||||
{"block-inbound", "false", func(t *testing.T, c *internal.Config) {
|
||||
require.False(t, c.BlockInbound)
|
||||
}, false},
|
||||
{"enable-lazy-connection", "true", func(t *testing.T, c *internal.Config) {
|
||||
require.True(t, c.LazyConnectionEnabled)
|
||||
}, false},
|
||||
{"wireguard-port", "51820", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, 51820, c.WgPort)
|
||||
}, false},
|
||||
{"dns-router-interval", "2m", func(t *testing.T, c *internal.Config) {
|
||||
require.Equal(t, 2*time.Minute, c.DNSRouteInterval)
|
||||
}, false},
|
||||
// Invalid cases
|
||||
{"enable-rosenpass", "notabool", nil, true},
|
||||
{"wireguard-port", "notanint", nil, true},
|
||||
{"dns-router-interval", "notaduration", nil, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.setting+"="+tt.value, func(t *testing.T) {
|
||||
args := []string{tt.setting, tt.value}
|
||||
err := setFunc(nil, args)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
config, err := internal.ReadConfig(configPath)
|
||||
require.NoError(t, err)
|
||||
if tt.verify != nil {
|
||||
tt.verify(t, config)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCommand_EnvVars(t *testing.T) {
|
||||
tempFile, err := os.CreateTemp("", "config.json")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
// Write empty JSON object to the config file to avoid JSON parse errors
|
||||
_, err = tempFile.WriteString("{}")
|
||||
require.NoError(t, err)
|
||||
tempFile.Close()
|
||||
|
||||
configPath = tempFile.Name()
|
||||
|
||||
os.Setenv("NB_INTERFACE_NAME", "utun77")
|
||||
defer os.Unsetenv("NB_INTERFACE_NAME")
|
||||
args := []string{"interface-name", "utun99"}
|
||||
err = setFunc(nil, args)
|
||||
require.NoError(t, err)
|
||||
config, err := internal.ReadConfig(configPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "utun77", config.WgIface)
|
||||
|
||||
os.Unsetenv("NB_INTERFACE_NAME")
|
||||
os.Setenv("WT_INTERFACE_NAME", "utun88")
|
||||
defer os.Unsetenv("WT_INTERFACE_NAME")
|
||||
err = setFunc(nil, args)
|
||||
require.NoError(t, err)
|
||||
config, err = internal.ReadConfig(configPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "utun88", config.WgIface)
|
||||
|
||||
os.Unsetenv("WT_INTERFACE_NAME")
|
||||
// No env var, should use CLI value
|
||||
err = setFunc(nil, args)
|
||||
require.NoError(t, err)
|
||||
config, err = internal.ReadConfig(configPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "utun99", config.WgIface)
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func getStatus(ctx context.Context) (*proto.StatusResponse, error) {
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
resp, err := proto.NewDaemonServiceClient(conn).Status(ctx, &proto.StatusRequest{GetFullPeerStatus: true})
|
||||
resp, err := proto.NewDaemonServiceClient(conn).Status(ctx, &proto.StatusRequest{GetFullPeerStatus: true, ShouldRunProbes: true})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("status failed: %v", status.Convert(err).Message())
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func startManagement(t *testing.T, config *types.Config, testFile string) (*grpc
|
||||
Return(&types.Settings{}, nil).
|
||||
AnyTimes()
|
||||
|
||||
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
||||
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -319,10 +319,6 @@ func (config *Config) apply(input ConfigInput) (updated bool, err error) {
|
||||
*input.WireguardPort, config.WgPort)
|
||||
config.WgPort = *input.WireguardPort
|
||||
updated = true
|
||||
} else if config.WgPort == 0 {
|
||||
config.WgPort = iface.DefaultWgPort
|
||||
log.Infof("using default Wireguard port %d", config.WgPort)
|
||||
updated = true
|
||||
}
|
||||
|
||||
if input.InterfaceName != nil && *input.InterfaceName != config.WgIface {
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
|
||||
"github.com/netbirdio/netbird/client/iface"
|
||||
"github.com/netbirdio/netbird/client/iface/device"
|
||||
"github.com/netbirdio/netbird/client/internal/dns"
|
||||
"github.com/netbirdio/netbird/client/internal/listener"
|
||||
@@ -526,17 +525,13 @@ func statusRecorderToSignalConnStateNotifier(statusRecorder *peer.Status) signal
|
||||
|
||||
// freePort attempts to determine if the provided port is available, if not it will ask the system for a free port.
|
||||
func freePort(initPort int) (int, error) {
|
||||
addr := net.UDPAddr{}
|
||||
if initPort == 0 {
|
||||
initPort = iface.DefaultWgPort
|
||||
}
|
||||
|
||||
addr.Port = initPort
|
||||
addr := net.UDPAddr{Port: initPort}
|
||||
|
||||
conn, err := net.ListenUDP("udp", &addr)
|
||||
if err == nil {
|
||||
returnPort := conn.LocalAddr().(*net.UDPAddr).Port
|
||||
closeConnWithLog(conn)
|
||||
return initPort, nil
|
||||
return returnPort, nil
|
||||
}
|
||||
|
||||
// if the port is already in use, ask the system for a free port
|
||||
|
||||
@@ -13,10 +13,10 @@ func Test_freePort(t *testing.T) {
|
||||
shouldMatch bool
|
||||
}{
|
||||
{
|
||||
name: "not provided, fallback to default",
|
||||
name: "when port is 0 use random port",
|
||||
port: 0,
|
||||
want: 51820,
|
||||
shouldMatch: true,
|
||||
want: 0,
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
name: "provided and available",
|
||||
@@ -31,7 +31,7 @@ func Test_freePort(t *testing.T) {
|
||||
shouldMatch: false,
|
||||
},
|
||||
}
|
||||
c1, err := net.ListenUDP("udp", &net.UDPAddr{Port: 51830})
|
||||
c1, err := net.ListenUDP("udp", &net.UDPAddr{Port: 0})
|
||||
if err != nil {
|
||||
t.Errorf("freePort error = %v", err)
|
||||
}
|
||||
@@ -39,6 +39,14 @@ func Test_freePort(t *testing.T) {
|
||||
_ = c1.Close()
|
||||
}(c1)
|
||||
|
||||
if tests[1].port == c1.LocalAddr().(*net.UDPAddr).Port {
|
||||
tests[1].port++
|
||||
tests[1].want++
|
||||
}
|
||||
|
||||
tests[2].port = c1.LocalAddr().(*net.UDPAddr).Port
|
||||
tests[2].want = c1.LocalAddr().(*net.UDPAddr).Port
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -1476,7 +1476,7 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
|
||||
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
|
||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@@ -28,7 +28,10 @@ func (n Nexthop) String() string {
|
||||
if n.Intf == nil {
|
||||
return n.IP.String()
|
||||
}
|
||||
return fmt.Sprintf("%s @ %d (%s)", n.IP.String(), n.Intf.Index, n.Intf.Name)
|
||||
if n.IP.IsValid() {
|
||||
return fmt.Sprintf("%s @ %d (%s)", n.IP.String(), n.Intf.Index, n.Intf.Name)
|
||||
}
|
||||
return fmt.Sprintf("no-ip @ %d (%s)", n.Intf.Index, n.Intf.Name)
|
||||
}
|
||||
|
||||
type wgIface interface {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<Wix
|
||||
xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
xmlns="http://wixtoolset.org/schemas/v4/wxs"
|
||||
xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
|
||||
<Package Name="NetBird" Version="$(env.NETBIRD_VERSION)" Manufacturer="NetBird GmbH" Language="1033" UpgradeCode="6456ec4e-3ad6-4b9b-a2be-98e81cb21ccf"
|
||||
InstallerVersion="500" Compressed="yes" Codepage="utf-8" >
|
||||
|
||||
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
|
||||
<Feature Id="NetbirdFeature" Title="Netbird" Level="1">
|
||||
@@ -46,29 +48,10 @@
|
||||
<ComponentRef Id="NetbirdFiles" />
|
||||
</ComponentGroup>
|
||||
|
||||
<Property Id="cmd" Value="cmd.exe"/>
|
||||
<util:CloseApplication Id="CloseNetBird" CloseMessage="no" Target="netbird.exe" RebootPrompt="no" />
|
||||
<util:CloseApplication Id="CloseNetBirdUI" CloseMessage="no" Target="netbird-ui.exe" RebootPrompt="no" />
|
||||
|
||||
<CustomAction Id="KillDaemon"
|
||||
ExeCommand='/c "taskkill /im netbird.exe"'
|
||||
Execute="deferred"
|
||||
Property="cmd"
|
||||
Impersonate="no"
|
||||
Return="ignore"
|
||||
/>
|
||||
|
||||
<CustomAction Id="KillUI"
|
||||
ExeCommand='/c "taskkill /im netbird-ui.exe"'
|
||||
Execute="deferred"
|
||||
Property="cmd"
|
||||
Impersonate="no"
|
||||
Return="ignore"
|
||||
/>
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<!-- For Uninstallation -->
|
||||
<Custom Action="KillDaemon" Before="RemoveFiles" Condition="Installed"/>
|
||||
<Custom Action="KillUI" After="KillDaemon" Condition="Installed"/>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<!-- Icons -->
|
||||
<Icon Id="NetbirdIcon" SourceFile=".\client\ui\assets\netbird.ico" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -67,6 +67,12 @@ service DaemonService {
|
||||
rpc SubscribeEvents(SubscribeRequest) returns (stream SystemEvent) {}
|
||||
|
||||
rpc GetEvents(GetEventsRequest) returns (GetEventsResponse) {}
|
||||
|
||||
// Reloads the configuration from disk
|
||||
rpc ReloadConfig(ReloadConfigRequest) returns (ReloadConfigResponse) {}
|
||||
|
||||
// Sets a configuration value (for use by regular users via the daemon)
|
||||
rpc SetConfigValue(SetConfigValueRequest) returns (SetConfigValueResponse) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +164,7 @@ message UpResponse {}
|
||||
|
||||
message StatusRequest{
|
||||
bool getFullPeerStatus = 1;
|
||||
bool shouldRunProbes = 2;
|
||||
}
|
||||
|
||||
message StatusResponse{
|
||||
@@ -495,3 +502,12 @@ message GetEventsRequest {}
|
||||
message GetEventsResponse {
|
||||
repeated SystemEvent events = 1;
|
||||
}
|
||||
|
||||
message ReloadConfigRequest {}
|
||||
message ReloadConfigResponse {}
|
||||
|
||||
message SetConfigValueRequest {
|
||||
string setting = 1;
|
||||
string value = 2;
|
||||
}
|
||||
message SetConfigValueResponse {}
|
||||
|
||||
@@ -55,6 +55,10 @@ type DaemonServiceClient interface {
|
||||
TracePacket(ctx context.Context, in *TracePacketRequest, opts ...grpc.CallOption) (*TracePacketResponse, error)
|
||||
SubscribeEvents(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (DaemonService_SubscribeEventsClient, error)
|
||||
GetEvents(ctx context.Context, in *GetEventsRequest, opts ...grpc.CallOption) (*GetEventsResponse, error)
|
||||
// Reloads the configuration from disk
|
||||
ReloadConfig(ctx context.Context, in *ReloadConfigRequest, opts ...grpc.CallOption) (*ReloadConfigResponse, error)
|
||||
// Sets a configuration value (for use by regular users via the daemon)
|
||||
SetConfigValue(ctx context.Context, in *SetConfigValueRequest, opts ...grpc.CallOption) (*SetConfigValueResponse, error)
|
||||
}
|
||||
|
||||
type daemonServiceClient struct {
|
||||
@@ -268,6 +272,24 @@ func (c *daemonServiceClient) GetEvents(ctx context.Context, in *GetEventsReques
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *daemonServiceClient) ReloadConfig(ctx context.Context, in *ReloadConfigRequest, opts ...grpc.CallOption) (*ReloadConfigResponse, error) {
|
||||
out := new(ReloadConfigResponse)
|
||||
err := c.cc.Invoke(ctx, "/daemon.DaemonService/ReloadConfig", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *daemonServiceClient) SetConfigValue(ctx context.Context, in *SetConfigValueRequest, opts ...grpc.CallOption) (*SetConfigValueResponse, error) {
|
||||
out := new(SetConfigValueResponse)
|
||||
err := c.cc.Invoke(ctx, "/daemon.DaemonService/SetConfigValue", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DaemonServiceServer is the server API for DaemonService service.
|
||||
// All implementations must embed UnimplementedDaemonServiceServer
|
||||
// for forward compatibility
|
||||
@@ -309,6 +331,10 @@ type DaemonServiceServer interface {
|
||||
TracePacket(context.Context, *TracePacketRequest) (*TracePacketResponse, error)
|
||||
SubscribeEvents(*SubscribeRequest, DaemonService_SubscribeEventsServer) error
|
||||
GetEvents(context.Context, *GetEventsRequest) (*GetEventsResponse, error)
|
||||
// Reloads the configuration from disk
|
||||
ReloadConfig(context.Context, *ReloadConfigRequest) (*ReloadConfigResponse, error)
|
||||
// Sets a configuration value (for use by regular users via the daemon)
|
||||
SetConfigValue(context.Context, *SetConfigValueRequest) (*SetConfigValueResponse, error)
|
||||
mustEmbedUnimplementedDaemonServiceServer()
|
||||
}
|
||||
|
||||
@@ -376,6 +402,12 @@ func (UnimplementedDaemonServiceServer) SubscribeEvents(*SubscribeRequest, Daemo
|
||||
func (UnimplementedDaemonServiceServer) GetEvents(context.Context, *GetEventsRequest) (*GetEventsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetEvents not implemented")
|
||||
}
|
||||
func (UnimplementedDaemonServiceServer) ReloadConfig(context.Context, *ReloadConfigRequest) (*ReloadConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReloadConfig not implemented")
|
||||
}
|
||||
func (UnimplementedDaemonServiceServer) SetConfigValue(context.Context, *SetConfigValueRequest) (*SetConfigValueResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetConfigValue not implemented")
|
||||
}
|
||||
func (UnimplementedDaemonServiceServer) mustEmbedUnimplementedDaemonServiceServer() {}
|
||||
|
||||
// UnsafeDaemonServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
@@ -752,6 +784,42 @@ func _DaemonService_GetEvents_Handler(srv interface{}, ctx context.Context, dec
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DaemonService_ReloadConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ReloadConfigRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DaemonServiceServer).ReloadConfig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/daemon.DaemonService/ReloadConfig",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DaemonServiceServer).ReloadConfig(ctx, req.(*ReloadConfigRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DaemonService_SetConfigValue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SetConfigValueRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DaemonServiceServer).SetConfigValue(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/daemon.DaemonService/SetConfigValue",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DaemonServiceServer).SetConfigValue(ctx, req.(*SetConfigValueRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DaemonService_ServiceDesc is the grpc.ServiceDesc for DaemonService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -835,6 +903,14 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "GetEvents",
|
||||
Handler: _DaemonService_GetEvents_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ReloadConfig",
|
||||
Handler: _DaemonService_ReloadConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SetConfigValue",
|
||||
Handler: _DaemonService_SetConfigValue_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
||||
@@ -5,10 +5,13 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
@@ -95,6 +98,8 @@ func (s *Server) Start() error {
|
||||
defer s.mutex.Unlock()
|
||||
state := internal.CtxGetState(s.rootCtx)
|
||||
|
||||
s.setupReloadSignal()
|
||||
|
||||
if err := handlePanicLog(); err != nil {
|
||||
log.Warnf("failed to redirect stderr: %v", err)
|
||||
}
|
||||
@@ -707,7 +712,9 @@ func (s *Server) Status(
|
||||
s.statusRecorder.UpdateRosenpass(s.config.RosenpassEnabled, s.config.RosenpassPermissive)
|
||||
|
||||
if msg.GetFullPeerStatus {
|
||||
s.runProbes()
|
||||
if msg.ShouldRunProbes {
|
||||
s.runProbes()
|
||||
}
|
||||
|
||||
fullStatus := s.statusRecorder.GetFullStatus()
|
||||
pbFullStatus := toProtoFullStatus(fullStatus)
|
||||
@@ -916,3 +923,186 @@ func sendTerminalNotification() error {
|
||||
|
||||
return wallCmd.Wait()
|
||||
}
|
||||
|
||||
// Add a gRPC method to reload config from disk
|
||||
func (s *Server) ReloadConfig(_ context.Context, _ *proto.ReloadConfigRequest) (*proto.ReloadConfigResponse, error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
config, err := internal.ReadConfig(s.latestConfigInput.ConfigPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to reload config: %v", err)
|
||||
}
|
||||
s.config = config
|
||||
s.statusRecorder.UpdateManagementAddress(config.ManagementURL.String())
|
||||
s.statusRecorder.UpdateRosenpass(config.RosenpassEnabled, config.RosenpassPermissive)
|
||||
s.statusRecorder.UpdateLazyConnection(config.LazyConnectionEnabled)
|
||||
log.Infof("Reloaded config from disk")
|
||||
return &proto.ReloadConfigResponse{}, nil
|
||||
}
|
||||
|
||||
// Optionally, handle SIGHUP to reload config
|
||||
func (s *Server) setupReloadSignal() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP)
|
||||
go func() {
|
||||
for range c {
|
||||
_, err := s.ReloadConfig(context.Background(), &proto.ReloadConfigRequest{})
|
||||
if err != nil {
|
||||
log.Warnf("failed to reload config on SIGHUP: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Server) SetConfigValue(_ context.Context, req *proto.SetConfigValueRequest) (*proto.SetConfigValueResponse, error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
setting := req.Setting
|
||||
value := req.Value
|
||||
input := internal.ConfigInput{ConfigPath: s.latestConfigInput.ConfigPath}
|
||||
switch setting {
|
||||
case "management-url":
|
||||
input.ManagementURL = value
|
||||
case "admin-url":
|
||||
input.AdminURL = value
|
||||
case "interface-name":
|
||||
input.InterfaceName = &value
|
||||
case "external-ip-map":
|
||||
if value == "" {
|
||||
input.NATExternalIPs = []string{}
|
||||
} else {
|
||||
input.NATExternalIPs = strings.Split(value, ",")
|
||||
}
|
||||
case "extra-iface-blacklist":
|
||||
if value == "" {
|
||||
input.ExtraIFaceBlackList = []string{}
|
||||
} else {
|
||||
input.ExtraIFaceBlackList = strings.Split(value, ",")
|
||||
}
|
||||
case "dns-resolver-address":
|
||||
input.CustomDNSAddress = []byte(value)
|
||||
case "extra-dns-labels":
|
||||
if value == "" {
|
||||
input.DNSLabels = nil
|
||||
} else {
|
||||
labels := strings.Split(value, ",")
|
||||
domains, err := domain.ValidateDomains(labels)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid DNS labels: %v", err)
|
||||
}
|
||||
input.DNSLabels = domains
|
||||
}
|
||||
case "preshared-key":
|
||||
input.PreSharedKey = &value
|
||||
case "enable-rosenpass":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.RosenpassEnabled = &b
|
||||
case "rosenpass-permissive":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.RosenpassPermissive = &b
|
||||
case "allow-server-ssh":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.ServerSSHAllowed = &b
|
||||
case "network-monitor":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.NetworkMonitor = &b
|
||||
case "disable-auto-connect":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.DisableAutoConnect = &b
|
||||
case "disable-client-routes":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.DisableClientRoutes = &b
|
||||
case "disable-server-routes":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.DisableServerRoutes = &b
|
||||
case "disable-dns":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.DisableDNS = &b
|
||||
case "disable-firewall":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.DisableFirewall = &b
|
||||
case "block-lan-access":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.BlockLANAccess = &b
|
||||
case "block-inbound":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.BlockInbound = &b
|
||||
case "enable-lazy-connection":
|
||||
b, err := parseBool(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.LazyConnectionEnabled = &b
|
||||
case "wireguard-port":
|
||||
var p int
|
||||
_, err := fmt.Sscanf(value, "%d", &p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid wireguard-port: %s", value)
|
||||
}
|
||||
input.WireguardPort = &p
|
||||
case "dns-router-interval":
|
||||
d, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid duration: %v", err)
|
||||
}
|
||||
input.DNSRouteInterval = &d
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown setting: %s", setting)
|
||||
}
|
||||
_, err := internal.UpdateOrCreateConfig(input)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update config: %v", err)
|
||||
}
|
||||
// Reload config in memory
|
||||
config, err := internal.ReadConfig(s.latestConfigInput.ConfigPath)
|
||||
if err == nil {
|
||||
s.config = config
|
||||
}
|
||||
return &proto.SetConfigValueResponse{}, nil
|
||||
}
|
||||
|
||||
func parseBool(val string) (bool, error) {
|
||||
v := strings.ToLower(val)
|
||||
if v == "true" || v == "1" {
|
||||
return true, nil
|
||||
}
|
||||
if v == "false" || v == "0" {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("invalid boolean value: %s", val)
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||
|
||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock, false)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ func (s *serviceClient) onUpdateAvailable() {
|
||||
func (s *serviceClient) onSessionExpire() {
|
||||
s.sendNotification = true
|
||||
if s.sendNotification {
|
||||
s.eventHandler.runSelfCommand(s.ctx, "login-url", "true")
|
||||
go s.eventHandler.runSelfCommand(s.ctx, "login-url", "true")
|
||||
s.sendNotification = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ NETBIRD_MGMT_API_CERT_KEY_FILE="/etc/letsencrypt/live/$NETBIRD_LETSENCRYPT_DOMAI
|
||||
NETBIRD_MGMT_SINGLE_ACCOUNT_MODE_DOMAIN=$NETBIRD_DOMAIN
|
||||
NETBIRD_MGMT_DNS_DOMAIN=${NETBIRD_MGMT_DNS_DOMAIN:-netbird.selfhosted}
|
||||
NETBIRD_MGMT_IDP_SIGNKEY_REFRESH=${NETBIRD_MGMT_IDP_SIGNKEY_REFRESH:-false}
|
||||
NETBIRD_MGMT_DISABLE_DEFAULT_POLICY=${NETBIRD_MGMT_DISABLE_DEFAULT_POLICY:-false}
|
||||
|
||||
# Signal
|
||||
NETBIRD_SIGNAL_PROTOCOL="http"
|
||||
@@ -60,7 +61,7 @@ NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
|
||||
NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS=${NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS:-"53000"}
|
||||
NETBIRD_AUTH_PKCE_USE_ID_TOKEN=${NETBIRD_AUTH_PKCE_USE_ID_TOKEN:-false}
|
||||
NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN=${NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN:-false}
|
||||
NETBIRD_AUTH_PKCE_LOGIN_FLAG=${NETBIRD_AUTH_PKCE_LOGIN_FLAG:-1}
|
||||
NETBIRD_AUTH_PKCE_LOGIN_FLAG=${NETBIRD_AUTH_PKCE_LOGIN_FLAG:-0}
|
||||
NETBIRD_AUTH_PKCE_AUDIENCE=$NETBIRD_AUTH_AUDIENCE
|
||||
|
||||
# Dashboard
|
||||
@@ -139,3 +140,4 @@ export NETBIRD_RELAY_PORT
|
||||
export NETBIRD_RELAY_ENDPOINT
|
||||
export NETBIRD_RELAY_AUTH_SECRET
|
||||
export NETBIRD_RELAY_TAG
|
||||
export NETBIRD_MGMT_DISABLE_DEFAULT_POLICY
|
||||
|
||||
@@ -791,7 +791,6 @@ services:
|
||||
- '443:443'
|
||||
- '443:443/udp'
|
||||
- '80:80'
|
||||
- '8080:8080'
|
||||
volumes:
|
||||
- netbird_caddy_data:/data
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"0.0.0.0/0"
|
||||
]
|
||||
},
|
||||
"DisableDefaultPolicy": $NETBIRD_MGMT_DISABLE_DEFAULT_POLICY,
|
||||
"Datadir": "",
|
||||
"DataStoreEncryptionKey": "$NETBIRD_DATASTORE_ENC_KEY",
|
||||
"StoreConfig": {
|
||||
|
||||
@@ -92,7 +92,8 @@ NETBIRD_LETSENCRYPT_EMAIL=""
|
||||
NETBIRD_DISABLE_ANONYMOUS_METRICS=false
|
||||
# DNS DOMAIN configures the domain name used for peer resolution. By default it is netbird.selfhosted
|
||||
NETBIRD_MGMT_DNS_DOMAIN=netbird.selfhosted
|
||||
|
||||
# Disable default all-to-all policy for new accounts
|
||||
NETBIRD_MGMT_DISABLE_DEFAULT_POLICY=false
|
||||
# -------------------------------------------
|
||||
# Relay settings
|
||||
# -------------------------------------------
|
||||
|
||||
@@ -29,3 +29,4 @@ NETBIRD_TURN_EXTERNAL_IP=1.2.3.4
|
||||
NETBIRD_RELAY_PORT=33445
|
||||
NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN=true
|
||||
NETBIRD_AUTH_PKCE_LOGIN_FLAG=0
|
||||
NETBIRD_MGMT_DISABLE_DEFAULT_POLICY=$CI_NETBIRD_MGMT_DISABLE_DEFAULT_POLICY
|
||||
|
||||
@@ -100,7 +100,7 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
||||
Return(true, nil).
|
||||
AnyTimes()
|
||||
|
||||
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
||||
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ var (
|
||||
peersManager := peers.NewManager(store, permissionsManager)
|
||||
proxyController := integrations.NewController(store)
|
||||
accountManager, err := server.BuildManager(ctx, store, peersUpdateManager, idpManager, mgmtSingleAccModeDomain,
|
||||
dnsDomain, eventStore, geo, userDeleteFromIDPEnabled, integratedPeerValidator, appMetrics, proxyController, settingsManager, permissionsManager)
|
||||
dnsDomain, eventStore, geo, userDeleteFromIDPEnabled, integratedPeerValidator, appMetrics, proxyController, settingsManager, permissionsManager, config.DisableDefaultPolicy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build default manager: %v", err)
|
||||
}
|
||||
|
||||
@@ -102,6 +102,8 @@ type DefaultAccountManager struct {
|
||||
|
||||
accountUpdateLocks sync.Map
|
||||
updateAccountPeersBufferInterval atomic.Int64
|
||||
|
||||
disableDefaultPolicy bool
|
||||
}
|
||||
|
||||
// getJWTGroupsChanges calculates the changes needed to sync a user's JWT groups.
|
||||
@@ -170,6 +172,7 @@ func BuildManager(
|
||||
proxyController port_forwarding.Controller,
|
||||
settingsManager settings.Manager,
|
||||
permissionsManager permissions.Manager,
|
||||
disableDefaultPolicy bool,
|
||||
) (*DefaultAccountManager, error) {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
@@ -195,6 +198,7 @@ func BuildManager(
|
||||
proxyController: proxyController,
|
||||
settingsManager: settingsManager,
|
||||
permissionsManager: permissionsManager,
|
||||
disableDefaultPolicy: disableDefaultPolicy,
|
||||
}
|
||||
|
||||
am.startWarmup(ctx)
|
||||
@@ -543,7 +547,7 @@ func (am *DefaultAccountManager) newAccount(ctx context.Context, userID, domain
|
||||
log.WithContext(ctx).Warnf("an account with ID already exists, retrying...")
|
||||
continue
|
||||
case statusErr.Type() == status.NotFound:
|
||||
newAccount := newAccountWithId(ctx, accountId, userID, domain)
|
||||
newAccount := newAccountWithId(ctx, accountId, userID, domain, am.disableDefaultPolicy)
|
||||
am.StoreEvent(ctx, userID, newAccount.Id, accountId, activity.AccountCreated, nil)
|
||||
return newAccount, nil
|
||||
default:
|
||||
@@ -1688,7 +1692,7 @@ func (am *DefaultAccountManager) GetAccountSettings(ctx context.Context, account
|
||||
}
|
||||
|
||||
// newAccountWithId creates a new Account with a default SetupKey (doesn't store in a Store) and provided id
|
||||
func newAccountWithId(ctx context.Context, accountID, userID, domain string) *types.Account {
|
||||
func newAccountWithId(ctx context.Context, accountID, userID, domain string, disableDefaultPolicy bool) *types.Account {
|
||||
log.WithContext(ctx).Debugf("creating new account")
|
||||
|
||||
network := types.NewNetwork()
|
||||
@@ -1731,7 +1735,7 @@ func newAccountWithId(ctx context.Context, accountID, userID, domain string) *ty
|
||||
},
|
||||
}
|
||||
|
||||
if err := acc.AddAllGroup(); err != nil {
|
||||
if err := acc.AddAllGroup(disableDefaultPolicy); err != nil {
|
||||
log.WithContext(ctx).Errorf("error adding all group to account %s: %v", acc.Id, err)
|
||||
}
|
||||
return acc
|
||||
@@ -1833,7 +1837,7 @@ func (am *DefaultAccountManager) GetOrCreateAccountByPrivateDomain(ctx context.C
|
||||
},
|
||||
}
|
||||
|
||||
if err := newAccount.AddAllGroup(); err != nil {
|
||||
if err := newAccount.AddAllGroup(am.disableDefaultPolicy); err != nil {
|
||||
return nil, false, status.Errorf(status.Internal, "failed to add all group to new account by private domain")
|
||||
}
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ func TestAccount_GetPeerNetworkMap(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, testCase := range tt {
|
||||
account := newAccountWithId(context.Background(), "account-1", userID, "netbird.io")
|
||||
account := newAccountWithId(context.Background(), "account-1", userID, "netbird.io", false)
|
||||
account.UpdateSettings(&testCase.accountSettings)
|
||||
account.Network = network
|
||||
account.Peers = testCase.peers
|
||||
@@ -398,7 +398,7 @@ func TestNewAccount(t *testing.T) {
|
||||
domain := "netbird.io"
|
||||
userId := "account_creator"
|
||||
accountID := "account_id"
|
||||
account := newAccountWithId(context.Background(), accountID, userId, domain)
|
||||
account := newAccountWithId(context.Background(), accountID, userId, domain, false)
|
||||
verifyNewAccountHasDefaultFields(t, account, userId, domain, []string{userId})
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ func TestDefaultAccountManager_GetAccountIDFromToken(t *testing.T) {
|
||||
func TestDefaultAccountManager_SyncUserJWTGroups(t *testing.T) {
|
||||
userId := "user-id"
|
||||
domain := "test.domain"
|
||||
_ = newAccountWithId(context.Background(), "", userId, domain)
|
||||
_ = newAccountWithId(context.Background(), "", userId, domain, false)
|
||||
manager, err := createManager(t)
|
||||
require.NoError(t, err, "unable to create account manager")
|
||||
accountID, err := manager.GetAccountIDByUserID(context.Background(), userId, domain)
|
||||
@@ -793,7 +793,7 @@ func TestAccountManager_GetAccountByUserID(t *testing.T) {
|
||||
}
|
||||
|
||||
func createAccount(am *DefaultAccountManager, accountID, userID, domain string) (*types.Account, error) {
|
||||
account := newAccountWithId(context.Background(), accountID, userID, domain)
|
||||
account := newAccountWithId(context.Background(), accountID, userID, domain, false)
|
||||
err := am.Store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -2879,7 +2879,7 @@ func createManager(t testing.TB) (*DefaultAccountManager, error) {
|
||||
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
|
||||
manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ func createDNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
||||
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
}
|
||||
|
||||
func createDNSStore(t *testing.T) (store.Store, error) {
|
||||
@@ -267,7 +267,7 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account
|
||||
|
||||
domain := "example.com"
|
||||
|
||||
account := newAccountWithId(context.Background(), dnsAccountID, dnsAdminUserID, domain)
|
||||
account := newAccountWithId(context.Background(), dnsAccountID, dnsAdminUserID, domain, false)
|
||||
|
||||
account.Users[dnsRegularUserID] = &types.User{
|
||||
Id: dnsRegularUserID,
|
||||
|
||||
@@ -127,7 +127,7 @@ func TestNewManagerPeerDisconnected(t *testing.T) {
|
||||
}
|
||||
|
||||
func seedPeers(store *MockStore, numberOfPeers int, numberOfEphemeralPeers int) {
|
||||
store.account = newAccountWithId(context.Background(), "my account", "", "")
|
||||
store.account = newAccountWithId(context.Background(), "my account", "", "", false)
|
||||
|
||||
for i := 0; i < numberOfPeers; i++ {
|
||||
peerId := fmt.Sprintf("peer_%d", i)
|
||||
|
||||
@@ -369,7 +369,7 @@ func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *t
|
||||
Id: "example user",
|
||||
AutoGroups: []string{groupForUsers.ID},
|
||||
}
|
||||
account := newAccountWithId(context.Background(), accountID, groupAdminUserID, domain)
|
||||
account := newAccountWithId(context.Background(), accountID, groupAdminUserID, domain, false)
|
||||
account.Routes[routeResource.ID] = routeResource
|
||||
account.Routes[routePeerGroupResource.ID] = routePeerGroupResource
|
||||
account.NameServerGroups[nameServerGroup.ID] = nameServerGroup
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
package testing_tools
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
@@ -138,7 +137,7 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve
|
||||
userManager := users.NewManager(store)
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
settingsManager := settings.NewManager(store, userManager, integrations.NewManager(&activity.InMemoryEventStore{}), permissionsManager)
|
||||
am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager, permissionsManager)
|
||||
am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager, permissionsManager, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create manager: %v", err)
|
||||
}
|
||||
|
||||
@@ -83,15 +83,12 @@ func (am *DefaultAccountManager) GetValidatedPeers(ctx context.Context, accountI
|
||||
var peers []*nbpeer.Peer
|
||||
var settings *types.Settings
|
||||
|
||||
err = am.Store.ExecuteInTransaction(ctx, func(transaction store.Store) error {
|
||||
groups, err = transaction.GetAccountGroups(ctx, store.LockingStrengthShare, accountID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groups, err = am.Store.GetAccountGroups(ctx, store.LockingStrengthShare, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
peers, err = transaction.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "")
|
||||
return err
|
||||
})
|
||||
peers, err = am.Store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -444,7 +444,7 @@ func startManagementForTest(t *testing.T, testFile string, config *types.Config)
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
|
||||
accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted",
|
||||
eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
|
||||
if err != nil {
|
||||
cleanup()
|
||||
|
||||
@@ -211,7 +211,7 @@ func startServer(
|
||||
port_forwarding.NewControllerMock(),
|
||||
settingsMockManager,
|
||||
permissionsManager,
|
||||
)
|
||||
false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creating an account manager: %v", err)
|
||||
}
|
||||
|
||||
@@ -779,7 +779,7 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
||||
t.Cleanup(ctrl.Finish)
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
}
|
||||
|
||||
func createNSStore(t *testing.T) (store.Store, error) {
|
||||
@@ -848,7 +848,7 @@ func initTestNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account,
|
||||
userID := testUserID
|
||||
domain := "example.com"
|
||||
|
||||
account := newAccountWithId(context.Background(), accountID, userID, domain)
|
||||
account := newAccountWithId(context.Background(), accountID, userID, domain, false)
|
||||
|
||||
account.NameServerGroups[existingNSGroup.ID] = &existingNSGroup
|
||||
|
||||
|
||||
@@ -1169,7 +1169,7 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
globalStart := time.Now()
|
||||
|
||||
approvedPeersMap, err := am.integratedPeerValidator.GetValidatedPeers(account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra)
|
||||
if err != nil {
|
||||
@@ -1204,18 +1204,27 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
defer wg.Done()
|
||||
defer func() { <-semaphore }()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
postureChecks, err := am.getPeerPostureChecks(account, p.ID)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Debugf("failed to get posture checks for peer %s: %v", peer.ID, err)
|
||||
return
|
||||
}
|
||||
|
||||
am.metrics.UpdateChannelMetrics().CountCalcPostureChecksDuration(time.Since(start))
|
||||
start = time.Now()
|
||||
|
||||
remotePeerNetworkMap := account.GetPeerNetworkMap(ctx, p.ID, customZone, approvedPeersMap, resourcePolicies, routers, am.metrics.AccountManagerMetrics())
|
||||
|
||||
am.metrics.UpdateChannelMetrics().CountCalcPeerNetworkMapDuration(time.Since(start))
|
||||
start = time.Now()
|
||||
|
||||
proxyNetworkMap, ok := proxyNetworkMaps[p.ID]
|
||||
if ok {
|
||||
remotePeerNetworkMap.Merge(proxyNetworkMap)
|
||||
}
|
||||
am.metrics.UpdateChannelMetrics().CountMergeNetworkMapDuration(time.Since(start))
|
||||
|
||||
extraSetting, err := am.settingsManager.GetExtraSettings(ctx, accountID)
|
||||
if err != nil {
|
||||
@@ -1223,7 +1232,10 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
return
|
||||
}
|
||||
|
||||
start = time.Now()
|
||||
update := toSyncResponse(ctx, nil, p, nil, nil, remotePeerNetworkMap, dnsDomain, postureChecks, dnsCache, account.Settings, extraSetting)
|
||||
am.metrics.UpdateChannelMetrics().CountToSyncResponseDuration(time.Since(start))
|
||||
|
||||
am.peersUpdateManager.SendUpdate(ctx, p.ID, &UpdateMessage{Update: update, NetworkMap: remotePeerNetworkMap})
|
||||
}(peer)
|
||||
}
|
||||
@@ -1232,7 +1244,7 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
|
||||
wg.Wait()
|
||||
if am.metrics != nil {
|
||||
am.metrics.AccountManagerMetrics().CountUpdateAccountPeersDuration(time.Since(start))
|
||||
am.metrics.AccountManagerMetrics().CountUpdateAccountPeersDuration(time.Since(globalStart))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -480,7 +480,7 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) {
|
||||
accountID := "test_account"
|
||||
adminUser := "account_creator"
|
||||
someUser := "some_user"
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "")
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "", false)
|
||||
account.Users[someUser] = &types.User{
|
||||
Id: someUser,
|
||||
Role: types.UserRoleUser,
|
||||
@@ -667,7 +667,7 @@ func TestDefaultAccountManager_GetPeers(t *testing.T) {
|
||||
accountID := "test_account"
|
||||
adminUser := "account_creator"
|
||||
someUser := "some_user"
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "")
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "", false)
|
||||
account.Users[someUser] = &types.User{
|
||||
Id: someUser,
|
||||
Role: testCase.role,
|
||||
@@ -737,7 +737,7 @@ func setupTestAccountManager(b testing.TB, peers int, groups int) (*DefaultAccou
|
||||
adminUser := "account_creator"
|
||||
regularUser := "regular_user"
|
||||
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "")
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "", false)
|
||||
account.Users[regularUser] = &types.User{
|
||||
Id: regularUser,
|
||||
Role: types.UserRoleUser,
|
||||
@@ -1267,7 +1267,7 @@ func Test_RegisterPeerByUser(t *testing.T) {
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||
@@ -1342,7 +1342,7 @@ func Test_RegisterPeerBySetupKey(t *testing.T) {
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||
@@ -1477,7 +1477,7 @@ func Test_RegisterPeerRollbackOnFailure(t *testing.T) {
|
||||
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||
@@ -1546,7 +1546,7 @@ func Test_LoginPeer(t *testing.T) {
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||
@@ -2052,7 +2052,7 @@ func Test_DeletePeer(t *testing.T) {
|
||||
// account with an admin and a regular user
|
||||
accountID := "test_account"
|
||||
adminUser := "account_creator"
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "")
|
||||
account := newAccountWithId(context.Background(), accountID, adminUser, "", false)
|
||||
account.Peers = map[string]*nbpeer.Peer{
|
||||
"peer1": {
|
||||
ID: "peer1",
|
||||
|
||||
@@ -106,7 +106,7 @@ func initTestPostureChecksAccount(am *DefaultAccountManager) (*types.Account, er
|
||||
Role: types.UserRoleUser,
|
||||
}
|
||||
|
||||
account := newAccountWithId(context.Background(), accountID, groupAdminUserID, domain)
|
||||
account := newAccountWithId(context.Background(), accountID, groupAdminUserID, domain, false)
|
||||
account.Users[admin.Id] = admin
|
||||
account.Users[user.Id] = user
|
||||
|
||||
|
||||
@@ -1284,7 +1284,7 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
|
||||
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
}
|
||||
|
||||
func createRouterStore(t *testing.T) (store.Store, error) {
|
||||
@@ -1305,7 +1305,7 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*types.Accou
|
||||
accountID := "testingAcc"
|
||||
domain := "example.com"
|
||||
|
||||
account := newAccountWithId(context.Background(), accountID, userID, domain)
|
||||
account := newAccountWithId(context.Background(), accountID, userID, domain, false)
|
||||
err := am.Store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1184,7 +1184,7 @@ func NewSqliteStoreFromFileStore(ctx context.Context, fileStore *FileStore, data
|
||||
for _, account := range fileStore.GetAllAccounts(ctx) {
|
||||
_, err = account.GetGroupAll()
|
||||
if err != nil {
|
||||
if err := account.AddAllGroup(); err != nil {
|
||||
if err := account.AddAllGroup(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2044,7 +2044,7 @@ func newAccountWithId(ctx context.Context, accountID, userID, domain string) *ty
|
||||
},
|
||||
}
|
||||
|
||||
if err := acc.AddAllGroup(); err != nil {
|
||||
if err := acc.AddAllGroup(false); err != nil {
|
||||
log.WithContext(ctx).Errorf("error adding all group to account %s: %v", acc.Id, err)
|
||||
}
|
||||
return acc
|
||||
|
||||
@@ -391,7 +391,7 @@ func addAllGroupToAccount(ctx context.Context, store Store) error {
|
||||
|
||||
_, err := account.GetGroupAll()
|
||||
if err != nil {
|
||||
if err := account.AddAllGroup(); err != nil {
|
||||
if err := account.AddAllGroup(false); err != nil {
|
||||
return err
|
||||
}
|
||||
shouldSave = true
|
||||
|
||||
@@ -18,6 +18,10 @@ type UpdateChannelMetrics struct {
|
||||
getAllConnectedPeersDurationMicro metric.Int64Histogram
|
||||
getAllConnectedPeers metric.Int64Histogram
|
||||
hasChannelDurationMicro metric.Int64Histogram
|
||||
calcPostureChecksDurationMicro metric.Int64Histogram
|
||||
calcPeerNetworkMapDurationMs metric.Int64Histogram
|
||||
mergeNetworkMapDurationMicro metric.Int64Histogram
|
||||
toSyncResponseDurationMicro metric.Int64Histogram
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
@@ -89,6 +93,38 @@ func NewUpdateChannelMetrics(ctx context.Context, meter metric.Meter) (*UpdateCh
|
||||
return nil, err
|
||||
}
|
||||
|
||||
calcPostureChecksDurationMicro, err := meter.Int64Histogram("management.updatechannel.calc.posturechecks.duration.micro",
|
||||
metric.WithUnit("microseconds"),
|
||||
metric.WithDescription("Duration of how long it takes to get the posture checks for a peer"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
calcPeerNetworkMapDurationMs, err := meter.Int64Histogram("management.updatechannel.calc.networkmap.duration.ms",
|
||||
metric.WithUnit("milliseconds"),
|
||||
metric.WithDescription("Duration of how long it takes to calculate the network map for a peer"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergeNetworkMapDurationMicro, err := meter.Int64Histogram("management.updatechannel.merge.networkmap.duration.micro",
|
||||
metric.WithUnit("microseconds"),
|
||||
metric.WithDescription("Duration of how long it takes to merge the network maps for a peer"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toSyncResponseDurationMicro, err := meter.Int64Histogram("management.updatechannel.tosyncresponse.duration.micro",
|
||||
metric.WithUnit("microseconds"),
|
||||
metric.WithDescription("Duration of how long it takes to convert the network map to sync response"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &UpdateChannelMetrics{
|
||||
createChannelDurationMicro: createChannelDurationMicro,
|
||||
closeChannelDurationMicro: closeChannelDurationMicro,
|
||||
@@ -98,6 +134,10 @@ func NewUpdateChannelMetrics(ctx context.Context, meter metric.Meter) (*UpdateCh
|
||||
getAllConnectedPeersDurationMicro: getAllConnectedPeersDurationMicro,
|
||||
getAllConnectedPeers: getAllConnectedPeers,
|
||||
hasChannelDurationMicro: hasChannelDurationMicro,
|
||||
calcPostureChecksDurationMicro: calcPostureChecksDurationMicro,
|
||||
calcPeerNetworkMapDurationMs: calcPeerNetworkMapDurationMs,
|
||||
mergeNetworkMapDurationMicro: mergeNetworkMapDurationMicro,
|
||||
toSyncResponseDurationMicro: toSyncResponseDurationMicro,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
@@ -137,3 +177,19 @@ func (metrics *UpdateChannelMetrics) CountGetAllConnectedPeersDuration(duration
|
||||
func (metrics *UpdateChannelMetrics) CountHasChannelDuration(duration time.Duration) {
|
||||
metrics.hasChannelDurationMicro.Record(metrics.ctx, duration.Microseconds())
|
||||
}
|
||||
|
||||
func (metrics *UpdateChannelMetrics) CountCalcPostureChecksDuration(duration time.Duration) {
|
||||
metrics.calcPostureChecksDurationMicro.Record(metrics.ctx, duration.Microseconds())
|
||||
}
|
||||
|
||||
func (metrics *UpdateChannelMetrics) CountCalcPeerNetworkMapDuration(duration time.Duration) {
|
||||
metrics.calcPeerNetworkMapDurationMs.Record(metrics.ctx, duration.Milliseconds())
|
||||
}
|
||||
|
||||
func (metrics *UpdateChannelMetrics) CountMergeNetworkMapDuration(duration time.Duration) {
|
||||
metrics.mergeNetworkMapDurationMicro.Record(metrics.ctx, duration.Microseconds())
|
||||
}
|
||||
|
||||
func (metrics *UpdateChannelMetrics) CountToSyncResponseDuration(duration time.Duration) {
|
||||
metrics.toSyncResponseDurationMicro.Record(metrics.ctx, duration.Microseconds())
|
||||
}
|
||||
|
||||
@@ -1546,7 +1546,7 @@ func getPoliciesSourcePeers(policies []*Policy, groups map[string]*Group) map[st
|
||||
}
|
||||
|
||||
// AddAllGroup to account object if it doesn't exist
|
||||
func (a *Account) AddAllGroup() error {
|
||||
func (a *Account) AddAllGroup(disableDefaultPolicy bool) error {
|
||||
if len(a.Groups) == 0 {
|
||||
allGroup := &Group{
|
||||
ID: xid.New().String(),
|
||||
@@ -1558,6 +1558,10 @@ func (a *Account) AddAllGroup() error {
|
||||
}
|
||||
a.Groups = map[string]*Group{allGroup.ID: allGroup}
|
||||
|
||||
if disableDefaultPolicy {
|
||||
return nil
|
||||
}
|
||||
|
||||
id := xid.New().String()
|
||||
|
||||
defaultPolicy := &Policy{
|
||||
|
||||
@@ -53,6 +53,9 @@ type Config struct {
|
||||
StoreConfig StoreConfig
|
||||
|
||||
ReverseProxy ReverseProxy
|
||||
|
||||
// disable default all-to-all policy
|
||||
DisableDefaultPolicy bool
|
||||
}
|
||||
|
||||
// GetAuthAudiences returns the audience from the http config and device authorization flow config
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestUser_CreatePAT_ForSameUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = s.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -103,7 +103,7 @@ func TestUser_CreatePAT_ForDifferentUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockTargetUserId] = &types.User{
|
||||
Id: mockTargetUserId,
|
||||
IsServiceUser: false,
|
||||
@@ -131,7 +131,7 @@ func TestUser_CreatePAT_ForServiceUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockTargetUserId] = &types.User{
|
||||
Id: mockTargetUserId,
|
||||
IsServiceUser: true,
|
||||
@@ -163,7 +163,7 @@ func TestUser_CreatePAT_WithWrongExpiration(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -188,7 +188,7 @@ func TestUser_CreatePAT_WithEmptyName(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -213,7 +213,7 @@ func TestUser_DeletePAT(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockUserID] = &types.User{
|
||||
Id: mockUserID,
|
||||
PATs: map[string]*types.PersonalAccessToken{
|
||||
@@ -256,7 +256,7 @@ func TestUser_GetPAT(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockUserID] = &types.User{
|
||||
Id: mockUserID,
|
||||
AccountID: mockAccountID,
|
||||
@@ -296,7 +296,7 @@ func TestUser_GetAllPATs(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockUserID] = &types.User{
|
||||
Id: mockUserID,
|
||||
AccountID: mockAccountID,
|
||||
@@ -406,7 +406,7 @@ func TestUser_CreateServiceUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -453,7 +453,7 @@ func TestUser_CreateUser_ServiceUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -501,7 +501,7 @@ func TestUser_CreateUser_RegularUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -532,7 +532,7 @@ func TestUser_InviteNewUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -639,7 +639,7 @@ func TestUser_DeleteUser_ServiceUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockServiceUserID] = tt.serviceUser
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
@@ -678,7 +678,7 @@ func TestUser_DeleteUser_SelfDelete(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -705,7 +705,7 @@ func TestUser_DeleteUser_regularUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
targetId := "user2"
|
||||
account.Users[targetId] = &types.User{
|
||||
@@ -792,7 +792,7 @@ func TestUser_DeleteUser_RegularUsers(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
targetId := "user2"
|
||||
account.Users[targetId] = &types.User{
|
||||
@@ -952,7 +952,7 @@ func TestDefaultAccountManager_GetUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
|
||||
err = store.SaveAccount(context.Background(), account)
|
||||
if err != nil {
|
||||
@@ -988,7 +988,7 @@ func TestDefaultAccountManager_ListUsers(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users["normal_user1"] = types.NewRegularUser("normal_user1")
|
||||
account.Users["normal_user2"] = types.NewRegularUser("normal_user2")
|
||||
|
||||
@@ -1030,7 +1030,7 @@ func TestDefaultAccountManager_ExternalCache(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
externalUser := &types.User{
|
||||
Id: "externalUser",
|
||||
Role: types.UserRoleUser,
|
||||
@@ -1098,7 +1098,7 @@ func TestUser_GetUsersFromAccount_ForAdmin(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockServiceUserID] = &types.User{
|
||||
Id: mockServiceUserID,
|
||||
Role: "user",
|
||||
@@ -1132,7 +1132,7 @@ func TestUser_GetUsersFromAccount_ForUser(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "")
|
||||
account := newAccountWithId(context.Background(), mockAccountID, mockUserID, "", false)
|
||||
account.Users[mockServiceUserID] = &types.User{
|
||||
Id: mockServiceUserID,
|
||||
Role: "user",
|
||||
@@ -1499,7 +1499,7 @@ func TestSaveOrAddUser_PreventAccountSwitch(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account1 := newAccountWithId(context.Background(), "account1", "ownerAccount1", "")
|
||||
account1 := newAccountWithId(context.Background(), "account1", "ownerAccount1", "", false)
|
||||
targetId := "user2"
|
||||
account1.Users[targetId] = &types.User{
|
||||
Id: targetId,
|
||||
@@ -1508,7 +1508,7 @@ func TestSaveOrAddUser_PreventAccountSwitch(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, s.SaveAccount(context.Background(), account1))
|
||||
|
||||
account2 := newAccountWithId(context.Background(), "account2", "ownerAccount2", "")
|
||||
account2 := newAccountWithId(context.Background(), "account2", "ownerAccount2", "", false)
|
||||
require.NoError(t, s.SaveAccount(context.Background(), account2))
|
||||
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
@@ -1535,7 +1535,7 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
account1 := newAccountWithId(context.Background(), "account1", "account1Owner", "")
|
||||
account1 := newAccountWithId(context.Background(), "account1", "account1Owner", "", false)
|
||||
account1.Settings.RegularUsersViewBlocked = false
|
||||
account1.Users["blocked-user"] = &types.User{
|
||||
Id: "blocked-user",
|
||||
@@ -1557,7 +1557,7 @@ func TestDefaultAccountManager_GetCurrentUserInfo(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, store.SaveAccount(context.Background(), account1))
|
||||
|
||||
account2 := newAccountWithId(context.Background(), "account2", "account2Owner", "")
|
||||
account2 := newAccountWithId(context.Background(), "account2", "account2Owner", "", false)
|
||||
account2.Users["settings-blocked-user"] = &types.User{
|
||||
Id: "settings-blocked-user",
|
||||
Role: types.UserRoleUser,
|
||||
|
||||
@@ -130,7 +130,7 @@ repo_gpgcheck=1
|
||||
EOF
|
||||
}
|
||||
|
||||
add_aur_repo() {
|
||||
install_aur_package() {
|
||||
INSTALL_PKGS="git base-devel go"
|
||||
REMOVE_PKGS=""
|
||||
|
||||
@@ -154,8 +154,10 @@ add_aur_repo() {
|
||||
cd netbird-ui && makepkg -sri --noconfirm
|
||||
fi
|
||||
|
||||
# Clean up the installed packages
|
||||
${SUDO} pacman -Rs "$REMOVE_PKGS" --noconfirm
|
||||
if [ -n "$REMOVE_PKGS" ]; then
|
||||
# Clean up the installed packages
|
||||
${SUDO} pacman -Rs "$REMOVE_PKGS" --noconfirm
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_tun_module() {
|
||||
@@ -277,7 +279,9 @@ install_netbird() {
|
||||
;;
|
||||
pacman)
|
||||
${SUDO} pacman -Syy
|
||||
add_aur_repo
|
||||
install_aur_package
|
||||
# in-line with the docs at https://wiki.archlinux.org/title/Netbird
|
||||
${SUDO} systemctl enable --now netbird@main.service
|
||||
;;
|
||||
pkg)
|
||||
# Check if the package is already installed
|
||||
@@ -494,4 +498,4 @@ case "$UPDATE_FLAG" in
|
||||
;;
|
||||
*)
|
||||
install_netbird
|
||||
esac
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user