classifier.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "net/http"
  8. "net/http/httputil"
  9. "regexp"
  10. "strings"
  11. )
  12. //Zexpressions is the set of regexp being used by zardoz
  13. var Zexpressions = []string{
  14. `[[:alpha:]]{4,32}`, // alpha digit token
  15. `[ ]([A-Za-z0-9-_]{4,}\.)+\w+`, // domain name
  16. `[ ]/[A-Za-z0-9-_/.]{4,}[ ]`, // URI path (also partial)
  17. `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}`, // IP address
  18. `[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}`, // UUID
  19. }
  20. func passAndLearn(resp *http.Response) error {
  21. ProxyFlow.response = resp
  22. ProxyFlow.seniority++
  23. req := ProxyFlow.request
  24. switch {
  25. case isAuth(resp):
  26. log.Println("401: We don't want to store credentials")
  27. case isError(resp):
  28. buf := bytes.NewBufferString(BlockMessage)
  29. resp.Body = ioutil.NopCloser(buf)
  30. resp.Status = "403 Forbidden"
  31. resp.StatusCode = 403
  32. resp.Header["Content-Length"] = []string{fmt.Sprint(buf.Len())}
  33. resp.Header.Set("Content-Encoding", "none")
  34. resp.Header.Set("Cache-Control", "no-cache, no-store")
  35. log.Println("Filing inside bad class")
  36. feedRequest(req, "BAD")
  37. ControPlane.StatsTokens <- "DOWNGRADE"
  38. case isSuccess(resp):
  39. log.Println("Filing inside Good Class: ", resp.StatusCode)
  40. feedRequest(req, "GOOD")
  41. }
  42. return nil
  43. }
  44. func blockAndlearn(resp *http.Response) error {
  45. ProxyFlow.response = resp
  46. ProxyFlow.seniority++
  47. req := ProxyFlow.request
  48. buf := bytes.NewBufferString(BlockMessage)
  49. resp.Body = ioutil.NopCloser(buf)
  50. resp.Status = "403 Forbidden"
  51. resp.StatusCode = 403
  52. resp.Header["Content-Length"] = []string{fmt.Sprint(buf.Len())}
  53. resp.Header.Set("Content-Encoding", "none")
  54. resp.Header.Set("Cache-Control", "no-cache, no-store")
  55. switch {
  56. case isAuth(resp):
  57. log.Println("401: We don't want to store credentials")
  58. case isError(resp):
  59. log.Println("Filing inside bad class")
  60. feedRequest(req, "BAD")
  61. case isSuccess(resp):
  62. log.Println("Filing inside Good Class: ", resp.StatusCode)
  63. ControPlane.StatsTokens <- "UPGRADED"
  64. feedRequest(req, "GOOD")
  65. }
  66. return nil
  67. }
  68. func sanitizeHeaders(s string) string {
  69. var collect []string
  70. ss := strings.ToLower(s)
  71. for _, zregexp := range Zexpressions {
  72. re, rerr := regexp.Compile(zregexp)
  73. if rerr != nil {
  74. log.Println("Error Compiling regular expression: ", zregexp)
  75. }
  76. matched := re.FindAllString(ss, -1)
  77. if matched == nil {
  78. matched = []string{"null"}
  79. }
  80. collect = append(collect, matched...)
  81. }
  82. uMatched := Unique(collect)
  83. log.Println("Matched: ", uMatched)
  84. return strings.Join(uMatched, " ")
  85. }
  86. func feedRequest(req *http.Request, class string) {
  87. feed := formatRequest(req)
  88. if class == "BAD" {
  89. log.Println("Feeding BAD token: ", feed)
  90. ControPlane.BadTokens <- sanitizeHeaders(feed)
  91. }
  92. if class == "GOOD" {
  93. log.Println("Feeding GOOD Token:", feed)
  94. ControPlane.GoodTokens <- sanitizeHeaders(feed)
  95. }
  96. }
  97. func formatRequest(req *http.Request) string {
  98. requestDump, err := httputil.DumpRequest(req, false)
  99. if err != nil {
  100. fmt.Println(err)
  101. }
  102. return fmt.Sprintf("%s\n", requestDump)
  103. }
  104. //Unique returns unique elements in the string
  105. func Unique(slice []string) []string {
  106. // create a map with all the values as key
  107. uniqMap := make(map[string]struct{})
  108. for _, v := range slice {
  109. uniqMap[v] = struct{}{}
  110. }
  111. // turn the map keys into a slice
  112. uniqSlice := make([]string, 0, len(uniqMap))
  113. for v := range uniqMap {
  114. uniqSlice = append(uniqSlice, v)
  115. }
  116. return uniqSlice
  117. }
  118. func isSuccess(resp *http.Response) bool {
  119. return resp.StatusCode <= 299
  120. }
  121. func isAuth(resp *http.Response) bool {
  122. return resp.StatusCode == 401
  123. }
  124. func isError(resp *http.Response) bool {
  125. return resp.StatusCode >= 400 && resp.StatusCode != 401
  126. }