package vnc import ( "context" "fmt" "net" "time" "github.com/mitchellh/go-vnc" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common/i18n" "github.com/shadow1ng/fscan/plugins/base" ) // VNCConnector VNC服务连接器 type VNCConnector struct{} // NewVNCConnector 创建新的VNC连接器 func NewVNCConnector() *VNCConnector { return &VNCConnector{} } // Connect 连接到VNC服务 func (c *VNCConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) timeout := time.Duration(common.Timeout) * time.Second // 使用带上下文的TCP连接 conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) if err != nil { return nil, fmt.Errorf(i18n.GetText("vnc_connection_failed"), err) } // 设置读写超时 if err := conn.SetDeadline(time.Now().Add(timeout)); err != nil { conn.Close() return nil, fmt.Errorf("failed to set connection deadline: %v", err) } return conn, nil } // Authenticate 认证VNC服务 func (c *VNCConnector) Authenticate(ctx context.Context, conn interface{}, cred *base.Credential) error { netConn, ok := conn.(net.Conn) if !ok { return fmt.Errorf("invalid connection type") } // 检查上下文是否已取消 select { case <-ctx.Done(): return ctx.Err() default: } // VNC只使用密码认证,忽略用户名 password := cred.Password if password == "" && cred.Username != "" { // 如果密码为空但用户名不为空,尝试使用用户名作为密码 password = cred.Username } // 创建完成通道 doneChan := make(chan error, 1) // 在协程中处理VNC认证 go func() { // 配置VNC客户端 config := &vnc.ClientConfig{ Auth: []vnc.ClientAuth{ &vnc.PasswordAuth{ Password: password, }, }, } // 尝试VNC认证 client, err := vnc.Client(netConn, config) if err != nil { select { case <-ctx.Done(): case doneChan <- err: } return } // 认证成功,立即关闭客户端 client.Close() select { case <-ctx.Done(): case doneChan <- nil: } }() // 等待认证结果或上下文取消 select { case err := <-doneChan: return err case <-ctx.Done(): return ctx.Err() } } // Close 关闭连接 func (c *VNCConnector) Close(conn interface{}) error { if closer, ok := conn.(interface{ Close() error }); ok && closer != nil { return closer.Close() } return nil }