ssh.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package ssh
  2. import (
  3. "bufio"
  4. "fmt"
  5. "os"
  6. "os/user"
  7. "path"
  8. "syscall"
  9. "time"
  10. "git.wecise.com/wecise/util/merrs"
  11. "golang.org/x/crypto/ssh"
  12. "golang.org/x/term"
  13. )
  14. var (
  15. DefaultCiphers = []string{
  16. "aes128-ctr",
  17. "aes192-ctr",
  18. "aes256-ctr",
  19. "aes128-gcm@openssh.com",
  20. "chacha20-poly1305@openssh.com",
  21. "arcfour256",
  22. "arcfour128",
  23. "arcfour",
  24. "aes128-cbc",
  25. "3des-cbc",
  26. "blowfish-cbc",
  27. "cast128-cbc",
  28. "aes192-cbc",
  29. "aes256-cbc",
  30. }
  31. )
  32. type Node struct {
  33. IPPort string
  34. User string
  35. Password string
  36. Passphrase string
  37. Keypath string
  38. Timeout time.Duration
  39. }
  40. type Client struct {
  41. *ssh.Client
  42. }
  43. func (me *Node) Connect() (*Client, error) {
  44. authMethods, err := authMethods(me.Password, me.Passphrase, me.Keypath)
  45. if err != nil {
  46. return nil, err
  47. }
  48. config := &ssh.ClientConfig{
  49. User: me.User,
  50. Auth: authMethods,
  51. HostKeyCallback: ssh.InsecureIgnoreHostKey(),
  52. Timeout: me.Timeout,
  53. }
  54. config.SetDefaults()
  55. config.Ciphers = append(config.Ciphers, DefaultCiphers...)
  56. client, err := ssh.Dial("tcp", me.IPPort, config)
  57. if err != nil {
  58. return nil, err
  59. }
  60. return &Client{
  61. Client: client,
  62. }, nil
  63. }
  64. func authMethods(password string, passphrase string, keypath string) ([]ssh.AuthMethod, error) {
  65. var authMethods []ssh.AuthMethod
  66. osuser, err := user.Current()
  67. if err != nil {
  68. return nil, merrs.NewError(err)
  69. }
  70. var pemBytes []byte
  71. if keypath == "" {
  72. pemBytes, err = os.ReadFile(path.Join(osuser.HomeDir, ".ssh/id_rsa"))
  73. } else {
  74. pemBytes, err = os.ReadFile(keypath)
  75. }
  76. if err != nil && !os.IsNotExist(err) {
  77. return nil, merrs.NewError(err)
  78. }
  79. if len(pemBytes) > 0 {
  80. var signer ssh.Signer
  81. if passphrase != "" {
  82. signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(passphrase))
  83. } else {
  84. signer, err = ssh.ParsePrivateKey(pemBytes)
  85. }
  86. if err != nil {
  87. return nil, merrs.NewError(err)
  88. }
  89. authMethods = append(authMethods, ssh.PublicKeys(signer))
  90. }
  91. if password != "" {
  92. authMethods = append(authMethods, ssh.Password(password))
  93. }
  94. authMethods = append(authMethods, ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) {
  95. answers := make([]string, 0, len(questions))
  96. for i, q := range questions {
  97. fmt.Print(q)
  98. if echos[i] {
  99. scan := bufio.NewScanner(os.Stdin)
  100. if scan.Scan() {
  101. answers = append(answers, scan.Text())
  102. }
  103. err := scan.Err()
  104. if err != nil {
  105. return nil, err
  106. }
  107. } else {
  108. b, err := term.ReadPassword(int(syscall.Stdin))
  109. if err != nil {
  110. return nil, err
  111. }
  112. fmt.Println()
  113. answers = append(answers, string(b))
  114. }
  115. }
  116. return answers, nil
  117. }))
  118. return authMethods, nil
  119. }