initial filter and proxy work
This commit is contained in:
commit
7149d63496
|
@ -0,0 +1,5 @@
|
|||
module git.openprivacy.ca/openprivacy/ddosFilter
|
||||
|
||||
go 1.14
|
||||
|
||||
require git.openprivacy.ca/openprivacy/log v1.0.1
|
|
@ -0,0 +1,2 @@
|
|||
git.openprivacy.ca/openprivacy/log v1.0.1 h1:NWV5oBTatvlSzUE6wtB+UQCulgyMOtm4BXGd34evMys=
|
||||
git.openprivacy.ca/openprivacy/log v1.0.1/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
|
@ -0,0 +1,162 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const MaxLength = 8192
|
||||
const SameCookieTimeLimitMins = 10
|
||||
|
||||
type Ip2LastSeen map[string]time.Time
|
||||
|
||||
var cookiesToIps sync.Map // map [ cookie string] Ip2LastSeen
|
||||
|
||||
func main() {
|
||||
var listenPort = flag.Int("listenPort", 5999, "port to listen on for incoming HTTP connections")
|
||||
var proxyPort = flag.Int("proxyPort", 6000, "port to forward connections to that pass the filter")
|
||||
flag.Parse()
|
||||
log.SetLevel(log.LevelInfo)
|
||||
log.Infof("Starting ddosFilter on %v -> %v...\n", *listenPort, *proxyPort)
|
||||
|
||||
listen(*listenPort, *proxyPort)
|
||||
}
|
||||
|
||||
func listen(listenPort, proxyPort int) {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { filter(w, r, listenPort, proxyPort)})
|
||||
addr := "127.0.0.1:" + strconv.Itoa(listenPort)
|
||||
err := http.ListenAndServe(addr, nil)
|
||||
if err != nil {
|
||||
log.Errorf("ListenAndServe on %v failed: %v\n", addr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func filter(res http.ResponseWriter, req *http.Request, listenPort, proxyPort int) {
|
||||
ip := req.RemoteAddr
|
||||
log.Infof("%v: Request %v %v\n", ip, req.Host, req.URL)
|
||||
cookie, err := req.Cookie("i_like_gogits")
|
||||
if err != nil {
|
||||
pass(res, req, listenPort, proxyPort)
|
||||
return
|
||||
}
|
||||
|
||||
ips, ok := cookiesToIps.Load(cookie)
|
||||
|
||||
if !ok {
|
||||
ips := Ip2LastSeen{ip: time.Now()}
|
||||
cookiesToIps.Store(cookie, ips)
|
||||
pass(res, req, listenPort, proxyPort)
|
||||
return
|
||||
}
|
||||
|
||||
ipsMap := ips.(Ip2LastSeen)
|
||||
var mostRecent string = ""
|
||||
|
||||
for ip, lastSeen := range ipsMap {
|
||||
if mostRecent == "" || lastSeen.After(ipsMap[mostRecent]) {
|
||||
mostRecent = ip
|
||||
}
|
||||
}
|
||||
|
||||
ipsMap[ip] = time.Now()
|
||||
cookiesToIps.Store(cookie, ipsMap)
|
||||
|
||||
if mostRecent == "" || mostRecent == ip {
|
||||
pass(res, req, listenPort, proxyPort)
|
||||
return
|
||||
}
|
||||
|
||||
timeDiff := time.Now().Sub(ipsMap[mostRecent])
|
||||
if timeDiff.Minutes() > SameCookieTimeLimitMins {
|
||||
pass(res, req, listenPort, proxyPort)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("different IP in the last %v minutes, 404ing\n", SameCookieTimeLimitMins)
|
||||
res.WriteHeader(http.StatusNotFound)
|
||||
fmt.Fprint(res, "404 - suspected botnet")
|
||||
}
|
||||
|
||||
// https://medium.com/@mlowicki/http-s-proxy-in-golang-in-less-than-100-lines-of-code-6a51c2f2c38c
|
||||
/*func copyHeader(dst, src *http.Header) {
|
||||
for k, vv := range src {
|
||||
for _, v := range vv {
|
||||
dst.Add(k, v)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//https://stackoverflow.com/questions/23164547/golang-reverseproxy-not-working
|
||||
func copyHeader(source http.Header, dest *http.Header){
|
||||
for n, v := range source {
|
||||
for _, vv := range v {
|
||||
dest.Add(n, vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pass(res http.ResponseWriter, req *http.Request, listenPort, proxyPort int) {
|
||||
log.Infoln("Request pass to proxy")
|
||||
|
||||
|
||||
log.Infof("orig: %v\n", req.Host)
|
||||
//req.Host = "http://" + strings.Replace(req.Host, strconv.Itoa(listenPort), strconv.Itoa(proxyPort), 1)i
|
||||
req.Host = "git.danballard.com"
|
||||
|
||||
req.URL.Host = "git.danballard.com"
|
||||
req.URL.Scheme = "https"
|
||||
|
||||
|
||||
if req.Method == "POST" {
|
||||
body, _ := ioutil.ReadAll(req.Body)
|
||||
fmt.Printf("POST Body: %v\n", string(body));
|
||||
}
|
||||
|
||||
/* Works but loses header and cookies */
|
||||
/*rr, err := http.NewRequest(req.Method, req.Host + req.URL.Path, req.Body)
|
||||
for _, cookie := range req.Cookies() {
|
||||
rr.AddCookie(cookie)
|
||||
log.Infof("copy cookie: %v\n", cookie.String())
|
||||
}*/
|
||||
|
||||
log.Infof("req: %v\n", req)
|
||||
//log.Infof("rr: %v\n", rr)
|
||||
/*if rr.Method == "POST" {
|
||||
body, _ := ioutil.ReadAll(rr.Body)
|
||||
fmt.Printf("POST Body: %v\n", string(body))
|
||||
}*/
|
||||
//log.Infof("rr body: %v\n", rr.Body.)
|
||||
var transport http.Transport
|
||||
resp, err := transport.RoundTrip(req) //rr)
|
||||
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error fetching: %v\n", err.Error())
|
||||
http.Error(res, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
//log.Infof("read BODY: %v\n", string(body))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
dH := res.Header()
|
||||
copyHeader(resp.Header, &dH)
|
||||
dH.Add("Requested-Host", rr.Host)
|
||||
res.WriteHeader(resp.StatusCode)
|
||||
|
||||
n, err := res.Write(body)
|
||||
log.Infof("res.write n: %v err: %v\n", n, err)
|
||||
|
||||
}
|
Loading…
Reference in New Issue