ssh_internal.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //go:build !plan9
  2. package sftp
  3. import (
  4. "context"
  5. "io"
  6. "net"
  7. "github.com/rclone/rclone/fs"
  8. "github.com/rclone/rclone/fs/fshttp"
  9. "github.com/rclone/rclone/lib/proxy"
  10. "golang.org/x/crypto/ssh"
  11. )
  12. // Internal ssh connections with "golang.org/x/crypto/ssh"
  13. type sshClientInternal struct {
  14. srv *ssh.Client
  15. }
  16. // newSSHClientInternal starts a client connection to the given SSH server. It is a
  17. // convenience function that connects to the given network address,
  18. // initiates the SSH handshake, and then sets up a Client.
  19. func (f *Fs) newSSHClientInternal(ctx context.Context, network, addr string, sshConfig *ssh.ClientConfig) (sshClient, error) {
  20. baseDialer := fshttp.NewDialer(ctx)
  21. var (
  22. conn net.Conn
  23. err error
  24. )
  25. if f.opt.SocksProxy != "" {
  26. conn, err = proxy.SOCKS5Dial(network, addr, f.opt.SocksProxy, baseDialer)
  27. } else {
  28. conn, err = baseDialer.Dial(network, addr)
  29. }
  30. if err != nil {
  31. return nil, err
  32. }
  33. c, chans, reqs, err := ssh.NewClientConn(conn, addr, sshConfig)
  34. if err != nil {
  35. return nil, err
  36. }
  37. fs.Debugf(f, "New connection %s->%s to %q", c.LocalAddr(), c.RemoteAddr(), c.ServerVersion())
  38. srv := ssh.NewClient(c, chans, reqs)
  39. return sshClientInternal{srv}, nil
  40. }
  41. // Wait for connection to close
  42. func (s sshClientInternal) Wait() error {
  43. return s.srv.Conn.Wait()
  44. }
  45. // Send a keepalive over the ssh connection
  46. func (s sshClientInternal) SendKeepAlive() {
  47. _, _, err := s.srv.SendRequest("keepalive@openssh.com", true, nil)
  48. if err != nil {
  49. fs.Debugf(nil, "Failed to send keep alive: %v", err)
  50. }
  51. }
  52. // Close the connection
  53. func (s sshClientInternal) Close() error {
  54. return s.srv.Close()
  55. }
  56. // CanReuse indicates if this client can be reused
  57. func (s sshClientInternal) CanReuse() bool {
  58. return true
  59. }
  60. // Check interfaces
  61. var _ sshClient = sshClientInternal{}
  62. // Thin wrapper for *ssh.Session to implement sshSession interface
  63. type sshSessionInternal struct {
  64. *ssh.Session
  65. }
  66. // Set the stdout
  67. func (s sshSessionInternal) SetStdout(wr io.Writer) {
  68. s.Session.Stdout = wr
  69. }
  70. // Set the stderr
  71. func (s sshSessionInternal) SetStderr(wr io.Writer) {
  72. s.Session.Stderr = wr
  73. }
  74. // NewSession makes an sshSession from an sshClient
  75. func (s sshClientInternal) NewSession() (sshSession, error) {
  76. session, err := s.srv.NewSession()
  77. if err != nil {
  78. return nil, err
  79. }
  80. return sshSessionInternal{Session: session}, nil
  81. }
  82. // Check interfaces
  83. var _ sshSession = sshSessionInternal{}