http_proxy_js_request.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package http_proxy
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "net/url"
  8. "regexp"
  9. "strings"
  10. "github.com/bettercap/bettercap/session"
  11. )
  12. type JSRequest struct {
  13. Client map[string]string
  14. Method string
  15. Version string
  16. Scheme string
  17. Path string
  18. Query string
  19. Hostname string
  20. Port string
  21. ContentType string
  22. Headers string
  23. Body string
  24. req *http.Request
  25. refHash string
  26. bodyRead bool
  27. }
  28. var header_regexp = regexp.MustCompile(`^\s*(.*?)\s*:\s*(.*)\s*$`)
  29. func NewJSRequest(req *http.Request) *JSRequest {
  30. headers := ""
  31. cType := ""
  32. for name, values := range req.Header {
  33. for _, value := range values {
  34. headers += name + ": " + value + "\r\n"
  35. if strings.ToLower(name) == "content-type" {
  36. cType = value
  37. }
  38. }
  39. }
  40. client_ip := strings.Split(req.RemoteAddr, ":")[0]
  41. client_mac := ""
  42. client_alias := ""
  43. if endpoint := session.I.Lan.GetByIp(client_ip); endpoint != nil {
  44. client_mac = endpoint.HwAddress
  45. client_alias = endpoint.Alias
  46. }
  47. jreq := &JSRequest{
  48. Client: map[string]string{"IP": client_ip, "MAC": client_mac, "Alias": client_alias},
  49. Method: req.Method,
  50. Version: fmt.Sprintf("%d.%d", req.ProtoMajor, req.ProtoMinor),
  51. Scheme: req.URL.Scheme,
  52. Hostname: req.URL.Hostname(),
  53. Port: req.URL.Port(),
  54. Path: req.URL.Path,
  55. Query: req.URL.RawQuery,
  56. ContentType: cType,
  57. Headers: headers,
  58. req: req,
  59. bodyRead: false,
  60. }
  61. jreq.UpdateHash()
  62. return jreq
  63. }
  64. func (j *JSRequest) NewHash() string {
  65. hash := fmt.Sprintf("%s.%s.%s.%s.%s.%s.%s.%s.%s.%s",
  66. j.Client["IP"],
  67. j.Method,
  68. j.Version,
  69. j.Scheme,
  70. j.Hostname,
  71. j.Port,
  72. j.Path,
  73. j.Query,
  74. j.ContentType,
  75. j.Headers)
  76. hash += "." + j.Body
  77. return hash
  78. }
  79. func (j *JSRequest) UpdateHash() {
  80. j.refHash = j.NewHash()
  81. }
  82. func (j *JSRequest) WasModified() bool {
  83. // body was read
  84. if j.bodyRead {
  85. return true
  86. }
  87. // check if any of the fields has been changed
  88. return j.NewHash() != j.refHash
  89. }
  90. func (j *JSRequest) GetHeader(name, deflt string) string {
  91. headers := strings.Split(j.Headers, "\r\n")
  92. for i := 0; i < len(headers); i++ {
  93. if headers[i] != "" {
  94. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  95. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  96. header_name := string(header_parts[0][1])
  97. header_value := string(header_parts[0][2])
  98. if strings.ToLower(name) == strings.ToLower(header_name) {
  99. return header_value
  100. }
  101. }
  102. }
  103. }
  104. return deflt
  105. }
  106. func (j *JSRequest) SetHeader(name, value string) {
  107. name = strings.TrimSpace(name)
  108. value = strings.TrimSpace(value)
  109. if strings.ToLower(name) == "content-type" {
  110. j.ContentType = value
  111. }
  112. headers := strings.Split(j.Headers, "\r\n")
  113. for i := 0; i < len(headers); i++ {
  114. if headers[i] != "" {
  115. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  116. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  117. header_name := string(header_parts[0][1])
  118. header_value := string(header_parts[0][2])
  119. if strings.ToLower(name) == strings.ToLower(header_name) {
  120. old_header := header_name + ": " + header_value + "\r\n"
  121. new_header := name + ": " + value + "\r\n"
  122. j.Headers = strings.Replace(j.Headers, old_header, new_header, 1)
  123. return
  124. }
  125. }
  126. }
  127. }
  128. j.Headers += name + ": " + value + "\r\n"
  129. }
  130. func (j *JSRequest) RemoveHeader(name string) {
  131. headers := strings.Split(j.Headers, "\r\n")
  132. for i := 0; i < len(headers); i++ {
  133. if headers[i] != "" {
  134. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  135. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  136. header_name := string(header_parts[0][1])
  137. header_value := string(header_parts[0][2])
  138. if strings.ToLower(name) == strings.ToLower(header_name) {
  139. removed_header := header_name + ": " + header_value + "\r\n"
  140. j.Headers = strings.Replace(j.Headers, removed_header, "", 1)
  141. return
  142. }
  143. }
  144. }
  145. }
  146. }
  147. func (j *JSRequest) ReadBody() string {
  148. raw, err := ioutil.ReadAll(j.req.Body)
  149. if err != nil {
  150. return ""
  151. }
  152. j.Body = string(raw)
  153. j.bodyRead = true
  154. // reset the request body to the original unread state
  155. j.req.Body = ioutil.NopCloser(bytes.NewBuffer(raw))
  156. return j.Body
  157. }
  158. func (j *JSRequest) ParseForm() map[string]string {
  159. if j.Body == "" {
  160. j.Body = j.ReadBody()
  161. }
  162. form := make(map[string]string)
  163. parts := strings.Split(j.Body, "&")
  164. for _, part := range parts {
  165. nv := strings.SplitN(part, "=", 2)
  166. if len(nv) == 2 {
  167. unescaped, err := url.QueryUnescape(nv[1])
  168. if err == nil {
  169. form[nv[0]] = unescaped
  170. } else {
  171. form[nv[0]] = nv[1]
  172. }
  173. }
  174. }
  175. return form
  176. }
  177. func (j *JSRequest) ToRequest() (req *http.Request) {
  178. portPart := ""
  179. if j.Port != "" {
  180. portPart = fmt.Sprintf(":%s", j.Port)
  181. }
  182. url := fmt.Sprintf("%s://%s%s%s?%s", j.Scheme, j.Hostname, portPart, j.Path, j.Query)
  183. if j.Body == "" {
  184. req, _ = http.NewRequest(j.Method, url, j.req.Body)
  185. } else {
  186. req, _ = http.NewRequest(j.Method, url, strings.NewReader(j.Body))
  187. }
  188. headers := strings.Split(j.Headers, "\r\n")
  189. for i := 0; i < len(headers); i++ {
  190. if headers[i] != "" {
  191. header_parts := header_regexp.FindAllSubmatch([]byte(headers[i]), 1)
  192. if len(header_parts) != 0 && len(header_parts[0]) == 3 {
  193. header_name := string(header_parts[0][1])
  194. header_value := string(header_parts[0][2])
  195. if strings.ToLower(header_name) == "content-type" {
  196. if header_value != j.ContentType {
  197. req.Header.Set(header_name, j.ContentType)
  198. continue
  199. }
  200. }
  201. req.Header.Set(header_name, header_value)
  202. }
  203. }
  204. }
  205. req.RemoteAddr = j.Client["IP"]
  206. return
  207. }