Guide to Implement an SSH Client Using Golang

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

SSH หรือ Secure Shell เป็นโปรโตคอลเครือข่ายที่ใช้สำหรับการล็อกอินเข้าสู่คอมพิวเตอร์เครื่องอื่นบนเครือข่ายจากระยะไกลอย่างปลอดภัย ผมเชื่อว่านักพัฒนาแบ็กเอนด์ส่วนใหญ่คุ้นเคยกับ SSH เครื่องมือเชลล์ทั่วไปที่ใช้สำหรับการล็อกอินเข้าสู่เซิร์ฟเวอร์ เช่น Xshell, SecureCRT และ iTerm2 ล้วนใช้โปรโตคอล SSH เป็นพื้นฐาน ใน Golang แพ็กเกจ crypto/ssh มีฟังก์ชันสำหรับการใช้งาน SSH client ในบทความนี้ เราจะอธิบายรายละเอียดวิธีการใช้งาน SSH client โดยใช้ Golang

การสร้างการกำหนดค่า SSH Client

อันดับแรก เราต้องกำหนดค่าพารามิเตอร์สำหรับ SSH client เพื่อเชื่อมต่อกับเซิร์ฟเวอร์ การกำหนดค่าพื้นฐานประกอบด้วย username, authentication method และ host key callback นี่คือตัวอย่างโค้ด:

package main

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

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

ในการกำหนดค่านี้ ชื่อผู้ใช้ถูกตั้งค่าเป็น "username" และรหัสผ่านถูกตั้งค่าเป็น "password" ฟังก์ชัน ssh.Password ใช้เพื่อสร้างวิธีการตรวจสอบสิทธิ์ด้วยรหัสผ่าน ฟังก์ชัน HostKeyCallback จะถูกเรียกใช้ทุกครั้งที่มีการเชื่อมต่อกับโฮสต์ใหม่ และใช้เพื่อตรวจสอบ host key ของเซิร์ฟเวอร์ ในตัวอย่างนี้ ssh.InsecureIgnoreHostKey ถูกใช้ ซึ่งหมายความว่า host key ใดๆ ก็ได้รับการยอมรับ ไม่แนะนำให้ใช้สิ่งนี้ในสภาพแวดล้อมการผลิตเนื่องจากการไม่ตรวจสอบ host key ทำให้เกิดความเสี่ยงด้านความปลอดภัย

การเชื่อมต่อกับ SSH Server

ฟังก์ชัน ssh.Dial ใช้เพื่อเชื่อมต่อกับ SSH server จากระยะไกล ต้องใช้พารามิเตอร์สามตัว: ประเภทเครือข่าย (โดยปกติคือ "tcp"), ที่อยู่และพอร์ตของเซิร์ฟเวอร์ และอ็อบเจ็กต์การกำหนดค่าที่สร้างไว้ก่อนหน้านี้ นี่คือตัวอย่างโค้ด:

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)
	}
}

เชื่อมต่อกับเซิร์ฟเวอร์ด้วยที่อยู่ IP 192.168.3.111 บนพอร์ต 22 (พอร์ตเริ่มต้นสำหรับโปรโตคอล SSH) หากการเชื่อมต่อล้มเหลว ข้อผิดพลาดจะถูกส่งกลับ และคุณสามารถใช้ log.Fatal เพื่อพิมพ์ข้อผิดพลาดและออกจากโปรแกรม

การสร้าง SSH Session

เมื่อการเชื่อมต่อ SSH ถูกสร้างขึ้นแล้ว คุณสามารถสร้าง SSH session เพื่อสื่อสารกับเซิร์ฟเวอร์ได้ นี่คือตัวอย่างโค้ด:

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()
}

ใช้ฟังก์ชัน client.NewSession เพื่อสร้าง session ใหม่ และหากล้มเหลว ข้อผิดพลาดจะถูกส่งกลับ ใช้คีย์เวิร์ด defer เพื่อให้แน่ใจว่า session จะถูกปิดหลังจากดำเนินการเสร็จสิ้น

การสร้าง Pseudo Terminal

โปรโตคอล SSH อนุญาตให้สร้าง pseudo terminal ซึ่งจำลองพฤติกรรมของ terminal จริงและอนุญาตให้ใช้คำสั่งแบบโต้ตอบ เช่น เชลล์หรือโปรแกรมแก้ไขข้อความ นี่คือตัวอย่างโค้ด:

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)
	}
}

ใช้ฟังก์ชัน session.RequestPty เพื่อขอ pseudo terminal ต้องใช้พารามิเตอร์สี่ตัว: ประเภท terminal (ในกรณีนี้คือ "xterm"), ความกว้างและความสูงของ terminal และแผนที่เพื่อตั้งค่าโหมด terminal ในแผนที่นี้ ssh.ECHO ถูกตั้งค่าเป็น 0 ซึ่งปิดใช้งานการสะท้อน และความเร็วในการป้อนข้อมูลและเอาต์พุตถูกตั้งค่าเป็น 14.4 kbaud

การตั้งค่า Input และ Output

ระบุอินพุตและเอาต์พุตมาตรฐานสำหรับเชลล์ระยะไกล นี่คือตัวอย่างโค้ด:

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
}

การเริ่ม Remote Shell

ตอนนี้ remote shell พร้อมแล้ว และคุณสามารถใช้ฟังก์ชัน session.Shell เพื่อเริ่มเชลล์เริ่มต้น หรือใช้ฟังก์ชัน session.Run เพื่อเรียกใช้คำสั่งเฉพาะ นี่คือตัวอย่างโค้ด:

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)
	}
}

เริ่มเชลล์เริ่มต้น และหากเริ่มไม่สำเร็จ ข้อผิดพลาดจะถูกส่งกลับ

การรอให้ Session สิ้นสุด

ใช้ฟังก์ชัน session.Wait เพื่อบล็อกจนกว่า session จะสิ้นสุด นี่คือตัวอย่างโค้ด:

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())
	}
}

ด้วยสิ่งนี้ คุณได้ดำเนินการสร้าง SSH client พื้นฐานเสร็จสมบูรณ์แล้ว client นี้สามารถเชื่อมต่อกับ SSH server เริ่ม remote shell และรอให้ session สิ้นสุด

สรุป

SSH client ที่ใช้งานในบทความนี้มีฟังก์ชันพื้นฐานที่สุดเท่านั้น ในการสร้าง SSH client ที่มีคุณสมบัติครบถ้วนและใช้งานง่าย คุณต้องใส่ใจในรายละเอียดมากมาย เช่น การจัดการข้อผิดพลาด การเชื่อมต่อใหม่ การหมดเวลา การจัดการสัญญาณ และอื่นๆ อีกมากมาย

SSH  GUIDE  GOLANG  SSH CLIENT 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Am I going to the past?