egress.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. package amneziawgnet
  2. import (
  3. "context"
  4. "crypto/hmac"
  5. "encoding/binary"
  6. "fmt"
  7. "io"
  8. "net"
  9. "net/netip"
  10. "sync"
  11. "time"
  12. "gvisor.dev/gvisor/pkg/tcpip"
  13. "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
  14. "github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
  15. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  16. )
  17. // EgressBasePort is the fixed loopback port of the panel's SOCKS5 egress
  18. // server; it appears in every generated amneziawg socks bridge.
  19. const EgressBasePort = 64900
  20. // socks5EgressServer is a minimal loopback SOCKS5 server routing Xray's
  21. // bridged amneziawg outbounds into their embedded devices' netstacks.
  22. type socks5EgressServer struct {
  23. mu sync.Mutex
  24. stacks map[string]*Device // outbound tag -> its device
  25. dns map[string]string // outbound tag -> its DNS server
  26. tracked map[net.Conn]struct{}
  27. // dnsServer resolves domain targets through the outbound netstack.
  28. dnsServer string
  29. listener net.Listener // nil when stopped; acceptLoop takes it as an arg
  30. closing chan struct{} // per-listener lifetime signal, rearmed by Listen
  31. wg sync.WaitGroup
  32. }
  33. var (
  34. egressOnce sync.Once
  35. egressServer *socks5EgressServer
  36. )
  37. // GetEgressServer returns the process-wide SOCKS5 egress server singleton.
  38. func GetEgressServer() *socks5EgressServer {
  39. egressOnce.Do(func() {
  40. egressServer = &socks5EgressServer{
  41. stacks: map[string]*Device{},
  42. dns: map[string]string{},
  43. tracked: map[net.Conn]struct{}{},
  44. }
  45. })
  46. return egressServer
  47. }
  48. // currentDNSServer reads dnsServer under lock -- custom per-tag DNS preferred.
  49. func (s *socks5EgressServer) currentDNSServer(tag ...string) string {
  50. s.mu.Lock()
  51. defer s.mu.Unlock()
  52. if len(tag) > 0 && tag[0] != "" {
  53. if custom, ok := s.dns[tag[0]]; ok && custom != "" {
  54. return custom
  55. }
  56. }
  57. return s.dnsServer
  58. }
  59. // SetDNSServer overrides the domain-target resolver (tests).
  60. func (s *socks5EgressServer) SetDNSServer(addr string) {
  61. s.mu.Lock()
  62. defer s.mu.Unlock()
  63. s.dnsServer = addr
  64. }
  65. // SetStack registers or replaces the device backing an outbound tag.
  66. func (s *socks5EgressServer) SetStack(tag string, dev *Device, dnsServer ...string) {
  67. norm := ""
  68. if len(dnsServer) > 0 && dnsServer[0] != "" {
  69. norm = amneziawg.NormalizeDNSServer(dnsServer[0])
  70. }
  71. s.mu.Lock()
  72. prevDev := s.stacks[tag]
  73. prevDNS := s.dns[tag]
  74. s.stacks[tag] = dev
  75. if norm != "" {
  76. s.dns[tag] = norm
  77. } else {
  78. delete(s.dns, tag)
  79. }
  80. changed := prevDev != dev || prevDNS != norm
  81. s.mu.Unlock()
  82. if changed {
  83. flushTunnelDNSCacheForTag(tag)
  84. }
  85. }
  86. // DeleteStack drops an outbound tag's registration (outbound removed).
  87. func (s *socks5EgressServer) DeleteStack(tag string) {
  88. s.mu.Lock()
  89. delete(s.stacks, tag)
  90. delete(s.dns, tag)
  91. s.mu.Unlock()
  92. flushTunnelDNSCacheForTag(tag)
  93. }
  94. // Listen starts accepting on the loopback listener. Idempotent; a bind
  95. // failure is returned and retried by the caller's reconcile tick.
  96. func (s *socks5EgressServer) Listen() error {
  97. s.mu.Lock()
  98. defer s.mu.Unlock()
  99. if s.listener != nil {
  100. return nil
  101. }
  102. ln, err := (&net.ListenConfig{}).Listen(context.Background(), "tcp", fmt.Sprintf("127.0.0.1:%d", EgressBasePort))
  103. if err != nil {
  104. return fmt.Errorf("amneziawgnet: egress listen: %w", err)
  105. }
  106. s.listener = ln
  107. s.closing = make(chan struct{})
  108. logger.Infof("amneziawgnet: egress socks listening on %s", ln.Addr())
  109. s.wg.Add(1)
  110. go s.acceptLoop(ln, s.closing)
  111. return nil
  112. }
  113. // Close stops the listener and in-flight handlers; signal first so an accept
  114. // error always observes closing.
  115. func (s *socks5EgressServer) Close() {
  116. s.mu.Lock()
  117. ln := s.listener
  118. s.listener = nil
  119. if ln == nil {
  120. s.mu.Unlock()
  121. return
  122. }
  123. close(s.closing)
  124. tracked := s.tracked
  125. s.tracked = map[net.Conn]struct{}{}
  126. s.mu.Unlock()
  127. ln.Close()
  128. for conn := range tracked {
  129. conn.Close()
  130. }
  131. s.wg.Wait()
  132. }
  133. func (s *socks5EgressServer) acceptLoop(ln net.Listener, closing chan struct{}) {
  134. defer s.wg.Done()
  135. for {
  136. conn, err := ln.Accept()
  137. if err != nil {
  138. select {
  139. case <-closing:
  140. return
  141. default:
  142. }
  143. logger.Warningf("amneziawgnet: egress accept: %v", err)
  144. continue
  145. }
  146. select {
  147. case <-closing:
  148. conn.Close()
  149. return
  150. default:
  151. }
  152. s.mu.Lock()
  153. if s.listener == nil {
  154. s.mu.Unlock()
  155. conn.Close()
  156. return
  157. }
  158. s.tracked[conn] = struct{}{}
  159. s.wg.Add(1)
  160. s.mu.Unlock()
  161. go func(c net.Conn) {
  162. defer s.wg.Done()
  163. defer func() {
  164. s.mu.Lock()
  165. delete(s.tracked, c)
  166. s.mu.Unlock()
  167. }()
  168. s.handleConn(c)
  169. }(conn)
  170. }
  171. }
  172. // stackFor resolves a tag to its live device at use time, so rebuilds take
  173. // effect for new connections without touching the listener.
  174. func (s *socks5EgressServer) stackFor(tag string) (*Device, bool) {
  175. s.mu.Lock()
  176. defer s.mu.Unlock()
  177. dev, ok := s.stacks[tag]
  178. return dev, ok
  179. }
  180. func (s *socks5EgressServer) handleConn(conn net.Conn) {
  181. defer conn.Close()
  182. // Bound the pre-auth handshake so a silent client never pins a handler
  183. // indefinitely across Close() and wg.Wait().
  184. _ = conn.SetDeadline(time.Now().Add(portForwardDialTimeout))
  185. method, err := socks5Greeting(conn)
  186. if err != nil || method == 0xFF {
  187. return
  188. }
  189. user := ""
  190. if method == 0x02 {
  191. // RFC 1929 sub-negotiation: VER(1) | ULEN(1) | UNAME | PLEN(1) |
  192. // PASSWD -- the leading 0x01 version byte must be consumed first.
  193. var ver [1]byte
  194. if _, err := io.ReadFull(conn, ver[:]); err != nil {
  195. return
  196. }
  197. var ulen [1]byte
  198. if _, err := io.ReadFull(conn, ulen[:]); err != nil {
  199. return
  200. }
  201. uname := make([]byte, ulen[0])
  202. if _, err := io.ReadFull(conn, uname); err != nil {
  203. return
  204. }
  205. user = string(uname)
  206. var plen [1]byte
  207. if _, err := io.ReadFull(conn, plen[:]); err != nil {
  208. return
  209. }
  210. pass := make([]byte, plen[0])
  211. if _, err := io.ReadFull(conn, pass); err != nil {
  212. return
  213. }
  214. if !hmac.Equal(pass, []byte(SocksPassword())) {
  215. _, _ = conn.Write([]byte{0x01, 0x01})
  216. return
  217. }
  218. if _, err := conn.Write([]byte{0x01, 0x00}); err != nil {
  219. return
  220. }
  221. }
  222. var req [4]byte
  223. if _, err := io.ReadFull(conn, req[:]); err != nil {
  224. return
  225. }
  226. // Handshake complete: clear deadline for the relay phase.
  227. _ = conn.SetDeadline(time.Time{})
  228. target, err := readSocksRequestTarget(conn, req[3])
  229. if err != nil {
  230. writeSocksReply(conn, 0x01, netip.AddrPort{})
  231. return
  232. }
  233. switch req[1] {
  234. case 0x01: // CONNECT
  235. dev, ok := s.stackFor(user)
  236. if !ok {
  237. writeSocksReply(conn, 0x05, netip.AddrPort{})
  238. return
  239. }
  240. dest, err := target.resolveTunnelVia(s.currentDNSServer(user), user, dev)
  241. if err != nil {
  242. logger.Warningf("amneziawgnet: egress %q: resolve %s: %v", user, target, err)
  243. writeSocksReply(conn, 0x04, netip.AddrPort{})
  244. return
  245. }
  246. s.relayTCP(dev, user, conn, dest)
  247. case 0x03: // UDP ASSOCIATE
  248. dev, ok := s.stackFor(user)
  249. if !ok {
  250. writeSocksReply(conn, 0x05, netip.AddrPort{})
  251. return
  252. }
  253. s.relayUDP(dev, user, udpControl{conn: conn}, target)
  254. default:
  255. writeSocksReply(conn, 0x07, netip.AddrPort{})
  256. }
  257. }
  258. // socks5Greeting requires RFC 1929 username/password auth (0x02).
  259. // Returns 0xFF when unauthenticated or unsupported.
  260. func socks5Greeting(conn net.Conn) (byte, error) {
  261. var hdr [2]byte
  262. if _, err := io.ReadFull(conn, hdr[:]); err != nil {
  263. return 0xFF, err
  264. }
  265. methods := make([]byte, hdr[1])
  266. if _, err := io.ReadFull(conn, methods); err != nil {
  267. return 0xFF, err
  268. }
  269. hasUserPass := false
  270. for _, m := range methods {
  271. if m == 0x02 {
  272. hasUserPass = true
  273. break
  274. }
  275. }
  276. if !hasUserPass {
  277. _, _ = conn.Write([]byte{0x05, 0xFF})
  278. return 0xFF, nil
  279. }
  280. if _, err := conn.Write([]byte{0x05, 0x02}); err != nil {
  281. return 0xFF, err
  282. }
  283. return 0x02, nil
  284. }
  285. // socksTarget is a parsed SOCKS5 request address: an IP, or the raw hostname
  286. // for ATYP 0x03 (resolved through the outbound's tunnel, never host-side).
  287. type socksTarget struct {
  288. host string
  289. ip netip.Addr
  290. port uint16
  291. }
  292. func readSocksRequestTarget(r io.Reader, atyp byte) (socksTarget, error) {
  293. var t socksTarget
  294. switch atyp {
  295. case 0x01:
  296. var b [4]byte
  297. if _, err := io.ReadFull(r, b[:]); err != nil {
  298. return t, err
  299. }
  300. t.ip = netip.AddrFrom4(b)
  301. case 0x04:
  302. var b [16]byte
  303. if _, err := io.ReadFull(r, b[:]); err != nil {
  304. return t, err
  305. }
  306. t.ip = netip.AddrFrom16(b)
  307. case 0x03:
  308. var l [1]byte
  309. if _, err := io.ReadFull(r, l[:]); err != nil {
  310. return t, err
  311. }
  312. name := make([]byte, l[0])
  313. if _, err := io.ReadFull(r, name); err != nil {
  314. return t, err
  315. }
  316. t.host = string(name)
  317. default:
  318. return t, fmt.Errorf("unsupported SOCKS5 request address type %d", atyp)
  319. }
  320. var portBytes [2]byte
  321. if _, err := io.ReadFull(r, portBytes[:]); err != nil {
  322. return t, err
  323. }
  324. t.port = binary.BigEndian.Uint16(portBytes[:])
  325. return t, nil
  326. }
  327. func (t socksTarget) String() string {
  328. if t.ip.IsValid() {
  329. return netip.AddrPortFrom(t.ip, t.port).String()
  330. }
  331. return fmt.Sprintf("%s:%d", t.host, t.port)
  332. }
  333. // Domain targets resolve via the tunnel; reply-side helper must not be used here.
  334. func (t socksTarget) resolveTunnelVia(dnsServer, tag string, dev *Device) (netip.AddrPort, error) {
  335. if t.ip.IsValid() {
  336. if !tunnelSupportsAddr(dev.LocalAddresses(), t.ip) {
  337. return netip.AddrPort{}, fmt.Errorf("tunnel has no route for %s (device addresses %v)", t.ip, dev.LocalAddresses())
  338. }
  339. return netip.AddrPortFrom(t.ip, t.port), nil
  340. }
  341. ctx, cancel := context.WithTimeout(context.Background(), tunnelResolveTimeout)
  342. defer cancel()
  343. addr, err := resolveTunnelVia(ctx, dev, tag, dnsServer, t.host)
  344. if err != nil {
  345. return netip.AddrPort{}, err
  346. }
  347. return netip.AddrPortFrom(addr, t.port), nil
  348. }
  349. // writeSocksReply emits a reply with an empty v4 bind address; Xray only
  350. // reads the code byte.
  351. func writeSocksReply(w io.Writer, code byte, _ netip.AddrPort) {
  352. out := []byte{0x05, code, 0x00, 0x01, 0, 0, 0, 0, 0, 0}
  353. _, _ = w.Write(out)
  354. }
  355. // relayTCP dials dest inside the tagged outbound's netstack and pipes both
  356. // directions until either side closes.
  357. func (s *socks5EgressServer) relayTCP(dev *Device, tag string, upstream net.Conn, dest netip.AddrPort) {
  358. fa := tcpip.FullAddress{
  359. NIC: 1,
  360. Addr: tcpip.AddrFromSlice(dest.Addr().AsSlice()),
  361. Port: dest.Port(),
  362. }
  363. // Bound dial with portForwardDialTimeout so unreachable peers do not
  364. // pin goroutines and netstack endpoints in s.tracked.
  365. dctx, dcancel := context.WithTimeout(context.Background(), portForwardDialTimeout)
  366. defer dcancel()
  367. tunnelConn, err := gonet.DialContextTCP(dctx, dev.Stack, fa, tunnelNetwork(dest.Addr()))
  368. if err != nil {
  369. logger.Warningf("amneziawgnet: egress %q: dial tunnel %s: %v", tag, dest, err)
  370. writeSocksReply(upstream, 0x01, netip.AddrPort{})
  371. return
  372. }
  373. defer tunnelConn.Close()
  374. if _, err := upstream.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0}); err != nil {
  375. return
  376. }
  377. done := make(chan struct{}, 2)
  378. go func() { _, _ = io.Copy(tunnelConn, upstream); done <- struct{}{} }()
  379. go func() { _, _ = io.Copy(upstream, tunnelConn); done <- struct{}{} }()
  380. <-done
  381. }
  382. // udpControl is the control half of one UDP ASSOCIATE: the TCP connection
  383. // whose lifetime bounds the association (RFC 1928).
  384. type udpControl struct{ conn net.Conn }
  385. // egressUDPSession is one UDP ASSOCIATE flow: host-facing socket plus a
  386. // connected tunnel endpoint whose source port makes replies answerable.
  387. type egressUDPSession struct {
  388. dst netip.AddrPort
  389. conn *gonet.UDPConn
  390. }
  391. // relayUDP answers the associate request and relays datagrams to
  392. // per-destination tunnel endpoints until the control connection closes.
  393. func (s *socks5EgressServer) relayUDP(dev *Device, tag string, ctl udpControl, _ socksTarget) {
  394. udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
  395. if err != nil {
  396. logger.Warningf("amneziawgnet: egress %q: udp bind: %v", tag, err)
  397. writeSocksReply(ctl.conn, 0x01, netip.AddrPort{})
  398. return
  399. }
  400. defer udpConn.Close()
  401. local := udpConn.LocalAddr().(*net.UDPAddr)
  402. ip4 := local.IP.To4()
  403. reply := []byte{
  404. 0x05, 0x00, 0x00, 0x01, ip4[0], ip4[1], ip4[2], ip4[3],
  405. byte(local.Port >> 8), byte(local.Port),
  406. }
  407. if _, err := ctl.conn.Write(reply); err != nil {
  408. return
  409. }
  410. sessions := &udpEgressSessions{m: map[netip.AddrPort]*egressUDPSession{}}
  411. // Reader: strip per-datagram SOCKS5 headers and forward into the tunnel;
  412. // only the associated client's address is accepted.
  413. go func() {
  414. var client netip.AddrPort
  415. buf := make([]byte, 65536)
  416. for {
  417. n, from, err := udpConn.ReadFrom(buf)
  418. if err != nil {
  419. return
  420. }
  421. if src, ok := udpAddrPort(from); ok {
  422. if client.IsValid() && src != client {
  423. continue // RFC 1928: only the associated client may send
  424. }
  425. client = src
  426. }
  427. data := buf[:n]
  428. if len(data) < 4 {
  429. continue
  430. }
  431. atyp := data[3]
  432. var dst netip.AddrPort
  433. var payloadOff int
  434. if atyp == 0x03 {
  435. name, port, hdrLen, perr := parseDatagramDomainHeader(data)
  436. if perr != nil {
  437. continue
  438. }
  439. // Resolve off reader loop so slow tunnel DNS lookups do not
  440. // stall other destinations on this association.
  441. go func(client netip.AddrPort, name string, port uint16, hdrLen int, datagram []byte) {
  442. dnsSrv := s.currentDNSServer(tag)
  443. rctx, rcancel := context.WithTimeout(context.Background(), tunnelResolveTimeout)
  444. daddr, rerr := resolveTunnelVia(rctx, dev, tag, dnsSrv, name)
  445. rcancel()
  446. if rerr != nil {
  447. logger.Warningf("amneziawgnet: egress %q: resolve udp %q (dns=%s): %v", tag, name, dnsSrv, rerr)
  448. return
  449. }
  450. s.deliverUDPDatagram(dev, tag, udpConn, client, sessions, netip.AddrPortFrom(daddr, port), datagram[hdrLen:])
  451. }(client, name, port, hdrLen, append([]byte(nil), data...))
  452. continue
  453. } else {
  454. hdrLen := 4 + addrLen(atyp) + 2
  455. if hdrLen <= 6 || len(data) < hdrLen {
  456. continue
  457. }
  458. d, derr := parseDatagramHeader(data[:hdrLen])
  459. if derr != nil {
  460. logger.Warningf("amneziawgnet: egress %q: udp header: %v", tag, derr)
  461. continue
  462. }
  463. dst = d
  464. payloadOff = hdrLen
  465. }
  466. s.deliverUDPDatagram(dev, tag, udpConn, client, sessions, dst, data[payloadOff:])
  467. }
  468. }()
  469. // Control-conn close tears down relaying -- relay.go UDPRelay contract.
  470. buf := make([]byte, 512)
  471. for {
  472. if _, err := ctl.conn.Read(buf); err != nil {
  473. sessions.closeAll()
  474. return
  475. }
  476. }
  477. }
  478. // udpEgressSessions guards the association's session map: the reader
  479. // goroutine inserts while the control-conn teardown iterates.
  480. type udpEgressSessions struct {
  481. mu sync.Mutex
  482. m map[netip.AddrPort]*egressUDPSession
  483. }
  484. func (s *udpEgressSessions) getOrDial(dev *Device, tag string, udpConn *net.UDPConn, client netip.AddrPort, dst netip.AddrPort) *egressUDPSession {
  485. s.mu.Lock()
  486. defer s.mu.Unlock()
  487. if sess, ok := s.m[dst]; ok {
  488. return sess
  489. }
  490. if !tunnelSupportsAddr(dev.LocalAddresses(), dst.Addr()) {
  491. logger.Warningf("amneziawgnet: egress %q: dial udp %s: tunnel has no route for address family (device addresses %v)", tag, dst, dev.LocalAddresses())
  492. return nil
  493. }
  494. raddr := tcpip.FullAddress{
  495. NIC: 1,
  496. Addr: tcpip.AddrFromSlice(dst.Addr().AsSlice()),
  497. Port: dst.Port(),
  498. }
  499. conn, err := gonet.DialUDP(dev.Stack, nil, &raddr, tunnelNetwork(dst.Addr()))
  500. if err != nil {
  501. logger.Warningf("amneziawgnet: egress %q: dial udp %s: %v", tag, dst, err)
  502. return nil
  503. }
  504. sess := &egressUDPSession{dst: dst, conn: conn}
  505. s.m[dst] = sess
  506. go pumpUDPEgress(udpConn, client, sess, s)
  507. return sess
  508. }
  509. func (s *udpEgressSessions) closeAll() {
  510. s.mu.Lock()
  511. defer s.mu.Unlock()
  512. for _, sess := range s.m {
  513. sess.conn.Close()
  514. }
  515. }
  516. // deliverUDPDatagram forwards one payload to dst through the tunnel endpoint.
  517. // Safe for concurrent use across resolver and direct-path goroutines.
  518. func (s *socks5EgressServer) deliverUDPDatagram(dev *Device, tag string, udpConn *net.UDPConn, client netip.AddrPort, sessions *udpEgressSessions, dst netip.AddrPort, payload []byte) {
  519. if !client.IsValid() {
  520. return // nothing to reply to yet
  521. }
  522. sess := sessions.getOrDial(dev, tag, udpConn, client, dst)
  523. if sess == nil {
  524. return
  525. }
  526. if _, werr := sess.conn.Write(payload); werr != nil {
  527. logger.Warningf("amneziawgnet: egress %q: send udp to %s: %v", tag, dst, werr)
  528. }
  529. }
  530. // pumpUDPEgress reads replies from one connected tunnel endpoint and writes
  531. // them back to the associated client as SOCKS5 UDP datagrams.
  532. func pumpUDPEgress(udpConn *net.UDPConn, client netip.AddrPort, sess *egressUDPSession, sessions *udpEgressSessions) {
  533. defer func() {
  534. sessions.mu.Lock()
  535. delete(sessions.m, sess.dst)
  536. sessions.mu.Unlock()
  537. sess.conn.Close()
  538. }()
  539. buf := make([]byte, 65536)
  540. for {
  541. // Reap idle egress sessions to avoid holding them indefinitely.
  542. _ = sess.conn.SetReadDeadline(time.Now().Add(portForwardUDPIdleTimeout))
  543. n, err := sess.conn.Read(buf)
  544. if err != nil {
  545. return
  546. }
  547. hdr := make([]byte, 0, 3+1+16+2+n)
  548. hdr = append(hdr, 0x00, 0x00, 0x00) // RSV RSV FRAG(=0)
  549. if sess.dst.Addr().Is4() {
  550. b := sess.dst.Addr().As4()
  551. hdr = append(hdr, 0x01)
  552. hdr = append(hdr, b[:]...)
  553. } else {
  554. b := sess.dst.Addr().As16()
  555. hdr = append(hdr, 0x04)
  556. hdr = append(hdr, b[:]...)
  557. }
  558. var portBytes [2]byte
  559. binary.BigEndian.PutUint16(portBytes[:], sess.dst.Port())
  560. hdr = append(hdr, portBytes[:]...)
  561. hdr = append(hdr, buf[:n]...)
  562. if _, err := udpConn.WriteTo(hdr, net.UDPAddrFromAddrPort(client)); err != nil {
  563. return
  564. }
  565. }
  566. }
  567. // parseDatagramDomainHeader decodes a domain SOCKS5 UDP header (RSV RSV FRAG
  568. // 0x03 LEN NAME PORT) into name, port, and header length.
  569. func parseDatagramDomainHeader(data []byte) (name string, port uint16, hdrLen int, err error) {
  570. if len(data) < 5 {
  571. return "", 0, 0, fmt.Errorf("short domain header")
  572. }
  573. l := int(data[4])
  574. hdrLen = 4 + 1 + l + 2
  575. if l == 0 || len(data) < hdrLen {
  576. return "", 0, 0, fmt.Errorf("short domain payload")
  577. }
  578. name = string(data[5 : 5+l])
  579. port = binary.BigEndian.Uint16(data[5+l : 7+l])
  580. return name, port, hdrLen, nil
  581. }
  582. // addrLen returns the wire length of a SOCKS5 address of the given ATYP.
  583. func addrLen(atyp byte) int {
  584. switch atyp {
  585. case 0x01:
  586. return 4
  587. case 0x04:
  588. return 16
  589. default:
  590. return -1
  591. }
  592. }
  593. // parseDatagramHeader decodes the destination from the front of a SOCKS5 UDP
  594. // datagram header block (RSV RSV FRAG ATYP ADDR PORT).
  595. func parseDatagramHeader(hdr []byte) (netip.AddrPort, error) {
  596. if len(hdr) < 4 {
  597. return netip.AddrPort{}, fmt.Errorf("short header")
  598. }
  599. atyp := hdr[3]
  600. body := hdr[4:]
  601. switch atyp {
  602. case 0x01:
  603. if len(body) < 6 {
  604. return netip.AddrPort{}, fmt.Errorf("short v4")
  605. }
  606. return netip.AddrPortFrom(netip.AddrFrom4([4]byte(body[:4])), binary.BigEndian.Uint16(body[4:6])), nil
  607. case 0x04:
  608. if len(body) < 18 {
  609. return netip.AddrPort{}, fmt.Errorf("short v6")
  610. }
  611. return netip.AddrPortFrom(netip.AddrFrom16([16]byte(body[:16])), binary.BigEndian.Uint16(body[16:18])), nil
  612. default:
  613. return netip.AddrPort{}, fmt.Errorf("unsupported atyp %d", atyp)
  614. }
  615. }