mirror of
https://github.com/tailscale/tailscale.git
synced 2025-05-06 07:37:38 +00:00
net/tshttpproxy: add GetProxyForURL negative cache
Otherwise when PAC server is down, we log, and each log entry is a new HTTP request (from logtail) and a new GetProxyForURL call, which again logs, non-stop. This is also nicer to the WinHTTP service. Then also hook up link change notifications to the cache to reset it if there's a chance the network might work sooner.
This commit is contained in:
parent
4cc0ed67f9
commit
5bcac4eaac
@ -10,14 +10,43 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
)
|
||||||
|
|
||||||
|
func setNoProxyUntil(d time.Duration) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
noProxyUntil = time.Now().Add(d)
|
||||||
|
}
|
||||||
|
|
||||||
// sysProxyFromEnv, if non-nil, specifies a platform-specific ProxyFromEnvironment
|
// sysProxyFromEnv, if non-nil, specifies a platform-specific ProxyFromEnvironment
|
||||||
// func to use if http.ProxyFromEnvironment doesn't return a proxy.
|
// func to use if http.ProxyFromEnvironment doesn't return a proxy.
|
||||||
// For example, WPAD PAC files on Windows.
|
// For example, WPAD PAC files on Windows.
|
||||||
var sysProxyFromEnv func(*http.Request) (*url.URL, error)
|
var sysProxyFromEnv func(*http.Request) (*url.URL, error)
|
||||||
|
|
||||||
func ProxyFromEnvironment(req *http.Request) (*url.URL, error) {
|
func ProxyFromEnvironment(req *http.Request) (*url.URL, error) {
|
||||||
|
mu.Lock()
|
||||||
|
noProxyTime := noProxyUntil
|
||||||
|
mu.Unlock()
|
||||||
|
if time.Now().Before(noProxyTime) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
u, err := http.ProxyFromEnvironment(req)
|
u, err := http.ProxyFromEnvironment(req)
|
||||||
if u != nil && err == nil {
|
if u != nil && err == nil {
|
||||||
return u, nil
|
return u, nil
|
||||||
|
@ -71,11 +71,19 @@ func proxyFromWinHTTPOrCache(req *http.Request) (*url.URL, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See https://docs.microsoft.com/en-us/windows/win32/winhttp/error-messages
|
// See https://docs.microsoft.com/en-us/windows/win32/winhttp/error-messages
|
||||||
const ERROR_WINHTTP_AUTODETECTION_FAILED = 12180
|
const (
|
||||||
|
ERROR_WINHTTP_AUTODETECTION_FAILED = 12180
|
||||||
|
ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT = 12167
|
||||||
|
)
|
||||||
if err == syscall.Errno(ERROR_WINHTTP_AUTODETECTION_FAILED) {
|
if err == syscall.Errno(ERROR_WINHTTP_AUTODETECTION_FAILED) {
|
||||||
|
setNoProxyUntil(10 * time.Second)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
log.Printf("tshttpproxy: winhttp: GetProxyForURL(%q): %v/%#v", urlStr, err, err)
|
log.Printf("tshttpproxy: winhttp: GetProxyForURL(%q): %v/%#v", urlStr, err, err)
|
||||||
|
if err == syscall.Errno(ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT) {
|
||||||
|
setNoProxyUntil(10 * time.Second)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
cachedProxy.Lock()
|
cachedProxy.Lock()
|
||||||
|
@ -242,7 +242,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
|||||||
log.Printf("setPrivateNetwork: adapter %v not found after %d tries, giving up", guid, tries)
|
log.Printf("setPrivateNetwork: adapter %v not found after %d tries, giving up", guid, tries)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
routes := []winipcfg.RouteData{}
|
|
||||||
var firstGateway4 *net.IP
|
var firstGateway4 *net.IP
|
||||||
var firstGateway6 *net.IP
|
var firstGateway6 *net.IP
|
||||||
addresses := make([]*net.IPNet, len(cfg.LocalAddrs))
|
addresses := make([]*net.IPNet, len(cfg.LocalAddrs))
|
||||||
@ -257,6 +256,7 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var routes []winipcfg.RouteData
|
||||||
foundDefault4 := false
|
foundDefault4 := false
|
||||||
foundDefault6 := false
|
foundDefault6 := false
|
||||||
for _, route := range cfg.Routes {
|
for _, route := range cfg.Routes {
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
"tailscale.com/net/interfaces"
|
"tailscale.com/net/interfaces"
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
|
"tailscale.com/net/tshttpproxy"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
@ -225,7 +226,10 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
|
|||||||
}
|
}
|
||||||
e.tundev.PreFilterOut = e.handleLocalPackets
|
e.tundev.PreFilterOut = e.handleLocalPackets
|
||||||
|
|
||||||
mon, err := monitor.New(logf, func() { e.LinkChange(false) })
|
mon, err := monitor.New(logf, func() {
|
||||||
|
e.LinkChange(false)
|
||||||
|
tshttpproxy.InvalidateCache()
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.tundev.Close()
|
e.tundev.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -349,6 +353,8 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
|
|||||||
}
|
}
|
||||||
// TODO(danderson): we should delete this. It's pointless to apply
|
// TODO(danderson): we should delete this. It's pointless to apply
|
||||||
// a no-op settings here.
|
// a no-op settings here.
|
||||||
|
// TODO(bradfitz): counter-point: it tests the router implementation early
|
||||||
|
// to see if any part of it might fail.
|
||||||
if err := e.router.Set(nil); err != nil {
|
if err := e.router.Set(nil); err != nil {
|
||||||
e.magicConn.Close()
|
e.magicConn.Close()
|
||||||
e.wgdev.Close()
|
e.wgdev.Close()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user