matrix.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "sort"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "time"
  12. )
  13. //ByControlPlane contains all the channels we need.
  14. type ByControlPlane struct {
  15. BadTokens chan string
  16. GoodTokens chan string
  17. StatsTokens chan string
  18. }
  19. //ControPlane is the variabile
  20. var ControPlane ByControlPlane
  21. //ByClassifier is the structure containing our Pseudo-Bayes classifier.
  22. type ByClassifier struct {
  23. GOOD sync.Map
  24. BAD sync.Map
  25. MEH sync.Map
  26. STATS sync.Map
  27. }
  28. //AddStats adds the statistics after proper blocking.
  29. func (c *ByClassifier) AddStats(action string) {
  30. var one int64 = 1
  31. if v, ok := c.STATS.Load(action); ok {
  32. c.STATS.Store(action, v.(int64)+1)
  33. } else {
  34. c.STATS.Store(action, one)
  35. }
  36. }
  37. //IsBAD inserts a bad key in the right place.
  38. func (c *ByClassifier) IsBAD(key string) {
  39. if _, ok := c.MEH.Load(key); ok {
  40. c.MEH.Store(key, time.Now().UnixNano())
  41. log.Println("Updated BAD into MEH: ", key)
  42. return
  43. }
  44. if _, ok := c.GOOD.Load(key); ok {
  45. c.MEH.Store(key, time.Now().UnixNano())
  46. c.GOOD.Delete(key)
  47. log.Println("Moved to MEH from GOOD: ", key)
  48. return
  49. }
  50. c.BAD.Store(key, time.Now().UnixNano())
  51. log.Println("Stored into BAD: ", key)
  52. }
  53. //IsGOOD inserts the key in the right place.
  54. func (c *ByClassifier) IsGOOD(key string) {
  55. if _, ok := c.MEH.Load(key); ok {
  56. c.MEH.Store(key, time.Now().UnixNano())
  57. log.Println("Updated GOOD into MEH: ", key)
  58. return
  59. }
  60. if _, ok := c.BAD.Load(key); ok {
  61. c.MEH.Store(key, time.Now().UnixNano())
  62. c.BAD.Delete(key)
  63. log.Println("Moved to MEH from BAD: ", key)
  64. return
  65. }
  66. c.GOOD.Store(key, time.Now().UnixNano())
  67. log.Println("Stored into GOOD: ", key)
  68. }
  69. //Posterior calculates the posterior probabilities in pseudo-bayes.
  70. func (c *ByClassifier) Posterior(hdr string) map[string]float64 {
  71. headers := strings.Fields(sanitizeHeaders(hdr))
  72. var result = make(map[string]float64)
  73. result["BAD"] = 0
  74. result["GOOD"] = 0
  75. var tmpResGood, tmpResBad, tmpResMeh, tmpTotal float64
  76. for _, token := range headers {
  77. if _, ok := c.BAD.Load(token); ok {
  78. tmpResBad++
  79. tmpTotal++
  80. }
  81. if _, ok := c.GOOD.Load(token); ok {
  82. tmpResGood++
  83. tmpTotal++
  84. }
  85. if _, ok := c.MEH.Load(token); ok {
  86. tmpResMeh++
  87. tmpTotal++
  88. }
  89. }
  90. if tmpTotal == 0 {
  91. tmpTotal = 1
  92. }
  93. log.Printf("Bad Tokens: %f, Good Tokens %f , Total %f\n", tmpResBad, tmpResGood, tmpTotal)
  94. result["BAD"] = (tmpResBad + tmpResMeh) / tmpTotal
  95. result["GOOD"] = (tmpResGood + tmpResMeh) / tmpTotal
  96. return result
  97. }
  98. //Janitor keeps the maps under a certain size, keeping the biggest values.
  99. func (c *ByClassifier) Janitor(size int) {
  100. log.Println("Janitor Running")
  101. sortMap(&c.BAD, size)
  102. sortMap(&c.GOOD, size)
  103. sortMap(&c.MEH, size)
  104. log.Println("Janitor Finished.")
  105. }
  106. //CleanThread is the Janitor thread
  107. func (c *ByClassifier) CleanThread() {
  108. for {
  109. MaxSize, err := strconv.Atoi(fmt.Sprintf("%d", Maturity))
  110. if err != nil {
  111. MaxSize = 1000
  112. log.Println("Maxsize converted to: ", MaxSize)
  113. }
  114. log.Println("Janitor Maxsize is now:", MaxSize)
  115. time.Sleep(10 * time.Second)
  116. c.Janitor(MaxSize)
  117. }
  118. }
  119. func (c *ByClassifier) enroll() {
  120. ControPlane.BadTokens = make(chan string, 2048)
  121. ControPlane.GoodTokens = make(chan string, 2048)
  122. ControPlane.StatsTokens = make(chan string, 2048)
  123. c.readInitList("blacklist.txt", "BAD")
  124. c.readInitList("whitelist.txt", "GOOD")
  125. c.MEH.Store("Dildo", time.Now().UnixNano())
  126. go c.readBadTokens()
  127. go c.readGoodTokens()
  128. go c.readStatsTokens()
  129. log.Println("Classifier populated...")
  130. go c.CleanThread()
  131. log.Println("Janitor Started")
  132. }
  133. func sortMap(unsorted *sync.Map, size int) {
  134. type Myt struct {
  135. Name string
  136. Num int64
  137. }
  138. var tempCont []Myt
  139. var tc Myt
  140. unsorted.Range(func(key interface{}, value interface{}) bool {
  141. tc.Name = key.(string)
  142. tc.Num = value.(int64)
  143. tempCont = append(tempCont, tc)
  144. return true
  145. })
  146. sort.Slice(tempCont, func(i, j int) bool { return tempCont[i].Num > tempCont[j].Num })
  147. if size > 0 && len(tempCont) > size {
  148. tempCont = tempCont[:size]
  149. }
  150. unsorted.Range(func(key interface{}, value interface{}) bool {
  151. unsorted.Delete(key)
  152. return true
  153. })
  154. for _, val := range tempCont {
  155. unsorted.Store(val.Name, val.Num)
  156. }
  157. }
  158. func (c *ByClassifier) readBadTokens() {
  159. log.Println("Start reading BAD tokens")
  160. for token := range ControPlane.BadTokens {
  161. log.Println("Received BAD Token: ", token)
  162. c.IsBAD(token)
  163. }
  164. }
  165. func (c *ByClassifier) readGoodTokens() {
  166. log.Println("Start reading GOOD tokens")
  167. for token := range ControPlane.GoodTokens {
  168. log.Println("Received GOOD Token: ", token)
  169. c.IsGOOD(token)
  170. }
  171. }
  172. func (c *ByClassifier) readStatsTokens() {
  173. log.Println("Start reading STATS tokens")
  174. for token := range ControPlane.StatsTokens {
  175. c.AddStats(token)
  176. }
  177. }
  178. func (c *ByClassifier) readInitList(filePath, class string) {
  179. inFile, err := os.Open(filePath)
  180. if err != nil {
  181. log.Println(err.Error() + `: ` + filePath)
  182. return
  183. }
  184. defer inFile.Close()
  185. scanner := bufio.NewScanner(inFile)
  186. for scanner.Scan() {
  187. if len(scanner.Text()) > 3 {
  188. switch class {
  189. case "BAD":
  190. log.Println("Loading into Blacklist: ", scanner.Text()) // the line
  191. c.IsBAD(scanner.Text())
  192. case "GOOD":
  193. log.Println("Loading into Whitelist: ", scanner.Text()) // the line
  194. c.IsGOOD(scanner.Text())
  195. }
  196. }
  197. }
  198. }