func initMimtConnect() { mitmConnect = &goproxy.ConnectAction{ Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&conf.SslCert), } }
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 NewTLSConfigCache(ca *tls.Certificate) *TLSConfigCache { return &TLSConfigCache{ cfgBuilder: goproxy.TLSConfigFromCA(ca), cache: map[string]CachedConfig{}, } }