diff --git a/README.md b/README.md index 50d91efe..05b09316 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Introduction -[![GoDoc](https://godoc.org/github.com/elazarl/goproxy?status.svg)](https://godoc.org/github.com/elazarl/goproxy) -[![Join the chat at https://gitter.im/elazarl/goproxy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/elazarl/goproxy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![GoDoc](https://godoc.org/github.com/oec/goproxy?status.svg)](https://godoc.org/github.com/oec/goproxy) +[![Join the chat at https://gitter.im/oec/goproxy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/oec/goproxy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Package goproxy provides a customizable HTTP proxy library for Go (golang), @@ -27,7 +27,7 @@ before their development. ## Latest Stable Release -Get the latest goproxy from `gopkg.in/elazarl/goproxy.v1`. +Get the latest goproxy from `gopkg.in/oec/goproxy.v1`. # Why not Fiddler2? @@ -48,7 +48,7 @@ To get a taste of `goproxy`, a basic HTTP/HTTPS transparent proxy package main import ( - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" "log" "net/http" ) @@ -103,8 +103,8 @@ See additional examples in the examples directory. # What's New 1. Ability to `Hijack` CONNECT requests. See -[the eavesdropper example](https://github.com/elazarl/goproxy/blob/master/examples/goproxy-eavesdropper/main.go#L27) -2. Transparent proxy support for http/https including MITM certificate generation for TLS. See the [transparent example.](https://github.com/elazarl/goproxy/tree/master/examples/goproxy-transparent) +[the eavesdropper example](https://github.com/oec/goproxy/blob/master/examples/goproxy-eavesdropper/main.go#L27) +2. Transparent proxy support for http/https including MITM certificate generation for TLS. See the [transparent example.](https://github.com/oec/goproxy/tree/master/examples/goproxy-transparent) # License diff --git a/certs/openssl.cnf b/certs/openssl.cnf index 2fbb5e5f..629fdaed 100644 --- a/certs/openssl.cnf +++ b/certs/openssl.cnf @@ -10,7 +10,7 @@ basicConstraints = critical,CA:true distinguished_name = req_distinguished_name [ req_distinguished_name ] countryName = Country Name (2 letter code) -countryName_default = IL +countryName_default = DE countryName_min = 2 countryName_max = 2 @@ -35,5 +35,5 @@ commonName_default = goproxy.github.io commonName_max = 64 emailAddress = Email Address -emailAddress_default = elazarl@gmail.com +emailAddress_default = oec-go@kesim.org emailAddress_max = 64 diff --git a/counterecryptor_test.go b/counterecryptor_test.go index 7362180c..535dd629 100644 --- a/counterecryptor_test.go +++ b/counterecryptor_test.go @@ -9,7 +9,7 @@ import ( "math/rand" "testing" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) type RandSeedReader struct { diff --git a/ctx.go b/ctx.go index 70b4cf0f..2c0001ef 100644 --- a/ctx.go +++ b/ctx.go @@ -1,6 +1,7 @@ package goproxy import ( + "crypto/tls" "net/http" "regexp" ) @@ -20,6 +21,7 @@ type ProxyCtx struct { UserData interface{} // Will connect a request to a response Session int64 + signer Signer proxy *ProxyHttpServer } @@ -27,6 +29,8 @@ type RoundTripper interface { RoundTrip(req *http.Request, ctx *ProxyCtx) (*http.Response, error) } +type Signer func(ca *tls.Certificate, hostname []string) (*tls.Certificate, error) + type RoundTripperFunc func(req *http.Request, ctx *ProxyCtx) (*http.Response, error) func (f RoundTripperFunc) RoundTrip(req *http.Request, ctx *ProxyCtx) (*http.Response, error) { diff --git a/doc.go b/doc.go index 50aaa71f..b790e91d 100644 --- a/doc.go +++ b/doc.go @@ -67,7 +67,7 @@ we close the body of the original repsonse, and return a new 403 response with a Example use cases: -1. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-avgsize +1. https://github.com/oec/goproxy/tree/master/examples/goproxy-avgsize To measure the average size of an Html served in your site. One can ask all the QA team to access the website by a proxy, and the proxy will @@ -79,20 +79,20 @@ All requests to your web servers should be directed through the proxy, when the proxy will detect html pieces sent as a response to AJAX request, it'll send a warning email. -3. https://github.com/elazarl/goproxy/blob/master/examples/goproxy-httpdump/ +3. https://github.com/oec/goproxy/blob/master/examples/goproxy-httpdump/ Generate a real traffic to your website by real users using through proxy. Record the traffic, and try it again for more real load testing. -4. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-no-reddit-at-worktime +4. https://github.com/oec/goproxy/tree/master/examples/goproxy-no-reddit-at-worktime Will allow browsing to reddit.com between 8:00am and 17:00pm -5. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-jquery-version +5. https://github.com/oec/goproxy/tree/master/examples/goproxy-jquery-version Will warn if multiple versions of jquery are used in the same domain. -6. https://github.com/elazarl/goproxy/blob/master/examples/goproxy-upside-down-ternet/ +6. https://github.com/oec/goproxy/blob/master/examples/goproxy-upside-down-ternet/ Modifies image files in an HTTP response via goproxy's image extension found in ext/. diff --git a/examples/cascadeproxy/main.go b/examples/cascadeproxy/main.go index 194d03a9..4b597621 100644 --- a/examples/cascadeproxy/main.go +++ b/examples/cascadeproxy/main.go @@ -10,9 +10,9 @@ import ( "strings" "time" - "github.com/elazarl/goproxy/ext/auth" + "github.com/oec/goproxy/ext/auth" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) const ( diff --git a/examples/goproxy-basic/main.go b/examples/goproxy-basic/main.go index 22dc4a90..2fef7eae 100644 --- a/examples/goproxy-basic/main.go +++ b/examples/goproxy-basic/main.go @@ -1,10 +1,11 @@ package main import ( - "github.com/elazarl/goproxy" - "log" "flag" + "log" "net/http" + + "github.com/oec/goproxy" ) func main() { diff --git a/examples/goproxy-customca/cert.go b/examples/goproxy-customca/cert.go index f4fb578f..7c698105 100644 --- a/examples/goproxy-customca/cert.go +++ b/examples/goproxy-customca/cert.go @@ -4,7 +4,7 @@ import ( "crypto/tls" "crypto/x509" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) var caCert = []byte(`-----BEGIN CERTIFICATE----- diff --git a/examples/goproxy-customca/main.go b/examples/goproxy-customca/main.go index 11171ef6..a9082b49 100644 --- a/examples/goproxy-customca/main.go +++ b/examples/goproxy-customca/main.go @@ -5,7 +5,7 @@ import ( "log" "net/http" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) func main() { diff --git a/examples/goproxy-eavesdropper/main.go b/examples/goproxy-eavesdropper/main.go index 9d80653b..e82d4a20 100644 --- a/examples/goproxy-eavesdropper/main.go +++ b/examples/goproxy-eavesdropper/main.go @@ -8,7 +8,7 @@ import ( "net/http" "regexp" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) func orPanic(err error) { @@ -26,28 +26,28 @@ func main() { // enable curl -p for all hosts on port 80 proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*:80$"))). 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() - }() - clientBuf := bufio.NewReadWriter(bufio.NewReader(client), bufio.NewWriter(client)) - remote, err := net.Dial("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) + 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() + }() + clientBuf := bufio.NewReadWriter(bufio.NewReader(client), bufio.NewWriter(client)) + remote, err := net.Dial("tcp", req.URL.Host) orPanic(err) - orPanic(resp.Write(clientBuf.Writer)) - orPanic(clientBuf.Flush()) - } - }) + 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()) + } + }) verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") addr := flag.String("addr", ":8080", "proxy listen address") flag.Parse() diff --git a/examples/goproxy-httpdump/httpdump.go b/examples/goproxy-httpdump/httpdump.go index 62a9b882..2d54379e 100644 --- a/examples/goproxy-httpdump/httpdump.go +++ b/examples/goproxy-httpdump/httpdump.go @@ -15,8 +15,8 @@ import ( "sync" "time" - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/transport" + "github.com/oec/goproxy" + "github.com/oec/goproxy/transport" ) type FileStream struct { diff --git a/examples/goproxy-jquery-version/main.go b/examples/goproxy-jquery-version/main.go index a92dddea..b255d786 100644 --- a/examples/goproxy-jquery-version/main.go +++ b/examples/goproxy-jquery-version/main.go @@ -1,11 +1,12 @@ package main import ( - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/ext/html" "log" "net/http" "regexp" + + "github.com/oec/goproxy" + "github.com/oec/goproxy/ext/html" ) var ( diff --git a/examples/goproxy-no-reddit-at-worktime/noreddit.go b/examples/goproxy-no-reddit-at-worktime/noreddit.go index b1748459..b9f97af2 100644 --- a/examples/goproxy-no-reddit-at-worktime/noreddit.go +++ b/examples/goproxy-no-reddit-at-worktime/noreddit.go @@ -1,10 +1,11 @@ package main import ( - "github.com/elazarl/goproxy" "log" "net/http" "time" + + "github.com/oec/goproxy" ) func main() { diff --git a/examples/goproxy-sokeepalive/sokeepalive.go b/examples/goproxy-sokeepalive/sokeepalive.go index 9135e575..70fd6888 100644 --- a/examples/goproxy-sokeepalive/sokeepalive.go +++ b/examples/goproxy-sokeepalive/sokeepalive.go @@ -2,10 +2,11 @@ package main import ( "flag" - "github.com/elazarl/goproxy" "log" "net" "net/http" + + "github.com/oec/goproxy" ) func main() { diff --git a/examples/goproxy-sslstrip/sslstrip.go b/examples/goproxy-sslstrip/sslstrip.go index b7e2dc9e..1bd4ed2f 100644 --- a/examples/goproxy-sslstrip/sslstrip.go +++ b/examples/goproxy-sslstrip/sslstrip.go @@ -1,10 +1,11 @@ package main import ( - "github.com/elazarl/goproxy" - "log" "flag" + "log" "net/http" + + "github.com/oec/goproxy" ) func main() { @@ -13,7 +14,7 @@ func main() { flag.Parse() proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm) - proxy.OnRequest().DoFunc(func (req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { + proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { if req.URL.Scheme == "https" { req.URL.Scheme = "http" } diff --git a/examples/goproxy-stats/main.go b/examples/goproxy-stats/main.go index e4cde8d9..d2636a90 100644 --- a/examples/goproxy-stats/main.go +++ b/examples/goproxy-stats/main.go @@ -2,12 +2,13 @@ package main import ( "fmt" - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/ext/html" "io" "log" . "net/http" "time" + + "github.com/oec/goproxy" + "github.com/oec/goproxy/ext/html" ) type Count struct { diff --git a/examples/goproxy-transparent/README.md b/examples/goproxy-transparent/README.md index 7edb0989..bc7aefc2 100644 --- a/examples/goproxy-transparent/README.md +++ b/examples/goproxy-transparent/README.md @@ -4,7 +4,7 @@ This transparent example in goproxy is meant to show how to transparenty proxy a ## Why not explicit? -Transparent proxies are more difficult to maintain and setup from a server side, but they require no configuration on the client(s) which could be in unmanaged systems or systems that don't support a proxy configuration. See the [eavesdropper example](https://github.com/elazarl/goproxy/blob/master/examples/goproxy-eavesdropper/main.go) if you want to see an explicit proxy example. +Transparent proxies are more difficult to maintain and setup from a server side, but they require no configuration on the client(s) which could be in unmanaged systems or systems that don't support a proxy configuration. See the [eavesdropper example](https://github.com/oec/goproxy/blob/master/examples/goproxy-eavesdropper/main.go) if you want to see an explicit proxy example. ## Potential Issues @@ -14,4 +14,4 @@ If you're routing table allows for it, an explicit http request to goproxy will ## Routing Rules -Example routing rules are included in [proxy.sh](https://github.com/elazarl/goproxy/blob/master/examples/goproxy-transparent/proxy.sh) but are best when setup using your distribution's configuration. +Example routing rules are included in [proxy.sh](https://github.com/oec/goproxy/blob/master/examples/goproxy-transparent/proxy.sh) but are best when setup using your distribution's configuration. diff --git a/examples/goproxy-transparent/transparent.go b/examples/goproxy-transparent/transparent.go index b4134e23..ca8a9237 100644 --- a/examples/goproxy-transparent/transparent.go +++ b/examples/goproxy-transparent/transparent.go @@ -11,8 +11,7 @@ import ( "net/url" "regexp" - "github.com/elazarl/goproxy" - "github.com/inconshreveable/go-vhost" + "github.com/oec/goproxy" ) func orPanic(err error) { @@ -46,28 +45,28 @@ func main() { HandleConnect(goproxy.AlwaysMitm) proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*:80$"))). 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() - }() - 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) + 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() + }() + clientBuf := bufio.NewReadWriter(bufio.NewReader(client), bufio.NewWriter(client)) + remote, err := connectDial(proxy, "tcp", req.URL.Host) orPanic(err) - orPanic(resp.Write(clientBuf.Writer)) - orPanic(clientBuf.Flush()) - } - }) + 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()) + } + }) go func() { log.Fatalln(http.ListenAndServe(*http_addr, proxy)) diff --git a/examples/goproxy-upside-down-ternet/main.go b/examples/goproxy-upside-down-ternet/main.go index 4b683fd3..3cc6f0d1 100644 --- a/examples/goproxy-upside-down-ternet/main.go +++ b/examples/goproxy-upside-down-ternet/main.go @@ -1,11 +1,12 @@ package main import ( - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/ext/image" "image" "log" "net/http" + + "github.com/oec/goproxy" + "github.com/oec/goproxy/ext/image" ) func main() { diff --git a/examples/goproxy-yui-minify/yui.go b/examples/goproxy-yui-minify/yui.go index 0e7eadbb..5fce756d 100644 --- a/examples/goproxy-yui-minify/yui.go +++ b/examples/goproxy-yui-minify/yui.go @@ -22,7 +22,7 @@ import ( "path" "strings" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) func main() { diff --git a/ext/auth/basic.go b/ext/auth/basic.go index a433f2d0..c82680ef 100644 --- a/ext/auth/basic.go +++ b/ext/auth/basic.go @@ -7,7 +7,7 @@ import ( "net/http" "strings" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" ) var unauthorizedMsg = []byte("407 Proxy Authentication Required") diff --git a/ext/auth/basic_test.go b/ext/auth/basic_test.go index 792d789b..86c09c6f 100644 --- a/ext/auth/basic_test.go +++ b/ext/auth/basic_test.go @@ -14,8 +14,8 @@ import ( "sync/atomic" "testing" - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/ext/auth" + "github.com/oec/goproxy" + "github.com/oec/goproxy/ext/auth" ) type ConstantHanlder string diff --git a/ext/html/html.go b/ext/html/html.go index 2dc294ec..69d9ca16 100644 --- a/ext/html/html.go +++ b/ext/html/html.go @@ -9,7 +9,7 @@ import ( "net/http" "strings" - "github.com/elazarl/goproxy" + "github.com/oec/goproxy" "github.com/rogpeppe/go-charset/charset" _ "github.com/rogpeppe/go-charset/data" ) diff --git a/ext/html/html_test.go b/ext/html/html_test.go index 9c876f75..b6c19cc2 100644 --- a/ext/html/html_test.go +++ b/ext/html/html_test.go @@ -1,13 +1,14 @@ package goproxy_html_test import ( - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/ext/html" "io/ioutil" "net/http" "net/http/httptest" "net/url" "testing" + + "github.com/oec/goproxy" + "github.com/oec/goproxy/ext/html" ) type ConstantServer int diff --git a/ext/image/image.go b/ext/image/image.go index cd9ac8a4..e74b7d63 100644 --- a/ext/image/image.go +++ b/ext/image/image.go @@ -2,14 +2,15 @@ package goproxy_image import ( "bytes" - . "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/regretable" "image" _ "image/gif" "image/jpeg" "image/png" "io/ioutil" "net/http" + + . "github.com/oec/goproxy" + "github.com/oec/goproxy/regretable" ) var RespIsImage = ContentTypeIs("image/gif", diff --git a/fd_test.go b/fd_test.go new file mode 100644 index 00000000..ab8e61aa --- /dev/null +++ b/fd_test.go @@ -0,0 +1,73 @@ +package goproxy_test + +// build +linux + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "os" + "strings" + "testing" + + "github.com/oec/goproxy" +) + +func oneShotProxyNoKeepalive(proxy *goproxy.ProxyHttpServer, t *testing.T) (client *http.Client, s *httptest.Server) { + s = httptest.NewServer(proxy) + + proxyUrl, _ := url.Parse(s.URL) + tr := &http.Transport{TLSClientConfig: acceptAllCerts, Proxy: http.ProxyURL(proxyUrl), DisableKeepAlives: true} + client = &http.Client{Transport: tr} + return +} + +func printfds(msg string, t *testing.T) int { + fd, _ := os.Open("/proc/self/fd") + fds, _ := fd.Readdir(-1) + fd.Close() + names := []string{} + links := []string{} + for _, f := range fds { + names = append(names, f.Name()) + link, _ := os.Readlink("/proc/self/fd/" + f.Name()) + links = append(links, link) + } + lines := []string{} + for i := range names { + lines = append(lines, fmt.Sprintf("%2v → %v", names[i], links[i])) + } + t.Logf("[%s] /proc/self/fd:\n\t%s", msg, strings.Join(lines, "\n\t")) + return len(fds) +} +func TestFDCountConnect(t *testing.T) { + + proxy := goproxy.NewProxyHttpServer() + althttps := httptest.NewTLSServer(ConstantHanlder("althttps")) + + proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { + u, _ := url.Parse(althttps.URL) + printfds("in handler", t) + return goproxy.OkConnect, u.Host + }) + + before := printfds("before", t) + + for i := range "12345" { + pre := fmt.Sprintf("call %d", i+1) + printfds(pre+", before", t) + client, l := oneShotProxyNoKeepalive(proxy, t) + if resp := string(getOrFail(https.URL+"/alturl", client, t)); resp != "althttps" { + t.Error("Proxy should redirect CONNECT requests to local althttps server, expected 'althttps' got ", resp) + } + l.Close() + printfds(pre+", after", t) + } + + after := printfds("after", t) + + if before != after { + t.Errorf("#FD before ≠ after! FD before: %d, after: %d", before, after) + } +} diff --git a/https.go b/https.go index 5498f8b7..ebe9d940 100644 --- a/https.go +++ b/https.go @@ -65,7 +65,10 @@ func (proxy *ProxyHttpServer) connectDial(network, addr string) (c net.Conn, err } func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request) { - ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy} + ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy, signer: signHost} + if proxy.Signer != nil { + ctx.signer = proxy.Signer + } hij, ok := w.(http.Hijacker) if !ok { @@ -105,8 +108,16 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request targetTCP, targetOK := targetSiteCon.(*net.TCPConn) proxyClientTCP, clientOK := proxyClient.(*net.TCPConn) if targetOK && clientOK { - go copyAndClose(ctx, targetTCP, proxyClientTCP) - go copyAndClose(ctx, proxyClientTCP, targetTCP) + go func() { + var wg sync.WaitGroup + wg.Add(2) + go copyAndClose(ctx, targetTCP, proxyClientTCP, &wg) + go copyAndClose(ctx, proxyClientTCP, targetTCP, &wg) + wg.Wait() + proxyClient.Close() + targetSiteCon.Close() + + }() } else { go func() { var wg sync.WaitGroup @@ -293,13 +304,14 @@ func copyOrWarn(ctx *ProxyCtx, dst io.Writer, src io.Reader, wg *sync.WaitGroup) wg.Done() } -func copyAndClose(ctx *ProxyCtx, dst, src *net.TCPConn) { +func copyAndClose(ctx *ProxyCtx, dst, src *net.TCPConn, wg *sync.WaitGroup) { if _, err := io.Copy(dst, src); err != nil { ctx.Warnf("Error copying to client: %s", err) } dst.CloseWrite() src.CloseRead() + wg.Done() } func dialerFromEnv(proxy *ProxyHttpServer) func(network, addr string) (net.Conn, error) { @@ -408,14 +420,21 @@ func (proxy *ProxyHttpServer) NewConnectDialToProxyWithHandler(https_proxy strin func TLSConfigFromCA(ca *tls.Certificate) func(host string, ctx *ProxyCtx) (*tls.Config, error) { return func(host string, ctx *ProxyCtx) (*tls.Config, error) { + var err error + var cert *tls.Certificate + + hostname := stripPort(host) config := *defaultTLSConfig - ctx.Logf("signing for %s", stripPort(host)) - cert, err := signHost(*ca, []string{stripPort(host)}) - if err != nil { - ctx.Warnf("Cannot sign host certificate with provided CA: %s", err) - return nil, err + ctx.Logf("signing for %s", hostname) + cert, err = ctx.signer(ca, []string{hostname}) + + if cert == nil { + if err != nil { + ctx.Warnf("Cannot sign host certificate with provided CA: %s", err) + return nil, err + } } - config.Certificates = append(config.Certificates, cert) + config.Certificates = append(config.Certificates, *cert) return &config, nil } } diff --git a/proxy.go b/proxy.go index 93359000..e411f75e 100644 --- a/proxy.go +++ b/proxy.go @@ -29,6 +29,7 @@ type ProxyHttpServer struct { // ConnectDial will be used to create TCP connections for CONNECT requests // if nil Tr.Dial will be used ConnectDial func(network string, addr string) (net.Conn, error) + Signer Signer } var hasPort = regexp.MustCompile(`:\d+$`) diff --git a/proxy_test.go b/proxy_test.go index 8117517f..9ba0bb29 100644 --- a/proxy_test.go +++ b/proxy_test.go @@ -18,8 +18,8 @@ import ( "strings" "testing" - "github.com/elazarl/goproxy" - "github.com/elazarl/goproxy/ext/image" + "github.com/oec/goproxy" + "github.com/oec/goproxy/ext/image" ) var acceptAllCerts = &tls.Config{InsecureSkipVerify: true} diff --git a/regretable/regretreader_test.go b/regretable/regretreader_test.go index 55969747..48eda1cc 100644 --- a/regretable/regretreader_test.go +++ b/regretable/regretreader_test.go @@ -2,11 +2,12 @@ package regretable_test import ( "bytes" - . "github.com/elazarl/goproxy/regretable" "io" "io/ioutil" "strings" "testing" + + . "github.com/oec/goproxy/regretable" ) func TestRegretableReader(t *testing.T) { diff --git a/signer.go b/signer.go index c01ec76d..6984c6a5 100644 --- a/signer.go +++ b/signer.go @@ -32,7 +32,7 @@ func hashSortedBigInt(lst []string) *big.Int { var goproxySignerVersion = ":goroxy1" -func signHost(ca tls.Certificate, hosts []string) (cert tls.Certificate, err error) { +func signHost(ca *tls.Certificate, hosts []string) (cert *tls.Certificate, err error) { var x509ca *x509.Certificate // Use the provided ca and not the global GoproxyCa for certificate generation. @@ -81,7 +81,7 @@ func signHost(ca tls.Certificate, hosts []string) (cert tls.Certificate, err err if derBytes, err = x509.CreateCertificate(&csprng, &template, x509ca, &certpriv.PublicKey, ca.PrivateKey); err != nil { return } - return tls.Certificate{ + return &tls.Certificate{ Certificate: [][]byte{derBytes, ca.Certificate[0]}, PrivateKey: certpriv, }, nil diff --git a/signer_test.go b/signer_test.go index d0e24d29..03395a41 100644 --- a/signer_test.go +++ b/signer_test.go @@ -38,14 +38,14 @@ func getBrowser(args []string) string { } func TestSingerTls(t *testing.T) { - cert, err := signHost(GoproxyCa, []string{"example.com", "1.1.1.1", "localhost"}) + cert, err := signHost(&GoproxyCa, []string{"example.com", "1.1.1.1", "localhost"}) orFatal("singHost", err, t) cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) orFatal("ParseCertificate", err, t) expected := "key verifies with Go" server := httptest.NewUnstartedServer(ConstantHanlder(expected)) defer server.Close() - server.TLS = &tls.Config{Certificates: []tls.Certificate{cert, GoproxyCa}} + server.TLS = &tls.Config{Certificates: []tls.Certificate{*cert, GoproxyCa}} server.TLS.BuildNameToCertificate() server.StartTLS() certpool := x509.NewCertPool() @@ -71,7 +71,7 @@ func TestSingerTls(t *testing.T) { } func TestSingerX509(t *testing.T) { - cert, err := signHost(GoproxyCa, []string{"example.com", "1.1.1.1", "localhost"}) + cert, err := signHost(&GoproxyCa, []string{"example.com", "1.1.1.1", "localhost"}) orFatal("singHost", err, t) cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) orFatal("ParseCertificate", err, t)