package main import ( "bytes" "fmt" "io/ioutil" "log" "net" "net/http" ) //Zexpressions is the set of regexp being used by zardoz var Zexpressions = []string{ `[[:alpha:]]{4,32}`, // alpha digit token `[ ]([A-Za-z0-9-_]{4,}\.)+\w+`, // domain name `[ ]/[A-Za-z0-9-_/.]{4,}[ ]`, // URI path (also partial) `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}`, // IP address `[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 } func passAndLearn(resp *http.Response) error { ProxyFlow.response = resp ProxyFlow.seniority++ req := ProxyFlow.request switch { case isAuth(resp): log.Println("401: We don't want to store credentials") case isError(resp): buf := bytes.NewBufferString(BlockMessage) resp.Body = ioutil.NopCloser(buf) resp.Status = "403 Forbidden" resp.StatusCode = 403 resp.Header["Content-Length"] = []string{fmt.Sprint(buf.Len())} resp.Header.Set("Content-Encoding", "none") resp.Header.Set("Cache-Control", "no-cache, no-store") log.Println("Filing inside bad class") feedRequest(req, "BAD") ControPlane.StatsTokens <- "DOWNGRADE" case isSuccess(resp): log.Println("Filing inside Good Class: ", resp.StatusCode) feedRequest(req, "GOOD") } return nil } func blockAndlearn(resp *http.Response) error { ProxyFlow.response = resp ProxyFlow.seniority++ req := ProxyFlow.request buf := bytes.NewBufferString(BlockMessage) resp.Body = ioutil.NopCloser(buf) resp.Status = "403 Forbidden" resp.StatusCode = 403 resp.Header["Content-Length"] = []string{fmt.Sprint(buf.Len())} resp.Header.Set("Content-Encoding", "none") resp.Header.Set("Cache-Control", "no-cache, no-store") switch { case isAuth(resp): log.Println("401: We don't want to store credentials") case isError(resp): log.Println("Filing inside bad class") feedRequest(req, "BAD") case isSuccess(resp): log.Println("Filing inside Good Class: ", resp.StatusCode) ControPlane.StatsTokens <- "UPGRADED" feedRequest(req, "GOOD") } return nil } func feedRequest(req *http.Request, class string) { feed := SourceIP(req) // feed := formatRequest(req) if class == "BAD" { log.Println("Feeding BAD token: ", feed) ControPlane.BadTokens <- feed } if class == "GOOD" { log.Println("Feeding GOOD Token:", feed) ControPlane.GoodTokens <- feed } } //Unique returns unique elements in the string func Unique(slice []string) []string { // create a map with all the values as key uniqMap := make(map[string]struct{}) for _, v := range slice { uniqMap[v] = struct{}{} } // turn the map keys into a slice uniqSlice := make([]string, 0, len(uniqMap)) for v := range uniqMap { uniqSlice = append(uniqSlice, v) } return uniqSlice } func isSuccess(resp *http.Response) bool { return resp.StatusCode <= 299 } func isAuth(resp *http.Response) bool { return resp.StatusCode == 401 } func isError(resp *http.Response) bool { return resp.StatusCode >= 400 && resp.StatusCode != 401 } //SourceIP returns the source IP of a http call func SourceIP(req *http.Request) string { var feed string if feed = req.Header.Get("X-Forwarded-For"); feed != "" { log.Println("Got X-Forwarded-For: " + feed) } else { feed, _, _ = net.SplitHostPort(req.RemoteAddr) log.Println("NO X-Forwarded-For, using: "+feed+" from ", req.RemoteAddr) } return feed }