github.com/devops-filetransfer/sshego@v7.0.4+incompatible/listen_test.go (about)

     1  package sshego
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"testing"
     8  	"time"
     9  
    10  	cv "github.com/glycerine/goconvey/convey"
    11  )
    12  
    13  func Test501BasicServerListenStartupAcceptAndShutdown(t *testing.T) {
    14  
    15  	cv.Convey("BasicServer should start and stop when requested-- in response to Listen() and Close() -- in place of Start() and Stop()", t, func() {
    16  		cfg, r1 := GenTestConfig()
    17  		r1() // release the held-open ports.
    18  		defer TempDirCleanup(cfg.Origdir, cfg.Tempdir)
    19  		s := NewBasicServer(cfg)
    20  		bs, err := s.Listen(cfg.EmbeddedSSHd.Addr)
    21  		panicOn(err)
    22  		var aerr error
    23  		acceptDone := make(chan bool)
    24  		ctx := context.Background()
    25  		go func() {
    26  			pp("bs.Accept starting")
    27  			_, aerr = bs.Accept(ctx)
    28  			_ = aerr
    29  			close(acceptDone)
    30  			pp("bs.Accept done and close(acceptDone) happened.")
    31  		}()
    32  
    33  		err = bs.Close()
    34  		pp("bs.Close() done")
    35  		// don't panic on err
    36  		<-acceptDone
    37  		pp("past <-acceptDone")
    38  
    39  		//pp("about to <-cfg.Esshd.Done")
    40  		//<-cfg.Esshd.Halt.DoneChan()
    41  		//pp("past <-cfg.Esshd.Done")
    42  		cv.So(true, cv.ShouldEqual, true) // we should get here.
    43  		fmt.Printf("\n done with 501\n")
    44  	})
    45  }
    46  
    47  func Test502BasicServerListenStartupAndShutdown(t *testing.T) {
    48  
    49  	cv.Convey("BasicServer should start and stop when requested-- in response to Listen() and Close() -- even if not Accept()-ing yet.", t, func() {
    50  		cfg, r1 := GenTestConfig()
    51  		r1() // release the held-open ports.
    52  		defer TempDirCleanup(cfg.Origdir, cfg.Tempdir)
    53  		s := NewBasicServer(cfg)
    54  		bs, err := s.Listen(cfg.EmbeddedSSHd.Addr)
    55  		panicOn(err)
    56  
    57  		err = bs.Close()
    58  		panicOn(err)
    59  
    60  		cv.So(true, cv.ShouldEqual, true) // we should get here.
    61  	})
    62  }
    63  
    64  // help method for tests in this file
    65  func startBackgroundTestSshServer2(ctx context.Context, serverDone chan bool, payloadByteCount int, confirmationPayload string, confirmationReply string, tcpSrvLsn *BasicListener) {
    66  	go func() {
    67  		for {
    68  			pp("startBackgroundTestTcpServer() about to call Accept().")
    69  			tcpServerConn, err := tcpSrvLsn.Accept(ctx)
    70  			if err != nil {
    71  				pp("startBackgroundTestSshServer2 ignoring"+
    72  					" error from Accept: '%v'", err)
    73  				continue
    74  			}
    75  			pp("startBackgroundTestTcpServer() progress: got Accept() back: %v",
    76  				tcpServerConn)
    77  
    78  			b := make([]byte, payloadByteCount)
    79  			n, err := tcpServerConn.Read(b)
    80  			panicOn(err)
    81  			if n != payloadByteCount {
    82  				panic(fmt.Errorf("read too short! got %v but expected %v", n, payloadByteCount))
    83  			}
    84  			saw := string(b)
    85  
    86  			if saw != confirmationPayload {
    87  				panic(fmt.Errorf("expected '%s', but saw '%s'", confirmationPayload, saw))
    88  			}
    89  
    90  			pp("success! in startBackgroundTestSshServer2(): "+
    91  				"server got expected confirmation payload of '%s'", saw)
    92  
    93  			// reply back
    94  			n, err = tcpServerConn.Write([]byte(confirmationReply))
    95  			panicOn(err)
    96  			if n != payloadByteCount {
    97  				panic(fmt.Errorf("write too short! got %v but expected %v", n, payloadByteCount))
    98  			}
    99  			//tcpServerConn.Close()
   100  			close(serverDone)
   101  			pp("startBackgroundTestSshServer2 goroutine returning")
   102  			return
   103  		}
   104  	}()
   105  }
   106  
   107  // help method for tests in this file
   108  func verifyExchange2(channelToTcpServer net.Conn, confirmationPayload, confirmationReply string, payloadByteCount int) {
   109  	m, err := channelToTcpServer.Write([]byte(confirmationPayload))
   110  	panicOn(err)
   111  	if m != len(confirmationPayload) {
   112  		panic("too short a write!")
   113  	}
   114  
   115  	// check reply
   116  	rep := make([]byte, payloadByteCount)
   117  	m, err = channelToTcpServer.Read(rep)
   118  	panicOn(err)
   119  	if m != payloadByteCount {
   120  		msg := fmt.Sprintf("too short a reply! m = %v, expected %v. rep = '%v'", m, payloadByteCount, string(rep))
   121  		pp(msg)
   122  		panic(msg)
   123  	}
   124  
   125  	srep := string(rep)
   126  	if srep != confirmationReply {
   127  		panic(fmt.Errorf("saw '%s' but expected '%s'", srep, confirmationReply))
   128  	}
   129  	pp("reply success! we got the expected srep reply '%s'", srep)
   130  }
   131  
   132  func Test504BasicServerListenAndAcceptConnection(t *testing.T) {
   133  
   134  	cv.Convey("Simple version of: Given an sshd BasicServer started with Listen() and Accept(), the verifyClientServerExchangeAcrossSshd() check with nonce requests and reply should verify the net.Conn usage. This is like cli_test.go Test201 but with the server using Listen() and Accept().", t, func() {
   135  
   136  		// 1. start a simple TCP server that is the target of the forward through the sshd,
   137  		// so we can confirm the client has made the connection.
   138  		// 2. generate a random payload for the client to send to the server.
   139  		payloadByteCount := 50
   140  		confirmationPayload := RandomString(payloadByteCount)
   141  		confirmationReply := RandomString(payloadByteCount)
   142  
   143  		serverDone := make(chan bool)
   144  
   145  		cfg, r1 := GenTestConfig()
   146  		cfg.SkipTOTP = true
   147  		cfg.SkipPassphrase = true
   148  		r1() // release the held-open ports.
   149  		defer TempDirCleanup(cfg.Origdir, cfg.Tempdir)
   150  
   151  		bs := NewBasicServer(cfg)
   152  		mylogin, _, rsaPath, _, err := TestCreateNewAccount(cfg)
   153  		panicOn(err)
   154  		ctx := context.Background()
   155  
   156  		blsn, err := bs.Listen(cfg.EmbeddedSSHd.Addr)
   157  		panicOn(err)
   158  		// let server come up.
   159  		time.Sleep(50 * time.Millisecond)
   160  
   161  		startBackgroundTestSshServer2(
   162  			ctx,
   163  			serverDone,
   164  			payloadByteCount,
   165  			confirmationPayload,
   166  			confirmationReply,
   167  			blsn)
   168  
   169  		// ===============
   170  		// begin dialing, client contacts server!
   171  		// ===============
   172  		dc := DialConfig{
   173  			// shortcut: re-use server's know hosts dir
   174  			ClientKnownHostsPath: cfg.ClientKnownHostsPath,
   175  			Mylogin:              mylogin,
   176  			RsaPath:              rsaPath,
   177  			Sshdhost:             cfg.EmbeddedSSHd.Host,
   178  			Sshdport:             cfg.EmbeddedSSHd.Port,
   179  			DownstreamHostPort:   "127.0.0.1:1",
   180  			TofuAddIfNotKnown:    true,
   181  		}
   182  
   183  		// first time we add the server key
   184  		channelToTcpServer, _, _, err := dc.Dial(ctx, nil, false)
   185  		pp("here!!")
   186  		cv.So(err.Error(), cv.ShouldContainSubstring, "Re-run without -new")
   187  
   188  		// second time we connect based on that server key
   189  		dc.TofuAddIfNotKnown = false
   190  		channelToTcpServer, _, _, err = dc.Dial(ctx, nil, false)
   191  		cv.So(err, cv.ShouldBeNil)
   192  
   193  		verifyExchange2(
   194  			channelToTcpServer,
   195  			confirmationPayload,
   196  			confirmationReply,
   197  			payloadByteCount)
   198  
   199  		// close out the client side.
   200  		channelToTcpServer.Close()
   201  
   202  		// tcp-server should have exited because it got the expected
   203  		// message and replied with the agreed upon reply and then exited.
   204  		pp("just before <-serverDone")
   205  		<-serverDone
   206  		pp("just after <-serverDone")
   207  
   208  		cv.So(true, cv.ShouldEqual, true) // we should get here.
   209  
   210  		fmt.Printf("\n done with 504\n")
   211  	})
   212  }
   213  
   214  func Test505BasicServerInterruptsAcceptOnClose(t *testing.T) {
   215  
   216  	cv.Convey("BasicServer.Close() should interrupt a waiting Accept() call.",
   217  		t, func() {
   218  			cfg, r1 := GenTestConfig()
   219  			r1() // release the held-open ports.
   220  			defer TempDirCleanup(cfg.Origdir, cfg.Tempdir)
   221  			s := NewBasicServer(cfg)
   222  			bs, err := s.Listen(cfg.EmbeddedSSHd.Addr)
   223  			panicOn(err)
   224  			ctx := context.Background()
   225  
   226  			var aerr error
   227  			acceptDone := make(chan bool)
   228  			go func() {
   229  				pp("bs.Accept starting")
   230  				_, aerr = bs.Accept(ctx)
   231  				close(acceptDone)
   232  				pp("bs.Accept done and close(acceptDone) happened.")
   233  			}()
   234  
   235  			select {
   236  			case <-time.After(time.Second):
   237  				pp("good, no acceptDone seen when Close() not yet called.")
   238  			case <-acceptDone:
   239  				panic("problem: we saw acceptDone before the Close()")
   240  			}
   241  
   242  			err = bs.Close()
   243  			pp("bs.Close() done")
   244  			// don't panic on err
   245  			<-acceptDone
   246  			pp("past <-acceptDone")
   247  			cv.So(aerr.Error(), cv.ShouldEqual, "shutting down")
   248  		})
   249  }