Line data Source code
1 : #pragma once 2 : 3 : #include "envoy/common/random_generator.h" 4 : #include "envoy/event/dispatcher.h" 5 : #include "envoy/extensions/common/dynamic_forward_proxy/v3/dns_cache.pb.h" 6 : #include "envoy/singleton/manager.h" 7 : #include "envoy/thread_local/thread_local.h" 8 : #include "envoy/upstream/resource_manager.h" 9 : 10 : #include "source/common/http/header_utility.h" 11 : #include "source/common/runtime/runtime_features.h" 12 : 13 : namespace Envoy { 14 : namespace Extensions { 15 : namespace Common { 16 : namespace DynamicForwardProxy { 17 : 18 : /** 19 : * A cached DNS host. 20 : */ 21 : class DnsHostInfo { 22 : public: 23 : // DFP hosts are created after a DNS lookup for a domain name (e.g. foo.com) but are created 24 : // with an IP address and port to resolve to. To prevent bugs where we insert say foo.com 25 : // (default port 80) then later look up foo.com (default port 443) and get IP addresses with 26 : // port 80, we "fully qualify" hostnames with the port. 27 : // 28 : // This normalizes hostnames, respecting the port if it exists, and adding the default port 29 : // if there is no port. 30 0 : static std::string normalizeHostForDfp(absl::string_view host, uint16_t default_port) { 31 0 : if (!Runtime::runtimeFeatureEnabled("envoy.reloadable_features.dfp_mixed_scheme")) { 32 0 : return std::string(host); 33 0 : } 34 0 : if (Http::HeaderUtility::hostHasPort(host)) { 35 0 : return std::string(host); 36 0 : } 37 0 : return absl::StrCat(host, ":", default_port); 38 0 : } 39 : 40 0 : virtual ~DnsHostInfo() = default; 41 : 42 : /** 43 : * Returns the host's currently resolved address. This address may change periodically due to 44 : * async re-resolution. This address may be null in the case of failed resolution. 45 : */ 46 : virtual Network::Address::InstanceConstSharedPtr address() const PURE; 47 : 48 : /** 49 : * Returns whether the first DNS resolving attempt is completed or not. 50 : */ 51 : virtual bool firstResolveComplete() const PURE; 52 : 53 : /** 54 : * Returns the host's currently resolved address. These addresses may change periodically due to 55 : * async re-resolution. 56 : */ 57 : virtual std::vector<Network::Address::InstanceConstSharedPtr> addressList() const PURE; 58 : 59 : /** 60 : * Returns the host that was actually resolved via DNS. If port was originally specified it will 61 : * be stripped from this return value. 62 : */ 63 : virtual const std::string& resolvedHost() const PURE; 64 : 65 : /** 66 : * Returns whether the original host is an IP address. 67 : */ 68 : virtual bool isIpAddress() const PURE; 69 : 70 : /** 71 : * Indicates that the host has been used and should not be purged depending on any configured 72 : * TTL policy 73 : */ 74 : virtual void touch() PURE; 75 : }; 76 : 77 : using DnsHostInfoSharedPtr = std::shared_ptr<DnsHostInfo>; 78 : 79 : #define ALL_DNS_CACHE_CIRCUIT_BREAKERS_STATS(OPEN_GAUGE, REMAINING_GAUGE) \ 80 0 : OPEN_GAUGE(rq_pending_open, Accumulate) \ 81 0 : REMAINING_GAUGE(rq_pending_remaining, Accumulate) 82 : 83 : struct DnsCacheCircuitBreakersStats { 84 : ALL_DNS_CACHE_CIRCUIT_BREAKERS_STATS(GENERATE_GAUGE_STRUCT, GENERATE_GAUGE_STRUCT) 85 : }; 86 : 87 : /** 88 : * A resource manager of DNS Cache. 89 : */ 90 : class DnsCacheResourceManager { 91 : public: 92 0 : virtual ~DnsCacheResourceManager() = default; 93 : 94 : /** 95 : * Returns the resource limit of pending requests to DNS. 96 : */ 97 : virtual ResourceLimit& pendingRequests() PURE; 98 : 99 : /** 100 : * Returns the reference of stats for dns cache circuit breakers. 101 : */ 102 : virtual DnsCacheCircuitBreakersStats& stats() PURE; 103 : }; 104 : 105 : /** 106 : * A cache of DNS hosts. Hosts will re-resolve their addresses or be automatically purged 107 : * depending on configured policy. 108 : */ 109 : class DnsCache { 110 : public: 111 : /** 112 : * Callbacks used in the loadDnsCacheEntry() method. 113 : */ 114 : class LoadDnsCacheEntryCallbacks { 115 : public: 116 0 : virtual ~LoadDnsCacheEntryCallbacks() = default; 117 : 118 : /** 119 : * Called when the DNS cache load is complete (or failed). 120 : * 121 : * @param host_info the DnsHostInfo for the resolved host. 122 : */ 123 : virtual void onLoadDnsCacheComplete(const DnsHostInfoSharedPtr& host_info) PURE; 124 : }; 125 : 126 : /** 127 : * Handle returned from loadDnsCacheEntry(). Destruction of the handle will cancel any future 128 : * callback. 129 : */ 130 : class LoadDnsCacheEntryHandle { 131 : public: 132 0 : virtual ~LoadDnsCacheEntryHandle() = default; 133 : }; 134 : 135 : using LoadDnsCacheEntryHandlePtr = std::unique_ptr<LoadDnsCacheEntryHandle>; 136 : 137 : /** 138 : * Update callbacks that can be registered in the addUpdateCallbacks() method. 139 : */ 140 : class UpdateCallbacks { 141 : public: 142 0 : virtual ~UpdateCallbacks() = default; 143 : 144 : /** 145 : * Called when a host has been added or has had its address updated. 146 : * @param host supplies the added/updated host. 147 : * @param host_info supplies the associated host info. 148 : */ 149 : virtual void onDnsHostAddOrUpdate(const std::string& host, 150 : const DnsHostInfoSharedPtr& host_info) PURE; 151 : 152 : /** 153 : * Called when a host has been removed. 154 : * @param host supplies the removed host. 155 : */ 156 : virtual void onDnsHostRemove(const std::string& host) PURE; 157 : 158 : /** 159 : * Called when any resolution for a host completes. 160 : * @param host supplies the added/updated host. 161 : * @param host_info supplies the associated host info. 162 : * @param status supplies the resolution status. 163 : */ 164 : virtual void onDnsResolutionComplete(const std::string& host, 165 : const DnsHostInfoSharedPtr& host_info, 166 : Network::DnsResolver::ResolutionStatus status) PURE; 167 : }; 168 : 169 : /** 170 : * Handle returned from addUpdateCallbacks(). Destruction of the handle will remove the 171 : * registered callbacks. 172 : */ 173 : class AddUpdateCallbacksHandle { 174 : public: 175 0 : virtual ~AddUpdateCallbacksHandle() = default; 176 : }; 177 : 178 : using AddUpdateCallbacksHandlePtr = std::unique_ptr<AddUpdateCallbacksHandle>; 179 : 180 5 : virtual ~DnsCache() = default; 181 : 182 : /** 183 : * Initiate a DNS cache load. 184 : * @param host supplies the host to load. Hosts are cached inclusive of port, even though the 185 : * port will be stripped during resolution. This means that 'a.b.c' and 'a.b.c:9001' 186 : * will both resolve 'a.b.c' but will generate different host entries with different 187 : * target ports. 188 : * @param default_port supplies the port to use if the host does not have a port embedded in it. 189 : * @param callbacks supplies the cache load callbacks to invoke if async processing is needed. 190 : * @return a cache load result which includes both a status and handle. If the handle is non-null 191 : * the callbacks will be invoked at a later time, otherwise consult the status for the 192 : * reason the cache is not loading. In this case, callbacks will never be called. 193 : */ 194 : enum class LoadDnsCacheEntryStatus { 195 : // The cache entry is already loaded. Callbacks will not be called. 196 : InCache, 197 : // The cache entry is loading. Callbacks will be called at a later time unless cancelled. 198 : Loading, 199 : // The cache is full and the requested host is not in cache. Callbacks will not be called. 200 : Overflow 201 : }; 202 : 203 : struct LoadDnsCacheEntryResult { 204 : LoadDnsCacheEntryStatus status_; 205 : LoadDnsCacheEntryHandlePtr handle_; 206 : absl::optional<DnsHostInfoSharedPtr> host_info_; 207 : }; 208 : 209 : /** 210 : * Attempt to load a DNS cache entry. 211 : * @param host the hostname to lookup 212 : * @param default_port the port to use 213 : * @param is_proxy_lookup indicates if the request is safe to fast-fail. The Dynamic Forward Proxy 214 : * filter sets this to true if no address is necessary due to an upstream proxy being configured. 215 : * @return a handle that on destruction will de-register the callbacks. 216 : */ 217 : virtual LoadDnsCacheEntryResult loadDnsCacheEntry(absl::string_view host, uint16_t default_port, 218 : bool is_proxy_lookup, 219 : LoadDnsCacheEntryCallbacks& callbacks) PURE; 220 : 221 : /** 222 : * Add update callbacks to the cache. 223 : * @param callbacks supplies the callbacks to add. 224 : * @return a handle that on destruction will de-register the callbacks. 225 : */ 226 : virtual AddUpdateCallbacksHandlePtr addUpdateCallbacks(UpdateCallbacks& callbacks) PURE; 227 : 228 : using IterateHostMapCb = std::function<void(absl::string_view, const DnsHostInfoSharedPtr&)>; 229 : 230 : /** 231 : * Iterates over all entries in the cache, calling a callback for each entry 232 : * 233 : * @param iterate_callback the callback to invoke for each entry in the cache 234 : */ 235 : virtual void iterateHostMap(IterateHostMapCb iterate_callback) PURE; 236 : 237 : /** 238 : * Retrieve the DNS host info of a given host currently stored in the cache. 239 : * @param host_name supplies the host name. 240 : * @return the DNS host info associated with the given host name if the host's address is cached, 241 : * otherwise `absl::nullopt`. 242 : */ 243 : virtual absl::optional<const DnsHostInfoSharedPtr> getHost(absl::string_view host_name) PURE; 244 : 245 : /** 246 : * Check if a DNS request is allowed given resource limits. 247 : * @return RAII handle for pending request circuit breaker if the request was allowed. 248 : */ 249 : virtual Upstream::ResourceAutoIncDecPtr canCreateDnsRequest() PURE; 250 : 251 : /** 252 : * Force a DNS refresh of all known hosts, ignoring any ongoing failure or success timers. This 253 : * can be used in response to network changes which might alter DNS responses, for example. 254 : */ 255 : virtual void forceRefreshHosts() PURE; 256 : }; 257 : 258 : using DnsCacheSharedPtr = std::shared_ptr<DnsCache>; 259 : 260 : /** 261 : * A manager for multiple DNS caches. 262 : */ 263 : class DnsCacheManager { 264 : public: 265 5 : virtual ~DnsCacheManager() = default; 266 : 267 : /** 268 : * Get a DNS cache. 269 : * @param config supplies the cache parameters. If a cache exists with the same parameters it 270 : * will be returned, otherwise a new one will be created. 271 : */ 272 : virtual absl::StatusOr<DnsCacheSharedPtr> 273 : getCache(const envoy::extensions::common::dynamic_forward_proxy::v3::DnsCacheConfig& config) PURE; 274 : 275 : /** 276 : * Look up an existing DNS cache by name. 277 : * @param name supplies the cache name to look up. If a cache exists with the same name it 278 : * will be returned. 279 : * @return pointer to the cache if it exists, nullptr otherwise. 280 : */ 281 : virtual DnsCacheSharedPtr lookUpCacheByName(absl::string_view cache_name) PURE; 282 : }; 283 : 284 : using DnsCacheManagerSharedPtr = std::shared_ptr<DnsCacheManager>; 285 : 286 : /** 287 : * Factory for getting a DNS cache manager. 288 : */ 289 : class DnsCacheManagerFactory { 290 : public: 291 5 : virtual ~DnsCacheManagerFactory() = default; 292 : 293 : /** 294 : * Get a DNS cache manager. 295 : */ 296 : virtual DnsCacheManagerSharedPtr get() PURE; 297 : }; 298 : 299 : } // namespace DynamicForwardProxy 300 : } // namespace Common 301 : } // namespace Extensions 302 : } // namespace Envoy