socks5_read_request_handle.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package socks5
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "errors"
  6. "github.com/cnlh/nps/core"
  7. "io"
  8. "net"
  9. "strconv"
  10. )
  11. type Request struct {
  12. clientConn net.Conn
  13. ctx context.Context
  14. }
  15. const (
  16. ipV4 = 1
  17. domainName = 3
  18. ipV6 = 4
  19. connectMethod = 1
  20. bindMethod = 2
  21. associateMethod = 3
  22. // The maximum packet size of any udp Associate packet, based on ethernet's max size,
  23. // minus the IP and UDP headerrequest. IPv4 has a 20 byte header, UDP adds an
  24. // additional 4 byterequest. This is a total overhead of 24 byterequest. Ethernet's
  25. // max packet size is 1500 bytes, 1500 - 24 = 1476.
  26. maxUDPPacketSize = 1476
  27. commandNotSupported = 7
  28. addrTypeNotSupported = 8
  29. )
  30. func (request *Request) GetConfigName() []*core.Config {
  31. return nil
  32. }
  33. func (request *Request) GetStage() core.Stage {
  34. return core.STAGE_RUN
  35. }
  36. func (request *Request) Start(ctx context.Context, config map[string]string) error {
  37. return nil
  38. }
  39. func (request *Request) End(ctx context.Context, config map[string]string) error {
  40. return nil
  41. }
  42. func (request *Request) Run(ctx context.Context, config map[string]string) error {
  43. clientCtxConn := ctx.Value(core.CLIENT_CONNECTION)
  44. if clientCtxConn == nil {
  45. return core.CLIENT_CONNECTION_NOT_EXIST
  46. }
  47. request.clientConn = clientCtxConn.(net.Conn)
  48. request.ctx = ctx
  49. /*
  50. The SOCKS request is formed as follows:
  51. +----+-----+-------+------+----------+----------+
  52. |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  53. +----+-----+-------+------+----------+----------+
  54. | 1 | 1 | X'00' | 1 | Variable | 2 |
  55. +----+-----+-------+------+----------+----------+
  56. */
  57. header := make([]byte, 3)
  58. _, err := io.ReadFull(request.clientConn, header)
  59. if err != nil {
  60. return errors.New("illegal request" + err.Error())
  61. }
  62. switch header[1] {
  63. case connectMethod:
  64. context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "tcp")
  65. return request.doConnect()
  66. case bindMethod:
  67. return request.handleBind()
  68. case associateMethod:
  69. context.WithValue(request.ctx, core.PROXY_CONNECTION_TYPE, "udp")
  70. return request.handleUDP()
  71. default:
  72. request.sendReply(commandNotSupported)
  73. return errors.New("command not supported")
  74. }
  75. return nil
  76. }
  77. func (request *Request) sendReply(rep uint8) error {
  78. reply := []byte{
  79. 5,
  80. rep,
  81. 0,
  82. 1,
  83. }
  84. localAddr := request.clientConn.LocalAddr().String()
  85. localHost, localPort, _ := net.SplitHostPort(localAddr)
  86. ipBytes := net.ParseIP(localHost).To4()
  87. nPort, _ := strconv.Atoi(localPort)
  88. reply = append(reply, ipBytes...)
  89. portBytes := make([]byte, 2)
  90. binary.BigEndian.PutUint16(portBytes, uint16(nPort))
  91. reply = append(reply, portBytes...)
  92. _, err := request.clientConn.Write(reply)
  93. return err
  94. }
  95. //do conn
  96. func (request *Request) doConnect() error {
  97. addrType := make([]byte, 1)
  98. request.clientConn.Read(addrType)
  99. var host string
  100. switch addrType[0] {
  101. case ipV4:
  102. ipv4 := make(net.IP, net.IPv4len)
  103. request.clientConn.Read(ipv4)
  104. host = ipv4.String()
  105. case ipV6:
  106. ipv6 := make(net.IP, net.IPv6len)
  107. request.clientConn.Read(ipv6)
  108. host = ipv6.String()
  109. case domainName:
  110. var domainLen uint8
  111. binary.Read(request.clientConn, binary.BigEndian, &domainLen)
  112. domain := make([]byte, domainLen)
  113. request.clientConn.Read(domain)
  114. host = string(domain)
  115. default:
  116. request.sendReply(addrTypeNotSupported)
  117. return errors.New("target address type is not support")
  118. }
  119. var port uint16
  120. binary.Read(request.clientConn, binary.BigEndian, &port)
  121. context.WithValue(request.ctx, core.PROXY_CONNECTION_ADDR, host)
  122. context.WithValue(request.ctx, core.PROXY_CONNECTION_PORT, port)
  123. return nil
  124. }
  125. // passive mode
  126. func (request *Request) handleBind() error {
  127. return nil
  128. }
  129. //udp
  130. func (request *Request) handleUDP() error {
  131. /*
  132. +----+------+------+----------+----------+----------+
  133. |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  134. +----+------+------+----------+----------+----------+
  135. | 2 | 1 | 1 | Variable | 2 | Variable |
  136. +----+------+------+----------+----------+----------+
  137. */
  138. buf := make([]byte, 3)
  139. request.clientConn.Read(buf)
  140. // relay udp datagram silently, without any notification to the requesting client
  141. if buf[2] != 0 {
  142. // does not support fragmentation, drop it
  143. dummy := make([]byte, maxUDPPacketSize)
  144. request.clientConn.Read(dummy)
  145. return errors.New("does not support fragmentation, drop")
  146. }
  147. return request.doConnect()
  148. }