socks5_read_request_handle.go 3.9 KB

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