packetman_linux_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // +build PACKET_MANIPULATOR_TEST
  2. /*
  3. * Copyright (c) 2020, Psiphon Inc.
  4. * All rights reserved.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package packetman
  21. import (
  22. "fmt"
  23. "io"
  24. "io/ioutil"
  25. "net"
  26. "net/http"
  27. "strconv"
  28. "testing"
  29. "time"
  30. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/stacktrace"
  32. )
  33. func TestPacketManipulatorIPv4(t *testing.T) {
  34. testPacketManipulator(false, t)
  35. }
  36. func TestPacketManipulatorIPv6(t *testing.T) {
  37. testPacketManipulator(true, t)
  38. }
  39. func testPacketManipulator(useIPv6 bool, t *testing.T) {
  40. // Test: run a Manipulator in front of a web server; make an HTTP request;
  41. // the expected transformation spec should be executed (as reported by
  42. // GetAppliedSpecName) and the request must succeed.
  43. ipv4, ipv6, err := common.GetRoutableInterfaceIPAddresses()
  44. if err != nil {
  45. t.Fatalf("GetRoutableInterfaceIPAddressesfailed: %v", err)
  46. }
  47. network := "tcp4"
  48. address := net.JoinHostPort(ipv4.String(), "0")
  49. if useIPv6 {
  50. network = "tcp6"
  51. address = net.JoinHostPort(ipv6.String(), "0")
  52. }
  53. listener, err := net.Listen(network, address)
  54. if err != nil {
  55. t.Fatalf("net.Listen failed: %v", err)
  56. }
  57. defer listener.Close()
  58. hostStr, portStr, err := net.SplitHostPort(listener.Addr().String())
  59. if err != nil {
  60. t.Fatalf("net.SplitHostPort failed: %s", err.Error())
  61. }
  62. listenerPort, _ := strconv.Atoi(portStr)
  63. // [["TCP-flags S"]] replaces the original SYN-ACK packet with a single
  64. // SYN packet, implementing TCP simultaneous open.
  65. testSpecName := "test-spec"
  66. config := &Config{
  67. Logger: newTestLogger(),
  68. ProtocolPorts: []int{listenerPort},
  69. Specs: []*Spec{&Spec{Name: testSpecName, PacketSpecs: [][]string{[]string{"TCP-flags S"}}}},
  70. SelectSpecName: func(protocolPort int, _ net.IP) string {
  71. if protocolPort == listenerPort {
  72. return testSpecName
  73. }
  74. return ""
  75. },
  76. QueueNumber: 1,
  77. }
  78. m, err := NewManipulator(config)
  79. if err != nil {
  80. t.Fatalf("NewManipulator failed: %v", err)
  81. }
  82. err = m.Start()
  83. if err != nil {
  84. t.Fatalf("Manipulator.Start failed: %v", err)
  85. }
  86. defer m.Stop()
  87. go func() {
  88. serveMux := http.NewServeMux()
  89. serveMux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
  90. io.WriteString(w, "test-response\n")
  91. })
  92. server := &http.Server{
  93. Handler: serveMux,
  94. ConnState: func(conn net.Conn, state http.ConnState) {
  95. if state == http.StateNew {
  96. localAddr := conn.LocalAddr().(*net.TCPAddr)
  97. remoteAddr := conn.RemoteAddr().(*net.TCPAddr)
  98. specName, err := m.GetAppliedSpecName(localAddr, remoteAddr)
  99. if err != nil {
  100. t.Fatalf("GetAppliedSpecName failed: %v", err)
  101. }
  102. if specName != testSpecName {
  103. t.Fatalf("unexpected spec name: %s", specName)
  104. }
  105. }
  106. },
  107. }
  108. server.Serve(listener)
  109. }()
  110. httpClient := &http.Client{
  111. Timeout: 30 * time.Second,
  112. }
  113. response, err := httpClient.Get(fmt.Sprintf("http://%s:%s", hostStr, portStr))
  114. if err != nil {
  115. t.Fatalf("http.Get failed: %v", err)
  116. }
  117. defer response.Body.Close()
  118. _, err = ioutil.ReadAll(response.Body)
  119. if err != nil {
  120. t.Fatalf("ioutil.ReadAll failed: %v", err)
  121. }
  122. if response.StatusCode != http.StatusOK {
  123. t.Fatalf("unexpected response code: %d", response.StatusCode)
  124. }
  125. }
  126. func newTestLogger() common.Logger {
  127. return &testLogger{}
  128. }
  129. type testLogger struct {
  130. }
  131. func (logger *testLogger) WithTrace() common.LogTrace {
  132. return &testLogTrace{
  133. trace: stacktrace.GetParentFunctionName(),
  134. }
  135. }
  136. func (logger *testLogger) WithTraceFields(fields common.LogFields) common.LogTrace {
  137. return &testLogTrace{
  138. trace: stacktrace.GetParentFunctionName(),
  139. fields: fields,
  140. }
  141. }
  142. func (logger *testLogger) LogMetric(metric string, fields common.LogFields) {
  143. }
  144. type testLogTrace struct {
  145. trace string
  146. fields common.LogFields
  147. }
  148. func (log *testLogTrace) log(
  149. noticeType string, args ...interface{}) {
  150. fmt.Printf("[%s] %s: %+v: %s\n",
  151. noticeType,
  152. log.trace,
  153. log.fields,
  154. fmt.Sprint(args...))
  155. }
  156. func (log *testLogTrace) Debug(args ...interface{}) {
  157. log.log("DEBUG", args...)
  158. }
  159. func (log *testLogTrace) Info(args ...interface{}) {
  160. log.log("INFO", args...)
  161. }
  162. func (log *testLogTrace) Warning(args ...interface{}) {
  163. log.log("ALERT", args...)
  164. }
  165. func (log *testLogTrace) Error(args ...interface{}) {
  166. log.log("ERROR", args...)
  167. }