package sshclient import ( "fmt" "os" "time" "golang.org/x/crypto/ssh" ) // Client SSH 客户端封装 type Client struct { User string Password string KeyFile string Port int Timeout time.Duration } // NewClient 创建 SSH 客户端 func NewClient(user, password, keyFile string, port int, timeout time.Duration) *Client { return &Client{ User: user, Password: password, KeyFile: keyFile, Port: port, Timeout: timeout, } } // Connect 尝试 SSH 连接,返回 SSH client func (c *Client) Connect(ip string) (*ssh.Client, error) { config, err := c.buildConfig() if err != nil { return nil, fmt.Errorf("SSH 配置构建失败: %w", err) } addr := fmt.Sprintf("%s:%d", ip, c.Port) client, err := ssh.Dial("tcp", addr, config) if err != nil { return nil, fmt.Errorf("SSH 连接 %s 失败: %w", addr, err) } return client, nil } // RunCommand 在远程主机执行命令,返回输出 func (c *Client) RunCommand(client *ssh.Client, command string) (string, error) { session, err := client.NewSession() if err != nil { return "", fmt.Errorf("创建会话失败: %w", err) } defer session.Close() out, err := session.CombinedOutput(command) if err != nil { return string(out), fmt.Errorf("命令执行失败: %w, 输出: %s", err, string(out)) } return string(out), nil } // buildConfig 构建 SSH 认证配置 func (c *Client) buildConfig() (*ssh.ClientConfig, error) { var authMethods []ssh.AuthMethod // 密码认证 if c.Password != "" { authMethods = append(authMethods, ssh.Password(c.Password)) } // 密钥认证 if c.KeyFile != "" { key, err := os.ReadFile(c.KeyFile) if err != nil { return nil, fmt.Errorf("读取密钥文件失败: %w", err) } signer, err := ssh.ParsePrivateKey(key) if err != nil { return nil, fmt.Errorf("解析私钥失败: %w", err) } authMethods = append(authMethods, ssh.PublicKeys(signer)) } if len(authMethods) == 0 { return nil, fmt.Errorf("未提供认证方式(密码或密钥)") } return &ssh.ClientConfig{ User: c.User, Auth: authMethods, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: c.Timeout, }, nil }