mux.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package obfs
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "io"
  7. "net"
  8. )
  9. type SessionStatus = byte
  10. const (
  11. SessionStatusNew SessionStatus = 0x01
  12. SessionStatusKeep SessionStatus = 0x02
  13. SessionStatusEnd SessionStatus = 0x03
  14. SessionStatusKeepAlive SessionStatus = 0x04
  15. )
  16. const (
  17. OptionNone = byte(0x00)
  18. OptionData = byte(0x01)
  19. OptionError = byte(0x02)
  20. )
  21. type MuxOption struct {
  22. ID [2]byte
  23. Port uint16
  24. Host string
  25. Type string
  26. }
  27. // Mux is an mux-compatible client for v2ray-plugin, not a complete implementation
  28. type Mux struct {
  29. net.Conn
  30. buf bytes.Buffer
  31. id [2]byte
  32. length [2]byte
  33. status [2]byte
  34. otb []byte
  35. remain int
  36. }
  37. func (m *Mux) Read(b []byte) (int, error) {
  38. if m.remain != 0 {
  39. length := m.remain
  40. if len(b) < m.remain {
  41. length = len(b)
  42. }
  43. n, err := m.Conn.Read(b[:length])
  44. if err != nil {
  45. return 0, err
  46. }
  47. m.remain -= n
  48. return n, nil
  49. }
  50. for {
  51. _, err := io.ReadFull(m.Conn, m.length[:])
  52. if err != nil {
  53. return 0, err
  54. }
  55. length := binary.BigEndian.Uint16(m.length[:])
  56. if length > 512 {
  57. return 0, errors.New("invalid metalen")
  58. }
  59. _, err = io.ReadFull(m.Conn, m.id[:])
  60. if err != nil {
  61. return 0, err
  62. }
  63. _, err = m.Conn.Read(m.status[:])
  64. if err != nil {
  65. return 0, err
  66. }
  67. opcode := m.status[0]
  68. if opcode == SessionStatusKeepAlive {
  69. continue
  70. }
  71. opts := m.status[1]
  72. if opts != OptionData {
  73. continue
  74. }
  75. _, err = io.ReadFull(m.Conn, m.length[:])
  76. if err != nil {
  77. return 0, err
  78. }
  79. dataLen := int(binary.BigEndian.Uint16(m.length[:]))
  80. m.remain = dataLen
  81. if dataLen > len(b) {
  82. dataLen = len(b)
  83. }
  84. n, err := m.Conn.Read(b[:dataLen])
  85. m.remain -= n
  86. return n, err
  87. }
  88. }
  89. func (m *Mux) Write(b []byte) (int, error) {
  90. if m.otb != nil {
  91. // create a sub connection
  92. if _, err := m.Conn.Write(m.otb); err != nil {
  93. return 0, err
  94. }
  95. m.otb = nil
  96. }
  97. m.buf.Reset()
  98. binary.Write(&m.buf, binary.BigEndian, uint16(4))
  99. m.buf.Write(m.id[:])
  100. m.buf.WriteByte(SessionStatusKeep)
  101. m.buf.WriteByte(OptionData)
  102. binary.Write(&m.buf, binary.BigEndian, uint16(len(b)))
  103. m.buf.Write(b)
  104. return m.Conn.Write(m.buf.Bytes())
  105. }
  106. func (m *Mux) Close() error {
  107. _, err := m.Conn.Write([]byte{0x0, 0x4, m.id[0], m.id[1], SessionStatusEnd, OptionNone})
  108. if err != nil {
  109. return err
  110. }
  111. return m.Conn.Close()
  112. }
  113. func NewMux(conn net.Conn, option MuxOption) *Mux {
  114. buf := &bytes.Buffer{}
  115. // fill empty length
  116. buf.Write([]byte{0x0, 0x0})
  117. buf.Write(option.ID[:])
  118. buf.WriteByte(SessionStatusNew)
  119. buf.WriteByte(OptionNone)
  120. // tcp
  121. netType := byte(0x1)
  122. if option.Type == "udp" {
  123. netType = byte(0x2)
  124. }
  125. buf.WriteByte(netType)
  126. // port
  127. binary.Write(buf, binary.BigEndian, option.Port)
  128. // address
  129. ip := net.ParseIP(option.Host)
  130. if ip == nil {
  131. buf.WriteByte(0x2)
  132. buf.WriteString(option.Host)
  133. } else if ipv4 := ip.To4(); ipv4 != nil {
  134. buf.WriteByte(0x1)
  135. buf.Write(ipv4)
  136. } else {
  137. buf.WriteByte(0x3)
  138. buf.Write(ip.To16())
  139. }
  140. metadata := buf.Bytes()
  141. binary.BigEndian.PutUint16(metadata[:2], uint16(len(metadata)-2))
  142. return &Mux{
  143. Conn: conn,
  144. id: option.ID,
  145. otb: metadata,
  146. }
  147. }