Skip to content

Commit

Permalink
On CONNECT check downstream proxy scheme and allow only HTTP(S)
Browse files Browse the repository at this point in the history
The connect() function only supports HTTP CONNECT proxies [1].
This patch validates that the downstream proxy is an HTTP proxy.
It also refactors the function to prepare it for the patches that follow.

[1] https://www.rfc-editor.org/rfc/rfc7231#section-4.3.6
  • Loading branch information
mmatczuk committed Nov 21, 2022
1 parent aeb4345 commit 8934903
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 16 deletions.
40 changes: 25 additions & 15 deletions proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"net/http"
Expand Down Expand Up @@ -637,33 +638,42 @@ func (p *Proxy) connect(req *http.Request) (*http.Response, net.Conn, error) {
proxyURL = u
}

if proxyURL != nil {
log.Debugf("martian: CONNECT with downstream proxy: %s", proxyURL.Host)
if proxyURL == nil {
log.Debugf("martian: CONNECT to host directly: %s", req.URL.Host)

conn, err := p.dial("tcp", proxyURL.Host)
conn, err := p.dial("tcp", req.URL.Host)
if err != nil {
return nil, nil, err
}
pbw := bufio.NewWriter(conn)
pbr := bufio.NewReader(conn)

req.Write(pbw)
pbw.Flush()
return proxyutil.NewResponse(200, nil, req), conn, nil
}

res, err := http.ReadResponse(pbr, req)
if err != nil {
return nil, nil, err
}
switch proxyURL.Scheme {
case "http", "https":
return p.connectHTTP(req, proxyURL)
default:
return nil, nil, fmt.Errorf("martian: unsupported proxy scheme: %s", proxyURL.Scheme)
}
}

func (p *Proxy) connectHTTP(req *http.Request, proxyURL *url.URL) (*http.Response, net.Conn, error) {
log.Debugf("martian: CONNECT with downstream HTTP proxy: %s", proxyURL.Host)

return res, conn, nil
conn, err := p.dial("tcp", proxyURL.Host)
if err != nil {
return nil, nil, err
}
pbw := bufio.NewWriter(conn)
pbr := bufio.NewReader(conn)

log.Debugf("martian: CONNECT to host directly: %s", req.URL.Host)
req.Write(pbw)
pbw.Flush()

conn, err := p.dial("tcp", req.URL.Host)
res, err := http.ReadResponse(pbr, req)
if err != nil {
return nil, nil, err
}

return proxyutil.NewResponse(200, nil, req), conn, nil
return res, conn, nil
}
3 changes: 2 additions & 1 deletion proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,8 @@ func TestIntegrationConnectDownstreamProxy(t *testing.T) {

// Set upstream proxy's downstream proxy to the host:port of the first proxy.
upstream.SetDownstreamProxy(&url.URL{
Host: dl.Addr().String(),
Scheme: "http",
Host: dl.Addr().String(),
})

go upstream.Serve(ul)
Expand Down

0 comments on commit 8934903

Please sign in to comment.