Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/filters/udp/dns_filter/dns_filter_resolver.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/filters/udp/dns_filter/dns_filter_resolver.h"
2
3
#include "source/common/network/utility.h"
4
5
namespace Envoy {
6
namespace Extensions {
7
namespace UdpFilters {
8
namespace DnsFilter {
9
10
void DnsFilterResolver::resolveExternalQuery(DnsQueryContextPtr context,
11
0
                                             const DnsQueryRecord* domain_query) {
12
  // Create an external resolution context for the query.
13
0
  LookupContext ctx{};
14
0
  ctx.query_rec = domain_query;
15
0
  ctx.query_context = std::move(context);
16
0
  ctx.query_context->in_callback_ = false;
17
0
  ctx.expiry = DateUtil::nowToSeconds(dispatcher_.timeSource()) +
18
0
               std::chrono::duration_cast<std::chrono::seconds>(timeout_).count();
19
0
  ctx.resolver_status = DnsFilterResolverStatus::Pending;
20
21
0
  Network::DnsLookupFamily lookup_family;
22
0
  switch (domain_query->type_) {
23
0
  case DNS_RECORD_TYPE_A:
24
0
    lookup_family = Network::DnsLookupFamily::V4Only;
25
0
    break;
26
0
  case DNS_RECORD_TYPE_AAAA:
27
0
    lookup_family = Network::DnsLookupFamily::V6Only;
28
0
    break;
29
0
  default:
30
    // We don't support other lookups other than A and AAAA. Set success here so that we don't
31
    // retry for something that we are certain will fail.
32
0
    ENVOY_LOG(debug, "Unknown query type [{}] for upstream lookup", domain_query->type_);
33
0
    ctx.query_context->resolution_status_ = Network::DnsResolver::ResolutionStatus::Success;
34
0
    ctx.resolver_status = DnsFilterResolverStatus::Complete;
35
0
    invokeCallback(ctx);
36
0
    return;
37
0
  }
38
39
0
  const DnsQueryRecord* id = domain_query;
40
41
  // If we have too many pending lookups, invoke the callback to retry the query.
42
0
  if (lookups_.size() > max_pending_lookups_) {
43
0
    ENVOY_LOG(
44
0
        trace,
45
0
        "Retrying query for [{}] because there are too many pending lookups: [pending {}/max {}]",
46
0
        domain_query->name_, lookups_.size(), max_pending_lookups_);
47
0
    ctx.resolver_status = DnsFilterResolverStatus::Complete;
48
0
    invokeCallback(ctx);
49
0
    return;
50
0
  }
51
52
0
  ctx.timeout_timer = dispatcher_.createTimer([this]() -> void { onResolveTimeout(); });
53
0
  ctx.timeout_timer->enableTimer(timeout_);
54
55
0
  lookups_.emplace(id, std::move(ctx));
56
57
0
  ENVOY_LOG(trace, "Pending queries: {}", lookups_.size());
58
59
  // Define the callback that is executed when resolution completes
60
  // Resolve the address in the query and add to the resolved_hosts vector
61
0
  resolver_->resolve(domain_query->name_, lookup_family,
62
0
                     [this, id](Network::DnsResolver::ResolutionStatus status,
63
0
                                std::list<Network::DnsResponse>&& response) -> void {
64
0
                       auto ctx_iter = lookups_.find(id);
65
66
                       // If the context is not in the map, the lookup has timed out and was removed
67
                       // when the timer executed
68
0
                       if (ctx_iter == lookups_.end()) {
69
0
                         ENVOY_LOG(debug, "Unable to find context for DNS query for ID [{}]",
70
0
                                   reinterpret_cast<intptr_t>(id));
71
0
                         return;
72
0
                       }
73
74
0
                       auto ctx = std::move(ctx_iter->second);
75
0
                       lookups_.erase(ctx_iter->first);
76
77
                       // We are processing the response here, so we did not timeout. Cancel the
78
                       // timer
79
0
                       ctx.timeout_timer->disableTimer();
80
81
0
                       ENVOY_LOG(trace, "async query status returned for query [{}]. Entries {}",
82
0
                                 ctx.query_context->id_, response.size());
83
0
                       ASSERT(ctx.resolver_status == DnsFilterResolverStatus::Pending);
84
85
0
                       ctx.query_context->in_callback_ = true;
86
0
                       ctx.query_context->resolution_status_ = status;
87
0
                       ctx.resolver_status = DnsFilterResolverStatus::Complete;
88
89
                       // C-ares doesn't expose the TTL in the data available here.
90
0
                       if (status == Network::DnsResolver::ResolutionStatus::Success) {
91
0
                         ctx.resolved_hosts.reserve(response.size());
92
0
                         for (const auto& resp : response) {
93
0
                           const auto& addrinfo = resp.addrInfo();
94
0
                           ASSERT(addrinfo.address_ != nullptr);
95
0
                           ENVOY_LOG(trace, "Resolved address: {} for {}",
96
0
                                     addrinfo.address_->ip()->addressAsString(),
97
0
                                     ctx.query_rec->name_);
98
0
                           ctx.resolved_hosts.emplace_back(std::move(addrinfo.address_));
99
0
                         }
100
0
                       }
101
                       // Invoke the filter callback notifying it of resolved addresses
102
0
                       invokeCallback(ctx);
103
0
                     });
104
0
}
105
106
0
void DnsFilterResolver::onResolveTimeout() {
107
0
  const uint64_t now = DateUtil::nowToSeconds(dispatcher_.timeSource());
108
0
  ENVOY_LOG(trace, "Pending queries: {}", lookups_.size());
109
110
  // Find an outstanding pending query and purge it
111
0
  for (auto& ctx_iter : lookups_) {
112
0
    if (ctx_iter.second.expiry <= now &&
113
0
        ctx_iter.second.resolver_status == DnsFilterResolverStatus::Pending) {
114
0
      auto ctx = std::move(ctx_iter.second);
115
116
0
      ENVOY_LOG(trace, "Purging expired query: {}", ctx_iter.first->name_);
117
118
0
      ctx.query_context->resolution_status_ = Network::DnsResolver::ResolutionStatus::Failure;
119
120
0
      lookups_.erase(ctx_iter.first);
121
0
      callback_(std::move(ctx.query_context), ctx.query_rec, ctx.resolved_hosts);
122
0
      return;
123
0
    }
124
0
  }
125
0
}
126
} // namespace DnsFilter
127
} // namespace UdpFilters
128
} // namespace Extensions
129
} // namespace Envoy