diff options
author | Emily Lange <[email protected]> | 2023-02-27 18:23:09 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2023-02-27 17:23:09 +0000 |
commit | 941eae5f615aeaf038f62002e673a7bf4886f1c7 (patch) | |
tree | 5bcbdac4f9f2662f7f4f44c0db05f330710ce6f6 /modules/caddyhttp/reverseproxy/upstreams.go | |
parent | 096971e313e1a8a32433213d3f2cb81b73d02b5e (diff) | |
download | caddy-941eae5f615aeaf038f62002e673a7bf4886f1c7.tar.gz caddy-941eae5f615aeaf038f62002e673a7bf4886f1c7.zip |
reverseproxy: allow specifying ip version for dynamic `a` upstream (#5401)
Co-authored-by: Francis Lavoie <[email protected]>
Diffstat (limited to 'modules/caddyhttp/reverseproxy/upstreams.go')
-rw-r--r-- | modules/caddyhttp/reverseproxy/upstreams.go | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/modules/caddyhttp/reverseproxy/upstreams.go b/modules/caddyhttp/reverseproxy/upstreams.go index 7a90016d0..30bd7b575 100644 --- a/modules/caddyhttp/reverseproxy/upstreams.go +++ b/modules/caddyhttp/reverseproxy/upstreams.go @@ -213,6 +213,11 @@ func (sl srvLookup) isFresh() bool { return time.Since(sl.freshness) < time.Duration(sl.srvUpstreams.Refresh) } +type ipVersions struct { + IPv4 *bool `json:"ipv4,omitempty"` + IPv6 *bool `json:"ipv6,omitempty"` +} + // AUpstreams provides upstreams from A/AAAA lookups. // Results are cached and refreshed at the configured // refresh interval. @@ -240,6 +245,11 @@ type AUpstreams struct { // A negative value disables this. FallbackDelay caddy.Duration `json:"dial_fallback_delay,omitempty"` + // The IP versions to resolve for. By default, both + // "ipv4" and "ipv6" will be enabled, which + // correspond to A and AAAA records respectively. + Versions *ipVersions `json:"versions,omitempty"` + resolver *net.Resolver } @@ -286,7 +296,29 @@ func (au *AUpstreams) Provision(_ caddy.Context) error { func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) { repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) - auStr := repl.ReplaceAll(au.String(), "") + + resolveIpv4 := au.Versions.IPv4 == nil || *au.Versions.IPv4 + resolveIpv6 := au.Versions.IPv6 == nil || *au.Versions.IPv6 + + // Map ipVersion early, so we can use it as part of the cache-key. + // This should be fairly inexpensive and comes and the upside of + // allowing the same dynamic upstream (name + port combination) + // to be used multiple times with different ip versions. + // + // It also forced a cache-miss if a previously cached dynamic + // upstream changes its ip version, e.g. after a config reload, + // while keeping the cache-invalidation as simple as it currently is. + var ipVersion string + switch { + case resolveIpv4 && !resolveIpv6: + ipVersion = "ip4" + case !resolveIpv4 && resolveIpv6: + ipVersion = "ip6" + default: + ipVersion = "ip" + } + + auStr := repl.ReplaceAll(au.String()+ipVersion, "") // first, use a cheap read-lock to return a cached result quickly aAaaaMu.RLock() @@ -311,7 +343,7 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) { name := repl.ReplaceAll(au.Name, "") port := repl.ReplaceAll(au.Port, "") - ips, err := au.resolver.LookupIPAddr(r.Context(), name) + ips, err := au.resolver.LookupIP(r.Context(), ipVersion, name) if err != nil { return nil, err } |