Change-Id: I9bfd61fe96d2bdaa890379a1a31b7e0f3f2b67ed Reviewed-on: https://go-review.googlesource.com/c/crypto/+/594435 Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Nicola Murino <nicola.murino@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: shuang cui <imcusg@gmail.com> Reviewed-by: Joedian Reid <joedian@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
// Copyright 2023 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package test
|
|
|
|
import (
|
|
"net"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
type exitStatusMsg struct {
|
|
Status uint32
|
|
}
|
|
|
|
// goTestServer is a test Go SSH server that accepts public key and certificate
|
|
// authentication and replies with a 0 exit status to any exec request without
|
|
// running any commands.
|
|
type goTestServer struct {
|
|
listener net.Listener
|
|
config *ssh.ServerConfig
|
|
done <-chan struct{}
|
|
}
|
|
|
|
func newTestServer(config *ssh.ServerConfig) (*goTestServer, error) {
|
|
server := &goTestServer{
|
|
config: config,
|
|
}
|
|
listener, err := net.Listen("tcp", "127.0.0.1:")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
server.listener = listener
|
|
done := make(chan struct{}, 1)
|
|
server.done = done
|
|
go server.acceptConnections(done)
|
|
|
|
return server, nil
|
|
}
|
|
|
|
func (s *goTestServer) port() (string, error) {
|
|
_, port, err := net.SplitHostPort(s.listener.Addr().String())
|
|
return port, err
|
|
}
|
|
|
|
func (s *goTestServer) acceptConnections(done chan<- struct{}) {
|
|
defer close(done)
|
|
|
|
for {
|
|
c, err := s.listener.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, chans, reqs, err := ssh.NewServerConn(c, s.config)
|
|
if err != nil {
|
|
return
|
|
}
|
|
go ssh.DiscardRequests(reqs)
|
|
defer c.Close()
|
|
|
|
for newChannel := range chans {
|
|
if newChannel.ChannelType() != "session" {
|
|
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
|
|
continue
|
|
}
|
|
|
|
channel, requests, err := newChannel.Accept()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
go func(in <-chan *ssh.Request) {
|
|
for req := range in {
|
|
ok := false
|
|
switch req.Type {
|
|
case "exec":
|
|
ok = true
|
|
go func() {
|
|
channel.SendRequest("exit-status", false, ssh.Marshal(&exitStatusMsg{Status: 0}))
|
|
channel.Close()
|
|
}()
|
|
}
|
|
if req.WantReply {
|
|
req.Reply(ok, nil)
|
|
}
|
|
}
|
|
}(requests)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *goTestServer) Close() error {
|
|
err := s.listener.Close()
|
|
// wait for the accept loop to exit
|
|
<-s.done
|
|
return err
|
|
}
|