Hopefully fix build error under windows. Binding to the wildcard is poor form for our darwin users as it triggers the firewall popup. Dialing the wildcard looks like it's implementation specific as well. R=agl, kardianos CC=golang-dev https://golang.org/cl/6104046
181 lines
3.8 KiB
Go
181 lines
3.8 KiB
Go
// Copyright 2012 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 ssh
|
|
|
|
import (
|
|
"bytes"
|
|
crypto_rand "crypto/rand"
|
|
"io"
|
|
"math/rand"
|
|
"testing"
|
|
)
|
|
|
|
// windowTestBytes is the number of bytes that we'll send to the SSH server.
|
|
const windowTestBytes = 16000 * 200
|
|
|
|
// CopyNRandomly copies n bytes from src to dst. It uses a variable, and random,
|
|
// buffer size to exercise more code paths.
|
|
func CopyNRandomly(dst io.Writer, src io.Reader, n int64) (written int64, err error) {
|
|
buf := make([]byte, 32*1024)
|
|
for written < n {
|
|
l := (rand.Intn(30) + 1) * 1024
|
|
if d := n - written; d < int64(l) {
|
|
l = int(d)
|
|
}
|
|
nr, er := src.Read(buf[0:l])
|
|
if nr > 0 {
|
|
nw, ew := dst.Write(buf[0:nr])
|
|
if nw > 0 {
|
|
written += int64(nw)
|
|
}
|
|
if ew != nil {
|
|
err = ew
|
|
break
|
|
}
|
|
if nr != nw {
|
|
err = io.ErrShortWrite
|
|
break
|
|
}
|
|
}
|
|
if er != nil {
|
|
err = er
|
|
break
|
|
}
|
|
}
|
|
return written, err
|
|
}
|
|
|
|
func TestServerWindow(t *testing.T) {
|
|
addr := startSSHServer(t)
|
|
runSSHClient(t, addr)
|
|
}
|
|
|
|
// runSSHClient writes random data to the server. The server is expected to echo
|
|
// the same data back, which is compared against the original.
|
|
func runSSHClient(t *testing.T, addr string) {
|
|
conn, err := Dial("tcp", addr, &ClientConfig{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
session, err := conn.NewSession()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
origBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
|
|
echoedBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
|
|
io.CopyN(origBuf, crypto_rand.Reader, windowTestBytes)
|
|
origBytes := origBuf.Bytes()
|
|
|
|
wait := make(chan bool)
|
|
|
|
// Read back the data from the server.
|
|
go func() {
|
|
defer session.Close()
|
|
serverStdout, err := session.StdoutPipe()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
n, err := CopyNRandomly(echoedBuf, serverStdout, windowTestBytes)
|
|
if err != nil && err != io.EOF {
|
|
t.Fatal(err)
|
|
}
|
|
if n != windowTestBytes {
|
|
t.Fatalf("Read only %d bytes from server, expected %d", n, windowTestBytes)
|
|
}
|
|
wait <- true
|
|
}()
|
|
|
|
serverStdin, err := session.StdinPipe()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
written, err := CopyNRandomly(serverStdin, origBuf, windowTestBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if written != windowTestBytes {
|
|
t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes)
|
|
}
|
|
|
|
<-wait
|
|
|
|
if !bytes.Equal(origBytes, echoedBuf.Bytes()) {
|
|
t.Error("Echoed buffer differed from original")
|
|
}
|
|
}
|
|
|
|
func startSSHServer(t *testing.T) (addr string) {
|
|
config := &ServerConfig{
|
|
NoClientAuth: true,
|
|
}
|
|
|
|
err := config.SetRSAPrivateKey([]byte(testServerPrivateKey))
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse private key: %s", err.Error())
|
|
}
|
|
|
|
listener, err := Listen("tcp", "127.0.0.1:0", config)
|
|
if err != nil {
|
|
t.Fatalf("Bind error: %s", err)
|
|
}
|
|
|
|
addr = listener.Addr().String()
|
|
|
|
go func() {
|
|
for {
|
|
sConn, err := listener.Accept()
|
|
|
|
err = sConn.Handshake()
|
|
if err != nil {
|
|
if err != io.EOF {
|
|
t.Fatalf("failed to handshake: %s", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
go connRun(t, sConn)
|
|
}
|
|
}()
|
|
|
|
return
|
|
}
|
|
|
|
func connRun(t *testing.T, sConn *ServerConn) {
|
|
for {
|
|
channel, err := sConn.Accept()
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
t.Fatalf("ServerConn.Accept failed: %s", err)
|
|
}
|
|
|
|
if channel.ChannelType() != "session" {
|
|
channel.Reject(UnknownChannelType, "unknown channel type")
|
|
continue
|
|
}
|
|
err = channel.Accept()
|
|
if err != nil {
|
|
t.Fatalf("Channel.Accept failed: %s", err)
|
|
}
|
|
|
|
go func() {
|
|
defer channel.Close()
|
|
|
|
n, err := CopyNRandomly(channel, channel, windowTestBytes)
|
|
if err != nil && err != io.EOF {
|
|
if err == io.ErrShortWrite {
|
|
t.Fatalf("short write, wrote %d, expected %d", n, windowTestBytes)
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
}
|
|
}
|