Guide to Implement an SSH Client Using Golang

  sonic0002        2023-11-11 09:19:29       7,985        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

SSH, viết tắt của Secure Shell, là một giao thức mạng được sử dụng để đăng nhập từ xa một cách an toàn vào các máy tính khác trên mạng. Tôi tin rằng hầu hết các nhà phát triển backend đều quen thuộc với SSH. Các công cụ shell phổ biến được sử dụng để đăng nhập vào máy chủ, chẳng hạn như Xshell, SecureCRT và iTerm2, đều dựa trên giao thức SSH. Trong Golang, gói crypto/ssh cung cấp chức năng để triển khai một SSH client. Trong bài viết này, chúng ta sẽ giải thích chi tiết cách triển khai một SSH client bằng Golang.

Tạo Cấu Hình SSH Client

Đầu tiên, chúng ta cần cấu hình các tham số để SSH client kết nối với máy chủ. Cấu hình cơ bản bao gồm username, authentication methodhost key callback. Dưới đây là một đoạn mã ví dụ:

package main

import "golang.org/x/crypto/ssh"

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}
}

Trong cấu hình này, username được đặt thành "username" và password được đặt thành "password". Hàm ssh.Password được sử dụng để tạo một phương thức xác thực bằng password. Hàm HostKeyCallback được gọi mỗi khi một host mới được kết nối và nó được sử dụng để xác minh host key của máy chủ. Trong ví dụ này, ssh.InsecureIgnoreHostKey được sử dụng, có nghĩa là bất kỳ host key nào cũng được chấp nhận. Không nên sử dụng điều này trong môi trường production vì việc không xác minh host key gây ra rủi ro bảo mật.

Kết Nối Đến SSH Server

Hàm ssh.Dial được sử dụng để kết nối đến SSH server từ xa. Nó yêu cầu ba tham số: loại mạng (thường là "tcp"), địa chỉ và cổng của máy chủ và đối tượng cấu hình đã tạo trước đó. Dưới đây là một đoạn mã ví dụ:

package main

import (
	"golang.org/x/crypto/ssh"
	"log"
)

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
	if err != nil {
		log.Fatal("Failed to dial: ", err)
	}
}

Kết nối đến máy chủ với địa chỉ IP 192.168.3.111 trên cổng 22 (cổng mặc định cho giao thức SSH). Nếu kết nối không thành công, một lỗi sẽ được trả về và bạn có thể sử dụng log.Fatal để in lỗi và thoát chương trình.

Tạo Một SSH Session

Sau khi kết nối SSH được thiết lập, bạn có thể tạo một SSH session để giao tiếp với máy chủ. Dưới đây là một đoạn mã ví dụ:

package main

import (
	"golang.org/x/crypto/ssh"
	"log"
)

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
	if err != nil {
		log.Fatal("Failed to dial: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()
}

Sử dụng hàm client.NewSession để tạo một session mới và nếu nó không thành công, một lỗi sẽ được trả về. Sử dụng từ khóa defer để đảm bảo rằng session được đóng sau khi các thao tác hoàn tất.

Tạo Một Pseudo Terminal

Giao thức SSH cho phép tạo một pseudo terminal, mô phỏng hành vi của một terminal thực và cho phép các lệnh tương tác, chẳng hạn như shell hoặc trình soạn thảo văn bản. Dưới đây là một đoạn mã ví dụ:

package main

import (
	"golang.org/x/crypto/ssh"
	"log"
)

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
	if err != nil {
		log.Fatal("Failed to dial: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	if err := session.RequestPty("linux", 80, 40, modes); err != nil {
		log.Fatal("request for pseudo terminal failed: ", err)
	}
}

Sử dụng hàm session.RequestPty để yêu cầu một pseudo terminal. Nó yêu cầu bốn tham số: loại terminal (trong trường hợp này là "xterm"), chiều rộng và chiều cao của terminal và một map để đặt các chế độ terminal. Trong map này, ssh.ECHO được đặt thành 0, điều này vô hiệu hóa việc lặp lại và tốc độ đầu vào và đầu ra được đặt thành 14,4 kbaud.

Thiết Lập Đầu Vào và Đầu Ra

Chỉ định đầu vào và đầu ra tiêu chuẩn cho shell từ xa. Dưới đây là một đoạn mã ví dụ:

package main

import (
	"golang.org/x/crypto/ssh"
	"log"
	"os"
)

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
	if err != nil {
		log.Fatal("Failed to dial: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	if err := session.RequestPty("linux", 80, 40, modes); err != nil {
		log.Fatal("request for pseudo terminal failed: ", err)
	}

	//set input and output
	session.Stdout = os.Stdout
	session.Stdin = os.Stdin
	session.Stderr = os.Stderr
}

Khởi Động Remote Shell

Một remote shell hiện đã sẵn sàng và bạn có thể sử dụng hàm session.Shell để khởi động một shell mặc định hoặc sử dụng hàm session.Run để thực thi một lệnh cụ thể. Dưới đây là một đoạn mã ví dụ:

package main

import (
	"golang.org/x/crypto/ssh"
	"log"
)

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
	if err != nil {
		log.Fatal("Failed to dial: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	if err := session.RequestPty("linux", 80, 40, modes); err != nil {
		log.Fatal("request for pseudo terminal failed: ", err)
	}
  
    // set input and output
	session.Stdout = os.Stdout
	session.Stdin = os.Stdin
	session.Stderr = os.Stderr

	if err := session.Shell(); err != nil {
		log.Fatal("failed to start shell: ", err)
	}
}

Khởi động một shell mặc định và nếu nó không khởi động được, một lỗi sẽ được trả về.

Chờ Session Kết Thúc

Sử dụng hàm session.Wait để chặn cho đến khi session kết thúc. Dưới đây là một đoạn mã ví dụ:

package main

import (
	"golang.org/x/crypto/ssh"
	"log"
	"os"
)

func main() {
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.Password("password"),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	client, err := ssh.Dial("tcp", "192.168.3.111:22", config)
	if err != nil {
		log.Fatal("Failed to dial: ", err)
	}

	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: ", err)
	}
	defer session.Close()

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	if err := session.RequestPty("linux", 80, 40, modes); err != nil {
		log.Fatal("request for pseudo terminal failed: ", err)
	}

	//set input and output
	session.Stdout = os.Stdout
	session.Stdin = os.Stdin
	session.Stderr = os.Stderr

	if err := session.Shell(); err != nil {
		log.Fatal("failed to start shell: ", err)
	}

	err = session.Wait()
	if err != nil {
		log.Fatal("Failed to run: " + err.Error())
	}
}

Với điều này, bạn đã hoàn thành việc triển khai một SSH client cơ bản. Client này có thể kết nối đến một SSH server, khởi động một remote shell và chờ session kết thúc.

Tóm tắt

SSH client được triển khai trong bài viết này chỉ cung cấp các chức năng cơ bản nhất. Để tạo một SSH client giàu tính năng và thân thiện với người dùng, bạn cần chú ý đến nhiều chi tiết, chẳng hạn như xử lý lỗi, kết nối lại, timeouts, xử lý tín hiệu và hơn thế nữa.

SSH  GUIDE  GOLANG  SSH CLIENT 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

The Magic of X's Show 35 Posts

Has anyone noticed that on Twitter’s “For You” tab, every time there are new posts, it always shows “Show 35 Posts”? Where does this number 35 come from?