1
0

socks_bridge.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. package tuic
  2. import (
  3. "context"
  4. "crypto/rand"
  5. "encoding/base64"
  6. "encoding/binary"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "net"
  12. "net/netip"
  13. "sync"
  14. "sync/atomic"
  15. "time"
  16. )
  17. var ErrUdpPayloadTooLarge = errors.New("tuic socks: UDP packet exceeds the maximum SOCKS datagram size")
  18. const maxSocksUdpDatagramSize = 65507
  19. // SocksRelay describes the loopback SOCKS5 endpoint where decrypted TUIC traffic is forwarded.
  20. type SocksRelay struct {
  21. Addr string // e.g. "127.0.0.1:63201"
  22. Password string // internal shared password for the SOCKS inbound
  23. }
  24. // CountingConn wraps a net.Conn and tracks bytes read and written atomically.
  25. type CountingConn struct {
  26. net.Conn
  27. bytesRead *atomic.Int64
  28. bytesWritten *atomic.Int64
  29. }
  30. func (c *CountingConn) Read(p []byte) (int, error) {
  31. n, err := c.Conn.Read(p)
  32. if n > 0 && c.bytesRead != nil {
  33. c.bytesRead.Add(int64(n))
  34. }
  35. return n, err
  36. }
  37. func (c *CountingConn) Write(p []byte) (int, error) {
  38. n, err := c.Conn.Write(p)
  39. if n > 0 && c.bytesWritten != nil {
  40. c.bytesWritten.Add(int64(n))
  41. }
  42. return n, err
  43. }
  44. // DialTCP establishes a SOCKS5 CONNECT tunnel to the target address on behalf of user.
  45. func (r *SocksRelay) DialTCP(ctx context.Context, user string, target *Address) (net.Conn, error) {
  46. dialer := net.Dialer{Timeout: 10 * time.Second}
  47. conn, err := dialer.DialContext(ctx, "tcp", r.Addr)
  48. if err != nil {
  49. return nil, fmt.Errorf("tuic socks: dial relay %s: %w", r.Addr, err)
  50. }
  51. _ = conn.SetDeadline(time.Now().Add(10 * time.Second))
  52. if err := socks5Handshake(conn, user, r.Password); err != nil {
  53. conn.Close()
  54. return nil, err
  55. }
  56. // Send SOCKS5 CONNECT request
  57. req := buildSocks5ConnectRequest(target)
  58. if req == nil {
  59. conn.Close()
  60. return nil, ErrInvalidAddr
  61. }
  62. if _, err := conn.Write(req); err != nil {
  63. conn.Close()
  64. return nil, fmt.Errorf("tuic socks: send CONNECT request: %w", err)
  65. }
  66. if _, err := readSocks5Reply(conn); err != nil {
  67. conn.Close()
  68. return nil, err
  69. }
  70. _ = conn.SetDeadline(time.Time{})
  71. return conn, nil
  72. }
  73. func buildSocks5ConnectRequest(target *Address) []byte {
  74. if target == nil {
  75. return nil
  76. }
  77. var req []byte
  78. switch target.Type {
  79. case AddrTypeIPv4:
  80. ip4 := target.IP.To4()
  81. if len(ip4) != 4 {
  82. return nil
  83. }
  84. req = make([]byte, 4+4+2)
  85. req[0] = 0x05 // SOCKS5
  86. req[1] = 0x01 // CONNECT
  87. req[2] = 0x00 // RSV
  88. req[3] = 0x01 // ATYP IPv4
  89. copy(req[4:8], ip4)
  90. binary.BigEndian.PutUint16(req[8:10], target.Port)
  91. case AddrTypeIPv6:
  92. ip16 := target.IP.To16()
  93. if len(ip16) != 16 {
  94. return nil
  95. }
  96. req = make([]byte, 4+16+2)
  97. req[0] = 0x05
  98. req[1] = 0x01
  99. req[2] = 0x00
  100. req[3] = 0x04 // ATYP IPv6
  101. copy(req[4:20], ip16)
  102. binary.BigEndian.PutUint16(req[20:22], target.Port)
  103. case AddrTypeDomain:
  104. dLen := len(target.Host)
  105. if dLen == 0 || dLen > 255 {
  106. return nil
  107. }
  108. req = make([]byte, 4+1+dLen+2)
  109. req[0] = 0x05
  110. req[1] = 0x01
  111. req[2] = 0x00
  112. req[3] = 0x03 // ATYP Domain
  113. req[4] = byte(dLen)
  114. copy(req[5:5+dLen], []byte(target.Host))
  115. binary.BigEndian.PutUint16(req[5+dLen:7+dLen], target.Port)
  116. default:
  117. return nil
  118. }
  119. return req
  120. }
  121. // SocksUDPSession manages a SOCKS5 UDP ASSOCIATE tunnel to Xray.
  122. type SocksUDPSession struct {
  123. ctrl net.Conn
  124. udpConn *net.UDPConn
  125. targetEP net.Addr
  126. user string
  127. closed atomic.Bool
  128. }
  129. // DialUDP establishes a SOCKS5 UDP ASSOCIATE tunnel to Xray.
  130. func (r *SocksRelay) DialUDP(ctx context.Context, user string) (*SocksUDPSession, error) {
  131. dialer := net.Dialer{Timeout: 10 * time.Second}
  132. ctrl, err := dialer.DialContext(ctx, "tcp", r.Addr)
  133. if err != nil {
  134. return nil, fmt.Errorf("tuic socks: dial UDP control connection: %w", err)
  135. }
  136. _ = ctrl.SetDeadline(time.Now().Add(10 * time.Second))
  137. if err := socks5Handshake(ctrl, user, r.Password); err != nil {
  138. ctrl.Close()
  139. return nil, err
  140. }
  141. // SOCKS5 UDP ASSOCIATE (0x03), dst 0.0.0.0:0
  142. if _, err := ctrl.Write([]byte{0x05, 0x03, 0x00, 0x01, 0, 0, 0, 0, 0, 0}); err != nil {
  143. ctrl.Close()
  144. return nil, fmt.Errorf("tuic socks: send UDP ASSOCIATE request: %w", err)
  145. }
  146. bind, err := readSocks5Reply(ctrl)
  147. if err != nil {
  148. ctrl.Close()
  149. return nil, err
  150. }
  151. _ = ctrl.SetDeadline(time.Time{})
  152. udpConn, err := net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(bind))
  153. if err != nil {
  154. ctrl.Close()
  155. return nil, fmt.Errorf("tuic socks: dial UDP relay endpoint %s: %w", bind, err)
  156. }
  157. return &SocksUDPSession{
  158. ctrl: ctrl,
  159. udpConn: udpConn,
  160. targetEP: udpConn.RemoteAddr(),
  161. user: user,
  162. }, nil
  163. }
  164. // Send sends a UDP payload to target via the SOCKS5 UDP ASSOCIATE relay.
  165. func (s *SocksUDPSession) Send(target *Address, payload []byte) (int, error) {
  166. if s.closed.Load() {
  167. return 0, net.ErrClosed
  168. }
  169. packet, err := buildSocks5UDPRequest(target, payload)
  170. if err != nil {
  171. return 0, err
  172. }
  173. return s.udpConn.Write(packet)
  174. }
  175. func buildSocks5UDPRequest(target *Address, payload []byte) ([]byte, error) {
  176. hdr := buildSocks5UDPHeader(target)
  177. if hdr == nil {
  178. return nil, ErrInvalidAddr
  179. }
  180. if len(hdr)+len(payload) > maxSocksUdpDatagramSize {
  181. return nil, ErrUdpPayloadTooLarge
  182. }
  183. packet := make([]byte, len(hdr)+len(payload))
  184. copy(packet, hdr)
  185. copy(packet[len(hdr):], payload)
  186. return packet, nil
  187. }
  188. // Receive reads a relayed UDP payload and extracts its original source address.
  189. func (s *SocksUDPSession) Receive(buf []byte) (*Address, []byte, error) {
  190. if s.closed.Load() {
  191. return nil, nil, net.ErrClosed
  192. }
  193. n, err := s.udpConn.Read(buf)
  194. if err != nil {
  195. return nil, nil, err
  196. }
  197. if n < 4 {
  198. return nil, nil, fmt.Errorf("tuic socks: UDP packet too short (%d bytes)", n)
  199. }
  200. // SOCKS5 UDP header: [RSV(2)][FRAG(1)][ATYP(1)]
  201. atyp := buf[3]
  202. var addr *Address
  203. var offset int
  204. switch atyp {
  205. case 0x01: // IPv4
  206. if n < 10 {
  207. return nil, nil, fmt.Errorf("tuic socks: truncated IPv4 UDP reply")
  208. }
  209. ip := net.IP(buf[4:8])
  210. port := binary.BigEndian.Uint16(buf[8:10])
  211. addr = &Address{Type: AddrTypeIPv4, IP: ip, Host: ip.String(), Port: port}
  212. offset = 10
  213. case 0x04: // IPv6
  214. if n < 22 {
  215. return nil, nil, fmt.Errorf("tuic socks: truncated IPv6 UDP reply")
  216. }
  217. ip := net.IP(buf[4:20])
  218. port := binary.BigEndian.Uint16(buf[20:22])
  219. addr = &Address{Type: AddrTypeIPv6, IP: ip, Host: ip.String(), Port: port}
  220. offset = 22
  221. case 0x03: // Domain
  222. dLen := int(buf[4])
  223. if n < 5+dLen+2 {
  224. return nil, nil, fmt.Errorf("tuic socks: truncated domain UDP reply")
  225. }
  226. host := string(buf[5 : 5+dLen])
  227. port := binary.BigEndian.Uint16(buf[5+dLen : 7+dLen])
  228. addr = &Address{Type: AddrTypeDomain, Host: host, Port: port}
  229. offset = 7 + dLen
  230. default:
  231. return nil, nil, fmt.Errorf("tuic socks: unsupported reply ATYP 0x%02x", atyp)
  232. }
  233. return addr, buf[offset:n], nil
  234. }
  235. // Close closes the SOCKS5 UDP session.
  236. func (s *SocksUDPSession) Close() error {
  237. if s.closed.Swap(true) {
  238. return nil
  239. }
  240. _ = s.udpConn.Close()
  241. return s.ctrl.Close()
  242. }
  243. func buildSocks5UDPHeader(target *Address) []byte {
  244. if target == nil {
  245. return nil
  246. }
  247. var hdr []byte
  248. switch target.Type {
  249. case AddrTypeIPv4:
  250. ip4 := target.IP.To4()
  251. if len(ip4) != 4 {
  252. return nil
  253. }
  254. hdr = make([]byte, 10)
  255. hdr[0] = 0x00 // RSV
  256. hdr[1] = 0x00 // RSV
  257. hdr[2] = 0x00 // FRAG
  258. hdr[3] = 0x01 // ATYP IPv4
  259. copy(hdr[4:8], ip4)
  260. binary.BigEndian.PutUint16(hdr[8:10], target.Port)
  261. case AddrTypeIPv6:
  262. ip16 := target.IP.To16()
  263. if len(ip16) != 16 {
  264. return nil
  265. }
  266. hdr = make([]byte, 22)
  267. hdr[0] = 0x00
  268. hdr[1] = 0x00
  269. hdr[2] = 0x00
  270. hdr[3] = 0x04 // ATYP IPv6
  271. copy(hdr[4:20], ip16)
  272. binary.BigEndian.PutUint16(hdr[20:22], target.Port)
  273. case AddrTypeDomain:
  274. dLen := len(target.Host)
  275. if dLen == 0 || dLen > 255 {
  276. return nil
  277. }
  278. hdr = make([]byte, 4+1+dLen+2)
  279. hdr[0] = 0x00
  280. hdr[1] = 0x00
  281. hdr[2] = 0x00
  282. hdr[3] = 0x03 // ATYP Domain
  283. hdr[4] = byte(dLen)
  284. copy(hdr[5:5+dLen], []byte(target.Host))
  285. binary.BigEndian.PutUint16(hdr[5+dLen:7+dLen], target.Port)
  286. default:
  287. return nil
  288. }
  289. return hdr
  290. }
  291. func socks5Handshake(conn net.Conn, user, password string) error {
  292. if _, err := conn.Write([]byte{0x05, 0x02, 0x00, 0x02}); err != nil {
  293. return fmt.Errorf("tuic socks: send greeting: %w", err)
  294. }
  295. var resp [2]byte
  296. if _, err := io.ReadFull(conn, resp[:]); err != nil {
  297. return fmt.Errorf("tuic socks: read greeting reply: %w", err)
  298. }
  299. if resp[0] != 0x05 {
  300. return fmt.Errorf("tuic socks: unexpected SOCKS version %d", resp[0])
  301. }
  302. switch resp[1] {
  303. case 0x00: // no auth
  304. return nil
  305. case 0x02: // username/password
  306. req := make([]byte, 0, 3+len(user)+len(password))
  307. req = append(req, 0x01, byte(len(user)))
  308. req = append(req, user...)
  309. req = append(req, byte(len(password)))
  310. req = append(req, password...)
  311. if _, err := conn.Write(req); err != nil {
  312. return fmt.Errorf("tuic socks: send auth: %w", err)
  313. }
  314. var authResp [2]byte
  315. if _, err := io.ReadFull(conn, authResp[:]); err != nil {
  316. return fmt.Errorf("tuic socks: read auth reply: %w", err)
  317. }
  318. if authResp[1] != 0x00 {
  319. return fmt.Errorf("tuic socks: auth rejected (code %d)", authResp[1])
  320. }
  321. return nil
  322. default:
  323. return fmt.Errorf("tuic socks: unsupported auth method %d", resp[1])
  324. }
  325. }
  326. func readSocks5Reply(r io.Reader) (netip.AddrPort, error) {
  327. var hdr [4]byte
  328. if _, err := io.ReadFull(r, hdr[:]); err != nil {
  329. return netip.AddrPort{}, fmt.Errorf("tuic socks: read reply header: %w", err)
  330. }
  331. if hdr[0] != 0x05 {
  332. return netip.AddrPort{}, fmt.Errorf("tuic socks: unexpected SOCKS version %d", hdr[0])
  333. }
  334. if hdr[1] != 0x00 {
  335. return netip.AddrPort{}, fmt.Errorf("tuic socks: request rejected (code %d)", hdr[1])
  336. }
  337. addr, err := readSocks5Addr(r, hdr[3])
  338. if err != nil {
  339. return netip.AddrPort{}, err
  340. }
  341. var portBytes [2]byte
  342. if _, err := io.ReadFull(r, portBytes[:]); err != nil {
  343. return netip.AddrPort{}, fmt.Errorf("tuic socks: read reply port: %w", err)
  344. }
  345. return netip.AddrPortFrom(addr, binary.BigEndian.Uint16(portBytes[:])), nil
  346. }
  347. func readSocks5Addr(r io.Reader, atyp byte) (netip.Addr, error) {
  348. switch atyp {
  349. case 0x01:
  350. var b [4]byte
  351. if _, err := io.ReadFull(r, b[:]); err != nil {
  352. return netip.Addr{}, err
  353. }
  354. return netip.AddrFrom4(b), nil
  355. case 0x04:
  356. var b [16]byte
  357. if _, err := io.ReadFull(r, b[:]); err != nil {
  358. return netip.Addr{}, err
  359. }
  360. return netip.AddrFrom16(b), nil
  361. case 0x03:
  362. var l [1]byte
  363. if _, err := io.ReadFull(r, l[:]); err != nil {
  364. return netip.Addr{}, err
  365. }
  366. name := make([]byte, l[0])
  367. if _, err := io.ReadFull(r, name); err != nil {
  368. return netip.Addr{}, err
  369. }
  370. resolved, err := net.ResolveIPAddr("ip", string(name))
  371. if err != nil {
  372. return netip.Addr{}, fmt.Errorf("tuic socks: resolve domain reply %q: %w", name, err)
  373. }
  374. addr, ok := netip.AddrFromSlice(resolved.IP)
  375. if !ok {
  376. return netip.Addr{}, fmt.Errorf("tuic socks: unparseable domain reply address")
  377. }
  378. return addr, nil
  379. default:
  380. return netip.Addr{}, fmt.Errorf("tuic socks: unsupported SOCKS5 address type %d", atyp)
  381. }
  382. }
  383. // halfCloseIdle bounds how long the surviving direction of a half-closed pair
  384. // may sit idle, so a peer that vanished mid-transfer cannot pin it forever.
  385. const halfCloseIdle = 2 * time.Minute
  386. type closeWriter interface {
  387. CloseWrite() error
  388. }
  389. type readDeadliner interface {
  390. SetReadDeadline(t time.Time) error
  391. }
  392. type guardedReader struct {
  393. r io.Reader
  394. dl readDeadliner
  395. armed atomic.Bool
  396. }
  397. func newGuardedReader(r io.Reader) *guardedReader {
  398. gr := &guardedReader{r: r}
  399. if dl, ok := r.(readDeadliner); ok {
  400. gr.dl = dl
  401. }
  402. return gr
  403. }
  404. func (g *guardedReader) Read(p []byte) (int, error) {
  405. if g.armed.Load() && g.dl != nil {
  406. _ = g.dl.SetReadDeadline(time.Now().Add(halfCloseIdle))
  407. }
  408. return g.r.Read(p)
  409. }
  410. func (g *guardedReader) arm() {
  411. g.armed.Store(true)
  412. if g.dl != nil {
  413. _ = g.dl.SetReadDeadline(time.Now().Add(halfCloseIdle))
  414. }
  415. }
  416. // PipeBiDirectional pipes data between two connections and tracks byte counts in each direction.
  417. func PipeBiDirectional(a, b io.ReadWriteCloser, upCounter, downCounter *atomic.Int64) {
  418. PipeBiDirectionalContext(context.Background(), a, b, upCounter, downCounter)
  419. }
  420. func PipeBiDirectionalContext(ctx context.Context, a, b io.ReadWriteCloser, upCounter, downCounter *atomic.Int64) {
  421. closeBoth := func() { _ = a.Close(); _ = b.Close() }
  422. stop := context.AfterFunc(ctx, closeBoth)
  423. defer stop()
  424. ga := newGuardedReader(a)
  425. gb := newGuardedReader(b)
  426. var wg sync.WaitGroup
  427. wg.Add(2)
  428. pipe := func(dst io.Writer, dstGuard *guardedReader, src *guardedReader, counter *atomic.Int64) {
  429. defer wg.Done()
  430. buf := make([]byte, 32*1024)
  431. for {
  432. n, err := src.Read(buf)
  433. if n > 0 {
  434. if counter != nil {
  435. counter.Add(int64(n))
  436. }
  437. if _, werr := dst.Write(buf[:n]); werr != nil {
  438. closeBoth()
  439. break
  440. }
  441. }
  442. if err != nil {
  443. if !errors.Is(err, io.EOF) {
  444. closeBoth()
  445. }
  446. break
  447. }
  448. }
  449. if cw, ok := dst.(closeWriter); ok {
  450. _ = cw.CloseWrite()
  451. } else if closer, ok := dst.(io.Closer); ok {
  452. _ = closer.Close()
  453. }
  454. dstGuard.arm()
  455. }
  456. // a -> b (upload: client to upstream)
  457. go pipe(b, gb, ga, upCounter)
  458. // b -> a (download: upstream to client)
  459. go pipe(a, ga, gb, downCounter)
  460. wg.Wait()
  461. _ = a.Close()
  462. _ = b.Close()
  463. }
  464. // SOCKSBasePort is the first loopback port used for a TUIC inbound's
  465. // internal Xray SOCKS5 relay inbound.
  466. const SOCKSBasePort = 64000
  467. // relayPortSlots is how many ids fit in the TUIC relay port window (64001..65000).
  468. const relayPortSlots = 1000
  469. // SOCKSPortForInbound derives one inbound's loopback SOCKS5 relay port from
  470. // its id, bounded within the dedicated range 64001..65000 so it never collides
  471. // with AmneziaWG (65101..65535), API (62789), or node egress (62800..63800).
  472. func SOCKSPortForInbound(inboundID int) int {
  473. if inboundID <= 0 {
  474. return SOCKSBasePort + 1
  475. }
  476. return SOCKSBasePort + 1 + (inboundID-1)%relayPortSlots
  477. }
  478. var (
  479. socksPasswordOnce sync.Once
  480. socksPassword string
  481. )
  482. // SocksPassword returns the process-wide password used to authenticate into
  483. // every TUIC SOCKS5 relay inbound.
  484. func SocksPassword() string {
  485. socksPasswordOnce.Do(func() {
  486. var b [24]byte
  487. if _, err := rand.Read(b[:]); err != nil {
  488. socksPassword = fmt.Sprintf("tuic-fallback-%x", b)
  489. return
  490. }
  491. socksPassword = base64.RawURLEncoding.EncodeToString(b[:])
  492. })
  493. return socksPassword
  494. }
  495. // SocksInboundSettings builds the JSON `settings` block for a stock Xray
  496. // SOCKS5 inbound with one username/password account per email, all sharing
  497. // password. UDP is enabled for UDP ASSOCIATE proxying.
  498. func SocksInboundSettings(emails []string, password string) ([]byte, error) {
  499. type account struct {
  500. User string `json:"user"`
  501. Pass string `json:"pass"`
  502. }
  503. settings := struct {
  504. Auth string `json:"auth"`
  505. UDP bool `json:"udp"`
  506. Accounts []account `json:"accounts"`
  507. }{Auth: "password", UDP: true}
  508. for _, email := range emails {
  509. settings.Accounts = append(settings.Accounts, account{User: email, Pass: password})
  510. }
  511. return json.Marshal(settings)
  512. }