1
0

pinned_bind_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package amneziawgnet
  2. import (
  3. "net"
  4. "net/netip"
  5. "strconv"
  6. "testing"
  7. "time"
  8. awgconn "github.com/amnezia-vpn/amneziawg-go/v3/conn"
  9. "github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
  10. )
  11. func TestParseListenAddr(t *testing.T) {
  12. cases := []struct {
  13. in string
  14. pinned bool
  15. want string
  16. }{
  17. {in: "", pinned: false},
  18. {in: " ", pinned: false},
  19. {in: "0.0.0.0", pinned: false},
  20. {in: "::", pinned: false},
  21. {in: "::0", pinned: false},
  22. {in: "[::]", pinned: false},
  23. {in: "[::0]", pinned: false},
  24. {in: "127.0.0.1", pinned: true, want: "127.0.0.1"},
  25. {in: "::1", pinned: true, want: "::1"},
  26. {in: "[::1]", pinned: true, want: "::1"},
  27. {in: "not-an-ip", pinned: false},
  28. {in: "/var/run/awg.sock", pinned: false},
  29. }
  30. for _, tc := range cases {
  31. addr, ok := parseListenAddr(tc.in)
  32. if ok != tc.pinned {
  33. t.Fatalf("parseListenAddr(%q) pinned=%v, want %v", tc.in, ok, tc.pinned)
  34. }
  35. if tc.pinned && addr.String() != tc.want {
  36. t.Fatalf("parseListenAddr(%q) = %s, want %s", tc.in, addr, tc.want)
  37. }
  38. }
  39. }
  40. func TestNewListenBindPinsSpecificAddress(t *testing.T) {
  41. bind := newListenBind("127.0.0.1")
  42. pb, ok := bind.(*pinnedBind)
  43. if !ok {
  44. t.Fatalf("bind type = %T, want *pinnedBind", bind)
  45. }
  46. fns, port, err := pb.Open(0)
  47. if err != nil {
  48. t.Fatalf("Open: %v", err)
  49. }
  50. defer pb.Close()
  51. if len(fns) != 1 {
  52. t.Fatalf("ReceiveFuncs = %d, want 1", len(fns))
  53. }
  54. if port == 0 {
  55. t.Fatal("expected a concrete ephemeral port")
  56. }
  57. laddr := pb.conn.LocalAddr().(*net.UDPAddr)
  58. got := laddr.AddrPort().Addr().Unmap()
  59. if got.String() != "127.0.0.1" {
  60. t.Fatalf("LocalAddr = %v, want 127.0.0.1", got)
  61. }
  62. clash := newListenBind("127.0.0.1")
  63. if _, _, err := clash.Open(port); err == nil {
  64. clash.Close()
  65. t.Fatalf("Open(%d) unexpectedly succeeded on an already-bound address", port)
  66. }
  67. }
  68. func TestNewListenBindWildcardUsesDefault(t *testing.T) {
  69. prev := wildcardBindHost
  70. wildcardBindHost = ""
  71. t.Cleanup(func() { wildcardBindHost = prev })
  72. for _, listen := range []string{"", "0.0.0.0", "::", "::0", "[::]", "hostname.example", "203.0.113.10", "not-an-ip"} {
  73. bind := newListenBind(listen)
  74. if _, ok := bind.(*pinnedBind); ok {
  75. t.Fatalf("newListenBind(%q) returned pinnedBind, want default StdNetBind", listen)
  76. }
  77. }
  78. }
  79. func TestPinnedBindRoundTrip(t *testing.T) {
  80. server := newListenBind("127.0.0.1")
  81. recvFns, port, err := server.Open(0)
  82. if err != nil {
  83. t.Fatalf("server Open: %v", err)
  84. }
  85. defer server.Close()
  86. client, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
  87. if err != nil {
  88. t.Fatalf("client listen: %v", err)
  89. }
  90. defer client.Close()
  91. payload := []byte("hello-awg-listen")
  92. dst := net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port)))
  93. ap, err := netip.ParseAddrPort(dst)
  94. if err != nil {
  95. t.Fatalf("ParseAddrPort: %v", err)
  96. }
  97. if _, err := client.WriteToUDPAddrPort(payload, ap); err != nil {
  98. t.Fatalf("client write: %v", err)
  99. }
  100. bufs := [][]byte{make([]byte, 1500)}
  101. sizes := make([]int, 1)
  102. eps := make([]awgconn.Endpoint, 1)
  103. n, err := recvFns[0](bufs, sizes, eps)
  104. if err != nil {
  105. t.Fatalf("receive: %v", err)
  106. }
  107. if n != 1 || sizes[0] != len(payload) {
  108. t.Fatalf("receive n=%d size=%d, want 1/%d", n, sizes[0], len(payload))
  109. }
  110. if string(bufs[0][:sizes[0]]) != string(payload) {
  111. t.Fatalf("payload = %q, want %q", bufs[0][:sizes[0]], payload)
  112. }
  113. reply := []byte("pong")
  114. if err := server.Send([][]byte{reply}, eps[0]); err != nil {
  115. t.Fatalf("Send: %v", err)
  116. }
  117. _ = client.SetReadDeadline(time.Now().Add(2 * time.Second))
  118. buf := make([]byte, 1500)
  119. rn, _, err := client.ReadFromUDP(buf)
  120. if err != nil {
  121. t.Fatalf("client read: %v", err)
  122. }
  123. if string(buf[:rn]) != string(reply) {
  124. t.Fatalf("reply = %q, want %q", buf[:rn], reply)
  125. }
  126. }
  127. func TestAddressFingerprintIncludesListen(t *testing.T) {
  128. base := amneziawg.Instance{
  129. MTU: 1420,
  130. Address: []string{"10.8.1.1/24"},
  131. Obfuscation: amneziawg.Obfuscation31{},
  132. }
  133. a := addressFingerprint(base)
  134. base.Listen = "127.0.0.1"
  135. b := addressFingerprint(base)
  136. if a == b {
  137. t.Fatalf("listen edit did not change addressFingerprint: %q", a)
  138. }
  139. base.Listen = "0.0.0.0"
  140. if addressFingerprint(base) != a {
  141. t.Fatal("wildcard spellings must share the empty-listen fingerprint")
  142. }
  143. base.Listen = "hostname.example"
  144. if addressFingerprint(base) != a {
  145. t.Fatal("unusable listen must fingerprint like wildcard fallback")
  146. }
  147. }
  148. var _ awgconn.Bind = (*pinnedBind)(nil)