1
0

egress_domain_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. package amneziawgnet
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "io"
  7. "net"
  8. "net/netip"
  9. "strconv"
  10. "strings"
  11. "testing"
  12. "time"
  13. "gvisor.dev/gvisor/pkg/tcpip"
  14. "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
  15. "gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
  16. "gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
  17. "github.com/amnezia-vpn/amneziawg-go/v3/device"
  18. "github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
  19. wgutil "github.com/mhsanaei/3x-ui/v3/internal/util/wireguard"
  20. )
  21. func verboseLoggerForTest(prefix string) *device.Logger {
  22. return device.NewLogger(device.LogLevelVerbose, prefix)
  23. }
  24. const (
  25. tunnelTestClientAddr = "10.203.0.2"
  26. tunnelTestServerAddr = "10.203.0.1"
  27. tunnelTestClientAddrV6 = "fd00:203::2"
  28. tunnelTestServerAddrV6 = "fd00:203::1"
  29. egressTestDialTimeout = 5 * time.Second
  30. )
  31. // pairedTunnel wires an outbound client device to an embedded server device
  32. // over host UDP; the server stack hosts the far-end services under test.
  33. type pairedTunnel struct {
  34. client *Device
  35. server *Device
  36. serverIP netip.Addr
  37. }
  38. func newPairedTunnelForTest(t *testing.T) *pairedTunnel {
  39. t.Helper()
  40. slog := verboseLoggerForTest("(tsrv) ")
  41. serverPriv, serverPub, err := wgutil.GenerateWireguardKeypair()
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. clientPriv, clientPub, err := wgutil.GenerateWireguardKeypair()
  46. if err != nil {
  47. t.Fatal(err)
  48. }
  49. pc, err := net.ListenPacket("udp", "127.0.0.1:0")
  50. if err != nil {
  51. t.Fatal(err)
  52. }
  53. listenPort := pc.LocalAddr().(*net.UDPAddr).Port
  54. pc.Close()
  55. obf := amneziawg.Obfuscation31{Jc: 4, Jmin: 40, Jmax: 70, S1: 20, S2: 30, S3: 20, S4: 20}
  56. serverInst := amneziawg.Instance{
  57. Id: 1,
  58. InterfaceName: "awg-dnstest",
  59. ListenPort: listenPort,
  60. PrivateKey: serverPriv,
  61. PublicKey: serverPub,
  62. Address: []string{tunnelTestServerAddr + "/24"},
  63. MTU: 1420,
  64. Obfuscation: obf,
  65. Peers: []amneziawg.Peer{{
  66. PublicKey: clientPub,
  67. AllowedIPs: []string{tunnelTestClientAddr + "/32"},
  68. }},
  69. }
  70. server, err := newUnconfiguredDevice(serverInst, DeviceOptions{Logger: slog})
  71. if err != nil {
  72. t.Fatalf("server device: %v", err)
  73. }
  74. t.Cleanup(server.Close)
  75. // Server Up before client exists: the first handshake fires at
  76. // ConfigureClient; a missed initiation costs a 5s REKEY_TIMEOUT.
  77. if err := server.Configure(serverInst, DeviceOptions{Logger: slog}); err != nil {
  78. t.Fatalf("server Configure: %v", err)
  79. }
  80. clientInst := amneziawg.OutboundInstance{
  81. Tag: "awg-dom-test",
  82. Address: []string{tunnelTestClientAddr + "/32"},
  83. MTU: 1420,
  84. PrivateKey: clientPriv,
  85. Obfuscation: obf,
  86. Peers: []amneziawg.OutboundPeer{{
  87. PublicKey: serverPub,
  88. Endpoint: net.JoinHostPort("127.0.0.1", strconv.Itoa(listenPort)),
  89. AllowedIPs: []string{"0.0.0.0/0", "::/0"},
  90. KeepAlive: 1,
  91. }},
  92. }
  93. clog := verboseLoggerForTest("(tcli) ")
  94. client, err := newUnconfiguredClientDevice(clientInst, DeviceOptions{Logger: clog})
  95. if err != nil {
  96. t.Fatalf("client device: %v", err)
  97. }
  98. if err := client.ConfigureClient(clientInst, DeviceOptions{Logger: clog}); err != nil {
  99. client.Close()
  100. t.Fatalf("ConfigureClient: %v", err)
  101. }
  102. t.Cleanup(client.Close)
  103. return &pairedTunnel{
  104. client: client,
  105. server: server,
  106. serverIP: netip.MustParseAddr(tunnelTestServerAddr),
  107. }
  108. }
  109. func newPairedTunnelV6ForTest(t *testing.T) *pairedTunnel {
  110. t.Helper()
  111. slog := verboseLoggerForTest("(tsrv6) ")
  112. serverPriv, serverPub, err := wgutil.GenerateWireguardKeypair()
  113. if err != nil {
  114. t.Fatal(err)
  115. }
  116. clientPriv, clientPub, err := wgutil.GenerateWireguardKeypair()
  117. if err != nil {
  118. t.Fatal(err)
  119. }
  120. pc, err := net.ListenPacket("udp", "127.0.0.1:0")
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. listenPort := pc.LocalAddr().(*net.UDPAddr).Port
  125. pc.Close()
  126. obf := amneziawg.Obfuscation31{Jc: 4, Jmin: 40, Jmax: 70, S1: 20, S2: 30, S3: 20, S4: 20}
  127. serverInst := amneziawg.Instance{
  128. Id: 2,
  129. InterfaceName: "awg-dnstest6",
  130. ListenPort: listenPort,
  131. PrivateKey: serverPriv,
  132. PublicKey: serverPub,
  133. Address: []string{tunnelTestServerAddrV6 + "/64", "2606:4700:4700::1111/128"},
  134. MTU: 1420,
  135. Obfuscation: obf,
  136. Peers: []amneziawg.Peer{{
  137. PublicKey: clientPub,
  138. AllowedIPs: []string{tunnelTestClientAddrV6 + "/128"},
  139. }},
  140. }
  141. server, err := newUnconfiguredDevice(serverInst, DeviceOptions{Logger: slog})
  142. if err != nil {
  143. t.Fatalf("server device: %v", err)
  144. }
  145. t.Cleanup(server.Close)
  146. if err := server.Configure(serverInst, DeviceOptions{Logger: slog}); err != nil {
  147. t.Fatalf("server Configure: %v", err)
  148. }
  149. clientInst := amneziawg.OutboundInstance{
  150. Tag: "awg-dom-v6-test",
  151. Address: []string{tunnelTestClientAddrV6 + "/128"},
  152. MTU: 1420,
  153. PrivateKey: clientPriv,
  154. Obfuscation: obf,
  155. Peers: []amneziawg.OutboundPeer{{
  156. PublicKey: serverPub,
  157. Endpoint: net.JoinHostPort("127.0.0.1", strconv.Itoa(listenPort)),
  158. AllowedIPs: []string{"::/0"},
  159. KeepAlive: 1,
  160. }},
  161. }
  162. clog := verboseLoggerForTest("(tcli6) ")
  163. client, err := newUnconfiguredClientDevice(clientInst, DeviceOptions{Logger: clog})
  164. if err != nil {
  165. t.Fatalf("client device: %v", err)
  166. }
  167. if err := client.ConfigureClient(clientInst, DeviceOptions{Logger: clog}); err != nil {
  168. client.Close()
  169. t.Fatalf("ConfigureClient: %v", err)
  170. }
  171. t.Cleanup(client.Close)
  172. return &pairedTunnel{
  173. client: client,
  174. server: server,
  175. serverIP: netip.MustParseAddr(tunnelTestServerAddrV6),
  176. }
  177. }
  178. func registerEgressDeviceForTest(t *testing.T, dev *Device) {
  179. t.Helper()
  180. srv := GetEgressServer()
  181. srv.SetStack("awg-dom-test", dev)
  182. if err := srv.Listen(); err != nil {
  183. t.Fatal(err)
  184. }
  185. t.Cleanup(func() { srv.DeleteStack("awg-dom-test") })
  186. }
  187. // startTunnelDNS answers A/AAAA queries from INSIDE the server's netstack;
  188. // reaching it proves DNS rode the tunnel, not the host resolver.
  189. func (p *pairedTunnel) startDNS(t *testing.T, answer netip.Addr) chan string {
  190. t.Helper()
  191. proto := ipv4.ProtocolNumber
  192. if p.serverIP.Is6() {
  193. proto = ipv6.ProtocolNumber
  194. }
  195. ln, err := gonet.DialUDP(p.server.Stack, &tcpip.FullAddress{NIC: 1, Port: 53}, nil, proto)
  196. if err != nil {
  197. t.Fatalf("bind fake dns in server stack: %v", err)
  198. }
  199. got := make(chan string, 8)
  200. go func() {
  201. defer ln.Close()
  202. buf := make([]byte, 512)
  203. for {
  204. n, from, rerr := ln.ReadFrom(buf)
  205. if rerr != nil {
  206. return
  207. }
  208. q := buf[:n]
  209. if name := dnsQuestionName(q); name != "" {
  210. select {
  211. case got <- name:
  212. default:
  213. }
  214. }
  215. if resp := buildARecordReply(q, answer); resp != nil {
  216. if _, werr := ln.WriteTo(resp, from); werr != nil {
  217. return
  218. }
  219. }
  220. }
  221. }()
  222. t.Cleanup(func() { ln.Close() })
  223. return got
  224. }
  225. func (p *pairedTunnel) overrideDNS(t *testing.T, answer netip.Addr) chan string {
  226. t.Helper()
  227. srv := GetEgressServer()
  228. prev := srv.currentDNSServer()
  229. srv.SetDNSServer(net.JoinHostPort(p.serverIP.String(), "53"))
  230. t.Cleanup(func() { srv.SetDNSServer(prev) })
  231. resetTunnelDNSCacheForTest()
  232. return p.startDNS(t, answer)
  233. }
  234. func resetTunnelDNSCacheForTest() {
  235. tunnelDNSCache.mu.Lock()
  236. tunnelDNSCache.m = map[string]tunnelDNSCacheEntry{}
  237. tunnelDNSCache.mu.Unlock()
  238. }
  239. func dnsQuestionName(q []byte) string {
  240. if len(q) < 12 {
  241. return ""
  242. }
  243. i := 12
  244. var parts []byte
  245. for i < len(q) {
  246. l := int(q[i])
  247. i++
  248. if l == 0 {
  249. break
  250. }
  251. if i+l > len(q) || l > 63 {
  252. return ""
  253. }
  254. parts = append(parts, q[i:i+l]...)
  255. parts = append(parts, '.')
  256. i += l
  257. }
  258. for len(parts) > 0 && parts[len(parts)-1] == '.' {
  259. parts = parts[:len(parts)-1]
  260. }
  261. return string(parts)
  262. }
  263. func buildARecordReply(q []byte, answer netip.Addr) []byte {
  264. if len(q) < 17 {
  265. return nil
  266. }
  267. out := make([]byte, 0, len(q)+16)
  268. header := make([]byte, 12)
  269. copy(header[0:2], q[0:2])
  270. header[2] = 0x81 // QR=1 RD=1
  271. header[3] = 0x80 // RA=1 RCODE=0
  272. binary.BigEndian.PutUint16(header[4:], 1)
  273. binary.BigEndian.PutUint16(header[6:], 1)
  274. out = append(out, header...)
  275. end := len(q)
  276. for end >= 5 && q[end-4] == 0 && q[end-3] == 0 && q[end-2] == 0 && q[end-1] == 0 {
  277. end -= 4
  278. }
  279. out = append(out, q[12:end]...)
  280. if answer.Is4() {
  281. a := answer.As4()
  282. rr := make([]byte, 16)
  283. rr[0], rr[1] = 0xc0, 0x0c
  284. binary.BigEndian.PutUint16(rr[2:], 1) // Type A
  285. binary.BigEndian.PutUint16(rr[4:], 1) // IN
  286. binary.BigEndian.PutUint32(rr[6:], 30) // TTL
  287. binary.BigEndian.PutUint16(rr[10:], 4)
  288. copy(rr[12:], a[:])
  289. out = append(out, rr...)
  290. } else if answer.Is6() {
  291. a16 := answer.As16()
  292. rr := make([]byte, 28)
  293. rr[0], rr[1] = 0xc0, 0x0c
  294. binary.BigEndian.PutUint16(rr[2:], 28) // Type AAAA
  295. binary.BigEndian.PutUint16(rr[4:], 1) // IN
  296. binary.BigEndian.PutUint32(rr[6:], 30) // TTL
  297. binary.BigEndian.PutUint16(rr[10:], 16)
  298. copy(rr[12:], a16[:])
  299. out = append(out, rr...)
  300. }
  301. return out
  302. }
  303. func socksAuthUser(t *testing.T, ctl net.Conn, user string) {
  304. t.Helper()
  305. ctl.SetDeadline(time.Now().Add(egressTestDialTimeout))
  306. if _, err := ctl.Write([]byte{0x05, 0x02, 0x00, 0x02}); err != nil {
  307. t.Fatal(err)
  308. }
  309. r := make([]byte, 2)
  310. if _, err := io.ReadFull(ctl, r); err != nil {
  311. t.Fatalf("greeting read: %v", err)
  312. }
  313. pass := SocksPassword()
  314. req := make([]byte, 0, 3+len(user)+len(pass))
  315. req = append(req, 0x01, byte(len(user)))
  316. req = append(req, user...)
  317. req = append(req, byte(len(pass)))
  318. req = append(req, pass...)
  319. if _, err := ctl.Write(req); err != nil {
  320. t.Fatal(err)
  321. }
  322. auth := make([]byte, 2)
  323. if _, err := io.ReadFull(ctl, auth); err != nil || auth[1] != 0x00 {
  324. t.Fatalf("auth rejected: %v %v", err, auth)
  325. }
  326. }
  327. func socksAuth(t *testing.T, ctl net.Conn) {
  328. t.Helper()
  329. socksAuthUser(t, ctl, "awg-dom-test")
  330. }
  331. func TestEgressGreetingRejectsNoAuthClient(t *testing.T) {
  332. tun := newPairedTunnelForTest(t)
  333. registerEgressDeviceForTest(t, tun.client)
  334. ctl, err := (&net.Dialer{Timeout: egressTestDialTimeout}).Dial("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(EgressBasePort)))
  335. if err != nil {
  336. t.Fatal(err)
  337. }
  338. defer ctl.Close()
  339. ctl.SetDeadline(time.Now().Add(egressTestDialTimeout))
  340. // Client offers only NO-AUTH; server must answer 0xFF.
  341. if _, err := ctl.Write([]byte{0x05, 0x01, 0x00}); err != nil {
  342. t.Fatal(err)
  343. }
  344. r := make([]byte, 2)
  345. if _, err := io.ReadFull(ctl, r); err != nil {
  346. t.Fatalf("greeting read: %v", err)
  347. }
  348. if r[0] != 0x05 || r[1] != 0xFF {
  349. t.Fatalf("greeting reply = %v, want 05 FF (auth required)", r)
  350. }
  351. }
  352. func TestEgressConnectDomainResolvesThroughTunnel(t *testing.T) {
  353. tun := newPairedTunnelForTest(t)
  354. registerEgressDeviceForTest(t, tun.client)
  355. // Resolving to the server's own tunnel address makes the follow-up dial
  356. // fail fast (nothing listens on :80), while proving resolution happened.
  357. gotQuery := tun.overrideDNS(t, tun.serverIP)
  358. ctl, err := (&net.Dialer{Timeout: egressTestDialTimeout}).Dial("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(EgressBasePort)))
  359. if err != nil {
  360. t.Fatal(err)
  361. }
  362. defer ctl.Close()
  363. socksAuth(t, ctl)
  364. name := "example.internal"
  365. req := make([]byte, 0, 7+len(name))
  366. req = append(req, 0x05, 0x01, 0x00, 0x03, byte(len(name)))
  367. req = append(req, name...)
  368. req = append(req, 0x00, 0x50)
  369. if _, err := ctl.Write(req); err != nil {
  370. t.Fatal(err)
  371. }
  372. select {
  373. case queried := <-gotQuery:
  374. if len(queried) < len(name) || queried[:len(name)] != name {
  375. t.Fatalf("resolver queried %q, want prefix %q -- DNS did not ride the tunnel", queried, name)
  376. }
  377. case <-time.After(egressTestDialTimeout):
  378. t.Fatal("no DNS query reached the in-tunnel resolver")
  379. }
  380. reply := make([]byte, 10)
  381. ctl.SetDeadline(time.Now().Add(egressTestDialTimeout))
  382. if _, err := io.ReadFull(ctl, reply); err != nil {
  383. t.Fatalf("read reply: %v", err)
  384. }
  385. if reply[1] == 0x00 {
  386. t.Fatal("unexpected success: nothing should be listening on the resolved address")
  387. }
  388. }
  389. func TestEgressConnectDomainIPv6OnlyTunnelResolvesThroughTunnel(t *testing.T) {
  390. tun := newPairedTunnelV6ForTest(t)
  391. srv := GetEgressServer()
  392. srv.SetStack("awg-dom-v6-test", tun.client)
  393. if err := srv.Listen(); err != nil {
  394. t.Fatal(err)
  395. }
  396. t.Cleanup(func() { srv.DeleteStack("awg-dom-v6-test") })
  397. // No override: a blank dns has to fall through currentDNSServer to
  398. // defaultDNSFor, which the server stack answers on its own v6 /128.
  399. prevDNS := srv.currentDNSServer()
  400. srv.SetDNSServer("")
  401. t.Cleanup(func() { srv.SetDNSServer(prevDNS) })
  402. resetTunnelDNSCacheForTest()
  403. gotQuery := tun.startDNS(t, tun.serverIP)
  404. ctl, err := (&net.Dialer{Timeout: egressTestDialTimeout}).Dial("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(EgressBasePort)))
  405. if err != nil {
  406. t.Fatal(err)
  407. }
  408. defer ctl.Close()
  409. socksAuthUser(t, ctl, "awg-dom-v6-test")
  410. name := "v6.example.internal"
  411. req := make([]byte, 0, 7+len(name))
  412. req = append(req, 0x05, 0x01, 0x00, 0x03, byte(len(name)))
  413. req = append(req, name...)
  414. req = append(req, 0x00, 0x50)
  415. if _, err := ctl.Write(req); err != nil {
  416. t.Fatal(err)
  417. }
  418. select {
  419. case queried := <-gotQuery:
  420. if len(queried) < len(name) || queried[:len(name)] != name {
  421. t.Fatalf("resolver queried %q, want prefix %q -- DNS did not ride the v6 tunnel", queried, name)
  422. }
  423. case <-time.After(egressTestDialTimeout):
  424. t.Fatal("no DNS query reached the in-tunnel v6 resolver")
  425. }
  426. reply := make([]byte, 10)
  427. ctl.SetDeadline(time.Now().Add(egressTestDialTimeout))
  428. if _, err := io.ReadFull(ctl, reply); err != nil {
  429. t.Fatalf("read reply: %v", err)
  430. }
  431. if reply[1] == 0x00 {
  432. t.Fatal("unexpected success: nothing should be listening on the resolved address")
  433. }
  434. }
  435. func TestEgressUDPDatagramDomainForwardedIntoTunnel(t *testing.T) {
  436. tun := newPairedTunnelForTest(t)
  437. registerEgressDeviceForTest(t, tun.client)
  438. gotQuery := tun.overrideDNS(t, tun.serverIP)
  439. in, err := gonet.DialUDP(tun.server.Stack, &tcpip.FullAddress{NIC: 1, Port: 9999}, nil, ipv4.ProtocolNumber)
  440. if err != nil {
  441. t.Fatal(err)
  442. }
  443. defer in.Close()
  444. ctl, err := (&net.Dialer{Timeout: egressTestDialTimeout}).Dial("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(EgressBasePort)))
  445. if err != nil {
  446. t.Fatal(err)
  447. }
  448. defer ctl.Close()
  449. socksAuth(t, ctl)
  450. if _, err := ctl.Write([]byte{0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0, 0, 0}); err != nil {
  451. t.Fatal(err)
  452. }
  453. reply := make([]byte, 10)
  454. if _, err := io.ReadFull(ctl, reply); err != nil || reply[1] != 0x00 {
  455. t.Fatalf("associate failed: %v %v", err, reply)
  456. }
  457. bindPort := binary.BigEndian.Uint16(reply[8:10])
  458. udp, err := net.DialUDP("udp", nil, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: int(bindPort)})
  459. if err != nil {
  460. t.Fatal(err)
  461. }
  462. defer udp.Close()
  463. udp.SetDeadline(time.Now().Add(egressTestDialTimeout))
  464. // Plain-IP control datagram isolates domain parsing from transport.
  465. // Retried to avoid warmup race on slow -race runners.
  466. ctrl := []byte{0x00, 0x00, 0x00, 0x01, 10, 203, 0, 1, 0x27, 0x0f, 'c', 't', 'r', 'l'}
  467. rcv := make([]byte, 64)
  468. var nr int
  469. var rerr error
  470. for attempt := 0; attempt < 3; attempt++ {
  471. if _, err := udp.Write(ctrl); err != nil {
  472. t.Fatal(err)
  473. }
  474. in.SetReadDeadline(time.Now().Add(3 * time.Second))
  475. nr, _, rerr = in.ReadFrom(rcv)
  476. if rerr == nil {
  477. break
  478. }
  479. }
  480. if rerr != nil {
  481. t.Fatalf("CONTROL datagram never reached the tunnel target: %v", rerr)
  482. }
  483. if string(rcv[:nr]) != "ctrl" {
  484. t.Fatalf("control payload = %q", rcv[:nr])
  485. }
  486. name := "quic.internal"
  487. dgram := make([]byte, 0, 5+len(name)+2+4)
  488. dgram = append(dgram, 0x00, 0x00, 0x00, 0x03, byte(len(name)))
  489. dgram = append(dgram, name...)
  490. dgram = append(dgram, 0x27, 0x0f)
  491. dgram = append(dgram, 'p', 'i', 'n', 'g')
  492. var queried string
  493. for attempt := 0; attempt < 3 && queried == ""; attempt++ {
  494. if _, err := udp.Write(dgram); err != nil {
  495. t.Fatal(err)
  496. }
  497. select {
  498. case q := <-gotQuery:
  499. queried = q
  500. case <-time.After(1500 * time.Millisecond):
  501. }
  502. }
  503. if len(queried) < len(name) || queried[:len(name)] != name {
  504. t.Fatalf("resolver queried %q, want prefix %q -- DNS did not ride the tunnel", queried, name)
  505. }
  506. in.SetReadDeadline(time.Now().Add(3 * time.Second))
  507. nr, _, rerr = in.ReadFrom(rcv)
  508. if rerr != nil {
  509. t.Fatalf("domain datagram never reached the tunnel target: %v", rerr)
  510. }
  511. if nr < 4 || string(rcv[:4]) != "ping" {
  512. t.Fatalf("payload = %q (n=%d)", rcv[:nr], nr)
  513. }
  514. }
  515. // TestEgressUDPDatagramDomainInterleavedClients ensures datagrams pass client
  516. // address by value into resolver goroutines so responses route correctly.
  517. func TestEgressUDPDatagramDomainInterleavedClients(t *testing.T) {
  518. tun := newPairedTunnelForTest(t)
  519. registerEgressDeviceForTest(t, tun.client)
  520. gotQuery := tun.overrideDNS(t, tun.serverIP)
  521. in, err := gonet.DialUDP(tun.server.Stack, &tcpip.FullAddress{NIC: 1, Port: 9999}, nil, ipv4.ProtocolNumber)
  522. if err != nil {
  523. t.Fatal(err)
  524. }
  525. defer in.Close()
  526. go func() {
  527. buf := make([]byte, 512)
  528. for {
  529. n, from, rerr := in.ReadFrom(buf)
  530. if rerr != nil {
  531. return
  532. }
  533. _, _ = in.WriteTo(append([]byte("echo:"), buf[:n]...), from)
  534. }
  535. }()
  536. dialUDP := func() *net.UDPConn {
  537. ctl, err := (&net.Dialer{Timeout: egressTestDialTimeout}).Dial("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(EgressBasePort)))
  538. if err != nil {
  539. t.Fatal(err)
  540. }
  541. t.Cleanup(func() { ctl.Close() })
  542. socksAuth(t, ctl)
  543. if _, err := ctl.Write([]byte{0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0, 0, 0}); err != nil {
  544. t.Fatal(err)
  545. }
  546. reply := make([]byte, 10)
  547. if _, err := io.ReadFull(ctl, reply); err != nil || reply[1] != 0x00 {
  548. t.Fatalf("associate failed: %v %v", err, reply)
  549. }
  550. bindPort := binary.BigEndian.Uint16(reply[8:10])
  551. udp, err := net.DialUDP("udp", nil, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: int(bindPort)})
  552. if err != nil {
  553. t.Fatal(err)
  554. }
  555. t.Cleanup(func() { udp.Close() })
  556. udp.SetDeadline(time.Now().Add(egressTestDialTimeout))
  557. return udp
  558. }
  559. name := func(i int) string { return fmt.Sprintf("interleaved-%d.internal", i) }
  560. dgram := func(i int, payload string) []byte {
  561. n := name(i)
  562. d := make([]byte, 0, 5+len(n)+2+len(payload))
  563. d = append(d, 0x00, 0x00, 0x00, 0x03, byte(len(n)))
  564. d = append(d, n...)
  565. d = append(d, 0x27, 0x0f)
  566. return append(d, payload...)
  567. }
  568. for seq := 0; seq < 4; seq++ {
  569. udp := dialUDP()
  570. payload := fmt.Sprintf("p-%d", seq)
  571. if _, err := udp.Write(dgram(seq, payload)); err != nil {
  572. t.Fatal(err)
  573. }
  574. select {
  575. case q := <-gotQuery:
  576. if !strings.HasPrefix(q, "interleaved-") {
  577. t.Fatalf("resolver queried %q, want an interleaved-* name", q)
  578. }
  579. case <-time.After(4 * time.Second):
  580. t.Fatalf("query %d not observed", seq)
  581. }
  582. rcv := make([]byte, 512)
  583. nr, _, rerr := udp.ReadFrom(rcv)
  584. if rerr != nil {
  585. t.Fatalf("reply %d never reached client: %v", seq, rerr)
  586. }
  587. if nr < 10 || !strings.Contains(string(rcv[:nr]), "echo:"+payload) {
  588. t.Fatalf("reply payload = %q, want echo:%s", rcv[:nr], payload)
  589. }
  590. }
  591. }
  592. func TestDefaultDNSFor(t *testing.T) {
  593. v4 := netip.MustParseAddr("10.8.0.2")
  594. v6 := netip.MustParseAddr("2001:db8::2")
  595. if got := defaultDNSFor([]netip.Addr{v4}); got != DefaultTunnelDNSServer {
  596. t.Errorf("defaultDNSFor(v4) = %q, want %q", got, DefaultTunnelDNSServer)
  597. }
  598. if got := defaultDNSFor([]netip.Addr{v4, v6}); got != DefaultTunnelDNSServer {
  599. t.Errorf("defaultDNSFor(dual) = %q, want %q", got, DefaultTunnelDNSServer)
  600. }
  601. if got := defaultDNSFor([]netip.Addr{v6}); got != DefaultTunnelDNSServerV6 {
  602. t.Errorf("defaultDNSFor(v6-only) = %q, want %q", got, DefaultTunnelDNSServerV6)
  603. }
  604. if got := defaultDNSFor(nil); got != DefaultTunnelDNSServer {
  605. t.Errorf("defaultDNSFor(nil) = %q, want %q", got, DefaultTunnelDNSServer)
  606. }
  607. }
  608. func TestParseDatagramDomainHeader(t *testing.T) {
  609. hdr := []byte{0, 0, 0, 0x03, 4, 'a', 'b', '.', 'd', 0x00, 0x35, 'x'}
  610. name, port, hdrLen, err := parseDatagramDomainHeader(hdr)
  611. if err != nil {
  612. t.Fatal(err)
  613. }
  614. if name != "ab.d" || port != 53 || hdrLen != 11 {
  615. t.Fatalf("name=%q port=%d hdrLen=%d", name, port, hdrLen)
  616. }
  617. truncated := []byte{0, 0, 0, 0x03, 200, 'a'}
  618. if _, _, _, err := parseDatagramDomainHeader(truncated); err == nil {
  619. t.Fatal("truncated domain accepted")
  620. }
  621. empty := []byte{0, 0, 0, 0x03, 0, 0x00, 0x35}
  622. if _, _, _, err := parseDatagramDomainHeader(empty); err == nil {
  623. t.Fatal("empty domain accepted")
  624. }
  625. }
  626. func TestReadSocksRequestTargetKeepsHostnameUnresolved(t *testing.T) {
  627. payload := append([]byte{byte(len("invalid."))}, []byte("invalid.")...)
  628. payload = append(payload, 0x01, 0xbb)
  629. tr, err := readSocksRequestTarget(bytes.NewReader(payload), 0x03)
  630. if err != nil {
  631. t.Fatalf("domain request rejected: %v", err)
  632. }
  633. if tr.host != "invalid." || tr.port != 443 || tr.ip.IsValid() {
  634. t.Fatalf("target = %+v", tr)
  635. }
  636. }
  637. func TestTunnelDNSCache_ScopedPerTagAndServer(t *testing.T) {
  638. resetTunnelDNSCacheForTest()
  639. tagA, tagB := "out-a", "out-b"
  640. dns1, dns2 := "1.1.1.1:53", "8.8.8.8:53"
  641. host := "example.com"
  642. addrA := netip.MustParseAddr("10.0.0.1")
  643. addrB := netip.MustParseAddr("10.0.0.2")
  644. keyA := dnsCacheKey(tagA, dns1, host)
  645. keyB := dnsCacheKey(tagB, dns1, host)
  646. keyA2 := dnsCacheKey(tagA, dns2, host)
  647. tunnelDNSCache.mu.Lock()
  648. tunnelDNSCache.m[keyA] = tunnelDNSCacheEntry{addr: addrA, exp: time.Now().Add(time.Hour)}
  649. tunnelDNSCache.m[keyB] = tunnelDNSCacheEntry{addr: addrB, exp: time.Now().Add(time.Hour)}
  650. tunnelDNSCache.mu.Unlock()
  651. tunnelDNSCache.mu.Lock()
  652. eA, okA := tunnelDNSCache.m[keyA]
  653. eB, okB := tunnelDNSCache.m[keyB]
  654. _, okA2 := tunnelDNSCache.m[keyA2]
  655. tunnelDNSCache.mu.Unlock()
  656. if !okA || eA.addr != addrA {
  657. t.Fatalf("tagA cache entry mismatch: %v, %v", okA, eA)
  658. }
  659. if !okB || eB.addr != addrB {
  660. t.Fatalf("tagB cache entry mismatch: %v, %v", okB, eB)
  661. }
  662. if okA2 {
  663. t.Fatal("key with different DNS server should not match")
  664. }
  665. flushTunnelDNSCacheForTag(tagA)
  666. tunnelDNSCache.mu.Lock()
  667. _, okAAfter := tunnelDNSCache.m[keyA]
  668. _, okBAfter := tunnelDNSCache.m[keyB]
  669. tunnelDNSCache.mu.Unlock()
  670. if okAAfter {
  671. t.Fatal("tagA entry should be flushed")
  672. }
  673. if !okBAfter {
  674. t.Fatal("tagB entry should survive flush of tagA")
  675. }
  676. }