diff --git a/go.mod b/go.mod index a40c87f..f6fef75 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/BurntSushi/toml v1.6.0 - github.com/elazarl/goproxy v1.7.2 + github.com/elazarl/goproxy v1.8.0 ) require ( diff --git a/go.sum b/go.sum index 0066927..ee9dd76 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,17 @@ -github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= -github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= -github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= +github.com/elazarl/goproxy v1.8.0 h1:dt561rX7UAYMeFRLtzFx6uQGl2TpL1dr6uCG23nFQSY= +github.com/elazarl/goproxy v1.8.0/go.mod h1:b5xm6W48AUHNpRTCvlnd0YVh+JafCCtsLsJZvvNTz+E= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/vendor/github.com/elazarl/goproxy/.golangci.yml b/vendor/github.com/elazarl/goproxy/.golangci.yml index 69e36d9..aaa111a 100644 --- a/vendor/github.com/elazarl/goproxy/.golangci.yml +++ b/vendor/github.com/elazarl/goproxy/.golangci.yml @@ -1,18 +1,10 @@ +version: "2" run: - timeout: 5m modules-download-mode: readonly # List from https://golangci-lint.run/usage/linters/ linters: enable: - # Default linters - - errcheck - - gosimple - - govet - - ineffassign - - staticcheck - - unused - # Other linters - asasalint - asciicheck - bidichk @@ -27,13 +19,10 @@ linters: - fatcontext - forbidigo - forcetypeassert - - gci - gocheckcompilerdirectives - gochecksumtype - gocritic - godot - - gofmt - - gofumpt - goheader - gomodguard - goprintffuncname @@ -57,9 +46,8 @@ linters: - predeclared - reassign - revive - - stylecheck + - staticcheck - tagalign - - tenv - testableexamples - testifylint - testpackage @@ -69,7 +57,6 @@ linters: - usestdlibvars - wastedassign - whitespace - disable: - bodyclose - canonicalheader @@ -89,7 +76,6 @@ linters: - goconst - gocyclo - godox - - goimports - gomoddirectives - inamedparam - intrange @@ -115,46 +101,65 @@ linters: - wrapcheck - wsl - zerologlint - -linters-settings: - gci: - sections: - - standard - - default - skip-generated: false - custom-order: true - gosec: - excludes: - - G402 # InsecureSkipVerify - - G102 # Binds to all network interfaces - - G403 # RSA keys should be at least 2048 bits - - G115 # Integer overflow conversion (uint64 -> int64) - - G404 # Use of weak random number generator (math/rand) - - G204 # Subprocess launched with a potential tainted input or cmd arguments - -issues: - exclude-rules: - - linters: - - gocritic - text: "ifElseChain" - - linters: - - lll - source: "^// " - - linters: - - revive - text: "add-constant: " - - linters: - - revive - text: "unused-parameter: " - - linters: - - revive - text: "empty-block: " - - linters: - - revive - text: "var-naming: " # TODO: Re-enable in V2 - - linters: - - stylecheck - text: " should be " # TODO: Re-enable in V2 - - linters: - - stylecheck - text: "ST1003: should not use ALL_CAPS in Go names; use CamelCase instead" # TODO: Re-enable in V2 + settings: + gosec: + excludes: + - G402 # InsecureSkipVerify + - G102 # Binds to all network interfaces + - G403 # RSA keys should be at least 2048 bits + - G115 # Integer overflow conversion (uint64 -> int64) + - G404 # Use of weak random number generator (math/rand) + - G204 # Subprocess launched with a potential tainted input or cmd arguments + - G602 # Slice index out of range + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - gocritic + text: ifElseChain + - linters: + - lll + source: '^// ' + - linters: + - revive + text: 'add-constant: ' + - linters: + - revive + text: 'unused-parameter: ' + - linters: + - revive + text: 'empty-block: ' + - linters: + - revive + text: 'var-naming: ' # TODO: Re-enable in V2 + - linters: + - staticcheck + text: ' should be ' # TODO: Re-enable in V2 + - linters: + - staticcheck + text: 'ST1003: should not use ALL_CAPS in Go names; use CamelCase instead' + paths: + - examples$ + - transport +formatters: + enable: + - gci + - gofmt + - gofumpt + settings: + gci: + sections: + - standard + - default + custom-order: true + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/elazarl/goproxy/README.md b/vendor/github.com/elazarl/goproxy/README.md index 435eded..6870834 100644 --- a/vendor/github.com/elazarl/goproxy/README.md +++ b/vendor/github.com/elazarl/goproxy/README.md @@ -169,10 +169,10 @@ local timezone: proxy.OnRequest(goproxy.DstHostIs("www.reddit.com")).DoFunc( func(req *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) { if h,_,_ := time.Now().Clock(); h >= 8 && h <= 17 { - resp := goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusForbidden, "Don't waste your time!") + resp := goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusForbidden, "Don't waste your time!") return req, resp } - return req,nil + return req, nil }) ``` diff --git a/vendor/github.com/elazarl/goproxy/chunked.go b/vendor/github.com/elazarl/goproxy/chunked.go deleted file mode 100644 index 8b34b68..0000000 --- a/vendor/github.com/elazarl/goproxy/chunked.go +++ /dev/null @@ -1,57 +0,0 @@ -// Taken from $GOROOT/src/pkg/net/http/chunked -// needed to write https responses to client. -package goproxy - -import ( - "io" - "strconv" -) - -// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP -// "chunked" format before writing them to w. Closing the returned chunkedWriter -// sends the final 0-length chunk that marks the end of the stream. -// -// newChunkedWriter is not needed by normal applications. The http -// package adds chunking automatically if handlers don't set a -// Content-Length header. Using newChunkedWriter inside a handler -// would result in double chunking or chunking with a Content-Length -// length, both of which are wrong. -func newChunkedWriter(w io.Writer) io.WriteCloser { - return &chunkedWriter{w} -} - -// Writing to chunkedWriter translates to writing in HTTP chunked Transfer -// Encoding wire format to the underlying Wire chunkedWriter. -type chunkedWriter struct { - Wire io.Writer -} - -// Write the contents of data as one chunk to Wire. -// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has -// a bug since it does not check for success of io.WriteString. -func (cw *chunkedWriter) Write(data []byte) (n int, err error) { - // Don't send 0-length data. It looks like EOF for chunked encoding. - if len(data) == 0 { - return 0, nil - } - - head := strconv.FormatInt(int64(len(data)), 16) + "\r\n" - - if _, err = io.WriteString(cw.Wire, head); err != nil { - return 0, err - } - if n, err = cw.Wire.Write(data); err != nil { - return n, err - } - if n != len(data) { - err = io.ErrShortWrite - return n, err - } - _, err = io.WriteString(cw.Wire, "\r\n") - return n, err -} - -func (cw *chunkedWriter) Close() error { - _, err := io.WriteString(cw.Wire, "0\r\n") - return err -} diff --git a/vendor/github.com/elazarl/goproxy/h2.go b/vendor/github.com/elazarl/goproxy/h2.go index 6d50948..2f6342c 100644 --- a/vendor/github.com/elazarl/goproxy/h2.go +++ b/vendor/github.com/elazarl/goproxy/h2.go @@ -2,6 +2,7 @@ package goproxy import ( "bufio" + "context" "crypto/tls" "errors" "io" @@ -45,7 +46,7 @@ func (r *H2Transport) RoundTrip(_ *http.Request) (*http.Response, error) { if !ok { return nil, errors.New("invalid TLS connection") } - if err = rawTLSConn.Handshake(); err != nil { + if err = rawTLSConn.HandshakeContext(context.Background()); err != nil { return nil, err } if r.TLSConfig == nil || !r.TLSConfig.InsecureSkipVerify { diff --git a/vendor/github.com/elazarl/goproxy/https.go b/vendor/github.com/elazarl/goproxy/https.go index 016e513..9a87dab 100644 --- a/vendor/github.com/elazarl/goproxy/https.go +++ b/vendor/github.com/elazarl/goproxy/https.go @@ -11,7 +11,6 @@ import ( "net/http" "net/url" "os" - "strconv" "strings" "sync" "sync/atomic" @@ -83,7 +82,8 @@ func (proxy *ProxyHttpServer) dial(ctx *ProxyCtx, network, addr string) (c net.C // if the user didn't specify any dialer, we just use the default one, // provided by net package - return net.Dial(network, addr) + var d net.Dialer + return d.DialContext(ctx.Req.Context(), network, addr) } func (proxy *ProxyHttpServer) connectDial(ctx *ProxyCtx, network, addr string) (c net.Conn, err error) { @@ -281,10 +281,9 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request } } go func() { - // TODO: cache connections to the remote website rawClientTls := tls.Server(proxyClient, tlsConfig) defer rawClientTls.Close() - if err := rawClientTls.Handshake(); err != nil { + if err := rawClientTls.HandshakeContext(context.Background()); err != nil { ctx.Warnf("Cannot handshake client %v %v", r.Host, err) return } @@ -377,46 +376,18 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request } ctx.Logf("resp %v", resp.Status) } + origBody := resp.Body resp = proxy.filterResponse(resp, ctx) + bodyModified := resp.Body != origBody defer resp.Body.Close() - - text := resp.Status - statusCode := strconv.Itoa(resp.StatusCode) + " " - text = strings.TrimPrefix(text, statusCode) - // always use 1.1 to support chunked encoding - if _, err := io.WriteString(rawClientTls, "HTTP/1.1"+" "+statusCode+text+"\r\n"); err != nil { - ctx.Warnf("Cannot write TLS response HTTP status from mitm'd client: %v", err) - return false - } - - isWebsocket := isWebSocketHandshake(resp.Header) - if isWebsocket || resp.Request.Method == http.MethodHead { - // don't change Content-Length for HEAD request - } else if (resp.StatusCode >= 100 && resp.StatusCode < 200) || - resp.StatusCode == http.StatusNoContent { - // RFC7230: A server MUST NOT send a Content-Length header field in any response - // with a status code of 1xx (Informational) or 204 (No Content) - resp.Header.Del("Content-Length") - } else { + if bodyModified { // Since we don't know the length of resp, return chunked encoded response - // TODO: use a more reasonable scheme + resp.ContentLength = -1 resp.Header.Del("Content-Length") - resp.Header.Set("Transfer-Encoding", "chunked") - } - // Force connection close otherwise chrome will keep CONNECT tunnel open forever - if !isWebsocket { - resp.Header.Set("Connection", "close") - } - if err := resp.Header.Write(rawClientTls); err != nil { - ctx.Warnf("Cannot write TLS response header from mitm'd client: %v", err) - return false - } - if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil { - ctx.Warnf("Cannot write TLS response header end from mitm'd client: %v", err) - return false + resp.TransferEncoding = []string{"chunked"} } - if isWebsocket { + if isWebSocketHandshake(resp.Header) { ctx.Logf("Response looks like websocket upgrade.") // According to resp.Body documentation: @@ -428,32 +399,21 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request ctx.Warnf("Unable to use Websocket connection") return false } + // Set Body to nil so resp.Write only writes the headers + // and returns immediately without blocking on the body + // (or else we wouldn't be able to proxy WebSocket data). + resp.Body = nil + if err := resp.Write(rawClientTls); err != nil { + ctx.Warnf("Cannot write TLS response header from mitm'd client: %v", err) + return false + } proxy.proxyWebsocket(ctx, wsConn, rawClientTls) - // We can't reuse connection after WebSocket handshake, - // by returning false here, the underlying connection will be closed return false } - if resp.Request.Method == http.MethodHead || - (resp.StatusCode >= 100 && resp.StatusCode < 200) || - resp.StatusCode == http.StatusNoContent || - resp.StatusCode == http.StatusNotModified { - // Don't write out a response body, when it's not allowed - // in RFC7230 - } else { - chunked := newChunkedWriter(rawClientTls) - if _, err := io.Copy(chunked, resp.Body); err != nil { - ctx.Warnf("Cannot write TLS response body from mitm'd client: %v", err) - return false - } - if err := chunked.Close(); err != nil { - ctx.Warnf("Cannot write TLS chunked EOF from mitm'd client: %v", err) - return false - } - if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil { - ctx.Warnf("Cannot write TLS response chunked trailer from mitm'd client: %v", err) - return false - } + if err := resp.Write(rawClientTls); err != nil { + ctx.Warnf("Cannot write TLS response from mitm'd client: %v", err) + return false } return true diff --git a/vendor/github.com/elazarl/goproxy/internal/signer/signer.go b/vendor/github.com/elazarl/goproxy/internal/signer/signer.go index 0ff00a5..d62ec1a 100644 --- a/vendor/github.com/elazarl/goproxy/internal/signer/signer.go +++ b/vendor/github.com/elazarl/goproxy/internal/signer/signer.go @@ -108,8 +108,12 @@ func SignHost(ca tls.Certificate, hosts []string) (cert *tls.Certificate, err er return nil, err } - certBytes := [][]byte{derBytes} - certBytes = append(certBytes, ca.Certificate...) + certBytes := make([][]byte, 1+len(ca.Certificate)) + certBytes[0] = derBytes + for i, singleCertBytes := range ca.Certificate { + certBytes[i+1] = singleCertBytes + } + return &tls.Certificate{ Certificate: certBytes, PrivateKey: certpriv, diff --git a/vendor/modules.txt b/vendor/modules.txt index af8e71e..737000b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2,8 +2,8 @@ ## explicit; go 1.18 github.com/BurntSushi/toml github.com/BurntSushi/toml/internal -# github.com/elazarl/goproxy v1.7.2 -## explicit; go 1.20 +# github.com/elazarl/goproxy v1.8.0 +## explicit; go 1.23.0 github.com/elazarl/goproxy github.com/elazarl/goproxy/internal/http1parser github.com/elazarl/goproxy/internal/signer