El dialer de SOCKS aporta el transporte; el paquete SSH realiza el saludo SSH sobre él. Llamar después a ssh.Dial crearía una conexión aparte en lugar de usar ese transporte.

Una función auxiliar en una aplicación que ya usa x/net/proxy y x/crypto/ssh puede devolver el cliente SSH configurado:

func dialSSHViaSOCKS(proxyAddr, sshAddr string,
    config *ssh.ClientConfig) (*ssh.Client, error) {
    dialer, err := proxy.SOCKS5("tcp", proxyAddr, nil, proxy.Direct)
    if err != nil {
        return nil, err
    }

    conn, err := dialer.Dial("tcp", sshAddr)
    if err != nil {
        return nil, err
    }

    transport, channels, requests, err :=
        ssh.NewClientConn(conn, sshAddr, config)
    if err != nil {
        conn.Close()
        return nil, err
    }

    return ssh.NewClient(transport, channels, requests), nil
}

Los nombres de paquete aquí son golang.org/x/net/proxy y golang.org/x/crypto/ssh. proxyAddr identifica el escucha SOCKS; sshAddr identifica el servidor final como host:port.

Proporciona en config el usuario SSH habitual de la aplicación, los métodos de autenticación y HostKeyCallback. El paquete knownhosts puede construir ese callback a partir de un archivo known_hosts de confianza. Pasa el nombre de host de destino a NewClientConn para que la comprobación de la clave de host use la identidad SSH prevista.

El argumento nil no selecciona credenciales SOCKS. Para destinos SSH públicos permitidos, una entrada sin cuenta de la lista de proxies SOCKS5 puede aportar proxyAddr si permite el host y el puerto SSH reales. Cuando haga falta, pasa un proxy.Auth con la cuenta del proxy; la autenticación SSH sigue en config.

NewClient recibe los flujos entrantes de canales y peticiones que devuelve NewClientConn y se ocupa de esa maquinaria del cliente. Cierra el cliente SSH devuelto cuando termine su trabajo. El manejo de conexiones en producción también necesita un marcado acotado y una política de saludo; esta función auxiliar solo ilustra el traspaso del transporte.

Artículos relacionados