mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-19 00:36:38 +00:00
Compare commits
5 Commits
dependabot
...
handle-exi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b86463e96 | ||
|
|
9deff6f06b | ||
|
|
1a1e94c805 | ||
|
|
ed939bf7f5 | ||
|
|
7caf733217 |
49
.github/workflows/docs-ack.yml
vendored
49
.github/workflows/docs-ack.yml
vendored
@@ -16,29 +16,19 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Read PR body
|
- name: Read PR body
|
||||||
id: body
|
id: body
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
BODY=$(jq -r '.pull_request.body // ""' "$GITHUB_EVENT_PATH")
|
||||||
BODY_B64=$(jq -r '.pull_request.body // "" | @base64' "$GITHUB_EVENT_PATH")
|
echo "body<<EOF" >> $GITHUB_OUTPUT
|
||||||
{
|
echo "$BODY" >> $GITHUB_OUTPUT
|
||||||
echo "body_b64=$BODY_B64"
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Validate checkbox selection
|
- name: Validate checkbox selection
|
||||||
id: validate
|
id: validate
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BODY_B64: ${{ steps.body.outputs.body_b64 }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
body='${{ steps.body.outputs.body }}'
|
||||||
if ! body="$(printf '%s' "$BODY_B64" | base64 -d)"; then
|
|
||||||
echo "::error::Failed to decode PR body from base64. Data may be corrupted or missing."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
added_checked=$(printf '%s' "$body" | grep -Ei '^[[:space:]]*-\s*\[x\]\s*I added/updated documentation' | wc -l | tr -d '[:space:]' || true)
|
|
||||||
noneed_checked=$(printf '%s' "$body" | grep -Ei '^[[:space:]]*-\s*\[x\]\s*Documentation is \*\*not needed\*\*' | wc -l | tr -d '[:space:]' || true)
|
|
||||||
|
|
||||||
|
added_checked=$(printf "%s" "$body" | grep -E '^- \[x\] I added/updated documentation' -i | wc -l | tr -d ' ')
|
||||||
|
noneed_checked=$(printf "%s" "$body" | grep -E '^- \[x\] Documentation is \*\*not needed\*\*' -i | wc -l | tr -d ' ')
|
||||||
|
|
||||||
if [ "$added_checked" -eq 1 ] && [ "$noneed_checked" -eq 1 ]; then
|
if [ "$added_checked" -eq 1 ] && [ "$noneed_checked" -eq 1 ]; then
|
||||||
echo "::error::Choose exactly one: either 'docs added' OR 'not needed'."
|
echo "::error::Choose exactly one: either 'docs added' OR 'not needed'."
|
||||||
@@ -51,35 +41,30 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$added_checked" -eq 1 ]; then
|
if [ "$added_checked" -eq 1 ]; then
|
||||||
echo "mode=added" >> "$GITHUB_OUTPUT"
|
echo "mode=added" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "mode=noneed" >> "$GITHUB_OUTPUT"
|
echo "mode=noneed" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Extract docs PR URL (when 'docs added')
|
- name: Extract docs PR URL (when 'docs added')
|
||||||
if: steps.validate.outputs.mode == 'added'
|
if: steps.validate.outputs.mode == 'added'
|
||||||
id: extract
|
id: extract
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
BODY_B64: ${{ steps.body.outputs.body_b64 }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
body='${{ steps.body.outputs.body }}'
|
||||||
body="$(printf '%s' "$BODY_B64" | base64 -d)"
|
|
||||||
|
|
||||||
# Strictly require HTTPS and that it's a PR in netbirdio/docs
|
# Strictly require HTTPS and that it's a PR in netbirdio/docs
|
||||||
# e.g., https://github.com/netbirdio/docs/pull/1234
|
# Examples accepted:
|
||||||
url="$(printf '%s' "$body" | grep -Eo 'https://github\.com/netbirdio/docs/pull/[0-9]+' | head -n1 || true)"
|
# https://github.com/netbirdio/docs/pull/1234
|
||||||
|
url=$(printf "%s" "$body" | grep -Eo 'https://github\.com/netbirdio/docs/pull/[0-9]+' | head -n1 || true)
|
||||||
|
|
||||||
if [ -z "${url:-}" ]; then
|
if [ -z "$url" ]; then
|
||||||
echo "::error::You checked 'docs added' but didn't include a valid HTTPS PR link to netbirdio/docs (e.g., https://github.com/netbirdio/docs/pull/1234)."
|
echo "::error::You checked 'docs added' but didn't include a valid HTTPS PR link to netbirdio/docs (e.g., https://github.com/netbirdio/docs/pull/1234)."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pr_number="$(printf '%s' "$url" | sed -E 's#.*/pull/([0-9]+)$#\1#')"
|
pr_number=$(echo "$url" | sed -E 's#.*/pull/([0-9]+)$#\1#')
|
||||||
{
|
echo "url=$url" >> $GITHUB_OUTPUT
|
||||||
echo "url=$url"
|
echo "pr_number=$pr_number" >> $GITHUB_OUTPUT
|
||||||
echo "pr_number=$pr_number"
|
|
||||||
} >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Verify docs PR exists (and is open or merged)
|
- name: Verify docs PR exists (and is open or merged)
|
||||||
if: steps.validate.outputs.mode == 'added'
|
if: steps.validate.outputs.mode == 'added'
|
||||||
|
|||||||
3
.github/workflows/golang-test-freebsd.yml
vendored
3
.github/workflows/golang-test-freebsd.yml
vendored
@@ -25,7 +25,8 @@ jobs:
|
|||||||
release: "14.2"
|
release: "14.2"
|
||||||
prepare: |
|
prepare: |
|
||||||
pkg install -y curl pkgconf xorg
|
pkg install -y curl pkgconf xorg
|
||||||
GO_TARBALL="go1.23.12.freebsd-amd64.tar.gz"
|
LATEST_VERSION=$(curl -s https://go.dev/VERSION?m=text|head -n 1)
|
||||||
|
GO_TARBALL="$LATEST_VERSION.freebsd-amd64.tar.gz"
|
||||||
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
GO_URL="https://go.dev/dl/$GO_TARBALL"
|
||||||
curl -vLO "$GO_URL"
|
curl -vLO "$GO_URL"
|
||||||
tar -C /usr/local -vxzf "$GO_TARBALL"
|
tar -C /usr/local -vxzf "$GO_TARBALL"
|
||||||
|
|||||||
@@ -83,15 +83,6 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup MySQL privileges
|
|
||||||
if: matrix.store == 'mysql'
|
|
||||||
run: |
|
|
||||||
sleep 10
|
|
||||||
mysql -h 127.0.0.1 -u root -pmysqlroot -e "
|
|
||||||
GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO 'netbird'@'%';
|
|
||||||
FLUSH PRIVILEGES;
|
|
||||||
"
|
|
||||||
|
|
||||||
- name: cp setup.env
|
- name: cp setup.env
|
||||||
run: cp infrastructure_files/tests/setup.env infrastructure_files/
|
run: cp infrastructure_files/tests/setup.env infrastructure_files/
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ var (
|
|||||||
var debugCmd = &cobra.Command{
|
var debugCmd = &cobra.Command{
|
||||||
Use: "debug",
|
Use: "debug",
|
||||||
Short: "Debugging commands",
|
Short: "Debugging commands",
|
||||||
Long: "Commands for debugging and logging within the NetBird daemon.",
|
Long: "Provides commands for debugging and logging control within the NetBird daemon.",
|
||||||
}
|
}
|
||||||
|
|
||||||
var debugBundleCmd = &cobra.Command{
|
var debugBundleCmd = &cobra.Command{
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ import (
|
|||||||
|
|
||||||
var downCmd = &cobra.Command{
|
var downCmd = &cobra.Command{
|
||||||
Use: "down",
|
Use: "down",
|
||||||
Short: "Disconnect from the NetBird network",
|
Short: "down netbird connections",
|
||||||
Long: "Disconnect the NetBird client from the network and management service. This will terminate all active connections with the remote peers.",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
SetFlagsFromEnvVars(rootCmd)
|
SetFlagsFromEnvVars(rootCmd)
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ func init() {
|
|||||||
|
|
||||||
var loginCmd = &cobra.Command{
|
var loginCmd = &cobra.Command{
|
||||||
Use: "login",
|
Use: "login",
|
||||||
Short: "Log in to the NetBird network",
|
Short: "login to the NetBird Management Service (first run)",
|
||||||
Long: "Log in to the NetBird network using a setup key or SSO",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if err := setEnvAndFlags(cmd); err != nil {
|
if err := setEnvAndFlags(cmd); err != nil {
|
||||||
return fmt.Errorf("set env and flags: %v", err)
|
return fmt.Errorf("set env and flags: %v", err)
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ import (
|
|||||||
var logoutCmd = &cobra.Command{
|
var logoutCmd = &cobra.Command{
|
||||||
Use: "deregister",
|
Use: "deregister",
|
||||||
Aliases: []string{"logout"},
|
Aliases: []string{"logout"},
|
||||||
Short: "Deregister from the NetBird management service and delete this peer",
|
Short: "deregister from the NetBird Management Service and delete peer",
|
||||||
Long: "This command will deregister the current peer from the NetBird management service and all associated configuration. Use with caution as this will remove the peer from the network.",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
SetFlagsFromEnvVars(rootCmd)
|
SetFlagsFromEnvVars(rootCmd)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ var appendFlag bool
|
|||||||
var networksCMD = &cobra.Command{
|
var networksCMD = &cobra.Command{
|
||||||
Use: "networks",
|
Use: "networks",
|
||||||
Aliases: []string{"routes"},
|
Aliases: []string{"routes"},
|
||||||
Short: "Manage connections to NetBird Networks and Resources",
|
Short: "Manage networks",
|
||||||
Long: `Commands to list, select, or deselect networks. Replaces the "routes" command.`,
|
Long: `Commands to list, select, or deselect networks. Replaces the "routes" command.`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import (
|
|||||||
|
|
||||||
var profileCmd = &cobra.Command{
|
var profileCmd = &cobra.Command{
|
||||||
Use: "profile",
|
Use: "profile",
|
||||||
Short: "Manage NetBird client profiles",
|
Short: "manage NetBird profiles",
|
||||||
Long: `Commands to list, add, remove, and switch profiles. Profiles allow you to maintain different accounts in one client app.`,
|
Long: `Manage NetBird profiles, allowing you to list, switch, and remove profiles.`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var profileListCmd = &cobra.Command{
|
var profileListCmd = &cobra.Command{
|
||||||
Use: "list",
|
Use: "list",
|
||||||
Short: "List all profiles",
|
Short: "list all profiles",
|
||||||
Long: `List all available profiles in the NetBird client.`,
|
Long: `List all available profiles in the NetBird client.`,
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
RunE: listProfilesFunc,
|
RunE: listProfilesFunc,
|
||||||
@@ -30,7 +30,7 @@ var profileListCmd = &cobra.Command{
|
|||||||
|
|
||||||
var profileAddCmd = &cobra.Command{
|
var profileAddCmd = &cobra.Command{
|
||||||
Use: "add <profile_name>",
|
Use: "add <profile_name>",
|
||||||
Short: "Add a new profile",
|
Short: "add a new profile",
|
||||||
Long: `Add a new profile to the NetBird client. The profile name must be unique.`,
|
Long: `Add a new profile to the NetBird client. The profile name must be unique.`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: addProfileFunc,
|
RunE: addProfileFunc,
|
||||||
@@ -38,16 +38,16 @@ var profileAddCmd = &cobra.Command{
|
|||||||
|
|
||||||
var profileRemoveCmd = &cobra.Command{
|
var profileRemoveCmd = &cobra.Command{
|
||||||
Use: "remove <profile_name>",
|
Use: "remove <profile_name>",
|
||||||
Short: "Remove a profile",
|
Short: "remove a profile",
|
||||||
Long: `Remove a profile from the NetBird client. The profile must not be inactive.`,
|
Long: `Remove a profile from the NetBird client. The profile must not be active.`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: removeProfileFunc,
|
RunE: removeProfileFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
var profileSelectCmd = &cobra.Command{
|
var profileSelectCmd = &cobra.Command{
|
||||||
Use: "select <profile_name>",
|
Use: "select <profile_name>",
|
||||||
Short: "Select a profile",
|
Short: "select a profile",
|
||||||
Long: `Make the specified profile active. This will switch the client to use the selected profile's configuration.`,
|
Long: `Select a profile to be the active profile in the NetBird client. The profile must exist.`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: selectProfileFunc,
|
RunE: selectProfileFunc,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ const (
|
|||||||
extraIFaceBlackListFlag = "extra-iface-blacklist"
|
extraIFaceBlackListFlag = "extra-iface-blacklist"
|
||||||
dnsRouteIntervalFlag = "dns-router-interval"
|
dnsRouteIntervalFlag = "dns-router-interval"
|
||||||
enableLazyConnectionFlag = "enable-lazy-connection"
|
enableLazyConnectionFlag = "enable-lazy-connection"
|
||||||
mtuFlag = "mtu"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -73,9 +72,7 @@ var (
|
|||||||
anonymizeFlag bool
|
anonymizeFlag bool
|
||||||
dnsRouteInterval time.Duration
|
dnsRouteInterval time.Duration
|
||||||
lazyConnEnabled bool
|
lazyConnEnabled bool
|
||||||
mtu uint16
|
|
||||||
profilesDisabled bool
|
profilesDisabled bool
|
||||||
updateSettingsDisabled bool
|
|
||||||
|
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "netbird",
|
Use: "netbird",
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ func TestSetFlagsFromEnvVars(t *testing.T) {
|
|||||||
cmd.PersistentFlags().StringVar(&interfaceName, interfaceNameFlag, iface.WgInterfaceDefault, "WireGuard interface name")
|
cmd.PersistentFlags().StringVar(&interfaceName, interfaceNameFlag, iface.WgInterfaceDefault, "WireGuard interface name")
|
||||||
cmd.PersistentFlags().BoolVar(&rosenpassEnabled, enableRosenpassFlag, false, "Enable Rosenpass feature Rosenpass.")
|
cmd.PersistentFlags().BoolVar(&rosenpassEnabled, enableRosenpassFlag, false, "Enable Rosenpass feature Rosenpass.")
|
||||||
cmd.PersistentFlags().Uint16Var(&wireguardPort, wireguardPortFlag, iface.DefaultWgPort, "WireGuard interface listening port")
|
cmd.PersistentFlags().Uint16Var(&wireguardPort, wireguardPortFlag, iface.DefaultWgPort, "WireGuard interface listening port")
|
||||||
cmd.PersistentFlags().Uint16Var(&mtu, mtuFlag, iface.DefaultMTU, "Set MTU (Maximum Transmission Unit) for the WireGuard interface")
|
|
||||||
|
|
||||||
t.Setenv("NB_EXTERNAL_IP_MAP", "abc,dec")
|
t.Setenv("NB_EXTERNAL_IP_MAP", "abc,dec")
|
||||||
t.Setenv("NB_INTERFACE_NAME", "test-name")
|
t.Setenv("NB_INTERFACE_NAME", "test-name")
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
var serviceCmd = &cobra.Command{
|
var serviceCmd = &cobra.Command{
|
||||||
Use: "service",
|
Use: "service",
|
||||||
Short: "Manage the NetBird daemon service",
|
Short: "manages NetBird service",
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -42,8 +42,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd, svcStatusCmd, installCmd, uninstallCmd, reconfigureCmd)
|
serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd, svcStatusCmd, installCmd, uninstallCmd, reconfigureCmd)
|
||||||
serviceCmd.PersistentFlags().BoolVar(&profilesDisabled, "disable-profiles", false, "Disables profiles feature. If enabled, the client will not be able to change or edit any profile. To persist this setting, use: netbird service install --disable-profiles")
|
serviceCmd.PersistentFlags().BoolVar(&profilesDisabled, "disable-profiles", false, "Disables profiles feature. If enabled, the client will not be able to change or edit any profile.")
|
||||||
serviceCmd.PersistentFlags().BoolVar(&updateSettingsDisabled, "disable-update-settings", false, "Disables update settings feature. If enabled, the client will not be able to change or edit any settings. To persist this setting, use: netbird service install --disable-update-settings")
|
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVarP(&serviceName, "service", "s", defaultServiceName, "Netbird system service name")
|
rootCmd.PersistentFlags().StringVarP(&serviceName, "service", "s", defaultServiceName, "Netbird system service name")
|
||||||
serviceEnvDesc := `Sets extra environment variables for the service. ` +
|
serviceEnvDesc := `Sets extra environment variables for the service. ` +
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func (p *program) Start(svc service.Service) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstance := server.New(p.ctx, util.FindFirstLogPath(logFiles), configPath, profilesDisabled, updateSettingsDisabled)
|
serverInstance := server.New(p.ctx, util.FindFirstLogPath(logFiles), configPath, profilesDisabled)
|
||||||
if err := serverInstance.Start(); err != nil {
|
if err := serverInstance.Start(); err != nil {
|
||||||
log.Fatalf("failed to start daemon: %v", err)
|
log.Fatalf("failed to start daemon: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,14 +49,6 @@ func buildServiceArguments() []string {
|
|||||||
args = append(args, "--log-file", logFile)
|
args = append(args, "--log-file", logFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if profilesDisabled {
|
|
||||||
args = append(args, "--disable-profiles")
|
|
||||||
}
|
|
||||||
|
|
||||||
if updateSettingsDisabled {
|
|
||||||
args = append(args, "--disable-update-settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +99,7 @@ func createServiceConfigForInstall() (*service.Config, error) {
|
|||||||
|
|
||||||
var installCmd = &cobra.Command{
|
var installCmd = &cobra.Command{
|
||||||
Use: "install",
|
Use: "install",
|
||||||
Short: "Install NetBird service",
|
Short: "installs NetBird service",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if err := setupServiceCommand(cmd); err != nil {
|
if err := setupServiceCommand(cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ var sshCmd = &cobra.Command{
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Short: "Connect to a remote SSH server",
|
Short: "connect to a remote SSH server",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
SetFlagsFromEnvVars(rootCmd)
|
SetFlagsFromEnvVars(rootCmd)
|
||||||
SetFlagsFromEnvVars(cmd)
|
SetFlagsFromEnvVars(cmd)
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ var (
|
|||||||
|
|
||||||
var statusCmd = &cobra.Command{
|
var statusCmd = &cobra.Command{
|
||||||
Use: "status",
|
Use: "status",
|
||||||
Short: "Display NetBird client status",
|
Short: "status of the Netbird Service",
|
||||||
Long: "Display the current status of the NetBird client, including connection status, peer information, and network details.",
|
|
||||||
RunE: statusFunc,
|
RunE: statusFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/server/config"
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/groups"
|
|
||||||
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"github.com/netbirdio/netbird/management/server/permissions"
|
||||||
"github.com/netbirdio/netbird/management/server/settings"
|
"github.com/netbirdio/netbird/management/server/settings"
|
||||||
@@ -28,15 +26,15 @@ import (
|
|||||||
|
|
||||||
clientProto "github.com/netbirdio/netbird/client/proto"
|
clientProto "github.com/netbirdio/netbird/client/proto"
|
||||||
client "github.com/netbirdio/netbird/client/server"
|
client "github.com/netbirdio/netbird/client/server"
|
||||||
mgmt "github.com/netbirdio/netbird/management/server"
|
|
||||||
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
||||||
|
mgmt "github.com/netbirdio/netbird/management/server"
|
||||||
sigProto "github.com/netbirdio/netbird/shared/signal/proto"
|
sigProto "github.com/netbirdio/netbird/shared/signal/proto"
|
||||||
sig "github.com/netbirdio/netbird/signal/server"
|
sig "github.com/netbirdio/netbird/signal/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
func startTestingServices(t *testing.T) string {
|
func startTestingServices(t *testing.T) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
config := &config.Config{}
|
config := &types.Config{}
|
||||||
_, err := util.ReadJson("../testdata/management.json", config)
|
_, err := util.ReadJson("../testdata/management.json", config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -71,7 +69,7 @@ func startSignal(t *testing.T) (*grpc.Server, net.Listener) {
|
|||||||
return s, lis
|
return s, lis
|
||||||
}
|
}
|
||||||
|
|
||||||
func startManagement(t *testing.T, config *config.Config, testFile string) (*grpc.Server, net.Listener) {
|
func startManagement(t *testing.T, config *types.Config, testFile string) (*grpc.Server, net.Listener) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", ":0")
|
lis, err := net.Listen("tcp", ":0")
|
||||||
@@ -99,7 +97,6 @@ func startManagement(t *testing.T, config *config.Config, testFile string) (*grp
|
|||||||
|
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||||
groupsManager := groups.NewManagerMock()
|
|
||||||
|
|
||||||
settingsMockManager.EXPECT().
|
settingsMockManager.EXPECT().
|
||||||
GetSettings(gomock.Any(), gomock.Any(), gomock.Any()).
|
GetSettings(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||||
@@ -111,7 +108,7 @@ func startManagement(t *testing.T, config *config.Config, testFile string) (*grp
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
secretsManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager, groupsManager)
|
secretsManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager)
|
||||||
mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, &mgmt.MockIntegratedValidator{})
|
mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, &mgmt.MockIntegratedValidator{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -137,7 +134,7 @@ func startClientDaemon(
|
|||||||
s := grpc.NewServer()
|
s := grpc.NewServer()
|
||||||
|
|
||||||
server := client.New(ctx,
|
server := client.New(ctx,
|
||||||
"", "", false, false)
|
"", "", false)
|
||||||
if err := server.Start(); err != nil {
|
if err := server.Start(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ var (
|
|||||||
|
|
||||||
upCmd = &cobra.Command{
|
upCmd = &cobra.Command{
|
||||||
Use: "up",
|
Use: "up",
|
||||||
Short: "Connect to the NetBird network",
|
Short: "install, login and start NetBird client",
|
||||||
Long: "Connect to the NetBird network using the provided setup key or SSO auth. This command will bring up the WireGuard interface, connect to the management server, and establish peer-to-peer connections with other peers in the network if required.",
|
|
||||||
RunE: upFunc,
|
RunE: upFunc,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -63,7 +62,6 @@ func init() {
|
|||||||
upCmd.PersistentFlags().BoolVarP(&foregroundMode, "foreground-mode", "F", false, "start service in foreground")
|
upCmd.PersistentFlags().BoolVarP(&foregroundMode, "foreground-mode", "F", false, "start service in foreground")
|
||||||
upCmd.PersistentFlags().StringVar(&interfaceName, interfaceNameFlag, iface.WgInterfaceDefault, "WireGuard interface name")
|
upCmd.PersistentFlags().StringVar(&interfaceName, interfaceNameFlag, iface.WgInterfaceDefault, "WireGuard interface name")
|
||||||
upCmd.PersistentFlags().Uint16Var(&wireguardPort, wireguardPortFlag, iface.DefaultWgPort, "WireGuard interface listening port")
|
upCmd.PersistentFlags().Uint16Var(&wireguardPort, wireguardPortFlag, iface.DefaultWgPort, "WireGuard interface listening port")
|
||||||
upCmd.PersistentFlags().Uint16Var(&mtu, mtuFlag, iface.DefaultMTU, "Set MTU (Maximum Transmission Unit) for the WireGuard interface")
|
|
||||||
upCmd.PersistentFlags().BoolVarP(&networkMonitor, networkMonitorFlag, "N", networkMonitor,
|
upCmd.PersistentFlags().BoolVarP(&networkMonitor, networkMonitorFlag, "N", networkMonitor,
|
||||||
`Manage network monitoring. Defaults to true on Windows and macOS, false on Linux and FreeBSD. `+
|
`Manage network monitoring. Defaults to true on Windows and macOS, false on Linux and FreeBSD. `+
|
||||||
`E.g. --network-monitor=false to disable or --network-monitor=true to enable.`,
|
`E.g. --network-monitor=false to disable or --network-monitor=true to enable.`,
|
||||||
@@ -358,11 +356,6 @@ func setupSetConfigReq(customDNSAddressConverted []byte, cmd *cobra.Command, pro
|
|||||||
req.WireguardPort = &p
|
req.WireguardPort = &p
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Flag(mtuFlag).Changed {
|
|
||||||
m := int64(mtu)
|
|
||||||
req.Mtu = &m
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.Flag(networkMonitorFlag).Changed {
|
if cmd.Flag(networkMonitorFlag).Changed {
|
||||||
req.NetworkMonitor = &networkMonitor
|
req.NetworkMonitor = &networkMonitor
|
||||||
}
|
}
|
||||||
@@ -442,13 +435,6 @@ func setupConfig(customDNSAddressConverted []byte, cmd *cobra.Command, configFil
|
|||||||
ic.WireguardPort = &p
|
ic.WireguardPort = &p
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Flag(mtuFlag).Changed {
|
|
||||||
if err := iface.ValidateMTU(mtu); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ic.MTU = &mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.Flag(networkMonitorFlag).Changed {
|
if cmd.Flag(networkMonitorFlag).Changed {
|
||||||
ic.NetworkMonitor = &networkMonitor
|
ic.NetworkMonitor = &networkMonitor
|
||||||
}
|
}
|
||||||
@@ -546,14 +532,6 @@ func setupLoginRequest(providedSetupKey string, customDNSAddressConverted []byte
|
|||||||
loginRequest.WireguardPort = &wp
|
loginRequest.WireguardPort = &wp
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Flag(mtuFlag).Changed {
|
|
||||||
if err := iface.ValidateMTU(mtu); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m := int64(mtu)
|
|
||||||
loginRequest.Mtu = &m
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.Flag(networkMonitorFlag).Changed {
|
if cmd.Flag(networkMonitorFlag).Changed {
|
||||||
loginRequest.NetworkMonitor = &networkMonitor
|
loginRequest.NetworkMonitor = &networkMonitor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
versionCmd = &cobra.Command{
|
versionCmd = &cobra.Command{
|
||||||
Use: "version",
|
Use: "version",
|
||||||
Short: "Print the NetBird's client application version",
|
Short: "prints NetBird version",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd.SetOut(cmd.OutOrStdout())
|
cmd.SetOut(cmd.OutOrStdout())
|
||||||
cmd.Println(version.NetbirdVersion())
|
cmd.Println(version.NetbirdVersion())
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func (m *aclManager) AddPeerFiltering(
|
|||||||
) ([]firewall.Rule, error) {
|
) ([]firewall.Rule, error) {
|
||||||
chain := chainNameInputRules
|
chain := chainNameInputRules
|
||||||
|
|
||||||
ipsetName = transformIPsetName(ipsetName, sPort, dPort, action)
|
ipsetName = transformIPsetName(ipsetName, sPort, dPort)
|
||||||
specs := filterRuleSpecs(ip, string(protocol), sPort, dPort, action, ipsetName)
|
specs := filterRuleSpecs(ip, string(protocol), sPort, dPort, action, ipsetName)
|
||||||
|
|
||||||
mangleSpecs := slices.Clone(specs)
|
mangleSpecs := slices.Clone(specs)
|
||||||
@@ -135,14 +135,7 @@ func (m *aclManager) AddPeerFiltering(
|
|||||||
return nil, fmt.Errorf("rule already exists")
|
return nil, fmt.Errorf("rule already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert DROP rules at the beginning, append ACCEPT rules at the end
|
if err := m.iptablesClient.Append(tableFilter, chain, specs...); err != nil {
|
||||||
if action == firewall.ActionDrop {
|
|
||||||
// Insert at the beginning of the chain (position 1)
|
|
||||||
err = m.iptablesClient.Insert(tableFilter, chain, 1, specs...)
|
|
||||||
} else {
|
|
||||||
err = m.iptablesClient.Append(tableFilter, chain, specs...)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,25 +388,17 @@ func actionToStr(action firewall.Action) string {
|
|||||||
return "DROP"
|
return "DROP"
|
||||||
}
|
}
|
||||||
|
|
||||||
func transformIPsetName(ipsetName string, sPort, dPort *firewall.Port, action firewall.Action) string {
|
func transformIPsetName(ipsetName string, sPort, dPort *firewall.Port) string {
|
||||||
if ipsetName == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include action in the ipset name to prevent squashing rules with different actions
|
|
||||||
actionSuffix := ""
|
|
||||||
if action == firewall.ActionDrop {
|
|
||||||
actionSuffix = "-drop"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case ipsetName == "":
|
||||||
|
return ""
|
||||||
case sPort != nil && dPort != nil:
|
case sPort != nil && dPort != nil:
|
||||||
return ipsetName + "-sport-dport" + actionSuffix
|
return ipsetName + "-sport-dport"
|
||||||
case sPort != nil:
|
case sPort != nil:
|
||||||
return ipsetName + "-sport" + actionSuffix
|
return ipsetName + "-sport"
|
||||||
case dPort != nil:
|
case dPort != nil:
|
||||||
return ipsetName + "-dport" + actionSuffix
|
return ipsetName + "-dport"
|
||||||
default:
|
default:
|
||||||
return ipsetName + actionSuffix
|
return ipsetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package iptables
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
|
|
||||||
var ifaceMock = &iFaceMock{
|
var ifaceMock = &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "wg-test"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() wgaddr.Address {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return wgaddr.Address{
|
return wgaddr.Address{
|
||||||
@@ -110,84 +109,10 @@ func TestIptablesManager(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIptablesManagerDenyRules(t *testing.T) {
|
|
||||||
ipv4Client, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
manager, err := Create(ifaceMock)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, manager.Init(nil))
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
err := manager.Close(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
t.Run("add deny rule", func(t *testing.T) {
|
|
||||||
ip := netip.MustParseAddr("10.20.0.3")
|
|
||||||
port := &fw.Port{Values: []uint16{22}}
|
|
||||||
|
|
||||||
rule, err := manager.AddPeerFiltering(nil, ip.AsSlice(), "tcp", nil, port, fw.ActionDrop, "deny-ssh")
|
|
||||||
require.NoError(t, err, "failed to add deny rule")
|
|
||||||
require.NotEmpty(t, rule, "deny rule should not be empty")
|
|
||||||
|
|
||||||
// Verify the rule was added by checking iptables
|
|
||||||
for _, r := range rule {
|
|
||||||
rr := r.(*Rule)
|
|
||||||
checkRuleSpecs(t, ipv4Client, rr.chain, true, rr.specs...)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("deny rule precedence test", func(t *testing.T) {
|
|
||||||
ip := netip.MustParseAddr("10.20.0.4")
|
|
||||||
port := &fw.Port{Values: []uint16{80}}
|
|
||||||
|
|
||||||
// Add accept rule first
|
|
||||||
_, err := manager.AddPeerFiltering(nil, ip.AsSlice(), "tcp", nil, port, fw.ActionAccept, "accept-http")
|
|
||||||
require.NoError(t, err, "failed to add accept rule")
|
|
||||||
|
|
||||||
// Add deny rule second for same IP/port - this should take precedence
|
|
||||||
_, err = manager.AddPeerFiltering(nil, ip.AsSlice(), "tcp", nil, port, fw.ActionDrop, "deny-http")
|
|
||||||
require.NoError(t, err, "failed to add deny rule")
|
|
||||||
|
|
||||||
// Inspect the actual iptables rules to verify deny rule comes before accept rule
|
|
||||||
rules, err := ipv4Client.List("filter", chainNameInputRules)
|
|
||||||
require.NoError(t, err, "failed to list iptables rules")
|
|
||||||
|
|
||||||
// Debug: print all rules
|
|
||||||
t.Logf("All iptables rules in chain %s:", chainNameInputRules)
|
|
||||||
for i, rule := range rules {
|
|
||||||
t.Logf(" [%d] %s", i, rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
var denyRuleIndex, acceptRuleIndex int = -1, -1
|
|
||||||
for i, rule := range rules {
|
|
||||||
if strings.Contains(rule, "DROP") {
|
|
||||||
t.Logf("Found DROP rule at index %d: %s", i, rule)
|
|
||||||
if strings.Contains(rule, "deny-http") && strings.Contains(rule, "80") {
|
|
||||||
denyRuleIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.Contains(rule, "ACCEPT") {
|
|
||||||
t.Logf("Found ACCEPT rule at index %d: %s", i, rule)
|
|
||||||
if strings.Contains(rule, "accept-http") && strings.Contains(rule, "80") {
|
|
||||||
acceptRuleIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotEqual(t, -1, denyRuleIndex, "deny rule should exist in iptables")
|
|
||||||
require.NotEqual(t, -1, acceptRuleIndex, "accept rule should exist in iptables")
|
|
||||||
require.Less(t, denyRuleIndex, acceptRuleIndex,
|
|
||||||
"deny rule should come before accept rule in iptables chain (deny at index %d, accept at index %d)",
|
|
||||||
denyRuleIndex, acceptRuleIndex)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIptablesManagerIPSet(t *testing.T) {
|
func TestIptablesManagerIPSet(t *testing.T) {
|
||||||
mock := &iFaceMock{
|
mock := &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "wg-test"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() wgaddr.Address {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return wgaddr.Address{
|
return wgaddr.Address{
|
||||||
@@ -251,7 +176,7 @@ func checkRuleSpecs(t *testing.T, ipv4Client *iptables.IPTables, chainName strin
|
|||||||
func TestIptablesCreatePerformance(t *testing.T) {
|
func TestIptablesCreatePerformance(t *testing.T) {
|
||||||
mock := &iFaceMock{
|
mock := &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "wg-test"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() wgaddr.Address {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return wgaddr.Address{
|
return wgaddr.Address{
|
||||||
|
|||||||
@@ -341,38 +341,30 @@ func (m *AclManager) addIOFiltering(
|
|||||||
userData := []byte(ruleId)
|
userData := []byte(ruleId)
|
||||||
|
|
||||||
chain := m.chainInputRules
|
chain := m.chainInputRules
|
||||||
rule := &nftables.Rule{
|
nftRule := m.rConn.AddRule(&nftables.Rule{
|
||||||
Table: m.workTable,
|
Table: m.workTable,
|
||||||
Chain: chain,
|
Chain: chain,
|
||||||
Exprs: mainExpressions,
|
Exprs: mainExpressions,
|
||||||
UserData: userData,
|
UserData: userData,
|
||||||
}
|
})
|
||||||
|
|
||||||
// Insert DROP rules at the beginning, append ACCEPT rules at the end
|
|
||||||
var nftRule *nftables.Rule
|
|
||||||
if action == firewall.ActionDrop {
|
|
||||||
nftRule = m.rConn.InsertRule(rule)
|
|
||||||
} else {
|
|
||||||
nftRule = m.rConn.AddRule(rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := m.rConn.Flush(); err != nil {
|
if err := m.rConn.Flush(); err != nil {
|
||||||
return nil, fmt.Errorf(flushError, err)
|
return nil, fmt.Errorf(flushError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleStruct := &Rule{
|
rule := &Rule{
|
||||||
nftRule: nftRule,
|
nftRule: nftRule,
|
||||||
mangleRule: m.createPreroutingRule(expressions, userData),
|
mangleRule: m.createPreroutingRule(expressions, userData),
|
||||||
nftSet: ipset,
|
nftSet: ipset,
|
||||||
ruleID: ruleId,
|
ruleID: ruleId,
|
||||||
ip: ip,
|
ip: ip,
|
||||||
}
|
}
|
||||||
m.rules[ruleId] = ruleStruct
|
m.rules[ruleId] = rule
|
||||||
if ipset != nil {
|
if ipset != nil {
|
||||||
m.ipsetStore.AddReferenceToIpset(ipset.Name)
|
m.ipsetStore.AddReferenceToIpset(ipset.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ruleStruct, nil
|
return rule, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AclManager) createPreroutingRule(expressions []expr.Any, userData []byte) *nftables.Rule {
|
func (m *AclManager) createPreroutingRule(expressions []expr.Any, userData []byte) *nftables.Rule {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package nftables
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -21,7 +20,7 @@ import (
|
|||||||
|
|
||||||
var ifaceMock = &iFaceMock{
|
var ifaceMock = &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "wg-test"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() wgaddr.Address {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return wgaddr.Address{
|
return wgaddr.Address{
|
||||||
@@ -104,8 +103,9 @@ func TestNftablesManager(t *testing.T) {
|
|||||||
Kind: expr.VerdictAccept,
|
Kind: expr.VerdictAccept,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Since DROP rules are inserted at position 0, the DROP rule comes first
|
compareExprsIgnoringCounters(t, rules[0].Exprs, expectedExprs1)
|
||||||
expectedDropExprs := []expr.Any{
|
|
||||||
|
expectedExprs2 := []expr.Any{
|
||||||
&expr.Payload{
|
&expr.Payload{
|
||||||
DestRegister: 1,
|
DestRegister: 1,
|
||||||
Base: expr.PayloadBaseNetworkHeader,
|
Base: expr.PayloadBaseNetworkHeader,
|
||||||
@@ -141,12 +141,7 @@ func TestNftablesManager(t *testing.T) {
|
|||||||
},
|
},
|
||||||
&expr.Verdict{Kind: expr.VerdictDrop},
|
&expr.Verdict{Kind: expr.VerdictDrop},
|
||||||
}
|
}
|
||||||
|
require.ElementsMatch(t, rules[1].Exprs, expectedExprs2, "expected the same expressions")
|
||||||
// Compare DROP rule at position 0 (inserted first due to InsertRule)
|
|
||||||
compareExprsIgnoringCounters(t, rules[0].Exprs, expectedDropExprs)
|
|
||||||
|
|
||||||
// Compare connection tracking rule at position 1 (pushed down by DROP rule insertion)
|
|
||||||
compareExprsIgnoringCounters(t, rules[1].Exprs, expectedExprs1)
|
|
||||||
|
|
||||||
for _, r := range rule {
|
for _, r := range rule {
|
||||||
err = manager.DeletePeerRule(r)
|
err = manager.DeletePeerRule(r)
|
||||||
@@ -165,90 +160,10 @@ func TestNftablesManager(t *testing.T) {
|
|||||||
require.NoError(t, err, "failed to reset")
|
require.NoError(t, err, "failed to reset")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNftablesManagerRuleOrder(t *testing.T) {
|
|
||||||
// This test verifies rule insertion order in nftables peer ACLs
|
|
||||||
// We add accept rule first, then deny rule to test ordering behavior
|
|
||||||
manager, err := Create(ifaceMock)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, manager.Init(nil))
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
err = manager.Close(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ip := netip.MustParseAddr("100.96.0.2").Unmap()
|
|
||||||
testClient := &nftables.Conn{}
|
|
||||||
|
|
||||||
// Add accept rule first
|
|
||||||
_, err = manager.AddPeerFiltering(nil, ip.AsSlice(), fw.ProtocolTCP, nil, &fw.Port{Values: []uint16{80}}, fw.ActionAccept, "accept-http")
|
|
||||||
require.NoError(t, err, "failed to add accept rule")
|
|
||||||
|
|
||||||
// Add deny rule second for the same traffic
|
|
||||||
_, err = manager.AddPeerFiltering(nil, ip.AsSlice(), fw.ProtocolTCP, nil, &fw.Port{Values: []uint16{80}}, fw.ActionDrop, "deny-http")
|
|
||||||
require.NoError(t, err, "failed to add deny rule")
|
|
||||||
|
|
||||||
err = manager.Flush()
|
|
||||||
require.NoError(t, err, "failed to flush")
|
|
||||||
|
|
||||||
rules, err := testClient.GetRules(manager.aclManager.workTable, manager.aclManager.chainInputRules)
|
|
||||||
require.NoError(t, err, "failed to get rules")
|
|
||||||
|
|
||||||
t.Logf("Found %d rules in nftables chain", len(rules))
|
|
||||||
|
|
||||||
// Find the accept and deny rules and verify deny comes before accept
|
|
||||||
var acceptRuleIndex, denyRuleIndex int = -1, -1
|
|
||||||
for i, rule := range rules {
|
|
||||||
hasAcceptHTTPSet := false
|
|
||||||
hasDenyHTTPSet := false
|
|
||||||
hasPort80 := false
|
|
||||||
var action string
|
|
||||||
|
|
||||||
for _, e := range rule.Exprs {
|
|
||||||
// Check for set lookup
|
|
||||||
if lookup, ok := e.(*expr.Lookup); ok {
|
|
||||||
if lookup.SetName == "accept-http" {
|
|
||||||
hasAcceptHTTPSet = true
|
|
||||||
} else if lookup.SetName == "deny-http" {
|
|
||||||
hasDenyHTTPSet = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for port 80
|
|
||||||
if cmp, ok := e.(*expr.Cmp); ok {
|
|
||||||
if cmp.Op == expr.CmpOpEq && len(cmp.Data) == 2 && binary.BigEndian.Uint16(cmp.Data) == 80 {
|
|
||||||
hasPort80 = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for verdict
|
|
||||||
if verdict, ok := e.(*expr.Verdict); ok {
|
|
||||||
if verdict.Kind == expr.VerdictAccept {
|
|
||||||
action = "ACCEPT"
|
|
||||||
} else if verdict.Kind == expr.VerdictDrop {
|
|
||||||
action = "DROP"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasAcceptHTTPSet && hasPort80 && action == "ACCEPT" {
|
|
||||||
t.Logf("Rule [%d]: accept-http set + Port 80 + ACCEPT", i)
|
|
||||||
acceptRuleIndex = i
|
|
||||||
} else if hasDenyHTTPSet && hasPort80 && action == "DROP" {
|
|
||||||
t.Logf("Rule [%d]: deny-http set + Port 80 + DROP", i)
|
|
||||||
denyRuleIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotEqual(t, -1, acceptRuleIndex, "accept rule should exist in nftables")
|
|
||||||
require.NotEqual(t, -1, denyRuleIndex, "deny rule should exist in nftables")
|
|
||||||
require.Less(t, denyRuleIndex, acceptRuleIndex,
|
|
||||||
"deny rule should come before accept rule in nftables chain (deny at index %d, accept at index %d)",
|
|
||||||
denyRuleIndex, acceptRuleIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNFtablesCreatePerformance(t *testing.T) {
|
func TestNFtablesCreatePerformance(t *testing.T) {
|
||||||
mock := &iFaceMock{
|
mock := &iFaceMock{
|
||||||
NameFunc: func() string {
|
NameFunc: func() string {
|
||||||
return "wg-test"
|
return "lo"
|
||||||
},
|
},
|
||||||
AddressFunc: func() wgaddr.Address {
|
AddressFunc: func() wgaddr.Address {
|
||||||
return wgaddr.Address{
|
return wgaddr.Address{
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ func (m *Manager) Close(stateManager *statemanager.Manager) error {
|
|||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
m.outgoingRules = make(map[netip.Addr]RuleSet)
|
m.outgoingRules = make(map[netip.Addr]RuleSet)
|
||||||
m.incomingDenyRules = make(map[netip.Addr]RuleSet)
|
|
||||||
m.incomingRules = make(map[netip.Addr]RuleSet)
|
m.incomingRules = make(map[netip.Addr]RuleSet)
|
||||||
|
|
||||||
if m.udpTracker != nil {
|
if m.udpTracker != nil {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ func (m *Manager) Close(*statemanager.Manager) error {
|
|||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
m.outgoingRules = make(map[netip.Addr]RuleSet)
|
m.outgoingRules = make(map[netip.Addr]RuleSet)
|
||||||
m.incomingDenyRules = make(map[netip.Addr]RuleSet)
|
|
||||||
m.incomingRules = make(map[netip.Addr]RuleSet)
|
m.incomingRules = make(map[netip.Addr]RuleSet)
|
||||||
|
|
||||||
if m.udpTracker != nil {
|
if m.udpTracker != nil {
|
||||||
|
|||||||
@@ -70,13 +70,14 @@ func (r RouteRules) Sort() {
|
|||||||
|
|
||||||
// Manager userspace firewall manager
|
// Manager userspace firewall manager
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
outgoingRules map[netip.Addr]RuleSet
|
// outgoingRules is used for hooks only
|
||||||
incomingDenyRules map[netip.Addr]RuleSet
|
outgoingRules map[netip.Addr]RuleSet
|
||||||
incomingRules map[netip.Addr]RuleSet
|
// incomingRules is used for filtering and hooks
|
||||||
routeRules RouteRules
|
incomingRules map[netip.Addr]RuleSet
|
||||||
decoders sync.Pool
|
routeRules RouteRules
|
||||||
wgIface common.IFaceMapper
|
decoders sync.Pool
|
||||||
nativeFirewall firewall.Manager
|
wgIface common.IFaceMapper
|
||||||
|
nativeFirewall firewall.Manager
|
||||||
|
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
|
|
||||||
@@ -185,7 +186,6 @@ func create(iface common.IFaceMapper, nativeFirewall firewall.Manager, disableSe
|
|||||||
},
|
},
|
||||||
nativeFirewall: nativeFirewall,
|
nativeFirewall: nativeFirewall,
|
||||||
outgoingRules: make(map[netip.Addr]RuleSet),
|
outgoingRules: make(map[netip.Addr]RuleSet),
|
||||||
incomingDenyRules: make(map[netip.Addr]RuleSet),
|
|
||||||
incomingRules: make(map[netip.Addr]RuleSet),
|
incomingRules: make(map[netip.Addr]RuleSet),
|
||||||
wgIface: iface,
|
wgIface: iface,
|
||||||
localipmanager: newLocalIPManager(),
|
localipmanager: newLocalIPManager(),
|
||||||
@@ -417,17 +417,10 @@ func (m *Manager) AddPeerFiltering(
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
var targetMap map[netip.Addr]RuleSet
|
if _, ok := m.incomingRules[r.ip]; !ok {
|
||||||
if r.drop {
|
m.incomingRules[r.ip] = make(RuleSet)
|
||||||
targetMap = m.incomingDenyRules
|
|
||||||
} else {
|
|
||||||
targetMap = m.incomingRules
|
|
||||||
}
|
}
|
||||||
|
m.incomingRules[r.ip][r.id] = r
|
||||||
if _, ok := targetMap[r.ip]; !ok {
|
|
||||||
targetMap[r.ip] = make(RuleSet)
|
|
||||||
}
|
|
||||||
targetMap[r.ip][r.id] = r
|
|
||||||
m.mutex.Unlock()
|
m.mutex.Unlock()
|
||||||
return []firewall.Rule{&r}, nil
|
return []firewall.Rule{&r}, nil
|
||||||
}
|
}
|
||||||
@@ -514,24 +507,10 @@ func (m *Manager) DeletePeerRule(rule firewall.Rule) error {
|
|||||||
return fmt.Errorf("delete rule: invalid rule type: %T", rule)
|
return fmt.Errorf("delete rule: invalid rule type: %T", rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sourceMap map[netip.Addr]RuleSet
|
if _, ok := m.incomingRules[r.ip][r.id]; !ok {
|
||||||
if r.drop {
|
|
||||||
sourceMap = m.incomingDenyRules
|
|
||||||
} else {
|
|
||||||
sourceMap = m.incomingRules
|
|
||||||
}
|
|
||||||
|
|
||||||
if ruleset, ok := sourceMap[r.ip]; ok {
|
|
||||||
if _, exists := ruleset[r.id]; !exists {
|
|
||||||
return fmt.Errorf("delete rule: no rule with such id: %v", r.id)
|
|
||||||
}
|
|
||||||
delete(ruleset, r.id)
|
|
||||||
if len(ruleset) == 0 {
|
|
||||||
delete(sourceMap, r.ip)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("delete rule: no rule with such id: %v", r.id)
|
return fmt.Errorf("delete rule: no rule with such id: %v", r.id)
|
||||||
}
|
}
|
||||||
|
delete(m.incomingRules[r.ip], r.id)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -593,7 +572,7 @@ func (m *Manager) UpdateSet(set firewall.Set, prefixes []netip.Prefix) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterOutbound filters outgoing packets
|
// FilterOutBound filters outgoing packets
|
||||||
func (m *Manager) FilterOutbound(packetData []byte, size int) bool {
|
func (m *Manager) FilterOutbound(packetData []byte, size int) bool {
|
||||||
return m.filterOutbound(packetData, size)
|
return m.filterOutbound(packetData, size)
|
||||||
}
|
}
|
||||||
@@ -782,7 +761,7 @@ func (m *Manager) filterInbound(packetData []byte, size int) bool {
|
|||||||
// handleLocalTraffic handles local traffic.
|
// handleLocalTraffic handles local traffic.
|
||||||
// If it returns true, the packet should be dropped.
|
// If it returns true, the packet should be dropped.
|
||||||
func (m *Manager) handleLocalTraffic(d *decoder, srcIP, dstIP netip.Addr, packetData []byte, size int) bool {
|
func (m *Manager) handleLocalTraffic(d *decoder, srcIP, dstIP netip.Addr, packetData []byte, size int) bool {
|
||||||
ruleID, blocked := m.peerACLsBlock(srcIP, d, packetData)
|
ruleID, blocked := m.peerACLsBlock(srcIP, packetData, m.incomingRules, d)
|
||||||
if blocked {
|
if blocked {
|
||||||
_, pnum := getProtocolFromPacket(d)
|
_, pnum := getProtocolFromPacket(d)
|
||||||
srcPort, dstPort := getPortsFromPacket(d)
|
srcPort, dstPort := getPortsFromPacket(d)
|
||||||
@@ -992,28 +971,26 @@ func (m *Manager) isSpecialICMP(d *decoder) bool {
|
|||||||
icmpType == layers.ICMPv4TypeTimeExceeded
|
icmpType == layers.ICMPv4TypeTimeExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) peerACLsBlock(srcIP netip.Addr, d *decoder, packetData []byte) ([]byte, bool) {
|
func (m *Manager) peerACLsBlock(srcIP netip.Addr, packetData []byte, rules map[netip.Addr]RuleSet, d *decoder) ([]byte, bool) {
|
||||||
m.mutex.RLock()
|
m.mutex.RLock()
|
||||||
defer m.mutex.RUnlock()
|
defer m.mutex.RUnlock()
|
||||||
|
|
||||||
if m.isSpecialICMP(d) {
|
if m.isSpecialICMP(d) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if mgmtId, filter, ok := validateRule(srcIP, packetData, m.incomingDenyRules[srcIP], d); ok {
|
if mgmtId, filter, ok := validateRule(srcIP, packetData, rules[srcIP], d); ok {
|
||||||
return mgmtId, filter
|
return mgmtId, filter
|
||||||
}
|
}
|
||||||
|
|
||||||
if mgmtId, filter, ok := validateRule(srcIP, packetData, m.incomingRules[srcIP], d); ok {
|
if mgmtId, filter, ok := validateRule(srcIP, packetData, rules[netip.IPv4Unspecified()], d); ok {
|
||||||
return mgmtId, filter
|
|
||||||
}
|
|
||||||
if mgmtId, filter, ok := validateRule(srcIP, packetData, m.incomingRules[netip.IPv4Unspecified()], d); ok {
|
|
||||||
return mgmtId, filter
|
|
||||||
}
|
|
||||||
if mgmtId, filter, ok := validateRule(srcIP, packetData, m.incomingRules[netip.IPv6Unspecified()], d); ok {
|
|
||||||
return mgmtId, filter
|
return mgmtId, filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mgmtId, filter, ok := validateRule(srcIP, packetData, rules[netip.IPv6Unspecified()], d); ok {
|
||||||
|
return mgmtId, filter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default policy: DROP ALL
|
||||||
return nil, true
|
return nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1036,7 +1013,6 @@ func portsMatch(rulePort *firewall.Port, packetPort uint16) bool {
|
|||||||
|
|
||||||
func validateRule(ip netip.Addr, packetData []byte, rules map[string]PeerRule, d *decoder) ([]byte, bool, bool) {
|
func validateRule(ip netip.Addr, packetData []byte, rules map[string]PeerRule, d *decoder) ([]byte, bool, bool) {
|
||||||
payloadLayer := d.decoded[1]
|
payloadLayer := d.decoded[1]
|
||||||
|
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
if rule.matchByIP && ip.Compare(rule.ip) != 0 {
|
if rule.matchByIP && ip.Compare(rule.ip) != 0 {
|
||||||
continue
|
continue
|
||||||
@@ -1069,7 +1045,6 @@ func validateRule(ip netip.Addr, packetData []byte, rules map[string]PeerRule, d
|
|||||||
return rule.mgmtId, rule.drop, true
|
return rule.mgmtId, rule.drop, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false, false
|
return nil, false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,7 +1116,6 @@ func (m *Manager) AddUDPPacketHook(in bool, ip netip.Addr, dPort uint16, hook fu
|
|||||||
|
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
if in {
|
if in {
|
||||||
// Incoming UDP hooks are stored in allow rules map
|
|
||||||
if _, ok := m.incomingRules[r.ip]; !ok {
|
if _, ok := m.incomingRules[r.ip]; !ok {
|
||||||
m.incomingRules[r.ip] = make(map[string]PeerRule)
|
m.incomingRules[r.ip] = make(map[string]PeerRule)
|
||||||
}
|
}
|
||||||
@@ -1162,7 +1136,6 @@ func (m *Manager) RemovePacketHook(hookID string) error {
|
|||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
// Check incoming hooks (stored in allow rules)
|
|
||||||
for _, arr := range m.incomingRules {
|
for _, arr := range m.incomingRules {
|
||||||
for _, r := range arr {
|
for _, r := range arr {
|
||||||
if r.id == hookID {
|
if r.id == hookID {
|
||||||
@@ -1171,7 +1144,6 @@ func (m *Manager) RemovePacketHook(hookID string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check outgoing hooks
|
|
||||||
for _, arr := range m.outgoingRules {
|
for _, arr := range m.outgoingRules {
|
||||||
for _, r := range arr {
|
for _, r := range arr {
|
||||||
if r.id == hookID {
|
if r.id == hookID {
|
||||||
|
|||||||
@@ -458,31 +458,6 @@ func TestPeerACLFiltering(t *testing.T) {
|
|||||||
ruleAction: fw.ActionDrop,
|
ruleAction: fw.ActionDrop,
|
||||||
shouldBeBlocked: true,
|
shouldBeBlocked: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Peer ACL - Drop rule should override accept all rule",
|
|
||||||
srcIP: "100.10.0.1",
|
|
||||||
dstIP: "100.10.0.100",
|
|
||||||
proto: fw.ProtocolTCP,
|
|
||||||
srcPort: 12345,
|
|
||||||
dstPort: 22,
|
|
||||||
ruleIP: "100.10.0.1",
|
|
||||||
ruleProto: fw.ProtocolTCP,
|
|
||||||
ruleDstPort: &fw.Port{Values: []uint16{22}},
|
|
||||||
ruleAction: fw.ActionDrop,
|
|
||||||
shouldBeBlocked: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Peer ACL - Drop all traffic from specific IP",
|
|
||||||
srcIP: "100.10.0.99",
|
|
||||||
dstIP: "100.10.0.100",
|
|
||||||
proto: fw.ProtocolTCP,
|
|
||||||
srcPort: 12345,
|
|
||||||
dstPort: 80,
|
|
||||||
ruleIP: "100.10.0.99",
|
|
||||||
ruleProto: fw.ProtocolALL,
|
|
||||||
ruleAction: fw.ActionDrop,
|
|
||||||
shouldBeBlocked: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("Implicit DROP (no rules)", func(t *testing.T) {
|
t.Run("Implicit DROP (no rules)", func(t *testing.T) {
|
||||||
@@ -493,11 +468,13 @@ func TestPeerACLFiltering(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
||||||
if tc.ruleAction == fw.ActionDrop {
|
if tc.ruleAction == fw.ActionDrop {
|
||||||
// add general accept rule for the same IP to test drop rule precedence
|
// add general accept rule to test drop rule
|
||||||
|
// TODO: this only works because 0.0.0.0 is tested last, we need to implement order
|
||||||
rules, err := manager.AddPeerFiltering(
|
rules, err := manager.AddPeerFiltering(
|
||||||
nil,
|
nil,
|
||||||
net.ParseIP(tc.ruleIP),
|
net.ParseIP("0.0.0.0"),
|
||||||
fw.ProtocolALL,
|
fw.ProtocolALL,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
|
|||||||
@@ -136,22 +136,9 @@ func TestManagerDeleteRule(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check rules exist in appropriate maps
|
|
||||||
for _, r := range rule2 {
|
for _, r := range rule2 {
|
||||||
peerRule, ok := r.(*PeerRule)
|
if _, ok := m.incomingRules[ip][r.ID()]; !ok {
|
||||||
if !ok {
|
t.Errorf("rule2 is not in the incomingRules")
|
||||||
t.Errorf("rule should be a PeerRule")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Check if rule exists in deny or allow maps based on action
|
|
||||||
var found bool
|
|
||||||
if peerRule.drop {
|
|
||||||
_, found = m.incomingDenyRules[ip][r.ID()]
|
|
||||||
} else {
|
|
||||||
_, found = m.incomingRules[ip][r.ID()]
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
t.Errorf("rule2 is not in the expected rules map")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,22 +150,9 @@ func TestManagerDeleteRule(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check rules are removed from appropriate maps
|
|
||||||
for _, r := range rule2 {
|
for _, r := range rule2 {
|
||||||
peerRule, ok := r.(*PeerRule)
|
if _, ok := m.incomingRules[ip][r.ID()]; ok {
|
||||||
if !ok {
|
t.Errorf("rule2 is not in the incomingRules")
|
||||||
t.Errorf("rule should be a PeerRule")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Check if rule is removed from deny or allow maps based on action
|
|
||||||
var found bool
|
|
||||||
if peerRule.drop {
|
|
||||||
_, found = m.incomingDenyRules[ip][r.ID()]
|
|
||||||
} else {
|
|
||||||
_, found = m.incomingRules[ip][r.ID()]
|
|
||||||
}
|
|
||||||
if found {
|
|
||||||
t.Errorf("rule2 should be removed from the rules map")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,17 +196,16 @@ func TestAddUDPPacketHook(t *testing.T) {
|
|||||||
|
|
||||||
var addedRule PeerRule
|
var addedRule PeerRule
|
||||||
if tt.in {
|
if tt.in {
|
||||||
// Incoming UDP hooks are stored in allow rules map
|
|
||||||
if len(manager.incomingRules[tt.ip]) != 1 {
|
if len(manager.incomingRules[tt.ip]) != 1 {
|
||||||
t.Errorf("expected 1 incoming rule, got %d", len(manager.incomingRules[tt.ip]))
|
t.Errorf("expected 1 incoming rule, got %d", len(manager.incomingRules))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, rule := range manager.incomingRules[tt.ip] {
|
for _, rule := range manager.incomingRules[tt.ip] {
|
||||||
addedRule = rule
|
addedRule = rule
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(manager.outgoingRules[tt.ip]) != 1 {
|
if len(manager.outgoingRules) != 1 {
|
||||||
t.Errorf("expected 1 outgoing rule, got %d", len(manager.outgoingRules[tt.ip]))
|
t.Errorf("expected 1 outgoing rule, got %d", len(manager.outgoingRules))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, rule := range manager.outgoingRules[tt.ip] {
|
for _, rule := range manager.outgoingRules[tt.ip] {
|
||||||
@@ -288,8 +261,8 @@ func TestManagerReset(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(m.outgoingRules) != 0 || len(m.incomingRules) != 0 || len(m.incomingDenyRules) != 0 {
|
if len(m.outgoingRules) != 0 || len(m.incomingRules) != 0 {
|
||||||
t.Errorf("rules are not empty")
|
t.Errorf("rules is not empty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ func (m *Manager) buildConntrackStateMessage(d *decoder) string {
|
|||||||
func (m *Manager) handleLocalDelivery(trace *PacketTrace, packetData []byte, d *decoder, srcIP, dstIP netip.Addr) bool {
|
func (m *Manager) handleLocalDelivery(trace *PacketTrace, packetData []byte, d *decoder, srcIP, dstIP netip.Addr) bool {
|
||||||
trace.AddResult(StageRouting, "Packet destined for local delivery", true)
|
trace.AddResult(StageRouting, "Packet destined for local delivery", true)
|
||||||
|
|
||||||
ruleId, blocked := m.peerACLsBlock(srcIP, d, packetData)
|
ruleId, blocked := m.peerACLsBlock(srcIP, packetData, m.incomingRules, d)
|
||||||
|
|
||||||
strRuleId := "<no id>"
|
strRuleId := "<no id>"
|
||||||
if ruleId != nil {
|
if ruleId != nil {
|
||||||
|
|||||||
@@ -56,11 +56,10 @@ type ICEBind struct {
|
|||||||
muUDPMux sync.Mutex
|
muUDPMux sync.Mutex
|
||||||
udpMux *UniversalUDPMuxDefault
|
udpMux *UniversalUDPMuxDefault
|
||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
mtu uint16
|
|
||||||
activityRecorder *ActivityRecorder
|
activityRecorder *ActivityRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICEBind(transportNet transport.Net, filterFn FilterFn, address wgaddr.Address, mtu uint16) *ICEBind {
|
func NewICEBind(transportNet transport.Net, filterFn FilterFn, address wgaddr.Address) *ICEBind {
|
||||||
b, _ := wgConn.NewStdNetBind().(*wgConn.StdNetBind)
|
b, _ := wgConn.NewStdNetBind().(*wgConn.StdNetBind)
|
||||||
ib := &ICEBind{
|
ib := &ICEBind{
|
||||||
StdNetBind: b,
|
StdNetBind: b,
|
||||||
@@ -70,7 +69,6 @@ func NewICEBind(transportNet transport.Net, filterFn FilterFn, address wgaddr.Ad
|
|||||||
endpoints: make(map[netip.Addr]net.Conn),
|
endpoints: make(map[netip.Addr]net.Conn),
|
||||||
closedChan: make(chan struct{}),
|
closedChan: make(chan struct{}),
|
||||||
closed: true,
|
closed: true,
|
||||||
mtu: mtu,
|
|
||||||
address: address,
|
address: address,
|
||||||
activityRecorder: NewActivityRecorder(),
|
activityRecorder: NewActivityRecorder(),
|
||||||
}
|
}
|
||||||
@@ -82,10 +80,6 @@ func NewICEBind(transportNet transport.Net, filterFn FilterFn, address wgaddr.Ad
|
|||||||
return ib
|
return ib
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ICEBind) MTU() uint16 {
|
|
||||||
return s.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ICEBind) Open(uport uint16) ([]wgConn.ReceiveFunc, uint16, error) {
|
func (s *ICEBind) Open(uport uint16) ([]wgConn.ReceiveFunc, uint16, error) {
|
||||||
s.closed = false
|
s.closed = false
|
||||||
s.closedChanMu.Lock()
|
s.closedChanMu.Lock()
|
||||||
@@ -164,7 +158,6 @@ func (s *ICEBind) createIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, r
|
|||||||
Net: s.transportNet,
|
Net: s.transportNet,
|
||||||
FilterFn: s.filterFn,
|
FilterFn: s.filterFn,
|
||||||
WGAddress: s.address,
|
WGAddress: s.address,
|
||||||
MTU: s.mtu,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return func(bufs [][]byte, sizes []int, eps []wgConn.Endpoint) (n int, err error) {
|
return func(bufs [][]byte, sizes []int, eps []wgConn.Endpoint) (n int, err error) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/pion/stun/v2"
|
"github.com/pion/stun/v2"
|
||||||
"github.com/pion/transport/v3"
|
"github.com/pion/transport/v3"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bufsize"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,7 +44,6 @@ type UniversalUDPMuxParams struct {
|
|||||||
Net transport.Net
|
Net transport.Net
|
||||||
FilterFn FilterFn
|
FilterFn FilterFn
|
||||||
WGAddress wgaddr.Address
|
WGAddress wgaddr.Address
|
||||||
MTU uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUniversalUDPMuxDefault creates an implementation of UniversalUDPMux embedding UDPMux
|
// NewUniversalUDPMuxDefault creates an implementation of UniversalUDPMux embedding UDPMux
|
||||||
@@ -86,7 +84,7 @@ func NewUniversalUDPMuxDefault(params UniversalUDPMuxParams) *UniversalUDPMuxDef
|
|||||||
// just ignore other packets printing an warning message.
|
// just ignore other packets printing an warning message.
|
||||||
// It is a blocking method, consider running in a go routine.
|
// It is a blocking method, consider running in a go routine.
|
||||||
func (m *UniversalUDPMuxDefault) ReadFromConn(ctx context.Context) {
|
func (m *UniversalUDPMuxDefault) ReadFromConn(ctx context.Context) {
|
||||||
buf := make([]byte, m.params.MTU+bufsize.WGBufferOverhead)
|
buf := make([]byte, 1500)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
package bufsize
|
|
||||||
|
|
||||||
const (
|
|
||||||
// WGBufferOverhead represents the additional buffer space needed beyond MTU
|
|
||||||
// for WireGuard packet encapsulation (WG header + UDP + IP + safety margin)
|
|
||||||
// Original hardcoded buffers were 1500, default MTU is 1280, so overhead = 220
|
|
||||||
// TODO: Calculate this properly based on actual protocol overhead instead of using hardcoded difference
|
|
||||||
WGBufferOverhead = 220
|
|
||||||
)
|
|
||||||
@@ -17,7 +17,6 @@ type WGTunDevice interface {
|
|||||||
Up() (*bind.UniversalUDPMuxDefault, error)
|
Up() (*bind.UniversalUDPMuxDefault, error)
|
||||||
UpdateAddr(address wgaddr.Address) error
|
UpdateAddr(address wgaddr.Address) error
|
||||||
WgAddress() wgaddr.Address
|
WgAddress() wgaddr.Address
|
||||||
MTU() uint16
|
|
||||||
DeviceName() string
|
DeviceName() string
|
||||||
Close() error
|
Close() error
|
||||||
FilteredDevice() *device.FilteredDevice
|
FilteredDevice() *device.FilteredDevice
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type WGTunDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
mtu int
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
tunAdapter TunAdapter
|
tunAdapter TunAdapter
|
||||||
disableDNS bool
|
disableDNS bool
|
||||||
@@ -33,7 +33,7 @@ type WGTunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, tunAdapter TunAdapter, disableDNS bool) *WGTunDevice {
|
func NewTunDevice(address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind, tunAdapter TunAdapter, disableDNS bool) *WGTunDevice {
|
||||||
return &WGTunDevice{
|
return &WGTunDevice{
|
||||||
address: address,
|
address: address,
|
||||||
port: port,
|
port: port,
|
||||||
@@ -58,7 +58,7 @@ func (t *WGTunDevice) Create(routes []string, dns string, searchDomains []string
|
|||||||
searchDomainsToString = ""
|
searchDomainsToString = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := t.tunAdapter.ConfigureInterface(t.address.String(), int(t.mtu), dns, searchDomainsToString, routesString)
|
fd, err := t.tunAdapter.ConfigureInterface(t.address.String(), t.mtu, dns, searchDomainsToString, routesString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to create Android interface: %s", err)
|
log.Errorf("failed to create Android interface: %s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -137,10 +137,6 @@ func (t *WGTunDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *WGTunDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *WGTunDevice) FilteredDevice() *FilteredDevice {
|
func (t *WGTunDevice) FilteredDevice() *FilteredDevice {
|
||||||
return t.filteredDevice
|
return t.filteredDevice
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type TunDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
mtu int
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
|
|
||||||
device *device.Device
|
device *device.Device
|
||||||
@@ -30,7 +30,7 @@ type TunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *TunDevice {
|
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind) *TunDevice {
|
||||||
return &TunDevice{
|
return &TunDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -42,7 +42,7 @@ func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) Create() (WGConfigurer, error) {
|
func (t *TunDevice) Create() (WGConfigurer, error) {
|
||||||
tunDevice, err := tun.CreateTUN(t.name, int(t.mtu))
|
tunDevice, err := tun.CreateTUN(t.name, t.mtu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating tun device: %s", err)
|
return nil, fmt.Errorf("error creating tun device: %s", err)
|
||||||
}
|
}
|
||||||
@@ -111,10 +111,6 @@ func (t *TunDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TunDevice) DeviceName() string {
|
func (t *TunDevice) DeviceName() string {
|
||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ type TunDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
tunFd int
|
tunFd int
|
||||||
|
|
||||||
@@ -32,13 +31,12 @@ type TunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, tunFd int) *TunDevice {
|
func NewTunDevice(name string, address wgaddr.Address, port int, key string, iceBind *bind.ICEBind, tunFd int) *TunDevice {
|
||||||
return &TunDevice{
|
return &TunDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
port: port,
|
port: port,
|
||||||
key: key,
|
key: key,
|
||||||
mtu: mtu,
|
|
||||||
iceBind: iceBind,
|
iceBind: iceBind,
|
||||||
tunFd: tunFd,
|
tunFd: tunFd,
|
||||||
}
|
}
|
||||||
@@ -127,10 +125,6 @@ func (t *TunDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TunDevice) UpdateAddr(_ wgaddr.Address) error {
|
func (t *TunDevice) UpdateAddr(_ wgaddr.Address) error {
|
||||||
// todo implement
|
// todo implement
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type TunKernelDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
wgPort int
|
wgPort int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
mtu int
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
transportNet transport.Net
|
transportNet transport.Net
|
||||||
@@ -36,7 +36,7 @@ type TunKernelDevice struct {
|
|||||||
filterFn bind.FilterFn
|
filterFn bind.FilterFn
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKernelDevice(name string, address wgaddr.Address, wgPort int, key string, mtu uint16, transportNet transport.Net) *TunKernelDevice {
|
func NewKernelDevice(name string, address wgaddr.Address, wgPort int, key string, mtu int, transportNet transport.Net) *TunKernelDevice {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return &TunKernelDevice{
|
return &TunKernelDevice{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
@@ -66,7 +66,7 @@ func (t *TunKernelDevice) Create() (WGConfigurer, error) {
|
|||||||
// TODO: do a MTU discovery
|
// TODO: do a MTU discovery
|
||||||
log.Debugf("setting MTU: %d interface: %s", t.mtu, t.name)
|
log.Debugf("setting MTU: %d interface: %s", t.mtu, t.name)
|
||||||
|
|
||||||
if err := link.setMTU(int(t.mtu)); err != nil {
|
if err := link.setMTU(t.mtu); err != nil {
|
||||||
return nil, fmt.Errorf("set mtu: %w", err)
|
return nil, fmt.Errorf("set mtu: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ func (t *TunKernelDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSock, err := sharedsock.Listen(t.wgPort, sharedsock.NewIncomingSTUNFilter(), t.mtu)
|
rawSock, err := sharedsock.Listen(t.wgPort, sharedsock.NewIncomingSTUNFilter())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,6 @@ func (t *TunKernelDevice) Up() (*bind.UniversalUDPMuxDefault, error) {
|
|||||||
Net: t.transportNet,
|
Net: t.transportNet,
|
||||||
FilterFn: t.filterFn,
|
FilterFn: t.filterFn,
|
||||||
WGAddress: t.address,
|
WGAddress: t.address,
|
||||||
MTU: t.mtu,
|
|
||||||
}
|
}
|
||||||
mux := bind.NewUniversalUDPMuxDefault(bindParams)
|
mux := bind.NewUniversalUDPMuxDefault(bindParams)
|
||||||
go mux.ReadFromConn(t.ctx)
|
go mux.ReadFromConn(t.ctx)
|
||||||
@@ -159,10 +158,6 @@ func (t *TunKernelDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunKernelDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TunKernelDevice) DeviceName() string {
|
func (t *TunKernelDevice) DeviceName() string {
|
||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
//go:build !android
|
||||||
|
// +build !android
|
||||||
|
|
||||||
package device
|
package device
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -19,7 +22,7 @@ type TunNetstackDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
mtu int
|
||||||
listenAddress string
|
listenAddress string
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
|
|
||||||
@@ -32,7 +35,7 @@ type TunNetstackDevice struct {
|
|||||||
net *netstack.Net
|
net *netstack.Net
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key string, mtu uint16, iceBind *bind.ICEBind, listenAddress string) *TunNetstackDevice {
|
func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key string, mtu int, iceBind *bind.ICEBind, listenAddress string) *TunNetstackDevice {
|
||||||
return &TunNetstackDevice{
|
return &TunNetstackDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -44,7 +47,7 @@ func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunNetstackDevice) create() (WGConfigurer, error) {
|
func (t *TunNetstackDevice) Create() (WGConfigurer, error) {
|
||||||
log.Info("create nbnetstack tun interface")
|
log.Info("create nbnetstack tun interface")
|
||||||
|
|
||||||
// TODO: get from service listener runtime IP
|
// TODO: get from service listener runtime IP
|
||||||
@@ -54,7 +57,7 @@ func (t *TunNetstackDevice) create() (WGConfigurer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("netstack using address: %s", t.address.IP)
|
log.Debugf("netstack using address: %s", t.address.IP)
|
||||||
t.nsTun = nbnetstack.NewNetStackTun(t.listenAddress, t.address.IP, dnsAddr, int(t.mtu))
|
t.nsTun = nbnetstack.NewNetStackTun(t.listenAddress, t.address.IP, dnsAddr, t.mtu)
|
||||||
log.Debugf("netstack using dns address: %s", dnsAddr)
|
log.Debugf("netstack using dns address: %s", dnsAddr)
|
||||||
tunIface, net, err := t.nsTun.Create()
|
tunIface, net, err := t.nsTun.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -122,10 +125,6 @@ func (t *TunNetstackDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunNetstackDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TunNetstackDevice) DeviceName() string {
|
func (t *TunNetstackDevice) DeviceName() string {
|
||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
//go:build android
|
|
||||||
|
|
||||||
package device
|
|
||||||
|
|
||||||
func (t *TunNetstackDevice) Create(routes []string, dns string, searchDomains []string) (WGConfigurer, error) {
|
|
||||||
return t.create()
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
//go:build !android
|
|
||||||
|
|
||||||
package device
|
|
||||||
|
|
||||||
func (t *TunNetstackDevice) Create() (WGConfigurer, error) {
|
|
||||||
return t.create()
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,7 @@ type USPDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
mtu int
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
|
|
||||||
device *device.Device
|
device *device.Device
|
||||||
@@ -29,7 +29,7 @@ type USPDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUSPDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *USPDevice {
|
func NewUSPDevice(name string, address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind) *USPDevice {
|
||||||
log.Infof("using userspace bind mode")
|
log.Infof("using userspace bind mode")
|
||||||
|
|
||||||
return &USPDevice{
|
return &USPDevice{
|
||||||
@@ -44,9 +44,9 @@ func NewUSPDevice(name string, address wgaddr.Address, port int, key string, mtu
|
|||||||
|
|
||||||
func (t *USPDevice) Create() (WGConfigurer, error) {
|
func (t *USPDevice) Create() (WGConfigurer, error) {
|
||||||
log.Info("create tun interface")
|
log.Info("create tun interface")
|
||||||
tunIface, err := tun.CreateTUN(t.name, int(t.mtu))
|
tunIface, err := tun.CreateTUN(t.name, t.mtu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("failed to create tun interface (%s, %d): %s", t.name, int(t.mtu), err)
|
log.Debugf("failed to create tun interface (%s, %d): %s", t.name, t.mtu, err)
|
||||||
return nil, fmt.Errorf("error creating tun device: %s", err)
|
return nil, fmt.Errorf("error creating tun device: %s", err)
|
||||||
}
|
}
|
||||||
t.filteredDevice = newDeviceFilter(tunIface)
|
t.filteredDevice = newDeviceFilter(tunIface)
|
||||||
@@ -118,10 +118,6 @@ func (t *USPDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *USPDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *USPDevice) DeviceName() string {
|
func (t *USPDevice) DeviceName() string {
|
||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ type TunDevice struct {
|
|||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
port int
|
port int
|
||||||
key string
|
key string
|
||||||
mtu uint16
|
mtu int
|
||||||
iceBind *bind.ICEBind
|
iceBind *bind.ICEBind
|
||||||
|
|
||||||
device *device.Device
|
device *device.Device
|
||||||
@@ -33,7 +33,7 @@ type TunDevice struct {
|
|||||||
configurer WGConfigurer
|
configurer WGConfigurer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *TunDevice {
|
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu int, iceBind *bind.ICEBind) *TunDevice {
|
||||||
return &TunDevice{
|
return &TunDevice{
|
||||||
name: name,
|
name: name,
|
||||||
address: address,
|
address: address,
|
||||||
@@ -59,7 +59,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Info("create tun interface")
|
log.Info("create tun interface")
|
||||||
tunDevice, err := tun.CreateTUNWithRequestedGUID(t.name, &guid, int(t.mtu))
|
tunDevice, err := tun.CreateTUNWithRequestedGUID(t.name, &guid, t.mtu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating tun device: %s", err)
|
return nil, fmt.Errorf("error creating tun device: %s", err)
|
||||||
}
|
}
|
||||||
@@ -144,10 +144,6 @@ func (t *TunDevice) WgAddress() wgaddr.Address {
|
|||||||
return t.address
|
return t.address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TunDevice) MTU() uint16 {
|
|
||||||
return t.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TunDevice) DeviceName() string {
|
func (t *TunDevice) DeviceName() string {
|
||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ type WGTunDevice interface {
|
|||||||
Up() (*bind.UniversalUDPMuxDefault, error)
|
Up() (*bind.UniversalUDPMuxDefault, error)
|
||||||
UpdateAddr(address wgaddr.Address) error
|
UpdateAddr(address wgaddr.Address) error
|
||||||
WgAddress() wgaddr.Address
|
WgAddress() wgaddr.Address
|
||||||
MTU() uint16
|
|
||||||
DeviceName() string
|
DeviceName() string
|
||||||
Close() error
|
Close() error
|
||||||
FilteredDevice() *device.FilteredDevice
|
FilteredDevice() *device.FilteredDevice
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultMTU = 1280
|
DefaultMTU = 1280
|
||||||
MinMTU = 576
|
|
||||||
MaxMTU = 8192
|
|
||||||
DefaultWgPort = 51820
|
DefaultWgPort = 51820
|
||||||
WgInterfaceDefault = configurer.WgInterfaceDefault
|
WgInterfaceDefault = configurer.WgInterfaceDefault
|
||||||
)
|
)
|
||||||
@@ -37,17 +35,6 @@ var (
|
|||||||
ErrIfaceNotFound = fmt.Errorf("wireguard interface not found")
|
ErrIfaceNotFound = fmt.Errorf("wireguard interface not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateMTU validates that MTU is within acceptable range
|
|
||||||
func ValidateMTU(mtu uint16) error {
|
|
||||||
if mtu < MinMTU {
|
|
||||||
return fmt.Errorf("MTU %d below minimum (%d bytes)", mtu, MinMTU)
|
|
||||||
}
|
|
||||||
if mtu > MaxMTU {
|
|
||||||
return fmt.Errorf("MTU %d exceeds maximum supported size (%d bytes)", mtu, MaxMTU)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type wgProxyFactory interface {
|
type wgProxyFactory interface {
|
||||||
GetProxy() wgproxy.Proxy
|
GetProxy() wgproxy.Proxy
|
||||||
Free() error
|
Free() error
|
||||||
@@ -58,7 +45,7 @@ type WGIFaceOpts struct {
|
|||||||
Address string
|
Address string
|
||||||
WGPort int
|
WGPort int
|
||||||
WGPrivKey string
|
WGPrivKey string
|
||||||
MTU uint16
|
MTU int
|
||||||
MobileArgs *device.MobileIFaceArguments
|
MobileArgs *device.MobileIFaceArguments
|
||||||
TransportNet transport.Net
|
TransportNet transport.Net
|
||||||
FilterFn bind.FilterFn
|
FilterFn bind.FilterFn
|
||||||
@@ -95,10 +82,6 @@ func (w *WGIface) Address() wgaddr.Address {
|
|||||||
return w.tun.WgAddress()
|
return w.tun.WgAddress()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WGIface) MTU() uint16 {
|
|
||||||
return w.tun.MTU()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToInterface returns the net.Interface for the Wireguard interface
|
// ToInterface returns the net.Interface for the Wireguard interface
|
||||||
func (r *WGIface) ToInterface() *net.Interface {
|
func (r *WGIface) ToInterface() *net.Interface {
|
||||||
name := r.tun.DeviceName()
|
name := r.tun.DeviceName()
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package iface
|
|||||||
import (
|
import (
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
"github.com/netbirdio/netbird/client/iface/netstack"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
"github.com/netbirdio/netbird/client/iface/wgaddr"
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||||
)
|
)
|
||||||
@@ -15,16 +14,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress, opts.MTU)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
if netstack.IsEnabled() {
|
|
||||||
wgIFace := &WGIface{
|
|
||||||
userspaceBind: true,
|
|
||||||
tun: device.NewNetstackDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, netstack.ListenAddr()),
|
|
||||||
wgProxyFactory: wgproxy.NewUSPFactory(iceBind),
|
|
||||||
}
|
|
||||||
return wgIFace, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
wgIFace := &WGIface{
|
wgIFace := &WGIface{
|
||||||
userspaceBind: true,
|
userspaceBind: true,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress, opts.MTU)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
var tun WGTunDevice
|
var tun WGTunDevice
|
||||||
if netstack.IsEnabled() {
|
if netstack.IsEnabled() {
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress, opts.MTU)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
wgIFace := &WGIface{
|
wgIFace := &WGIface{
|
||||||
tun: device.NewTunDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, opts.MobileArgs.TunFd),
|
tun: device.NewTunDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, iceBind, opts.MobileArgs.TunFd),
|
||||||
userspaceBind: true,
|
userspaceBind: true,
|
||||||
wgProxyFactory: wgproxy.NewUSPFactory(iceBind),
|
wgProxyFactory: wgproxy.NewUSPFactory(iceBind),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
wgIFace := &WGIface{}
|
wgIFace := &WGIface{}
|
||||||
|
|
||||||
if netstack.IsEnabled() {
|
if netstack.IsEnabled() {
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress, opts.MTU)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
wgIFace.tun = device.NewNetstackDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, netstack.ListenAddr())
|
wgIFace.tun = device.NewNetstackDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind, netstack.ListenAddr())
|
||||||
wgIFace.userspaceBind = true
|
wgIFace.userspaceBind = true
|
||||||
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
||||||
@@ -31,11 +31,11 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
|
|
||||||
if device.WireGuardModuleIsLoaded() {
|
if device.WireGuardModuleIsLoaded() {
|
||||||
wgIFace.tun = device.NewKernelDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, opts.TransportNet)
|
wgIFace.tun = device.NewKernelDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, opts.TransportNet)
|
||||||
wgIFace.wgProxyFactory = wgproxy.NewKernelFactory(opts.WGPort, opts.MTU)
|
wgIFace.wgProxyFactory = wgproxy.NewKernelFactory(opts.WGPort)
|
||||||
return wgIFace, nil
|
return wgIFace, nil
|
||||||
}
|
}
|
||||||
if device.ModuleTunIsLoaded() {
|
if device.ModuleTunIsLoaded() {
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress, opts.MTU)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
wgIFace.tun = device.NewUSPDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind)
|
wgIFace.tun = device.NewUSPDevice(opts.IFaceName, wgAddress, opts.WGPort, opts.WGPrivKey, opts.MTU, iceBind)
|
||||||
wgIFace.userspaceBind = true
|
wgIFace.userspaceBind = true
|
||||||
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
wgIFace.wgProxyFactory = wgproxy.NewUSPFactory(iceBind)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func NewWGIFace(opts WGIFaceOpts) (*WGIface, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress, opts.MTU)
|
iceBind := bind.NewICEBind(opts.TransportNet, opts.FilterFn, wgAddress)
|
||||||
|
|
||||||
var tun WGTunDevice
|
var tun WGTunDevice
|
||||||
if netstack.IsEnabled() {
|
if netstack.IsEnabled() {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
"github.com/netbirdio/netbird/client/iface/bufsize"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy/listener"
|
"github.com/netbirdio/netbird/client/iface/wgproxy/listener"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -136,7 +135,7 @@ func (p *ProxyBind) proxyToLocal(ctx context.Context) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, p.Bind.MTU()+bufsize.WGBufferOverhead)
|
buf := make([]byte, 1500)
|
||||||
n, err := p.remoteConn.Read(buf)
|
n, err := p.remoteConn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
nberrors "github.com/netbirdio/netbird/client/errors"
|
nberrors "github.com/netbirdio/netbird/client/errors"
|
||||||
"github.com/netbirdio/netbird/client/iface/bufsize"
|
|
||||||
"github.com/netbirdio/netbird/client/internal/ebpf"
|
"github.com/netbirdio/netbird/client/internal/ebpf"
|
||||||
ebpfMgr "github.com/netbirdio/netbird/client/internal/ebpf/manager"
|
ebpfMgr "github.com/netbirdio/netbird/client/internal/ebpf/manager"
|
||||||
nbnet "github.com/netbirdio/netbird/util/net"
|
nbnet "github.com/netbirdio/netbird/util/net"
|
||||||
@@ -30,7 +29,6 @@ const (
|
|||||||
// WGEBPFProxy definition for proxy with EBPF support
|
// WGEBPFProxy definition for proxy with EBPF support
|
||||||
type WGEBPFProxy struct {
|
type WGEBPFProxy struct {
|
||||||
localWGListenPort int
|
localWGListenPort int
|
||||||
mtu uint16
|
|
||||||
|
|
||||||
ebpfManager ebpfMgr.Manager
|
ebpfManager ebpfMgr.Manager
|
||||||
turnConnStore map[uint16]net.Conn
|
turnConnStore map[uint16]net.Conn
|
||||||
@@ -45,11 +43,10 @@ type WGEBPFProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewWGEBPFProxy create new WGEBPFProxy instance
|
// NewWGEBPFProxy create new WGEBPFProxy instance
|
||||||
func NewWGEBPFProxy(wgPort int, mtu uint16) *WGEBPFProxy {
|
func NewWGEBPFProxy(wgPort int) *WGEBPFProxy {
|
||||||
log.Debugf("instantiate ebpf proxy")
|
log.Debugf("instantiate ebpf proxy")
|
||||||
wgProxy := &WGEBPFProxy{
|
wgProxy := &WGEBPFProxy{
|
||||||
localWGListenPort: wgPort,
|
localWGListenPort: wgPort,
|
||||||
mtu: mtu,
|
|
||||||
ebpfManager: ebpf.GetEbpfManagerInstance(),
|
ebpfManager: ebpf.GetEbpfManagerInstance(),
|
||||||
turnConnStore: make(map[uint16]net.Conn),
|
turnConnStore: make(map[uint16]net.Conn),
|
||||||
}
|
}
|
||||||
@@ -141,7 +138,7 @@ func (p *WGEBPFProxy) Free() error {
|
|||||||
// proxyToRemote read messages from local WireGuard interface and forward it to remote conn
|
// proxyToRemote read messages from local WireGuard interface and forward it to remote conn
|
||||||
// From this go routine has only one instance.
|
// From this go routine has only one instance.
|
||||||
func (p *WGEBPFProxy) proxyToRemote() {
|
func (p *WGEBPFProxy) proxyToRemote() {
|
||||||
buf := make([]byte, p.mtu+bufsize.WGBufferOverhead)
|
buf := make([]byte, 1500)
|
||||||
for p.ctx.Err() == nil {
|
for p.ctx.Err() == nil {
|
||||||
if err := p.readAndForwardPacket(buf); err != nil {
|
if err := p.readAndForwardPacket(buf); err != nil {
|
||||||
if p.ctx.Err() != nil {
|
if p.ctx.Err() != nil {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestWGEBPFProxy_connStore(t *testing.T) {
|
func TestWGEBPFProxy_connStore(t *testing.T) {
|
||||||
wgProxy := NewWGEBPFProxy(1, 1280)
|
wgProxy := NewWGEBPFProxy(1)
|
||||||
|
|
||||||
p, _ := wgProxy.storeTurnConn(nil)
|
p, _ := wgProxy.storeTurnConn(nil)
|
||||||
if p != 1 {
|
if p != 1 {
|
||||||
@@ -27,7 +27,7 @@ func TestWGEBPFProxy_connStore(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWGEBPFProxy_portCalculation_overflow(t *testing.T) {
|
func TestWGEBPFProxy_portCalculation_overflow(t *testing.T) {
|
||||||
wgProxy := NewWGEBPFProxy(1, 1280)
|
wgProxy := NewWGEBPFProxy(1)
|
||||||
|
|
||||||
_, _ = wgProxy.storeTurnConn(nil)
|
_, _ = wgProxy.storeTurnConn(nil)
|
||||||
wgProxy.lastUsedPort = 65535
|
wgProxy.lastUsedPort = 65535
|
||||||
@@ -43,7 +43,7 @@ func TestWGEBPFProxy_portCalculation_overflow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWGEBPFProxy_portCalculation_maxConn(t *testing.T) {
|
func TestWGEBPFProxy_portCalculation_maxConn(t *testing.T) {
|
||||||
wgProxy := NewWGEBPFProxy(1, 1280)
|
wgProxy := NewWGEBPFProxy(1)
|
||||||
|
|
||||||
for i := 0; i < 65535; i++ {
|
for i := 0; i < 65535; i++ {
|
||||||
_, _ = wgProxy.storeTurnConn(nil)
|
_, _ = wgProxy.storeTurnConn(nil)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/bufsize"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy/listener"
|
"github.com/netbirdio/netbird/client/iface/wgproxy/listener"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -104,7 +103,7 @@ func (e *ProxyWrapper) CloseConn() error {
|
|||||||
func (p *ProxyWrapper) proxyToLocal(ctx context.Context) {
|
func (p *ProxyWrapper) proxyToLocal(ctx context.Context) {
|
||||||
defer p.WgeBPFProxy.removeTurnConn(uint16(p.wgEndpointAddr.Port))
|
defer p.WgeBPFProxy.removeTurnConn(uint16(p.wgEndpointAddr.Port))
|
||||||
|
|
||||||
buf := make([]byte, p.WgeBPFProxy.mtu+bufsize.WGBufferOverhead)
|
buf := make([]byte, 1500)
|
||||||
for {
|
for {
|
||||||
n, err := p.readFromRemote(ctx, buf)
|
n, err := p.readFromRemote(ctx, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -11,18 +11,16 @@ import (
|
|||||||
|
|
||||||
type KernelFactory struct {
|
type KernelFactory struct {
|
||||||
wgPort int
|
wgPort int
|
||||||
mtu uint16
|
|
||||||
|
|
||||||
ebpfProxy *ebpf.WGEBPFProxy
|
ebpfProxy *ebpf.WGEBPFProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKernelFactory(wgPort int, mtu uint16) *KernelFactory {
|
func NewKernelFactory(wgPort int) *KernelFactory {
|
||||||
f := &KernelFactory{
|
f := &KernelFactory{
|
||||||
wgPort: wgPort,
|
wgPort: wgPort,
|
||||||
mtu: mtu,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ebpfProxy := ebpf.NewWGEBPFProxy(wgPort, mtu)
|
ebpfProxy := ebpf.NewWGEBPFProxy(wgPort)
|
||||||
if err := ebpfProxy.Listen(); err != nil {
|
if err := ebpfProxy.Listen(); err != nil {
|
||||||
log.Infof("WireGuard Proxy Factory will produce UDP proxy")
|
log.Infof("WireGuard Proxy Factory will produce UDP proxy")
|
||||||
log.Warnf("failed to initialize ebpf proxy, fallback to user space proxy: %s", err)
|
log.Warnf("failed to initialize ebpf proxy, fallback to user space proxy: %s", err)
|
||||||
@@ -35,7 +33,7 @@ func NewKernelFactory(wgPort int, mtu uint16) *KernelFactory {
|
|||||||
|
|
||||||
func (w *KernelFactory) GetProxy() Proxy {
|
func (w *KernelFactory) GetProxy() Proxy {
|
||||||
if w.ebpfProxy == nil {
|
if w.ebpfProxy == nil {
|
||||||
return udpProxy.NewWGUDPProxy(w.wgPort, w.mtu)
|
return udpProxy.NewWGUDPProxy(w.wgPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ebpf.NewProxyWrapper(w.ebpfProxy)
|
return ebpf.NewProxyWrapper(w.ebpfProxy)
|
||||||
|
|||||||
@@ -9,21 +9,19 @@ import (
|
|||||||
// KernelFactory todo: check eBPF support on FreeBSD
|
// KernelFactory todo: check eBPF support on FreeBSD
|
||||||
type KernelFactory struct {
|
type KernelFactory struct {
|
||||||
wgPort int
|
wgPort int
|
||||||
mtu uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKernelFactory(wgPort int, mtu uint16) *KernelFactory {
|
func NewKernelFactory(wgPort int) *KernelFactory {
|
||||||
log.Infof("WireGuard Proxy Factory will produce UDP proxy")
|
log.Infof("WireGuard Proxy Factory will produce UDP proxy")
|
||||||
f := &KernelFactory{
|
f := &KernelFactory{
|
||||||
wgPort: wgPort,
|
wgPort: wgPort,
|
||||||
mtu: mtu,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *KernelFactory) GetProxy() Proxy {
|
func (w *KernelFactory) GetProxy() Proxy {
|
||||||
return udpProxy.NewWGUDPProxy(w.wgPort, w.mtu)
|
return udpProxy.NewWGUDPProxy(w.wgPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *KernelFactory) Free() error {
|
func (w *KernelFactory) Free() error {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func TestProxyCloseByRemoteConnEBPF(t *testing.T) {
|
|||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
ebpfProxy := ebpf.NewWGEBPFProxy(51831, 1280)
|
ebpfProxy := ebpf.NewWGEBPFProxy(51831)
|
||||||
if err := ebpfProxy.Listen(); err != nil {
|
if err := ebpfProxy.Listen(); err != nil {
|
||||||
t.Fatalf("failed to initialize ebpf proxy: %s", err)
|
t.Fatalf("failed to initialize ebpf proxy: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,12 +84,12 @@ func TestProxyCloseByRemoteConn(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "userspace proxy",
|
name: "userspace proxy",
|
||||||
proxy: udpProxy.NewWGUDPProxy(51830, 1280),
|
proxy: udpProxy.NewWGUDPProxy(51830),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "linux" && os.Getenv("GITHUB_ACTIONS") != "true" {
|
if runtime.GOOS == "linux" && os.Getenv("GITHUB_ACTIONS") != "true" {
|
||||||
ebpfProxy := ebpf.NewWGEBPFProxy(51831, 1280)
|
ebpfProxy := ebpf.NewWGEBPFProxy(51831)
|
||||||
if err := ebpfProxy.Listen(); err != nil {
|
if err := ebpfProxy.Listen(); err != nil {
|
||||||
t.Fatalf("failed to initialize ebpf proxy: %s", err)
|
t.Fatalf("failed to initialize ebpf proxy: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,12 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
cerrors "github.com/netbirdio/netbird/client/errors"
|
cerrors "github.com/netbirdio/netbird/client/errors"
|
||||||
"github.com/netbirdio/netbird/client/iface/bufsize"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/wgproxy/listener"
|
"github.com/netbirdio/netbird/client/iface/wgproxy/listener"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WGUDPProxy proxies
|
// WGUDPProxy proxies
|
||||||
type WGUDPProxy struct {
|
type WGUDPProxy struct {
|
||||||
localWGListenPort int
|
localWGListenPort int
|
||||||
mtu uint16
|
|
||||||
|
|
||||||
remoteConn net.Conn
|
remoteConn net.Conn
|
||||||
localConn net.Conn
|
localConn net.Conn
|
||||||
@@ -36,11 +34,10 @@ type WGUDPProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewWGUDPProxy instantiate a UDP based WireGuard proxy. This is not a thread safe implementation
|
// NewWGUDPProxy instantiate a UDP based WireGuard proxy. This is not a thread safe implementation
|
||||||
func NewWGUDPProxy(wgPort int, mtu uint16) *WGUDPProxy {
|
func NewWGUDPProxy(wgPort int) *WGUDPProxy {
|
||||||
log.Debugf("Initializing new user space proxy with port %d", wgPort)
|
log.Debugf("Initializing new user space proxy with port %d", wgPort)
|
||||||
p := &WGUDPProxy{
|
p := &WGUDPProxy{
|
||||||
localWGListenPort: wgPort,
|
localWGListenPort: wgPort,
|
||||||
mtu: mtu,
|
|
||||||
closeListener: listener.NewCloseListener(),
|
closeListener: listener.NewCloseListener(),
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
@@ -147,7 +144,7 @@ func (p *WGUDPProxy) proxyToRemote(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
buf := make([]byte, p.mtu+bufsize.WGBufferOverhead)
|
buf := make([]byte, 1500)
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
n, err := p.localConn.Read(buf)
|
n, err := p.localConn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -182,7 +179,7 @@ func (p *WGUDPProxy) proxyToLocal(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
buf := make([]byte, p.mtu+bufsize.WGBufferOverhead)
|
buf := make([]byte, 1500)
|
||||||
for {
|
for {
|
||||||
n, err := p.remoteConnRead(ctx, buf)
|
n, err := p.remoteConnRead(ctx, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,17 +3,15 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
"github.com/netbirdio/netbird/client/internal"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockHTTPClient struct {
|
type mockHTTPClient struct {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
gstatus "google.golang.org/grpc/status"
|
gstatus "google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
|
||||||
"github.com/netbirdio/netbird/client/iface/device"
|
"github.com/netbirdio/netbird/client/iface/device"
|
||||||
"github.com/netbirdio/netbird/client/internal/dns"
|
"github.com/netbirdio/netbird/client/internal/dns"
|
||||||
"github.com/netbirdio/netbird/client/internal/listener"
|
"github.com/netbirdio/netbird/client/internal/listener"
|
||||||
@@ -245,15 +244,7 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
|||||||
c.statusRecorder.MarkSignalConnected()
|
c.statusRecorder.MarkSignalConnected()
|
||||||
|
|
||||||
relayURLs, token := parseRelayInfo(loginResp)
|
relayURLs, token := parseRelayInfo(loginResp)
|
||||||
peerConfig := loginResp.GetPeerConfig()
|
relayManager := relayClient.NewManager(engineCtx, relayURLs, myPrivateKey.PublicKey().String())
|
||||||
|
|
||||||
engineConfig, err := createEngineConfig(myPrivateKey, c.config, peerConfig)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return wrapErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
relayManager := relayClient.NewManager(engineCtx, relayURLs, myPrivateKey.PublicKey().String(), engineConfig.MTU)
|
|
||||||
c.statusRecorder.SetRelayMgr(relayManager)
|
c.statusRecorder.SetRelayMgr(relayManager)
|
||||||
if len(relayURLs) > 0 {
|
if len(relayURLs) > 0 {
|
||||||
if token != nil {
|
if token != nil {
|
||||||
@@ -268,6 +259,14 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
peerConfig := loginResp.GetPeerConfig()
|
||||||
|
|
||||||
|
engineConfig, err := createEngineConfig(myPrivateKey, c.config, peerConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return wrapErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
checks := loginResp.GetChecks()
|
checks := loginResp.GetChecks()
|
||||||
|
|
||||||
c.engineMutex.Lock()
|
c.engineMutex.Lock()
|
||||||
@@ -445,8 +444,6 @@ func createEngineConfig(key wgtypes.Key, config *profilemanager.Config, peerConf
|
|||||||
BlockInbound: config.BlockInbound,
|
BlockInbound: config.BlockInbound,
|
||||||
|
|
||||||
LazyConnectionEnabled: config.LazyConnectionEnabled,
|
LazyConnectionEnabled: config.LazyConnectionEnabled,
|
||||||
|
|
||||||
MTU: selectMTU(config.MTU, peerConfig.Mtu),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.PreSharedKey != "" {
|
if config.PreSharedKey != "" {
|
||||||
@@ -469,20 +466,6 @@ func createEngineConfig(key wgtypes.Key, config *profilemanager.Config, peerConf
|
|||||||
return engineConf, nil
|
return engineConf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectMTU(localMTU uint16, peerMTU int32) uint16 {
|
|
||||||
var finalMTU uint16 = iface.DefaultMTU
|
|
||||||
if localMTU > 0 {
|
|
||||||
finalMTU = localMTU
|
|
||||||
} else if peerMTU > 0 {
|
|
||||||
finalMTU = uint16(peerMTU)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set global DNS MTU
|
|
||||||
dns.SetCurrentMTU(finalMTU)
|
|
||||||
|
|
||||||
return finalMTU
|
|
||||||
}
|
|
||||||
|
|
||||||
// connectToSignal creates Signal Service client and established a connection
|
// connectToSignal creates Signal Service client and established a connection
|
||||||
func connectToSignal(ctx context.Context, wtConfig *mgmProto.NetbirdConfig, ourPrivateKey wgtypes.Key) (*signal.GrpcClient, error) {
|
func connectToSignal(ctx context.Context, wtConfig *mgmProto.NetbirdConfig, ourPrivateKey wgtypes.Key) (*signal.GrpcClient, error) {
|
||||||
var sigTLSEnabled bool
|
var sigTLSEnabled bool
|
||||||
|
|||||||
@@ -176,3 +176,4 @@ nameserver 192.168.0.1
|
|||||||
t.Errorf("unexpected resolv.conf content: %v", cfg)
|
t.Errorf("unexpected resolv.conf content: %v", cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,10 +166,9 @@ func (s *systemConfigurator) removeKeyFromSystemConfig(key string) error {
|
|||||||
|
|
||||||
func (s *systemConfigurator) addLocalDNS() error {
|
func (s *systemConfigurator) addLocalDNS() error {
|
||||||
if !s.systemDNSSettings.ServerIP.IsValid() || len(s.systemDNSSettings.Domains) == 0 {
|
if !s.systemDNSSettings.ServerIP.IsValid() || len(s.systemDNSSettings.Domains) == 0 {
|
||||||
if err := s.recordSystemDNSSettings(true); err != nil {
|
err := s.recordSystemDNSSettings(true)
|
||||||
log.Errorf("Unable to get system DNS configuration")
|
log.Errorf("Unable to get system DNS configuration")
|
||||||
return fmt.Errorf("recordSystemDNSSettings(): %w", err)
|
return err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
localKey := getKeyWithInput(netbirdDNSStateKeyFormat, localSuffix)
|
localKey := getKeyWithInput(netbirdDNSStateKeyFormat, localSuffix)
|
||||||
if s.systemDNSSettings.ServerIP.IsValid() && len(s.systemDNSSettings.Domains) != 0 {
|
if s.systemDNSSettings.ServerIP.IsValid() && len(s.systemDNSSettings.Domains) != 0 {
|
||||||
|
|||||||
@@ -64,10 +64,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type registryConfigurator struct {
|
type registryConfigurator struct {
|
||||||
guid string
|
guid string
|
||||||
routingAll bool
|
routingAll bool
|
||||||
gpo bool
|
gpo bool
|
||||||
nrptEntryCount int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHostManager(wgInterface WGIface) (*registryConfigurator, error) {
|
func newHostManager(wgInterface WGIface) (*registryConfigurator, error) {
|
||||||
@@ -178,11 +177,7 @@ func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig, stateManager
|
|||||||
log.Infof("removed %s as main DNS forwarder for this peer", config.ServerIP)
|
log.Infof("removed %s as main DNS forwarder for this peer", config.ServerIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateManager.UpdateState(&ShutdownState{
|
if err := stateManager.UpdateState(&ShutdownState{Guid: r.guid, GPO: r.gpo}); err != nil {
|
||||||
Guid: r.guid,
|
|
||||||
GPO: r.gpo,
|
|
||||||
NRPTEntryCount: r.nrptEntryCount,
|
|
||||||
}); err != nil {
|
|
||||||
log.Errorf("failed to update shutdown state: %s", err)
|
log.Errorf("failed to update shutdown state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,24 +193,13 @@ func (r *registryConfigurator) applyDNSConfig(config HostDNSConfig, stateManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(matchDomains) != 0 {
|
if len(matchDomains) != 0 {
|
||||||
count, err := r.addDNSMatchPolicy(matchDomains, config.ServerIP)
|
if err := r.addDNSMatchPolicy(matchDomains, config.ServerIP); err != nil {
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("add dns match policy: %w", err)
|
return fmt.Errorf("add dns match policy: %w", err)
|
||||||
}
|
}
|
||||||
r.nrptEntryCount = count
|
|
||||||
} else {
|
} else {
|
||||||
if err := r.removeDNSMatchPolicies(); err != nil {
|
if err := r.removeDNSMatchPolicies(); err != nil {
|
||||||
return fmt.Errorf("remove dns match policies: %w", err)
|
return fmt.Errorf("remove dns match policies: %w", err)
|
||||||
}
|
}
|
||||||
r.nrptEntryCount = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := stateManager.UpdateState(&ShutdownState{
|
|
||||||
Guid: r.guid,
|
|
||||||
GPO: r.gpo,
|
|
||||||
NRPTEntryCount: r.nrptEntryCount,
|
|
||||||
}); err != nil {
|
|
||||||
log.Errorf("failed to update shutdown state: %s", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.updateSearchDomains(searchDomains); err != nil {
|
if err := r.updateSearchDomains(searchDomains); err != nil {
|
||||||
@@ -236,34 +220,28 @@ func (r *registryConfigurator) addDNSSetupForAll(ip netip.Addr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registryConfigurator) addDNSMatchPolicy(domains []string, ip netip.Addr) (int, error) {
|
func (r *registryConfigurator) addDNSMatchPolicy(domains []string, ip netip.Addr) error {
|
||||||
// if the gpo key is present, we need to put our DNS settings there, otherwise our config might be ignored
|
// if the gpo key is present, we need to put our DNS settings there, otherwise our config might be ignored
|
||||||
// see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpnrpt/8cc31cb9-20cb-4140-9e85-3e08703b4745
|
// see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpnrpt/8cc31cb9-20cb-4140-9e85-3e08703b4745
|
||||||
for i, domain := range domains {
|
|
||||||
policyPath := fmt.Sprintf("%s-%d", dnsPolicyConfigMatchPath, i)
|
|
||||||
if r.gpo {
|
|
||||||
policyPath = fmt.Sprintf("%s-%d", gpoDnsPolicyConfigMatchPath, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
singleDomain := []string{domain}
|
|
||||||
|
|
||||||
if err := r.configureDNSPolicy(policyPath, singleDomain, ip); err != nil {
|
|
||||||
return i, fmt.Errorf("configure DNS policy for domain %s: %w", domain, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("added NRPT entry for domain: %s", domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.gpo {
|
if r.gpo {
|
||||||
|
if err := r.configureDNSPolicy(gpoDnsPolicyConfigMatchPath, domains, ip); err != nil {
|
||||||
|
return fmt.Errorf("configure GPO DNS policy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := refreshGroupPolicy(); err != nil {
|
if err := refreshGroupPolicy(); err != nil {
|
||||||
log.Warnf("failed to refresh group policy: %v", err)
|
log.Warnf("failed to refresh group policy: %v", err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if err := r.configureDNSPolicy(dnsPolicyConfigMatchPath, domains, ip); err != nil {
|
||||||
|
return fmt.Errorf("configure local DNS policy: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("added %d separate NRPT entries. Domain list: %s", len(domains), domains)
|
log.Infof("added %d match domains. Domain list: %s", len(domains), domains)
|
||||||
return len(domains), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configureDNSPolicy handles the actual configuration of a DNS policy at the specified path
|
||||||
func (r *registryConfigurator) configureDNSPolicy(policyPath string, domains []string, ip netip.Addr) error {
|
func (r *registryConfigurator) configureDNSPolicy(policyPath string, domains []string, ip netip.Addr) error {
|
||||||
if err := removeRegistryKeyFromDNSPolicyConfig(policyPath); err != nil {
|
if err := removeRegistryKeyFromDNSPolicyConfig(policyPath); err != nil {
|
||||||
return fmt.Errorf("remove existing dns policy: %w", err)
|
return fmt.Errorf("remove existing dns policy: %w", err)
|
||||||
@@ -396,25 +374,12 @@ func (r *registryConfigurator) restoreHostDNS() error {
|
|||||||
|
|
||||||
func (r *registryConfigurator) removeDNSMatchPolicies() error {
|
func (r *registryConfigurator) removeDNSMatchPolicies() error {
|
||||||
var merr *multierror.Error
|
var merr *multierror.Error
|
||||||
|
|
||||||
// Try to remove the base entries (for backward compatibility)
|
|
||||||
if err := removeRegistryKeyFromDNSPolicyConfig(dnsPolicyConfigMatchPath); err != nil {
|
if err := removeRegistryKeyFromDNSPolicyConfig(dnsPolicyConfigMatchPath); err != nil {
|
||||||
merr = multierror.Append(merr, fmt.Errorf("remove local base entry: %w", err))
|
merr = multierror.Append(merr, fmt.Errorf("remove local registry key: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := removeRegistryKeyFromDNSPolicyConfig(gpoDnsPolicyConfigMatchPath); err != nil {
|
if err := removeRegistryKeyFromDNSPolicyConfig(gpoDnsPolicyConfigMatchPath); err != nil {
|
||||||
merr = multierror.Append(merr, fmt.Errorf("remove GPO base entry: %w", err))
|
merr = multierror.Append(merr, fmt.Errorf("remove GPO registry key: %w", err))
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < r.nrptEntryCount; i++ {
|
|
||||||
localPath := fmt.Sprintf("%s-%d", dnsPolicyConfigMatchPath, i)
|
|
||||||
gpoPath := fmt.Sprintf("%s-%d", gpoDnsPolicyConfigMatchPath, i)
|
|
||||||
|
|
||||||
if err := removeRegistryKeyFromDNSPolicyConfig(localPath); err != nil {
|
|
||||||
merr = multierror.Append(merr, fmt.Errorf("remove local entry %d: %w", i, err))
|
|
||||||
}
|
|
||||||
if err := removeRegistryKeyFromDNSPolicyConfig(gpoPath); err != nil {
|
|
||||||
merr = multierror.Append(merr, fmt.Errorf("remove GPO entry %d: %w", i, err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := refreshGroupPolicy(); err != nil {
|
if err := refreshGroupPolicy(); err != nil {
|
||||||
|
|||||||
@@ -695,12 +695,6 @@ func (s *DefaultServer) createHandlersForDomainGroup(domainGroup nsGroupsByDomai
|
|||||||
ns.IP.String(), ns.NSType.String(), nbdns.UDPNameServerType.String())
|
ns.IP.String(), ns.NSType.String(), nbdns.UDPNameServerType.String())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ns.IP == s.service.RuntimeIP() {
|
|
||||||
log.Warnf("skipping nameserver %s as it matches our DNS server IP, preventing potential loop", ns.IP)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.upstreamServers = append(handler.upstreamServers, ns.AddrPort())
|
handler.upstreamServers = append(handler.upstreamServers, ns.AddrPort())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2056,124 +2056,3 @@ func TestLocalResolverPriorityConstants(t *testing.T) {
|
|||||||
assert.Equal(t, PriorityLocal, localMuxUpdates[0].priority, "Local handler should use PriorityLocal")
|
assert.Equal(t, PriorityLocal, localMuxUpdates[0].priority, "Local handler should use PriorityLocal")
|
||||||
assert.Equal(t, "local.example.com", localMuxUpdates[0].domain)
|
assert.Equal(t, "local.example.com", localMuxUpdates[0].domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDNSLoopPrevention(t *testing.T) {
|
|
||||||
wgInterface := &mocWGIface{}
|
|
||||||
service := NewServiceViaMemory(wgInterface)
|
|
||||||
dnsServerIP := service.RuntimeIP()
|
|
||||||
|
|
||||||
server := &DefaultServer{
|
|
||||||
ctx: context.Background(),
|
|
||||||
wgInterface: wgInterface,
|
|
||||||
service: service,
|
|
||||||
localResolver: local.NewResolver(),
|
|
||||||
handlerChain: NewHandlerChain(),
|
|
||||||
hostManager: &noopHostConfigurator{},
|
|
||||||
dnsMuxMap: make(registeredHandlerMap),
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
nsGroups []*nbdns.NameServerGroup
|
|
||||||
expectedHandlers int
|
|
||||||
expectedServers []netip.Addr
|
|
||||||
shouldFilterOwnIP bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "FilterOwnDNSServerIP",
|
|
||||||
nsGroups: []*nbdns.NameServerGroup{
|
|
||||||
{
|
|
||||||
Primary: true,
|
|
||||||
NameServers: []nbdns.NameServer{
|
|
||||||
{IP: netip.MustParseAddr("8.8.8.8"), NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
{IP: dnsServerIP, NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
{IP: netip.MustParseAddr("1.1.1.1"), NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
},
|
|
||||||
Domains: []string{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedHandlers: 1,
|
|
||||||
expectedServers: []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("1.1.1.1")},
|
|
||||||
shouldFilterOwnIP: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "AllServersFiltered",
|
|
||||||
nsGroups: []*nbdns.NameServerGroup{
|
|
||||||
{
|
|
||||||
Primary: false,
|
|
||||||
NameServers: []nbdns.NameServer{
|
|
||||||
{IP: dnsServerIP, NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
},
|
|
||||||
Domains: []string{"example.com"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedHandlers: 0,
|
|
||||||
expectedServers: []netip.Addr{},
|
|
||||||
shouldFilterOwnIP: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "MixedServersWithOwnIP",
|
|
||||||
nsGroups: []*nbdns.NameServerGroup{
|
|
||||||
{
|
|
||||||
Primary: false,
|
|
||||||
NameServers: []nbdns.NameServer{
|
|
||||||
{IP: netip.MustParseAddr("8.8.8.8"), NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
{IP: dnsServerIP, NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
{IP: netip.MustParseAddr("1.1.1.1"), NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
{IP: dnsServerIP, NSType: nbdns.UDPNameServerType, Port: 53}, // duplicate
|
|
||||||
},
|
|
||||||
Domains: []string{"test.com"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedHandlers: 1,
|
|
||||||
expectedServers: []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("1.1.1.1")},
|
|
||||||
shouldFilterOwnIP: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "NoOwnIPInList",
|
|
||||||
nsGroups: []*nbdns.NameServerGroup{
|
|
||||||
{
|
|
||||||
Primary: true,
|
|
||||||
NameServers: []nbdns.NameServer{
|
|
||||||
{IP: netip.MustParseAddr("8.8.8.8"), NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
{IP: netip.MustParseAddr("1.1.1.1"), NSType: nbdns.UDPNameServerType, Port: 53},
|
|
||||||
},
|
|
||||||
Domains: []string{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedHandlers: 1,
|
|
||||||
expectedServers: []netip.Addr{netip.MustParseAddr("8.8.8.8"), netip.MustParseAddr("1.1.1.1")},
|
|
||||||
shouldFilterOwnIP: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
muxUpdates, err := server.buildUpstreamHandlerUpdate(tt.nsGroups)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, muxUpdates, tt.expectedHandlers)
|
|
||||||
|
|
||||||
if tt.expectedHandlers > 0 {
|
|
||||||
handler := muxUpdates[0].handler.(*upstreamResolver)
|
|
||||||
assert.Len(t, handler.upstreamServers, len(tt.expectedServers))
|
|
||||||
|
|
||||||
if tt.shouldFilterOwnIP {
|
|
||||||
for _, upstream := range handler.upstreamServers {
|
|
||||||
assert.NotEqual(t, dnsServerIP, upstream.Addr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, expected := range tt.expectedServers {
|
|
||||||
found := false
|
|
||||||
for _, upstream := range handler.upstreamServers {
|
|
||||||
if upstream.Addr() == expected {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert.True(t, found, "Expected server %s not found", expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ShutdownState struct {
|
type ShutdownState struct {
|
||||||
Guid string
|
Guid string
|
||||||
GPO bool
|
GPO bool
|
||||||
NRPTEntryCount int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShutdownState) Name() string {
|
func (s *ShutdownState) Name() string {
|
||||||
@@ -16,9 +15,8 @@ func (s *ShutdownState) Name() string {
|
|||||||
|
|
||||||
func (s *ShutdownState) Cleanup() error {
|
func (s *ShutdownState) Cleanup() error {
|
||||||
manager := ®istryConfigurator{
|
manager := ®istryConfigurator{
|
||||||
guid: s.Guid,
|
guid: s.Guid,
|
||||||
gpo: s.GPO,
|
gpo: s.GPO,
|
||||||
nrptEntryCount: s.NRPTEntryCount,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := manager.restoreUncleanShutdownDNS(); err != nil {
|
if err := manager.restoreUncleanShutdownDNS(); err != nil {
|
||||||
|
|||||||
@@ -26,12 +26,6 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/proto"
|
"github.com/netbirdio/netbird/client/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var currentMTU uint16 = iface.DefaultMTU
|
|
||||||
|
|
||||||
func SetCurrentMTU(mtu uint16) {
|
|
||||||
currentMTU = mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UpstreamTimeout = 15 * time.Second
|
UpstreamTimeout = 15 * time.Second
|
||||||
|
|
||||||
@@ -364,8 +358,8 @@ func (u *upstreamResolverBase) testNameserver(server netip.AddrPort, timeout tim
|
|||||||
// If the passed context is nil, this will use Exchange instead of ExchangeContext.
|
// If the passed context is nil, this will use Exchange instead of ExchangeContext.
|
||||||
func ExchangeWithFallback(ctx context.Context, client *dns.Client, r *dns.Msg, upstream string) (*dns.Msg, time.Duration, error) {
|
func ExchangeWithFallback(ctx context.Context, client *dns.Client, r *dns.Msg, upstream string) (*dns.Msg, time.Duration, error) {
|
||||||
// MTU - ip + udp headers
|
// MTU - ip + udp headers
|
||||||
// Note: this could be sent out on an interface that is not ours, but higher MTU settings could break truncation handling.
|
// Note: this could be sent out on an interface that is not ours, but our MTU should always be lower.
|
||||||
client.UDPSize = uint16(currentMTU - (60 + 8))
|
client.UDPSize = iface.DefaultMTU - (60 + 8)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
rm *dns.Msg
|
rm *dns.Msg
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func (f *DNSForwarder) handleDNSQuery(w dns.ResponseWriter, query *dns.Msg) *dns
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
ips, err := f.resolver.LookupNetIP(ctx, network, domain)
|
ips, err := f.resolver.LookupNetIP(ctx, network, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.handleDNSError(ctx, w, question, resp, domain, err)
|
f.handleDNSError(w, query, resp, domain, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,57 +244,20 @@ func (f *DNSForwarder) updateFirewall(matchingEntries []*ForwarderEntry, prefixe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setResponseCodeForNotFound determines and sets the appropriate response code when IsNotFound is true
|
|
||||||
// It distinguishes between NXDOMAIN (domain doesn't exist) and NODATA (domain exists but no records of requested type)
|
|
||||||
//
|
|
||||||
// LIMITATION: This function only checks A and AAAA record types to determine domain existence.
|
|
||||||
// If a domain has only other record types (MX, TXT, CNAME, etc.) but no A/AAAA records,
|
|
||||||
// it may incorrectly return NXDOMAIN instead of NODATA. This is acceptable since the forwarder
|
|
||||||
// only handles A/AAAA queries and returns NOTIMP for other types.
|
|
||||||
func (f *DNSForwarder) setResponseCodeForNotFound(ctx context.Context, resp *dns.Msg, domain string, originalQtype uint16) {
|
|
||||||
// Try querying for a different record type to see if the domain exists
|
|
||||||
// If the original query was for AAAA, try A. If it was for A, try AAAA.
|
|
||||||
// This helps distinguish between NXDOMAIN and NODATA.
|
|
||||||
var alternativeNetwork string
|
|
||||||
switch originalQtype {
|
|
||||||
case dns.TypeAAAA:
|
|
||||||
alternativeNetwork = "ip4"
|
|
||||||
case dns.TypeA:
|
|
||||||
alternativeNetwork = "ip6"
|
|
||||||
default:
|
|
||||||
resp.Rcode = dns.RcodeNameError
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := f.resolver.LookupNetIP(ctx, alternativeNetwork, domain); err != nil {
|
|
||||||
var dnsErr *net.DNSError
|
|
||||||
if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
|
|
||||||
// Alternative query also returned not found - domain truly doesn't exist
|
|
||||||
resp.Rcode = dns.RcodeNameError
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Some other error (timeout, server failure, etc.) - can't determine, assume domain exists
|
|
||||||
resp.Rcode = dns.RcodeSuccess
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alternative query succeeded - domain exists but has no records of this type
|
|
||||||
resp.Rcode = dns.RcodeSuccess
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleDNSError processes DNS lookup errors and sends an appropriate error response
|
// handleDNSError processes DNS lookup errors and sends an appropriate error response
|
||||||
func (f *DNSForwarder) handleDNSError(ctx context.Context, w dns.ResponseWriter, question dns.Question, resp *dns.Msg, domain string, err error) {
|
func (f *DNSForwarder) handleDNSError(w dns.ResponseWriter, query, resp *dns.Msg, domain string, err error) {
|
||||||
var dnsErr *net.DNSError
|
var dnsErr *net.DNSError
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errors.As(err, &dnsErr):
|
case errors.As(err, &dnsErr):
|
||||||
resp.Rcode = dns.RcodeServerFailure
|
resp.Rcode = dns.RcodeServerFailure
|
||||||
if dnsErr.IsNotFound {
|
if dnsErr.IsNotFound {
|
||||||
f.setResponseCodeForNotFound(ctx, resp, domain, question.Qtype)
|
// Pass through NXDOMAIN
|
||||||
|
resp.Rcode = dns.RcodeNameError
|
||||||
}
|
}
|
||||||
|
|
||||||
if dnsErr.Server != "" {
|
if dnsErr.Server != "" {
|
||||||
log.Warnf("failed to resolve query for type=%s domain=%s server=%s: %v", dns.TypeToString[question.Qtype], domain, dnsErr.Server, err)
|
log.Warnf("failed to resolve query for type=%s domain=%s server=%s: %v", dns.TypeToString[query.Question[0].Qtype], domain, dnsErr.Server, err)
|
||||||
} else {
|
} else {
|
||||||
log.Warnf(errResolveFailed, domain, err)
|
log.Warnf(errResolveFailed, domain, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package dnsfwd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -17,8 +16,8 @@ import (
|
|||||||
firewall "github.com/netbirdio/netbird/client/firewall/manager"
|
firewall "github.com/netbirdio/netbird/client/firewall/manager"
|
||||||
"github.com/netbirdio/netbird/client/internal/dns/test"
|
"github.com/netbirdio/netbird/client/internal/dns/test"
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
"github.com/netbirdio/netbird/route"
|
|
||||||
"github.com/netbirdio/netbird/shared/management/domain"
|
"github.com/netbirdio/netbird/shared/management/domain"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_getMatchingEntries(t *testing.T) {
|
func Test_getMatchingEntries(t *testing.T) {
|
||||||
@@ -709,131 +708,6 @@ func TestDNSForwarder_MultipleOverlappingPatterns(t *testing.T) {
|
|||||||
assert.Len(t, matches, 3, "Should match 3 patterns")
|
assert.Len(t, matches, 3, "Should match 3 patterns")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDNSForwarder_NodataVsNxdomain tests that the forwarder correctly distinguishes
|
|
||||||
// between NXDOMAIN (domain doesn't exist) and NODATA (domain exists but no records of that type)
|
|
||||||
func TestDNSForwarder_NodataVsNxdomain(t *testing.T) {
|
|
||||||
mockFirewall := &MockFirewall{}
|
|
||||||
mockResolver := &MockResolver{}
|
|
||||||
|
|
||||||
forwarder := NewDNSForwarder("127.0.0.1:0", 300, mockFirewall, &peer.Status{})
|
|
||||||
forwarder.resolver = mockResolver
|
|
||||||
|
|
||||||
d, err := domain.FromString("example.com")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
set := firewall.NewDomainSet([]domain.Domain{d})
|
|
||||||
entries := []*ForwarderEntry{{Domain: d, ResID: "test-res", Set: set}}
|
|
||||||
forwarder.UpdateDomains(entries)
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
queryType uint16
|
|
||||||
setupMocks func()
|
|
||||||
expectedCode int
|
|
||||||
expectNoAnswer bool // true if we expect NOERROR with empty answer (NODATA case)
|
|
||||||
description string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "domain exists but no AAAA records (NODATA)",
|
|
||||||
queryType: dns.TypeAAAA,
|
|
||||||
setupMocks: func() {
|
|
||||||
// First query for AAAA returns not found
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip6", "example.com.").
|
|
||||||
Return([]netip.Addr{}, &net.DNSError{IsNotFound: true, Name: "example.com"}).Once()
|
|
||||||
// Check query for A records succeeds (domain exists)
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip4", "example.com.").
|
|
||||||
Return([]netip.Addr{netip.MustParseAddr("1.2.3.4")}, nil).Once()
|
|
||||||
},
|
|
||||||
expectedCode: dns.RcodeSuccess,
|
|
||||||
expectNoAnswer: true,
|
|
||||||
description: "Should return NOERROR when domain exists but has no records of requested type",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "domain exists but no A records (NODATA)",
|
|
||||||
queryType: dns.TypeA,
|
|
||||||
setupMocks: func() {
|
|
||||||
// First query for A returns not found
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip4", "example.com.").
|
|
||||||
Return([]netip.Addr{}, &net.DNSError{IsNotFound: true, Name: "example.com"}).Once()
|
|
||||||
// Check query for AAAA records succeeds (domain exists)
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip6", "example.com.").
|
|
||||||
Return([]netip.Addr{netip.MustParseAddr("2001:db8::1")}, nil).Once()
|
|
||||||
},
|
|
||||||
expectedCode: dns.RcodeSuccess,
|
|
||||||
expectNoAnswer: true,
|
|
||||||
description: "Should return NOERROR when domain exists but has no A records",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "domain doesn't exist (NXDOMAIN)",
|
|
||||||
queryType: dns.TypeA,
|
|
||||||
setupMocks: func() {
|
|
||||||
// First query for A returns not found
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip4", "example.com.").
|
|
||||||
Return([]netip.Addr{}, &net.DNSError{IsNotFound: true, Name: "example.com"}).Once()
|
|
||||||
// Check query for AAAA also returns not found (domain doesn't exist)
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip6", "example.com.").
|
|
||||||
Return([]netip.Addr{}, &net.DNSError{IsNotFound: true, Name: "example.com"}).Once()
|
|
||||||
},
|
|
||||||
expectedCode: dns.RcodeNameError,
|
|
||||||
expectNoAnswer: true,
|
|
||||||
description: "Should return NXDOMAIN when domain doesn't exist at all",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "domain exists with records (normal success)",
|
|
||||||
queryType: dns.TypeA,
|
|
||||||
setupMocks: func() {
|
|
||||||
mockResolver.On("LookupNetIP", mock.Anything, "ip4", "example.com.").
|
|
||||||
Return([]netip.Addr{netip.MustParseAddr("1.2.3.4")}, nil).Once()
|
|
||||||
// Expect firewall update for successful resolution
|
|
||||||
expectedPrefix := netip.PrefixFrom(netip.MustParseAddr("1.2.3.4"), 32)
|
|
||||||
mockFirewall.On("UpdateSet", set, []netip.Prefix{expectedPrefix}).Return(nil).Once()
|
|
||||||
},
|
|
||||||
expectedCode: dns.RcodeSuccess,
|
|
||||||
expectNoAnswer: false,
|
|
||||||
description: "Should return NOERROR with answer when records exist",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// Reset mock expectations
|
|
||||||
mockResolver.ExpectedCalls = nil
|
|
||||||
mockResolver.Calls = nil
|
|
||||||
mockFirewall.ExpectedCalls = nil
|
|
||||||
mockFirewall.Calls = nil
|
|
||||||
|
|
||||||
tt.setupMocks()
|
|
||||||
|
|
||||||
query := &dns.Msg{}
|
|
||||||
query.SetQuestion(dns.Fqdn("example.com"), tt.queryType)
|
|
||||||
|
|
||||||
var writtenResp *dns.Msg
|
|
||||||
mockWriter := &test.MockResponseWriter{
|
|
||||||
WriteMsgFunc: func(m *dns.Msg) error {
|
|
||||||
writtenResp = m
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
resp := forwarder.handleDNSQuery(mockWriter, query)
|
|
||||||
|
|
||||||
// If a response was returned, it means it should be written (happens in wrapper functions)
|
|
||||||
if resp != nil && writtenResp == nil {
|
|
||||||
writtenResp = resp
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotNil(t, writtenResp, "Expected response to be written")
|
|
||||||
assert.Equal(t, tt.expectedCode, writtenResp.Rcode, tt.description)
|
|
||||||
|
|
||||||
if tt.expectNoAnswer {
|
|
||||||
assert.Empty(t, writtenResp.Answer, "Response should have no answer records")
|
|
||||||
}
|
|
||||||
|
|
||||||
mockResolver.AssertExpectations(t)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDNSForwarder_EmptyQuery(t *testing.T) {
|
func TestDNSForwarder_EmptyQuery(t *testing.T) {
|
||||||
// Test handling of malformed query with no questions
|
// Test handling of malformed query with no questions
|
||||||
forwarder := NewDNSForwarder("127.0.0.1:0", 300, nil, &peer.Status{})
|
forwarder := NewDNSForwarder("127.0.0.1:0", 300, nil, &peer.Status{})
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ import (
|
|||||||
nbssh "github.com/netbirdio/netbird/client/ssh"
|
nbssh "github.com/netbirdio/netbird/client/ssh"
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/route"
|
|
||||||
mgm "github.com/netbirdio/netbird/shared/management/client"
|
mgm "github.com/netbirdio/netbird/shared/management/client"
|
||||||
mgmProto "github.com/netbirdio/netbird/shared/management/proto"
|
mgmProto "github.com/netbirdio/netbird/shared/management/proto"
|
||||||
auth "github.com/netbirdio/netbird/shared/relay/auth/hmac"
|
auth "github.com/netbirdio/netbird/shared/relay/auth/hmac"
|
||||||
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
signal "github.com/netbirdio/netbird/shared/signal/client"
|
signal "github.com/netbirdio/netbird/shared/signal/client"
|
||||||
sProto "github.com/netbirdio/netbird/shared/signal/proto"
|
sProto "github.com/netbirdio/netbird/shared/signal/proto"
|
||||||
"github.com/netbirdio/netbird/util"
|
"github.com/netbirdio/netbird/util"
|
||||||
@@ -125,8 +125,6 @@ type EngineConfig struct {
|
|||||||
BlockInbound bool
|
BlockInbound bool
|
||||||
|
|
||||||
LazyConnectionEnabled bool
|
LazyConnectionEnabled bool
|
||||||
|
|
||||||
MTU uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Engine is a mechanism responsible for reacting on Signal and Management stream events and managing connections to the remote peers.
|
// Engine is a mechanism responsible for reacting on Signal and Management stream events and managing connections to the remote peers.
|
||||||
@@ -256,7 +254,6 @@ func NewEngine(
|
|||||||
}
|
}
|
||||||
engine.stateManager = statemanager.New(path)
|
engine.stateManager = statemanager.New(path)
|
||||||
|
|
||||||
log.Infof("I am: %s", config.WgPrivateKey.PublicKey().String())
|
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,10 +346,6 @@ func (e *Engine) Start() error {
|
|||||||
e.syncMsgMux.Lock()
|
e.syncMsgMux.Lock()
|
||||||
defer e.syncMsgMux.Unlock()
|
defer e.syncMsgMux.Unlock()
|
||||||
|
|
||||||
if err := iface.ValidateMTU(e.config.MTU); err != nil {
|
|
||||||
return fmt.Errorf("invalid MTU configuration: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.cancel != nil {
|
if e.cancel != nil {
|
||||||
e.cancel()
|
e.cancel()
|
||||||
}
|
}
|
||||||
@@ -1117,16 +1110,15 @@ func toRoutes(protoRoutes []*mgmProto.Route) []*route.Route {
|
|||||||
}
|
}
|
||||||
|
|
||||||
convertedRoute := &route.Route{
|
convertedRoute := &route.Route{
|
||||||
ID: route.ID(protoRoute.ID),
|
ID: route.ID(protoRoute.ID),
|
||||||
Network: prefix.Masked(),
|
Network: prefix.Masked(),
|
||||||
Domains: domain.FromPunycodeList(protoRoute.Domains),
|
Domains: domain.FromPunycodeList(protoRoute.Domains),
|
||||||
NetID: route.NetID(protoRoute.NetID),
|
NetID: route.NetID(protoRoute.NetID),
|
||||||
NetworkType: route.NetworkType(protoRoute.NetworkType),
|
NetworkType: route.NetworkType(protoRoute.NetworkType),
|
||||||
Peer: protoRoute.Peer,
|
Peer: protoRoute.Peer,
|
||||||
Metric: int(protoRoute.Metric),
|
Metric: int(protoRoute.Metric),
|
||||||
Masquerade: protoRoute.Masquerade,
|
Masquerade: protoRoute.Masquerade,
|
||||||
KeepRoute: protoRoute.KeepRoute,
|
KeepRoute: protoRoute.KeepRoute,
|
||||||
SkipAutoApply: protoRoute.SkipAutoApply,
|
|
||||||
}
|
}
|
||||||
routes = append(routes, convertedRoute)
|
routes = append(routes, convertedRoute)
|
||||||
}
|
}
|
||||||
@@ -1338,17 +1330,52 @@ func (e *Engine) receiveSignalEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch msg.GetBody().Type {
|
switch msg.GetBody().Type {
|
||||||
case sProto.Body_OFFER, sProto.Body_ANSWER:
|
case sProto.Body_OFFER:
|
||||||
offerAnswer, err := convertToOfferAnswer(msg)
|
remoteCred, err := signal.UnMarshalCredential(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Body.Type == sProto.Body_OFFER {
|
var rosenpassPubKey []byte
|
||||||
conn.OnRemoteOffer(*offerAnswer)
|
rosenpassAddr := ""
|
||||||
} else {
|
if msg.GetBody().GetRosenpassConfig() != nil {
|
||||||
conn.OnRemoteAnswer(*offerAnswer)
|
rosenpassPubKey = msg.GetBody().GetRosenpassConfig().GetRosenpassPubKey()
|
||||||
|
rosenpassAddr = msg.GetBody().GetRosenpassConfig().GetRosenpassServerAddr()
|
||||||
}
|
}
|
||||||
|
conn.OnRemoteOffer(peer.OfferAnswer{
|
||||||
|
IceCredentials: peer.IceCredentials{
|
||||||
|
UFrag: remoteCred.UFrag,
|
||||||
|
Pwd: remoteCred.Pwd,
|
||||||
|
},
|
||||||
|
WgListenPort: int(msg.GetBody().GetWgListenPort()),
|
||||||
|
Version: msg.GetBody().GetNetBirdVersion(),
|
||||||
|
RosenpassPubKey: rosenpassPubKey,
|
||||||
|
RosenpassAddr: rosenpassAddr,
|
||||||
|
RelaySrvAddress: msg.GetBody().GetRelayServerAddress(),
|
||||||
|
})
|
||||||
|
case sProto.Body_ANSWER:
|
||||||
|
remoteCred, err := signal.UnMarshalCredential(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var rosenpassPubKey []byte
|
||||||
|
rosenpassAddr := ""
|
||||||
|
if msg.GetBody().GetRosenpassConfig() != nil {
|
||||||
|
rosenpassPubKey = msg.GetBody().GetRosenpassConfig().GetRosenpassPubKey()
|
||||||
|
rosenpassAddr = msg.GetBody().GetRosenpassConfig().GetRosenpassServerAddr()
|
||||||
|
}
|
||||||
|
conn.OnRemoteAnswer(peer.OfferAnswer{
|
||||||
|
IceCredentials: peer.IceCredentials{
|
||||||
|
UFrag: remoteCred.UFrag,
|
||||||
|
Pwd: remoteCred.Pwd,
|
||||||
|
},
|
||||||
|
WgListenPort: int(msg.GetBody().GetWgListenPort()),
|
||||||
|
Version: msg.GetBody().GetNetBirdVersion(),
|
||||||
|
RosenpassPubKey: rosenpassPubKey,
|
||||||
|
RosenpassAddr: rosenpassAddr,
|
||||||
|
RelaySrvAddress: msg.GetBody().GetRelayServerAddress(),
|
||||||
|
})
|
||||||
case sProto.Body_CANDIDATE:
|
case sProto.Body_CANDIDATE:
|
||||||
candidate, err := ice.UnmarshalCandidate(msg.GetBody().Payload)
|
candidate, err := ice.UnmarshalCandidate(msg.GetBody().Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1498,7 +1525,7 @@ func (e *Engine) newWgIface() (*iface.WGIface, error) {
|
|||||||
Address: e.config.WgAddr,
|
Address: e.config.WgAddr,
|
||||||
WGPort: e.config.WgPort,
|
WGPort: e.config.WgPort,
|
||||||
WGPrivKey: e.config.WgPrivateKey.String(),
|
WGPrivKey: e.config.WgPrivateKey.String(),
|
||||||
MTU: e.config.MTU,
|
MTU: iface.DefaultMTU,
|
||||||
TransportNet: transportNet,
|
TransportNet: transportNet,
|
||||||
FilterFn: e.addrViaRoutes,
|
FilterFn: e.addrViaRoutes,
|
||||||
DisableDNS: e.config.DisableDNS,
|
DisableDNS: e.config.DisableDNS,
|
||||||
@@ -2046,44 +2073,3 @@ func createFile(path string) error {
|
|||||||
}
|
}
|
||||||
return file.Close()
|
return file.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertToOfferAnswer(msg *sProto.Message) (*peer.OfferAnswer, error) {
|
|
||||||
remoteCred, err := signal.UnMarshalCredential(msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
rosenpassPubKey []byte
|
|
||||||
rosenpassAddr string
|
|
||||||
)
|
|
||||||
if cfg := msg.GetBody().GetRosenpassConfig(); cfg != nil {
|
|
||||||
rosenpassPubKey = cfg.GetRosenpassPubKey()
|
|
||||||
rosenpassAddr = cfg.GetRosenpassServerAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle optional SessionID
|
|
||||||
var sessionID *peer.ICESessionID
|
|
||||||
if sessionBytes := msg.GetBody().GetSessionId(); sessionBytes != nil {
|
|
||||||
if id, err := peer.ICESessionIDFromBytes(sessionBytes); err != nil {
|
|
||||||
log.Warnf("Invalid session ID in message: %v", err)
|
|
||||||
sessionID = nil // Set to nil if conversion fails
|
|
||||||
} else {
|
|
||||||
sessionID = &id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offerAnswer := peer.OfferAnswer{
|
|
||||||
IceCredentials: peer.IceCredentials{
|
|
||||||
UFrag: remoteCred.UFrag,
|
|
||||||
Pwd: remoteCred.Pwd,
|
|
||||||
},
|
|
||||||
WgListenPort: int(msg.GetBody().GetWgListenPort()),
|
|
||||||
Version: msg.GetBody().GetNetBirdVersion(),
|
|
||||||
RosenpassPubKey: rosenpassPubKey,
|
|
||||||
RosenpassAddr: rosenpassAddr,
|
|
||||||
RelaySrvAddress: msg.GetBody().GetRelayServerAddress(),
|
|
||||||
SessionID: sessionID,
|
|
||||||
}
|
|
||||||
return &offerAnswer, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import (
|
|||||||
"golang.zx2c4.com/wireguard/tun/netstack"
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
||||||
|
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
"github.com/netbirdio/netbird/management/internals/server/config"
|
|
||||||
"github.com/netbirdio/netbird/management/server/groups"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface"
|
"github.com/netbirdio/netbird/client/iface"
|
||||||
"github.com/netbirdio/netbird/client/iface/bind"
|
"github.com/netbirdio/netbird/client/iface/bind"
|
||||||
@@ -45,6 +43,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/ssh"
|
"github.com/netbirdio/netbird/client/ssh"
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
|
mgmt "github.com/netbirdio/netbird/shared/management/client"
|
||||||
|
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
||||||
"github.com/netbirdio/netbird/management/server"
|
"github.com/netbirdio/netbird/management/server"
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
||||||
@@ -54,10 +54,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
"github.com/netbirdio/netbird/monotime"
|
"github.com/netbirdio/netbird/monotime"
|
||||||
"github.com/netbirdio/netbird/route"
|
|
||||||
mgmt "github.com/netbirdio/netbird/shared/management/client"
|
|
||||||
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
|
||||||
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
signal "github.com/netbirdio/netbird/shared/signal/client"
|
signal "github.com/netbirdio/netbird/shared/signal/client"
|
||||||
"github.com/netbirdio/netbird/shared/signal/proto"
|
"github.com/netbirdio/netbird/shared/signal/proto"
|
||||||
signalServer "github.com/netbirdio/netbird/signal/server"
|
signalServer "github.com/netbirdio/netbird/signal/server"
|
||||||
@@ -218,7 +216,7 @@ func TestEngine_SSH(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU)
|
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String())
|
||||||
engine := NewEngine(
|
engine := NewEngine(
|
||||||
ctx, cancel,
|
ctx, cancel,
|
||||||
&signal.MockClient{},
|
&signal.MockClient{},
|
||||||
@@ -230,7 +228,6 @@ func TestEngine_SSH(t *testing.T) {
|
|||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: 33100,
|
WgPort: 33100,
|
||||||
ServerSSHAllowed: true,
|
ServerSSHAllowed: true,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
},
|
},
|
||||||
MobileDependency{},
|
MobileDependency{},
|
||||||
peer.NewRecorder("https://mgm"),
|
peer.NewRecorder("https://mgm"),
|
||||||
@@ -364,7 +361,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU)
|
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String())
|
||||||
engine := NewEngine(
|
engine := NewEngine(
|
||||||
ctx, cancel,
|
ctx, cancel,
|
||||||
&signal.MockClient{},
|
&signal.MockClient{},
|
||||||
@@ -375,7 +372,6 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
|||||||
WgAddr: "100.64.0.1/24",
|
WgAddr: "100.64.0.1/24",
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: 33100,
|
WgPort: 33100,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
},
|
},
|
||||||
MobileDependency{},
|
MobileDependency{},
|
||||||
peer.NewRecorder("https://mgm"),
|
peer.NewRecorder("https://mgm"),
|
||||||
@@ -414,7 +410,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
engine.udpMux = bind.NewUniversalUDPMuxDefault(bind.UniversalUDPMuxParams{UDPConn: conn, MTU: 1280})
|
engine.udpMux = bind.NewUniversalUDPMuxDefault(bind.UniversalUDPMuxParams{UDPConn: conn})
|
||||||
engine.ctx = ctx
|
engine.ctx = ctx
|
||||||
engine.srWatcher = guard.NewSRWatcher(nil, nil, nil, icemaker.Config{})
|
engine.srWatcher = guard.NewSRWatcher(nil, nil, nil, icemaker.Config{})
|
||||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, wgIface)
|
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, wgIface)
|
||||||
@@ -591,13 +587,12 @@ func TestEngine_Sync(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU)
|
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String())
|
||||||
engine := NewEngine(ctx, cancel, &signal.MockClient{}, &mgmt.MockClient{SyncFunc: syncFunc}, relayMgr, &EngineConfig{
|
engine := NewEngine(ctx, cancel, &signal.MockClient{}, &mgmt.MockClient{SyncFunc: syncFunc}, relayMgr, &EngineConfig{
|
||||||
WgIfaceName: "utun103",
|
WgIfaceName: "utun103",
|
||||||
WgAddr: "100.64.0.1/24",
|
WgAddr: "100.64.0.1/24",
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: 33100,
|
WgPort: 33100,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
}, MobileDependency{}, peer.NewRecorder("https://mgm"), nil)
|
}, MobileDependency{}, peer.NewRecorder("https://mgm"), nil)
|
||||||
engine.ctx = ctx
|
engine.ctx = ctx
|
||||||
|
|
||||||
@@ -756,13 +751,12 @@ func TestEngine_UpdateNetworkMapWithRoutes(t *testing.T) {
|
|||||||
wgIfaceName := fmt.Sprintf("utun%d", 104+n)
|
wgIfaceName := fmt.Sprintf("utun%d", 104+n)
|
||||||
wgAddr := fmt.Sprintf("100.66.%d.1/24", n)
|
wgAddr := fmt.Sprintf("100.66.%d.1/24", n)
|
||||||
|
|
||||||
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU)
|
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String())
|
||||||
engine := NewEngine(ctx, cancel, &signal.MockClient{}, &mgmt.MockClient{}, relayMgr, &EngineConfig{
|
engine := NewEngine(ctx, cancel, &signal.MockClient{}, &mgmt.MockClient{}, relayMgr, &EngineConfig{
|
||||||
WgIfaceName: wgIfaceName,
|
WgIfaceName: wgIfaceName,
|
||||||
WgAddr: wgAddr,
|
WgAddr: wgAddr,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: 33100,
|
WgPort: 33100,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
}, MobileDependency{}, peer.NewRecorder("https://mgm"), nil)
|
}, MobileDependency{}, peer.NewRecorder("https://mgm"), nil)
|
||||||
engine.ctx = ctx
|
engine.ctx = ctx
|
||||||
newNet, err := stdnet.NewNet()
|
newNet, err := stdnet.NewNet()
|
||||||
@@ -958,13 +952,12 @@ func TestEngine_UpdateNetworkMapWithDNSUpdate(t *testing.T) {
|
|||||||
wgIfaceName := fmt.Sprintf("utun%d", 104+n)
|
wgIfaceName := fmt.Sprintf("utun%d", 104+n)
|
||||||
wgAddr := fmt.Sprintf("100.66.%d.1/24", n)
|
wgAddr := fmt.Sprintf("100.66.%d.1/24", n)
|
||||||
|
|
||||||
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU)
|
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String())
|
||||||
engine := NewEngine(ctx, cancel, &signal.MockClient{}, &mgmt.MockClient{}, relayMgr, &EngineConfig{
|
engine := NewEngine(ctx, cancel, &signal.MockClient{}, &mgmt.MockClient{}, relayMgr, &EngineConfig{
|
||||||
WgIfaceName: wgIfaceName,
|
WgIfaceName: wgIfaceName,
|
||||||
WgAddr: wgAddr,
|
WgAddr: wgAddr,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: 33100,
|
WgPort: 33100,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
}, MobileDependency{}, peer.NewRecorder("https://mgm"), nil)
|
}, MobileDependency{}, peer.NewRecorder("https://mgm"), nil)
|
||||||
engine.ctx = ctx
|
engine.ctx = ctx
|
||||||
|
|
||||||
@@ -1186,7 +1179,6 @@ func Test_ParseNATExternalIPMappings(t *testing.T) {
|
|||||||
config: &EngineConfig{
|
config: &EngineConfig{
|
||||||
IFaceBlackList: testCase.inputBlacklistInterface,
|
IFaceBlackList: testCase.inputBlacklistInterface,
|
||||||
NATExternalIPs: testCase.inputMapList,
|
NATExternalIPs: testCase.inputMapList,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
parsedList := engine.parseNATExternalIPMappings()
|
parsedList := engine.parseNATExternalIPMappings()
|
||||||
@@ -1487,10 +1479,9 @@ func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey strin
|
|||||||
WgAddr: resp.PeerConfig.Address,
|
WgAddr: resp.PeerConfig.Address,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
WgPort: wgPort,
|
WgPort: wgPort,
|
||||||
MTU: iface.DefaultMTU,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String(), iface.DefaultMTU)
|
relayMgr := relayClient.NewManager(ctx, nil, key.PublicKey().String())
|
||||||
e, err := NewEngine(ctx, cancel, signalClient, mgmtClient, relayMgr, conf, MobileDependency{}, peer.NewRecorder("https://mgm"), nil), nil
|
e, err := NewEngine(ctx, cancel, signalClient, mgmtClient, relayMgr, conf, MobileDependency{}, peer.NewRecorder("https://mgm"), nil), nil
|
||||||
e.ctx = ctx
|
e.ctx = ctx
|
||||||
return e, err
|
return e, err
|
||||||
@@ -1522,15 +1513,15 @@ func startSignal(t *testing.T) (*grpc.Server, string, error) {
|
|||||||
func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, string, error) {
|
func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, string, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
config := &config.Config{
|
config := &types.Config{
|
||||||
Stuns: []*config.Host{},
|
Stuns: []*types.Host{},
|
||||||
TURNConfig: &config.TURNConfig{},
|
TURNConfig: &types.TURNConfig{},
|
||||||
Relay: &config.Relay{
|
Relay: &types.Relay{
|
||||||
Addresses: []string{"127.0.0.1:1234"},
|
Addresses: []string{"127.0.0.1:1234"},
|
||||||
CredentialsTTL: util.Duration{Duration: time.Hour},
|
CredentialsTTL: util.Duration{Duration: time.Hour},
|
||||||
Secret: "222222222222222222",
|
Secret: "222222222222222222",
|
||||||
},
|
},
|
||||||
Signal: &config.Host{
|
Signal: &types.Host{
|
||||||
Proto: "http",
|
Proto: "http",
|
||||||
URI: "localhost:10000",
|
URI: "localhost:10000",
|
||||||
},
|
},
|
||||||
@@ -1573,14 +1564,13 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
|
|||||||
AnyTimes()
|
AnyTimes()
|
||||||
|
|
||||||
permissionsManager := permissions.NewManager(store)
|
permissionsManager := permissions.NewManager(store)
|
||||||
groupsManager := groups.NewManagerMock()
|
|
||||||
|
|
||||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
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 {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager, groupsManager)
|
secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager)
|
||||||
mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, &server.MockIntegratedValidator{})
|
mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, &server.MockIntegratedValidator{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/peer/id"
|
"github.com/netbirdio/netbird/client/internal/peer/id"
|
||||||
"github.com/netbirdio/netbird/client/internal/peer/worker"
|
"github.com/netbirdio/netbird/client/internal/peer/worker"
|
||||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
"github.com/netbirdio/netbird/route"
|
|
||||||
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
semaphoregroup "github.com/netbirdio/netbird/util/semaphore-group"
|
semaphoregroup "github.com/netbirdio/netbird/util/semaphore-group"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -200,11 +200,19 @@ func (conn *Conn) Open(engineCtx context.Context) error {
|
|||||||
conn.wg.Add(1)
|
conn.wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer conn.wg.Done()
|
defer conn.wg.Done()
|
||||||
|
|
||||||
conn.waitInitialRandomSleepTime(conn.ctx)
|
conn.waitInitialRandomSleepTime(conn.ctx)
|
||||||
conn.semaphore.Done(conn.ctx)
|
conn.semaphore.Done(conn.ctx)
|
||||||
|
|
||||||
conn.guard.Start(conn.ctx, conn.onGuardEvent)
|
conn.dumpState.SendOffer()
|
||||||
|
if err := conn.handshaker.sendOffer(); err != nil {
|
||||||
|
conn.Log.Errorf("failed to send initial offer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
conn.guard.Start(conn.ctx, conn.onGuardEvent)
|
||||||
|
conn.wg.Done()
|
||||||
|
}()
|
||||||
}()
|
}()
|
||||||
conn.opened = true
|
conn.opened = true
|
||||||
return nil
|
return nil
|
||||||
@@ -266,10 +274,10 @@ func (conn *Conn) Close(signalToRemote bool) {
|
|||||||
|
|
||||||
// OnRemoteAnswer handles an offer from the remote peer and returns true if the message was accepted, false otherwise
|
// OnRemoteAnswer handles an offer from the remote peer and returns true if the message was accepted, false otherwise
|
||||||
// doesn't block, discards the message if connection wasn't ready
|
// doesn't block, discards the message if connection wasn't ready
|
||||||
func (conn *Conn) OnRemoteAnswer(answer OfferAnswer) {
|
func (conn *Conn) OnRemoteAnswer(answer OfferAnswer) bool {
|
||||||
conn.dumpState.RemoteAnswer()
|
conn.dumpState.RemoteAnswer()
|
||||||
conn.Log.Infof("OnRemoteAnswer, priority: %s, status ICE: %s, status relay: %s", conn.currentConnPriority, conn.statusICE, conn.statusRelay)
|
conn.Log.Infof("OnRemoteAnswer, priority: %s, status ICE: %s, status relay: %s", conn.currentConnPriority, conn.statusICE, conn.statusRelay)
|
||||||
conn.handshaker.OnRemoteAnswer(answer)
|
return conn.handshaker.OnRemoteAnswer(answer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnRemoteCandidate Handles ICE connection Candidate provided by the remote peer.
|
// OnRemoteCandidate Handles ICE connection Candidate provided by the remote peer.
|
||||||
@@ -288,10 +296,10 @@ func (conn *Conn) SetOnDisconnected(handler func(remotePeer string)) {
|
|||||||
conn.onDisconnected = handler
|
conn.onDisconnected = handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) OnRemoteOffer(offer OfferAnswer) {
|
func (conn *Conn) OnRemoteOffer(offer OfferAnswer) bool {
|
||||||
conn.dumpState.RemoteOffer()
|
conn.dumpState.RemoteOffer()
|
||||||
conn.Log.Infof("OnRemoteOffer, on status ICE: %s, status Relay: %s", conn.statusICE, conn.statusRelay)
|
conn.Log.Infof("OnRemoteOffer, on status ICE: %s, status Relay: %s", conn.statusICE, conn.statusRelay)
|
||||||
conn.handshaker.OnRemoteOffer(offer)
|
return conn.handshaker.OnRemoteOffer(offer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WgConfig returns the WireGuard config
|
// WgConfig returns the WireGuard config
|
||||||
@@ -540,6 +548,7 @@ func (conn *Conn) onRelayDisconnected() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) onGuardEvent() {
|
func (conn *Conn) onGuardEvent() {
|
||||||
|
conn.Log.Debugf("send offer to peer")
|
||||||
conn.dumpState.SendOffer()
|
conn.dumpState.SendOffer()
|
||||||
if err := conn.handshaker.SendOffer(); err != nil {
|
if err := conn.handshaker.SendOffer(); err != nil {
|
||||||
conn.Log.Errorf("failed to send offer: %v", err)
|
conn.Log.Errorf("failed to send offer: %v", err)
|
||||||
@@ -663,7 +672,7 @@ func (conn *Conn) isConnectedOnAllWay() (connected bool) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if conn.statusICE.Get() == worker.StatusDisconnected && !conn.workerICE.InProgress() {
|
if conn.statusICE.Get() == worker.StatusDisconnected {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package peer
|
package peer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -79,30 +79,31 @@ func TestConn_OnRemoteOffer(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewOffeChan := make(chan struct{})
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
<-conn.handshaker.remoteOffersCh
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
conn.handshaker.AddOnNewOfferListener(func(remoteOfferAnswer *OfferAnswer) {
|
go func() {
|
||||||
onNewOffeChan <- struct{}{}
|
for {
|
||||||
})
|
accepted := conn.OnRemoteOffer(OfferAnswer{
|
||||||
|
IceCredentials: IceCredentials{
|
||||||
|
UFrag: "test",
|
||||||
|
Pwd: "test",
|
||||||
|
},
|
||||||
|
WgListenPort: 0,
|
||||||
|
Version: "",
|
||||||
|
})
|
||||||
|
if accepted {
|
||||||
|
wg.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
conn.OnRemoteOffer(OfferAnswer{
|
wg.Wait()
|
||||||
IceCredentials: IceCredentials{
|
|
||||||
UFrag: "test",
|
|
||||||
Pwd: "test",
|
|
||||||
},
|
|
||||||
WgListenPort: 0,
|
|
||||||
Version: "",
|
|
||||||
})
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-onNewOffeChan:
|
|
||||||
// success
|
|
||||||
case <-ctx.Done():
|
|
||||||
t.Error("expected to receive a new offer notification, but timed out")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConn_OnRemoteAnswer(t *testing.T) {
|
func TestConn_OnRemoteAnswer(t *testing.T) {
|
||||||
@@ -118,29 +119,31 @@ func TestConn_OnRemoteAnswer(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewOffeChan := make(chan struct{})
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
<-conn.handshaker.remoteAnswerCh
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
conn.handshaker.AddOnNewOfferListener(func(remoteOfferAnswer *OfferAnswer) {
|
go func() {
|
||||||
onNewOffeChan <- struct{}{}
|
for {
|
||||||
})
|
accepted := conn.OnRemoteAnswer(OfferAnswer{
|
||||||
|
IceCredentials: IceCredentials{
|
||||||
|
UFrag: "test",
|
||||||
|
Pwd: "test",
|
||||||
|
},
|
||||||
|
WgListenPort: 0,
|
||||||
|
Version: "",
|
||||||
|
})
|
||||||
|
if accepted {
|
||||||
|
wg.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
conn.OnRemoteAnswer(OfferAnswer{
|
wg.Wait()
|
||||||
IceCredentials: IceCredentials{
|
|
||||||
UFrag: "test",
|
|
||||||
Pwd: "test",
|
|
||||||
},
|
|
||||||
WgListenPort: 0,
|
|
||||||
Version: "",
|
|
||||||
})
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-onNewOffeChan:
|
|
||||||
// success
|
|
||||||
case <-ctx.Done():
|
|
||||||
t.Error("expected to receive a new offer notification, but timed out")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConn_presharedKey(t *testing.T) {
|
func TestConn_presharedKey(t *testing.T) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type isConnectedFunc func() bool
|
|||||||
// - Relayed connection disconnected
|
// - Relayed connection disconnected
|
||||||
// - ICE candidate changes
|
// - ICE candidate changes
|
||||||
type Guard struct {
|
type Guard struct {
|
||||||
|
Reconnect chan struct{}
|
||||||
log *log.Entry
|
log *log.Entry
|
||||||
isConnectedOnAllWay isConnectedFunc
|
isConnectedOnAllWay isConnectedFunc
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
@@ -29,6 +30,7 @@ type Guard struct {
|
|||||||
|
|
||||||
func NewGuard(log *log.Entry, isConnectedFn isConnectedFunc, timeout time.Duration, srWatcher *SRWatcher) *Guard {
|
func NewGuard(log *log.Entry, isConnectedFn isConnectedFunc, timeout time.Duration, srWatcher *SRWatcher) *Guard {
|
||||||
return &Guard{
|
return &Guard{
|
||||||
|
Reconnect: make(chan struct{}, 1),
|
||||||
log: log,
|
log: log,
|
||||||
isConnectedOnAllWay: isConnectedFn,
|
isConnectedOnAllWay: isConnectedFn,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
@@ -39,7 +41,6 @@ func NewGuard(log *log.Entry, isConnectedFn isConnectedFunc, timeout time.Durati
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) Start(ctx context.Context, eventCallback func()) {
|
func (g *Guard) Start(ctx context.Context, eventCallback func()) {
|
||||||
g.log.Infof("starting guard for reconnection with MaxInterval: %s", g.timeout)
|
|
||||||
g.reconnectLoopWithRetry(ctx, eventCallback)
|
g.reconnectLoopWithRetry(ctx, eventCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,14 +61,17 @@ func (g *Guard) SetICEConnDisconnected() {
|
|||||||
// reconnectLoopWithRetry periodically check the connection status.
|
// reconnectLoopWithRetry periodically check the connection status.
|
||||||
// Try to send offer while the P2P is not established or while the Relay is not connected if is it supported
|
// Try to send offer while the P2P is not established or while the Relay is not connected if is it supported
|
||||||
func (g *Guard) reconnectLoopWithRetry(ctx context.Context, callback func()) {
|
func (g *Guard) reconnectLoopWithRetry(ctx context.Context, callback func()) {
|
||||||
|
waitForInitialConnectionTry(ctx)
|
||||||
|
|
||||||
srReconnectedChan := g.srWatcher.NewListener()
|
srReconnectedChan := g.srWatcher.NewListener()
|
||||||
defer g.srWatcher.RemoveListener(srReconnectedChan)
|
defer g.srWatcher.RemoveListener(srReconnectedChan)
|
||||||
|
|
||||||
ticker := g.initialTicker(ctx)
|
ticker := g.prepareExponentTicker(ctx)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
tickerChannel := ticker.C
|
tickerChannel := ticker.C
|
||||||
|
|
||||||
|
g.log.Infof("start reconnect loop...")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case t := <-tickerChannel:
|
case t := <-tickerChannel:
|
||||||
@@ -81,6 +85,7 @@ func (g *Guard) reconnectLoopWithRetry(ctx context.Context, callback func()) {
|
|||||||
if !g.isConnectedOnAllWay() {
|
if !g.isConnectedOnAllWay() {
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-g.relayedConnDisconnected:
|
case <-g.relayedConnDisconnected:
|
||||||
g.log.Debugf("Relay connection changed, reset reconnection ticker")
|
g.log.Debugf("Relay connection changed, reset reconnection ticker")
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
@@ -106,20 +111,6 @@ func (g *Guard) reconnectLoopWithRetry(ctx context.Context, callback func()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialTicker give chance to the peer to establish the initial connection.
|
|
||||||
func (g *Guard) initialTicker(ctx context.Context) *backoff.Ticker {
|
|
||||||
bo := backoff.WithContext(&backoff.ExponentialBackOff{
|
|
||||||
InitialInterval: 3 * time.Second,
|
|
||||||
RandomizationFactor: 0.1,
|
|
||||||
Multiplier: 2,
|
|
||||||
MaxInterval: g.timeout,
|
|
||||||
Stop: backoff.Stop,
|
|
||||||
Clock: backoff.SystemClock,
|
|
||||||
}, ctx)
|
|
||||||
|
|
||||||
return backoff.NewTicker(bo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Guard) prepareExponentTicker(ctx context.Context) *backoff.Ticker {
|
func (g *Guard) prepareExponentTicker(ctx context.Context) *backoff.Ticker {
|
||||||
bo := backoff.WithContext(&backoff.ExponentialBackOff{
|
bo := backoff.WithContext(&backoff.ExponentialBackOff{
|
||||||
InitialInterval: 800 * time.Millisecond,
|
InitialInterval: 800 * time.Millisecond,
|
||||||
@@ -135,3 +126,13 @@ func (g *Guard) prepareExponentTicker(ctx context.Context) *backoff.Ticker {
|
|||||||
|
|
||||||
return ticker
|
return ticker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give chance to the peer to establish the initial connection.
|
||||||
|
// With it, we can decrease to send necessary offer
|
||||||
|
func waitForInitialConnectionTry(ctx context.Context) {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-time.After(3 * time.Second):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,15 +39,6 @@ type OfferAnswer struct {
|
|||||||
|
|
||||||
// relay server address
|
// relay server address
|
||||||
RelaySrvAddress string
|
RelaySrvAddress string
|
||||||
// SessionID is the unique identifier of the session, used to discard old messages
|
|
||||||
SessionID *ICESessionID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oa *OfferAnswer) SessionIDString() string {
|
|
||||||
if oa.SessionID == nil {
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
return oa.SessionID.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handshaker struct {
|
type Handshaker struct {
|
||||||
@@ -83,25 +74,21 @@ func (h *Handshaker) AddOnNewOfferListener(offer func(remoteOfferAnswer *OfferAn
|
|||||||
|
|
||||||
func (h *Handshaker) Listen(ctx context.Context) {
|
func (h *Handshaker) Listen(ctx context.Context) {
|
||||||
for {
|
for {
|
||||||
select {
|
h.log.Info("wait for remote offer confirmation")
|
||||||
case remoteOfferAnswer := <-h.remoteOffersCh:
|
remoteOfferAnswer, err := h.waitForRemoteOfferConfirmation(ctx)
|
||||||
// received confirmation from the remote peer -> ready to proceed
|
if err != nil {
|
||||||
if err := h.sendAnswer(); err != nil {
|
var connectionClosedError *ConnectionClosedError
|
||||||
h.log.Errorf("failed to send remote offer confirmation: %s", err)
|
if errors.As(err, &connectionClosedError) {
|
||||||
continue
|
h.log.Info("exit from handshaker")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
for _, listener := range h.onNewOfferListeners {
|
h.log.Errorf("failed to received remote offer confirmation: %s", err)
|
||||||
listener(&remoteOfferAnswer)
|
continue
|
||||||
}
|
}
|
||||||
h.log.Infof("received offer, running version %s, remote WireGuard listen port %d, session id: %s", remoteOfferAnswer.Version, remoteOfferAnswer.WgListenPort, remoteOfferAnswer.SessionIDString())
|
|
||||||
case remoteOfferAnswer := <-h.remoteAnswerCh:
|
h.log.Infof("received connection confirmation, running version %s and with remote WireGuard listen port %d", remoteOfferAnswer.Version, remoteOfferAnswer.WgListenPort)
|
||||||
h.log.Infof("received answer, running version %s, remote WireGuard listen port %d, session id: %s", remoteOfferAnswer.Version, remoteOfferAnswer.WgListenPort, remoteOfferAnswer.SessionIDString())
|
for _, listener := range h.onNewOfferListeners {
|
||||||
for _, listener := range h.onNewOfferListeners {
|
go listener(remoteOfferAnswer)
|
||||||
listener(&remoteOfferAnswer)
|
|
||||||
}
|
|
||||||
case <-ctx.Done():
|
|
||||||
h.log.Infof("stop listening for remote offers and answers")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,27 +101,43 @@ func (h *Handshaker) SendOffer() error {
|
|||||||
|
|
||||||
// OnRemoteOffer handles an offer from the remote peer and returns true if the message was accepted, false otherwise
|
// OnRemoteOffer handles an offer from the remote peer and returns true if the message was accepted, false otherwise
|
||||||
// doesn't block, discards the message if connection wasn't ready
|
// doesn't block, discards the message if connection wasn't ready
|
||||||
func (h *Handshaker) OnRemoteOffer(offer OfferAnswer) {
|
func (h *Handshaker) OnRemoteOffer(offer OfferAnswer) bool {
|
||||||
select {
|
select {
|
||||||
case h.remoteOffersCh <- offer:
|
case h.remoteOffersCh <- offer:
|
||||||
return
|
return true
|
||||||
default:
|
default:
|
||||||
h.log.Warnf("skipping remote offer message because receiver not ready")
|
h.log.Warnf("OnRemoteOffer skipping message because is not ready")
|
||||||
// connection might not be ready yet to receive so we ignore the message
|
// connection might not be ready yet to receive so we ignore the message
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnRemoteAnswer handles an offer from the remote peer and returns true if the message was accepted, false otherwise
|
// OnRemoteAnswer handles an offer from the remote peer and returns true if the message was accepted, false otherwise
|
||||||
// doesn't block, discards the message if connection wasn't ready
|
// doesn't block, discards the message if connection wasn't ready
|
||||||
func (h *Handshaker) OnRemoteAnswer(answer OfferAnswer) {
|
func (h *Handshaker) OnRemoteAnswer(answer OfferAnswer) bool {
|
||||||
select {
|
select {
|
||||||
case h.remoteAnswerCh <- answer:
|
case h.remoteAnswerCh <- answer:
|
||||||
return
|
return true
|
||||||
default:
|
default:
|
||||||
// connection might not be ready yet to receive so we ignore the message
|
// connection might not be ready yet to receive so we ignore the message
|
||||||
h.log.Warnf("skipping remote answer message because receiver not ready")
|
h.log.Debugf("OnRemoteAnswer skipping message because is not ready")
|
||||||
return
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handshaker) waitForRemoteOfferConfirmation(ctx context.Context) (*OfferAnswer, error) {
|
||||||
|
select {
|
||||||
|
case remoteOfferAnswer := <-h.remoteOffersCh:
|
||||||
|
// received confirmation from the remote peer -> ready to proceed
|
||||||
|
if err := h.sendAnswer(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &remoteOfferAnswer, nil
|
||||||
|
case remoteOfferAnswer := <-h.remoteAnswerCh:
|
||||||
|
return &remoteOfferAnswer, nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
// closed externally
|
||||||
|
return nil, NewConnectionClosedError(h.config.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,34 +147,43 @@ func (h *Handshaker) sendOffer() error {
|
|||||||
return ErrSignalIsNotReady
|
return ErrSignalIsNotReady
|
||||||
}
|
}
|
||||||
|
|
||||||
offer := h.buildOfferAnswer()
|
iceUFrag, icePwd := h.ice.GetLocalUserCredentials()
|
||||||
h.log.Infof("sending offer with serial: %s", offer.SessionIDString())
|
offer := OfferAnswer{
|
||||||
|
IceCredentials: IceCredentials{iceUFrag, icePwd},
|
||||||
|
WgListenPort: h.config.LocalWgPort,
|
||||||
|
Version: version.NetbirdVersion(),
|
||||||
|
RosenpassPubKey: h.config.RosenpassConfig.PubKey,
|
||||||
|
RosenpassAddr: h.config.RosenpassConfig.Addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := h.relay.RelayInstanceAddress()
|
||||||
|
if err == nil {
|
||||||
|
offer.RelaySrvAddress = addr
|
||||||
|
}
|
||||||
|
|
||||||
return h.signaler.SignalOffer(offer, h.config.Key)
|
return h.signaler.SignalOffer(offer, h.config.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handshaker) sendAnswer() error {
|
func (h *Handshaker) sendAnswer() error {
|
||||||
answer := h.buildOfferAnswer()
|
h.log.Infof("sending answer")
|
||||||
h.log.Infof("sending answer with serial: %s", answer.SessionIDString())
|
|
||||||
|
|
||||||
return h.signaler.SignalAnswer(answer, h.config.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handshaker) buildOfferAnswer() OfferAnswer {
|
|
||||||
uFrag, pwd := h.ice.GetLocalUserCredentials()
|
uFrag, pwd := h.ice.GetLocalUserCredentials()
|
||||||
sid := h.ice.SessionID()
|
|
||||||
answer := OfferAnswer{
|
answer := OfferAnswer{
|
||||||
IceCredentials: IceCredentials{uFrag, pwd},
|
IceCredentials: IceCredentials{uFrag, pwd},
|
||||||
WgListenPort: h.config.LocalWgPort,
|
WgListenPort: h.config.LocalWgPort,
|
||||||
Version: version.NetbirdVersion(),
|
Version: version.NetbirdVersion(),
|
||||||
RosenpassPubKey: h.config.RosenpassConfig.PubKey,
|
RosenpassPubKey: h.config.RosenpassConfig.PubKey,
|
||||||
RosenpassAddr: h.config.RosenpassConfig.Addr,
|
RosenpassAddr: h.config.RosenpassConfig.Addr,
|
||||||
SessionID: &sid,
|
|
||||||
}
|
}
|
||||||
|
addr, err := h.relay.RelayInstanceAddress()
|
||||||
if addr, err := h.relay.RelayInstanceAddress(); err == nil {
|
if err == nil {
|
||||||
answer.RelaySrvAddress = addr
|
answer.RelaySrvAddress = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
return answer
|
err = h.signaler.SignalAnswer(answer, h.config.Key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package ice
|
package ice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/ice/v3"
|
"github.com/pion/ice/v3"
|
||||||
@@ -24,20 +23,7 @@ const (
|
|||||||
iceRelayAcceptanceMinWaitDefault = 2 * time.Second
|
iceRelayAcceptanceMinWaitDefault = 2 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
type ThreadSafeAgent struct {
|
func NewAgent(iFaceDiscover stdnet.ExternalIFaceDiscover, config Config, candidateTypes []ice.CandidateType, ufrag string, pwd string) (*ice.Agent, error) {
|
||||||
*ice.Agent
|
|
||||||
once sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ThreadSafeAgent) Close() error {
|
|
||||||
var err error
|
|
||||||
a.once.Do(func() {
|
|
||||||
err = a.Agent.Close()
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAgent(iFaceDiscover stdnet.ExternalIFaceDiscover, config Config, candidateTypes []ice.CandidateType, ufrag string, pwd string) (*ThreadSafeAgent, error) {
|
|
||||||
iceKeepAlive := iceKeepAlive()
|
iceKeepAlive := iceKeepAlive()
|
||||||
iceDisconnectedTimeout := iceDisconnectedTimeout()
|
iceDisconnectedTimeout := iceDisconnectedTimeout()
|
||||||
iceFailedTimeout := iceFailedTimeout()
|
iceFailedTimeout := iceFailedTimeout()
|
||||||
@@ -75,12 +61,7 @@ func NewAgent(iFaceDiscover stdnet.ExternalIFaceDiscover, config Config, candida
|
|||||||
agentConfig.NetworkTypes = []ice.NetworkType{ice.NetworkTypeUDP4}
|
agentConfig.NetworkTypes = []ice.NetworkType{ice.NetworkTypeUDP4}
|
||||||
}
|
}
|
||||||
|
|
||||||
agent, err := ice.NewAgent(agentConfig)
|
return ice.NewAgent(agentConfig)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ThreadSafeAgent{Agent: agent}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateICECredentials() (string, string, error) {
|
func GenerateICECredentials() (string, string, error) {
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
package peer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
const sessionIDSize = 5
|
|
||||||
|
|
||||||
type ICESessionID string
|
|
||||||
|
|
||||||
// NewICESessionID generates a new session ID for distinguishing sessions
|
|
||||||
func NewICESessionID() (ICESessionID, error) {
|
|
||||||
b := make([]byte, sessionIDSize)
|
|
||||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to generate session ID: %w", err)
|
|
||||||
}
|
|
||||||
return ICESessionID(hex.EncodeToString(b)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ICESessionIDFromBytes(b []byte) (ICESessionID, error) {
|
|
||||||
if len(b) != sessionIDSize {
|
|
||||||
return "", fmt.Errorf("invalid session ID length: %d", len(b))
|
|
||||||
}
|
|
||||||
return ICESessionID(hex.EncodeToString(b)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns the raw bytes of the session ID for protobuf serialization
|
|
||||||
func (id ICESessionID) Bytes() ([]byte, error) {
|
|
||||||
if len(id) == 0 {
|
|
||||||
return nil, fmt.Errorf("ICE session ID is empty")
|
|
||||||
}
|
|
||||||
b, err := hex.DecodeString(string(id))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid ICE session ID encoding: %w", err)
|
|
||||||
}
|
|
||||||
if len(b) != sessionIDSize {
|
|
||||||
return nil, fmt.Errorf("invalid ICE session ID length: expected %d bytes, got %d", sessionIDSize, len(b))
|
|
||||||
}
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (id ICESessionID) String() string {
|
|
||||||
return string(id)
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ package peer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pion/ice/v3"
|
"github.com/pion/ice/v3"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
signal "github.com/netbirdio/netbird/shared/signal/client"
|
signal "github.com/netbirdio/netbird/shared/signal/client"
|
||||||
@@ -46,10 +45,6 @@ func (s *Signaler) Ready() bool {
|
|||||||
|
|
||||||
// SignalOfferAnswer signals either an offer or an answer to remote peer
|
// SignalOfferAnswer signals either an offer or an answer to remote peer
|
||||||
func (s *Signaler) signalOfferAnswer(offerAnswer OfferAnswer, remoteKey string, bodyType sProto.Body_Type) error {
|
func (s *Signaler) signalOfferAnswer(offerAnswer OfferAnswer, remoteKey string, bodyType sProto.Body_Type) error {
|
||||||
sessionIDBytes, err := offerAnswer.SessionID.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to get session ID bytes: %v", err)
|
|
||||||
}
|
|
||||||
msg, err := signal.MarshalCredential(
|
msg, err := signal.MarshalCredential(
|
||||||
s.wgPrivateKey,
|
s.wgPrivateKey,
|
||||||
offerAnswer.WgListenPort,
|
offerAnswer.WgListenPort,
|
||||||
@@ -61,13 +56,13 @@ func (s *Signaler) signalOfferAnswer(offerAnswer OfferAnswer, remoteKey string,
|
|||||||
bodyType,
|
bodyType,
|
||||||
offerAnswer.RosenpassPubKey,
|
offerAnswer.RosenpassPubKey,
|
||||||
offerAnswer.RosenpassAddr,
|
offerAnswer.RosenpassAddr,
|
||||||
offerAnswer.RelaySrvAddress,
|
offerAnswer.RelaySrvAddress)
|
||||||
sessionIDBytes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s.signal.Send(msg); err != nil {
|
err = s.signal.Send(msg)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,18 +42,8 @@ type WorkerICE struct {
|
|||||||
statusRecorder *Status
|
statusRecorder *Status
|
||||||
hasRelayOnLocally bool
|
hasRelayOnLocally bool
|
||||||
|
|
||||||
agent *icemaker.ThreadSafeAgent
|
agent *ice.Agent
|
||||||
agentDialerCancel context.CancelFunc
|
muxAgent sync.Mutex
|
||||||
agentConnecting bool // while it is true, drop all incoming offers
|
|
||||||
lastSuccess time.Time // with this avoid the too frequent ICE agent recreation
|
|
||||||
// remoteSessionID represents the peer's session identifier from the latest remote offer.
|
|
||||||
remoteSessionID ICESessionID
|
|
||||||
// sessionID is used to track the current session ID of the ICE agent
|
|
||||||
// increase by one when disconnecting the agent
|
|
||||||
// with it the remote peer can discard the already deprecated offer/answer
|
|
||||||
// Without it the remote peer may recreate a workable ICE connection
|
|
||||||
sessionID ICESessionID
|
|
||||||
muxAgent sync.Mutex
|
|
||||||
|
|
||||||
StunTurn []*stun.URI
|
StunTurn []*stun.URI
|
||||||
|
|
||||||
@@ -67,11 +57,6 @@ type WorkerICE struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewWorkerICE(ctx context.Context, log *log.Entry, config ConnConfig, conn *Conn, signaler *Signaler, ifaceDiscover stdnet.ExternalIFaceDiscover, statusRecorder *Status, hasRelayOnLocally bool) (*WorkerICE, error) {
|
func NewWorkerICE(ctx context.Context, log *log.Entry, config ConnConfig, conn *Conn, signaler *Signaler, ifaceDiscover stdnet.ExternalIFaceDiscover, statusRecorder *Status, hasRelayOnLocally bool) (*WorkerICE, error) {
|
||||||
sessionID, err := NewICESessionID()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
w := &WorkerICE{
|
w := &WorkerICE{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
log: log,
|
log: log,
|
||||||
@@ -82,7 +67,6 @@ func NewWorkerICE(ctx context.Context, log *log.Entry, config ConnConfig, conn *
|
|||||||
statusRecorder: statusRecorder,
|
statusRecorder: statusRecorder,
|
||||||
hasRelayOnLocally: hasRelayOnLocally,
|
hasRelayOnLocally: hasRelayOnLocally,
|
||||||
lastKnownState: ice.ConnectionStateDisconnected,
|
lastKnownState: ice.ConnectionStateDisconnected,
|
||||||
sessionID: sessionID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localUfrag, localPwd, err := icemaker.GenerateICECredentials()
|
localUfrag, localPwd, err := icemaker.GenerateICECredentials()
|
||||||
@@ -95,36 +79,15 @@ func NewWorkerICE(ctx context.Context, log *log.Entry, config ConnConfig, conn *
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *OfferAnswer) {
|
func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *OfferAnswer) {
|
||||||
w.log.Debugf("OnNewOffer for ICE, serial: %s", remoteOfferAnswer.SessionIDString())
|
w.log.Debugf("OnNewOffer for ICE")
|
||||||
w.muxAgent.Lock()
|
w.muxAgent.Lock()
|
||||||
|
|
||||||
if w.agentConnecting {
|
if w.agent != nil {
|
||||||
w.log.Debugf("agent connection is in progress, skipping the offer")
|
w.log.Debugf("agent already exists, skipping the offer")
|
||||||
w.muxAgent.Unlock()
|
w.muxAgent.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.agent != nil {
|
|
||||||
// backward compatibility with old clients that do not send session ID
|
|
||||||
if remoteOfferAnswer.SessionID == nil {
|
|
||||||
w.log.Debugf("agent already exists, skipping the offer")
|
|
||||||
w.muxAgent.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if w.remoteSessionID == *remoteOfferAnswer.SessionID {
|
|
||||||
w.log.Debugf("agent already exists and session ID matches, skipping the offer: %s", remoteOfferAnswer.SessionIDString())
|
|
||||||
w.muxAgent.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.log.Debugf("agent already exists, recreate the connection")
|
|
||||||
w.agentDialerCancel()
|
|
||||||
if err := w.agent.Close(); err != nil {
|
|
||||||
w.log.Warnf("failed to close ICE agent: %s", err)
|
|
||||||
}
|
|
||||||
w.agent = nil
|
|
||||||
// todo consider to switch to Relay connection while establishing a new ICE connection
|
|
||||||
}
|
|
||||||
|
|
||||||
var preferredCandidateTypes []ice.CandidateType
|
var preferredCandidateTypes []ice.CandidateType
|
||||||
if w.hasRelayOnLocally && remoteOfferAnswer.RelaySrvAddress != "" {
|
if w.hasRelayOnLocally && remoteOfferAnswer.RelaySrvAddress != "" {
|
||||||
preferredCandidateTypes = icemaker.CandidateTypesP2P()
|
preferredCandidateTypes = icemaker.CandidateTypesP2P()
|
||||||
@@ -133,124 +96,36 @@ func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *OfferAnswer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.log.Debugf("recreate ICE agent")
|
w.log.Debugf("recreate ICE agent")
|
||||||
dialerCtx, dialerCancel := context.WithCancel(w.ctx)
|
agentCtx, agentCancel := context.WithCancel(w.ctx)
|
||||||
agent, err := w.reCreateAgent(dialerCancel, preferredCandidateTypes)
|
agent, err := w.reCreateAgent(agentCancel, preferredCandidateTypes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.log.Errorf("failed to recreate ICE Agent: %s", err)
|
w.log.Errorf("failed to recreate ICE Agent: %s", err)
|
||||||
w.muxAgent.Unlock()
|
w.muxAgent.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.sentExtraSrflx = false
|
|
||||||
w.agent = agent
|
w.agent = agent
|
||||||
w.agentDialerCancel = dialerCancel
|
|
||||||
w.agentConnecting = true
|
|
||||||
w.muxAgent.Unlock()
|
w.muxAgent.Unlock()
|
||||||
|
|
||||||
go w.connect(dialerCtx, agent, remoteOfferAnswer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnRemoteCandidate Handles ICE connection Candidate provided by the remote peer.
|
|
||||||
func (w *WorkerICE) OnRemoteCandidate(candidate ice.Candidate, haRoutes route.HAMap) {
|
|
||||||
w.muxAgent.Lock()
|
|
||||||
defer w.muxAgent.Unlock()
|
|
||||||
w.log.Debugf("OnRemoteCandidate from peer %s -> %s", w.config.Key, candidate.String())
|
|
||||||
if w.agent == nil {
|
|
||||||
w.log.Warnf("ICE Agent is not initialized yet")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidateViaRoutes(candidate, haRoutes) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := w.agent.AddRemoteCandidate(candidate); err != nil {
|
|
||||||
w.log.Errorf("error while handling remote candidate")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) GetLocalUserCredentials() (frag string, pwd string) {
|
|
||||||
return w.localUfrag, w.localPwd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) InProgress() bool {
|
|
||||||
w.muxAgent.Lock()
|
|
||||||
defer w.muxAgent.Unlock()
|
|
||||||
|
|
||||||
return w.agentConnecting
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) Close() {
|
|
||||||
w.muxAgent.Lock()
|
|
||||||
defer w.muxAgent.Unlock()
|
|
||||||
|
|
||||||
if w.agent == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.agentDialerCancel()
|
|
||||||
if err := w.agent.Close(); err != nil {
|
|
||||||
w.log.Warnf("failed to close ICE agent: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.agent = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) reCreateAgent(dialerCancel context.CancelFunc, candidates []ice.CandidateType) (*icemaker.ThreadSafeAgent, error) {
|
|
||||||
agent, err := icemaker.NewAgent(w.iFaceDiscover, w.config.ICEConfig, candidates, w.localUfrag, w.localPwd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("create agent: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := agent.OnCandidate(w.onICECandidate); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := agent.OnConnectionStateChange(w.onConnectionStateChange(agent, dialerCancel)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := agent.OnSelectedCandidatePairChange(w.onICESelectedCandidatePair); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := agent.OnSuccessfulSelectedPairBindingResponse(w.onSuccessfulSelectedPairBindingResponse); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed setting binding response callback: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return agent, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) SessionID() ICESessionID {
|
|
||||||
w.muxAgent.Lock()
|
|
||||||
defer w.muxAgent.Unlock()
|
|
||||||
|
|
||||||
return w.sessionID
|
|
||||||
}
|
|
||||||
|
|
||||||
// will block until connection succeeded
|
|
||||||
// but it won't release if ICE Agent went into Disconnected or Failed state,
|
|
||||||
// so we have to cancel it with the provided context once agent detected a broken connection
|
|
||||||
func (w *WorkerICE) connect(ctx context.Context, agent *icemaker.ThreadSafeAgent, remoteOfferAnswer *OfferAnswer) {
|
|
||||||
w.log.Debugf("gather candidates")
|
w.log.Debugf("gather candidates")
|
||||||
if err := agent.GatherCandidates(); err != nil {
|
err = w.agent.GatherCandidates()
|
||||||
w.log.Warnf("failed to gather candidates: %s", err)
|
if err != nil {
|
||||||
w.closeAgent(agent, w.agentDialerCancel)
|
w.log.Debugf("failed to gather candidates: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// will block until connection succeeded
|
||||||
|
// but it won't release if ICE Agent went into Disconnected or Failed state,
|
||||||
|
// so we have to cancel it with the provided context once agent detected a broken connection
|
||||||
w.log.Debugf("turn agent dial")
|
w.log.Debugf("turn agent dial")
|
||||||
remoteConn, err := w.turnAgentDial(ctx, agent, remoteOfferAnswer)
|
remoteConn, err := w.turnAgentDial(agentCtx, remoteOfferAnswer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.log.Debugf("failed to dial the remote peer: %s", err)
|
w.log.Debugf("failed to dial the remote peer: %s", err)
|
||||||
w.closeAgent(agent, w.agentDialerCancel)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.log.Debugf("agent dial succeeded")
|
w.log.Debugf("agent dial succeeded")
|
||||||
|
|
||||||
pair, err := agent.GetSelectedCandidatePair()
|
pair, err := w.agent.GetSelectedCandidatePair()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.closeAgent(agent, w.agentDialerCancel)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,39 +152,114 @@ func (w *WorkerICE) connect(ctx context.Context, agent *icemaker.ThreadSafeAgent
|
|||||||
RelayedOnLocal: isRelayCandidate(pair.Local),
|
RelayedOnLocal: isRelayCandidate(pair.Local),
|
||||||
}
|
}
|
||||||
w.log.Debugf("on ICE conn is ready to use")
|
w.log.Debugf("on ICE conn is ready to use")
|
||||||
|
go w.conn.onICEConnectionIsReady(selectedPriority(pair), ci)
|
||||||
w.log.Infof("connection succeeded with offer session: %s", remoteOfferAnswer.SessionIDString())
|
|
||||||
w.muxAgent.Lock()
|
|
||||||
w.agentConnecting = false
|
|
||||||
w.lastSuccess = time.Now()
|
|
||||||
if remoteOfferAnswer.SessionID != nil {
|
|
||||||
w.remoteSessionID = *remoteOfferAnswer.SessionID
|
|
||||||
}
|
|
||||||
w.muxAgent.Unlock()
|
|
||||||
|
|
||||||
// todo: the potential problem is a race between the onConnectionStateChange
|
|
||||||
w.conn.onICEConnectionIsReady(selectedPriority(pair), ci)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerICE) closeAgent(agent *icemaker.ThreadSafeAgent, cancel context.CancelFunc) {
|
// OnRemoteCandidate Handles ICE connection Candidate provided by the remote peer.
|
||||||
cancel()
|
func (w *WorkerICE) OnRemoteCandidate(candidate ice.Candidate, haRoutes route.HAMap) {
|
||||||
if err := agent.Close(); err != nil {
|
w.muxAgent.Lock()
|
||||||
|
defer w.muxAgent.Unlock()
|
||||||
|
w.log.Debugf("OnRemoteCandidate from peer %s -> %s", w.config.Key, candidate.String())
|
||||||
|
if w.agent == nil {
|
||||||
|
w.log.Warnf("ICE Agent is not initialized yet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if candidateViaRoutes(candidate, haRoutes) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := w.agent.AddRemoteCandidate(candidate)
|
||||||
|
if err != nil {
|
||||||
|
w.log.Errorf("error while handling remote candidate")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorkerICE) GetLocalUserCredentials() (frag string, pwd string) {
|
||||||
|
w.muxAgent.Lock()
|
||||||
|
defer w.muxAgent.Unlock()
|
||||||
|
return w.localUfrag, w.localPwd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorkerICE) Close() {
|
||||||
|
w.muxAgent.Lock()
|
||||||
|
defer w.muxAgent.Unlock()
|
||||||
|
|
||||||
|
if w.agent == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.agent.Close(); err != nil {
|
||||||
w.log.Warnf("failed to close ICE agent: %s", err)
|
w.log.Warnf("failed to close ICE agent: %s", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w.muxAgent.Lock()
|
func (w *WorkerICE) reCreateAgent(agentCancel context.CancelFunc, candidates []ice.CandidateType) (*ice.Agent, error) {
|
||||||
// todo review does it make sense to generate new session ID all the time when w.agent==agent
|
w.sentExtraSrflx = false
|
||||||
sessionID, err := NewICESessionID()
|
|
||||||
|
agent, err := icemaker.NewAgent(w.iFaceDiscover, w.config.ICEConfig, candidates, w.localUfrag, w.localPwd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.log.Errorf("failed to create new session ID: %s", err)
|
return nil, fmt.Errorf("create agent: %w", err)
|
||||||
}
|
}
|
||||||
w.sessionID = sessionID
|
|
||||||
|
|
||||||
if w.agent == agent {
|
err = agent.OnCandidate(w.onICECandidate)
|
||||||
w.agent = nil
|
if err != nil {
|
||||||
w.agentConnecting = false
|
return nil, err
|
||||||
}
|
}
|
||||||
w.muxAgent.Unlock()
|
|
||||||
|
err = agent.OnConnectionStateChange(func(state ice.ConnectionState) {
|
||||||
|
w.log.Debugf("ICE ConnectionState has changed to %s", state.String())
|
||||||
|
switch state {
|
||||||
|
case ice.ConnectionStateConnected:
|
||||||
|
w.lastKnownState = ice.ConnectionStateConnected
|
||||||
|
return
|
||||||
|
case ice.ConnectionStateFailed, ice.ConnectionStateDisconnected:
|
||||||
|
if w.lastKnownState == ice.ConnectionStateConnected {
|
||||||
|
w.lastKnownState = ice.ConnectionStateDisconnected
|
||||||
|
w.conn.onICEStateDisconnected()
|
||||||
|
}
|
||||||
|
w.closeAgent(agentCancel)
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = agent.OnSelectedCandidatePairChange(w.onICESelectedCandidatePair)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = agent.OnSuccessfulSelectedPairBindingResponse(func(p *ice.CandidatePair) {
|
||||||
|
err := w.statusRecorder.UpdateLatency(w.config.Key, p.Latency())
|
||||||
|
if err != nil {
|
||||||
|
w.log.Debugf("failed to update latency for peer: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed setting binding response callback: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return agent, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WorkerICE) closeAgent(cancel context.CancelFunc) {
|
||||||
|
w.muxAgent.Lock()
|
||||||
|
defer w.muxAgent.Unlock()
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
if w.agent == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.agent.Close(); err != nil {
|
||||||
|
w.log.Warnf("failed to close ICE agent: %s", err)
|
||||||
|
}
|
||||||
|
w.agent = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerICE) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int) {
|
func (w *WorkerICE) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int) {
|
||||||
@@ -381,32 +331,6 @@ func (w *WorkerICE) onICESelectedCandidatePair(c1 ice.Candidate, c2 ice.Candidat
|
|||||||
w.config.Key)
|
w.config.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerICE) onConnectionStateChange(agent *icemaker.ThreadSafeAgent, dialerCancel context.CancelFunc) func(ice.ConnectionState) {
|
|
||||||
return func(state ice.ConnectionState) {
|
|
||||||
w.log.Debugf("ICE ConnectionState has changed to %s", state.String())
|
|
||||||
switch state {
|
|
||||||
case ice.ConnectionStateConnected:
|
|
||||||
w.lastKnownState = ice.ConnectionStateConnected
|
|
||||||
return
|
|
||||||
case ice.ConnectionStateFailed, ice.ConnectionStateDisconnected:
|
|
||||||
if w.lastKnownState == ice.ConnectionStateConnected {
|
|
||||||
w.lastKnownState = ice.ConnectionStateDisconnected
|
|
||||||
w.conn.onICEStateDisconnected()
|
|
||||||
}
|
|
||||||
w.closeAgent(agent, dialerCancel)
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) onSuccessfulSelectedPairBindingResponse(pair *ice.CandidatePair) {
|
|
||||||
if err := w.statusRecorder.UpdateLatency(w.config.Key, pair.Latency()); err != nil {
|
|
||||||
w.log.Debugf("failed to update latency for peer: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WorkerICE) shouldSendExtraSrflxCandidate(candidate ice.Candidate) bool {
|
func (w *WorkerICE) shouldSendExtraSrflxCandidate(candidate ice.Candidate) bool {
|
||||||
if !w.sentExtraSrflx && candidate.Type() == ice.CandidateTypeServerReflexive && candidate.Port() != candidate.RelatedAddress().Port {
|
if !w.sentExtraSrflx && candidate.Type() == ice.CandidateTypeServerReflexive && candidate.Port() != candidate.RelatedAddress().Port {
|
||||||
return true
|
return true
|
||||||
@@ -414,12 +338,12 @@ func (w *WorkerICE) shouldSendExtraSrflxCandidate(candidate ice.Candidate) bool
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerICE) turnAgentDial(ctx context.Context, agent *icemaker.ThreadSafeAgent, remoteOfferAnswer *OfferAnswer) (*ice.Conn, error) {
|
func (w *WorkerICE) turnAgentDial(ctx context.Context, remoteOfferAnswer *OfferAnswer) (*ice.Conn, error) {
|
||||||
isControlling := w.config.LocalKey > w.config.Key
|
isControlling := w.config.LocalKey > w.config.Key
|
||||||
if isControlling {
|
if isControlling {
|
||||||
return agent.Dial(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd)
|
return w.agent.Dial(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd)
|
||||||
} else {
|
} else {
|
||||||
return agent.Accept(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd)
|
return w.agent.Accept(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ type ConfigInput struct {
|
|||||||
DNSLabels domain.List
|
DNSLabels domain.List
|
||||||
|
|
||||||
LazyConnectionEnabled *bool
|
LazyConnectionEnabled *bool
|
||||||
|
|
||||||
MTU *uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config Configuration type
|
// Config Configuration type
|
||||||
@@ -143,8 +141,6 @@ type Config struct {
|
|||||||
ClientCertKeyPair *tls.Certificate `json:"-"`
|
ClientCertKeyPair *tls.Certificate `json:"-"`
|
||||||
|
|
||||||
LazyConnectionEnabled bool
|
LazyConnectionEnabled bool
|
||||||
|
|
||||||
MTU uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConfigDirOverride string
|
var ConfigDirOverride string
|
||||||
@@ -497,16 +493,6 @@ func (config *Config) apply(input ConfigInput) (updated bool, err error) {
|
|||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.MTU != nil && *input.MTU != config.MTU {
|
|
||||||
log.Infof("updating MTU to %d (old value %d)", *input.MTU, config.MTU)
|
|
||||||
config.MTU = *input.MTU
|
|
||||||
updated = true
|
|
||||||
} else if config.MTU == 0 {
|
|
||||||
config.MTU = iface.DefaultMTU
|
|
||||||
log.Infof("using default MTU %d", config.MTU)
|
|
||||||
updated = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated, nil
|
return updated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/routemanager/vars"
|
"github.com/netbirdio/netbird/client/internal/routemanager/vars"
|
||||||
"github.com/netbirdio/netbird/client/internal/routeselector"
|
"github.com/netbirdio/netbird/client/internal/routeselector"
|
||||||
"github.com/netbirdio/netbird/client/internal/statemanager"
|
"github.com/netbirdio/netbird/client/internal/statemanager"
|
||||||
"github.com/netbirdio/netbird/route"
|
|
||||||
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
nbnet "github.com/netbirdio/netbird/util/net"
|
nbnet "github.com/netbirdio/netbird/util/net"
|
||||||
"github.com/netbirdio/netbird/version"
|
"github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
@@ -368,11 +368,7 @@ func (m *DefaultManager) UpdateRoutes(
|
|||||||
|
|
||||||
var merr *multierror.Error
|
var merr *multierror.Error
|
||||||
if !m.disableClientRoutes {
|
if !m.disableClientRoutes {
|
||||||
|
filteredClientRoutes := m.routeSelector.FilterSelected(clientRoutes)
|
||||||
// Update route selector based on management server's isSelected status
|
|
||||||
m.updateRouteSelectorFromManagement(clientRoutes)
|
|
||||||
|
|
||||||
filteredClientRoutes := m.routeSelector.FilterSelectedExitNodes(clientRoutes)
|
|
||||||
|
|
||||||
if err := m.updateSystemRoutes(filteredClientRoutes); err != nil {
|
if err := m.updateSystemRoutes(filteredClientRoutes); err != nil {
|
||||||
merr = multierror.Append(merr, fmt.Errorf("update system routes: %w", err))
|
merr = multierror.Append(merr, fmt.Errorf("update system routes: %w", err))
|
||||||
@@ -434,7 +430,7 @@ func (m *DefaultManager) TriggerSelection(networks route.HAMap) {
|
|||||||
m.mux.Lock()
|
m.mux.Lock()
|
||||||
defer m.mux.Unlock()
|
defer m.mux.Unlock()
|
||||||
|
|
||||||
networks = m.routeSelector.FilterSelectedExitNodes(networks)
|
networks = m.routeSelector.FilterSelected(networks)
|
||||||
|
|
||||||
m.notifier.OnNewRoutes(networks)
|
m.notifier.OnNewRoutes(networks)
|
||||||
|
|
||||||
@@ -587,106 +583,3 @@ func resolveURLsToIPs(urls []string) []net.IP {
|
|||||||
}
|
}
|
||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateRouteSelectorFromManagement updates the route selector based on the isSelected status from the management server
|
|
||||||
func (m *DefaultManager) updateRouteSelectorFromManagement(clientRoutes route.HAMap) {
|
|
||||||
exitNodeInfo := m.collectExitNodeInfo(clientRoutes)
|
|
||||||
if len(exitNodeInfo.allIDs) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
m.updateExitNodeSelections(exitNodeInfo)
|
|
||||||
m.logExitNodeUpdate(exitNodeInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
type exitNodeInfo struct {
|
|
||||||
allIDs []route.NetID
|
|
||||||
selectedByManagement []route.NetID
|
|
||||||
userSelected []route.NetID
|
|
||||||
userDeselected []route.NetID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) collectExitNodeInfo(clientRoutes route.HAMap) exitNodeInfo {
|
|
||||||
var info exitNodeInfo
|
|
||||||
|
|
||||||
for haID, routes := range clientRoutes {
|
|
||||||
if !m.isExitNodeRoute(routes) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
netID := haID.NetID()
|
|
||||||
info.allIDs = append(info.allIDs, netID)
|
|
||||||
|
|
||||||
if m.routeSelector.HasUserSelectionForRoute(netID) {
|
|
||||||
m.categorizeUserSelection(netID, &info)
|
|
||||||
} else {
|
|
||||||
m.checkManagementSelection(routes, netID, &info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) isExitNodeRoute(routes []*route.Route) bool {
|
|
||||||
return len(routes) > 0 && routes[0].Network.String() == vars.ExitNodeCIDR
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) categorizeUserSelection(netID route.NetID, info *exitNodeInfo) {
|
|
||||||
if m.routeSelector.IsSelected(netID) {
|
|
||||||
info.userSelected = append(info.userSelected, netID)
|
|
||||||
} else {
|
|
||||||
info.userDeselected = append(info.userDeselected, netID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) checkManagementSelection(routes []*route.Route, netID route.NetID, info *exitNodeInfo) {
|
|
||||||
for _, route := range routes {
|
|
||||||
if !route.SkipAutoApply {
|
|
||||||
info.selectedByManagement = append(info.selectedByManagement, netID)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) updateExitNodeSelections(info exitNodeInfo) {
|
|
||||||
routesToDeselect := m.getRoutesToDeselect(info.allIDs)
|
|
||||||
m.deselectExitNodes(routesToDeselect)
|
|
||||||
m.selectExitNodesByManagement(info.selectedByManagement, info.allIDs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) getRoutesToDeselect(allIDs []route.NetID) []route.NetID {
|
|
||||||
var routesToDeselect []route.NetID
|
|
||||||
for _, netID := range allIDs {
|
|
||||||
if !m.routeSelector.HasUserSelectionForRoute(netID) {
|
|
||||||
routesToDeselect = append(routesToDeselect, netID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return routesToDeselect
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) deselectExitNodes(routesToDeselect []route.NetID) {
|
|
||||||
if len(routesToDeselect) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err := m.routeSelector.DeselectRoutes(routesToDeselect, routesToDeselect)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("Failed to deselect exit nodes: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) selectExitNodesByManagement(selectedByManagement []route.NetID, allIDs []route.NetID) {
|
|
||||||
if len(selectedByManagement) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err := m.routeSelector.SelectRoutes(selectedByManagement, true, allIDs)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("Failed to select exit nodes: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *DefaultManager) logExitNodeUpdate(info exitNodeInfo) {
|
|
||||||
log.Debugf("Updated route selector: %d exit nodes available, %d selected by management, %d user-selected, %d user-deselected",
|
|
||||||
len(info.allIDs), len(info.selectedByManagement), len(info.userSelected), len(info.userDeselected))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -190,15 +190,14 @@ func TestManagerUpdateRoutes(t *testing.T) {
|
|||||||
name: "No Small Client Route Should Be Added",
|
name: "No Small Client Route Should Be Added",
|
||||||
inputRoutes: []*route.Route{
|
inputRoutes: []*route.Route{
|
||||||
{
|
{
|
||||||
ID: "a",
|
ID: "a",
|
||||||
NetID: "routeA",
|
NetID: "routeA",
|
||||||
Peer: remotePeerKey1,
|
Peer: remotePeerKey1,
|
||||||
Network: netip.MustParsePrefix("0.0.0.0/0"),
|
Network: netip.MustParsePrefix("0.0.0.0/0"),
|
||||||
NetworkType: route.IPv4Network,
|
NetworkType: route.IPv4Network,
|
||||||
Metric: 9999,
|
Metric: 9999,
|
||||||
Masquerade: false,
|
Masquerade: false,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
SkipAutoApply: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inputSerial: 1,
|
inputSerial: 1,
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ func createIPForwardEntry2(route *MIB_IPFORWARD_ROW2) error {
|
|||||||
if e1 != 0 {
|
if e1 != 0 {
|
||||||
return fmt.Errorf("CreateIpForwardEntry2: %w", e1)
|
return fmt.Errorf("CreateIpForwardEntry2: %w", e1)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("CreateIpForwardEntry2: code %d", windows.NTStatus(r1))
|
return fmt.Errorf("CreateIpForwardEntry2: code %d", r1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,4 @@ var (
|
|||||||
|
|
||||||
Defaultv4 = netip.PrefixFrom(netip.IPv4Unspecified(), 0)
|
Defaultv4 = netip.PrefixFrom(netip.IPv4Unspecified(), 0)
|
||||||
Defaultv6 = netip.PrefixFrom(netip.IPv6Unspecified(), 0)
|
Defaultv6 = netip.PrefixFrom(netip.IPv6Unspecified(), 0)
|
||||||
|
|
||||||
ExitNodeCIDR = "0.0.0.0/0"
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,27 +9,19 @@ import (
|
|||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/errors"
|
"github.com/netbirdio/netbird/client/errors"
|
||||||
"github.com/netbirdio/netbird/route"
|
"github.com/netbirdio/netbird/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
exitNodeCIDR = "0.0.0.0/0"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RouteSelector struct {
|
type RouteSelector struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
deselectedRoutes map[route.NetID]struct{}
|
deselectedRoutes map[route.NetID]struct{}
|
||||||
selectedRoutes map[route.NetID]struct{}
|
|
||||||
deselectAll bool
|
deselectAll bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouteSelector() *RouteSelector {
|
func NewRouteSelector() *RouteSelector {
|
||||||
return &RouteSelector{
|
return &RouteSelector{
|
||||||
deselectedRoutes: map[route.NetID]struct{}{},
|
deselectedRoutes: map[route.NetID]struct{}{},
|
||||||
selectedRoutes: map[route.NetID]struct{}{},
|
|
||||||
deselectAll: false,
|
deselectAll: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,14 +32,7 @@ func (rs *RouteSelector) SelectRoutes(routes []route.NetID, appendRoute bool, al
|
|||||||
defer rs.mu.Unlock()
|
defer rs.mu.Unlock()
|
||||||
|
|
||||||
if !appendRoute || rs.deselectAll {
|
if !appendRoute || rs.deselectAll {
|
||||||
if rs.deselectedRoutes == nil {
|
|
||||||
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
if rs.selectedRoutes == nil {
|
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
maps.Clear(rs.deselectedRoutes)
|
maps.Clear(rs.deselectedRoutes)
|
||||||
maps.Clear(rs.selectedRoutes)
|
|
||||||
for _, r := range allRoutes {
|
for _, r := range allRoutes {
|
||||||
rs.deselectedRoutes[r] = struct{}{}
|
rs.deselectedRoutes[r] = struct{}{}
|
||||||
}
|
}
|
||||||
@@ -60,7 +45,6 @@ func (rs *RouteSelector) SelectRoutes(routes []route.NetID, appendRoute bool, al
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delete(rs.deselectedRoutes, route)
|
delete(rs.deselectedRoutes, route)
|
||||||
rs.selectedRoutes[route] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rs.deselectAll = false
|
rs.deselectAll = false
|
||||||
@@ -74,14 +58,7 @@ func (rs *RouteSelector) SelectAllRoutes() {
|
|||||||
defer rs.mu.Unlock()
|
defer rs.mu.Unlock()
|
||||||
|
|
||||||
rs.deselectAll = false
|
rs.deselectAll = false
|
||||||
if rs.deselectedRoutes == nil {
|
|
||||||
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
if rs.selectedRoutes == nil {
|
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
maps.Clear(rs.deselectedRoutes)
|
maps.Clear(rs.deselectedRoutes)
|
||||||
maps.Clear(rs.selectedRoutes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeselectRoutes removes specific routes from the selection.
|
// DeselectRoutes removes specific routes from the selection.
|
||||||
@@ -100,7 +77,6 @@ func (rs *RouteSelector) DeselectRoutes(routes []route.NetID, allRoutes []route.
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rs.deselectedRoutes[route] = struct{}{}
|
rs.deselectedRoutes[route] = struct{}{}
|
||||||
delete(rs.selectedRoutes, route)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.FormatErrorOrNil(err)
|
return errors.FormatErrorOrNil(err)
|
||||||
@@ -112,14 +88,7 @@ func (rs *RouteSelector) DeselectAllRoutes() {
|
|||||||
defer rs.mu.Unlock()
|
defer rs.mu.Unlock()
|
||||||
|
|
||||||
rs.deselectAll = true
|
rs.deselectAll = true
|
||||||
if rs.deselectedRoutes == nil {
|
|
||||||
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
if rs.selectedRoutes == nil {
|
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
maps.Clear(rs.deselectedRoutes)
|
maps.Clear(rs.deselectedRoutes)
|
||||||
maps.Clear(rs.selectedRoutes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSelected checks if a specific route is selected.
|
// IsSelected checks if a specific route is selected.
|
||||||
@@ -128,14 +97,11 @@ func (rs *RouteSelector) IsSelected(routeID route.NetID) bool {
|
|||||||
defer rs.mu.RUnlock()
|
defer rs.mu.RUnlock()
|
||||||
|
|
||||||
if rs.deselectAll {
|
if rs.deselectAll {
|
||||||
log.Debugf("Route %s not selected (deselect all)", routeID)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
_, deselected := rs.deselectedRoutes[routeID]
|
_, deselected := rs.deselectedRoutes[routeID]
|
||||||
isSelected := !deselected
|
return !deselected
|
||||||
log.Debugf("Route %s selection status: %v (deselected: %v)", routeID, isSelected, deselected)
|
|
||||||
return isSelected
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterSelected removes unselected routes from the provided map.
|
// FilterSelected removes unselected routes from the provided map.
|
||||||
@@ -158,98 +124,15 @@ func (rs *RouteSelector) FilterSelected(routes route.HAMap) route.HAMap {
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasUserSelectionForRoute returns true if the user has explicitly selected or deselected this specific route
|
|
||||||
func (rs *RouteSelector) HasUserSelectionForRoute(routeID route.NetID) bool {
|
|
||||||
rs.mu.RLock()
|
|
||||||
defer rs.mu.RUnlock()
|
|
||||||
|
|
||||||
_, selected := rs.selectedRoutes[routeID]
|
|
||||||
_, deselected := rs.deselectedRoutes[routeID]
|
|
||||||
return selected || deselected
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *RouteSelector) FilterSelectedExitNodes(routes route.HAMap) route.HAMap {
|
|
||||||
rs.mu.RLock()
|
|
||||||
defer rs.mu.RUnlock()
|
|
||||||
|
|
||||||
if rs.deselectAll {
|
|
||||||
return route.HAMap{}
|
|
||||||
}
|
|
||||||
|
|
||||||
filtered := make(route.HAMap, len(routes))
|
|
||||||
for id, rt := range routes {
|
|
||||||
netID := id.NetID()
|
|
||||||
if rs.isDeselected(netID) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isExitNode(rt) {
|
|
||||||
filtered[id] = rt
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
rs.applyExitNodeFilter(id, netID, rt, filtered)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filtered
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *RouteSelector) isDeselected(netID route.NetID) bool {
|
|
||||||
_, deselected := rs.deselectedRoutes[netID]
|
|
||||||
return deselected || rs.deselectAll
|
|
||||||
}
|
|
||||||
|
|
||||||
func isExitNode(rt []*route.Route) bool {
|
|
||||||
return len(rt) > 0 && rt[0].Network.String() == exitNodeCIDR
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *RouteSelector) applyExitNodeFilter(
|
|
||||||
id route.HAUniqueID,
|
|
||||||
netID route.NetID,
|
|
||||||
rt []*route.Route,
|
|
||||||
out route.HAMap,
|
|
||||||
) {
|
|
||||||
|
|
||||||
if rs.hasUserSelections() {
|
|
||||||
// user made explicit selects/deselects
|
|
||||||
if rs.IsSelected(netID) {
|
|
||||||
out[id] = rt
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// no explicit selections: only include routes marked !SkipAutoApply (=AutoApply)
|
|
||||||
sel := collectSelected(rt)
|
|
||||||
if len(sel) > 0 {
|
|
||||||
out[id] = sel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *RouteSelector) hasUserSelections() bool {
|
|
||||||
return len(rs.selectedRoutes) > 0 || len(rs.deselectedRoutes) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectSelected(rt []*route.Route) []*route.Route {
|
|
||||||
var sel []*route.Route
|
|
||||||
for _, r := range rt {
|
|
||||||
if !r.SkipAutoApply {
|
|
||||||
sel = append(sel, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sel
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface
|
// MarshalJSON implements the json.Marshaler interface
|
||||||
func (rs *RouteSelector) MarshalJSON() ([]byte, error) {
|
func (rs *RouteSelector) MarshalJSON() ([]byte, error) {
|
||||||
rs.mu.RLock()
|
rs.mu.RLock()
|
||||||
defer rs.mu.RUnlock()
|
defer rs.mu.RUnlock()
|
||||||
|
|
||||||
return json.Marshal(struct {
|
return json.Marshal(struct {
|
||||||
SelectedRoutes map[route.NetID]struct{} `json:"selected_routes"`
|
|
||||||
DeselectedRoutes map[route.NetID]struct{} `json:"deselected_routes"`
|
DeselectedRoutes map[route.NetID]struct{} `json:"deselected_routes"`
|
||||||
DeselectAll bool `json:"deselect_all"`
|
DeselectAll bool `json:"deselect_all"`
|
||||||
}{
|
}{
|
||||||
SelectedRoutes: rs.selectedRoutes,
|
|
||||||
DeselectedRoutes: rs.deselectedRoutes,
|
DeselectedRoutes: rs.deselectedRoutes,
|
||||||
DeselectAll: rs.deselectAll,
|
DeselectAll: rs.deselectAll,
|
||||||
})
|
})
|
||||||
@@ -264,13 +147,11 @@ func (rs *RouteSelector) UnmarshalJSON(data []byte) error {
|
|||||||
// Check for null or empty JSON
|
// Check for null or empty JSON
|
||||||
if len(data) == 0 || string(data) == "null" {
|
if len(data) == 0 || string(data) == "null" {
|
||||||
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
rs.deselectAll = false
|
rs.deselectAll = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var temp struct {
|
var temp struct {
|
||||||
SelectedRoutes map[route.NetID]struct{} `json:"selected_routes"`
|
|
||||||
DeselectedRoutes map[route.NetID]struct{} `json:"deselected_routes"`
|
DeselectedRoutes map[route.NetID]struct{} `json:"deselected_routes"`
|
||||||
DeselectAll bool `json:"deselect_all"`
|
DeselectAll bool `json:"deselect_all"`
|
||||||
}
|
}
|
||||||
@@ -279,16 +160,12 @@ func (rs *RouteSelector) UnmarshalJSON(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rs.selectedRoutes = temp.SelectedRoutes
|
|
||||||
rs.deselectedRoutes = temp.DeselectedRoutes
|
rs.deselectedRoutes = temp.DeselectedRoutes
|
||||||
rs.deselectAll = temp.DeselectAll
|
rs.deselectAll = temp.DeselectAll
|
||||||
|
|
||||||
if rs.deselectedRoutes == nil {
|
if rs.deselectedRoutes == nil {
|
||||||
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
rs.deselectedRoutes = map[route.NetID]struct{}{}
|
||||||
}
|
}
|
||||||
if rs.selectedRoutes == nil {
|
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package routeselector_test
|
package routeselector_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -274,62 +273,6 @@ func TestRouteSelector_FilterSelected(t *testing.T) {
|
|||||||
}, filtered)
|
}, filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouteSelector_FilterSelectedExitNodes(t *testing.T) {
|
|
||||||
rs := routeselector.NewRouteSelector()
|
|
||||||
|
|
||||||
// Create test routes
|
|
||||||
exitNode1 := &route.Route{
|
|
||||||
ID: "route1",
|
|
||||||
NetID: "net1",
|
|
||||||
Network: netip.MustParsePrefix("0.0.0.0/0"),
|
|
||||||
Peer: "peer1",
|
|
||||||
SkipAutoApply: false,
|
|
||||||
}
|
|
||||||
exitNode2 := &route.Route{
|
|
||||||
ID: "route2",
|
|
||||||
NetID: "net1",
|
|
||||||
Network: netip.MustParsePrefix("0.0.0.0/0"),
|
|
||||||
Peer: "peer2",
|
|
||||||
SkipAutoApply: true,
|
|
||||||
}
|
|
||||||
normalRoute := &route.Route{
|
|
||||||
ID: "route3",
|
|
||||||
NetID: "net2",
|
|
||||||
Network: netip.MustParsePrefix("192.168.1.0/24"),
|
|
||||||
Peer: "peer3",
|
|
||||||
SkipAutoApply: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
routes := route.HAMap{
|
|
||||||
"net1|0.0.0.0/0": {exitNode1, exitNode2},
|
|
||||||
"net2|192.168.1.0/24": {normalRoute},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test filtering
|
|
||||||
filtered := rs.FilterSelectedExitNodes(routes)
|
|
||||||
|
|
||||||
// Should only include selected exit nodes and all normal routes
|
|
||||||
assert.Len(t, filtered, 2)
|
|
||||||
assert.Len(t, filtered["net1|0.0.0.0/0"], 1) // Only the selected exit node
|
|
||||||
assert.Equal(t, exitNode1.ID, filtered["net1|0.0.0.0/0"][0].ID)
|
|
||||||
assert.Len(t, filtered["net2|192.168.1.0/24"], 1) // Normal route should be included
|
|
||||||
assert.Equal(t, normalRoute.ID, filtered["net2|192.168.1.0/24"][0].ID)
|
|
||||||
|
|
||||||
// Test with deselected routes
|
|
||||||
err := rs.DeselectRoutes([]route.NetID{"net1"}, []route.NetID{"net1", "net2"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
filtered = rs.FilterSelectedExitNodes(routes)
|
|
||||||
assert.Len(t, filtered, 1) // Only normal route should remain
|
|
||||||
assert.Len(t, filtered["net2|192.168.1.0/24"], 1)
|
|
||||||
assert.Equal(t, normalRoute.ID, filtered["net2|192.168.1.0/24"][0].ID)
|
|
||||||
|
|
||||||
// Test with deselect all
|
|
||||||
rs = routeselector.NewRouteSelector()
|
|
||||||
rs.DeselectAllRoutes()
|
|
||||||
filtered = rs.FilterSelectedExitNodes(routes)
|
|
||||||
assert.Len(t, filtered, 0) // No routes should be selected
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRouteSelector_NewRoutesBehavior(t *testing.T) {
|
func TestRouteSelector_NewRoutesBehavior(t *testing.T) {
|
||||||
initialRoutes := []route.NetID{"route1", "route2", "route3"}
|
initialRoutes := []route.NetID{"route1", "route2", "route3"}
|
||||||
newRoutes := []route.NetID{"route1", "route2", "route3", "route4", "route5"}
|
newRoutes := []route.NetID{"route1", "route2", "route3", "route4", "route5"}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/iface/netstack"
|
|
||||||
"github.com/pion/transport/v3"
|
"github.com/pion/transport/v3"
|
||||||
"github.com/pion/transport/v3/stdnet"
|
"github.com/pion/transport/v3/stdnet"
|
||||||
)
|
)
|
||||||
@@ -33,15 +32,9 @@ type Net struct {
|
|||||||
// NewNetWithDiscover creates a new StdNet instance.
|
// NewNetWithDiscover creates a new StdNet instance.
|
||||||
func NewNetWithDiscover(iFaceDiscover ExternalIFaceDiscover, disallowList []string) (*Net, error) {
|
func NewNetWithDiscover(iFaceDiscover ExternalIFaceDiscover, disallowList []string) (*Net, error) {
|
||||||
n := &Net{
|
n := &Net{
|
||||||
|
iFaceDiscover: newMobileIFaceDiscover(iFaceDiscover),
|
||||||
interfaceFilter: InterfaceFilter(disallowList),
|
interfaceFilter: InterfaceFilter(disallowList),
|
||||||
}
|
}
|
||||||
// current ExternalIFaceDiscover implement in android-client https://github.dev/netbirdio/android-client
|
|
||||||
// so in android cli use pionDiscover
|
|
||||||
if netstack.IsEnabled() {
|
|
||||||
n.iFaceDiscover = pionDiscover{}
|
|
||||||
} else {
|
|
||||||
newMobileIFaceDiscover(iFaceDiscover)
|
|
||||||
}
|
|
||||||
return n, n.UpdateInterfaces()
|
return n, n.UpdateInterfaces()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,7 +278,6 @@ type LoginRequest struct {
|
|||||||
BlockInbound *bool `protobuf:"varint,29,opt,name=block_inbound,json=blockInbound,proto3,oneof" json:"block_inbound,omitempty"`
|
BlockInbound *bool `protobuf:"varint,29,opt,name=block_inbound,json=blockInbound,proto3,oneof" json:"block_inbound,omitempty"`
|
||||||
ProfileName *string `protobuf:"bytes,30,opt,name=profileName,proto3,oneof" json:"profileName,omitempty"`
|
ProfileName *string `protobuf:"bytes,30,opt,name=profileName,proto3,oneof" json:"profileName,omitempty"`
|
||||||
Username *string `protobuf:"bytes,31,opt,name=username,proto3,oneof" json:"username,omitempty"`
|
Username *string `protobuf:"bytes,31,opt,name=username,proto3,oneof" json:"username,omitempty"`
|
||||||
Mtu *int64 `protobuf:"varint,32,opt,name=mtu,proto3,oneof" json:"mtu,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -531,13 +530,6 @@ func (x *LoginRequest) GetUsername() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *LoginRequest) GetMtu() int64 {
|
|
||||||
if x != nil && x.Mtu != nil {
|
|
||||||
return *x.Mtu
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginResponse struct {
|
type LoginResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
NeedsSSOLogin bool `protobuf:"varint,1,opt,name=needsSSOLogin,proto3" json:"needsSSOLogin,omitempty"`
|
NeedsSSOLogin bool `protobuf:"varint,1,opt,name=needsSSOLogin,proto3" json:"needsSSOLogin,omitempty"`
|
||||||
@@ -1042,7 +1034,6 @@ type GetConfigResponse struct {
|
|||||||
AdminURL string `protobuf:"bytes,5,opt,name=adminURL,proto3" json:"adminURL,omitempty"`
|
AdminURL string `protobuf:"bytes,5,opt,name=adminURL,proto3" json:"adminURL,omitempty"`
|
||||||
InterfaceName string `protobuf:"bytes,6,opt,name=interfaceName,proto3" json:"interfaceName,omitempty"`
|
InterfaceName string `protobuf:"bytes,6,opt,name=interfaceName,proto3" json:"interfaceName,omitempty"`
|
||||||
WireguardPort int64 `protobuf:"varint,7,opt,name=wireguardPort,proto3" json:"wireguardPort,omitempty"`
|
WireguardPort int64 `protobuf:"varint,7,opt,name=wireguardPort,proto3" json:"wireguardPort,omitempty"`
|
||||||
Mtu int64 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"`
|
|
||||||
DisableAutoConnect bool `protobuf:"varint,9,opt,name=disableAutoConnect,proto3" json:"disableAutoConnect,omitempty"`
|
DisableAutoConnect bool `protobuf:"varint,9,opt,name=disableAutoConnect,proto3" json:"disableAutoConnect,omitempty"`
|
||||||
ServerSSHAllowed bool `protobuf:"varint,10,opt,name=serverSSHAllowed,proto3" json:"serverSSHAllowed,omitempty"`
|
ServerSSHAllowed bool `protobuf:"varint,10,opt,name=serverSSHAllowed,proto3" json:"serverSSHAllowed,omitempty"`
|
||||||
RosenpassEnabled bool `protobuf:"varint,11,opt,name=rosenpassEnabled,proto3" json:"rosenpassEnabled,omitempty"`
|
RosenpassEnabled bool `protobuf:"varint,11,opt,name=rosenpassEnabled,proto3" json:"rosenpassEnabled,omitempty"`
|
||||||
@@ -1138,13 +1129,6 @@ func (x *GetConfigResponse) GetWireguardPort() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *GetConfigResponse) GetMtu() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Mtu
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetConfigResponse) GetDisableAutoConnect() bool {
|
func (x *GetConfigResponse) GetDisableAutoConnect() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.DisableAutoConnect
|
return x.DisableAutoConnect
|
||||||
@@ -3695,7 +3679,6 @@ type SetConfigRequest struct {
|
|||||||
// cleanDNSLabels clean map list of DNS labels.
|
// cleanDNSLabels clean map list of DNS labels.
|
||||||
CleanDNSLabels bool `protobuf:"varint,26,opt,name=cleanDNSLabels,proto3" json:"cleanDNSLabels,omitempty"`
|
CleanDNSLabels bool `protobuf:"varint,26,opt,name=cleanDNSLabels,proto3" json:"cleanDNSLabels,omitempty"`
|
||||||
DnsRouteInterval *durationpb.Duration `protobuf:"bytes,27,opt,name=dnsRouteInterval,proto3,oneof" json:"dnsRouteInterval,omitempty"`
|
DnsRouteInterval *durationpb.Duration `protobuf:"bytes,27,opt,name=dnsRouteInterval,proto3,oneof" json:"dnsRouteInterval,omitempty"`
|
||||||
Mtu *int64 `protobuf:"varint,28,opt,name=mtu,proto3,oneof" json:"mtu,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -3919,13 +3902,6 @@ func (x *SetConfigRequest) GetDnsRouteInterval() *durationpb.Duration {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SetConfigRequest) GetMtu() int64 {
|
|
||||||
if x != nil && x.Mtu != nil {
|
|
||||||
return *x.Mtu
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type SetConfigResponse struct {
|
type SetConfigResponse struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
@@ -4454,94 +4430,6 @@ func (*LogoutResponse) Descriptor() ([]byte, []int) {
|
|||||||
return file_daemon_proto_rawDescGZIP(), []int{66}
|
return file_daemon_proto_rawDescGZIP(), []int{66}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetFeaturesRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetFeaturesRequest) Reset() {
|
|
||||||
*x = GetFeaturesRequest{}
|
|
||||||
mi := &file_daemon_proto_msgTypes[67]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetFeaturesRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetFeaturesRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetFeaturesRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_daemon_proto_msgTypes[67]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetFeaturesRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetFeaturesRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_daemon_proto_rawDescGZIP(), []int{67}
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetFeaturesResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
DisableProfiles bool `protobuf:"varint,1,opt,name=disable_profiles,json=disableProfiles,proto3" json:"disable_profiles,omitempty"`
|
|
||||||
DisableUpdateSettings bool `protobuf:"varint,2,opt,name=disable_update_settings,json=disableUpdateSettings,proto3" json:"disable_update_settings,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetFeaturesResponse) Reset() {
|
|
||||||
*x = GetFeaturesResponse{}
|
|
||||||
mi := &file_daemon_proto_msgTypes[68]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetFeaturesResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetFeaturesResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetFeaturesResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_daemon_proto_msgTypes[68]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetFeaturesResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetFeaturesResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_daemon_proto_rawDescGZIP(), []int{68}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetFeaturesResponse) GetDisableProfiles() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.DisableProfiles
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetFeaturesResponse) GetDisableUpdateSettings() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.DisableUpdateSettings
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type PortInfo_Range struct {
|
type PortInfo_Range struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Start uint32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"`
|
Start uint32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"`
|
||||||
@@ -4552,7 +4440,7 @@ type PortInfo_Range struct {
|
|||||||
|
|
||||||
func (x *PortInfo_Range) Reset() {
|
func (x *PortInfo_Range) Reset() {
|
||||||
*x = PortInfo_Range{}
|
*x = PortInfo_Range{}
|
||||||
mi := &file_daemon_proto_msgTypes[70]
|
mi := &file_daemon_proto_msgTypes[68]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -4564,7 +4452,7 @@ func (x *PortInfo_Range) String() string {
|
|||||||
func (*PortInfo_Range) ProtoMessage() {}
|
func (*PortInfo_Range) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *PortInfo_Range) ProtoReflect() protoreflect.Message {
|
func (x *PortInfo_Range) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_daemon_proto_msgTypes[70]
|
mi := &file_daemon_proto_msgTypes[68]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -4599,7 +4487,7 @@ var File_daemon_proto protoreflect.FileDescriptor
|
|||||||
const file_daemon_proto_rawDesc = "" +
|
const file_daemon_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\fdaemon.proto\x12\x06daemon\x1a google/protobuf/descriptor.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/duration.proto\"\x0e\n" +
|
"\fdaemon.proto\x12\x06daemon\x1a google/protobuf/descriptor.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/duration.proto\"\x0e\n" +
|
||||||
"\fEmptyRequest\"\xc3\x0e\n" +
|
"\fEmptyRequest\"\xa4\x0e\n" +
|
||||||
"\fLoginRequest\x12\x1a\n" +
|
"\fLoginRequest\x12\x1a\n" +
|
||||||
"\bsetupKey\x18\x01 \x01(\tR\bsetupKey\x12&\n" +
|
"\bsetupKey\x18\x01 \x01(\tR\bsetupKey\x12&\n" +
|
||||||
"\fpreSharedKey\x18\x02 \x01(\tB\x02\x18\x01R\fpreSharedKey\x12$\n" +
|
"\fpreSharedKey\x18\x02 \x01(\tB\x02\x18\x01R\fpreSharedKey\x12$\n" +
|
||||||
@@ -4635,8 +4523,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\x15lazyConnectionEnabled\x18\x1c \x01(\bH\x0fR\x15lazyConnectionEnabled\x88\x01\x01\x12(\n" +
|
"\x15lazyConnectionEnabled\x18\x1c \x01(\bH\x0fR\x15lazyConnectionEnabled\x88\x01\x01\x12(\n" +
|
||||||
"\rblock_inbound\x18\x1d \x01(\bH\x10R\fblockInbound\x88\x01\x01\x12%\n" +
|
"\rblock_inbound\x18\x1d \x01(\bH\x10R\fblockInbound\x88\x01\x01\x12%\n" +
|
||||||
"\vprofileName\x18\x1e \x01(\tH\x11R\vprofileName\x88\x01\x01\x12\x1f\n" +
|
"\vprofileName\x18\x1e \x01(\tH\x11R\vprofileName\x88\x01\x01\x12\x1f\n" +
|
||||||
"\busername\x18\x1f \x01(\tH\x12R\busername\x88\x01\x01\x12\x15\n" +
|
"\busername\x18\x1f \x01(\tH\x12R\busername\x88\x01\x01B\x13\n" +
|
||||||
"\x03mtu\x18 \x01(\x03H\x13R\x03mtu\x88\x01\x01B\x13\n" +
|
|
||||||
"\x11_rosenpassEnabledB\x10\n" +
|
"\x11_rosenpassEnabledB\x10\n" +
|
||||||
"\x0e_interfaceNameB\x10\n" +
|
"\x0e_interfaceNameB\x10\n" +
|
||||||
"\x0e_wireguardPortB\x17\n" +
|
"\x0e_wireguardPortB\x17\n" +
|
||||||
@@ -4655,8 +4542,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\x16_lazyConnectionEnabledB\x10\n" +
|
"\x16_lazyConnectionEnabledB\x10\n" +
|
||||||
"\x0e_block_inboundB\x0e\n" +
|
"\x0e_block_inboundB\x0e\n" +
|
||||||
"\f_profileNameB\v\n" +
|
"\f_profileNameB\v\n" +
|
||||||
"\t_usernameB\x06\n" +
|
"\t_username\"\xb5\x01\n" +
|
||||||
"\x04_mtu\"\xb5\x01\n" +
|
|
||||||
"\rLoginResponse\x12$\n" +
|
"\rLoginResponse\x12$\n" +
|
||||||
"\rneedsSSOLogin\x18\x01 \x01(\bR\rneedsSSOLogin\x12\x1a\n" +
|
"\rneedsSSOLogin\x18\x01 \x01(\bR\rneedsSSOLogin\x12\x1a\n" +
|
||||||
"\buserCode\x18\x02 \x01(\tR\buserCode\x12(\n" +
|
"\buserCode\x18\x02 \x01(\tR\buserCode\x12(\n" +
|
||||||
@@ -4687,7 +4573,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\fDownResponse\"P\n" +
|
"\fDownResponse\"P\n" +
|
||||||
"\x10GetConfigRequest\x12 \n" +
|
"\x10GetConfigRequest\x12 \n" +
|
||||||
"\vprofileName\x18\x01 \x01(\tR\vprofileName\x12\x1a\n" +
|
"\vprofileName\x18\x01 \x01(\tR\vprofileName\x12\x1a\n" +
|
||||||
"\busername\x18\x02 \x01(\tR\busername\"\xb5\x06\n" +
|
"\busername\x18\x02 \x01(\tR\busername\"\xa3\x06\n" +
|
||||||
"\x11GetConfigResponse\x12$\n" +
|
"\x11GetConfigResponse\x12$\n" +
|
||||||
"\rmanagementUrl\x18\x01 \x01(\tR\rmanagementUrl\x12\x1e\n" +
|
"\rmanagementUrl\x18\x01 \x01(\tR\rmanagementUrl\x12\x1e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
@@ -4697,8 +4583,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\fpreSharedKey\x18\x04 \x01(\tR\fpreSharedKey\x12\x1a\n" +
|
"\fpreSharedKey\x18\x04 \x01(\tR\fpreSharedKey\x12\x1a\n" +
|
||||||
"\badminURL\x18\x05 \x01(\tR\badminURL\x12$\n" +
|
"\badminURL\x18\x05 \x01(\tR\badminURL\x12$\n" +
|
||||||
"\rinterfaceName\x18\x06 \x01(\tR\rinterfaceName\x12$\n" +
|
"\rinterfaceName\x18\x06 \x01(\tR\rinterfaceName\x12$\n" +
|
||||||
"\rwireguardPort\x18\a \x01(\x03R\rwireguardPort\x12\x10\n" +
|
"\rwireguardPort\x18\a \x01(\x03R\rwireguardPort\x12.\n" +
|
||||||
"\x03mtu\x18\b \x01(\x03R\x03mtu\x12.\n" +
|
|
||||||
"\x12disableAutoConnect\x18\t \x01(\bR\x12disableAutoConnect\x12*\n" +
|
"\x12disableAutoConnect\x18\t \x01(\bR\x12disableAutoConnect\x12*\n" +
|
||||||
"\x10serverSSHAllowed\x18\n" +
|
"\x10serverSSHAllowed\x18\n" +
|
||||||
" \x01(\bR\x10serverSSHAllowed\x12*\n" +
|
" \x01(\bR\x10serverSSHAllowed\x12*\n" +
|
||||||
@@ -4912,7 +4797,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\busername\x18\x02 \x01(\tH\x01R\busername\x88\x01\x01B\x0e\n" +
|
"\busername\x18\x02 \x01(\tH\x01R\busername\x88\x01\x01B\x0e\n" +
|
||||||
"\f_profileNameB\v\n" +
|
"\f_profileNameB\v\n" +
|
||||||
"\t_username\"\x17\n" +
|
"\t_username\"\x17\n" +
|
||||||
"\x15SwitchProfileResponse\"\x8e\r\n" +
|
"\x15SwitchProfileResponse\"\xef\f\n" +
|
||||||
"\x10SetConfigRequest\x12\x1a\n" +
|
"\x10SetConfigRequest\x12\x1a\n" +
|
||||||
"\busername\x18\x01 \x01(\tR\busername\x12 \n" +
|
"\busername\x18\x01 \x01(\tR\busername\x12 \n" +
|
||||||
"\vprofileName\x18\x02 \x01(\tR\vprofileName\x12$\n" +
|
"\vprofileName\x18\x02 \x01(\tR\vprofileName\x12$\n" +
|
||||||
@@ -4944,8 +4829,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\n" +
|
"\n" +
|
||||||
"dns_labels\x18\x19 \x03(\tR\tdnsLabels\x12&\n" +
|
"dns_labels\x18\x19 \x03(\tR\tdnsLabels\x12&\n" +
|
||||||
"\x0ecleanDNSLabels\x18\x1a \x01(\bR\x0ecleanDNSLabels\x12J\n" +
|
"\x0ecleanDNSLabels\x18\x1a \x01(\bR\x0ecleanDNSLabels\x12J\n" +
|
||||||
"\x10dnsRouteInterval\x18\x1b \x01(\v2\x19.google.protobuf.DurationH\x10R\x10dnsRouteInterval\x88\x01\x01\x12\x15\n" +
|
"\x10dnsRouteInterval\x18\x1b \x01(\v2\x19.google.protobuf.DurationH\x10R\x10dnsRouteInterval\x88\x01\x01B\x13\n" +
|
||||||
"\x03mtu\x18\x1c \x01(\x03H\x11R\x03mtu\x88\x01\x01B\x13\n" +
|
|
||||||
"\x11_rosenpassEnabledB\x10\n" +
|
"\x11_rosenpassEnabledB\x10\n" +
|
||||||
"\x0e_interfaceNameB\x10\n" +
|
"\x0e_interfaceNameB\x10\n" +
|
||||||
"\x0e_wireguardPortB\x17\n" +
|
"\x0e_wireguardPortB\x17\n" +
|
||||||
@@ -4962,8 +4846,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\x16_disable_notificationsB\x18\n" +
|
"\x16_disable_notificationsB\x18\n" +
|
||||||
"\x16_lazyConnectionEnabledB\x10\n" +
|
"\x16_lazyConnectionEnabledB\x10\n" +
|
||||||
"\x0e_block_inboundB\x13\n" +
|
"\x0e_block_inboundB\x13\n" +
|
||||||
"\x11_dnsRouteIntervalB\x06\n" +
|
"\x11_dnsRouteInterval\"\x13\n" +
|
||||||
"\x04_mtu\"\x13\n" +
|
|
||||||
"\x11SetConfigResponse\"Q\n" +
|
"\x11SetConfigResponse\"Q\n" +
|
||||||
"\x11AddProfileRequest\x12\x1a\n" +
|
"\x11AddProfileRequest\x12\x1a\n" +
|
||||||
"\busername\x18\x01 \x01(\tR\busername\x12 \n" +
|
"\busername\x18\x01 \x01(\tR\busername\x12 \n" +
|
||||||
@@ -4989,11 +4872,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\busername\x18\x02 \x01(\tH\x01R\busername\x88\x01\x01B\x0e\n" +
|
"\busername\x18\x02 \x01(\tH\x01R\busername\x88\x01\x01B\x0e\n" +
|
||||||
"\f_profileNameB\v\n" +
|
"\f_profileNameB\v\n" +
|
||||||
"\t_username\"\x10\n" +
|
"\t_username\"\x10\n" +
|
||||||
"\x0eLogoutResponse\"\x14\n" +
|
"\x0eLogoutResponse*b\n" +
|
||||||
"\x12GetFeaturesRequest\"x\n" +
|
|
||||||
"\x13GetFeaturesResponse\x12)\n" +
|
|
||||||
"\x10disable_profiles\x18\x01 \x01(\bR\x0fdisableProfiles\x126\n" +
|
|
||||||
"\x17disable_update_settings\x18\x02 \x01(\bR\x15disableUpdateSettings*b\n" +
|
|
||||||
"\bLogLevel\x12\v\n" +
|
"\bLogLevel\x12\v\n" +
|
||||||
"\aUNKNOWN\x10\x00\x12\t\n" +
|
"\aUNKNOWN\x10\x00\x12\t\n" +
|
||||||
"\x05PANIC\x10\x01\x12\t\n" +
|
"\x05PANIC\x10\x01\x12\t\n" +
|
||||||
@@ -5002,7 +4881,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\x04WARN\x10\x04\x12\b\n" +
|
"\x04WARN\x10\x04\x12\b\n" +
|
||||||
"\x04INFO\x10\x05\x12\t\n" +
|
"\x04INFO\x10\x05\x12\t\n" +
|
||||||
"\x05DEBUG\x10\x06\x12\t\n" +
|
"\x05DEBUG\x10\x06\x12\t\n" +
|
||||||
"\x05TRACE\x10\a2\x8f\x10\n" +
|
"\x05TRACE\x10\a2\xc5\x0f\n" +
|
||||||
"\rDaemonService\x126\n" +
|
"\rDaemonService\x126\n" +
|
||||||
"\x05Login\x12\x14.daemon.LoginRequest\x1a\x15.daemon.LoginResponse\"\x00\x12K\n" +
|
"\x05Login\x12\x14.daemon.LoginRequest\x1a\x15.daemon.LoginResponse\"\x00\x12K\n" +
|
||||||
"\fWaitSSOLogin\x12\x1b.daemon.WaitSSOLoginRequest\x1a\x1c.daemon.WaitSSOLoginResponse\"\x00\x12-\n" +
|
"\fWaitSSOLogin\x12\x1b.daemon.WaitSSOLoginRequest\x1a\x1c.daemon.WaitSSOLoginResponse\"\x00\x12-\n" +
|
||||||
@@ -5033,8 +4912,7 @@ const file_daemon_proto_rawDesc = "" +
|
|||||||
"\rRemoveProfile\x12\x1c.daemon.RemoveProfileRequest\x1a\x1d.daemon.RemoveProfileResponse\"\x00\x12K\n" +
|
"\rRemoveProfile\x12\x1c.daemon.RemoveProfileRequest\x1a\x1d.daemon.RemoveProfileResponse\"\x00\x12K\n" +
|
||||||
"\fListProfiles\x12\x1b.daemon.ListProfilesRequest\x1a\x1c.daemon.ListProfilesResponse\"\x00\x12W\n" +
|
"\fListProfiles\x12\x1b.daemon.ListProfilesRequest\x1a\x1c.daemon.ListProfilesResponse\"\x00\x12W\n" +
|
||||||
"\x10GetActiveProfile\x12\x1f.daemon.GetActiveProfileRequest\x1a .daemon.GetActiveProfileResponse\"\x00\x129\n" +
|
"\x10GetActiveProfile\x12\x1f.daemon.GetActiveProfileRequest\x1a .daemon.GetActiveProfileResponse\"\x00\x129\n" +
|
||||||
"\x06Logout\x12\x15.daemon.LogoutRequest\x1a\x16.daemon.LogoutResponse\"\x00\x12H\n" +
|
"\x06Logout\x12\x15.daemon.LogoutRequest\x1a\x16.daemon.LogoutResponse\"\x00B\bZ\x06/protob\x06proto3"
|
||||||
"\vGetFeatures\x12\x1a.daemon.GetFeaturesRequest\x1a\x1b.daemon.GetFeaturesResponse\"\x00B\bZ\x06/protob\x06proto3"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_daemon_proto_rawDescOnce sync.Once
|
file_daemon_proto_rawDescOnce sync.Once
|
||||||
@@ -5049,7 +4927,7 @@ func file_daemon_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||||
var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 72)
|
var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 70)
|
||||||
var file_daemon_proto_goTypes = []any{
|
var file_daemon_proto_goTypes = []any{
|
||||||
(LogLevel)(0), // 0: daemon.LogLevel
|
(LogLevel)(0), // 0: daemon.LogLevel
|
||||||
(SystemEvent_Severity)(0), // 1: daemon.SystemEvent.Severity
|
(SystemEvent_Severity)(0), // 1: daemon.SystemEvent.Severity
|
||||||
@@ -5121,20 +4999,18 @@ var file_daemon_proto_goTypes = []any{
|
|||||||
(*GetActiveProfileResponse)(nil), // 67: daemon.GetActiveProfileResponse
|
(*GetActiveProfileResponse)(nil), // 67: daemon.GetActiveProfileResponse
|
||||||
(*LogoutRequest)(nil), // 68: daemon.LogoutRequest
|
(*LogoutRequest)(nil), // 68: daemon.LogoutRequest
|
||||||
(*LogoutResponse)(nil), // 69: daemon.LogoutResponse
|
(*LogoutResponse)(nil), // 69: daemon.LogoutResponse
|
||||||
(*GetFeaturesRequest)(nil), // 70: daemon.GetFeaturesRequest
|
nil, // 70: daemon.Network.ResolvedIPsEntry
|
||||||
(*GetFeaturesResponse)(nil), // 71: daemon.GetFeaturesResponse
|
(*PortInfo_Range)(nil), // 71: daemon.PortInfo.Range
|
||||||
nil, // 72: daemon.Network.ResolvedIPsEntry
|
nil, // 72: daemon.SystemEvent.MetadataEntry
|
||||||
(*PortInfo_Range)(nil), // 73: daemon.PortInfo.Range
|
(*durationpb.Duration)(nil), // 73: google.protobuf.Duration
|
||||||
nil, // 74: daemon.SystemEvent.MetadataEntry
|
(*timestamppb.Timestamp)(nil), // 74: google.protobuf.Timestamp
|
||||||
(*durationpb.Duration)(nil), // 75: google.protobuf.Duration
|
|
||||||
(*timestamppb.Timestamp)(nil), // 76: google.protobuf.Timestamp
|
|
||||||
}
|
}
|
||||||
var file_daemon_proto_depIdxs = []int32{
|
var file_daemon_proto_depIdxs = []int32{
|
||||||
75, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
|
73, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
|
||||||
22, // 1: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
|
22, // 1: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus
|
||||||
76, // 2: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
|
74, // 2: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp
|
||||||
76, // 3: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp
|
74, // 3: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp
|
||||||
75, // 4: daemon.PeerState.latency:type_name -> google.protobuf.Duration
|
73, // 4: daemon.PeerState.latency:type_name -> google.protobuf.Duration
|
||||||
19, // 5: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
|
19, // 5: daemon.FullStatus.managementState:type_name -> daemon.ManagementState
|
||||||
18, // 6: daemon.FullStatus.signalState:type_name -> daemon.SignalState
|
18, // 6: daemon.FullStatus.signalState:type_name -> daemon.SignalState
|
||||||
17, // 7: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
|
17, // 7: daemon.FullStatus.localPeerState:type_name -> daemon.LocalPeerState
|
||||||
@@ -5143,8 +5019,8 @@ var file_daemon_proto_depIdxs = []int32{
|
|||||||
21, // 10: daemon.FullStatus.dns_servers:type_name -> daemon.NSGroupState
|
21, // 10: daemon.FullStatus.dns_servers:type_name -> daemon.NSGroupState
|
||||||
52, // 11: daemon.FullStatus.events:type_name -> daemon.SystemEvent
|
52, // 11: daemon.FullStatus.events:type_name -> daemon.SystemEvent
|
||||||
28, // 12: daemon.ListNetworksResponse.routes:type_name -> daemon.Network
|
28, // 12: daemon.ListNetworksResponse.routes:type_name -> daemon.Network
|
||||||
72, // 13: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry
|
70, // 13: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry
|
||||||
73, // 14: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range
|
71, // 14: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range
|
||||||
29, // 15: daemon.ForwardingRule.destinationPort:type_name -> daemon.PortInfo
|
29, // 15: daemon.ForwardingRule.destinationPort:type_name -> daemon.PortInfo
|
||||||
29, // 16: daemon.ForwardingRule.translatedPort:type_name -> daemon.PortInfo
|
29, // 16: daemon.ForwardingRule.translatedPort:type_name -> daemon.PortInfo
|
||||||
30, // 17: daemon.ForwardingRulesResponse.rules:type_name -> daemon.ForwardingRule
|
30, // 17: daemon.ForwardingRulesResponse.rules:type_name -> daemon.ForwardingRule
|
||||||
@@ -5155,10 +5031,10 @@ var file_daemon_proto_depIdxs = []int32{
|
|||||||
49, // 22: daemon.TracePacketResponse.stages:type_name -> daemon.TraceStage
|
49, // 22: daemon.TracePacketResponse.stages:type_name -> daemon.TraceStage
|
||||||
1, // 23: daemon.SystemEvent.severity:type_name -> daemon.SystemEvent.Severity
|
1, // 23: daemon.SystemEvent.severity:type_name -> daemon.SystemEvent.Severity
|
||||||
2, // 24: daemon.SystemEvent.category:type_name -> daemon.SystemEvent.Category
|
2, // 24: daemon.SystemEvent.category:type_name -> daemon.SystemEvent.Category
|
||||||
76, // 25: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp
|
74, // 25: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp
|
||||||
74, // 26: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry
|
72, // 26: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry
|
||||||
52, // 27: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent
|
52, // 27: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent
|
||||||
75, // 28: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
|
73, // 28: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration
|
||||||
65, // 29: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile
|
65, // 29: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile
|
||||||
27, // 30: daemon.Network.ResolvedIPsEntry.value:type_name -> daemon.IPList
|
27, // 30: daemon.Network.ResolvedIPsEntry.value:type_name -> daemon.IPList
|
||||||
4, // 31: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
|
4, // 31: daemon.DaemonService.Login:input_type -> daemon.LoginRequest
|
||||||
@@ -5188,37 +5064,35 @@ var file_daemon_proto_depIdxs = []int32{
|
|||||||
63, // 55: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest
|
63, // 55: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest
|
||||||
66, // 56: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest
|
66, // 56: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest
|
||||||
68, // 57: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest
|
68, // 57: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest
|
||||||
70, // 58: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest
|
5, // 58: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
|
||||||
5, // 59: daemon.DaemonService.Login:output_type -> daemon.LoginResponse
|
7, // 59: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
|
||||||
7, // 60: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse
|
9, // 60: daemon.DaemonService.Up:output_type -> daemon.UpResponse
|
||||||
9, // 61: daemon.DaemonService.Up:output_type -> daemon.UpResponse
|
11, // 61: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
|
||||||
11, // 62: daemon.DaemonService.Status:output_type -> daemon.StatusResponse
|
13, // 62: daemon.DaemonService.Down:output_type -> daemon.DownResponse
|
||||||
13, // 63: daemon.DaemonService.Down:output_type -> daemon.DownResponse
|
15, // 63: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
|
||||||
15, // 64: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse
|
24, // 64: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse
|
||||||
24, // 65: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse
|
26, // 65: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse
|
||||||
26, // 66: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse
|
26, // 66: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse
|
||||||
26, // 67: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse
|
31, // 67: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse
|
||||||
31, // 68: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse
|
33, // 68: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse
|
||||||
33, // 69: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse
|
35, // 69: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse
|
||||||
35, // 70: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse
|
37, // 70: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse
|
||||||
37, // 71: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse
|
40, // 71: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse
|
||||||
40, // 72: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse
|
42, // 72: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse
|
||||||
42, // 73: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse
|
44, // 73: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse
|
||||||
44, // 74: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse
|
46, // 74: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse
|
||||||
46, // 75: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse
|
50, // 75: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse
|
||||||
50, // 76: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse
|
52, // 76: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent
|
||||||
52, // 77: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent
|
54, // 77: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse
|
||||||
54, // 78: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse
|
56, // 78: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse
|
||||||
56, // 79: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse
|
58, // 79: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse
|
||||||
58, // 80: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse
|
60, // 80: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse
|
||||||
60, // 81: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse
|
62, // 81: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse
|
||||||
62, // 82: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse
|
64, // 82: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse
|
||||||
64, // 83: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse
|
67, // 83: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse
|
||||||
67, // 84: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse
|
69, // 84: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse
|
||||||
69, // 85: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse
|
58, // [58:85] is the sub-list for method output_type
|
||||||
71, // 86: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse
|
31, // [31:58] is the sub-list for method input_type
|
||||||
59, // [59:87] is the sub-list for method output_type
|
|
||||||
31, // [31:59] is the sub-list for method input_type
|
|
||||||
31, // [31:31] is the sub-list for extension type_name
|
31, // [31:31] is the sub-list for extension type_name
|
||||||
31, // [31:31] is the sub-list for extension extendee
|
31, // [31:31] is the sub-list for extension extendee
|
||||||
0, // [0:31] is the sub-list for field type_name
|
0, // [0:31] is the sub-list for field type_name
|
||||||
@@ -5246,7 +5120,7 @@ func file_daemon_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_proto_rawDesc), len(file_daemon_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_proto_rawDesc), len(file_daemon_proto_rawDesc)),
|
||||||
NumEnums: 3,
|
NumEnums: 3,
|
||||||
NumMessages: 72,
|
NumMessages: 70,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -82,8 +82,6 @@ service DaemonService {
|
|||||||
|
|
||||||
// Logout disconnects from the network and deletes the peer from the management server
|
// Logout disconnects from the network and deletes the peer from the management server
|
||||||
rpc Logout(LogoutRequest) returns (LogoutResponse) {}
|
rpc Logout(LogoutRequest) returns (LogoutResponse) {}
|
||||||
|
|
||||||
rpc GetFeatures(GetFeaturesRequest) returns (GetFeaturesResponse) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -156,8 +154,6 @@ message LoginRequest {
|
|||||||
|
|
||||||
optional string profileName = 30;
|
optional string profileName = 30;
|
||||||
optional string username = 31;
|
optional string username = 31;
|
||||||
|
|
||||||
optional int64 mtu = 32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message LoginResponse {
|
message LoginResponse {
|
||||||
@@ -225,8 +221,6 @@ message GetConfigResponse {
|
|||||||
|
|
||||||
int64 wireguardPort = 7;
|
int64 wireguardPort = 7;
|
||||||
|
|
||||||
int64 mtu = 8;
|
|
||||||
|
|
||||||
bool disableAutoConnect = 9;
|
bool disableAutoConnect = 9;
|
||||||
|
|
||||||
bool serverSSHAllowed = 10;
|
bool serverSSHAllowed = 10;
|
||||||
@@ -587,7 +581,6 @@ message SetConfigRequest {
|
|||||||
|
|
||||||
optional google.protobuf.Duration dnsRouteInterval = 27;
|
optional google.protobuf.Duration dnsRouteInterval = 27;
|
||||||
|
|
||||||
optional int64 mtu = 28;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetConfigResponse{}
|
message SetConfigResponse{}
|
||||||
@@ -632,10 +625,3 @@ message LogoutRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message LogoutResponse {}
|
message LogoutResponse {}
|
||||||
|
|
||||||
message GetFeaturesRequest{}
|
|
||||||
|
|
||||||
message GetFeaturesResponse{
|
|
||||||
bool disable_profiles = 1;
|
|
||||||
bool disable_update_settings = 2;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ type DaemonServiceClient interface {
|
|||||||
GetActiveProfile(ctx context.Context, in *GetActiveProfileRequest, opts ...grpc.CallOption) (*GetActiveProfileResponse, error)
|
GetActiveProfile(ctx context.Context, in *GetActiveProfileRequest, opts ...grpc.CallOption) (*GetActiveProfileResponse, error)
|
||||||
// Logout disconnects from the network and deletes the peer from the management server
|
// Logout disconnects from the network and deletes the peer from the management server
|
||||||
Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error)
|
Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error)
|
||||||
GetFeatures(ctx context.Context, in *GetFeaturesRequest, opts ...grpc.CallOption) (*GetFeaturesResponse, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type daemonServiceClient struct {
|
type daemonServiceClient struct {
|
||||||
@@ -340,15 +339,6 @@ func (c *daemonServiceClient) Logout(ctx context.Context, in *LogoutRequest, opt
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *daemonServiceClient) GetFeatures(ctx context.Context, in *GetFeaturesRequest, opts ...grpc.CallOption) (*GetFeaturesResponse, error) {
|
|
||||||
out := new(GetFeaturesResponse)
|
|
||||||
err := c.cc.Invoke(ctx, "/daemon.DaemonService/GetFeatures", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonServiceServer is the server API for DaemonService service.
|
// DaemonServiceServer is the server API for DaemonService service.
|
||||||
// All implementations must embed UnimplementedDaemonServiceServer
|
// All implementations must embed UnimplementedDaemonServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
@@ -398,7 +388,6 @@ type DaemonServiceServer interface {
|
|||||||
GetActiveProfile(context.Context, *GetActiveProfileRequest) (*GetActiveProfileResponse, error)
|
GetActiveProfile(context.Context, *GetActiveProfileRequest) (*GetActiveProfileResponse, error)
|
||||||
// Logout disconnects from the network and deletes the peer from the management server
|
// Logout disconnects from the network and deletes the peer from the management server
|
||||||
Logout(context.Context, *LogoutRequest) (*LogoutResponse, error)
|
Logout(context.Context, *LogoutRequest) (*LogoutResponse, error)
|
||||||
GetFeatures(context.Context, *GetFeaturesRequest) (*GetFeaturesResponse, error)
|
|
||||||
mustEmbedUnimplementedDaemonServiceServer()
|
mustEmbedUnimplementedDaemonServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,9 +476,6 @@ func (UnimplementedDaemonServiceServer) GetActiveProfile(context.Context, *GetAc
|
|||||||
func (UnimplementedDaemonServiceServer) Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) {
|
func (UnimplementedDaemonServiceServer) Logout(context.Context, *LogoutRequest) (*LogoutResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method Logout not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedDaemonServiceServer) GetFeatures(context.Context, *GetFeaturesRequest) (*GetFeaturesResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetFeatures not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedDaemonServiceServer) mustEmbedUnimplementedDaemonServiceServer() {}
|
func (UnimplementedDaemonServiceServer) mustEmbedUnimplementedDaemonServiceServer() {}
|
||||||
|
|
||||||
// UnsafeDaemonServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeDaemonServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
@@ -992,24 +978,6 @@ func _DaemonService_Logout_Handler(srv interface{}, ctx context.Context, dec fun
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _DaemonService_GetFeatures_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(GetFeaturesRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(DaemonServiceServer).GetFeatures(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/daemon.DaemonService/GetFeatures",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(DaemonServiceServer).GetFeatures(ctx, req.(*GetFeaturesRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonService_ServiceDesc is the grpc.ServiceDesc for DaemonService service.
|
// DaemonService_ServiceDesc is the grpc.ServiceDesc for DaemonService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@@ -1121,10 +1089,6 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "Logout",
|
MethodName: "Logout",
|
||||||
Handler: _DaemonService_Logout_Handler,
|
Handler: _DaemonService_Logout_Handler,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
MethodName: "GetFeatures",
|
|
||||||
Handler: _DaemonService_GetFeatures_Handler,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{
|
Streams: []grpc.StreamDesc{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,9 +46,8 @@ const (
|
|||||||
defaultMaxRetryTime = 14 * 24 * time.Hour
|
defaultMaxRetryTime = 14 * 24 * time.Hour
|
||||||
defaultRetryMultiplier = 1.7
|
defaultRetryMultiplier = 1.7
|
||||||
|
|
||||||
errRestoreResidualState = "failed to restore residual state: %v"
|
errRestoreResidualState = "failed to restore residual state: %v"
|
||||||
errProfilesDisabled = "profiles are disabled, you cannot use this feature without profiles enabled"
|
errProfilesDisabled = "profiles are disabled, you cannot use this feature without profiles enabled"
|
||||||
errUpdateSettingsDisabled = "update settings are disabled, you cannot use this feature without update settings enabled"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrServiceNotUp = errors.New("service is not up")
|
var ErrServiceNotUp = errors.New("service is not up")
|
||||||
@@ -75,9 +74,8 @@ type Server struct {
|
|||||||
persistSyncResponse bool
|
persistSyncResponse bool
|
||||||
isSessionActive atomic.Bool
|
isSessionActive atomic.Bool
|
||||||
|
|
||||||
profileManager *profilemanager.ServiceManager
|
profileManager *profilemanager.ServiceManager
|
||||||
profilesDisabled bool
|
profilesDisabled bool
|
||||||
updateSettingsDisabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type oauthAuthFlow struct {
|
type oauthAuthFlow struct {
|
||||||
@@ -88,15 +86,14 @@ type oauthAuthFlow struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New server instance constructor.
|
// New server instance constructor.
|
||||||
func New(ctx context.Context, logFile string, configFile string, profilesDisabled bool, updateSettingsDisabled bool) *Server {
|
func New(ctx context.Context, logFile string, configFile string, profilesDisabled bool) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
rootCtx: ctx,
|
rootCtx: ctx,
|
||||||
logFile: logFile,
|
logFile: logFile,
|
||||||
persistSyncResponse: true,
|
persistSyncResponse: true,
|
||||||
statusRecorder: peer.NewRecorder(""),
|
statusRecorder: peer.NewRecorder(""),
|
||||||
profileManager: profilemanager.NewServiceManager(configFile),
|
profileManager: profilemanager.NewServiceManager(configFile),
|
||||||
profilesDisabled: profilesDisabled,
|
profilesDisabled: profilesDisabled,
|
||||||
updateSettingsDisabled: updateSettingsDisabled,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,8 +322,8 @@ func (s *Server) SetConfig(callerCtx context.Context, msg *proto.SetConfigReques
|
|||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
defer s.mutex.Unlock()
|
defer s.mutex.Unlock()
|
||||||
|
|
||||||
if s.checkUpdateSettingsDisabled() {
|
if s.checkProfilesDisabled() {
|
||||||
return nil, gstatus.Errorf(codes.Unavailable, errUpdateSettingsDisabled)
|
return nil, gstatus.Errorf(codes.Unavailable, errProfilesDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
profState := profilemanager.ActiveProfileState{
|
profState := profilemanager.ActiveProfileState{
|
||||||
@@ -400,11 +397,6 @@ func (s *Server) SetConfig(callerCtx context.Context, msg *proto.SetConfigReques
|
|||||||
config.LazyConnectionEnabled = msg.LazyConnectionEnabled
|
config.LazyConnectionEnabled = msg.LazyConnectionEnabled
|
||||||
config.BlockInbound = msg.BlockInbound
|
config.BlockInbound = msg.BlockInbound
|
||||||
|
|
||||||
if msg.Mtu != nil {
|
|
||||||
mtu := uint16(*msg.Mtu)
|
|
||||||
config.MTU = &mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := profilemanager.UpdateConfig(config); err != nil {
|
if _, err := profilemanager.UpdateConfig(config); err != nil {
|
||||||
log.Errorf("failed to update profile config: %v", err)
|
log.Errorf("failed to update profile config: %v", err)
|
||||||
return nil, fmt.Errorf("failed to update profile config: %w", err)
|
return nil, fmt.Errorf("failed to update profile config: %w", err)
|
||||||
@@ -489,7 +481,6 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
|
|||||||
// nolint
|
// nolint
|
||||||
ctx = context.WithValue(ctx, system.DeviceNameCtxKey, msg.Hostname)
|
ctx = context.WithValue(ctx, system.DeviceNameCtxKey, msg.Hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
|
|
||||||
config, err := s.getConfig(activeProf)
|
config, err := s.getConfig(activeProf)
|
||||||
@@ -1111,7 +1102,6 @@ func (s *Server) GetConfig(ctx context.Context, req *proto.GetConfigRequest) (*p
|
|||||||
AdminURL: adminURL.String(),
|
AdminURL: adminURL.String(),
|
||||||
InterfaceName: cfg.WgIface,
|
InterfaceName: cfg.WgIface,
|
||||||
WireguardPort: int64(cfg.WgPort),
|
WireguardPort: int64(cfg.WgPort),
|
||||||
Mtu: int64(cfg.MTU),
|
|
||||||
DisableAutoConnect: cfg.DisableAutoConnect,
|
DisableAutoConnect: cfg.DisableAutoConnect,
|
||||||
ServerSSHAllowed: *cfg.ServerSSHAllowed,
|
ServerSSHAllowed: *cfg.ServerSSHAllowed,
|
||||||
RosenpassEnabled: cfg.RosenpassEnabled,
|
RosenpassEnabled: cfg.RosenpassEnabled,
|
||||||
@@ -1340,31 +1330,10 @@ func (s *Server) GetActiveProfile(ctx context.Context, msg *proto.GetActiveProfi
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFeatures returns the features supported by the daemon.
|
|
||||||
func (s *Server) GetFeatures(ctx context.Context, msg *proto.GetFeaturesRequest) (*proto.GetFeaturesResponse, error) {
|
|
||||||
s.mutex.Lock()
|
|
||||||
defer s.mutex.Unlock()
|
|
||||||
|
|
||||||
features := &proto.GetFeaturesResponse{
|
|
||||||
DisableProfiles: s.checkProfilesDisabled(),
|
|
||||||
DisableUpdateSettings: s.checkUpdateSettingsDisabled(),
|
|
||||||
}
|
|
||||||
|
|
||||||
return features, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) checkProfilesDisabled() bool {
|
func (s *Server) checkProfilesDisabled() bool {
|
||||||
// Check if the environment variable is set to disable profiles
|
// Check if the environment variable is set to disable profiles
|
||||||
if s.profilesDisabled {
|
if s.profilesDisabled {
|
||||||
return true
|
log.Warn("Profiles are disabled via NB_DISABLE_PROFILES environment variable")
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) checkUpdateSettingsDisabled() bool {
|
|
||||||
// Check if the environment variable is set to disable profiles
|
|
||||||
if s.updateSettingsDisabled {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import (
|
|||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
|
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
"github.com/netbirdio/netbird/management/internals/server/config"
|
|
||||||
"github.com/netbirdio/netbird/management/server/groups"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -26,6 +24,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
"github.com/netbirdio/netbird/client/internal/profilemanager"
|
"github.com/netbirdio/netbird/client/internal/profilemanager"
|
||||||
daemonProto "github.com/netbirdio/netbird/client/proto"
|
daemonProto "github.com/netbirdio/netbird/client/proto"
|
||||||
|
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
||||||
"github.com/netbirdio/netbird/management/server"
|
"github.com/netbirdio/netbird/management/server"
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
||||||
@@ -33,7 +32,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/settings"
|
"github.com/netbirdio/netbird/management/server/settings"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
"github.com/netbirdio/netbird/shared/signal/proto"
|
"github.com/netbirdio/netbird/shared/signal/proto"
|
||||||
signalServer "github.com/netbirdio/netbird/signal/server"
|
signalServer "github.com/netbirdio/netbird/signal/server"
|
||||||
)
|
)
|
||||||
@@ -95,7 +94,7 @@ func TestConnectWithRetryRuns(t *testing.T) {
|
|||||||
t.Fatalf("failed to set active profile state: %v", err)
|
t.Fatalf("failed to set active profile state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := New(ctx, "debug", "", false, false)
|
s := New(ctx, "debug", "", false)
|
||||||
|
|
||||||
s.config = config
|
s.config = config
|
||||||
|
|
||||||
@@ -152,7 +151,7 @@ func TestServer_Up(t *testing.T) {
|
|||||||
t.Fatalf("failed to set active profile state: %v", err)
|
t.Fatalf("failed to set active profile state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := New(ctx, "console", "", false, false)
|
s := New(ctx, "console", "", false)
|
||||||
|
|
||||||
err = s.Start()
|
err = s.Start()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -228,7 +227,7 @@ func TestServer_SubcribeEvents(t *testing.T) {
|
|||||||
t.Fatalf("failed to set active profile state: %v", err)
|
t.Fatalf("failed to set active profile state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := New(ctx, "console", "", false, false)
|
s := New(ctx, "console", "", false)
|
||||||
|
|
||||||
err = s.Start()
|
err = s.Start()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -267,10 +266,10 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
dataDir := t.TempDir()
|
dataDir := t.TempDir()
|
||||||
|
|
||||||
config := &config.Config{
|
config := &types.Config{
|
||||||
Stuns: []*config.Host{},
|
Stuns: []*types.Host{},
|
||||||
TURNConfig: &config.TURNConfig{},
|
TURNConfig: &types.TURNConfig{},
|
||||||
Signal: &config.Host{
|
Signal: &types.Host{
|
||||||
Proto: "http",
|
Proto: "http",
|
||||||
URI: signalAddr,
|
URI: signalAddr,
|
||||||
},
|
},
|
||||||
@@ -303,14 +302,13 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
|
|||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||||
groupsManager := groups.NewManagerMock()
|
|
||||||
|
|
||||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock, false)
|
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 {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager, groupsManager)
|
secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager)
|
||||||
mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, &server.MockIntegratedValidator{})
|
mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, &server.MockIntegratedValidator{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|||||||
@@ -257,7 +257,6 @@ type serviceClient struct {
|
|||||||
iPreSharedKey *widget.Entry
|
iPreSharedKey *widget.Entry
|
||||||
iInterfaceName *widget.Entry
|
iInterfaceName *widget.Entry
|
||||||
iInterfacePort *widget.Entry
|
iInterfacePort *widget.Entry
|
||||||
iMTU *widget.Entry
|
|
||||||
|
|
||||||
// switch elements for settings form
|
// switch elements for settings form
|
||||||
sRosenpassPermissive *widget.Check
|
sRosenpassPermissive *widget.Check
|
||||||
@@ -273,7 +272,6 @@ type serviceClient struct {
|
|||||||
RosenpassPermissive bool
|
RosenpassPermissive bool
|
||||||
interfaceName string
|
interfaceName string
|
||||||
interfacePort int
|
interfacePort int
|
||||||
mtu uint16
|
|
||||||
networkMonitor bool
|
networkMonitor bool
|
||||||
disableDNS bool
|
disableDNS bool
|
||||||
disableClientRoutes bool
|
disableClientRoutes bool
|
||||||
@@ -394,16 +392,6 @@ func (s *serviceClient) updateIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceClient) showSettingsUI() {
|
func (s *serviceClient) showSettingsUI() {
|
||||||
// Check if update settings are disabled by daemon
|
|
||||||
features, err := s.getFeatures()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get features from daemon: %v", err)
|
|
||||||
// Continue with default behavior if features can't be retrieved
|
|
||||||
} else if features != nil && features.DisableUpdateSettings {
|
|
||||||
log.Warn("Update settings are disabled by daemon")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add settings window UI elements.
|
// add settings window UI elements.
|
||||||
s.wSettings = s.app.NewWindow("NetBird Settings")
|
s.wSettings = s.app.NewWindow("NetBird Settings")
|
||||||
s.wSettings.SetOnClosed(s.cancel)
|
s.wSettings.SetOnClosed(s.cancel)
|
||||||
@@ -415,7 +403,6 @@ func (s *serviceClient) showSettingsUI() {
|
|||||||
s.iPreSharedKey = widget.NewPasswordEntry()
|
s.iPreSharedKey = widget.NewPasswordEntry()
|
||||||
s.iInterfaceName = widget.NewEntry()
|
s.iInterfaceName = widget.NewEntry()
|
||||||
s.iInterfacePort = widget.NewEntry()
|
s.iInterfacePort = widget.NewEntry()
|
||||||
s.iMTU = widget.NewEntry()
|
|
||||||
|
|
||||||
s.sRosenpassPermissive = widget.NewCheck("Enable Rosenpass permissive mode", nil)
|
s.sRosenpassPermissive = widget.NewCheck("Enable Rosenpass permissive mode", nil)
|
||||||
|
|
||||||
@@ -449,7 +436,6 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
{Text: "Quantum-Resistance", Widget: s.sRosenpassPermissive},
|
{Text: "Quantum-Resistance", Widget: s.sRosenpassPermissive},
|
||||||
{Text: "Interface Name", Widget: s.iInterfaceName},
|
{Text: "Interface Name", Widget: s.iInterfaceName},
|
||||||
{Text: "Interface Port", Widget: s.iInterfacePort},
|
{Text: "Interface Port", Widget: s.iInterfacePort},
|
||||||
{Text: "MTU", Widget: s.iMTU},
|
|
||||||
{Text: "Management URL", Widget: s.iMngURL},
|
{Text: "Management URL", Widget: s.iMngURL},
|
||||||
{Text: "Pre-shared Key", Widget: s.iPreSharedKey},
|
{Text: "Pre-shared Key", Widget: s.iPreSharedKey},
|
||||||
{Text: "Log File", Widget: s.iLogFile},
|
{Text: "Log File", Widget: s.iLogFile},
|
||||||
@@ -461,17 +447,6 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
},
|
},
|
||||||
SubmitText: "Save",
|
SubmitText: "Save",
|
||||||
OnSubmit: func() {
|
OnSubmit: func() {
|
||||||
// Check if update settings are disabled by daemon
|
|
||||||
features, err := s.getFeatures()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get features from daemon: %v", err)
|
|
||||||
// Continue with default behavior if features can't be retrieved
|
|
||||||
} else if features != nil && features.DisableUpdateSettings {
|
|
||||||
log.Warn("Configuration updates are disabled by daemon")
|
|
||||||
dialog.ShowError(fmt.Errorf("Configuration updates are disabled by daemon"), s.wSettings)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != censoredPreSharedKey {
|
if s.iPreSharedKey.Text != "" && s.iPreSharedKey.Text != censoredPreSharedKey {
|
||||||
// validate preSharedKey if it added
|
// validate preSharedKey if it added
|
||||||
if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil {
|
if _, err := wgtypes.ParseKey(s.iPreSharedKey.Text); err != nil {
|
||||||
@@ -486,21 +461,6 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var mtu int64
|
|
||||||
mtuText := strings.TrimSpace(s.iMTU.Text)
|
|
||||||
if mtuText != "" {
|
|
||||||
var err error
|
|
||||||
mtu, err = strconv.ParseInt(mtuText, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
dialog.ShowError(errors.New("Invalid MTU value"), s.wSettings)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if mtu < iface.MinMTU || mtu > iface.MaxMTU {
|
|
||||||
dialog.ShowError(fmt.Errorf("MTU must be between %d and %d bytes", iface.MinMTU, iface.MaxMTU), s.wSettings)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iMngURL := strings.TrimSpace(s.iMngURL.Text)
|
iMngURL := strings.TrimSpace(s.iMngURL.Text)
|
||||||
|
|
||||||
defer s.wSettings.Close()
|
defer s.wSettings.Close()
|
||||||
@@ -509,7 +469,6 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
if s.managementURL != iMngURL || s.preSharedKey != s.iPreSharedKey.Text ||
|
if s.managementURL != iMngURL || s.preSharedKey != s.iPreSharedKey.Text ||
|
||||||
s.RosenpassPermissive != s.sRosenpassPermissive.Checked ||
|
s.RosenpassPermissive != s.sRosenpassPermissive.Checked ||
|
||||||
s.interfaceName != s.iInterfaceName.Text || s.interfacePort != int(port) ||
|
s.interfaceName != s.iInterfaceName.Text || s.interfacePort != int(port) ||
|
||||||
s.mtu != uint16(mtu) ||
|
|
||||||
s.networkMonitor != s.sNetworkMonitor.Checked ||
|
s.networkMonitor != s.sNetworkMonitor.Checked ||
|
||||||
s.disableDNS != s.sDisableDNS.Checked ||
|
s.disableDNS != s.sDisableDNS.Checked ||
|
||||||
s.disableClientRoutes != s.sDisableClientRoutes.Checked ||
|
s.disableClientRoutes != s.sDisableClientRoutes.Checked ||
|
||||||
@@ -518,7 +477,6 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
|
|
||||||
s.managementURL = iMngURL
|
s.managementURL = iMngURL
|
||||||
s.preSharedKey = s.iPreSharedKey.Text
|
s.preSharedKey = s.iPreSharedKey.Text
|
||||||
s.mtu = uint16(mtu)
|
|
||||||
|
|
||||||
currUser, err := user.Current()
|
currUser, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -537,9 +495,6 @@ func (s *serviceClient) getSettingsForm() *widget.Form {
|
|||||||
req.RosenpassPermissive = &s.sRosenpassPermissive.Checked
|
req.RosenpassPermissive = &s.sRosenpassPermissive.Checked
|
||||||
req.InterfaceName = &s.iInterfaceName.Text
|
req.InterfaceName = &s.iInterfaceName.Text
|
||||||
req.WireguardPort = &port
|
req.WireguardPort = &port
|
||||||
if mtu > 0 {
|
|
||||||
req.Mtu = &mtu
|
|
||||||
}
|
|
||||||
req.NetworkMonitor = &s.sNetworkMonitor.Checked
|
req.NetworkMonitor = &s.sNetworkMonitor.Checked
|
||||||
req.DisableDns = &s.sDisableDNS.Checked
|
req.DisableDns = &s.sDisableDNS.Checked
|
||||||
req.DisableClientRoutes = &s.sDisableClientRoutes.Checked
|
req.DisableClientRoutes = &s.sDisableClientRoutes.Checked
|
||||||
@@ -881,20 +836,6 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
s.mCreateDebugBundle = s.mSettings.AddSubMenuItem("Create Debug Bundle", debugBundleMenuDescr)
|
s.mCreateDebugBundle = s.mSettings.AddSubMenuItem("Create Debug Bundle", debugBundleMenuDescr)
|
||||||
s.loadSettings()
|
s.loadSettings()
|
||||||
|
|
||||||
// Disable settings menu if update settings are disabled by daemon
|
|
||||||
features, err := s.getFeatures()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get features from daemon: %v", err)
|
|
||||||
// Continue with default behavior if features can't be retrieved
|
|
||||||
} else {
|
|
||||||
if features != nil && features.DisableUpdateSettings {
|
|
||||||
s.setSettingsEnabled(false)
|
|
||||||
}
|
|
||||||
if features != nil && features.DisableProfiles {
|
|
||||||
s.mProfile.setEnabled(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.exitNodeMu.Lock()
|
s.exitNodeMu.Lock()
|
||||||
s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
|
s.mExitNode = systray.AddMenuItem("Exit Node", exitNodeMenuDescr)
|
||||||
s.mExitNode.Disable()
|
s.mExitNode.Disable()
|
||||||
@@ -935,10 +876,6 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error while updating status: %v", err)
|
log.Errorf("error while updating status: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check features periodically to handle daemon restarts
|
|
||||||
s.checkAndUpdateFeatures()
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -1011,59 +948,6 @@ func (s *serviceClient) getSrvClient(timeout time.Duration) (proto.DaemonService
|
|||||||
return s.conn, nil
|
return s.conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setSettingsEnabled enables or disables the settings menu based on the provided state
|
|
||||||
func (s *serviceClient) setSettingsEnabled(enabled bool) {
|
|
||||||
if s.mSettings != nil {
|
|
||||||
if enabled {
|
|
||||||
s.mSettings.Enable()
|
|
||||||
s.mSettings.SetTooltip(settingsMenuDescr)
|
|
||||||
} else {
|
|
||||||
s.mSettings.Hide()
|
|
||||||
s.mSettings.SetTooltip("Settings are disabled by daemon")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkAndUpdateFeatures checks the current features and updates the UI accordingly
|
|
||||||
func (s *serviceClient) checkAndUpdateFeatures() {
|
|
||||||
features, err := s.getFeatures()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get features from daemon: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update settings menu based on current features
|
|
||||||
if features != nil && features.DisableUpdateSettings {
|
|
||||||
s.setSettingsEnabled(false)
|
|
||||||
} else {
|
|
||||||
s.setSettingsEnabled(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update profile menu based on current features
|
|
||||||
if s.mProfile != nil {
|
|
||||||
if features != nil && features.DisableProfiles {
|
|
||||||
s.mProfile.setEnabled(false)
|
|
||||||
} else {
|
|
||||||
s.mProfile.setEnabled(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFeatures from the daemon to determine which features are enabled/disabled.
|
|
||||||
func (s *serviceClient) getFeatures() (*proto.GetFeaturesResponse, error) {
|
|
||||||
conn, err := s.getSrvClient(failFastTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get client for features: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
features, err := conn.GetFeatures(s.ctx, &proto.GetFeaturesRequest{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get features from daemon: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return features, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getSrvConfig from the service to show it in the settings window.
|
// getSrvConfig from the service to show it in the settings window.
|
||||||
func (s *serviceClient) getSrvConfig() {
|
func (s *serviceClient) getSrvConfig() {
|
||||||
s.managementURL = profilemanager.DefaultManagementURL
|
s.managementURL = profilemanager.DefaultManagementURL
|
||||||
@@ -1112,7 +996,6 @@ func (s *serviceClient) getSrvConfig() {
|
|||||||
s.RosenpassPermissive = cfg.RosenpassPermissive
|
s.RosenpassPermissive = cfg.RosenpassPermissive
|
||||||
s.interfaceName = cfg.WgIface
|
s.interfaceName = cfg.WgIface
|
||||||
s.interfacePort = cfg.WgPort
|
s.interfacePort = cfg.WgPort
|
||||||
s.mtu = cfg.MTU
|
|
||||||
|
|
||||||
s.networkMonitor = *cfg.NetworkMonitor
|
s.networkMonitor = *cfg.NetworkMonitor
|
||||||
s.disableDNS = cfg.DisableDNS
|
s.disableDNS = cfg.DisableDNS
|
||||||
@@ -1125,12 +1008,6 @@ func (s *serviceClient) getSrvConfig() {
|
|||||||
s.iPreSharedKey.SetText(cfg.PreSharedKey)
|
s.iPreSharedKey.SetText(cfg.PreSharedKey)
|
||||||
s.iInterfaceName.SetText(cfg.WgIface)
|
s.iInterfaceName.SetText(cfg.WgIface)
|
||||||
s.iInterfacePort.SetText(strconv.Itoa(cfg.WgPort))
|
s.iInterfacePort.SetText(strconv.Itoa(cfg.WgPort))
|
||||||
if cfg.MTU != 0 {
|
|
||||||
s.iMTU.SetText(strconv.Itoa(int(cfg.MTU)))
|
|
||||||
} else {
|
|
||||||
s.iMTU.SetText("")
|
|
||||||
s.iMTU.SetPlaceHolder(strconv.Itoa(int(iface.DefaultMTU)))
|
|
||||||
}
|
|
||||||
s.sRosenpassPermissive.SetChecked(cfg.RosenpassPermissive)
|
s.sRosenpassPermissive.SetChecked(cfg.RosenpassPermissive)
|
||||||
if !cfg.RosenpassEnabled {
|
if !cfg.RosenpassEnabled {
|
||||||
s.sRosenpassPermissive.Disable()
|
s.sRosenpassPermissive.Disable()
|
||||||
@@ -1191,12 +1068,6 @@ func protoConfigToConfig(cfg *proto.GetConfigResponse) *profilemanager.Config {
|
|||||||
config.WgPort = iface.DefaultWgPort
|
config.WgPort = iface.DefaultWgPort
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Mtu != 0 {
|
|
||||||
config.MTU = uint16(cfg.Mtu)
|
|
||||||
} else {
|
|
||||||
config.MTU = iface.DefaultMTU
|
|
||||||
}
|
|
||||||
|
|
||||||
config.DisableAutoConnect = cfg.DisableAutoConnect
|
config.DisableAutoConnect = cfg.DisableAutoConnect
|
||||||
config.ServerSSHAllowed = &cfg.ServerSSHAllowed
|
config.ServerSSHAllowed = &cfg.ServerSSHAllowed
|
||||||
config.RosenpassEnabled = cfg.RosenpassEnabled
|
config.RosenpassEnabled = cfg.RosenpassEnabled
|
||||||
|
|||||||
@@ -654,19 +654,6 @@ func (p *profileMenu) clear(profiles []Profile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setEnabled enables or disables the profile menu based on the provided state
|
|
||||||
func (p *profileMenu) setEnabled(enabled bool) {
|
|
||||||
if p.profileMenuItem != nil {
|
|
||||||
if enabled {
|
|
||||||
p.profileMenuItem.Enable()
|
|
||||||
p.profileMenuItem.SetTooltip("")
|
|
||||||
} else {
|
|
||||||
p.profileMenuItem.Hide()
|
|
||||||
p.profileMenuItem.SetTooltip("Profiles are disabled by daemon")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *profileMenu) updateMenu() {
|
func (p *profileMenu) updateMenu() {
|
||||||
// check every second
|
// check every second
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
@@ -675,6 +662,7 @@ func (p *profileMenu) updateMenu() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
|
||||||
// get profilesList
|
// get profilesList
|
||||||
profiles, err := p.getProfiles()
|
profiles, err := p.getProfiles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
44
go.mod
44
go.mod
@@ -6,6 +6,7 @@ require (
|
|||||||
cunicu.li/go-rosenpass v0.4.0
|
cunicu.li/go-rosenpass v0.4.0
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
github.com/cloudflare/circl v1.3.3 // indirect
|
github.com/cloudflare/circl v1.3.3 // indirect
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/golang/protobuf v1.5.4
|
github.com/golang/protobuf v1.5.4
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
@@ -18,12 +19,12 @@ require (
|
|||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/vishvananda/netlink v1.3.0
|
github.com/vishvananda/netlink v1.3.0
|
||||||
golang.org/x/crypto v0.40.0
|
golang.org/x/crypto v0.37.0
|
||||||
golang.org/x/sys v0.34.0
|
golang.org/x/sys v0.32.0
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1
|
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||||
google.golang.org/grpc v1.73.0
|
google.golang.org/grpc v1.64.1
|
||||||
google.golang.org/protobuf v1.36.6
|
google.golang.org/protobuf v1.36.6
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
)
|
)
|
||||||
@@ -47,7 +48,6 @@ require (
|
|||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/gliderlabs/ssh v0.3.8
|
github.com/gliderlabs/ssh v0.3.8
|
||||||
github.com/godbus/dbus/v5 v5.1.0
|
github.com/godbus/dbus/v5 v5.1.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/google/go-cmp v0.7.0
|
github.com/google/go-cmp v0.7.0
|
||||||
github.com/google/gopacket v1.1.19
|
github.com/google/gopacket v1.1.19
|
||||||
@@ -63,7 +63,7 @@ require (
|
|||||||
github.com/miekg/dns v1.1.59
|
github.com/miekg/dns v1.1.59
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||||
github.com/nadoo/ipset v0.5.0
|
github.com/nadoo/ipset v0.5.0
|
||||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20250820151658-9ee1b34f4190
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250805121557-5f225a973d1f
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45
|
||||||
github.com/okta/okta-sdk-golang/v2 v2.18.0
|
github.com/okta/okta-sdk-golang/v2 v2.18.0
|
||||||
github.com/oschwald/maxminddb-golang v1.12.0
|
github.com/oschwald/maxminddb-golang v1.12.0
|
||||||
@@ -93,18 +93,18 @@ require (
|
|||||||
github.com/yusufpapurcu/wmi v1.2.4
|
github.com/yusufpapurcu/wmi v1.2.4
|
||||||
github.com/zcalusic/sysinfo v1.1.3
|
github.com/zcalusic/sysinfo v1.1.3
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0
|
||||||
go.opentelemetry.io/otel v1.35.0
|
go.opentelemetry.io/otel v1.26.0
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0
|
go.opentelemetry.io/otel/exporters/prometheus v0.48.0
|
||||||
go.opentelemetry.io/otel/metric v1.35.0
|
go.opentelemetry.io/otel/metric v1.26.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0
|
go.opentelemetry.io/otel/sdk/metric v1.26.0
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
goauthentik.io/api/v3 v3.2023051.3
|
goauthentik.io/api/v3 v3.2023051.3
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a
|
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a
|
||||||
golang.org/x/net v0.42.0
|
golang.org/x/net v0.39.0
|
||||||
golang.org/x/oauth2 v0.28.0
|
golang.org/x/oauth2 v0.24.0
|
||||||
golang.org/x/sync v0.16.0
|
golang.org/x/sync v0.13.0
|
||||||
golang.org/x/term v0.33.0
|
golang.org/x/term v0.31.0
|
||||||
google.golang.org/api v0.177.0
|
google.golang.org/api v0.177.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gorm.io/driver/mysql v1.5.7
|
gorm.io/driver/mysql v1.5.7
|
||||||
@@ -117,7 +117,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
cloud.google.com/go/auth v0.3.0 // indirect
|
cloud.google.com/go/auth v0.3.0 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
@@ -144,14 +144,14 @@ require (
|
|||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/containerd/containerd v1.7.27 // indirect
|
github.com/containerd/containerd v1.7.26 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/containerd/platforms v0.2.1 // indirect
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/docker v28.0.0+incompatible // indirect
|
github.com/docker/docker v26.1.5+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
@@ -232,19 +232,19 @@ require (
|
|||||||
github.com/yuin/goldmark v1.7.1 // indirect
|
github.com/yuin/goldmark v1.7.1 // indirect
|
||||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.26.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
go.opentelemetry.io/otel/trace v1.26.0 // indirect
|
||||||
go.uber.org/mock v0.4.0 // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/image v0.18.0 // indirect
|
golang.org/x/image v0.18.0 // indirect
|
||||||
golang.org/x/mod v0.25.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/text v0.27.0 // indirect
|
golang.org/x/text v0.24.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.34.0 // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
95
go.sum
95
go.sum
@@ -29,8 +29,8 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
|
|||||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||||
@@ -142,8 +142,8 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
|
|||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
|
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
|
||||||
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||||
github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
|
github.com/containerd/containerd v1.7.26 h1:3cs8K2RHlMQaPifLqgRyI4VBkoldNdEw62cb7qQga7k=
|
||||||
github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
|
github.com/containerd/containerd v1.7.26/go.mod h1:m4JU0E+h0ebbo9yXD7Hyt+sWnc8tChm7MudCjj4jRvQ=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
@@ -167,8 +167,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v28.0.0+incompatible h1:Olh0KS820sJ7nPsBKChVhk5pzqcwDR15fumfAd/p9hM=
|
github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g=
|
||||||
github.com/docker/docker v28.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
@@ -246,8 +246,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
|||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@@ -503,8 +503,8 @@ github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944 h1:TDtJKmM6S
|
|||||||
github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944/go.mod h1:sHA6TRxjQ6RLbnI+3R4DZo2Eseg/iKiPRfNmcuNySVQ=
|
github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944/go.mod h1:sHA6TRxjQ6RLbnI+3R4DZo2Eseg/iKiPRfNmcuNySVQ=
|
||||||
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e h1:PURA50S8u4mF6RrkYYCAvvPCixhqqEiEy3Ej6avh04c=
|
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e h1:PURA50S8u4mF6RrkYYCAvvPCixhqqEiEy3Ej6avh04c=
|
||||||
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e/go.mod h1:YMLU7qbKfVjmEv7EoZPIVEI+kNYxWCdPK3VS0BU+U4Q=
|
github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e/go.mod h1:YMLU7qbKfVjmEv7EoZPIVEI+kNYxWCdPK3VS0BU+U4Q=
|
||||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20250820151658-9ee1b34f4190 h1:/ZbExdcDwRq6XgTpTf5I1DPqnC3eInEf0fcmkqR8eSg=
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250805121557-5f225a973d1f h1:YmqNWdRbeVn1lSpkLzIiFHX2cndRuaVYyynx2ibrOtg=
|
||||||
github.com/netbirdio/management-integrations/integrations v0.0.0-20250820151658-9ee1b34f4190/go.mod h1:v0nUbbHbuQnqR7yKIYnKzsLBCswLtp2JctmKYmGgVhc=
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20250805121557-5f225a973d1f/go.mod h1:Gi9raplYzCCyh07Olw/DVfCJTFgpr1WCXJ/Q+8TSA9Q=
|
||||||
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9axERMVN63dqyFqnvuD+EMJHzM7mNGON8=
|
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9axERMVN63dqyFqnvuD+EMJHzM7mNGON8=
|
||||||
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ=
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ=
|
||||||
@@ -588,8 +588,8 @@ github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0
|
|||||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
|
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
|
||||||
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
|
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
|
||||||
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
||||||
@@ -712,28 +712,26 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
|||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
|
||||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
|
||||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0 h1:sBQe3VNGUjY9IKWQC6z2lNqa5iGbDSxhs60ABwK4y0s=
|
go.opentelemetry.io/otel/exporters/prometheus v0.48.0 h1:sBQe3VNGUjY9IKWQC6z2lNqa5iGbDSxhs60ABwK4y0s=
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0/go.mod h1:DtrbMzoZWwQHyrQmCfLam5DZbnmorsGbOtTbYHycU5o=
|
go.opentelemetry.io/otel/exporters/prometheus v0.48.0/go.mod h1:DtrbMzoZWwQHyrQmCfLam5DZbnmorsGbOtTbYHycU5o=
|
||||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
|
||||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
go.opentelemetry.io/otel/sdk/metric v1.26.0 h1:cWSks5tfriHPdWFnl+qpX3P681aAYqlZHcAyHw5aU9Y=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
go.opentelemetry.io/otel/sdk/metric v1.26.0/go.mod h1:ClMFFknnThJCksebJwz7KIyEDHO+nTB6gK8obLy8RyE=
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
|
||||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
@@ -761,8 +759,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -808,8 +806,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -855,8 +853,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
|||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -870,8 +868,8 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ
|
|||||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||||
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
||||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -885,8 +883,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -954,8 +952,8 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@@ -963,8 +961,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
|||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -978,8 +976,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -1042,8 +1040,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -1126,11 +1124,10 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
|
|||||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434 h1:OpXbo8JnN8+jZGPrL4SSfaDjSCjupr8lXyBAbexEm/U=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 h1:hE3bRWtU6uceqlh4fhrSnUyjKHMKB9KrTLLG+bc0ddM=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434/go.mod h1:FfiGhwUm6CJviekPrc0oJ+7h29e+DmWU6UtjX0ZvI7Y=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
@@ -1151,8 +1148,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
|||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
|
||||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ upstream signal {
|
|||||||
server 127.0.0.1:10000;
|
server 127.0.0.1:10000;
|
||||||
}
|
}
|
||||||
upstream management {
|
upstream management {
|
||||||
# insert the grpc+http port of your management container here
|
# insert the grpc+http port of your signal container here
|
||||||
server 127.0.0.1:8012;
|
server 127.0.0.1:8012;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,40 +2,88 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"path"
|
"path"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
grpcMiddleware "github.com/grpc-ecosystem/go-grpc-middleware/v2"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/crypto/acme/autocert"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
"golang.org/x/net/http2/h2c"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/keepalive"
|
||||||
|
|
||||||
|
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/realip"
|
||||||
|
|
||||||
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/peers"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/encryption"
|
||||||
"github.com/netbirdio/netbird/formatter/hook"
|
"github.com/netbirdio/netbird/formatter/hook"
|
||||||
"github.com/netbirdio/netbird/management/internals/server"
|
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
||||||
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
|
"github.com/netbirdio/netbird/management/server"
|
||||||
|
"github.com/netbirdio/netbird/management/server/auth"
|
||||||
|
nbContext "github.com/netbirdio/netbird/management/server/context"
|
||||||
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
||||||
|
"github.com/netbirdio/netbird/management/server/groups"
|
||||||
|
nbhttp "github.com/netbirdio/netbird/management/server/http"
|
||||||
|
"github.com/netbirdio/netbird/management/server/idp"
|
||||||
|
"github.com/netbirdio/netbird/management/server/metrics"
|
||||||
|
"github.com/netbirdio/netbird/management/server/networks"
|
||||||
|
"github.com/netbirdio/netbird/management/server/networks/resources"
|
||||||
|
"github.com/netbirdio/netbird/management/server/networks/routers"
|
||||||
|
"github.com/netbirdio/netbird/management/server/settings"
|
||||||
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
|
"github.com/netbirdio/netbird/management/server/telemetry"
|
||||||
|
"github.com/netbirdio/netbird/management/server/users"
|
||||||
"github.com/netbirdio/netbird/util"
|
"github.com/netbirdio/netbird/util"
|
||||||
|
"github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
var newServer = func(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort int, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool) server.Server {
|
// ManagementLegacyPort is the port that was used before by the Management gRPC server.
|
||||||
return server.NewServer(config, dnsDomain, mgmtSingleAccModeDomain, mgmtPort, mgmtMetricsPort, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled)
|
// It is used for backward compatibility now.
|
||||||
}
|
const ManagementLegacyPort = 33073
|
||||||
|
|
||||||
func SetNewServer(fn func(config *nbconfig.Config, dnsDomain, mgmtSingleAccModeDomain string, mgmtPort int, mgmtMetricsPort int, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled bool) server.Server) {
|
|
||||||
newServer = fn
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
config *nbconfig.Config
|
mgmtPort int
|
||||||
|
mgmtMetricsPort int
|
||||||
|
mgmtLetsencryptDomain string
|
||||||
|
mgmtSingleAccModeDomain string
|
||||||
|
certFile string
|
||||||
|
certKey string
|
||||||
|
config *types.Config
|
||||||
|
|
||||||
|
kaep = keepalive.EnforcementPolicy{
|
||||||
|
MinTime: 15 * time.Second,
|
||||||
|
PermitWithoutStream: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
kasp = keepalive.ServerParameters{
|
||||||
|
MaxConnectionIdle: 15 * time.Second,
|
||||||
|
MaxConnectionAgeGrace: 5 * time.Second,
|
||||||
|
Time: 5 * time.Second,
|
||||||
|
Timeout: 2 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
mgmtCmd = &cobra.Command{
|
mgmtCmd = &cobra.Command{
|
||||||
Use: "management",
|
Use: "management",
|
||||||
@@ -54,9 +102,9 @@ var (
|
|||||||
// detect whether user specified a port
|
// detect whether user specified a port
|
||||||
userPort := cmd.Flag("port").Changed
|
userPort := cmd.Flag("port").Changed
|
||||||
|
|
||||||
config, err = loadMgmtConfig(ctx, nbconfig.MgmtConfigPath)
|
config, err = loadMgmtConfig(ctx, types.MgmtConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed reading provided config file: %s: %v", nbconfig.MgmtConfigPath, err)
|
return fmt.Errorf("failed reading provided config file: %s: %v", types.MgmtConfigPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Flag(idpSignKeyRefreshEnabledFlagName).Changed {
|
if cmd.Flag(idpSignKeyRefreshEnabledFlagName).Changed {
|
||||||
@@ -103,38 +151,356 @@ var (
|
|||||||
return fmt.Errorf("failed creating datadir: %s: %v", config.Datadir, err)
|
return fmt.Errorf("failed creating datadir: %s: %v", config.Datadir, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
appMetrics, err := telemetry.NewDefaultAppMetrics(cmd.Context())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = appMetrics.Expose(ctx, mgmtMetricsPort, "/metrics")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
integrationMetrics, err := integrations.InitIntegrationMetrics(ctx, appMetrics)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := store.NewStore(ctx, config.StoreConfig.Engine, config.Datadir, appMetrics, false)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating Store: %s: %v", config.Datadir, err)
|
||||||
|
}
|
||||||
|
peersUpdateManager := server.NewPeersUpdateManager(appMetrics)
|
||||||
|
|
||||||
|
var idpManager idp.Manager
|
||||||
|
if config.IdpManagerConfig != nil {
|
||||||
|
idpManager, err = idp.NewManager(ctx, *config.IdpManagerConfig, appMetrics)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed retrieving a new idp manager with err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if disableSingleAccMode {
|
if disableSingleAccMode {
|
||||||
mgmtSingleAccModeDomain = ""
|
mgmtSingleAccModeDomain = ""
|
||||||
}
|
}
|
||||||
|
eventStore, key, err := integrations.InitEventStore(ctx, config.Datadir, config.DataStoreEncryptionKey, integrationMetrics)
|
||||||
srv := newServer(config, dnsDomain, mgmtSingleAccModeDomain, mgmtPort, mgmtMetricsPort, disableMetrics, disableGeoliteUpdate, userDeleteFromIDPEnabled)
|
if err != nil {
|
||||||
go func() {
|
return fmt.Errorf("initialize database: %s", err)
|
||||||
if err := srv.Start(cmd.Context()); err != nil {
|
|
||||||
log.Fatalf("Server error: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
stopChan := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM)
|
|
||||||
select {
|
|
||||||
case <-stopChan:
|
|
||||||
log.Info("Received shutdown signal, stopping server...")
|
|
||||||
err = srv.Stop()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to stop server gracefully: %v", err)
|
|
||||||
}
|
|
||||||
case err := <-srv.Errors():
|
|
||||||
log.Fatalf("Server stopped unexpectedly: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.DataStoreEncryptionKey != key {
|
||||||
|
log.WithContext(ctx).Infof("update config with activity store key")
|
||||||
|
config.DataStoreEncryptionKey = key
|
||||||
|
err := updateMgmtConfig(ctx, types.MgmtConfigPath, config)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("write out store encryption key: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geo, err := geolocation.NewGeolocation(ctx, config.Datadir, !disableGeoliteUpdate)
|
||||||
|
if err != nil {
|
||||||
|
log.WithContext(ctx).Warnf("could not initialize geolocation service. proceeding without geolocation support: %v", err)
|
||||||
|
} else {
|
||||||
|
log.WithContext(ctx).Infof("geolocation service has been initialized from %s", config.Datadir)
|
||||||
|
}
|
||||||
|
|
||||||
|
integratedPeerValidator, err := integrations.NewIntegratedValidator(ctx, eventStore)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("initialize integrated peer validator: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionsManager := integrations.InitPermissionsManager(store)
|
||||||
|
userManager := users.NewManager(store)
|
||||||
|
extraSettingsManager := integrations.NewManager(eventStore)
|
||||||
|
settingsManager := settings.NewManager(store, userManager, extraSettingsManager, permissionsManager)
|
||||||
|
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, config.DisableDefaultPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("build default manager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsManager)
|
||||||
|
|
||||||
|
trustedPeers := config.ReverseProxy.TrustedPeers
|
||||||
|
defaultTrustedPeers := []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0")}
|
||||||
|
if len(trustedPeers) == 0 || slices.Equal[[]netip.Prefix](trustedPeers, defaultTrustedPeers) {
|
||||||
|
log.WithContext(ctx).Warn("TrustedPeers are configured to default value '0.0.0.0/0', '::/0'. This allows connection IP spoofing.")
|
||||||
|
trustedPeers = defaultTrustedPeers
|
||||||
|
}
|
||||||
|
trustedHTTPProxies := config.ReverseProxy.TrustedHTTPProxies
|
||||||
|
trustedProxiesCount := config.ReverseProxy.TrustedHTTPProxiesCount
|
||||||
|
if len(trustedHTTPProxies) > 0 && trustedProxiesCount > 0 {
|
||||||
|
log.WithContext(ctx).Warn("TrustedHTTPProxies and TrustedHTTPProxiesCount both are configured. " +
|
||||||
|
"This is not recommended way to extract X-Forwarded-For. Consider using one of these options.")
|
||||||
|
}
|
||||||
|
realipOpts := []realip.Option{
|
||||||
|
realip.WithTrustedPeers(trustedPeers),
|
||||||
|
realip.WithTrustedProxies(trustedHTTPProxies),
|
||||||
|
realip.WithTrustedProxiesCount(trustedProxiesCount),
|
||||||
|
realip.WithHeaders([]string{realip.XForwardedFor, realip.XRealIp}),
|
||||||
|
}
|
||||||
|
gRPCOpts := []grpc.ServerOption{
|
||||||
|
grpc.KeepaliveEnforcementPolicy(kaep),
|
||||||
|
grpc.KeepaliveParams(kasp),
|
||||||
|
grpc.ChainUnaryInterceptor(realip.UnaryServerInterceptorOpts(realipOpts...), unaryInterceptor),
|
||||||
|
grpc.ChainStreamInterceptor(realip.StreamServerInterceptorOpts(realipOpts...), streamInterceptor),
|
||||||
|
}
|
||||||
|
|
||||||
|
var certManager *autocert.Manager
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
tlsEnabled := false
|
||||||
|
if config.HttpConfig.LetsEncryptDomain != "" {
|
||||||
|
certManager, err = encryption.CreateCertManager(config.Datadir, config.HttpConfig.LetsEncryptDomain)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating LetsEncrypt cert manager: %v", err)
|
||||||
|
}
|
||||||
|
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
||||||
|
gRPCOpts = append(gRPCOpts, grpc.Creds(transportCredentials))
|
||||||
|
tlsEnabled = true
|
||||||
|
} else if config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "" {
|
||||||
|
tlsConfig, err = loadTLSConfig(config.HttpConfig.CertFile, config.HttpConfig.CertKey)
|
||||||
|
if err != nil {
|
||||||
|
log.WithContext(ctx).Errorf("cannot load TLS credentials: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
transportCredentials := credentials.NewTLS(tlsConfig)
|
||||||
|
gRPCOpts = append(gRPCOpts, grpc.Creds(transportCredentials))
|
||||||
|
tlsEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
authManager := auth.NewManager(store,
|
||||||
|
config.HttpConfig.AuthIssuer,
|
||||||
|
config.HttpConfig.AuthAudience,
|
||||||
|
config.HttpConfig.AuthKeysLocation,
|
||||||
|
config.HttpConfig.AuthUserIDClaim,
|
||||||
|
config.GetAuthAudiences(),
|
||||||
|
config.HttpConfig.IdpSignKeyRefreshEnabled)
|
||||||
|
|
||||||
|
groupsManager := groups.NewManager(store, permissionsManager, accountManager)
|
||||||
|
resourcesManager := resources.NewManager(store, permissionsManager, groupsManager, accountManager)
|
||||||
|
routersManager := routers.NewManager(store, permissionsManager, accountManager)
|
||||||
|
networksManager := networks.NewManager(store, permissionsManager, resourcesManager, routersManager, accountManager)
|
||||||
|
|
||||||
|
httpAPIHandler, err := nbhttp.NewAPIHandler(ctx, accountManager, networksManager, resourcesManager, routersManager, groupsManager, geo, authManager, appMetrics, integratedPeerValidator, proxyController, permissionsManager, peersManager, settingsManager)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating HTTP API handler: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ephemeralManager := server.NewEphemeralManager(store, accountManager)
|
||||||
|
ephemeralManager.LoadInitialPeers(ctx)
|
||||||
|
|
||||||
|
gRPCAPIHandler := grpc.NewServer(gRPCOpts...)
|
||||||
|
srv, err := server.NewServer(ctx, config, accountManager, settingsManager, peersUpdateManager, secretsManager, appMetrics, ephemeralManager, authManager, integratedPeerValidator)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating gRPC API handler: %v", err)
|
||||||
|
}
|
||||||
|
mgmtProto.RegisterManagementServiceServer(gRPCAPIHandler, srv)
|
||||||
|
|
||||||
|
installationID, err := getInstallationID(ctx, store)
|
||||||
|
if err != nil {
|
||||||
|
log.WithContext(ctx).Errorf("cannot load TLS credentials: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !disableMetrics {
|
||||||
|
idpManager := "disabled"
|
||||||
|
if config.IdpManagerConfig != nil && config.IdpManagerConfig.ManagerType != "" {
|
||||||
|
idpManager = config.IdpManagerConfig.ManagerType
|
||||||
|
}
|
||||||
|
metricsWorker := metrics.NewWorker(ctx, installationID, store, peersUpdateManager, idpManager)
|
||||||
|
go metricsWorker.Run(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
var compatListener net.Listener
|
||||||
|
if mgmtPort != ManagementLegacyPort {
|
||||||
|
// The Management gRPC server was running on port 33073 previously. Old agents that are already connected to it
|
||||||
|
// are using port 33073. For compatibility purposes we keep running a 2nd gRPC server on port 33073.
|
||||||
|
compatListener, err = serveGRPC(ctx, gRPCAPIHandler, ManagementLegacyPort)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.WithContext(ctx).Infof("running gRPC backward compatibility server: %s", compatListener.Addr().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
rootHandler := handlerFunc(gRPCAPIHandler, httpAPIHandler)
|
||||||
|
var listener net.Listener
|
||||||
|
if certManager != nil {
|
||||||
|
// a call to certManager.Listener() always creates a new listener so we do it once
|
||||||
|
cml := certManager.Listener()
|
||||||
|
if mgmtPort == 443 {
|
||||||
|
// CertManager, HTTP and gRPC API all on the same port
|
||||||
|
rootHandler = certManager.HTTPHandler(rootHandler)
|
||||||
|
listener = cml
|
||||||
|
} else {
|
||||||
|
listener, err = tls.Listen("tcp", fmt.Sprintf(":%d", mgmtPort), certManager.TLSConfig())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating TLS listener on port %d: %v", mgmtPort, err)
|
||||||
|
}
|
||||||
|
log.WithContext(ctx).Infof("running HTTP server (LetsEncrypt challenge handler): %s", cml.Addr().String())
|
||||||
|
serveHTTP(ctx, cml, certManager.HTTPHandler(nil))
|
||||||
|
}
|
||||||
|
} else if tlsConfig != nil {
|
||||||
|
listener, err = tls.Listen("tcp", fmt.Sprintf(":%d", mgmtPort), tlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating TLS listener on port %d: %v", mgmtPort, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listener, err = net.Listen("tcp", fmt.Sprintf(":%d", mgmtPort))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed creating TCP listener on port %d: %v", mgmtPort, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithContext(ctx).Infof("management server version %s", version.NetbirdVersion())
|
||||||
|
log.WithContext(ctx).Infof("running HTTP server and gRPC server on the same port: %s", listener.Addr().String())
|
||||||
|
serveGRPCWithHTTP(ctx, listener, rootHandler, tlsEnabled)
|
||||||
|
|
||||||
|
update := version.NewUpdate("nb/management")
|
||||||
|
update.SetDaemonVersion(version.NetbirdVersion())
|
||||||
|
update.SetOnUpdateListener(func() {
|
||||||
|
log.WithContext(ctx).Infof("your management version, \"%s\", is outdated, a new management version is available. Learn more here: https://github.com/netbirdio/netbird/releases", version.NetbirdVersion())
|
||||||
|
})
|
||||||
|
defer update.StopWatch()
|
||||||
|
|
||||||
|
SetupCloseHandler()
|
||||||
|
|
||||||
|
<-stopCh
|
||||||
|
integratedPeerValidator.Stop(ctx)
|
||||||
|
if geo != nil {
|
||||||
|
_ = geo.Stop()
|
||||||
|
}
|
||||||
|
ephemeralManager.Stop()
|
||||||
|
_ = appMetrics.Close()
|
||||||
|
_ = listener.Close()
|
||||||
|
if certManager != nil {
|
||||||
|
_ = certManager.Listener().Close()
|
||||||
|
}
|
||||||
|
gRPCAPIHandler.Stop()
|
||||||
|
_ = store.Close(ctx)
|
||||||
|
_ = eventStore.Close(ctx)
|
||||||
|
log.WithContext(ctx).Infof("stopped Management Service")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Config, error) {
|
func unaryInterceptor(
|
||||||
loadedConfig := &nbconfig.Config{}
|
ctx context.Context,
|
||||||
|
req interface{},
|
||||||
|
info *grpc.UnaryServerInfo,
|
||||||
|
handler grpc.UnaryHandler,
|
||||||
|
) (interface{}, error) {
|
||||||
|
reqID := uuid.New().String()
|
||||||
|
//nolint
|
||||||
|
ctx = context.WithValue(ctx, hook.ExecutionContextKey, hook.GRPCSource)
|
||||||
|
//nolint
|
||||||
|
ctx = context.WithValue(ctx, nbContext.RequestIDKey, reqID)
|
||||||
|
return handler(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func streamInterceptor(
|
||||||
|
srv interface{},
|
||||||
|
ss grpc.ServerStream,
|
||||||
|
info *grpc.StreamServerInfo,
|
||||||
|
handler grpc.StreamHandler,
|
||||||
|
) error {
|
||||||
|
reqID := uuid.New().String()
|
||||||
|
wrapped := grpcMiddleware.WrapServerStream(ss)
|
||||||
|
//nolint
|
||||||
|
ctx := context.WithValue(ss.Context(), hook.ExecutionContextKey, hook.GRPCSource)
|
||||||
|
//nolint
|
||||||
|
wrapped.WrappedContext = context.WithValue(ctx, nbContext.RequestIDKey, reqID)
|
||||||
|
return handler(srv, wrapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
func notifyStop(ctx context.Context, msg string) {
|
||||||
|
select {
|
||||||
|
case stopCh <- 1:
|
||||||
|
log.WithContext(ctx).Error(msg)
|
||||||
|
default:
|
||||||
|
// stop has been already called, nothing to report
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInstallationID(ctx context.Context, store store.Store) (string, error) {
|
||||||
|
installationID := store.GetInstallationID()
|
||||||
|
if installationID != "" {
|
||||||
|
return installationID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
installationID = strings.ToUpper(uuid.New().String())
|
||||||
|
err := store.SaveInstallationID(ctx, installationID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return installationID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveGRPC(ctx context.Context, grpcServer *grpc.Server, port int) (net.Listener, error) {
|
||||||
|
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
err := grpcServer.Serve(listener)
|
||||||
|
if err != nil {
|
||||||
|
notifyStop(ctx, fmt.Sprintf("failed running gRPC server on port %d: %v", port, err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return listener, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveHTTP(ctx context.Context, httpListener net.Listener, handler http.Handler) {
|
||||||
|
go func() {
|
||||||
|
err := http.Serve(httpListener, handler)
|
||||||
|
if err != nil {
|
||||||
|
notifyStop(ctx, fmt.Sprintf("failed running HTTP server: %v", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveGRPCWithHTTP(ctx context.Context, listener net.Listener, handler http.Handler, tlsEnabled bool) {
|
||||||
|
go func() {
|
||||||
|
var err error
|
||||||
|
if tlsEnabled {
|
||||||
|
err = http.Serve(listener, handler)
|
||||||
|
} else {
|
||||||
|
// the following magic is needed to support HTTP2 without TLS
|
||||||
|
// and still share a single port between gRPC and HTTP APIs
|
||||||
|
h1s := &http.Server{
|
||||||
|
Handler: h2c.NewHandler(handler, &http2.Server{}),
|
||||||
|
}
|
||||||
|
err = h1s.Serve(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case stopCh <- 1:
|
||||||
|
log.WithContext(ctx).Errorf("failed to serve HTTP and gRPC server: %v", err)
|
||||||
|
default:
|
||||||
|
// stop has been already called, nothing to report
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlerFunc(gRPCHandler *grpc.Server, httpHandler http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
grpcHeader := strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc") ||
|
||||||
|
strings.HasPrefix(request.Header.Get("Content-Type"), "application/grpc+proto")
|
||||||
|
if request.ProtoMajor == 2 && grpcHeader {
|
||||||
|
gRPCHandler.ServeHTTP(writer, request)
|
||||||
|
} else {
|
||||||
|
httpHandler.ServeHTTP(writer, request)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*types.Config, error) {
|
||||||
|
loadedConfig := &types.Config{}
|
||||||
_, err := util.ReadJsonWithEnvSub(mgmtConfigPath, loadedConfig)
|
_, err := util.ReadJsonWithEnvSub(mgmtConfigPath, loadedConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -169,7 +535,7 @@ func loadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi
|
|||||||
oidcConfig.JwksURI, loadedConfig.HttpConfig.AuthKeysLocation)
|
oidcConfig.JwksURI, loadedConfig.HttpConfig.AuthKeysLocation)
|
||||||
loadedConfig.HttpConfig.AuthKeysLocation = oidcConfig.JwksURI
|
loadedConfig.HttpConfig.AuthKeysLocation = oidcConfig.JwksURI
|
||||||
|
|
||||||
if !(loadedConfig.DeviceAuthorizationFlow == nil || strings.ToLower(loadedConfig.DeviceAuthorizationFlow.Provider) == string(nbconfig.NONE)) {
|
if !(loadedConfig.DeviceAuthorizationFlow == nil || strings.ToLower(loadedConfig.DeviceAuthorizationFlow.Provider) == string(types.NONE)) {
|
||||||
log.WithContext(ctx).Infof("overriding DeviceAuthorizationFlow.TokenEndpoint with a new value: %s, previously configured value: %s",
|
log.WithContext(ctx).Infof("overriding DeviceAuthorizationFlow.TokenEndpoint with a new value: %s, previously configured value: %s",
|
||||||
oidcConfig.TokenEndpoint, loadedConfig.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint)
|
oidcConfig.TokenEndpoint, loadedConfig.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint)
|
||||||
loadedConfig.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint = oidcConfig.TokenEndpoint
|
loadedConfig.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint = oidcConfig.TokenEndpoint
|
||||||
@@ -186,7 +552,7 @@ func loadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi
|
|||||||
loadedConfig.DeviceAuthorizationFlow.ProviderConfig.Domain = u.Host
|
loadedConfig.DeviceAuthorizationFlow.ProviderConfig.Domain = u.Host
|
||||||
|
|
||||||
if loadedConfig.DeviceAuthorizationFlow.ProviderConfig.Scope == "" {
|
if loadedConfig.DeviceAuthorizationFlow.ProviderConfig.Scope == "" {
|
||||||
loadedConfig.DeviceAuthorizationFlow.ProviderConfig.Scope = nbconfig.DefaultDeviceAuthFlowScope
|
loadedConfig.DeviceAuthorizationFlow.ProviderConfig.Scope = types.DefaultDeviceAuthFlowScope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +573,10 @@ func loadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi
|
|||||||
return loadedConfig, err
|
return loadedConfig, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateMgmtConfig(ctx context.Context, path string, config *types.Config) error {
|
||||||
|
return util.DirectWriteJson(ctx, path, config)
|
||||||
|
}
|
||||||
|
|
||||||
// OIDCConfigResponse used for parsing OIDC config response
|
// OIDCConfigResponse used for parsing OIDC config response
|
||||||
type OIDCConfigResponse struct {
|
type OIDCConfigResponse struct {
|
||||||
Issuer string `json:"issuer"`
|
Issuer string `json:"issuer"`
|
||||||
@@ -249,6 +619,25 @@ func fetchOIDCConfig(ctx context.Context, oidcEndpoint string) (OIDCConfigRespon
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadTLSConfig(certFile string, certKey string) (*tls.Config, error) {
|
||||||
|
// Load server's certificate and private key
|
||||||
|
serverCert, err := tls.LoadX509KeyPair(certFile, certKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultAppMetrics the credentials and return it
|
||||||
|
config := &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{serverCert},
|
||||||
|
ClientAuth: tls.NoClientCert,
|
||||||
|
NextProtos: []string{
|
||||||
|
"h2", "http/1.1", // enable HTTP/2
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleRebrand(cmd *cobra.Command) error {
|
func handleRebrand(cmd *cobra.Command) error {
|
||||||
var err error
|
var err error
|
||||||
if logFile == defaultLogFile {
|
if logFile == defaultLogFile {
|
||||||
@@ -260,7 +649,7 @@ func handleRebrand(cmd *cobra.Command) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nbconfig.MgmtConfigPath == defaultMgmtConfig {
|
if types.MgmtConfigPath == defaultMgmtConfig {
|
||||||
if migrateToNetbird(oldDefaultMgmtConfig, defaultMgmtConfig) {
|
if migrateToNetbird(oldDefaultMgmtConfig, defaultMgmtConfig) {
|
||||||
cmd.Printf("will copy Config dir %s and its content to %s\n", oldDefaultMgmtConfigDir, defaultMgmtConfigDir)
|
cmd.Printf("will copy Config dir %s and its content to %s\n", oldDefaultMgmtConfigDir, defaultMgmtConfigDir)
|
||||||
err = cpDir(oldDefaultMgmtConfigDir, defaultMgmtConfigDir)
|
err = cpDir(oldDefaultMgmtConfigDir, defaultMgmtConfigDir)
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
"github.com/netbirdio/netbird/version"
|
"github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,12 +27,6 @@ var (
|
|||||||
disableGeoliteUpdate bool
|
disableGeoliteUpdate bool
|
||||||
idpSignKeyRefreshEnabled bool
|
idpSignKeyRefreshEnabled bool
|
||||||
userDeleteFromIDPEnabled bool
|
userDeleteFromIDPEnabled bool
|
||||||
mgmtPort int
|
|
||||||
mgmtMetricsPort int
|
|
||||||
mgmtLetsencryptDomain string
|
|
||||||
mgmtSingleAccModeDomain string
|
|
||||||
certFile string
|
|
||||||
certKey string
|
|
||||||
|
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
Use: "netbird-mgmt",
|
Use: "netbird-mgmt",
|
||||||
@@ -46,6 +42,8 @@ var (
|
|||||||
Long: "",
|
Long: "",
|
||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
}
|
}
|
||||||
|
// Execution control channel for stopCh signal
|
||||||
|
stopCh chan int
|
||||||
)
|
)
|
||||||
|
|
||||||
// Execute executes the root command.
|
// Execute executes the root command.
|
||||||
@@ -54,10 +52,11 @@ func Execute() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
stopCh = make(chan int)
|
||||||
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 80, "server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 80, "server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
|
||||||
mgmtCmd.Flags().IntVar(&mgmtMetricsPort, "metrics-port", 9090, "metrics endpoint http port. Metrics are accessible under host:metrics-port/metrics")
|
mgmtCmd.Flags().IntVar(&mgmtMetricsPort, "metrics-port", 9090, "metrics endpoint http port. Metrics are accessible under host:metrics-port/metrics")
|
||||||
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", defaultMgmtDataDir, "server data directory location")
|
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", defaultMgmtDataDir, "server data directory location")
|
||||||
mgmtCmd.Flags().StringVar(&nbconfig.MgmtConfigPath, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
|
mgmtCmd.Flags().StringVar(&types.MgmtConfigPath, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
|
||||||
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
|
||||||
mgmtCmd.Flags().StringVar(&mgmtSingleAccModeDomain, "single-account-mode-domain", defaultSingleAccModeDomain, "Enables single account mode. This means that all the users will be under the same account grouped by the specified domain. If the installation has more than one account, the property is ineffective. Enabled by default with the default domain "+defaultSingleAccModeDomain)
|
mgmtCmd.Flags().StringVar(&mgmtSingleAccModeDomain, "single-account-mode-domain", defaultSingleAccModeDomain, "Enables single account mode. This means that all the users will be under the same account grouped by the specified domain. If the installation has more than one account, the property is ineffective. Enabled by default with the default domain "+defaultSingleAccModeDomain)
|
||||||
mgmtCmd.Flags().BoolVar(&disableSingleAccMode, "disable-single-account-mode", false, "If set to true, disables single account mode. The --single-account-mode-domain property will be ignored and every new user will have a separate NetBird account.")
|
mgmtCmd.Flags().BoolVar(&disableSingleAccMode, "disable-single-account-mode", false, "If set to true, disables single account mode. The --single-account-mode-domain property will be ignored and every new user will have a separate NetBird account.")
|
||||||
@@ -81,3 +80,15 @@ func init() {
|
|||||||
|
|
||||||
rootCmd.AddCommand(migrationCmd)
|
rootCmd.AddCommand(migrationCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetupCloseHandler handles SIGTERM signal and exits with success
|
||||||
|
func SetupCloseHandler() {
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
go func() {
|
||||||
|
for range c {
|
||||||
|
fmt.Println("\r- Ctrl+C pressed in Terminal")
|
||||||
|
stopCh <- 0
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
// @note this file includes all the lower level dependencies, db, http and grpc BaseServer, metrics, logger, etc.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"net/http"
|
|
||||||
"net/netip"
|
|
||||||
"slices"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
grpcMiddleware "github.com/grpc-ecosystem/go-grpc-middleware/v2"
|
|
||||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/realip"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
"google.golang.org/grpc/keepalive"
|
|
||||||
|
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
|
||||||
"github.com/netbirdio/netbird/encryption"
|
|
||||||
"github.com/netbirdio/netbird/formatter/hook"
|
|
||||||
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
|
|
||||||
"github.com/netbirdio/netbird/management/server"
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
|
||||||
nbContext "github.com/netbirdio/netbird/management/server/context"
|
|
||||||
nbhttp "github.com/netbirdio/netbird/management/server/http"
|
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
|
||||||
"github.com/netbirdio/netbird/management/server/telemetry"
|
|
||||||
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
kaep = keepalive.EnforcementPolicy{
|
|
||||||
MinTime: 15 * time.Second,
|
|
||||||
PermitWithoutStream: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
kasp = keepalive.ServerParameters{
|
|
||||||
MaxConnectionIdle: 15 * time.Second,
|
|
||||||
MaxConnectionAgeGrace: 5 * time.Second,
|
|
||||||
Time: 5 * time.Second,
|
|
||||||
Timeout: 2 * time.Second,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *BaseServer) Metrics() telemetry.AppMetrics {
|
|
||||||
return Create(s, func() telemetry.AppMetrics {
|
|
||||||
appMetrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error while creating app metrics: %s", err)
|
|
||||||
}
|
|
||||||
return appMetrics
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BaseServer) Store() store.Store {
|
|
||||||
return Create(s, func() store.Store {
|
|
||||||
store, err := store.NewStore(context.Background(), s.config.StoreConfig.Engine, s.config.Datadir, s.Metrics(), false)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to create store: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return store
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BaseServer) EventStore() activity.Store {
|
|
||||||
return Create(s, func() activity.Store {
|
|
||||||
integrationMetrics, err := integrations.InitIntegrationMetrics(context.Background(), s.Metrics())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to initialize integration metrics: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
eventStore, key, err := integrations.InitEventStore(context.Background(), s.config.Datadir, s.config.DataStoreEncryptionKey, integrationMetrics)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to initialize event store: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.config.DataStoreEncryptionKey != key {
|
|
||||||
log.WithContext(context.Background()).Infof("update config with activity store key")
|
|
||||||
s.config.DataStoreEncryptionKey = key
|
|
||||||
err := updateMgmtConfig(context.Background(), nbconfig.MgmtConfigPath, s.config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to update config with activity store: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return eventStore
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BaseServer) APIHandler() http.Handler {
|
|
||||||
return Create(s, func() http.Handler {
|
|
||||||
httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to create API handler: %v", err)
|
|
||||||
}
|
|
||||||
return httpAPIHandler
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BaseServer) GRPCServer() *grpc.Server {
|
|
||||||
return Create(s, func() *grpc.Server {
|
|
||||||
trustedPeers := s.config.ReverseProxy.TrustedPeers
|
|
||||||
defaultTrustedPeers := []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0")}
|
|
||||||
if len(trustedPeers) == 0 || slices.Equal[[]netip.Prefix](trustedPeers, defaultTrustedPeers) {
|
|
||||||
log.WithContext(context.Background()).Warn("TrustedPeers are configured to default value '0.0.0.0/0', '::/0'. This allows connection IP spoofing.")
|
|
||||||
trustedPeers = defaultTrustedPeers
|
|
||||||
}
|
|
||||||
trustedHTTPProxies := s.config.ReverseProxy.TrustedHTTPProxies
|
|
||||||
trustedProxiesCount := s.config.ReverseProxy.TrustedHTTPProxiesCount
|
|
||||||
if len(trustedHTTPProxies) > 0 && trustedProxiesCount > 0 {
|
|
||||||
log.WithContext(context.Background()).Warn("TrustedHTTPProxies and TrustedHTTPProxiesCount both are configured. " +
|
|
||||||
"This is not recommended way to extract X-Forwarded-For. Consider using one of these options.")
|
|
||||||
}
|
|
||||||
realipOpts := []realip.Option{
|
|
||||||
realip.WithTrustedPeers(trustedPeers),
|
|
||||||
realip.WithTrustedProxies(trustedHTTPProxies),
|
|
||||||
realip.WithTrustedProxiesCount(trustedProxiesCount),
|
|
||||||
realip.WithHeaders([]string{realip.XForwardedFor, realip.XRealIp}),
|
|
||||||
}
|
|
||||||
gRPCOpts := []grpc.ServerOption{
|
|
||||||
grpc.KeepaliveEnforcementPolicy(kaep),
|
|
||||||
grpc.KeepaliveParams(kasp),
|
|
||||||
grpc.ChainUnaryInterceptor(realip.UnaryServerInterceptorOpts(realipOpts...), unaryInterceptor),
|
|
||||||
grpc.ChainStreamInterceptor(realip.StreamServerInterceptorOpts(realipOpts...), streamInterceptor),
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.config.HttpConfig.LetsEncryptDomain != "" {
|
|
||||||
certManager, err := encryption.CreateCertManager(s.config.Datadir, s.config.HttpConfig.LetsEncryptDomain)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to create certificate manager: %v", err)
|
|
||||||
}
|
|
||||||
transportCredentials := credentials.NewTLS(certManager.TLSConfig())
|
|
||||||
gRPCOpts = append(gRPCOpts, grpc.Creds(transportCredentials))
|
|
||||||
} else if s.config.HttpConfig.CertFile != "" && s.config.HttpConfig.CertKey != "" {
|
|
||||||
tlsConfig, err := loadTLSConfig(s.config.HttpConfig.CertFile, s.config.HttpConfig.CertKey)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("cannot load TLS credentials: %v", err)
|
|
||||||
}
|
|
||||||
transportCredentials := credentials.NewTLS(tlsConfig)
|
|
||||||
gRPCOpts = append(gRPCOpts, grpc.Creds(transportCredentials))
|
|
||||||
}
|
|
||||||
|
|
||||||
gRPCAPIHandler := grpc.NewServer(gRPCOpts...)
|
|
||||||
srv, err := server.NewServer(context.Background(), s.config, s.AccountManager(), s.SettingsManager(), s.PeersUpdateManager(), s.SecretsManager(), s.Metrics(), s.EphemeralManager(), s.AuthManager(), s.IntegratedValidator())
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to create management server: %v", err)
|
|
||||||
}
|
|
||||||
mgmtProto.RegisterManagementServiceServer(gRPCAPIHandler, srv)
|
|
||||||
|
|
||||||
return gRPCAPIHandler
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadTLSConfig(certFile string, certKey string) (*tls.Config, error) {
|
|
||||||
// Load server's certificate and private key
|
|
||||||
serverCert, err := tls.LoadX509KeyPair(certFile, certKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDefaultAppMetrics the credentials and return it
|
|
||||||
config := &tls.Config{
|
|
||||||
Certificates: []tls.Certificate{serverCert},
|
|
||||||
ClientAuth: tls.NoClientCert,
|
|
||||||
NextProtos: []string{
|
|
||||||
"h2", "http/1.1", // enable HTTP/2
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unaryInterceptor(
|
|
||||||
ctx context.Context,
|
|
||||||
req interface{},
|
|
||||||
info *grpc.UnaryServerInfo,
|
|
||||||
handler grpc.UnaryHandler,
|
|
||||||
) (interface{}, error) {
|
|
||||||
reqID := uuid.New().String()
|
|
||||||
//nolint
|
|
||||||
ctx = context.WithValue(ctx, hook.ExecutionContextKey, hook.GRPCSource)
|
|
||||||
//nolint
|
|
||||||
ctx = context.WithValue(ctx, nbContext.RequestIDKey, reqID)
|
|
||||||
return handler(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func streamInterceptor(
|
|
||||||
srv interface{},
|
|
||||||
ss grpc.ServerStream,
|
|
||||||
info *grpc.StreamServerInfo,
|
|
||||||
handler grpc.StreamHandler,
|
|
||||||
) error {
|
|
||||||
reqID := uuid.New().String()
|
|
||||||
wrapped := grpcMiddleware.WrapServerStream(ss)
|
|
||||||
//nolint
|
|
||||||
ctx := context.WithValue(ss.Context(), hook.ExecutionContextKey, hook.GRPCSource)
|
|
||||||
//nolint
|
|
||||||
wrapped.WrappedContext = context.WithValue(ctx, nbContext.RequestIDKey, reqID)
|
|
||||||
return handler(srv, wrapped)
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user