Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

11
vendor/tailscale.com/net/tshttpproxy/mksyscall.go generated vendored Normal file
View 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
View 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 addressese.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
}
}

View 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
}

View 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()
}

View 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
}

View 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
}