func main() { bl := Create() proxy := goproxy.NewProxyHttpServer() proxy.Verbose = false proxy.OnRequest(goproxy.DstHostIs("nogame")).DoFunc(bl.conf) proxy.OnRequest().DoFunc(bl.checkHost) log.Fatal(http.ListenAndServe(":8080", proxy)) }
func main() { proxy := goproxy.NewProxyHttpServer() proxy.OnRequest(goproxy.DstHostIs("www.reddit.com")).DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { if h, _, _ := time.Now().Clock(); h >= 8 && h <= 17 { return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusForbidden, "Don't waste your time!") } return r, nil }) log.Fatalln(http.ListenAndServe(":8080", proxy)) }
func main() { flag.Parse() init_datastore(*datastore) proxy := goproxy.NewProxyHttpServer() proxy.Verbose = *verbose // Requests for eccaHandlerHost allow the user to select and create certificates // This handler sends a response to the client, never upstream. proxy.OnRequest(goproxy.DstHostIs(eccaHandlerHost)).DoFunc(eccaHandler) // All other requests (where the user want to go to) are handled here. // When this needs an account, it redirects the client to the eccaHandler above. proxy.OnRequest().DoFunc(eccaProxy) // Decode any messages when we have the "Eccentric-Authentication" header set to "decrypt" proxy.OnResponse().DoFunc(DecodeMessages) // Verify any messages where we have the Eccentric-Authentication header set to "verification" proxy.OnResponse().DoFunc(VerifyMessages) // Change the redirect location (from https) to http so the client gets back to us. proxy.OnResponse().DoFunc(ChangeToHttp) restartAllTorListeners() log.Printf("Starting proxy access at [::1]:%d and at 127.0.0.1:%d\n", *port, *port) log.Printf("Configure your browser to use one of those as http-proxy.\n") log.Printf("Then browse to http://dating.wtmnd.nl:10443/\n") log.Printf("Use http (not https) to benefit from this proxy.\n") log.Printf("For assistence, please see: http://eccentric-authentication.org/contact.html\n") server6 := &http.Server{ Addr: fmt.Sprintf("[::1]:%d", *port), Handler: proxy, } // TODO: disable KeepAlives when your golang version supports it //server6.SetKeepAlivesEnabled(false) server4 := &http.Server{ Addr: fmt.Sprintf("127.0.0.1:%d", *port), Handler: proxy, } // TODO: disable KeepAlives when your golang version supports it //server4.SetKeepAlivesEnabled(false) // run or die. Try ipv6 first go server6.ListenAndServe() log.Fatal(server4.ListenAndServe()) }
func main() { proxy := goproxy.NewProxyHttpServer() proxy.Verbose = *verbose if proxy.Verbose { log.Printf("Server starting up! - configured to listen on http interface %s and https interface %s with hostname %s", *http_addr, *https_addr, *proxy_hostname) } proxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if req.Host == "" { fmt.Fprintln(w, "Cannot handle requests without Host header, e.g., HTTP 1.0") return } req.URL.Scheme = "http" req.URL.Host = req.Host proxy.ServeHTTP(w, req) }) cert, err := tls.LoadX509KeyPair("ca.crt", "ca.key") if err != nil { log.Fatalf("Unable to load certificate - %v", err) } proxy.OnRequest(goproxy.DstHostIs(*proxy_hostname)).DoFunc(whitelistService) proxy.OnRequest().DoFunc(whiteListHandler) proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { ip, _, err := net.SplitHostPort(ctx.Req.RemoteAddr) if err != nil { panic(fmt.Sprintf("userip: %q is not IP:port", ctx.Req.RemoteAddr)) } userIP := net.ParseIP(ip) if userIP == nil { panic(fmt.Sprintf("userip: %q is not IP", ip)) } log.Printf("Handled connect from ip - %s - for host %s", ip, host) if err != nil { log.Printf("Error creating URL for host %s", host) } else if host != *proxy_hostname && wlm.Check(userIP, Site{ URL: ctx.Req.URL, Referer: "pressl", }) { // don't tear down the SSL session return &goproxy.ConnectAction{ Action: goproxy.ConnectAccept, }, host + ":443" } return &goproxy.ConnectAction{ Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&cert), }, host + ":443" }) go func() { log.Fatalln(http.ListenAndServe(*http_addr, proxy)) }() // listen to the TLS ClientHello but make it a CONNECT request instead ln, err := net.Listen("tcp", *https_addr) if err != nil { log.Fatalf("Error listening for https connections - %v", err) } for { c, err := ln.Accept() if err != nil { log.Printf("Error accepting new connection - %v", err) continue } go func(c net.Conn) { tlsConn, err := vhost.TLS(c) if err != nil { log.Printf("Error accepting new connection - %v", err) } host := tlsConn.Host() if host == "" { log.Printf("Cannot support non-SNI enabled clients, attempting to make an educated guess") // TODO: add other options than dnsmasq through journald cmd := exec.Command( "/usr/bin/sudo", "/usr/bin/journalctl", "-n 20", ) output, err := cmd.CombinedOutput() if err != nil { log.Printf("Could not find a recent DNS lookup in the dnsmasq logs - %v", err) } else { lines := bufio.NewScanner(bytes.NewReader(output)) requestor, _, _ := net.SplitHostPort(c.RemoteAddr().String()) for lines.Scan() { if strings.Contains(lines.Text(), requestor) { split := strings.Split(lines.Text(), " ") if len(split) >= 7 { host = split[6] break } } } } if host == "" { // At this point we're going to error, give the client a hint as to why host = "yourclientdoesnotsuppportsni" } log.Printf("Guessing with %s", host) } connectReq := &http.Request{ RemoteAddr: c.RemoteAddr().String(), Method: "CONNECT", URL: &url.URL{ Opaque: host, Host: host, }, Host: host, Header: make(http.Header), } log.Printf("Making faux CONNECT request with URL - %s", connectReq.URL) log.Printf("Request.URL.Host - %v", connectReq.URL.Host) resp := dumbResponseWriter{tlsConn} proxy.ServeHTTP(resp, connectReq) }(c) } }
func myproxy() { pname := "HttpProxy4U" pver := "1.0.0" // get current working directory cwd, err := os.Getwd() checkError(err) // parse input parameters var port, wlistFile, blistFile, rulesFile, aname, apwd, tdir, rdir string var verbose int var interval int64 flag.StringVar(&port, "port", ":9998", "Proxy port number") flag.StringVar(&tdir, "tmpl-dir", filepath.Join(cwd, "static/tmpl"), "Template directory") flag.StringVar(&rdir, "rule-dir", filepath.Join(cwd, "static/rules"), "Rules directory") flag.StringVar(&wlistFile, "whitelist", filepath.Join(rdir, "whitelist.txt"), "White list file") flag.StringVar(&blistFile, "blacklist", filepath.Join(rdir, "blacklist.txt"), "Black list file") flag.StringVar(&rulesFile, "rules", filepath.Join(rdir, "rules.txt"), "Rules list file") flag.IntVar(&verbose, "verbose", 0, "logging level") flag.Int64Var(&interval, "interval", 300, "reload interval") flag.StringVar(&aname, "login", "admin", "Admin login name") flag.StringVar(&apwd, "password", "test", "Admin password") flag.Parse() // init proxy server proxy := goproxy.NewProxyHttpServer() proxy.Verbose = false // true if verbose > 1 { proxy.Verbose = true } msg := fmt.Sprintf("port=%s, verbose=%d, wlist=%s, blist=%s, rule=%s", port, verbose, wlistFile, blistFile, rulesFile) log.Println(msg) // read out client settings whitelist := readTxtFile(wlistFile) log.Println("White list:", whitelist) blacklist := readTxtFile(blistFile) log.Println("Black list:", blacklist) ruleslist := parseRules(readCSVFile(rulesFile)) log.Println("Rules list:", ruleslist) lastRead := time.Now().UTC().Unix() // local variables var rules []string for _, r := range ruleslist { rules = append(rules, r.ToCSV()) } tcss := "main.tmpl.css" tmplData := map[string]interface{}{} css := parseTmpl(tdir, tcss, tmplData) tfooter := "footer.tmpl.html" tmplData["package"] = pname tmplData["version"] = pver tmplData["css"] = css footer := parseTmpl(tdir, tfooter, tmplData) tmplData["whitelist"] = strings.Join(whitelist, "\n") tmplData["blacklist"] = strings.Join(blacklist, "\n") tmplData["ruleslist"] = strings.Join(rules, "\n") tmplData["footer"] = footer // admin handler // proxy.OnRequest(goproxy.IsLocalHost).DoFunc( proxy.OnRequest(goproxy.DstHostIs("")).DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { path := html.EscapeString(r.URL.Path) log.Println("admin interface", path) if path == "/admin" { tauth := "auth.tmpl.html" u := r.FormValue("login") p := r.FormValue("password") if u == aname && p == apwd { log.Println("access admin interface") } else { return r, goproxy.NewResponse(r, goproxy.ContentTypeHtml, http.StatusOK, parseTmpl(tdir, tauth, tmplData)) } tpage := "admin.tmpl.html" return r, goproxy.NewResponse(r, goproxy.ContentTypeHtml, http.StatusOK, parseTmpl(tdir, tpage, tmplData)) } else if path == "/save" { wlist := strip(r.FormValue("whitelist")) blist := strip(r.FormValue("blacklist")) rlist := strip(r.FormValue("ruleslist")) saveList(wlistFile, wlist) saveList(blistFile, blist) saveList(rulesFile, rlist) tmplData["whitelist"] = wlist tmplData["blacklist"] = blist tmplData["ruleslist"] = rlist tpage := "save.tmpl.html" tmplData["body"] = fmt.Sprintf("New rules has been saved on %s", time.Now()) return r, goproxy.NewResponse(r, goproxy.ContentTypeHtml, http.StatusOK, parseTmpl(tdir, tpage, tmplData)) } else { tpage := "index.tmpl.html" return r, goproxy.NewResponse(r, goproxy.ContentTypeHtml, http.StatusOK, parseTmpl(tdir, tpage, tmplData)) } }) // restrict certain sites on time based rules for _, rule := range ruleslist { proxy.OnRequest(goproxy.DstHostIs(rule.Url)).DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { // reload maps if necessary unix := time.Now().UTC().Unix() if unix-lastRead > interval { ruleslist := parseRules(readCSVFile(rulesFile)) if verbose > 0 { log.Println("Rules list:", ruleslist) } lastRead = unix } h, _, _ := time.Now().Clock() if h < rule.MinHour && h > rule.MaxHour { return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusForbidden, "Your exceed your time window on this site") } return r, nil }) } // filter white/black lists proxy.OnRequest().DoFunc( func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { // reload maps if necessary unix := time.Now().UTC().Unix() if unix-lastRead > interval { whitelist := readTxtFile(wlistFile) blacklist := readTxtFile(blistFile) if verbose > 0 { log.Println("Reload white list:", whitelist) log.Println("Reload black list:", blacklist) } lastRead = unix } pat1 := strings.Join(whitelist, "|") expect1 := false // match=false means site not in whitelist match1, err := regexp.MatchString(pat1, r.URL.Host) if err != nil { log.Println("ERROR: fail in match", pat1, r.URL.Host) } pat2 := strings.Join(blacklist, "|") expect2 := true // match=true means site is in blacklist match2, err := regexp.MatchString(pat2, r.URL.Host) if err != nil { log.Println("ERROR: fail in match", pat2, r.URL.Host) } if match2 == expect2 || match1 == expect1 { path := html.EscapeString(r.URL.Path) if verbose > 0 { log.Println(r.URL.Host, path) } return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusForbidden, "This site is not accessible to you") } return r, nil }) // start and log http proxy server log.Fatal(http.ListenAndServe(port, proxy)) }
func TestHttpsMitmURLRewrite(t *testing.T) { scheme := "https" testCases := []struct { Host string RawPath string AddOpaque bool }{ { Host: "example.com", RawPath: "/blah/v1/data/realtime", AddOpaque: true, }, { Host: "example.com:443", RawPath: "/blah/v1/data/realtime?encodedURL=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile", }, { Host: "example.com:443", RawPath: "/blah/v1/data/realtime?unencodedURL=https://www.googleapis.com/auth/userinfo.profile", }, } for _, tc := range testCases { proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm) proxy.OnRequest(goproxy.DstHostIs(tc.Host)).DoFunc( func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { return nil, goproxy.TextResponse(req, "Dummy response") }) client, s := oneShotProxy(proxy, t) defer s.Close() fullURL := scheme + "://" + tc.Host + tc.RawPath req, err := http.NewRequest("GET", fullURL, nil) if err != nil { t.Fatal(err) } if tc.AddOpaque { req.URL.Scheme = scheme req.URL.Opaque = "//" + tc.Host + tc.RawPath } resp, err := client.Do(req) if err != nil { t.Fatal(err) } b, err := ioutil.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { t.Fatal(err) } body := string(b) if body != "Dummy response" { t.Errorf("Expected proxy to return dummy body content but got %s", body) } if resp.StatusCode != http.StatusAccepted { t.Errorf("Expected status: %d, got: %d", http.StatusAccepted, resp.StatusCode) } } }