mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-23 05:49:07 +02:00
[client] Increase ssh detection timeout (#4827)
This commit is contained in:
+13
-4
@@ -749,7 +749,9 @@ func sshProxyFn(cmd *cobra.Command, args []string) error {
|
|||||||
if firstLogFile := util.FindFirstLogPath(logFiles); firstLogFile != "" && firstLogFile != defaultLogFile {
|
if firstLogFile := util.FindFirstLogPath(logFiles); firstLogFile != "" && firstLogFile != defaultLogFile {
|
||||||
logOutput = firstLogFile
|
logOutput = firstLogFile
|
||||||
}
|
}
|
||||||
if err := util.InitLog(logLevel, logOutput); err != nil {
|
|
||||||
|
proxyLogLevel := getEnvOrDefault("LOG_LEVEL", logLevel)
|
||||||
|
if err := util.InitLog(proxyLogLevel, logOutput); err != nil {
|
||||||
return fmt.Errorf("init log: %w", err)
|
return fmt.Errorf("init log: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,7 +790,8 @@ var sshDetectCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sshDetectFn(cmd *cobra.Command, args []string) error {
|
func sshDetectFn(cmd *cobra.Command, args []string) error {
|
||||||
if err := util.InitLog(logLevel, "console"); err != nil {
|
detectLogLevel := getEnvOrDefault("LOG_LEVEL", logLevel)
|
||||||
|
if err := util.InitLog(detectLogLevel, "console"); err != nil {
|
||||||
os.Exit(detection.ServerTypeRegular.ExitCode())
|
os.Exit(detection.ServerTypeRegular.ExitCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,15 +800,21 @@ func sshDetectFn(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
port, err := strconv.Atoi(portStr)
|
port, err := strconv.Atoi(portStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Debugf("invalid port %q: %v", portStr, err)
|
||||||
os.Exit(detection.ServerTypeRegular.ExitCode())
|
os.Exit(detection.ServerTypeRegular.ExitCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
dialer := &net.Dialer{Timeout: detection.Timeout}
|
ctx, cancel := context.WithTimeout(cmd.Context(), detection.DefaultTimeout)
|
||||||
serverType, err := detection.DetectSSHServerType(cmd.Context(), dialer, host, port)
|
|
||||||
|
dialer := &net.Dialer{}
|
||||||
|
serverType, err := detection.DetectSSHServerType(ctx, dialer, host, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Debugf("SSH server detection failed: %v", err)
|
||||||
|
cancel()
|
||||||
os.Exit(detection.ServerTypeRegular.ExitCode())
|
os.Exit(detection.ServerTypeRegular.ExitCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
os.Exit(serverType.ExitCode())
|
os.Exit(serverType.ExitCode())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,10 +343,13 @@ func dialWithJWT(ctx context.Context, network, addr string, config *ssh.ClientCo
|
|||||||
return nil, fmt.Errorf("parse port %s: %w", portStr, err)
|
return nil, fmt.Errorf("parse port %s: %w", portStr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dialer := &net.Dialer{Timeout: detection.Timeout}
|
detectionCtx, cancel := context.WithTimeout(ctx, config.Timeout)
|
||||||
serverType, err := detection.DetectSSHServerType(ctx, dialer, host, port)
|
defer cancel()
|
||||||
|
|
||||||
|
dialer := &net.Dialer{}
|
||||||
|
serverType, err := detection.DetectSSHServerType(detectionCtx, dialer, host, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("SSH server detection failed: %w", err)
|
return nil, fmt.Errorf("SSH server detection: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !serverType.RequiresJWT() {
|
if !serverType.RequiresJWT() {
|
||||||
|
|||||||
@@ -189,12 +189,7 @@ func (m *Manager) buildPeerConfig(allHostPatterns []string) (string, error) {
|
|||||||
|
|
||||||
hostLine := strings.Join(deduplicatedPatterns, " ")
|
hostLine := strings.Join(deduplicatedPatterns, " ")
|
||||||
config := fmt.Sprintf("Host %s\n", hostLine)
|
config := fmt.Sprintf("Host %s\n", hostLine)
|
||||||
|
config += fmt.Sprintf(" Match exec \"%s ssh detect %%h %%p\"\n", execPath)
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
config += fmt.Sprintf(" Match exec \"%s ssh detect %%h %%p\"\n", execPath)
|
|
||||||
} else {
|
|
||||||
config += fmt.Sprintf(" Match exec \"%s ssh detect %%h %%p 2>/dev/null\"\n", execPath)
|
|
||||||
}
|
|
||||||
config += " PreferredAuthentications password,publickey,keyboard-interactive\n"
|
config += " PreferredAuthentications password,publickey,keyboard-interactive\n"
|
||||||
config += " PasswordAuthentication yes\n"
|
config += " PasswordAuthentication yes\n"
|
||||||
config += " PubkeyAuthentication yes\n"
|
config += " PubkeyAuthentication yes\n"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package detection
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -19,8 +20,8 @@ const (
|
|||||||
// JWTRequiredMarker is appended to responses when JWT is required
|
// JWTRequiredMarker is appended to responses when JWT is required
|
||||||
JWTRequiredMarker = "NetBird-JWT-Required"
|
JWTRequiredMarker = "NetBird-JWT-Required"
|
||||||
|
|
||||||
// Timeout is the timeout for SSH server detection
|
// DefaultTimeout is the default timeout for SSH server detection
|
||||||
Timeout = 5 * time.Second
|
DefaultTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerType string
|
type ServerType string
|
||||||
@@ -61,21 +62,20 @@ func DetectSSHServerType(ctx context.Context, dialer Dialer, host string, port i
|
|||||||
|
|
||||||
conn, err := dialer.DialContext(ctx, "tcp", targetAddr)
|
conn, err := dialer.DialContext(ctx, "tcp", targetAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("SSH connection failed for detection: %v", err)
|
return ServerTypeRegular, fmt.Errorf("connect to %s: %w", targetAddr, err)
|
||||||
return ServerTypeRegular, nil
|
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(Timeout)); err != nil {
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
log.Debugf("set read deadline: %v", err)
|
if err := conn.SetReadDeadline(deadline); err != nil {
|
||||||
return ServerTypeRegular, nil
|
return ServerTypeRegular, fmt.Errorf("set read deadline: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(conn)
|
reader := bufio.NewReader(conn)
|
||||||
serverBanner, err := reader.ReadString('\n')
|
serverBanner, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("read SSH banner: %v", err)
|
return ServerTypeRegular, fmt.Errorf("read SSH banner: %w", err)
|
||||||
return ServerTypeRegular, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverBanner = strings.TrimSpace(serverBanner)
|
serverBanner = strings.TrimSpace(serverBanner)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func TestJWTEnforcement(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
port, err := strconv.Atoi(portStr)
|
port, err := strconv.Atoi(portStr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dialer := &net.Dialer{Timeout: detection.Timeout}
|
dialer := &net.Dialer{}
|
||||||
serverType, err := detection.DetectSSHServerType(context.Background(), dialer, host, port)
|
serverType, err := detection.DetectSSHServerType(context.Background(), dialer, host, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("Detection failed: %v", err)
|
t.Logf("Detection failed: %v", err)
|
||||||
@@ -93,7 +93,7 @@ func TestJWTEnforcement(t *testing.T) {
|
|||||||
portNoJWT, err := strconv.Atoi(portStrNoJWT)
|
portNoJWT, err := strconv.Atoi(portStrNoJWT)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
dialer := &net.Dialer{Timeout: detection.Timeout}
|
dialer := &net.Dialer{}
|
||||||
serverType, err := detection.DetectSSHServerType(context.Background(), dialer, hostNoJWT, portNoJWT)
|
serverType, err := detection.DetectSSHServerType(context.Background(), dialer, hostNoJWT, portNoJWT)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, detection.ServerTypeNetBirdNoJWT, serverType)
|
assert.Equal(t, detection.ServerTypeNetBirdNoJWT, serverType)
|
||||||
@@ -218,7 +218,7 @@ func TestJWTDetection(t *testing.T) {
|
|||||||
port, err := strconv.Atoi(portStr)
|
port, err := strconv.Atoi(portStr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
dialer := &net.Dialer{Timeout: detection.Timeout}
|
dialer := &net.Dialer{}
|
||||||
serverType, err := detection.DetectSSHServerType(context.Background(), dialer, host, port)
|
serverType, err := detection.DetectSSHServerType(context.Background(), dialer, host, port)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, detection.ServerTypeNetBirdJWT, serverType)
|
assert.Equal(t, detection.ServerTypeNetBirdJWT, serverType)
|
||||||
|
|||||||
+14
-10
@@ -19,9 +19,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
clientStartTimeout = 30 * time.Second
|
clientStartTimeout = 30 * time.Second
|
||||||
clientStopTimeout = 10 * time.Second
|
clientStopTimeout = 10 * time.Second
|
||||||
defaultLogLevel = "warn"
|
defaultLogLevel = "warn"
|
||||||
|
defaultSSHDetectionTimeout = 20 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -207,11 +208,19 @@ func createDetectSSHServerMethod(client *netbird.Client) js.Func {
|
|||||||
host := args[0].String()
|
host := args[0].String()
|
||||||
port := args[1].Int()
|
port := args[1].Int()
|
||||||
|
|
||||||
|
timeoutMs := int(defaultSSHDetectionTimeout.Milliseconds())
|
||||||
|
if len(args) >= 3 && !args[2].IsNull() && !args[2].IsUndefined() {
|
||||||
|
timeoutMs = args[2].Int()
|
||||||
|
if timeoutMs <= 0 {
|
||||||
|
return js.ValueOf("error: timeout must be positive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return createPromise(func(resolve, reject js.Value) {
|
return createPromise(func(resolve, reject js.Value) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutMs)*time.Millisecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
serverType, err := detectSSHServerType(ctx, client, host, port)
|
serverType, err := sshdetection.DetectSSHServerType(ctx, client, host, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reject.Invoke(err.Error())
|
reject.Invoke(err.Error())
|
||||||
return
|
return
|
||||||
@@ -222,11 +231,6 @@ func createDetectSSHServerMethod(client *netbird.Client) js.Func {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// detectSSHServerType detects SSH server type using NetBird network connection
|
|
||||||
func detectSSHServerType(ctx context.Context, client *netbird.Client, host string, port int) (sshdetection.ServerType, error) {
|
|
||||||
return sshdetection.DetectSSHServerType(ctx, client, host, port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// createClientObject wraps the NetBird client in a JavaScript object
|
// createClientObject wraps the NetBird client in a JavaScript object
|
||||||
func createClientObject(client *netbird.Client) js.Value {
|
func createClientObject(client *netbird.Client) js.Value {
|
||||||
obj := make(map[string]interface{})
|
obj := make(map[string]interface{})
|
||||||
|
|||||||
Reference in New Issue
Block a user