Просмотр исходного кода

Rework custom Host header logic

- x/net/http2 rejects requests where URL.Opaque contains a host.

- For unproxied HTTP and HTTPS, the request line URL need only contain the
  path, while this logic forced a full URL via URL.Opaque.

- For all proxied cases using CONNECT, which includes all HTTPS and most HTTPS
  cases, the CONNECT request line is rendered elsewhere, in the upstreamproxy
  package, and the MeekConn URL/Host values are not directly relevant
  (URL.Opaque is used here:
  https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/78d82c60c9558fe00ef3063f0e8a5c9709f38c70/psiphon/upstreamproxy/proxy_http.go#L143-L166)

- For proxied, direct HTTP -- the non-CONNECT special case -- net/http will
  render the request line using the URL but preferring the Host header for
  the host value, which means the custom host header will clobber the true
  destination address. The URL.Opaque logic is applied in this single case.
Rod Hynes 4 лет назад
Родитель
Сommit
fcdad64615
1 измененных файлов с 35 добавлено и 8 удалено
  1. 35 8
      psiphon/meekConn.go

+ 35 - 8
psiphon/meekConn.go

@@ -333,6 +333,7 @@ func DialMeek(
 
 	var (
 		scheme            string
+		opaqueURL         string
 		transport         transporter
 		additionalHeaders http.Header
 		proxyUrl          func(*http.Request) (*url.URL, error)
@@ -538,8 +539,28 @@ func DialMeek(
 
 			dialer = NewTCPDialer(copyDialConfig)
 
+			// In this proxy case, the destination server address is in the
+			// request line URL. net/http will render the request line using
+			// the URL but preferring the Host header for the host value,
+			// which means any custom host header will clobber the true
+			// destination address. The URL.Opaque logic is applied in this
+			// case, to force the request line URL value.
+			//
+			// This URL.Opaque setting assumes MeekModeRelay, with no path; at
+			// this time plain HTTP is used only with MeekModeRelay.
+			// x/net/http2 will reject requests where the URL.Opaque contains
+			// more than the path; but HTTP/2 is not used in this case.
+
+			values := dialConfig.CustomHeaders["Host"]
+			if len(values) > 0 {
+				opaqueURL = "http://" + meekConfig.DialAddress + "/"
+			}
+
 		} else {
 
+			// If dialConfig.UpstreamProxyURL is set, HTTP proxying via
+			// CONNECT will be used by the dialer.
+
 			baseDialer := NewTCPDialer(dialConfig)
 
 			// The dialer ignores any address that http.Transport will pass in
@@ -556,9 +577,14 @@ func DialMeek(
 		}
 
 		if proxyUrl != nil {
-			// Wrap transport with a transport that can perform HTTP proxy auth negotiation
+
+			// When http.Transport is handling proxying, wrap transport with a
+			// transport that (a) adds custom headers; (b) can perform HTTP
+			// proxy auth negotiation.
+
 			var err error
-			transport, err = upstreamproxy.NewProxyAuthTransport(httpTransport, dialConfig.CustomHeaders)
+			transport, err = upstreamproxy.NewProxyAuthTransport(
+				httpTransport, dialConfig.CustomHeaders)
 			if err != nil {
 				return nil, errors.Trace(err)
 			}
@@ -571,6 +597,7 @@ func DialMeek(
 		Scheme: scheme,
 		Host:   meekConfig.HostHeader,
 		Path:   "/",
+		Opaque: opaqueURL,
 	}
 
 	if meekConfig.UseHTTPS {
@@ -583,6 +610,12 @@ func DialMeek(
 		}
 	} else {
 		if proxyUrl == nil {
+
+			// Add custom headers to plain, unproxied HTTP and to CONNECT
+			// method proxied HTTP (in the latter case, the CONNECT request
+			// itself will also have custom headers via upstreamproxy applied
+			// by the dialer).
+
 			additionalHeaders = dialConfig.CustomHeaders
 		}
 	}
@@ -1423,14 +1456,8 @@ func (meek *MeekConn) relayRoundTrip(sendBuffer *bytes.Buffer) (int64, error) {
 // custom headers to HTTP proxy requests.
 func (meek *MeekConn) addAdditionalHeaders(request *http.Request) {
 	for name, value := range meek.additionalHeaders {
-		// hack around special case of "Host" header
-		// https://golang.org/src/net/http/request.go#L474
-		// using URL.Opaque, see URL.RequestURI() https://golang.org/src/net/url/url.go#L915
 		if name == "Host" {
 			if len(value) > 0 {
-				if request.URL.Opaque == "" {
-					request.URL.Opaque = request.URL.Scheme + "://" + request.Host + request.URL.RequestURI()
-				}
 				request.Host = value[0]
 			}
 		} else {