Update dependencies
This commit is contained in:
11
vendor/tailscale.com/net/tshttpproxy/mksyscall.go
generated
vendored
Normal file
11
vendor/tailscale.com/net/tshttpproxy/mksyscall.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tshttpproxy
|
||||
|
||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go mksyscall.go
|
||||
|
||||
//sys globalFree(hglobal winHGlobal) (err error) [failretval==0] = kernel32.GlobalFree
|
||||
//sys winHTTPCloseHandle(whi winHTTPInternet) (err error) [failretval==0] = winhttp.WinHttpCloseHandle
|
||||
//sys winHTTPGetProxyForURL(whi winHTTPInternet, url *uint16, options *winHTTPAutoProxyOptions, proxyInfo *winHTTPProxyInfo) (err error) [failretval==0] = winhttp.WinHttpGetProxyForUrl
|
||||
//sys winHTTPOpen(agent *uint16, accessType uint32, proxy *uint16, proxyBypass *uint16, flags uint32) (whi winHTTPInternet, err error) [failretval==0] = winhttp.WinHttpOpen
|
||||
219
vendor/tailscale.com/net/tshttpproxy/tshttpproxy.go
generated
vendored
Normal file
219
vendor/tailscale.com/net/tshttpproxy/tshttpproxy.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package tshttpproxy contains Tailscale additions to httpproxy not available
|
||||
// in golang.org/x/net/http/httpproxy. Notably, it aims to support Windows better.
|
||||
package tshttpproxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
"tailscale.com/util/mak"
|
||||
)
|
||||
|
||||
// InvalidateCache invalidates the package-level cache for ProxyFromEnvironment.
|
||||
//
|
||||
// It's intended to be called on network link/routing table changes.
|
||||
func InvalidateCache() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
noProxyUntil = time.Time{}
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
noProxyUntil time.Time // if non-zero, time at which ProxyFromEnvironment should check again
|
||||
config *httpproxy.Config // used to create proxyFunc
|
||||
proxyFunc func(*url.URL) (*url.URL, error)
|
||||
)
|
||||
|
||||
func getProxyFunc() func(*url.URL) (*url.URL, error) {
|
||||
// Create config/proxyFunc if it's not created
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if config == nil {
|
||||
config = httpproxy.FromEnvironment()
|
||||
}
|
||||
if proxyFunc == nil {
|
||||
proxyFunc = config.ProxyFunc()
|
||||
}
|
||||
return proxyFunc
|
||||
}
|
||||
|
||||
// setNoProxyUntil stops calls to sysProxyEnv (if any) for the provided duration.
|
||||
func setNoProxyUntil(d time.Duration) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
noProxyUntil = time.Now().Add(d)
|
||||
}
|
||||
|
||||
var _ = setNoProxyUntil // quiet staticcheck; Windows uses the above, more might later
|
||||
|
||||
// SetSelfProxy configures this package to avoid proxying through any of the
|
||||
// provided addresses–e.g. if they refer to proxies being run by this process.
|
||||
func SetSelfProxy(addrs ...string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
// Ensure we have a valid config
|
||||
if config == nil {
|
||||
config = httpproxy.FromEnvironment()
|
||||
}
|
||||
|
||||
normalizeHostPort := func(s string) string {
|
||||
host, portStr, err := net.SplitHostPort(s)
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
|
||||
// Normalize the localhost IP into "localhost", to avoid IPv4/IPv6 confusion.
|
||||
if host == "127.0.0.1" || host == "::1" {
|
||||
return "localhost:" + portStr
|
||||
}
|
||||
|
||||
// On Linux, all 127.0.0.1/8 IPs are also localhost.
|
||||
if runtime.GOOS == "linux" && strings.HasPrefix(host, "127.0.0.") {
|
||||
return "localhost:" + portStr
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
normHTTP := normalizeHostPort(config.HTTPProxy)
|
||||
normHTTPS := normalizeHostPort(config.HTTPSProxy)
|
||||
|
||||
// If any of our proxy variables point to one of the configured
|
||||
// addresses, ignore them.
|
||||
for _, addr := range addrs {
|
||||
normAddr := normalizeHostPort(addr)
|
||||
if normHTTP != "" && normHTTP == normAddr {
|
||||
log.Printf("tshttpproxy: skipping HTTP_PROXY pointing to self: %q", addr)
|
||||
config.HTTPProxy = ""
|
||||
normHTTP = ""
|
||||
}
|
||||
if normHTTPS != "" && normHTTPS == normAddr {
|
||||
log.Printf("tshttpproxy: skipping HTTPS_PROXY pointing to self: %q", addr)
|
||||
config.HTTPSProxy = ""
|
||||
normHTTPS = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Invalidate to cause it to get re-created
|
||||
proxyFunc = nil
|
||||
}
|
||||
|
||||
// sysProxyFromEnv, if non-nil, specifies a platform-specific ProxyFromEnvironment
|
||||
// func to use if http.ProxyFromEnvironment doesn't return a proxy.
|
||||
// For example, WPAD PAC files on Windows.
|
||||
var sysProxyFromEnv func(*http.Request) (*url.URL, error)
|
||||
|
||||
// These variables track whether we've printed a log message for a given proxy
|
||||
// URL; we only print them once to avoid log spam.
|
||||
var (
|
||||
logMessageMu sync.Mutex
|
||||
logMessagePrinted map[string]bool
|
||||
)
|
||||
|
||||
// ProxyFromEnvironment is like the standard library's http.ProxyFromEnvironment
|
||||
// but additionally does OS-specific proxy lookups if the environment variables
|
||||
// alone don't specify a proxy.
|
||||
func ProxyFromEnvironment(req *http.Request) (ret *url.URL, _ error) {
|
||||
defer func() {
|
||||
if ret == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ss := ret.String()
|
||||
|
||||
logMessageMu.Lock()
|
||||
defer logMessageMu.Unlock()
|
||||
if logMessagePrinted[ss] {
|
||||
return
|
||||
}
|
||||
log.Printf("tshttpproxy: using proxy %q for URL: %q", ss, req.URL.String())
|
||||
mak.Set(&logMessagePrinted, ss, true)
|
||||
}()
|
||||
|
||||
localProxyFunc := getProxyFunc()
|
||||
u, err := localProxyFunc(req.URL)
|
||||
if u != nil && err == nil {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
noProxyTime := noProxyUntil
|
||||
mu.Unlock()
|
||||
if time.Now().Before(noProxyTime) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if sysProxyFromEnv != nil {
|
||||
u, err := sysProxyFromEnv(req)
|
||||
if u != nil && err == nil {
|
||||
return u, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sysAuthHeader func(*url.URL) (string, error)
|
||||
|
||||
// GetAuthHeader returns the Authorization header value to send to proxy u.
|
||||
func GetAuthHeader(u *url.URL) (string, error) {
|
||||
if fake := os.Getenv("TS_DEBUG_FAKE_PROXY_AUTH"); fake != "" {
|
||||
return fake, nil
|
||||
}
|
||||
if user := u.User.Username(); user != "" {
|
||||
pass, ok := u.User.Password()
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
req := &http.Request{Header: make(http.Header)}
|
||||
req.SetBasicAuth(user, pass)
|
||||
return req.Header.Get("Authorization"), nil
|
||||
}
|
||||
if sysAuthHeader != nil {
|
||||
return sysAuthHeader(u)
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
const proxyAuthHeader = "Proxy-Authorization"
|
||||
|
||||
// SetTransportGetProxyConnectHeader sets the provided Transport's
|
||||
// GetProxyConnectHeader field, and adds logging of the received response.
|
||||
func SetTransportGetProxyConnectHeader(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 v == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return http.Header{proxyAuthHeader: []string{v}}, nil
|
||||
}
|
||||
tr.OnProxyConnectResponse = func(ctx context.Context, proxyURL *url.URL, connectReq *http.Request, res *http.Response) error {
|
||||
auth := connectReq.Header.Get(proxyAuthHeader)
|
||||
const truncLen = 20
|
||||
if len(auth) > truncLen {
|
||||
auth = fmt.Sprintf("%s...(%d total bytes)", auth[:truncLen], len(auth))
|
||||
}
|
||||
log.Printf("tshttpproxy: CONNECT response from %v for target %q (auth %q): %v", proxyURL, connectReq.Host, auth, res.Status)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
24
vendor/tailscale.com/net/tshttpproxy/tshttpproxy_linux.go
generated
vendored
Normal file
24
vendor/tailscale.com/net/tshttpproxy/tshttpproxy_linux.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build linux
|
||||
|
||||
package tshttpproxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"tailscale.com/version/distro"
|
||||
)
|
||||
|
||||
func init() {
|
||||
sysProxyFromEnv = linuxSysProxyFromEnv
|
||||
}
|
||||
|
||||
func linuxSysProxyFromEnv(req *http.Request) (*url.URL, error) {
|
||||
if distro.Get() == distro.Synology {
|
||||
return synologyProxyFromConfigCached(req)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
140
vendor/tailscale.com/net/tshttpproxy/tshttpproxy_synology.go
generated
vendored
Normal file
140
vendor/tailscale.com/net/tshttpproxy/tshttpproxy_synology.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build linux
|
||||
|
||||
package tshttpproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"tailscale.com/util/lineread"
|
||||
)
|
||||
|
||||
// These vars are overridden for tests.
|
||||
var (
|
||||
synologyProxyConfigPath = "/etc/proxy.conf"
|
||||
|
||||
openSynologyProxyConf = func() (io.ReadCloser, error) {
|
||||
return os.Open(synologyProxyConfigPath)
|
||||
}
|
||||
)
|
||||
|
||||
var cache struct {
|
||||
sync.Mutex
|
||||
httpProxy *url.URL
|
||||
httpsProxy *url.URL
|
||||
updated time.Time
|
||||
}
|
||||
|
||||
func synologyProxyFromConfigCached(req *http.Request) (*url.URL, error) {
|
||||
if req.URL == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cache.Lock()
|
||||
defer cache.Unlock()
|
||||
|
||||
var err error
|
||||
modtime := mtime(synologyProxyConfigPath)
|
||||
|
||||
if modtime != cache.updated {
|
||||
cache.httpProxy, cache.httpsProxy, err = synologyProxiesFromConfig()
|
||||
cache.updated = modtime
|
||||
}
|
||||
|
||||
if req.URL.Scheme == "https" {
|
||||
return cache.httpsProxy, err
|
||||
}
|
||||
return cache.httpProxy, err
|
||||
}
|
||||
|
||||
func synologyProxiesFromConfig() (*url.URL, *url.URL, error) {
|
||||
r, err := openSynologyProxyConf()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
return parseSynologyConfig(r)
|
||||
}
|
||||
|
||||
// parseSynologyConfig parses the Synology proxy configuration, and returns any
|
||||
// http proxy, and any https proxy respectively, or an error if parsing fails.
|
||||
func parseSynologyConfig(r io.Reader) (*url.URL, *url.URL, error) {
|
||||
cfg := map[string]string{}
|
||||
|
||||
if err := lineread.Reader(r, func(line []byte) error {
|
||||
// accept and skip over empty lines
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
key, value, ok := strings.Cut(string(line), "=")
|
||||
if !ok {
|
||||
return fmt.Errorf("missing \"=\" in proxy.conf line: %q", line)
|
||||
}
|
||||
cfg[string(key)] = string(value)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if cfg["proxy_enabled"] != "yes" {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
httpProxyURL := new(url.URL)
|
||||
httpsProxyURL := new(url.URL)
|
||||
if cfg["auth_enabled"] == "yes" {
|
||||
httpProxyURL.User = url.UserPassword(cfg["proxy_user"], cfg["proxy_pwd"])
|
||||
httpsProxyURL.User = url.UserPassword(cfg["proxy_user"], cfg["proxy_pwd"])
|
||||
}
|
||||
|
||||
// As far as we are aware, synology does not support tls proxies.
|
||||
httpProxyURL.Scheme = "http"
|
||||
httpsProxyURL.Scheme = "http"
|
||||
|
||||
httpsProxyURL = addHostPort(httpsProxyURL, cfg["https_host"], cfg["https_port"])
|
||||
httpProxyURL = addHostPort(httpProxyURL, cfg["http_host"], cfg["http_port"])
|
||||
|
||||
return httpProxyURL, httpsProxyURL, nil
|
||||
}
|
||||
|
||||
// addHostPort adds to u the given host and port and returns the updated url, or
|
||||
// if host is empty, it returns nil.
|
||||
func addHostPort(u *url.URL, host, port string) *url.URL {
|
||||
if host == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if port == "" {
|
||||
u.Host = host
|
||||
} else {
|
||||
u.Host = net.JoinHostPort(host, port)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// mtime stat's path and returns its modification time. If path does not exist,
|
||||
// it returns the unix epoch.
|
||||
func mtime(path string) time.Time {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
return fi.ModTime()
|
||||
}
|
||||
276
vendor/tailscale.com/net/tshttpproxy/tshttpproxy_windows.go
generated
vendored
Normal file
276
vendor/tailscale.com/net/tshttpproxy/tshttpproxy_windows.go
generated
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tshttpproxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/alexbrainman/sspi/negotiate"
|
||||
"golang.org/x/sys/windows"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/cmpver"
|
||||
)
|
||||
|
||||
func init() {
|
||||
sysProxyFromEnv = proxyFromWinHTTPOrCache
|
||||
sysAuthHeader = sysAuthHeaderWindows
|
||||
}
|
||||
|
||||
var cachedProxy struct {
|
||||
sync.Mutex
|
||||
val *url.URL
|
||||
}
|
||||
|
||||
// proxyErrorf is a rate-limited logger specifically for errors asking
|
||||
// WinHTTP for the proxy information. We don't want to log about
|
||||
// errors often, otherwise the log message itself will generate a new
|
||||
// HTTP request which ultimately will call back into us to log again,
|
||||
// forever. So for errors, we only log a bit.
|
||||
var proxyErrorf = logger.RateLimitedFn(log.Printf, 10*time.Minute, 2 /* burst*/, 10 /* maxCache */)
|
||||
|
||||
var (
|
||||
metricSuccess = clientmetric.NewCounter("winhttp_proxy_success")
|
||||
metricErrDetectionFailed = clientmetric.NewCounter("winhttp_proxy_err_detection_failed")
|
||||
metricErrInvalidParameters = clientmetric.NewCounter("winhttp_proxy_err_invalid_param")
|
||||
metricErrDownloadScript = clientmetric.NewCounter("winhttp_proxy_err_download_script")
|
||||
metricErrTimeout = clientmetric.NewCounter("winhttp_proxy_err_timeout")
|
||||
metricErrOther = clientmetric.NewCounter("winhttp_proxy_err_other")
|
||||
)
|
||||
|
||||
func proxyFromWinHTTPOrCache(req *http.Request) (*url.URL, error) {
|
||||
if req.URL == nil {
|
||||
return nil, nil
|
||||
}
|
||||
urlStr := req.URL.String()
|
||||
|
||||
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
type result struct {
|
||||
proxy *url.URL
|
||||
err error
|
||||
}
|
||||
resc := make(chan result, 1)
|
||||
go func() {
|
||||
proxy, err := proxyFromWinHTTP(ctx, urlStr)
|
||||
resc <- result{proxy, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-resc:
|
||||
err := res.err
|
||||
if err == nil {
|
||||
metricSuccess.Add(1)
|
||||
cachedProxy.Lock()
|
||||
defer cachedProxy.Unlock()
|
||||
if was, now := fmt.Sprint(cachedProxy.val), fmt.Sprint(res.proxy); was != now {
|
||||
log.Printf("tshttpproxy: winhttp: updating cached proxy setting from %v to %v", was, now)
|
||||
}
|
||||
cachedProxy.val = res.proxy
|
||||
return res.proxy, nil
|
||||
}
|
||||
|
||||
// See https://docs.microsoft.com/en-us/windows/win32/winhttp/error-messages
|
||||
const (
|
||||
ERROR_WINHTTP_AUTODETECTION_FAILED = 12180
|
||||
ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT = 12167
|
||||
)
|
||||
if err == syscall.Errno(ERROR_WINHTTP_AUTODETECTION_FAILED) {
|
||||
metricErrDetectionFailed.Add(1)
|
||||
setNoProxyUntil(10 * time.Second)
|
||||
return nil, nil
|
||||
}
|
||||
if err == windows.ERROR_INVALID_PARAMETER {
|
||||
metricErrInvalidParameters.Add(1)
|
||||
// Seen on Windows 8.1. (https://github.com/tailscale/tailscale/issues/879)
|
||||
// TODO(bradfitz): figure this out.
|
||||
setNoProxyUntil(time.Hour)
|
||||
proxyErrorf("tshttpproxy: winhttp: GetProxyForURL(%q): ERROR_INVALID_PARAMETER [unexpected]", urlStr)
|
||||
return nil, nil
|
||||
}
|
||||
proxyErrorf("tshttpproxy: winhttp: GetProxyForURL(%q): %v/%#v", urlStr, err, err)
|
||||
if err == syscall.Errno(ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT) {
|
||||
metricErrDownloadScript.Add(1)
|
||||
setNoProxyUntil(10 * time.Second)
|
||||
return nil, nil
|
||||
}
|
||||
metricErrOther.Add(1)
|
||||
return nil, err
|
||||
case <-ctx.Done():
|
||||
metricErrTimeout.Add(1)
|
||||
cachedProxy.Lock()
|
||||
defer cachedProxy.Unlock()
|
||||
proxyErrorf("tshttpproxy: winhttp: GetProxyForURL(%q): timeout; using cached proxy %v", urlStr, cachedProxy.val)
|
||||
return cachedProxy.val, nil
|
||||
}
|
||||
}
|
||||
|
||||
func proxyFromWinHTTP(ctx context.Context, urlStr string) (proxy *url.URL, err error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
whi, err := httpOpen()
|
||||
if err != nil {
|
||||
proxyErrorf("winhttp: Open: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
defer whi.Close()
|
||||
|
||||
t0 := time.Now()
|
||||
v, err := whi.GetProxyForURL(urlStr)
|
||||
td := time.Since(t0).Round(time.Millisecond)
|
||||
if err := ctx.Err(); err != nil {
|
||||
log.Printf("tshttpproxy: winhttp: context canceled, ignoring GetProxyForURL(%q) after %v", urlStr, td)
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v == "" {
|
||||
return nil, nil
|
||||
}
|
||||
// Discard all but first proxy value for now.
|
||||
if i := strings.Index(v, ";"); i != -1 {
|
||||
v = v[:i]
|
||||
}
|
||||
if !strings.HasPrefix(v, "https://") {
|
||||
v = "http://" + v
|
||||
}
|
||||
return url.Parse(v)
|
||||
}
|
||||
|
||||
var userAgent = windows.StringToUTF16Ptr("Tailscale")
|
||||
|
||||
const (
|
||||
winHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0
|
||||
winHTTP_ACCESS_TYPE_AUTOMATIC_PROXY = 4
|
||||
winHTTP_AUTOPROXY_ALLOW_AUTOCONFIG = 0x00000100
|
||||
winHTTP_AUTOPROXY_AUTO_DETECT = 1
|
||||
winHTTP_AUTO_DETECT_TYPE_DHCP = 0x00000001
|
||||
winHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002
|
||||
)
|
||||
|
||||
// Windows 8.1 is actually Windows 6.3 under the hood. Yay, marketing!
|
||||
const win8dot1Ver = "6.3"
|
||||
|
||||
// accessType is the flag we must pass to WinHttpOpen for proxy resolution
|
||||
// depending on whether or not we're running Windows < 8.1
|
||||
var accessType syncs.AtomicValue[uint32]
|
||||
|
||||
func getAccessFlag() uint32 {
|
||||
if flag, ok := accessType.LoadOk(); ok {
|
||||
return flag
|
||||
}
|
||||
var flag uint32
|
||||
if cmpver.Compare(hostinfo.GetOSVersion(), win8dot1Ver) < 0 {
|
||||
flag = winHTTP_ACCESS_TYPE_DEFAULT_PROXY
|
||||
} else {
|
||||
flag = winHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
|
||||
}
|
||||
accessType.Store(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
func httpOpen() (winHTTPInternet, error) {
|
||||
return winHTTPOpen(
|
||||
userAgent,
|
||||
getAccessFlag(),
|
||||
nil, /* WINHTTP_NO_PROXY_NAME */
|
||||
nil, /* WINHTTP_NO_PROXY_BYPASS */
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
type winHTTPInternet windows.Handle
|
||||
|
||||
func (hi winHTTPInternet) Close() error {
|
||||
return winHTTPCloseHandle(hi)
|
||||
}
|
||||
|
||||
// WINHTTP_AUTOPROXY_OPTIONS
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winhttp/ns-winhttp-winhttp_autoproxy_options
|
||||
type winHTTPAutoProxyOptions struct {
|
||||
DwFlags uint32
|
||||
DwAutoDetectFlags uint32
|
||||
AutoConfigUrl *uint16
|
||||
_ uintptr
|
||||
_ uint32
|
||||
FAutoLogonIfChallenged int32 // BOOL
|
||||
}
|
||||
|
||||
// WINHTTP_PROXY_INFO
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winhttp/ns-winhttp-winhttp_proxy_info
|
||||
type winHTTPProxyInfo struct {
|
||||
AccessType uint32
|
||||
Proxy *uint16
|
||||
ProxyBypass *uint16
|
||||
}
|
||||
|
||||
type winHGlobal windows.Handle
|
||||
|
||||
func globalFreeUTF16Ptr(p *uint16) error {
|
||||
return globalFree((winHGlobal)(unsafe.Pointer(p)))
|
||||
}
|
||||
|
||||
func (pi *winHTTPProxyInfo) free() {
|
||||
if pi.Proxy != nil {
|
||||
globalFreeUTF16Ptr(pi.Proxy)
|
||||
pi.Proxy = nil
|
||||
}
|
||||
if pi.ProxyBypass != nil {
|
||||
globalFreeUTF16Ptr(pi.ProxyBypass)
|
||||
pi.ProxyBypass = nil
|
||||
}
|
||||
}
|
||||
|
||||
var proxyForURLOpts = &winHTTPAutoProxyOptions{
|
||||
DwFlags: winHTTP_AUTOPROXY_ALLOW_AUTOCONFIG | winHTTP_AUTOPROXY_AUTO_DETECT,
|
||||
DwAutoDetectFlags: winHTTP_AUTO_DETECT_TYPE_DHCP, // | winHTTP_AUTO_DETECT_TYPE_DNS_A,
|
||||
}
|
||||
|
||||
func (hi winHTTPInternet) GetProxyForURL(urlStr string) (string, error) {
|
||||
var out winHTTPProxyInfo
|
||||
err := winHTTPGetProxyForURL(
|
||||
hi,
|
||||
windows.StringToUTF16Ptr(urlStr),
|
||||
proxyForURLOpts,
|
||||
&out,
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer out.free()
|
||||
return windows.UTF16PtrToString(out.Proxy), nil
|
||||
}
|
||||
|
||||
func sysAuthHeaderWindows(u *url.URL) (string, error) {
|
||||
spn := "HTTP/" + u.Hostname()
|
||||
creds, err := negotiate.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("negotiate.AcquireCurrentUserCredentials: %w", err)
|
||||
}
|
||||
defer creds.Release()
|
||||
|
||||
secCtx, token, err := negotiate.NewClientContext(creds, spn)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("negotiate.NewClientContext: %w", err)
|
||||
}
|
||||
defer secCtx.Release()
|
||||
|
||||
return "Negotiate " + base64.StdEncoding.EncodeToString(token), nil
|
||||
}
|
||||
81
vendor/tailscale.com/net/tshttpproxy/zsyscall_windows.go
generated
vendored
Normal file
81
vendor/tailscale.com/net/tshttpproxy/zsyscall_windows.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package tshttpproxy
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
modwinhttp = windows.NewLazySystemDLL("winhttp.dll")
|
||||
|
||||
procGlobalFree = modkernel32.NewProc("GlobalFree")
|
||||
procWinHttpCloseHandle = modwinhttp.NewProc("WinHttpCloseHandle")
|
||||
procWinHttpGetProxyForUrl = modwinhttp.NewProc("WinHttpGetProxyForUrl")
|
||||
procWinHttpOpen = modwinhttp.NewProc("WinHttpOpen")
|
||||
)
|
||||
|
||||
func globalFree(hglobal winHGlobal) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGlobalFree.Addr(), 1, uintptr(hglobal), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func winHTTPCloseHandle(whi winHTTPInternet) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procWinHttpCloseHandle.Addr(), 1, uintptr(whi), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func winHTTPGetProxyForURL(whi winHTTPInternet, url *uint16, options *winHTTPAutoProxyOptions, proxyInfo *winHTTPProxyInfo) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procWinHttpGetProxyForUrl.Addr(), 4, uintptr(whi), uintptr(unsafe.Pointer(url)), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(proxyInfo)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func winHTTPOpen(agent *uint16, accessType uint32, proxy *uint16, proxyBypass *uint16, flags uint32) (whi winHTTPInternet, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procWinHttpOpen.Addr(), 5, uintptr(unsafe.Pointer(agent)), uintptr(accessType), uintptr(unsafe.Pointer(proxy)), uintptr(unsafe.Pointer(proxyBypass)), uintptr(flags), 0)
|
||||
whi = winHTTPInternet(r0)
|
||||
if whi == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user