socks_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package main
  2. import (
  3. "context"
  4. "net"
  5. "net/netip"
  6. "testing"
  7. "time"
  8. C "github.com/sagernet/sing-box/constant"
  9. "github.com/sagernet/sing-box/option"
  10. "github.com/sagernet/sing/common"
  11. F "github.com/sagernet/sing/common/format"
  12. "github.com/sagernet/sing/common/json/badoption"
  13. M "github.com/sagernet/sing/common/metadata"
  14. N "github.com/sagernet/sing/common/network"
  15. "github.com/sagernet/sing/protocol/socks"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func TestSOCKSUDPTimeout(t *testing.T) {
  19. const testTimeout = 2 * time.Second
  20. udpTimeout := option.UDPTimeoutCompat(testTimeout)
  21. startInstance(t, option.Options{
  22. Inbounds: []option.Inbound{
  23. {
  24. Type: C.TypeSOCKS,
  25. Tag: "socks-in",
  26. Options: &option.SocksInboundOptions{
  27. ListenOptions: option.ListenOptions{
  28. Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
  29. ListenPort: clientPort,
  30. UDPTimeout: udpTimeout,
  31. },
  32. },
  33. },
  34. },
  35. Outbounds: []option.Outbound{
  36. {
  37. Type: C.TypeDirect,
  38. },
  39. },
  40. })
  41. testUDPSessionIdleTimeout(t, clientPort, testPort, testTimeout)
  42. }
  43. func TestMixedUDPTimeout(t *testing.T) {
  44. const testTimeout = 2 * time.Second
  45. udpTimeout := option.UDPTimeoutCompat(testTimeout)
  46. startInstance(t, option.Options{
  47. Inbounds: []option.Inbound{
  48. {
  49. Type: C.TypeMixed,
  50. Tag: "mixed-in",
  51. Options: &option.HTTPMixedInboundOptions{
  52. ListenOptions: option.ListenOptions{
  53. Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
  54. ListenPort: clientPort,
  55. UDPTimeout: udpTimeout,
  56. },
  57. },
  58. },
  59. },
  60. Outbounds: []option.Outbound{
  61. {
  62. Type: C.TypeDirect,
  63. },
  64. },
  65. })
  66. testUDPSessionIdleTimeout(t, clientPort, testPort, testTimeout)
  67. }
  68. func testUDPSessionIdleTimeout(t *testing.T, proxyPort uint16, echoPort uint16, expectedTimeout time.Duration) {
  69. echoServer, err := listenPacket("udp", ":"+F.ToString(echoPort))
  70. require.NoError(t, err)
  71. defer echoServer.Close()
  72. go func() {
  73. buffer := make([]byte, 1024)
  74. for {
  75. n, address, err := echoServer.ReadFrom(buffer)
  76. if err != nil {
  77. return
  78. }
  79. _, _ = echoServer.WriteTo(buffer[:n], address)
  80. }
  81. }()
  82. dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", proxyPort), socks.Version5, "", "")
  83. packetConn, err := dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", echoPort))
  84. require.NoError(t, err)
  85. defer packetConn.Close()
  86. remoteAddress := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: int(echoPort)}
  87. _, err = packetConn.WriteTo([]byte("hello"), remoteAddress)
  88. require.NoError(t, err)
  89. buffer := make([]byte, 1024)
  90. packetConn.SetReadDeadline(time.Now().Add(5 * time.Second))
  91. n, _, err := packetConn.ReadFrom(buffer)
  92. require.NoError(t, err, "failed to receive echo response")
  93. require.Equal(t, "hello", string(buffer[:n]))
  94. t.Log("UDP echo successful, session established")
  95. packetConn.SetReadDeadline(time.Time{})
  96. waitTime := expectedTimeout + time.Second
  97. t.Logf("Waiting %v for UDP session to timeout...", waitTime)
  98. time.Sleep(waitTime)
  99. _, err = packetConn.WriteTo([]byte("after-timeout"), remoteAddress)
  100. if err != nil {
  101. t.Logf("Write after timeout correctly failed: %v", err)
  102. return
  103. }
  104. packetConn.SetReadDeadline(time.Now().Add(3 * time.Second))
  105. n, _, err = packetConn.ReadFrom(buffer)
  106. if err != nil {
  107. t.Logf("Read after timeout correctly failed: %v", err)
  108. return
  109. }
  110. t.Fatalf("UDP session should have timed out after %v, but received response: %s",
  111. expectedTimeout, string(buffer[:n]))
  112. }