繁体   English   中英

Golang SSH服务器:如何使用scp处理文件传输?

[英]Golang SSH-Server: How to handle file transfer with scp?

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

它支持返回交互式外壳程序并立即执行命令。

这是服务器的最小示例:

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,然后执行命令并将退出代码设置为命令/进程返回的任何内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM