tshttpproxy, controlclient, derphttp, logpolicy: send Negotiate auth to proxies

For Windows only, and only when built with Tailscale's Go tree.

Updates tailscale/corp#583
This commit is contained in:
Brad Fitzpatrick 2020-08-26 20:02:16 -07:00
parent 756d6a72bd
commit 28f9cd06f5
5 changed files with 61 additions and 1 deletions

View File

@ -149,6 +149,7 @@ func NewDirect(opts Options) (*Direct, error) {
dialer := netns.NewDialer()
tr := http.DefaultTransport.(*http.Transport).Clone()
tr.Proxy = tshttpproxy.ProxyFromEnvironment
tshttpproxy.SetTransportGetProxyConnectHeader(tr)
tr.DialContext = dialer.DialContext
tr.ForceAttemptHTTP2 = true
tr.TLSClientConfig = tlsdial.Config(serverURL.Host, tr.TLSClientConfig)

View File

@ -589,7 +589,15 @@ func (c *Client) dialNodeUsingProxy(ctx context.Context, n *tailcfg.DERPNode, pr
}()
target := net.JoinHostPort(n.HostName, "443")
if _, err := fmt.Fprintf(proxyConn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", target, pu.Hostname()); err != nil {
var authHeader string
if v, err := tshttpproxy.GetAuthHeader(pu); err != nil {
c.logf("derphttp: error getting proxy auth header for %v: %v", proxyURL, err)
} else if v != "" {
authHeader = fmt.Sprintf("Authorization: %s\r\n", v)
}
if _, err := fmt.Fprintf(proxyConn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n%s\r\n", target, pu.Hostname(), authHeader); err != nil {
if ctx.Err() != nil {
return nil, ctx.Err()
}

View File

@ -433,6 +433,7 @@ func newLogtailTransport(host string) *http.Transport {
tr := http.DefaultTransport.(*http.Transport).Clone()
tr.Proxy = tshttpproxy.ProxyFromEnvironment
tshttpproxy.SetTransportGetProxyConnectHeader(tr)
// We do our own zstd compression on uploads, and responses never contain any payload,
// so don't send "Accept-Encoding: gzip" to save a few bytes on the wire, since there

View File

@ -41,3 +41,16 @@ func GetAuthHeader(u *url.URL) (string, error) {
}
return "", nil
}
var condSetTransportGetProxyConnectHeader func(*http.Transport)
// SetTarnsportGetProxyConnectHeader sets the provided Transport's
// GetProxyConnectHeader field, if the current build of Go supports
// it.
//
// See https://github.com/golang/go/issues/41048.
func SetTransportGetProxyConnectHeader(tr *http.Transport) {
if f := condSetTransportGetProxyConnectHeader; f != nil {
f(tr)
}
}

View File

@ -0,0 +1,37 @@
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build tailscale_go
// We want to use https://github.com/golang/go/issues/41048 but it's only in the
// Tailscale Go tree for now. Hence the build tag above.
package tshttpproxy
import (
"context"
"log"
"net/http"
"net/url"
"os"
)
func init() {
condSetTransportGetProxyConnectHeader = func(tr *http.Transport) {
tr.GetProxyConnectHeader = func(ctx context.Context, proxyURL *url.URL, target string) (http.Header, error) {
v, err := GetAuthHeader(proxyURL)
if err != nil {
log.Printf("failed to get proxy Auth header for %v; ignoring: %v", proxyURL, err)
return nil, nil
}
if fake := os.Getenv("TS_DEBUG_FAKE_PROXY_AUTH"); fake != "" {
v = fake
}
if v == "" {
return nil, nil
}
return http.Header{"Authorization": []string{v}}, nil
}
}
}