diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 04d8d9b..49de7cb 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -36,6 +36,11 @@ "Comment": "v5", "Rev": "7b2428fec40033549c68f54e26e89e7ca9a9ce31" }, + { + "ImportPath": "github.com/coreos/goproxy", + "Comment": "v1.0-84-gd49035e", + "Rev": "d49035e9433ee1038960c346999fdcb12e8704b5" + }, { "ImportPath": "github.com/coreos/pkg/capnslog", "Rev": "1914e367e85eaf0c25d495b48e060dfe6190f8d0" @@ -72,11 +77,6 @@ "ImportPath": "github.com/pmezard/go-difflib/difflib", "Rev": "792786c7400a136282c1664665ae0a8db921c6c2" }, - { - "ImportPath": "github.com/quentin-m/goproxy", - "Comment": "v1.0-78-g68c684f", - "Rev": "68c684f60e7acc501496bf6c9752c286eb8044c7" - }, { "ImportPath": "github.com/stretchr/testify/assert", "Comment": "v1.1.3-12-gc5d7a69", diff --git a/jwt/proxy_handlers.go b/jwt/proxy_handlers.go index 28e3d2b..6955664 100644 --- a/jwt/proxy_handlers.go +++ b/jwt/proxy_handlers.go @@ -23,7 +23,7 @@ import ( "strings" log "github.com/Sirupsen/logrus" - "github.com/quentin-m/goproxy" + "github.com/coreos/goproxy" "github.com/coreos/jwtproxy/config" "github.com/coreos/jwtproxy/jwt/claims" diff --git a/proxy/proxy.go b/proxy/proxy.go index fb2f94f..f9fafa4 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -28,7 +28,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/coreos/jwtproxy/stop" - "github.com/quentin-m/goproxy" + "github.com/coreos/goproxy" "github.com/tylerb/graceful" ) diff --git a/vendor/github.com/quentin-m/goproxy/.gitignore b/vendor/github.com/coreos/goproxy/.gitignore similarity index 100% rename from vendor/github.com/quentin-m/goproxy/.gitignore rename to vendor/github.com/coreos/goproxy/.gitignore diff --git a/vendor/github.com/quentin-m/goproxy/LICENSE b/vendor/github.com/coreos/goproxy/LICENSE similarity index 100% rename from vendor/github.com/quentin-m/goproxy/LICENSE rename to vendor/github.com/coreos/goproxy/LICENSE diff --git a/vendor/github.com/quentin-m/goproxy/README.md b/vendor/github.com/coreos/goproxy/README.md similarity index 100% rename from vendor/github.com/quentin-m/goproxy/README.md rename to vendor/github.com/coreos/goproxy/README.md diff --git a/vendor/github.com/quentin-m/goproxy/actions.go b/vendor/github.com/coreos/goproxy/actions.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/actions.go rename to vendor/github.com/coreos/goproxy/actions.go diff --git a/vendor/github.com/quentin-m/goproxy/all.bash b/vendor/github.com/coreos/goproxy/all.bash similarity index 100% rename from vendor/github.com/quentin-m/goproxy/all.bash rename to vendor/github.com/coreos/goproxy/all.bash diff --git a/vendor/github.com/quentin-m/goproxy/ca.pem b/vendor/github.com/coreos/goproxy/ca.pem similarity index 100% rename from vendor/github.com/quentin-m/goproxy/ca.pem rename to vendor/github.com/coreos/goproxy/ca.pem diff --git a/vendor/github.com/quentin-m/goproxy/certs.go b/vendor/github.com/coreos/goproxy/certs.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/certs.go rename to vendor/github.com/coreos/goproxy/certs.go diff --git a/vendor/github.com/quentin-m/goproxy/chunked.go b/vendor/github.com/coreos/goproxy/chunked.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/chunked.go rename to vendor/github.com/coreos/goproxy/chunked.go diff --git a/vendor/github.com/quentin-m/goproxy/counterecryptor.go b/vendor/github.com/coreos/goproxy/counterecryptor.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/counterecryptor.go rename to vendor/github.com/coreos/goproxy/counterecryptor.go diff --git a/vendor/github.com/quentin-m/goproxy/ctx.go b/vendor/github.com/coreos/goproxy/ctx.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/ctx.go rename to vendor/github.com/coreos/goproxy/ctx.go diff --git a/vendor/github.com/quentin-m/goproxy/dispatcher.go b/vendor/github.com/coreos/goproxy/dispatcher.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/dispatcher.go rename to vendor/github.com/coreos/goproxy/dispatcher.go diff --git a/vendor/github.com/quentin-m/goproxy/doc.go b/vendor/github.com/coreos/goproxy/doc.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/doc.go rename to vendor/github.com/coreos/goproxy/doc.go diff --git a/vendor/github.com/quentin-m/goproxy/https.go b/vendor/github.com/coreos/goproxy/https.go similarity index 96% rename from vendor/github.com/quentin-m/goproxy/https.go rename to vendor/github.com/coreos/goproxy/https.go index 2ff4d6a..a9fa6ad 100644 --- a/vendor/github.com/quentin-m/goproxy/https.go +++ b/vendor/github.com/coreos/goproxy/https.go @@ -23,6 +23,7 @@ const ( ConnectMitm ConnectHijack ConnectHTTPMitm + ConnectProxyAuthHijack ) var ( @@ -164,6 +165,7 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request } defer rawClientTls.Close() clientTlsReader := bufio.NewReader(rawClientTls) + for !isEof(clientTlsReader) { req, err := http.ReadRequest(clientTlsReader) if err != nil && err != io.EOF { @@ -173,6 +175,7 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request ctx.Warnf("Cannot read TLS request from mitm'd client %v %v", r.Host, err) return } + req.RemoteAddr = r.RemoteAddr // since we're converting the request, need to carry over the original connecting IP as well ctx.Logf("req %v", r.Host) req.URL, err = url.Parse("https://" + r.Host + req.URL.String()) @@ -183,6 +186,11 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request req, resp := proxy.filterRequest(req, ctx) if resp == nil { + if isWebSocketRequest(req) { + ctx.Logf("Request looks like websocket upgrade.") + proxy.serveWebsocketTLS(ctx, w, req, tlsConfig, rawClientTls) + return + } if err != nil { ctx.Warnf("Illegal URL %s", "https://"+r.Host+req.URL.Path) return @@ -195,6 +203,7 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request } ctx.Logf("resp %v", resp.Status) } + resp = proxy.filterResponse(resp, ctx) text := resp.Status statusCode := strconv.Itoa(resp.StatusCode) + " " @@ -234,6 +243,9 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request } ctx.Logf("Exiting on EOF") }() + case ConnectProxyAuthHijack: + proxyClient.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\n")) + todo.Hijack(r, proxyClient, ctx) case ConnectReject: if ctx.Resp != nil { if err := ctx.Resp.Write(proxyClient); err != nil { @@ -313,7 +325,7 @@ func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(net return c, nil } } - if u.Scheme == "https" { + if u.Scheme == "https" || u.Scheme == "wss" { if strings.IndexRune(u.Host, ':') == -1 { u.Host += ":443" } diff --git a/vendor/github.com/quentin-m/goproxy/key.pem b/vendor/github.com/coreos/goproxy/key.pem similarity index 100% rename from vendor/github.com/quentin-m/goproxy/key.pem rename to vendor/github.com/coreos/goproxy/key.pem diff --git a/vendor/github.com/quentin-m/goproxy/proxy.go b/vendor/github.com/coreos/goproxy/proxy.go similarity index 97% rename from vendor/github.com/quentin-m/goproxy/proxy.go rename to vendor/github.com/coreos/goproxy/proxy.go index 4901f67..648adc7 100644 --- a/vendor/github.com/quentin-m/goproxy/proxy.go +++ b/vendor/github.com/coreos/goproxy/proxy.go @@ -107,7 +107,6 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) proxy.NonproxyHandler.ServeHTTP(w, r) return } - r, resp := proxy.filterRequest(r, ctx) if resp == nil { @@ -115,6 +114,11 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) panic("ReverseProxy did not rewrite request's Scheme or Host") } + if isWebSocketRequest(r) { + ctx.Logf("Request looks like websocket upgrade.") + proxy.serveWebsocket(ctx, w, r) + } + removeProxyHeaders(ctx, r) resp, err = ctx.RoundTrip(r) if err != nil { diff --git a/vendor/github.com/quentin-m/goproxy/responses.go b/vendor/github.com/coreos/goproxy/responses.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/responses.go rename to vendor/github.com/coreos/goproxy/responses.go diff --git a/vendor/github.com/quentin-m/goproxy/signer.go b/vendor/github.com/coreos/goproxy/signer.go similarity index 100% rename from vendor/github.com/quentin-m/goproxy/signer.go rename to vendor/github.com/coreos/goproxy/signer.go diff --git a/vendor/github.com/coreos/goproxy/websocket.go b/vendor/github.com/coreos/goproxy/websocket.go new file mode 100644 index 0000000..2a96991 --- /dev/null +++ b/vendor/github.com/coreos/goproxy/websocket.go @@ -0,0 +1,121 @@ +package goproxy + +import ( + "bufio" + "crypto/tls" + "io" + "net/http" + "net/url" + "strings" +) + +func headerContains(header http.Header, name string, value string) bool { + for _, v := range header[name] { + for _, s := range strings.Split(v, ",") { + if strings.EqualFold(value, strings.TrimSpace(s)) { + return true + } + } + } + return false +} + +func isWebSocketRequest(r *http.Request) bool { + return headerContains(r.Header, "Connection", "upgrade") && + headerContains(r.Header, "Upgrade", "websocket") +} + +func (proxy *ProxyHttpServer) serveWebsocketTLS(ctx *ProxyCtx, w http.ResponseWriter, req *http.Request, tlsConfig *tls.Config, clientConn *tls.Conn) { + targetURL := url.URL{Scheme: "wss", Host: req.URL.Host, Path: req.URL.Path} + + // Connect to upstream + targetConn, err := tls.Dial("tcp", targetURL.Host, tlsConfig) + if err != nil { + ctx.Warnf("Error dialing target site: %v", err) + return + } + defer targetConn.Close() + + // Perform handshake + if err := proxy.websocketHandshake(ctx, req, targetConn, clientConn); err != nil { + ctx.Warnf("Websocket handshake error: %v", err) + return + } + + // Proxy wss connection + proxy.proxyWebsocket(ctx, targetConn, clientConn) +} + +func (proxy *ProxyHttpServer) serveWebsocket(ctx *ProxyCtx, w http.ResponseWriter, req *http.Request) { + targetURL := url.URL{Scheme: "ws", Host: req.URL.Host, Path: req.URL.Path} + + targetConn, err := proxy.connectDial("tcp", targetURL.Host) + if err != nil { + ctx.Warnf("Error dialing target site: %v", err) + return + } + defer targetConn.Close() + + // Connect to Client + hj, ok := w.(http.Hijacker) + if !ok { + panic("httpserver does not support hijacking") + } + clientConn, _, err := hj.Hijack() + if err != nil { + ctx.Warnf("Hijack error: %v", err) + return + } + + // Perform handshake + if err := proxy.websocketHandshake(ctx, req, targetConn, clientConn); err != nil { + ctx.Warnf("Websocket handshake error: %v", err) + return + } + + // Proxy ws connection + proxy.proxyWebsocket(ctx, targetConn, clientConn) +} + +func (proxy *ProxyHttpServer) websocketHandshake(ctx *ProxyCtx, req *http.Request, targetSiteConn io.ReadWriter, clientConn io.ReadWriter) error { + // write handshake request to target + err := req.Write(targetSiteConn) + if err != nil { + ctx.Warnf("Error writing upgrade request: %v", err) + return err + } + + targetTLSReader := bufio.NewReader(targetSiteConn) + + // Read handshake response from target + resp, err := http.ReadResponse(targetTLSReader, req) + if err != nil { + ctx.Warnf("Error reading handhsake response %v", err) + return err + } + + // Run response through handlers + resp = proxy.filterResponse(resp, ctx) + + // Proxy handshake back to client + err = resp.Write(clientConn) + if err != nil { + ctx.Warnf("Error writing handshake response: %v", err) + return err + } + return nil +} + +func (proxy *ProxyHttpServer) proxyWebsocket(ctx *ProxyCtx, dest io.ReadWriter, source io.ReadWriter) { + errChan := make(chan error, 2) + cp := func(dst io.Writer, src io.Reader) { + _, err := io.Copy(dst, src) + ctx.Warnf("Websocket error: %v", err) + errChan <- err + } + + // Start proxying websocket data + go cp(dest, source) + go cp(source, dest) + <-errChan +}