payload_tcp_parser.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package handler
  2. import (
  3. "bufio"
  4. "bytes"
  5. "net/http"
  6. "regexp"
  7. "strings"
  8. )
  9. var tcpParsers = []func([]byte) (uint8, string){
  10. sniNewParser,
  11. httpParser,
  12. }
  13. func onTCP(payload []byte) (uint8, string) {
  14. size := len(payload)
  15. ihl := (payload[12] & 0xf0) >> 2
  16. if int(ihl) > size {
  17. return acc_proto_tcp, ""
  18. }
  19. data := payload[ihl:]
  20. for _, parser := range tcpParsers {
  21. if proto, info := parser(data); proto != acc_proto_tcp {
  22. return proto, info
  23. }
  24. }
  25. return acc_proto_tcp, ""
  26. }
  27. func sniNewParser(b []byte) (uint8, string) {
  28. if len(b) < 2 || b[0] != 0x16 || b[1] != 0x03 {
  29. return acc_proto_tcp, ""
  30. }
  31. rest := b[5:]
  32. restLen := len(rest)
  33. if restLen == 0 {
  34. return acc_proto_tcp, ""
  35. }
  36. current := 0
  37. handshakeType := rest[0]
  38. current += 1
  39. if handshakeType != 0x1 {
  40. return acc_proto_tcp, ""
  41. }
  42. // Skip over another length
  43. current += 3
  44. // Skip over protocolversion
  45. current += 2
  46. // Skip over random number
  47. current += 4 + 28
  48. if current >= restLen {
  49. return acc_proto_https, ""
  50. }
  51. // Skip over session ID
  52. sessionIDLength := int(rest[current])
  53. current += 1
  54. current += sessionIDLength
  55. if current+1 >= restLen {
  56. return acc_proto_https, ""
  57. }
  58. cipherSuiteLength := (int(rest[current]) << 8) + int(rest[current+1])
  59. current += 2
  60. current += cipherSuiteLength
  61. if current >= restLen {
  62. return acc_proto_https, ""
  63. }
  64. compressionMethodLength := int(rest[current])
  65. current += 1
  66. current += compressionMethodLength
  67. if current >= restLen {
  68. return acc_proto_https, ""
  69. }
  70. current += 2
  71. hostname := ""
  72. for current+4 < restLen && hostname == "" {
  73. extensionType := (int(rest[current]) << 8) + int(rest[current+1])
  74. current += 2
  75. extensionDataLength := (int(rest[current]) << 8) + int(rest[current+1])
  76. current += 2
  77. if extensionType == 0 {
  78. // Skip over number of names as we're assuming there's just one
  79. current += 2
  80. if current >= restLen {
  81. return acc_proto_https, ""
  82. }
  83. nameType := rest[current]
  84. current += 1
  85. if nameType != 0 {
  86. return acc_proto_https, ""
  87. }
  88. if current+1 >= restLen {
  89. return acc_proto_https, ""
  90. }
  91. nameLen := (int(rest[current]) << 8) + int(rest[current+1])
  92. current += 2
  93. if current+nameLen >= restLen {
  94. return acc_proto_https, ""
  95. }
  96. hostname = string(rest[current : current+nameLen])
  97. }
  98. current += extensionDataLength
  99. }
  100. if hostname == "" {
  101. return acc_proto_https, ""
  102. }
  103. if !validDomainChar(hostname) {
  104. return acc_proto_https, ""
  105. }
  106. return acc_proto_https, hostname
  107. }
  108. // Beta
  109. func httpNewParser(data []byte) (uint8, string) {
  110. methodArr := []string{"OPTIONS", "HEAD", "GET", "POST", "PUT", "DELETE", "TRACE", "CONNECT"}
  111. pos := bytes.IndexByte(data, 10)
  112. if pos == -1 {
  113. return acc_proto_tcp, ""
  114. }
  115. method, uri, _ := strings.Cut(string(data[:pos]), " ")
  116. ok := false
  117. for _, v := range methodArr {
  118. if v == method {
  119. ok = true
  120. }
  121. }
  122. if !ok {
  123. return acc_proto_tcp, ""
  124. }
  125. hostname := ""
  126. // GET http://www.google.com/index.html HTTP/1.1
  127. if len(uri) > 7 && uri[:4] == "http" {
  128. uriSlice := strings.Split(uri[7:], "/")
  129. hostname = uriSlice[0]
  130. return acc_proto_http, hostname
  131. }
  132. packet := string(data)
  133. hostPos := strings.Index(packet, "Host: ")
  134. if hostPos == -1 {
  135. hostPos = strings.Index(packet, "HOST: ")
  136. if hostPos == -1 {
  137. return acc_proto_tcp, ""
  138. }
  139. }
  140. hostEndPos := strings.Index(packet[hostPos:], "\n")
  141. if hostEndPos == -1 {
  142. return acc_proto_tcp, ""
  143. }
  144. hostname = packet[hostPos+6 : hostPos+hostEndPos-1]
  145. return acc_proto_http, hostname
  146. }
  147. func sniParser(data []byte) (uint8, string) {
  148. if len(data) < 2 || data[0] != 0x16 || data[1] != 0x03 {
  149. return acc_proto_tcp, ""
  150. }
  151. sniRe := regexp.MustCompile("\x00\x00.{4}\x00.{2}([a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6})\x00")
  152. m := sniRe.FindSubmatch(data)
  153. if len(m) < 2 {
  154. return acc_proto_tcp, ""
  155. }
  156. host := string(m[1])
  157. return acc_proto_https, host
  158. }
  159. func httpParser(data []byte) (uint8, string) {
  160. if req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(data))); err == nil {
  161. return acc_proto_http, req.Host
  162. }
  163. return acc_proto_tcp, ""
  164. }
  165. // 校验域名的合法字符, 处理乱码问题
  166. func validDomainChar(addr string) bool {
  167. // Allow a-z A-Z . - 0-9
  168. for i := 0; i < len(addr); i++ {
  169. c := addr[i]
  170. if !((c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 45 && c <= 46) || (c >= 48 && c <= 57)) {
  171. return false
  172. }
  173. }
  174. return true
  175. }