security: use net.JoinHostPort for SSH addresses to support IPv6
fmt.Sprintf("%s:%d") produces invalid addresses for IPv6. Also adds
mockable sshDial variable for testability.
This commit is contained in:
parent
8b65dffc37
commit
a0516c2bd1
2 changed files with 39 additions and 2 deletions
7
ssh.go
7
ssh.go
|
|
@ -4,6 +4,8 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/towerops-app/towerops-agent/pb"
|
||||
|
|
@ -11,6 +13,7 @@ import (
|
|||
)
|
||||
|
||||
var sshBackup = executeMikrotikBackup
|
||||
var sshDial = ssh.Dial
|
||||
var doPing = pingDevice
|
||||
|
||||
// executeMikrotikBackup connects via SSH and runs /export compact.
|
||||
|
|
@ -26,8 +29,8 @@ func executeMikrotikBackup(ip string, port uint16, username, password string) (s
|
|||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", ip, port)
|
||||
conn, err := ssh.Dial("tcp", addr, config)
|
||||
addr := net.JoinHostPort(ip, strconv.Itoa(int(port)))
|
||||
conn, err := sshDial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ssh dial %s: %w", addr, err)
|
||||
}
|
||||
|
|
|
|||
34
ssh_test.go
34
ssh_test.go
|
|
@ -270,6 +270,40 @@ func TestExecuteMikrotikBackupViaSSH(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestSSHBackupIPv6Address(t *testing.T) {
|
||||
origDial := sshDial
|
||||
defer func() { sshDial = origDial }()
|
||||
|
||||
var capturedAddr string
|
||||
sshDial = func(network, addr string, config *ssh.ClientConfig) (*ssh.Client, error) {
|
||||
capturedAddr = addr
|
||||
return nil, fmt.Errorf("mock dial")
|
||||
}
|
||||
|
||||
_, _ = executeMikrotikBackup("::1", 22, "admin", "pass")
|
||||
|
||||
if capturedAddr != "[::1]:22" {
|
||||
t.Errorf("expected [::1]:22, got %q", capturedAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSHBackupIPv4Address(t *testing.T) {
|
||||
origDial := sshDial
|
||||
defer func() { sshDial = origDial }()
|
||||
|
||||
var capturedAddr string
|
||||
sshDial = func(network, addr string, config *ssh.ClientConfig) (*ssh.Client, error) {
|
||||
capturedAddr = addr
|
||||
return nil, fmt.Errorf("mock dial")
|
||||
}
|
||||
|
||||
_, _ = executeMikrotikBackup("10.0.0.1", 22, "admin", "pass")
|
||||
|
||||
if capturedAddr != "10.0.0.1:22" {
|
||||
t.Errorf("expected 10.0.0.1:22, got %q", capturedAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteMikrotikBackupDialError(t *testing.T) {
|
||||
_, err := executeMikrotikBackup("127.0.0.1", 1, "admin", "pass")
|
||||
if err == nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue