mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-08-10 13:20:33 +02:00
all: fallback to use direct IPs for ControlD assets
This commit is contained in:
+2
-1
@@ -1278,8 +1278,9 @@ func initUpgradeCmd() *cobra.Command {
|
|||||||
dlUrl := upgradeUrl(baseUrl)
|
dlUrl := upgradeUrl(baseUrl)
|
||||||
mainLog.Load().Debug().Msgf("Downloading binary: %s", dlUrl)
|
mainLog.Load().Debug().Msgf("Downloading binary: %s", dlUrl)
|
||||||
|
|
||||||
resp, err := getWithRetry(dlUrl)
|
resp, err := getWithRetry(dlUrl, downloadServerIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
mainLog.Load().Fatal().Err(err).Msg("failed to download binary")
|
mainLog.Load().Fatal().Err(err).Msg("failed to download binary")
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|||||||
@@ -519,13 +519,8 @@ func (p *prog) proxy(ctx context.Context, req *proxyRequest) *proxyResponse {
|
|||||||
ctrld.Log(ctx, mainLog.Load().Error().Err(err), "failed to create resolver")
|
ctrld.Log(ctx, mainLog.Load().Error().Err(err), "failed to create resolver")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resolveCtx, cancel := context.WithCancel(ctx)
|
resolveCtx, cancel := upstreamConfig.Context(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if upstreamConfig.Timeout > 0 {
|
|
||||||
timeoutCtx, cancel := context.WithTimeout(resolveCtx, time.Millisecond*time.Duration(upstreamConfig.Timeout))
|
|
||||||
defer cancel()
|
|
||||||
resolveCtx = timeoutCtx
|
|
||||||
}
|
|
||||||
return dnsResolver.Resolve(resolveCtx, msg)
|
return dnsResolver.Resolve(resolveCtx, msg)
|
||||||
}
|
}
|
||||||
resolve := func(upstream string, upstreamConfig *ctrld.UpstreamConfig, msg *dns.Msg) *dns.Msg {
|
resolve := func(upstream string, upstreamConfig *ctrld.UpstreamConfig, msg *dns.Msg) *dns.Msg {
|
||||||
|
|||||||
+19
-4
@@ -28,6 +28,7 @@ type AppConfig struct {
|
|||||||
const (
|
const (
|
||||||
defaultHTTPTimeout = 30 * time.Second
|
defaultHTTPTimeout = 30 * time.Second
|
||||||
defaultMaxRetries = 3
|
defaultMaxRetries = 3
|
||||||
|
downloadServerIp = "23.171.240.151"
|
||||||
)
|
)
|
||||||
|
|
||||||
// httpClientWithFallback returns an HTTP client configured with timeout and IPv4 fallback
|
// httpClientWithFallback returns an HTTP client configured with timeout and IPv4 fallback
|
||||||
@@ -46,10 +47,15 @@ func httpClientWithFallback(timeout time.Duration) *http.Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// doWithRetry performs an HTTP request with retries
|
// doWithRetry performs an HTTP request with retries
|
||||||
func doWithRetry(req *http.Request, maxRetries int) (*http.Response, error) {
|
func doWithRetry(req *http.Request, maxRetries int, ip string) (*http.Response, error) {
|
||||||
var lastErr error
|
var lastErr error
|
||||||
client := httpClientWithFallback(defaultHTTPTimeout)
|
client := httpClientWithFallback(defaultHTTPTimeout)
|
||||||
|
var ipReq *http.Request
|
||||||
|
if ip != "" {
|
||||||
|
ipReq = req.Clone(req.Context())
|
||||||
|
ipReq.Host = ip
|
||||||
|
ipReq.URL.Host = ip
|
||||||
|
}
|
||||||
for attempt := 0; attempt < maxRetries; attempt++ {
|
for attempt := 0; attempt < maxRetries; attempt++ {
|
||||||
if attempt > 0 {
|
if attempt > 0 {
|
||||||
time.Sleep(time.Second * time.Duration(attempt+1)) // Exponential backoff
|
time.Sleep(time.Second * time.Duration(attempt+1)) // Exponential backoff
|
||||||
@@ -59,6 +65,15 @@ func doWithRetry(req *http.Request, maxRetries int) (*http.Response, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
if ipReq != nil {
|
||||||
|
mainLog.Load().Warn().Err(err).Msgf("dial to %q failed", req.Host)
|
||||||
|
mainLog.Load().Warn().Msgf("fallback to direct IP to download prod version: %q", ip)
|
||||||
|
resp, err = client.Do(ipReq)
|
||||||
|
if err == nil {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lastErr = err
|
lastErr = err
|
||||||
mainLog.Load().Debug().Err(err).
|
mainLog.Load().Debug().Err(err).
|
||||||
Str("method", req.Method).
|
Str("method", req.Method).
|
||||||
@@ -69,10 +84,10 @@ func doWithRetry(req *http.Request, maxRetries int) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for making GET requests with retries
|
// Helper for making GET requests with retries
|
||||||
func getWithRetry(url string) (*http.Response, error) {
|
func getWithRetry(url string, ip string) (*http.Response, error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return doWithRetry(req, defaultMaxRetries)
|
return doWithRetry(req, defaultMaxRetries, ip)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,10 +53,27 @@ const (
|
|||||||
FreeDnsDomain = "freedns.controld.com"
|
FreeDnsDomain = "freedns.controld.com"
|
||||||
// FreeDNSBoostrapIP is the IP address of freedns.controld.com.
|
// FreeDNSBoostrapIP is the IP address of freedns.controld.com.
|
||||||
FreeDNSBoostrapIP = "76.76.2.11"
|
FreeDNSBoostrapIP = "76.76.2.11"
|
||||||
|
// FreeDNSBoostrapIPv6 is the IPv6 address of freedns.controld.com.
|
||||||
|
FreeDNSBoostrapIPv6 = "2606:1a40::11"
|
||||||
// PremiumDnsDomain is the domain name of premium ControlD service.
|
// PremiumDnsDomain is the domain name of premium ControlD service.
|
||||||
PremiumDnsDomain = "dns.controld.com"
|
PremiumDnsDomain = "dns.controld.com"
|
||||||
// PremiumDNSBoostrapIP is the IP address of dns.controld.com.
|
// PremiumDNSBoostrapIP is the IP address of dns.controld.com.
|
||||||
PremiumDNSBoostrapIP = "76.76.2.22"
|
PremiumDNSBoostrapIP = "76.76.2.22"
|
||||||
|
// PremiumDNSBoostrapIPv6 is the IPv6 address of dns.controld.com.
|
||||||
|
PremiumDNSBoostrapIPv6 = "2606:1a40::22"
|
||||||
|
|
||||||
|
// freeDnsDomainDev is the domain name of free ControlD service on dev env.
|
||||||
|
freeDnsDomainDev = "freedns.controld.dev"
|
||||||
|
// freeDNSBoostrapIP is the IP address of freedns.controld.dev.
|
||||||
|
freeDNSBoostrapIP = "176.125.239.11"
|
||||||
|
// freeDNSBoostrapIPv6 is the IPv6 address of freedns.controld.com.
|
||||||
|
freeDNSBoostrapIPv6 = "2606:1a40:f000::11"
|
||||||
|
// premiumDnsDomainDev is the domain name of premium ControlD service on dev env.
|
||||||
|
premiumDnsDomainDev = "dns.controld.dev"
|
||||||
|
// premiumDNSBoostrapIP is the IP address of dns.controld.dev.
|
||||||
|
premiumDNSBoostrapIP = "176.125.239.22"
|
||||||
|
// premiumDNSBoostrapIPv6 is the IPv6 address of dns.controld.dev.
|
||||||
|
premiumDNSBoostrapIPv6 = "2606:1a40:f000::22"
|
||||||
|
|
||||||
controlDComDomain = "controld.com"
|
controlDComDomain = "controld.com"
|
||||||
controlDNetDomain = "controld.net"
|
controlDNetDomain = "controld.net"
|
||||||
@@ -261,6 +278,7 @@ type UpstreamConfig struct {
|
|||||||
http3RoundTripper6 http.RoundTripper
|
http3RoundTripper6 http.RoundTripper
|
||||||
certPool *x509.CertPool
|
certPool *x509.CertPool
|
||||||
u *url.URL
|
u *url.URL
|
||||||
|
fallbackOnce sync.Once
|
||||||
uid string
|
uid string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,6 +444,10 @@ func (uc *UpstreamConfig) SetupBootstrapIP() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uc.bootstrapIPs = uc.bootstrapIPs[:n]
|
uc.bootstrapIPs = uc.bootstrapIPs[:n]
|
||||||
|
if len(uc.bootstrapIPs) == 0 {
|
||||||
|
uc.bootstrapIPs = bootstrapIPsFromControlDDomain(uc.Domain)
|
||||||
|
ProxyLogger.Load().Warn().Msgf("no bootstrap IPs found for %q, fallback to direct IPs", uc.Domain)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(uc.bootstrapIPs) > 0 {
|
if len(uc.bootstrapIPs) > 0 {
|
||||||
break
|
break
|
||||||
@@ -538,7 +560,10 @@ func (uc *UpstreamConfig) newDOHTransport(addrs []string) *http.Transport {
|
|||||||
|
|
||||||
// Ping warms up the connection to DoH/DoH3 upstream.
|
// Ping warms up the connection to DoH/DoH3 upstream.
|
||||||
func (uc *UpstreamConfig) Ping() {
|
func (uc *UpstreamConfig) Ping() {
|
||||||
_ = uc.ping()
|
if err := uc.ping(); err != nil {
|
||||||
|
ProxyLogger.Load().Debug().Err(err).Msgf("upstream ping failed: %s", uc.Endpoint)
|
||||||
|
_ = uc.FallbackToDirectIP()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorPing is like Ping, but return an error if any.
|
// ErrorPing is like Ping, but return an error if any.
|
||||||
@@ -575,7 +600,6 @@ func (uc *UpstreamConfig) ping() error {
|
|||||||
for _, typ := range []uint16{dns.TypeA, dns.TypeAAAA} {
|
for _, typ := range []uint16{dns.TypeA, dns.TypeAAAA} {
|
||||||
switch uc.Type {
|
switch uc.Type {
|
||||||
case ResolverTypeDOH:
|
case ResolverTypeDOH:
|
||||||
|
|
||||||
if err := ping(uc.dohTransport(typ)); err != nil {
|
if err := ping(uc.dohTransport(typ)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -743,6 +767,41 @@ func (uc *UpstreamConfig) initDnsStamps() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Context returns a new context with timeout set from upstream config.
|
||||||
|
func (uc *UpstreamConfig) Context(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||||
|
if uc.Timeout > 0 {
|
||||||
|
return context.WithTimeout(ctx, time.Millisecond*time.Duration(uc.Timeout))
|
||||||
|
}
|
||||||
|
return context.WithCancel(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FallbackToDirectIP changes ControlD upstream endpoint to use direct IP instead of domain.
|
||||||
|
func (uc *UpstreamConfig) FallbackToDirectIP() bool {
|
||||||
|
if !uc.IsControlD() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if uc.u == nil || uc.Domain == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
done := false
|
||||||
|
uc.fallbackOnce.Do(func() {
|
||||||
|
var ip string
|
||||||
|
switch {
|
||||||
|
case dns.IsSubDomain(PremiumDnsDomain, uc.Domain):
|
||||||
|
ip = PremiumDNSBoostrapIP
|
||||||
|
case dns.IsSubDomain(FreeDnsDomain, uc.Domain):
|
||||||
|
ip = FreeDNSBoostrapIP
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ProxyLogger.Load().Warn().Msgf("using direct IP for %q: %s", uc.Endpoint, ip)
|
||||||
|
uc.u.Host = ip
|
||||||
|
done = true
|
||||||
|
})
|
||||||
|
return done
|
||||||
|
}
|
||||||
|
|
||||||
// Init initialized necessary values for an ListenerConfig.
|
// Init initialized necessary values for an ListenerConfig.
|
||||||
func (lc *ListenerConfig) Init() {
|
func (lc *ListenerConfig) Init() {
|
||||||
if lc.Policy != nil {
|
if lc.Policy != nil {
|
||||||
@@ -889,3 +948,18 @@ func (uc *UpstreamConfig) String() string {
|
|||||||
return fmt.Sprintf("{name: %q, type: %q, endpoint: %q, bootstrap_ip: %q, domain: %q, ip_stack: %q}",
|
return fmt.Sprintf("{name: %q, type: %q, endpoint: %q, bootstrap_ip: %q, domain: %q, ip_stack: %q}",
|
||||||
uc.Name, uc.Type, uc.Endpoint, uc.BootstrapIP, uc.Domain, uc.IPStack)
|
uc.Name, uc.Type, uc.Endpoint, uc.BootstrapIP, uc.Domain, uc.IPStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bootstrapIPsFromControlDDomain returns bootstrap IPs for ControlD domain.
|
||||||
|
func bootstrapIPsFromControlDDomain(domain string) []string {
|
||||||
|
switch domain {
|
||||||
|
case PremiumDnsDomain:
|
||||||
|
return []string{PremiumDNSBoostrapIP, PremiumDNSBoostrapIPv6}
|
||||||
|
case FreeDnsDomain:
|
||||||
|
return []string{FreeDNSBoostrapIP, FreeDNSBoostrapIPv6}
|
||||||
|
case premiumDnsDomainDev:
|
||||||
|
return []string{premiumDNSBoostrapIP, premiumDNSBoostrapIPv6}
|
||||||
|
case freeDnsDomainDev:
|
||||||
|
return []string{freeDNSBoostrapIP, freeDNSBoostrapIPv6}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ func (r *dohResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, erro
|
|||||||
c.Transport = transport
|
c.Transport = transport
|
||||||
}
|
}
|
||||||
resp, err := c.Do(req)
|
resp, err := c.Do(req)
|
||||||
|
if err != nil && r.uc.FallbackToDirectIP() {
|
||||||
|
retryCtx, cancel := r.uc.Context(context.WithoutCancel(ctx))
|
||||||
|
defer cancel()
|
||||||
|
Log(ctx, ProxyLogger.Load().Warn().Err(err), "retrying request after fallback to direct ip")
|
||||||
|
resp, err = c.Do(req.Clone(retryCtx))
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if r.isDoH3 {
|
if r.isDoH3 {
|
||||||
if closer, ok := c.Transport.(io.Closer); ok {
|
if closer, ok := c.Transport.(io.Closer); ok {
|
||||||
|
|||||||
+59
-29
@@ -24,7 +24,10 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
apiDomainCom = "api.controld.com"
|
apiDomainCom = "api.controld.com"
|
||||||
|
apiDomainComIPv4 = "147.185.34.1"
|
||||||
|
apiDomainComIPv6 = "2606:1a40:3::1"
|
||||||
apiDomainDev = "api.controld.dev"
|
apiDomainDev = "api.controld.dev"
|
||||||
|
apiDomainDevIPv4 = "23.171.240.84"
|
||||||
apiURLCom = "https://api.controld.com"
|
apiURLCom = "https://api.controld.com"
|
||||||
apiURLDev = "https://api.controld.dev"
|
apiURLDev = "https://api.controld.dev"
|
||||||
resolverDataURLCom = apiURLCom + "/utility"
|
resolverDataURLCom = apiURLCom + "/utility"
|
||||||
@@ -136,11 +139,11 @@ func postUtilityAPI(version string, cdDev, lastUpdatedFailed bool, body io.Reade
|
|||||||
req.URL.RawQuery = q.Encode()
|
req.URL.RawQuery = q.Encode()
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
transport := apiTransport(cdDev)
|
transport := apiTransport(cdDev)
|
||||||
client := http.Client{
|
client := &http.Client{
|
||||||
Timeout: defaultTimeout,
|
Timeout: defaultTimeout,
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
resp, err := client.Do(req)
|
resp, err := doWithFallback(client, req, apiServerIP(cdDev))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("postUtilityAPI client.Do: %w", err)
|
return nil, fmt.Errorf("postUtilityAPI client.Do: %w", err)
|
||||||
}
|
}
|
||||||
@@ -177,11 +180,11 @@ func SendLogs(lr *LogsRequest, cdDev bool) error {
|
|||||||
req.URL.RawQuery = q.Encode()
|
req.URL.RawQuery = q.Encode()
|
||||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
transport := apiTransport(cdDev)
|
transport := apiTransport(cdDev)
|
||||||
client := http.Client{
|
client := &http.Client{
|
||||||
Timeout: sendLogTimeout,
|
Timeout: sendLogTimeout,
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
resp, err := client.Do(req)
|
resp, err := doWithFallback(client, req, apiServerIP(cdDev))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("SendLogs client.Do: %w", err)
|
return fmt.Errorf("SendLogs client.Do: %w", err)
|
||||||
}
|
}
|
||||||
@@ -213,20 +216,20 @@ func apiTransport(cdDev bool) *http.Transport {
|
|||||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
apiDomain := apiDomainCom
|
apiDomain := apiDomainCom
|
||||||
|
apiIpsV4 := []string{apiDomainComIPv4}
|
||||||
|
apiIpsV6 := []string{apiDomainComIPv6}
|
||||||
|
apiIPs := []string{apiDomainComIPv4, apiDomainComIPv6}
|
||||||
if cdDev {
|
if cdDev {
|
||||||
apiDomain = apiDomainDev
|
apiDomain = apiDomainDev
|
||||||
}
|
apiIpsV4 = []string{apiDomainDevIPv4}
|
||||||
|
apiIpsV6 = []string{}
|
||||||
// First try IPv4
|
apiIPs = []string{apiDomainDevIPv4}
|
||||||
dialer := &net.Dialer{
|
|
||||||
Timeout: 10 * time.Second,
|
|
||||||
KeepAlive: 30 * time.Second,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ips := ctrld.LookupIP(apiDomain)
|
ips := ctrld.LookupIP(apiDomain)
|
||||||
if len(ips) == 0 {
|
if len(ips) == 0 {
|
||||||
ctrld.ProxyLogger.Load().Warn().Msgf("No IPs found for %s, falling back to direct connection to %s", apiDomain, addr)
|
ctrld.ProxyLogger.Load().Warn().Msgf("No IPs found for %s, use direct IPs: %v", apiDomain, apiIPs)
|
||||||
return dialer.DialContext(ctx, network, addr)
|
ips = apiIPs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separate IPv4 and IPv6 addresses
|
// Separate IPv4 and IPv6 addresses
|
||||||
@@ -239,35 +242,62 @@ func apiTransport(cdDev bool) *http.Transport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dial := func(ctx context.Context, network string, addrs []string) (net.Conn, error) {
|
||||||
|
d := &ctrldnet.ParallelDialer{}
|
||||||
|
return d.DialContext(ctx, network, addrs, ctrld.ProxyLogger.Load())
|
||||||
|
}
|
||||||
_, port, _ := net.SplitHostPort(addr)
|
_, port, _ := net.SplitHostPort(addr)
|
||||||
|
|
||||||
// Try IPv4 first
|
// Try IPv4 first
|
||||||
if len(ipv4s) > 0 {
|
if len(ipv4s) > 0 {
|
||||||
addrs := make([]string, len(ipv4s))
|
if conn, err := dial(ctx, "tcp4", addrsFromPort(ipv4s, port)); err == nil {
|
||||||
for i, ip := range ipv4s {
|
|
||||||
addrs[i] = net.JoinHostPort(ip, port)
|
|
||||||
}
|
|
||||||
d := &ctrldnet.ParallelDialer{}
|
|
||||||
if conn, err := d.DialContext(ctx, "tcp4", addrs, ctrld.ProxyLogger.Load()); err == nil {
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Fallback to direct IPv4
|
||||||
// Fall back to IPv6 if available
|
if conn, err := dial(ctx, "tcp4", addrsFromPort(apiIpsV4, port)); err == nil {
|
||||||
if len(ipv6s) > 0 {
|
return conn, nil
|
||||||
addrs := make([]string, len(ipv6s))
|
|
||||||
for i, ip := range ipv6s {
|
|
||||||
addrs[i] = net.JoinHostPort(ip, port)
|
|
||||||
}
|
|
||||||
d := &ctrldnet.ParallelDialer{}
|
|
||||||
return d.DialContext(ctx, "tcp6", addrs, ctrld.ProxyLogger.Load())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final fallback to direct connection
|
// Fallback to IPv6 if available
|
||||||
return dialer.DialContext(ctx, network, addr)
|
if len(ipv6s) > 0 {
|
||||||
|
if conn, err := dial(ctx, "tcp6", addrsFromPort(ipv6s, port)); err == nil {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback to direct IPv6
|
||||||
|
return dial(ctx, "tcp6", addrsFromPort(apiIpsV6, port))
|
||||||
}
|
}
|
||||||
if router.Name() == ddwrt.Name || runtime.GOOS == "android" {
|
if router.Name() == ddwrt.Name || runtime.GOOS == "android" {
|
||||||
transport.TLSClientConfig = &tls.Config{RootCAs: certs.CACertPool()}
|
transport.TLSClientConfig = &tls.Config{RootCAs: certs.CACertPool()}
|
||||||
}
|
}
|
||||||
return transport
|
return transport
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addrsFromPort(ips []string, port string) []string {
|
||||||
|
addrs := make([]string, len(ips))
|
||||||
|
for i, ip := range ips {
|
||||||
|
addrs[i] = net.JoinHostPort(ip, port)
|
||||||
|
}
|
||||||
|
return addrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func doWithFallback(client *http.Client, req *http.Request, apiIp string) (*http.Response, error) {
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
ctrld.ProxyLogger.Load().Warn().Err(err).Msgf("failed to send request, fallback to direct IP: %s", apiIp)
|
||||||
|
ipReq := req.Clone(req.Context())
|
||||||
|
ipReq.Host = apiIp
|
||||||
|
ipReq.URL.Host = apiIp
|
||||||
|
resp, err = client.Do(ipReq)
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// apiServerIP returns the direct IP to connect to API server.
|
||||||
|
func apiServerIP(cdDev bool) string {
|
||||||
|
if cdDev {
|
||||||
|
return apiDomainDevIPv4
|
||||||
|
}
|
||||||
|
return apiDomainComIPv4
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user