The SOCKS dialer supplies the transport; the SSH package performs the SSH handshake over it. Calling ssh.Dial afterward would create a separate connection instead of using that transport.

A helper in an application already using x/net/proxy and x/crypto/ssh can return the configured SSH client:

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
}

The package names here are golang.org/x/net/proxy and golang.org/x/crypto/ssh. proxyAddr identifies the SOCKS listener; sshAddr identifies the final server as host:port.

Supply the application’s normal SSH user, authentication methods and HostKeyCallback in config. The knownhosts package can build that callback from a trusted known_hosts file. Pass the destination hostname into NewClientConn so host-key matching uses the intended SSH identity.

The nil argument selects no SOCKS credentials. For allowed public SSH destinations, a no-account entry from the SOCKS5 proxy list can supply proxyAddr if it permits the actual SSH host and port. When required, pass a proxy.Auth containing the proxy account; SSH authentication remains in config.

NewClient receives the incoming channel and request streams returned by NewClientConn and handles that client machinery. Close the returned SSH client when its workload ends. Production connection handling also needs a bounded dialing and handshake policy; this helper only illustrates the transport handoff.

متعلقہ مضامین