1
0

pinned_bind_test.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. for _, listen := range []string{"", "0.0.0.0", "::", "::0", "[::]", "hostname.example", "203.0.113.10", "not-an-ip"} {
  70. bind := newListenBind(listen)
  71. if _, ok := bind.(*pinnedBind); ok {
  72. t.Fatalf("newListenBind(%q) returned pinnedBind, want default StdNetBind", listen)
  73. }
  74. }
  75. }
  76. func TestPinnedBindRoundTrip(t *testing.T) {
  77. server := newListenBind("127.0.0.1")
  78. recvFns, port, err := server.Open(0)
  79. if err != nil {
  80. t.Fatalf("server Open: %v", err)
  81. }
  82. defer server.Close()
  83. client, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
  84. if err != nil {
  85. t.Fatalf("client listen: %v", err)
  86. }
  87. defer client.Close()
  88. payload := []byte("hello-awg-listen")
  89. dst := net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port)))
  90. ap, err := netip.ParseAddrPort(dst)
  91. if err != nil {
  92. t.Fatalf("ParseAddrPort: %v", err)
  93. }
  94. if _, err := client.WriteToUDPAddrPort(payload, ap); err != nil {
  95. t.Fatalf("client write: %v", err)
  96. }
  97. bufs := [][]byte{make([]byte, 1500)}
  98. sizes := make([]int, 1)
  99. eps := make([]awgconn.Endpoint, 1)
  100. n, err := recvFns[0](bufs, sizes, eps)
  101. if err != nil {
  102. t.Fatalf("receive: %v", err)
  103. }
  104. if n != 1 || sizes[0] != len(payload) {
  105. t.Fatalf("receive n=%d size=%d, want 1/%d", n, sizes[0], len(payload))
  106. }
  107. if string(bufs[0][:sizes[0]]) != string(payload) {
  108. t.Fatalf("payload = %q, want %q", bufs[0][:sizes[0]], payload)
  109. }
  110. reply := []byte("pong")
  111. if err := server.Send([][]byte{reply}, eps[0]); err != nil {
  112. t.Fatalf("Send: %v", err)
  113. }
  114. _ = client.SetReadDeadline(time.Now().Add(2 * time.Second))
  115. buf := make([]byte, 1500)
  116. rn, _, err := client.ReadFromUDP(buf)
  117. if err != nil {
  118. t.Fatalf("client read: %v", err)
  119. }
  120. if string(buf[:rn]) != string(reply) {
  121. t.Fatalf("reply = %q, want %q", buf[:rn], reply)
  122. }
  123. }
  124. func TestAddressFingerprintIncludesListen(t *testing.T) {
  125. base := amneziawg.Instance{
  126. MTU: 1420,
  127. Address: []string{"10.8.1.1/24"},
  128. Obfuscation: amneziawg.Obfuscation31{},
  129. }
  130. a := addressFingerprint(base)
  131. base.Listen = "127.0.0.1"
  132. b := addressFingerprint(base)
  133. if a == b {
  134. t.Fatalf("listen edit did not change addressFingerprint: %q", a)
  135. }
  136. base.Listen = "0.0.0.0"
  137. if addressFingerprint(base) != a {
  138. t.Fatal("wildcard spellings must share the empty-listen fingerprint")
  139. }
  140. base.Listen = "hostname.example"
  141. if addressFingerprint(base) != a {
  142. t.Fatal("unusable listen must fingerprint like wildcard fallback")
  143. }
  144. }
  145. var _ awgconn.Bind = (*pinnedBind)(nil)