proxy.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. // Package proxy contains all proxies used by Xray.
  2. //
  3. // To implement an inbound or outbound proxy, one needs to do the following:
  4. // 1. Implement the interface(s) below.
  5. // 2. Register a config creator through common.RegisterConfig.
  6. package proxy
  7. import (
  8. "bytes"
  9. "context"
  10. "crypto/rand"
  11. "io"
  12. "math/big"
  13. "runtime"
  14. "strconv"
  15. "time"
  16. "github.com/pires/go-proxyproto"
  17. "github.com/xtls/xray-core/app/dispatcher"
  18. "github.com/xtls/xray-core/common/buf"
  19. "github.com/xtls/xray-core/common/errors"
  20. "github.com/xtls/xray-core/common/net"
  21. "github.com/xtls/xray-core/common/protocol"
  22. "github.com/xtls/xray-core/common/session"
  23. "github.com/xtls/xray-core/common/signal"
  24. "github.com/xtls/xray-core/features/routing"
  25. "github.com/xtls/xray-core/features/stats"
  26. "github.com/xtls/xray-core/transport"
  27. "github.com/xtls/xray-core/transport/internet"
  28. "github.com/xtls/xray-core/transport/internet/reality"
  29. "github.com/xtls/xray-core/transport/internet/stat"
  30. "github.com/xtls/xray-core/transport/internet/tls"
  31. )
  32. var (
  33. Tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04}
  34. TlsClientHandShakeStart = []byte{0x16, 0x03}
  35. TlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
  36. TlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
  37. Tls13CipherSuiteDic = map[uint16]string{
  38. 0x1301: "TLS_AES_128_GCM_SHA256",
  39. 0x1302: "TLS_AES_256_GCM_SHA384",
  40. 0x1303: "TLS_CHACHA20_POLY1305_SHA256",
  41. 0x1304: "TLS_AES_128_CCM_SHA256",
  42. 0x1305: "TLS_AES_128_CCM_8_SHA256",
  43. }
  44. )
  45. const (
  46. TlsHandshakeTypeClientHello byte = 0x01
  47. TlsHandshakeTypeServerHello byte = 0x02
  48. CommandPaddingContinue byte = 0x00
  49. CommandPaddingEnd byte = 0x01
  50. CommandPaddingDirect byte = 0x02
  51. )
  52. // An Inbound processes inbound connections.
  53. type Inbound interface {
  54. // Network returns a list of networks that this inbound supports. Connections with not-supported networks will not be passed into Process().
  55. Network() []net.Network
  56. // Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.
  57. Process(context.Context, net.Network, stat.Connection, routing.Dispatcher) error
  58. }
  59. // An Outbound process outbound connections.
  60. type Outbound interface {
  61. // Process processes the given connection. The given dialer may be used to dial a system outbound connection.
  62. Process(context.Context, *transport.Link, internet.Dialer) error
  63. }
  64. // UserManager is the interface for Inbounds and Outbounds that can manage their users.
  65. type UserManager interface {
  66. // AddUser adds a new user.
  67. AddUser(context.Context, *protocol.MemoryUser) error
  68. // RemoveUser removes a user by email.
  69. RemoveUser(context.Context, string) error
  70. // Get user by email.
  71. GetUser(context.Context, string) *protocol.MemoryUser
  72. // Get all users.
  73. GetUsers(context.Context) []*protocol.MemoryUser
  74. // Get users count.
  75. GetUsersCount(context.Context) int64
  76. }
  77. type GetInbound interface {
  78. GetInbound() Inbound
  79. }
  80. type GetOutbound interface {
  81. GetOutbound() Outbound
  82. }
  83. // TrafficState is used to track uplink and downlink of one connection
  84. // It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
  85. type TrafficState struct {
  86. UserUUID []byte
  87. NumberOfPacketToFilter int
  88. EnableXtls bool
  89. IsTLS12orAbove bool
  90. IsTLS bool
  91. Cipher uint16
  92. RemainingServerHello int32
  93. Inbound InboundState
  94. Outbound OutboundState
  95. }
  96. type InboundState struct {
  97. // reader link state
  98. WithinPaddingBuffers bool
  99. UplinkReaderDirectCopy bool
  100. RemainingCommand int32
  101. RemainingContent int32
  102. RemainingPadding int32
  103. CurrentCommand int
  104. // write link state
  105. IsPadding bool
  106. DownlinkWriterDirectCopy bool
  107. }
  108. type OutboundState struct {
  109. // reader link state
  110. WithinPaddingBuffers bool
  111. DownlinkReaderDirectCopy bool
  112. RemainingCommand int32
  113. RemainingContent int32
  114. RemainingPadding int32
  115. CurrentCommand int
  116. // write link state
  117. IsPadding bool
  118. UplinkWriterDirectCopy bool
  119. }
  120. func NewTrafficState(userUUID []byte) *TrafficState {
  121. return &TrafficState{
  122. UserUUID: userUUID,
  123. NumberOfPacketToFilter: 8,
  124. EnableXtls: false,
  125. IsTLS12orAbove: false,
  126. IsTLS: false,
  127. Cipher: 0,
  128. RemainingServerHello: -1,
  129. Inbound: InboundState{
  130. WithinPaddingBuffers: true,
  131. UplinkReaderDirectCopy: false,
  132. RemainingCommand: -1,
  133. RemainingContent: -1,
  134. RemainingPadding: -1,
  135. CurrentCommand: 0,
  136. IsPadding: true,
  137. DownlinkWriterDirectCopy: false,
  138. },
  139. Outbound: OutboundState{
  140. WithinPaddingBuffers: true,
  141. DownlinkReaderDirectCopy: false,
  142. RemainingCommand: -1,
  143. RemainingContent: -1,
  144. RemainingPadding: -1,
  145. CurrentCommand: 0,
  146. IsPadding: true,
  147. UplinkWriterDirectCopy: false,
  148. },
  149. }
  150. }
  151. // VisionReader is used to read xtls vision protocol
  152. // Note Vision probably only make sense as the inner most layer of reader, since it need assess traffic state from origin proxy traffic
  153. type VisionReader struct {
  154. buf.Reader
  155. trafficState *TrafficState
  156. ctx context.Context
  157. isUplink bool
  158. }
  159. func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, context context.Context) *VisionReader {
  160. return &VisionReader{
  161. Reader: reader,
  162. trafficState: state,
  163. ctx: context,
  164. isUplink: isUplink,
  165. }
  166. }
  167. func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
  168. buffer, err := w.Reader.ReadMultiBuffer()
  169. if !buffer.IsEmpty() {
  170. var withinPaddingBuffers *bool
  171. var remainingContent *int32
  172. var remainingPadding *int32
  173. var currentCommand *int
  174. var switchToDirectCopy *bool
  175. if w.isUplink {
  176. withinPaddingBuffers = &w.trafficState.Inbound.WithinPaddingBuffers
  177. remainingContent = &w.trafficState.Inbound.RemainingContent
  178. remainingPadding = &w.trafficState.Inbound.RemainingPadding
  179. currentCommand = &w.trafficState.Inbound.CurrentCommand
  180. switchToDirectCopy = &w.trafficState.Inbound.UplinkReaderDirectCopy
  181. } else {
  182. withinPaddingBuffers = &w.trafficState.Outbound.WithinPaddingBuffers
  183. remainingContent = &w.trafficState.Outbound.RemainingContent
  184. remainingPadding = &w.trafficState.Outbound.RemainingPadding
  185. currentCommand = &w.trafficState.Outbound.CurrentCommand
  186. switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
  187. }
  188. if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
  189. mb2 := make(buf.MultiBuffer, 0, len(buffer))
  190. for _, b := range buffer {
  191. newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
  192. if newbuffer.Len() > 0 {
  193. mb2 = append(mb2, newbuffer)
  194. }
  195. }
  196. buffer = mb2
  197. if *remainingContent > 0 || *remainingPadding > 0 || *currentCommand == 0 {
  198. *withinPaddingBuffers = true
  199. } else if *currentCommand == 1 {
  200. *withinPaddingBuffers = false
  201. } else if *currentCommand == 2 {
  202. *withinPaddingBuffers = false
  203. *switchToDirectCopy = true
  204. } else {
  205. errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
  206. }
  207. }
  208. if w.trafficState.NumberOfPacketToFilter > 0 {
  209. XtlsFilterTls(buffer, w.trafficState, w.ctx)
  210. }
  211. }
  212. return buffer, err
  213. }
  214. // VisionWriter is used to write xtls vision protocol
  215. // Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
  216. type VisionWriter struct {
  217. buf.Writer
  218. trafficState *TrafficState
  219. ctx context.Context
  220. writeOnceUserUUID []byte
  221. isUplink bool
  222. }
  223. func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, context context.Context) *VisionWriter {
  224. w := make([]byte, len(state.UserUUID))
  225. copy(w, state.UserUUID)
  226. return &VisionWriter{
  227. Writer: writer,
  228. trafficState: state,
  229. ctx: context,
  230. writeOnceUserUUID: w,
  231. isUplink: isUplink,
  232. }
  233. }
  234. func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
  235. if w.trafficState.NumberOfPacketToFilter > 0 {
  236. XtlsFilterTls(mb, w.trafficState, w.ctx)
  237. }
  238. var isPadding *bool
  239. var switchToDirectCopy *bool
  240. if w.isUplink {
  241. isPadding = &w.trafficState.Outbound.IsPadding
  242. switchToDirectCopy = &w.trafficState.Outbound.UplinkWriterDirectCopy
  243. } else {
  244. isPadding = &w.trafficState.Inbound.IsPadding
  245. switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
  246. }
  247. if *isPadding {
  248. if len(mb) == 1 && mb[0] == nil {
  249. mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
  250. return w.Writer.WriteMultiBuffer(mb)
  251. }
  252. mb = ReshapeMultiBuffer(w.ctx, mb)
  253. longPadding := w.trafficState.IsTLS
  254. for i, b := range mb {
  255. if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
  256. if w.trafficState.EnableXtls {
  257. *switchToDirectCopy = true
  258. }
  259. var command byte = CommandPaddingContinue
  260. if i == len(mb)-1 {
  261. command = CommandPaddingEnd
  262. if w.trafficState.EnableXtls {
  263. command = CommandPaddingDirect
  264. }
  265. }
  266. mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
  267. *isPadding = false // padding going to end
  268. longPadding = false
  269. continue
  270. } else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
  271. *isPadding = false
  272. mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
  273. break
  274. }
  275. var command byte = CommandPaddingContinue
  276. if i == len(mb)-1 && !*isPadding {
  277. command = CommandPaddingEnd
  278. if w.trafficState.EnableXtls {
  279. command = CommandPaddingDirect
  280. }
  281. }
  282. mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
  283. }
  284. }
  285. return w.Writer.WriteMultiBuffer(mb)
  286. }
  287. // ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
  288. func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer {
  289. needReshape := 0
  290. for _, b := range buffer {
  291. if b.Len() >= buf.Size-21 {
  292. needReshape += 1
  293. }
  294. }
  295. if needReshape == 0 {
  296. return buffer
  297. }
  298. mb2 := make(buf.MultiBuffer, 0, len(buffer)+needReshape)
  299. toPrint := ""
  300. for i, buffer1 := range buffer {
  301. if buffer1.Len() >= buf.Size-21 {
  302. index := int32(bytes.LastIndex(buffer1.Bytes(), TlsApplicationDataStart))
  303. if index < 21 || index > buf.Size-21 {
  304. index = buf.Size / 2
  305. }
  306. buffer2 := buf.New()
  307. buffer2.Write(buffer1.BytesFrom(index))
  308. buffer1.Resize(0, index)
  309. mb2 = append(mb2, buffer1, buffer2)
  310. toPrint += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len()))
  311. } else {
  312. mb2 = append(mb2, buffer1)
  313. toPrint += " " + strconv.Itoa(int(buffer1.Len()))
  314. }
  315. buffer[i] = nil
  316. }
  317. buffer = buffer[:0]
  318. errors.LogInfo(ctx, "ReshapeMultiBuffer ", toPrint)
  319. return mb2
  320. }
  321. // XtlsPadding add padding to eliminate length signature during tls handshake
  322. func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
  323. var contentLen int32 = 0
  324. var paddingLen int32 = 0
  325. if b != nil {
  326. contentLen = b.Len()
  327. }
  328. if contentLen < 900 && longPadding {
  329. l, err := rand.Int(rand.Reader, big.NewInt(500))
  330. if err != nil {
  331. errors.LogDebugInner(ctx, err, "failed to generate padding")
  332. }
  333. paddingLen = int32(l.Int64()) + 900 - contentLen
  334. } else {
  335. l, err := rand.Int(rand.Reader, big.NewInt(256))
  336. if err != nil {
  337. errors.LogDebugInner(ctx, err, "failed to generate padding")
  338. }
  339. paddingLen = int32(l.Int64())
  340. }
  341. if paddingLen > buf.Size-21-contentLen {
  342. paddingLen = buf.Size - 21 - contentLen
  343. }
  344. newbuffer := buf.New()
  345. if userUUID != nil {
  346. newbuffer.Write(*userUUID)
  347. *userUUID = nil
  348. }
  349. newbuffer.Write([]byte{command, byte(contentLen >> 8), byte(contentLen), byte(paddingLen >> 8), byte(paddingLen)})
  350. if b != nil {
  351. newbuffer.Write(b.Bytes())
  352. b.Release()
  353. b = nil
  354. }
  355. newbuffer.Extend(paddingLen)
  356. errors.LogInfo(ctx, "XtlsPadding ", contentLen, " ", paddingLen, " ", command)
  357. return newbuffer
  358. }
  359. // XtlsUnpadding remove padding and parse command
  360. func XtlsUnpadding(b *buf.Buffer, s *TrafficState, isUplink bool, ctx context.Context) *buf.Buffer {
  361. var remainingCommand *int32
  362. var remainingContent *int32
  363. var remainingPadding *int32
  364. var currentCommand *int
  365. if isUplink {
  366. remainingCommand = &s.Inbound.RemainingCommand
  367. remainingContent = &s.Inbound.RemainingContent
  368. remainingPadding = &s.Inbound.RemainingPadding
  369. currentCommand = &s.Inbound.CurrentCommand
  370. } else {
  371. remainingCommand = &s.Outbound.RemainingCommand
  372. remainingContent = &s.Outbound.RemainingContent
  373. remainingPadding = &s.Outbound.RemainingPadding
  374. currentCommand = &s.Outbound.CurrentCommand
  375. }
  376. if *remainingCommand == -1 && *remainingContent == -1 && *remainingPadding == -1 { // initial state
  377. if b.Len() >= 21 && bytes.Equal(s.UserUUID, b.BytesTo(16)) {
  378. b.Advance(16)
  379. *remainingCommand = 5
  380. } else {
  381. return b
  382. }
  383. }
  384. newbuffer := buf.New()
  385. for b.Len() > 0 {
  386. if *remainingCommand > 0 {
  387. data, err := b.ReadByte()
  388. if err != nil {
  389. return newbuffer
  390. }
  391. switch *remainingCommand {
  392. case 5:
  393. *currentCommand = int(data)
  394. case 4:
  395. *remainingContent = int32(data) << 8
  396. case 3:
  397. *remainingContent = *remainingContent | int32(data)
  398. case 2:
  399. *remainingPadding = int32(data) << 8
  400. case 1:
  401. *remainingPadding = *remainingPadding | int32(data)
  402. errors.LogInfo(ctx, "Xtls Unpadding new block, content ", *remainingContent, " padding ", *remainingPadding, " command ", *currentCommand)
  403. }
  404. *remainingCommand--
  405. } else if *remainingContent > 0 {
  406. len := *remainingContent
  407. if b.Len() < len {
  408. len = b.Len()
  409. }
  410. data, err := b.ReadBytes(len)
  411. if err != nil {
  412. return newbuffer
  413. }
  414. newbuffer.Write(data)
  415. *remainingContent -= len
  416. } else { // remainingPadding > 0
  417. len := *remainingPadding
  418. if b.Len() < len {
  419. len = b.Len()
  420. }
  421. b.Advance(len)
  422. *remainingPadding -= len
  423. }
  424. if *remainingCommand <= 0 && *remainingContent <= 0 && *remainingPadding <= 0 { // this block done
  425. if *currentCommand == 0 {
  426. *remainingCommand = 5
  427. } else {
  428. *remainingCommand = -1 // set to initial state
  429. *remainingContent = -1
  430. *remainingPadding = -1
  431. if b.Len() > 0 { // shouldn't happen
  432. newbuffer.Write(b.Bytes())
  433. }
  434. break
  435. }
  436. }
  437. }
  438. b.Release()
  439. b = nil
  440. return newbuffer
  441. }
  442. // XtlsFilterTls filter and recognize tls 1.3 and other info
  443. func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx context.Context) {
  444. for _, b := range buffer {
  445. if b == nil {
  446. continue
  447. }
  448. trafficState.NumberOfPacketToFilter--
  449. if b.Len() >= 6 {
  450. startsBytes := b.BytesTo(6)
  451. if bytes.Equal(TlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == TlsHandshakeTypeServerHello {
  452. trafficState.RemainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5
  453. trafficState.IsTLS12orAbove = true
  454. trafficState.IsTLS = true
  455. if b.Len() >= 79 && trafficState.RemainingServerHello >= 79 {
  456. sessionIdLen := int32(b.Byte(43))
  457. cipherSuite := b.BytesRange(43+sessionIdLen+1, 43+sessionIdLen+3)
  458. trafficState.Cipher = uint16(cipherSuite[0])<<8 | uint16(cipherSuite[1])
  459. } else {
  460. errors.LogInfo(ctx, "XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", trafficState.RemainingServerHello)
  461. }
  462. } else if bytes.Equal(TlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == TlsHandshakeTypeClientHello {
  463. trafficState.IsTLS = true
  464. errors.LogInfo(ctx, "XtlsFilterTls found tls client hello! ", buffer.Len())
  465. }
  466. }
  467. if trafficState.RemainingServerHello > 0 {
  468. end := trafficState.RemainingServerHello
  469. if end > b.Len() {
  470. end = b.Len()
  471. }
  472. trafficState.RemainingServerHello -= b.Len()
  473. if bytes.Contains(b.BytesTo(end), Tls13SupportedVersions) {
  474. v, ok := Tls13CipherSuiteDic[trafficState.Cipher]
  475. if !ok {
  476. v = "Old cipher: " + strconv.FormatUint(uint64(trafficState.Cipher), 16)
  477. } else if v != "TLS_AES_128_CCM_8_SHA256" {
  478. trafficState.EnableXtls = true
  479. }
  480. errors.LogInfo(ctx, "XtlsFilterTls found tls 1.3! ", b.Len(), " ", v)
  481. trafficState.NumberOfPacketToFilter = 0
  482. return
  483. } else if trafficState.RemainingServerHello <= 0 {
  484. errors.LogInfo(ctx, "XtlsFilterTls found tls 1.2! ", b.Len())
  485. trafficState.NumberOfPacketToFilter = 0
  486. return
  487. }
  488. errors.LogInfo(ctx, "XtlsFilterTls inconclusive server hello ", b.Len(), " ", trafficState.RemainingServerHello)
  489. }
  490. if trafficState.NumberOfPacketToFilter <= 0 {
  491. errors.LogInfo(ctx, "XtlsFilterTls stop filtering", buffer.Len())
  492. }
  493. }
  494. }
  495. // UnwrapRawConn support unwrap stats, tls, utls, reality, proxyproto, uds-wrapper conn and get raw tcp/uds conn from it
  496. func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
  497. var readCounter, writerCounter stats.Counter
  498. if conn != nil {
  499. statConn, ok := conn.(*stat.CounterConnection)
  500. if ok {
  501. conn = statConn.Connection
  502. readCounter = statConn.ReadCounter
  503. writerCounter = statConn.WriteCounter
  504. }
  505. if xc, ok := conn.(*tls.Conn); ok {
  506. conn = xc.NetConn()
  507. } else if utlsConn, ok := conn.(*tls.UConn); ok {
  508. conn = utlsConn.NetConn()
  509. } else if realityConn, ok := conn.(*reality.Conn); ok {
  510. conn = realityConn.NetConn()
  511. } else if realityUConn, ok := conn.(*reality.UConn); ok {
  512. conn = realityUConn.NetConn()
  513. }
  514. if pc, ok := conn.(*proxyproto.Conn); ok {
  515. conn = pc.Raw()
  516. // 8192 > 4096, there is no need to process pc's bufReader
  517. }
  518. if uc, ok := conn.(*internet.UnixConnWrapper); ok {
  519. conn = uc.UnixConn
  520. }
  521. }
  522. return conn, readCounter, writerCounter
  523. }
  524. // CopyRawConnIfExist use the most efficient copy method.
  525. // - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
  526. // - writer are from *transport.Link
  527. func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer *signal.ActivityTimer, inTimer *signal.ActivityTimer) error {
  528. readerConn, readCounter, _ := UnwrapRawConn(readerConn)
  529. writerConn, _, writeCounter := UnwrapRawConn(writerConn)
  530. reader := buf.NewReader(readerConn)
  531. if runtime.GOOS != "linux" && runtime.GOOS != "android" {
  532. return readV(ctx, reader, writer, timer, readCounter)
  533. }
  534. tc, ok := writerConn.(*net.TCPConn)
  535. if !ok || readerConn == nil || writerConn == nil {
  536. return readV(ctx, reader, writer, timer, readCounter)
  537. }
  538. inbound := session.InboundFromContext(ctx)
  539. if inbound == nil || inbound.CanSpliceCopy == 3 {
  540. return readV(ctx, reader, writer, timer, readCounter)
  541. }
  542. outbounds := session.OutboundsFromContext(ctx)
  543. if len(outbounds) == 0 {
  544. return readV(ctx, reader, writer, timer, readCounter)
  545. }
  546. for _, ob := range outbounds {
  547. if ob.CanSpliceCopy == 3 {
  548. return readV(ctx, reader, writer, timer, readCounter)
  549. }
  550. }
  551. for {
  552. inbound := session.InboundFromContext(ctx)
  553. outbounds := session.OutboundsFromContext(ctx)
  554. var splice = inbound.CanSpliceCopy == 1
  555. for _, ob := range outbounds {
  556. if ob.CanSpliceCopy != 1 {
  557. splice = false
  558. }
  559. }
  560. if splice {
  561. errors.LogInfo(ctx, "CopyRawConn splice")
  562. statWriter, _ := writer.(*dispatcher.SizeStatWriter)
  563. //runtime.Gosched() // necessary
  564. time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
  565. timer.SetTimeout(8 * time.Hour) // prevent leak, just in case
  566. if inTimer != nil {
  567. inTimer.SetTimeout(8 * time.Hour)
  568. }
  569. w, err := tc.ReadFrom(readerConn)
  570. if readCounter != nil {
  571. readCounter.Add(w) // outbound stats
  572. }
  573. if writeCounter != nil {
  574. writeCounter.Add(w) // inbound stats
  575. }
  576. if statWriter != nil {
  577. statWriter.Counter.Add(w) // user stats
  578. }
  579. if err != nil && errors.Cause(err) != io.EOF {
  580. return err
  581. }
  582. return nil
  583. }
  584. buffer, err := reader.ReadMultiBuffer()
  585. if !buffer.IsEmpty() {
  586. if readCounter != nil {
  587. readCounter.Add(int64(buffer.Len()))
  588. }
  589. timer.Update()
  590. if werr := writer.WriteMultiBuffer(buffer); werr != nil {
  591. return werr
  592. }
  593. }
  594. if err != nil {
  595. return err
  596. }
  597. }
  598. }
  599. func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
  600. errors.LogInfo(ctx, "CopyRawConn readv")
  601. if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
  602. return errors.New("failed to process response").Base(err)
  603. }
  604. return nil
  605. }