gpt4 book ai didi

ssh - Golang SSH 服务器 : How to handle file transfer with scp?

转载 作者:IT王子 更新时间:2023-10-29 02:23:38 32 4
gpt4 key购买 nike

我在 golang 中使用 crypto/ssh 包编写了一个小型 SSH 服务器。

它支持返回交互式 shell 并立即执行命令。

这是服务器的一个最小示例:

package main

import (
"fmt"
"io/ioutil"
"log"
"net"
"os/exec"

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

func main() {
c := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "foo" && string(pass) == "bar" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}

keyBytes, _ := ioutil.ReadFile("key")
key, _ := ssh.ParsePrivateKey(keyBytes)
c.AddHostKey(key)

listener, _ := net.Listen("tcp", "0.0.0.0:2200")
for {
tcpConn, _ := listener.Accept()
_, chans, reqs, _ := ssh.NewServerConn(tcpConn, c)
go ssh.DiscardRequests(reqs)
go handleChannels(chans)
}
}

func handleChannels(chans <-chan ssh.NewChannel) {
for newChannel := range chans {
go handleChannel(newChannel)
}
}

func handleChannel(newChannel ssh.NewChannel) {
channel, requests, _ := newChannel.Accept()
for req := range requests {
switch req.Type {
case "shell":
go handleShell(channel)
case "exec":
go handleExec(channel, req)
}
}
}

func handleShell(c ssh.Channel) {}
func handleExec(c ssh.Channel, r *ssh.Request) {
cmdString, args, _ := parseCommand(r.Payload)
log.Printf("exec: %s\n", cmdString)
for i := range args {
log.Printf("arg %d: %s\n", i, args[i])
}
cmd := exec.Command(cmdString, args...)
cmd.Run()
}

func parseCommand(b []byte) (string, []string, error) {
cmdString := strings.TrimSpace(string(b))
cmdArray := strings.Split(cmdString, " ")

cmd := strings.Trim(cmdArray[0], " ")
args := cmdArray[1:]

return cmd, args, nil
}

如果我运行服务器,执行scp如下:

scp -P 2200 test.file foo@localhost:~/

handleExec 函数被调用。

cmdString 的输出显示:

2015/11/22 17:49:14 exec: scp
2015/11/22 17:49:14 arg 0: -t
2015/11/22 17:49:14 arg 1: ~/

但是我如何实现 handleExec 函数来实际保存我通过 scp 传递的文件/目录?

最佳答案

我刚刚遇到了在我的 ssh 服务器上执行 scp 和自定义命令的问题,由于没有记录如何执行此操作,我从 crypto.ssh(https://github.com/golang/crypto/blob/master/ssh/session.gohttps://github.com/golang/crypto/blob/master/ssh/session_test.go)中的测试中拼凑了一些代码它与 OpenSSH 和 crypto.ssh 客户端一起工作。例如,您可以在客户端调用 session.Run() 并处理例如scp 或自定义命令。

type exitStatusMsg struct {
Status uint32
}

// RFC 4254 Section 6.5.
type execMsg struct {
Command string
}

go func(in <-chan *ssh.Request, channel ssh.Channel) {
for req := range in {
if req.Type == "exec" {
var msg execMsg
if err := ssh.Unmarshal(req.Payload, &msg); err != nil {
log.Printf("error parsing ssh execMsg: %s\n", err)
req.Reply(false, nil)
return
}
go func(msg execMsg, ch ssh.Channel) {
// ch can be used as a ReadWriteCloser if there should be interactivity
runYourCommand(msg.Command, ch)
ex := exitStatusMsg{
Status: 0,
}
// return the status code
if _, err := ch.SendRequest("exit-status", false, ssh.Marshal(&ex)); err != nil {
log.Printf("unable to send status: %v", err)
}
ch.Close()
}(msg, channel)
req.Reply(true, nil) // tell the other end that we can run the request
} else {
req.Reply(req.Type == "shell", nil)
}
}
}(requests, channel)

您需要用任何函数替换 runYourCommand 然后执行您的命令并将退出代码设置为您的命令/进程返回的任何内容。

关于ssh - Golang SSH 服务器 : How to handle file transfer with scp?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33846959/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com