148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
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
|
|
|
|
}
|