socks5_request_handle.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. c := make([]*core.Config, 0)
  32. c = append(c, &core.Config{ConfigName: "socks5_check_request", Description: "need check the permission?"})
  33. c = append(c, &core.Config{ConfigName: "socks5_request_username", Description: "auth username"})
  34. c = append(c, &core.Config{ConfigName: "socks5_request_password", Description: "auth password"})
  35. return nil
  36. }
  37. func (request *Request) GetStage() core.Stage {
  38. return core.STAGE_RUN
  39. }
  40. func (request *Request) Start(ctx context.Context, config map[string]string) error {
  41. return nil
  42. }
  43. func (request *Request) End(ctx context.Context, config map[string]string) error {
  44. return nil
  45. }
  46. func (request *Request) Run(ctx context.Context, config map[string]string) error {
  47. clientCtxConn := ctx.Value("clientConn")
  48. if clientCtxConn == nil {
  49. return errors.New("the client request.clientConnection is not exist")
  50. }
  51. request.clientConn = clientCtxConn.(net.Conn)
  52. request.ctx = ctx
  53. /*
  54. The SOCKS request is formed as follows:
  55. +----+-----+-------+------+----------+----------+
  56. |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  57. +----+-----+-------+------+----------+----------+
  58. | 1 | 1 | X'00' | 1 | Variable | 2 |
  59. +----+-----+-------+------+----------+----------+
  60. */
  61. header := make([]byte, 3)
  62. _, err := io.ReadFull(request.clientConn, header)
  63. if err != nil {
  64. return errors.New("illegal request" + err.Error())
  65. }
  66. switch header[1] {
  67. case connectMethod:
  68. context.WithValue(request.ctx, "socks5_target_type", "tcp")
  69. return request.doConnect()
  70. case bindMethod:
  71. return request.handleBind()
  72. case associateMethod:
  73. context.WithValue(request.ctx, "socks5_target_type", "udp")
  74. return request.handleUDP()
  75. default:
  76. request.sendReply(commandNotSupported)
  77. return errors.New("command not supported")
  78. }
  79. return nil
  80. }
  81. func (request *Request) sendReply(rep uint8) error {
  82. reply := []byte{
  83. 5,
  84. rep,
  85. 0,
  86. 1,
  87. }
  88. localAddr := request.clientConn.LocalAddr().String()
  89. localHost, localPort, _ := net.SplitHostPort(localAddr)
  90. ipBytes := net.ParseIP(localHost).To4()
  91. nPort, _ := strconv.Atoi(localPort)
  92. reply = append(reply, ipBytes...)
  93. portBytes := make([]byte, 2)
  94. binary.BigEndian.PutUint16(portBytes, uint16(nPort))
  95. reply = append(reply, portBytes...)
  96. _, err := request.clientConn.Write(reply)
  97. return err
  98. }
  99. //do conn
  100. func (request *Request) doConnect() error {
  101. addrType := make([]byte, 1)
  102. request.clientConn.Read(addrType)
  103. var host string
  104. switch addrType[0] {
  105. case ipV4:
  106. ipv4 := make(net.IP, net.IPv4len)
  107. request.clientConn.Read(ipv4)
  108. host = ipv4.String()
  109. case ipV6:
  110. ipv6 := make(net.IP, net.IPv6len)
  111. request.clientConn.Read(ipv6)
  112. host = ipv6.String()
  113. case domainName:
  114. var domainLen uint8
  115. binary.Read(request.clientConn, binary.BigEndian, &domainLen)
  116. domain := make([]byte, domainLen)
  117. request.clientConn.Read(domain)
  118. host = string(domain)
  119. default:
  120. request.sendReply(addrTypeNotSupported)
  121. return errors.New("target address type is not support")
  122. }
  123. var port uint16
  124. binary.Read(request.clientConn, binary.BigEndian, &port)
  125. context.WithValue(request.ctx, "socks5_target_host", host)
  126. context.WithValue(request.ctx, "socks5_target_port", port)
  127. return nil
  128. }
  129. // passive mode
  130. func (request *Request) handleBind() error {
  131. return nil
  132. }
  133. //udp
  134. func (request *Request) handleUDP() error {
  135. /*
  136. +----+------+------+----------+----------+----------+
  137. |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
  138. +----+------+------+----------+----------+----------+
  139. | 2 | 1 | 1 | Variable | 2 | Variable |
  140. +----+------+------+----------+----------+----------+
  141. */
  142. buf := make([]byte, 3)
  143. request.clientConn.Read(buf)
  144. // relay udp datagram silently, without any notification to the requesting client
  145. if buf[2] != 0 {
  146. // does not support fragmentation, drop it
  147. dummy := make([]byte, maxUDPPacketSize)
  148. request.clientConn.Read(dummy)
  149. return errors.New("does not support fragmentation, drop")
  150. }
  151. return request.doConnect()
  152. }