func TestWithBrowser(t *testing.T) { // an easy way to check if auth works with webserver // to test, run with // $ go test -run TestWithBrowser -- server // configure a browser to use the printed proxy address, use the proxy // and exit with Ctrl-C. It will throw error if your haven't acutally used the proxy if os.Args[len(os.Args)-1] != "server" { return } proxy := goproxy.NewProxyHttpServer() println("proxy localhost port 8082") access := int32(0) proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { atomic.AddInt32(&access, 1) return user == "user" && passwd == "1234" })) l, err := net.Listen("tcp", "localhost:8082") if err != nil { t.Fatal(err) } ch := make(chan os.Signal) signal.Notify(ch, os.Interrupt) go func() { <-ch l.Close() }() http.Serve(l, proxy) if access <= 0 { t.Error("No one accessed the proxy") } }
func TestBasicAuthWithCurl(t *testing.T) { expected := ":c>" background := httptest.NewServer(ConstantHanlder(expected)) defer background.Close() proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { return user == "user" && passwd == "open sesame" })) _, proxyserver := oneShotProxy(proxy) defer proxyserver.Close() cmd := exec.Command("curl", "--silent", "--show-error", "-x", proxyserver.URL, "-U", "user:open sesame", "--url", background.URL+"/[1-3]", ) out, err := cmd.CombinedOutput() // if curl got error, it'll show up in stderr if err != nil { t.Fatal(err, string(out)) } finalexpected := times(3, expected) if string(out) != finalexpected { t.Error("Expected", finalexpected, "got", string(out)) } }
func TestBasicAuth(t *testing.T) { expected := "hello" background := httptest.NewServer(ConstantHanlder(expected)) defer background.Close() proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { return user == "user" && passwd == "open sesame" })) client, proxyserver := oneShotProxy(proxy) defer proxyserver.Close() // without auth resp, err := client.Get(background.URL) if err != nil { t.Fatal(err) } if resp.Header.Get("Proxy-Authenticate") != "Basic realm=my_realm" { t.Error("Expected Proxy-Authenticate header got", resp.Header.Get("Proxy-Authenticate")) } if resp.StatusCode != 407 { t.Error("Expected status 407 Proxy Authentication Required, got", resp.Status) } // with auth req, err := http.NewRequest("GET", background.URL, nil) if err != nil { t.Fatal(err) } req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("user:open sesame"))) resp, err = client.Do(req) if err != nil { t.Fatal(err) } if resp.StatusCode != 200 { t.Error("Expected status 200 OK, got", resp.Status) } msg, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if string(msg) != "hello" { t.Errorf("Expected '%s', actual '%s'", expected, string(msg)) } }
func TestCharset(t *testing.T) { s := httptest.NewServer(ConstantServer(1)) defer s.Close() ch := make(chan string, 2) proxy := goproxy.NewProxyHttpServer() proxy.OnResponse().Do(goproxy_html.HandleString( func(s string, ctx *goproxy.ProxyCtx) string { ch <- s return s })) proxyServer := httptest.NewServer(proxy) defer proxyServer.Close() proxyUrl, _ := url.Parse(proxyServer.URL) client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}} resp, err := client.Get(s.URL + "/cp1255.txt") if err != nil { t.Fatal("GET:", err) } b, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal("readAll:", err) } resp.Body.Close() inHandleString := "" select { case inHandleString = <-ch: default: } if len(b) != 2 || b[0] != 0xe3 || b[1] != 0xf3 { t.Error("Did not translate back to 0xe3,0xf3, instead", b) } if inHandleString != "דף" { t.Error("HandleString did not convert DALET & PEH SOFIT (דף) from ISO-8859-8 to utf-8, got", []byte(inHandleString)) } }
// Main func main() { runtime.GOMAXPROCS(runtime.NumCPU()) verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") /*login := flag.String("login", "", "proxy login") password := flag.String("password", "", "proxy passwd")*/ addr := flag.String("addr", ":8080", "proxy listen address") flag.Parse() // Yara c, err := yara.NewCompiler() handleErr(err) // Load & compile rules err = filepath.Walk("rules/yara", func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } return c.AddFile("", "rules/yara/"+info.Name()) }) handleErr(err) engine, err := c.Rules() handleErr(err) c.Destroy() // HTML cleaners htmlCleaner := NewHTMLCleaner() err = htmlCleaner.LoadRulesFromFile("rules/HTMLCleaner.txt") handleErr(err) // CSS injector cssInjector := NewCSSInjector() err = cssInjector.LoadRulesFromFile("rules/filters/css2inject.txt") handleErr(err) // launch proxy goproxy.CertOrganisation = "Pure proxy" // Cache for certs TLSConfigCache, err = lru.New(TLSCacheSize) //goproxy.GoproxyCa, err = tls.X509KeyPair(CaCert, CaKey) ca, err := tls.X509KeyPair(CaCert, CaKey) handleErr(err) proxy := goproxy.NewProxyHttpServer() proxy.Verbose = *verbose MitmConnect := &goproxy.ConnectAction{ Action: goproxy.ConnectMitm, TLSConfig: func(host string, ctx *goproxy.ProxyCtx) (*tls.Config, error) { return TLSGetConfig(host, ctx, &ca) }, } var AlwaysMitm goproxy.FuncHttpsHandler = func(host string, ctx *goproxy.ProxyCtx) ( *goproxy.ConnectAction, string) { return MitmConnect, host } proxy.OnRequest().HandleConnect(AlwaysMitm) /*auth.ProxyBasic(proxy, "my_realm", func(user, passwd string) bool { return user == *login && passwd == *password })*/ /* proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { log.Println(host) name := "" err = engine.ScanMemory([]byte(host), func(rule *yara.Rule) yara.CallbackStatus { name = rule.Identifier return yara.Abort }) if name != "" { log.Println("REJECTED", name, host) return goproxy.RejectConnect, host } return goproxy.OkConnect, host }) */ // POC websocket /*proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { log.Println(host) if host == "live.toorop.fr:80" { msg := "---------------------------------------------------------\n" for k, v := range ctx.Req.Header { msg += string(k) + ":" + v[0] + "\n" } msg += "---------------------------------------------------------\n\n" log.Println(msg) } return goproxy.OkConnect, host })*/ /*proxy.OnRequest(IsWebsocket). HijackConnect(func(req *http.Request, client net.Conn, ctx *goproxy.ProxyCtx) { defer func() { if e := recover(); e != nil { ctx.Logf("error connecting to remote: %v", e) client.Write([]byte("HTTP/1.1 500 Cannot reach destination\r\n\r\n")) } client.Close() }() log.Println("Requete versTHE websocket") clientBuf := bufio.NewReadWriter(bufio.NewReader(client), bufio.NewWriter(client)) remote, err := connectDial(proxy, "tcp", req.URL.Host) orPanic(err) remoteBuf := bufio.NewReadWriter(bufio.NewReader(remote), bufio.NewWriter(remote)) for { req, err := http.ReadRequest(clientBuf.Reader) orPanic(err) orPanic(req.Write(remoteBuf)) orPanic(remoteBuf.Flush()) resp, err := http.ReadResponse(remoteBuf.Reader, req) orPanic(err) orPanic(resp.Write(clientBuf.Writer)) orPanic(clientBuf.Flush()) } })*/ /*proxy.OnRequest(IsWebsocket).DoFunc(func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { log.Println("Requete vers websocket") return r, nil })*/ proxy.OnRequest().DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { name := "" err = engine.ScanMemory([]byte(r.Host), func(rule *yara.Rule) yara.CallbackStatus { name = rule.Identifier return yara.Abort }) if name == "" { err = engine.ScanMemory([]byte(r.RequestURI), func(rule *yara.Rule) yara.CallbackStatus { name = rule.Identifier return yara.Abort }) } if name != "" { log.Println("BLOCKED", name, r.RequestURI) return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusForbidden, "I'm sorry, Dave. I'm afraid I can't do that.") } return r, nil }) // Scan response - POC // TODO: refactoring proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { if resp == nil { return nil } contentType := resp.Header.Get("content-type") // http if strings.HasPrefix(contentType, "text/html") { resp.Body = htmlCleaner.Clean(resp.Body, ctx.Req.Host) } else if strings.HasPrefix(contentType, "text/css") { resp.Body = cssInjector.Inject(resp.Body, ctx.Req.Host) } else if strings.HasPrefix(contentType, "application/json") { // POC remove google ads on search if ctx.Req.Host == "www.google.fr" { // read body body, err := ioutil.ReadAll(resp.Body) if err != nil { ctx.Warnf("Pure - ERROR while reading body: %s", err) return resp } bodyPart := strings.Split(string(body), `/*""*/`) t := "" for _, p := range bodyPart { if strings.Contains(p, "commercial-unit") || strings.Contains(p, "tadsb") { continue } t = t + p + `/*""*/` } body = []byte(t) resp.Body = ioutil.NopCloser(bytes.NewBuffer(body)) } } return resp }) log.Fatal(http.ListenAndServe(*addr, proxy)) }