下面是一个更完整的 Golang SSH 服务器的示例代码:
package main
import (
"io"
"log"
"net"
"golang.org/x/crypto/ssh"
)
func main() {
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "your_username" && string(pass) == "your_password" {
return nil, nil
}
return nil, fmt.Errorf("invalid username or password")
},
}
privateBytes, err := ioutil.ReadFile("private_key")
if err != nil {
log.Fatalf("Failed to load private key (%s)", err)
}
privateKey, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatalf("Failed to parse private key (%s)", err)
}
config.AddHostKey(privateKey)
listener, err := net.Listen("tcp", "0.0.0.0:2222")
if err != nil {
log.Fatalf("Failed to listen for connections (%s)", err)
}
log.Println("Listening on 0.0.0.0:2222...")
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("Failed to accept incoming connection (%s)", err)
continue
}
go handleConnection(conn, config)
}
}
func handleConnection(conn net.Conn, config *ssh.ServerConfig) {
defer conn.Close()
sConn, chans, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
log.Printf("Failed to handshake (%s)", err)
return
}
log.Printf("New SSH connection from %s", sConn.RemoteAddr())
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Printf("Failed to accept channel (%s)", err)
return
}
go handleSession(channel, requests)
}
}
func handleSession(channel ssh.Channel, requests <-chan *ssh.Request) {
defer channel.Close()
for req := range requests {
switch req.Type {
case "exec":
// 处理执行命令的请求
command := string(req.Payload[4:])
log.Printf("Executing command: %s", command)
// 执行命令并将输出发送回客户端
output, err := exec.Command(command).CombinedOutput()
if err != nil {
log.Printf("Command execution failed (%s)", err)
}
_, _ = channel.Write(output)
// 发送退出状态码给客户端
status := 0
_, _ = channel.SendRequest("exit-status", false, ssh.Marshal(&struct{ C uint32 }{uint32(status)}))
// 关闭通道
channel.Close()
case "pty-req":
// 处理终端请求(可选)
case "window-change":
// 处理窗口大小变化请求(可选)
default:
req.Reply(false, nil) // 不支持其他请求类型
}
}
}
请注意,上述示例代码只是一个基本的实现,并不包含全部功能。你可以根据自己的需求添加更多的处理逻辑,例如处理终端请求、窗口大小变化等。
另外,请确保将 “your_username” 和 “your_password” 替换为实际的用户名和密码,并将 “private_key” 替换为你自己的私钥文件路径。
希望这能帮助到你!如果有其他问题,请随时提问。
内容由零声教学AI助手提供,问题来源于学员提问