forward_unix_test.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build darwin freebsd linux netbsd openbsd
  5. package test
  6. import (
  7. "bytes"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "math/rand"
  12. "net"
  13. "testing"
  14. "time"
  15. "code.google.com/p/go.crypto/ssh"
  16. )
  17. func listenSSHAuto(conn *ssh.ClientConn) (net.Listener, error) {
  18. var sshListener net.Listener
  19. var err error
  20. tries := 10
  21. for i := 0; i < tries; i++ {
  22. port := 1024 + rand.Intn(50000)
  23. // We can't reliably test dynamic port allocation, as it does
  24. // not work correctly with OpenSSH before 6.0. See also
  25. // https://bugzilla.mindrot.org/show_bug.cgi?id=2017
  26. sshListener, err = conn.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
  27. if err == nil {
  28. break
  29. }
  30. }
  31. if err != nil {
  32. return nil, fmt.Errorf("conn.Listen failed: %v (after %d tries)", err, tries)
  33. }
  34. return sshListener, nil
  35. }
  36. func TestPortForward(t *testing.T) {
  37. server := newServer(t)
  38. defer server.Shutdown()
  39. conn := server.Dial(clientConfig())
  40. defer conn.Close()
  41. sshListener, err := listenSSHAuto(conn)
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. go func() {
  46. sshConn, err := sshListener.Accept()
  47. if err != nil {
  48. t.Fatalf("listen.Accept failed: %v", err)
  49. }
  50. _, err = io.Copy(sshConn, sshConn)
  51. if err != nil && err != io.EOF {
  52. t.Fatalf("ssh client copy: %v", err)
  53. }
  54. sshConn.Close()
  55. }()
  56. forwardedAddr := sshListener.Addr().String()
  57. tcpConn, err := net.Dial("tcp", forwardedAddr)
  58. if err != nil {
  59. t.Fatalf("TCP dial failed: %v", err)
  60. }
  61. readChan := make(chan []byte)
  62. go func() {
  63. data, _ := ioutil.ReadAll(tcpConn)
  64. readChan <- data
  65. }()
  66. // Invent some data.
  67. data := make([]byte, 100*1000)
  68. for i := range data {
  69. data[i] = byte(i % 255)
  70. }
  71. var sent []byte
  72. for len(sent) < 1000*1000 {
  73. // Send random sized chunks
  74. m := rand.Intn(len(data))
  75. n, err := tcpConn.Write(data[:m])
  76. if err != nil {
  77. break
  78. }
  79. sent = append(sent, data[:n]...)
  80. }
  81. if err := tcpConn.(*net.TCPConn).CloseWrite(); err != nil {
  82. t.Errorf("tcpConn.CloseWrite: %v", err)
  83. }
  84. read := <-readChan
  85. if len(sent) != len(read) {
  86. t.Fatalf("got %d bytes, want %d", len(read), len(sent))
  87. }
  88. if bytes.Compare(sent, read) != 0 {
  89. t.Fatalf("read back data does not match")
  90. }
  91. if err := sshListener.Close(); err != nil {
  92. t.Fatalf("sshListener.Close: %v", err)
  93. }
  94. // Check that the forward disappeared.
  95. tcpConn, err = net.Dial("tcp", forwardedAddr)
  96. if err == nil {
  97. tcpConn.Close()
  98. t.Errorf("still listening to %s after closing", forwardedAddr)
  99. }
  100. }
  101. func TestAcceptClose(t *testing.T) {
  102. server := newServer(t)
  103. defer server.Shutdown()
  104. conn := server.Dial(clientConfig())
  105. sshListener, err := listenSSHAuto(conn)
  106. if err != nil {
  107. t.Fatal(err)
  108. }
  109. quit := make(chan error, 1)
  110. go func() {
  111. for {
  112. c, err := sshListener.Accept()
  113. if err != nil {
  114. quit <- err
  115. break
  116. }
  117. c.Close()
  118. }
  119. }()
  120. sshListener.Close()
  121. select {
  122. case <-time.After(1 * time.Second):
  123. t.Errorf("timeout: listener did not close.")
  124. case err := <-quit:
  125. t.Logf("quit as expected (error %v)", err)
  126. }
  127. }
  128. // TODO(hanwen): test that closing the connection also
  129. // exits the listeners.