Directory: | cvmfs/ |
---|---|
File: | cvmfs/network/dns.cc |
Date: | 2025-09-14 02:35:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 617 | 698 | 88.4% |
Branches: | 515 | 806 | 63.9% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | * | ||
4 | * The CernVM-FS name resolving uses objects that inherit from the Resolver | ||
5 | * interface. Resolvers implement a vector interface that resolves multiple | ||
6 | * names in parallel. Common cases such as IP addresses as names are handled | ||
7 | * by the base class -- Resolver implementations only have to resolve real host | ||
8 | * names to IPv4/6 addresses, using given search domains if necessary. | ||
9 | * | ||
10 | * Name resolving information is stored in Host objects. Host objects are | ||
11 | * immutable. They associate a hostname with sets of IPv4 and IPv6 addresses. | ||
12 | * They also carry the result of the name resolution attempt (success, failure) | ||
13 | * and the TTL in the form of a deadline. They are only created by a resolver | ||
14 | * and upon creation carry a unique id that corresponds to a particular name | ||
15 | * resolving attempt. | ||
16 | * | ||
17 | * The NormalResolver uses both the CaresResolver for DNS queries and the | ||
18 | * HostfileResolve for queries in /etc/hosts. If an entry is found in | ||
19 | * /etc/hosts, the CaresResolver is unused. | ||
20 | */ | ||
21 | |||
22 | #include "dns.h" | ||
23 | |||
24 | #include <arpa/inet.h> | ||
25 | #include <arpa/nameser.h> | ||
26 | #include <errno.h> | ||
27 | #include <netdb.h> | ||
28 | #include <poll.h> | ||
29 | #include <unistd.h> | ||
30 | |||
31 | #include <algorithm> | ||
32 | #include <cassert> | ||
33 | #include <cstdio> | ||
34 | #include <cstdlib> | ||
35 | #include <cstring> | ||
36 | |||
37 | #include "sanitizer.h" | ||
38 | #include "util/exception.h" | ||
39 | #include "util/logging.h" | ||
40 | #include "util/smalloc.h" | ||
41 | #include "util/string.h" | ||
42 | |||
43 | using namespace std; // NOLINT | ||
44 | |||
45 | namespace dns { | ||
46 | |||
47 | /** | ||
48 | * Sets pos_begin and pos_end to the first/last character of the host name in | ||
49 | * a string like http://<hostname>:<port>. Works also if the host name is an | ||
50 | * IPv4/6 address. Sets pos_begin and pos_end to 0 if url doesn't match the | ||
51 | * format. | ||
52 | */ | ||
53 | 10590 | static void PinpointHostSubstr(const std::string &url, | |
54 | unsigned *pos_begin, | ||
55 | unsigned *pos_end) { | ||
56 | 10590 | *pos_begin = *pos_end = 0; | |
57 | 10590 | const unsigned len = url.size(); | |
58 | 10590 | unsigned i = 0; | |
59 | |||
60 | // Search '//' in the url string and jump behind | ||
61 |
2/2✓ Branch 0 taken 65268 times.
✓ Branch 1 taken 3436 times.
|
68704 | for (; i < len; ++i) { |
62 |
8/8✓ Branch 1 taken 7778 times.
✓ Branch 2 taken 57490 times.
✓ Branch 3 taken 7298 times.
✓ Branch 4 taken 480 times.
✓ Branch 6 taken 7154 times.
✓ Branch 7 taken 144 times.
✓ Branch 8 taken 7154 times.
✓ Branch 9 taken 58114 times.
|
65268 | if ((url[i] == '/') && (i < len - 2) && (url[i + 1] == '/')) { |
63 | 7154 | i += 2; | |
64 | 7154 | *pos_begin = i; | |
65 | 7154 | break; | |
66 | } | ||
67 | } | ||
68 | |||
69 | // Search '@' within the hostname part and jump behind if present | ||
70 |
2/2✓ Branch 0 taken 7154 times.
✓ Branch 1 taken 3436 times.
|
10590 | if (*pos_begin > 0) { |
71 |
2/2✓ Branch 0 taken 79660 times.
✓ Branch 1 taken 5810 times.
|
85470 | for (i = *pos_begin; i < len; ++i) { |
72 |
2/2✓ Branch 1 taken 1104 times.
✓ Branch 2 taken 78556 times.
|
79660 | if (url[i] == '/') { |
73 | 1104 | break; | |
74 |
2/2✓ Branch 1 taken 240 times.
✓ Branch 2 taken 78316 times.
|
78556 | } else if (url[i] == '@') { |
75 | 240 | *pos_begin = ++i; | |
76 | 240 | break; | |
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // Find the end of the hostname part | ||
82 |
2/2✓ Branch 0 taken 7154 times.
✓ Branch 1 taken 3436 times.
|
10590 | if (*pos_begin > 0) { |
83 | 7154 | bool in_ipv6 = (url[*pos_begin] == '['); | |
84 |
2/2✓ Branch 0 taken 60020 times.
✓ Branch 1 taken 912 times.
|
60932 | for (i = *pos_begin; i < len; ++i) { |
85 |
2/2✓ Branch 0 taken 5280 times.
✓ Branch 1 taken 54740 times.
|
60020 | if (in_ipv6) { |
86 |
2/2✓ Branch 1 taken 4272 times.
✓ Branch 2 taken 1008 times.
|
5280 | if (url[i] != ']') |
87 | 4272 | continue; | |
88 | 1008 | in_ipv6 = false; | |
89 | } | ||
90 | |||
91 |
6/6✓ Branch 1 taken 50178 times.
✓ Branch 2 taken 5570 times.
✓ Branch 4 taken 672 times.
✓ Branch 5 taken 49506 times.
✓ Branch 6 taken 6242 times.
✓ Branch 7 taken 49506 times.
|
55748 | if ((url[i] == ':') || (url[i] == '/')) |
92 | 6242 | break; | |
93 | } | ||
94 |
2/2✓ Branch 0 taken 6866 times.
✓ Branch 1 taken 288 times.
|
7154 | if (!in_ipv6) |
95 | 6866 | *pos_end = i - 1; | |
96 | |||
97 |
2/2✓ Branch 0 taken 864 times.
✓ Branch 1 taken 6290 times.
|
7154 | if (*pos_end < *pos_begin) |
98 | 864 | *pos_end = *pos_begin = 0; | |
99 | } | ||
100 | 10590 | } | |
101 | |||
102 | |||
103 | /** | ||
104 | * Returns the host name from a string in the format | ||
105 | * http://<hostname>:<port>[/path] | ||
106 | * or an empty string if url doesn't match the format. | ||
107 | */ | ||
108 | 5501 | std::string ExtractHost(const std::string &url) { | |
109 | unsigned pos_begin; | ||
110 | unsigned pos_end; | ||
111 | 5501 | PinpointHostSubstr(url, &pos_begin, &pos_end); | |
112 |
2/2✓ Branch 0 taken 2764 times.
✓ Branch 1 taken 2737 times.
|
5501 | if (pos_begin == 0) |
113 |
1/2✓ Branch 2 taken 2764 times.
✗ Branch 3 not taken.
|
2764 | return ""; |
114 |
1/2✓ Branch 1 taken 2737 times.
✗ Branch 2 not taken.
|
2737 | return url.substr(pos_begin, (pos_end - pos_begin) + 1); |
115 | } | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Returns the port from a string in the format | ||
120 | * http://<hostname>:<port>/path | ||
121 | * or an empty string if url doesn't match the format. | ||
122 | */ | ||
123 | 4117 | std::string ExtractPort(const std::string &url) { | |
124 | unsigned pos_begin; | ||
125 | unsigned pos_end; | ||
126 | 4117 | PinpointHostSubstr(url, &pos_begin, &pos_end); | |
127 |
9/10✓ Branch 0 taken 3109 times.
✓ Branch 1 taken 1008 times.
✓ Branch 3 taken 2773 times.
✓ Branch 4 taken 336 times.
✓ Branch 6 taken 2773 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 144 times.
✓ Branch 9 taken 2629 times.
✓ Branch 10 taken 1488 times.
✓ Branch 11 taken 2629 times.
|
4117 | if (pos_begin == 0 || pos_end + 2 >= url.size() || url.at(pos_end + 1) != ':') |
128 |
1/2✓ Branch 2 taken 1488 times.
✗ Branch 3 not taken.
|
1488 | return ""; |
129 | |||
130 | // Do not include path | ||
131 | 2629 | const std::size_t pos_port = url.find("/", pos_end); | |
132 | 2629 | std::string retme; | |
133 |
2/2✓ Branch 0 taken 2341 times.
✓ Branch 1 taken 288 times.
|
2629 | if (pos_port == std::string::npos) |
134 |
1/2✓ Branch 1 taken 2341 times.
✗ Branch 2 not taken.
|
2341 | retme = url.substr(pos_end + 2); |
135 | else | ||
136 |
1/2✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
|
288 | retme = url.substr(pos_end + 2, pos_port - pos_end - 2); |
137 | |||
138 | // Port is an integer | ||
139 |
2/2✓ Branch 4 taken 8548 times.
✓ Branch 5 taken 2437 times.
|
10985 | for (std::string::iterator it = retme.begin(); it != retme.end(); ++it) |
140 |
2/2✓ Branch 1 taken 192 times.
✓ Branch 2 taken 8356 times.
|
8548 | if (isdigit(*it) == 0) |
141 |
1/2✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
|
192 | return ""; |
142 | |||
143 | 2437 | return retme; | |
144 | 2629 | } | |
145 | |||
146 | |||
147 | /** | ||
148 | * Replaces the host name in the url with the given IP address. If it is an | ||
149 | * IPv6 address, it has to be in brackets. If the input is not a valid URL, | ||
150 | * it is returned unmodified. | ||
151 | */ | ||
152 | 972 | string RewriteUrl(const string &url, const string &ip) { | |
153 | unsigned pos_begin; | ||
154 | unsigned pos_end; | ||
155 | 972 | PinpointHostSubstr(url, &pos_begin, &pos_end); | |
156 |
2/2✓ Branch 0 taken 528 times.
✓ Branch 1 taken 444 times.
|
972 | if (pos_begin == 0) |
157 |
1/2✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
|
528 | return url; |
158 | |||
159 |
1/2✓ Branch 1 taken 444 times.
✗ Branch 2 not taken.
|
444 | string result = url; |
160 |
1/2✓ Branch 1 taken 444 times.
✗ Branch 2 not taken.
|
444 | result.replace(pos_begin, (pos_end - pos_begin) + 1, ip); |
161 | 444 | return result; | |
162 | 444 | } | |
163 | |||
164 | |||
165 | /** | ||
166 | * Removes the brackets from IPv6 addresses. Leaves IPv4 addresses unchanged. | ||
167 | */ | ||
168 | 384 | string StripIp(const string &decorated_ip) { | |
169 |
2/2✓ Branch 1 taken 336 times.
✓ Branch 2 taken 48 times.
|
384 | if (!decorated_ip.empty()) { |
170 | 336 | if ((decorated_ip[0] == '[') | |
171 |
6/6✓ Branch 0 taken 192 times.
✓ Branch 1 taken 144 times.
✓ Branch 4 taken 96 times.
✓ Branch 5 taken 96 times.
✓ Branch 6 taken 96 times.
✓ Branch 7 taken 240 times.
|
336 | && (decorated_ip[decorated_ip.length() - 1] == ']')) { |
172 | 96 | return decorated_ip.substr(1, decorated_ip.length() - 2); | |
173 | } | ||
174 | } | ||
175 | 288 | return decorated_ip; | |
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Adds http:// if it is missing from proxy | ||
181 | */ | ||
182 | 5216 | std::string AddDefaultScheme(const std::string &proxy) { | |
183 | 5216 | const bool ignore_case = true; | |
184 |
4/12✓ Branch 1 taken 5216 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5216 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5072 times.
✓ Branch 8 taken 144 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
10432 | if (HasPrefix(proxy, "http://", ignore_case) |
185 |
9/19✓ Branch 2 taken 5144 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5144 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5096 times.
✓ Branch 8 taken 48 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 192 times.
✓ Branch 11 taken 4904 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 5144 times.
✓ Branch 14 taken 72 times.
✓ Branch 16 taken 5216 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
|
10360 | || HasPrefix(proxy, "https://", ignore_case) || (proxy == "DIRECT") |
186 |
7/9✓ Branch 2 taken 5216 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5144 times.
✓ Branch 5 taken 72 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
✓ Branch 8 taken 144 times.
✓ Branch 9 taken 5144 times.
✓ Branch 10 taken 72 times.
|
15576 | || proxy.empty()) { |
187 | 5072 | return proxy; | |
188 | } | ||
189 | 144 | return "http://" + proxy; | |
190 | } | ||
191 | |||
192 | |||
193 | //------------------------------------------------------------------------------ | ||
194 | |||
195 | |||
196 | atomic_int64 Host::global_id_ = 0; | ||
197 | |||
198 | 444 | const set<string> &Host::ViewBestAddresses(IpPreference preference) const { | |
199 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 144 times.
|
288 | if (((preference == kIpPreferSystem) || (preference == kIpPreferV4)) |
200 |
6/6✓ Branch 0 taken 288 times.
✓ Branch 1 taken 156 times.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 96 times.
✓ Branch 5 taken 204 times.
✓ Branch 6 taken 240 times.
|
732 | && HasIpv4()) { |
201 | 204 | return ipv4_addresses_; | |
202 | } | ||
203 |
6/6✓ Branch 0 taken 144 times.
✓ Branch 1 taken 96 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 96 times.
✓ Branch 5 taken 48 times.
✓ Branch 6 taken 192 times.
|
240 | if ((preference == kIpPreferV6) && !HasIpv6()) |
204 | 48 | return ipv4_addresses_; | |
205 | 192 | return ipv6_addresses_; | |
206 | } | ||
207 | |||
208 | |||
209 | 23323 | void Host::CopyFrom(const Host &other) { | |
210 | 23323 | deadline_ = other.deadline_; | |
211 | 23323 | id_ = other.id_; | |
212 | 23323 | ipv4_addresses_ = other.ipv4_addresses_; | |
213 | 23323 | ipv6_addresses_ = other.ipv6_addresses_; | |
214 | 23323 | name_ = other.name_; | |
215 | 23323 | status_ = other.status_; | |
216 | 23323 | } | |
217 | |||
218 | |||
219 | /** | ||
220 | * Creates a copy of the original host with a new ID and sets a new dealine | ||
221 | * given in seconds from the current time. | ||
222 | */ | ||
223 | 48 | Host Host::ExtendDeadline(const Host &original, unsigned seconds_from_now) { | |
224 | 48 | Host new_host(original); | |
225 | 48 | new_host.id_ = atomic_xadd64(&global_id_, 1); | |
226 | 48 | new_host.deadline_ = time(NULL) + seconds_from_now; | |
227 | 48 | return new_host; | |
228 | } | ||
229 | |||
230 | |||
231 | /** | ||
232 | * All fields except the unique id_ are set by the resolver. Host objects | ||
233 | * can be copied around but only the resolver can create valid, new objects. | ||
234 | */ | ||
235 | 13686 | Host::Host() | |
236 | 13686 | : deadline_(0) | |
237 | 13686 | , id_(atomic_xadd64(&global_id_, 1)) | |
238 | 13686 | , status_(kFailNotYetResolved) { } | |
239 | |||
240 | |||
241 |
1/2✓ Branch 4 taken 17992 times.
✗ Branch 5 not taken.
|
17992 | Host::Host(const Host &other) { CopyFrom(other); } |
242 | |||
243 | |||
244 | 5334 | Host &Host::operator=(const Host &other) { | |
245 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5331 times.
|
5334 | if (&other == this) |
246 | 3 | return *this; | |
247 | 5331 | CopyFrom(other); | |
248 | 5331 | return *this; | |
249 | } | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Compares the name and the resolved addresses independent of deadlines. Used | ||
254 | * to decide if the current proxy list needs to be changed after re-resolving | ||
255 | * a host name. | ||
256 | */ | ||
257 | 1056 | bool Host::IsEquivalent(const Host &other) const { | |
258 |
2/2✓ Branch 0 taken 864 times.
✓ Branch 1 taken 48 times.
|
912 | return (status_ == kFailOk) && (other.status_ == kFailOk) |
259 |
3/4✓ Branch 1 taken 864 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 768 times.
✓ Branch 5 taken 96 times.
|
864 | && (name_ == other.name_) && (ipv4_addresses_ == other.ipv4_addresses_) |
260 |
4/4✓ Branch 0 taken 912 times.
✓ Branch 1 taken 144 times.
✓ Branch 3 taken 576 times.
✓ Branch 4 taken 192 times.
|
1968 | && (ipv6_addresses_ == other.ipv6_addresses_); |
261 | } | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Compares the TTL from a provious call to time() with the current time. | ||
266 | */ | ||
267 | 684 | bool Host::IsExpired() const { | |
268 | 684 | const time_t now = time(NULL); | |
269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 684 times.
|
684 | assert(now != static_cast<time_t>(-1)); |
270 | 684 | return deadline_ < now; | |
271 | } | ||
272 | |||
273 | |||
274 | /** | ||
275 | * A host object is valid after it has been successfully resolved and until the | ||
276 | * DNS ttl expires. Successful name resolution means that there is at least | ||
277 | * one IP address. | ||
278 | */ | ||
279 | 768 | bool Host::IsValid() const { | |
280 |
2/2✓ Branch 0 taken 288 times.
✓ Branch 1 taken 480 times.
|
768 | if (status_ != kFailOk) |
281 | 288 | return false; | |
282 | |||
283 |
3/4✓ Branch 1 taken 96 times.
✓ Branch 2 taken 384 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 96 times.
|
480 | assert(!ipv4_addresses_.empty() || !ipv6_addresses_.empty()); |
284 | 480 | return !IsExpired(); | |
285 | } | ||
286 | |||
287 | |||
288 | //------------------------------------------------------------------------------ | ||
289 | |||
290 | |||
291 | /** | ||
292 | * Basic input validation to ensure that this could syntactically represent a | ||
293 | * valid IPv4 address. | ||
294 | */ | ||
295 | 38048 | bool Resolver::IsIpv4Address(const string &address) { | |
296 | // Are there any unexpected characters? | ||
297 |
2/4✓ Branch 2 taken 38048 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 38048 times.
✗ Branch 6 not taken.
|
76096 | const sanitizer::InputSanitizer sanitizer("09 ."); |
298 |
3/4✓ Branch 1 taken 38048 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15364 times.
✓ Branch 4 taken 22684 times.
|
38048 | if (!sanitizer.IsValid(address)) |
299 | 15364 | return false; | |
300 | |||
301 | // 4 octets in the range 0-255? | ||
302 |
1/2✓ Branch 1 taken 22684 times.
✗ Branch 2 not taken.
|
22684 | vector<string> octets = SplitString(address, '.'); |
303 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 22636 times.
|
22684 | if (octets.size() != 4) |
304 | 48 | return false; | |
305 |
2/2✓ Branch 0 taken 90544 times.
✓ Branch 1 taken 22588 times.
|
113132 | for (unsigned i = 0; i < 4; ++i) { |
306 |
1/2✓ Branch 2 taken 90544 times.
✗ Branch 3 not taken.
|
90544 | const uint64_t this_octet = String2Uint64(octets[i]); |
307 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 90496 times.
|
90544 | if (this_octet > 255) |
308 | 48 | return false; | |
309 | } | ||
310 | |||
311 | 22588 | return true; | |
312 | 38048 | } | |
313 | |||
314 | |||
315 | /** | ||
316 | * Basic input validation to ensure that this could syntactically represent a | ||
317 | * valid IPv6 address. | ||
318 | */ | ||
319 | 2112 | bool Resolver::IsIpv6Address(const string &address) { | |
320 | // Are there any unexpected characters? | ||
321 |
2/4✓ Branch 2 taken 2112 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2112 times.
✗ Branch 6 not taken.
|
4224 | const sanitizer::InputSanitizer sanitizer("09 af AF :"); |
322 |
1/2✓ Branch 1 taken 2112 times.
✗ Branch 2 not taken.
|
4224 | return sanitizer.IsValid(address); |
323 | 2112 | } | |
324 | |||
325 | |||
326 | 23598 | Resolver::Resolver(const bool ipv4_only, | |
327 | const unsigned retries, | ||
328 | 23598 | const unsigned timeout_ms) | |
329 | 23598 | : ipv4_only_(ipv4_only) | |
330 | 23598 | , retries_(retries) | |
331 | 23598 | , timeout_ms_(timeout_ms) | |
332 | 23598 | , throttle_(0) | |
333 | 23598 | , min_ttl_(kDefaultMinTtl) | |
334 | 23598 | , max_ttl_(kDefaultMaxTtl) { | |
335 | 23598 | prng_.InitLocaltime(); | |
336 | 23598 | } | |
337 | |||
338 | |||
339 | /** | ||
340 | * Wrapper around the vector interface. | ||
341 | */ | ||
342 | 3298 | Host Resolver::Resolve(const string &name) { | |
343 | 3298 | vector<string> names; | |
344 |
1/2✓ Branch 1 taken 3298 times.
✗ Branch 2 not taken.
|
3298 | names.push_back(name); |
345 | 3298 | vector<Host> hosts; | |
346 |
1/2✓ Branch 1 taken 3298 times.
✗ Branch 2 not taken.
|
3298 | ResolveMany(names, &hosts); |
347 |
1/2✓ Branch 2 taken 3298 times.
✗ Branch 3 not taken.
|
6596 | return hosts[0]; |
348 | 3298 | } | |
349 | |||
350 | |||
351 | /** | ||
352 | * Calls the overwritten concrete resolver, verifies the sanity of the returned | ||
353 | * addresses and constructs the Host objects in the same order as the names. | ||
354 | */ | ||
355 | 5879 | void Resolver::ResolveMany(const vector<string> &names, vector<Host> *hosts) { | |
356 | 5879 | const unsigned num = names.size(); | |
357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5879 times.
|
5879 | if (num == 0) |
358 | ✗ | return; | |
359 | |||
360 |
1/2✓ Branch 2 taken 5879 times.
✗ Branch 3 not taken.
|
5879 | vector<vector<string> > ipv4_addresses(num); |
361 |
1/2✓ Branch 2 taken 5879 times.
✗ Branch 3 not taken.
|
5879 | vector<vector<string> > ipv6_addresses(num); |
362 |
1/2✓ Branch 2 taken 5879 times.
✗ Branch 3 not taken.
|
5879 | vector<Failures> failures(num); |
363 |
1/2✓ Branch 2 taken 5879 times.
✗ Branch 3 not taken.
|
5879 | vector<unsigned> ttls(num); |
364 |
1/2✓ Branch 2 taken 5879 times.
✗ Branch 3 not taken.
|
5879 | vector<string> fqdns(num); |
365 |
1/2✓ Branch 2 taken 5879 times.
✗ Branch 3 not taken.
|
5879 | vector<bool> skip(num); |
366 | |||
367 | // Deal with special names: empty, IPv4, IPv6 | ||
368 |
2/2✓ Branch 0 taken 7082 times.
✓ Branch 1 taken 5879 times.
|
12961 | for (unsigned i = 0; i < num; ++i) { |
369 |
2/2✓ Branch 2 taken 2476 times.
✓ Branch 3 taken 4606 times.
|
7082 | if (names[i].empty()) { |
370 |
1/2✓ Branch 1 taken 2476 times.
✗ Branch 2 not taken.
|
2476 | LogCvmfs(kLogDns, kLogDebug, "empty hostname"); |
371 | 2476 | Host invalid_host; | |
372 |
1/2✓ Branch 1 taken 2476 times.
✗ Branch 2 not taken.
|
2476 | invalid_host.name_ = ""; |
373 | 2476 | invalid_host.status_ = kFailInvalidHost; | |
374 |
1/2✓ Branch 1 taken 2476 times.
✗ Branch 2 not taken.
|
2476 | hosts->push_back(invalid_host); |
375 |
1/2✓ Branch 1 taken 2476 times.
✗ Branch 2 not taken.
|
2476 | skip[i] = true; |
376 |
3/4✓ Branch 3 taken 4606 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 622 times.
✓ Branch 6 taken 3984 times.
|
7082 | } else if (IsIpv4Address(names[i])) { |
377 |
1/2✓ Branch 3 taken 622 times.
✗ Branch 4 not taken.
|
622 | LogCvmfs(kLogDns, kLogDebug, "IPv4 address %s", names[i].c_str()); |
378 | 622 | Host ipv4_host; | |
379 |
1/2✓ Branch 2 taken 622 times.
✗ Branch 3 not taken.
|
622 | ipv4_host.name_ = names[i]; |
380 | 622 | ipv4_host.status_ = kFailOk; | |
381 |
1/2✓ Branch 2 taken 622 times.
✗ Branch 3 not taken.
|
622 | ipv4_host.ipv4_addresses_.insert(names[i]); |
382 | 622 | ipv4_host.deadline_ = time(NULL) + max_ttl_; | |
383 |
1/2✓ Branch 1 taken 622 times.
✗ Branch 2 not taken.
|
622 | hosts->push_back(ipv4_host); |
384 |
1/2✓ Branch 1 taken 622 times.
✗ Branch 2 not taken.
|
622 | skip[i] = true; |
385 |
2/2✓ Branch 5 taken 192 times.
✓ Branch 6 taken 3552 times.
|
8350 | } else if ((names[i].length() >= 3) && (names[i][0] == '[') |
386 |
5/6✓ Branch 0 taken 3744 times.
✓ Branch 1 taken 240 times.
✓ Branch 6 taken 192 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 192 times.
✓ Branch 9 taken 3792 times.
|
7728 | && (names[i][names[i].length() - 1] == ']')) { |
387 |
1/2✓ Branch 3 taken 192 times.
✗ Branch 4 not taken.
|
192 | LogCvmfs(kLogDns, kLogDebug, "IPv6 address %s", names[i].c_str()); |
388 | 192 | Host ipv6_host; | |
389 |
1/2✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
|
192 | ipv6_host.name_ = names[i]; |
390 | 192 | ipv6_host.status_ = kFailOk; | |
391 |
1/2✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
|
192 | ipv6_host.ipv6_addresses_.insert(names[i]); |
392 | 192 | ipv6_host.deadline_ = time(NULL) + max_ttl_; | |
393 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | hosts->push_back(ipv6_host); |
394 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | skip[i] = true; |
395 | 192 | } else { | |
396 |
1/2✓ Branch 2 taken 3792 times.
✗ Branch 3 not taken.
|
3792 | hosts->push_back(Host()); |
397 |
1/2✓ Branch 1 taken 3792 times.
✗ Branch 2 not taken.
|
3792 | skip[i] = false; |
398 | } | ||
399 | } | ||
400 | |||
401 |
1/2✓ Branch 1 taken 5879 times.
✗ Branch 2 not taken.
|
5879 | DoResolve(names, skip, &ipv4_addresses, &ipv6_addresses, &failures, &ttls, |
402 | &fqdns); | ||
403 | |||
404 | // Construct host objects | ||
405 |
2/2✓ Branch 0 taken 7082 times.
✓ Branch 1 taken 5879 times.
|
12961 | for (unsigned i = 0; i < num; ++i) { |
406 |
3/5✓ Branch 1 taken 7082 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3290 times.
✓ Branch 5 taken 3792 times.
|
7082 | if (skip[i]) |
407 | 4058 | continue; | |
408 | |||
409 | 3792 | Host host; | |
410 |
1/2✓ Branch 2 taken 3792 times.
✗ Branch 3 not taken.
|
3792 | host.name_ = fqdns[i]; |
411 | 3792 | host.status_ = failures[i]; | |
412 | |||
413 | 3792 | unsigned effective_ttl = ttls[i]; | |
414 |
2/2✓ Branch 0 taken 816 times.
✓ Branch 1 taken 2976 times.
|
3792 | if (effective_ttl < min_ttl_) { |
415 | 816 | effective_ttl = min_ttl_; | |
416 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 2880 times.
|
2976 | } else if (effective_ttl > max_ttl_) { |
417 | 96 | effective_ttl = max_ttl_; | |
418 | } | ||
419 | 3792 | host.deadline_ = time(NULL) + effective_ttl; | |
420 | |||
421 |
2/2✓ Branch 0 taken 768 times.
✓ Branch 1 taken 3024 times.
|
3792 | if (host.status_ != kFailOk) { |
422 |
1/2✓ Branch 3 taken 768 times.
✗ Branch 4 not taken.
|
1536 | LogCvmfs(kLogDns, kLogDebug, "failed to resolve %s - %d (%s), ttl %u", |
423 | 768 | names[i].c_str(), host.status_, Code2Ascii(host.status_), | |
424 | effective_ttl); | ||
425 |
1/2✓ Branch 2 taken 768 times.
✗ Branch 3 not taken.
|
768 | (*hosts)[i] = host; |
426 | 768 | continue; | |
427 | } | ||
428 | |||
429 | // Verify addresses and make them readily available for curl | ||
430 |
2/2✓ Branch 2 taken 3408 times.
✓ Branch 3 taken 3024 times.
|
6432 | for (unsigned j = 0; j < ipv4_addresses[i].size(); ++j) { |
431 |
3/4✓ Branch 3 taken 3408 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 192 times.
✓ Branch 6 taken 3216 times.
|
3408 | if (!IsIpv4Address(ipv4_addresses[i][j])) { |
432 |
1/4✓ Branch 3 taken 192 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
384 | LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, |
433 | "host name %s resolves to invalid IPv4 address %s", | ||
434 | 384 | names[i].c_str(), ipv4_addresses[i][j].c_str()); | |
435 | 192 | continue; | |
436 | } | ||
437 |
2/2✓ Branch 2 taken 2928 times.
✓ Branch 3 taken 288 times.
|
3216 | if (names[i] == host.name_) { |
438 |
1/2✓ Branch 4 taken 2928 times.
✗ Branch 5 not taken.
|
2928 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s", names[i].c_str(), |
439 | 2928 | ipv4_addresses[i][j].c_str()); | |
440 | } else { | ||
441 |
1/2✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
|
576 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s -> %s", |
442 | 288 | names[i].c_str(), host.name_.c_str(), | |
443 | 288 | ipv4_addresses[i][j].c_str()); | |
444 | } | ||
445 |
1/2✓ Branch 3 taken 3216 times.
✗ Branch 4 not taken.
|
3216 | host.ipv4_addresses_.insert(ipv4_addresses[i][j]); |
446 | } | ||
447 | |||
448 |
2/2✓ Branch 2 taken 2112 times.
✓ Branch 3 taken 3024 times.
|
5136 | for (unsigned j = 0; j < ipv6_addresses[i].size(); ++j) { |
449 |
3/4✓ Branch 3 taken 2112 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 96 times.
✓ Branch 6 taken 2016 times.
|
2112 | if (!IsIpv6Address(ipv6_addresses[i][j])) { |
450 |
1/4✓ Branch 3 taken 96 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
192 | LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, |
451 | "host name %s resolves to invalid IPv6 address %s", | ||
452 | 192 | names[i].c_str(), ipv6_addresses[i][j].c_str()); | |
453 | 96 | continue; | |
454 | } | ||
455 | // For URLs we need brackets around IPv6 addresses | ||
456 |
2/2✓ Branch 2 taken 1872 times.
✓ Branch 3 taken 144 times.
|
2016 | if (names[i] == host.name_) { |
457 |
1/2✓ Branch 4 taken 1872 times.
✗ Branch 5 not taken.
|
1872 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s", names[i].c_str(), |
458 | 1872 | ipv6_addresses[i][j].c_str()); | |
459 | } else { | ||
460 |
1/2✓ Branch 4 taken 144 times.
✗ Branch 5 not taken.
|
288 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s -> %s", |
461 | 144 | names[i].c_str(), host.name_.c_str(), | |
462 | 144 | ipv6_addresses[i][j].c_str()); | |
463 | } | ||
464 |
3/6✓ Branch 3 taken 2016 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2016 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2016 times.
✗ Branch 10 not taken.
|
2016 | host.ipv6_addresses_.insert("[" + ipv6_addresses[i][j] + "]"); |
465 | } | ||
466 | |||
467 |
6/6✓ Branch 1 taken 240 times.
✓ Branch 2 taken 2784 times.
✓ Branch 4 taken 144 times.
✓ Branch 5 taken 96 times.
✓ Branch 6 taken 144 times.
✓ Branch 7 taken 2880 times.
|
3024 | if (host.ipv4_addresses_.empty() && host.ipv6_addresses_.empty()) { |
468 |
1/2✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
|
144 | LogCvmfs(kLogDns, kLogDebug, "no addresses returned for %s", |
469 | 144 | names[i].c_str()); | |
470 | 144 | host.status_ = kFailNoAddress; | |
471 | } | ||
472 | |||
473 | // Remove surplus IP addresses | ||
474 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2976 times.
|
3024 | if (throttle_ > 0) { |
475 |
2/2✓ Branch 1 taken 96 times.
✓ Branch 2 taken 48 times.
|
144 | while (host.ipv4_addresses_.size() > throttle_) { |
476 | 96 | const unsigned random = prng_.Next(host.ipv4_addresses_.size()); | |
477 | 96 | set<string>::iterator rnd_itr = host.ipv4_addresses_.begin(); | |
478 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | std::advance(rnd_itr, random); |
479 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | host.ipv4_addresses_.erase(rnd_itr); |
480 | } | ||
481 |
2/2✓ Branch 1 taken 96 times.
✓ Branch 2 taken 48 times.
|
144 | while (host.ipv6_addresses_.size() > throttle_) { |
482 | 96 | const unsigned random = prng_.Next(host.ipv6_addresses_.size()); | |
483 | 96 | set<string>::iterator rnd_itr = host.ipv6_addresses_.begin(); | |
484 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | std::advance(rnd_itr, random); |
485 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | host.ipv6_addresses_.erase(rnd_itr); |
486 | } | ||
487 | } | ||
488 | |||
489 |
1/2✓ Branch 2 taken 3024 times.
✗ Branch 3 not taken.
|
3024 | (*hosts)[i] = host; |
490 |
2/2✓ Branch 1 taken 3024 times.
✓ Branch 2 taken 768 times.
|
3792 | } |
491 | 5879 | } | |
492 | |||
493 | |||
494 | //------------------------------------------------------------------------------ | ||
495 | |||
496 | |||
497 | namespace { | ||
498 | |||
499 | enum ResourceRecord { | ||
500 | kRrA = 0, | ||
501 | kRrAaaa, | ||
502 | }; | ||
503 | |||
504 | /** | ||
505 | * Used to transport a name resolving request across the asynchronous c-ares | ||
506 | * interface. The QueryInfo objects are used for both IPv4 and IPv6 requests. | ||
507 | * The addresses are entered directly via pointers, ttls and fqdns are later | ||
508 | * merged into a single response (for IPv4/IPv6). | ||
509 | */ | ||
510 | struct QueryInfo { | ||
511 | 2928 | QueryInfo(vector<string> *a, const string &n, const ResourceRecord r) | |
512 | 2928 | : addresses(a) | |
513 | 2928 | , complete(false) | |
514 | 2928 | , fqdn(n) | |
515 |
1/2✓ Branch 1 taken 2928 times.
✗ Branch 2 not taken.
|
2928 | , name(n) |
516 | 2928 | , record(r) | |
517 | 2928 | , status(kFailOther) | |
518 | 2928 | , ttl(0) { } | |
519 | |||
520 | vector<string> *addresses; | ||
521 | bool complete; | ||
522 | string fqdn; | ||
523 | string name; | ||
524 | ResourceRecord record; | ||
525 | Failures status; | ||
526 | unsigned ttl; | ||
527 | }; | ||
528 | |||
529 | } // namespace | ||
530 | |||
531 | |||
532 | static Failures CaresExtractIpv4(const unsigned char *abuf, int alen, | ||
533 | vector<string> *addresses, unsigned *ttl, | ||
534 | string *fqdn); | ||
535 | static Failures CaresExtractIpv6(const unsigned char *abuf, int alen, | ||
536 | vector<string> *addresses, unsigned *ttl, | ||
537 | string *fqdn); | ||
538 | |||
539 | /** | ||
540 | * Called when a DNS query returns or times out. Sets the return status and the | ||
541 | * IP addresses (if successful) in the QueryInfo object. | ||
542 | */ | ||
543 | 2928 | static void CallbackCares(void *arg, int status, int timeouts_ms, | |
544 | unsigned char *abuf, int alen) { | ||
545 | 2928 | QueryInfo *info = reinterpret_cast<QueryInfo *>(arg); | |
546 | |||
547 | 2928 | info->complete = true; | |
548 |
5/7✓ Branch 0 taken 2304 times.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 384 times.
✓ Branch 4 taken 144 times.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
|
2928 | switch (status) { |
549 | 2304 | case ARES_SUCCESS: | |
550 | Failures retval; | ||
551 |
2/3✓ Branch 0 taken 1200 times.
✓ Branch 1 taken 1104 times.
✗ Branch 2 not taken.
|
2304 | switch (info->record) { |
552 | 1200 | case kRrA: | |
553 | 1200 | retval = CaresExtractIpv4(abuf, alen, info->addresses, &info->ttl, | |
554 | &info->fqdn); | ||
555 | 1200 | break; | |
556 | 1104 | case kRrAaaa: | |
557 | 1104 | retval = CaresExtractIpv6(abuf, alen, info->addresses, &info->ttl, | |
558 | &info->fqdn); | ||
559 | 1104 | break; | |
560 | ✗ | default: | |
561 | // Never here. | ||
562 | ✗ | PANIC(NULL); | |
563 | } | ||
564 | 2304 | info->status = retval; | |
565 | 2304 | break; | |
566 | 48 | case ARES_ENODATA: | |
567 | 48 | info->status = kFailUnknownHost; | |
568 | 48 | break; | |
569 | ✗ | case ARES_EFORMERR: | |
570 | ✗ | info->status = kFailMalformed; | |
571 | ✗ | break; | |
572 | 384 | case ARES_ENOTFOUND: | |
573 | 384 | info->status = kFailUnknownHost; | |
574 | 384 | break; | |
575 | 144 | case ARES_ETIMEOUT: | |
576 | 144 | info->status = kFailTimeout; | |
577 | 144 | break; | |
578 | 48 | case ARES_ECONNREFUSED: | |
579 | 48 | info->status = kFailInvalidResolvers; | |
580 | 48 | break; | |
581 | ✗ | default: | |
582 | ✗ | info->status = kFailOther; | |
583 | } | ||
584 | 2928 | } | |
585 | |||
586 | |||
587 | /** | ||
588 | * Extracts IPv4 addresses from an A record return in c-ares. TTLs are | ||
589 | * merged to a single one, representing the minimum. | ||
590 | */ | ||
591 | 1200 | static Failures CaresExtractIpv4(const unsigned char *abuf, | |
592 | int alen, | ||
593 | vector<string> *addresses, | ||
594 | unsigned *ttl, | ||
595 | string *fqdn) { | ||
596 | 1200 | struct hostent *host_entry = NULL; | |
597 | struct ares_addrttl records[CaresResolver::kMaxAddresses]; | ||
598 | 1200 | int naddrttls = CaresResolver::kMaxAddresses; | |
599 |
1/2✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
|
1200 | const int retval = ares_parse_a_reply(abuf, alen, &host_entry, records, |
600 | &naddrttls); | ||
601 | |||
602 |
1/3✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1200 | switch (retval) { |
603 | 1200 | case ARES_SUCCESS: | |
604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | if (host_entry == NULL) |
605 | ✗ | return kFailMalformed; | |
606 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | if (host_entry->h_name == NULL) { |
607 | ✗ | ares_free_hostent(host_entry); | |
608 | ✗ | return kFailMalformed; | |
609 | } | ||
610 |
1/2✓ Branch 2 taken 1200 times.
✗ Branch 3 not taken.
|
1200 | *fqdn = string(host_entry->h_name); |
611 |
1/2✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
|
1200 | ares_free_hostent(host_entry); |
612 | |||
613 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | if (naddrttls <= 0) |
614 | ✗ | return kFailMalformed; | |
615 | 1200 | *ttl = unsigned(-1); | |
616 |
2/2✓ Branch 0 taken 1200 times.
✓ Branch 1 taken 1200 times.
|
2400 | for (unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) { |
617 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | if (records[i].ttl < 0) |
618 | ✗ | continue; | |
619 | 1200 | *ttl = std::min(unsigned(records[i].ttl), *ttl); | |
620 | |||
621 | char addrstr[INET_ADDRSTRLEN]; | ||
622 | 1200 | const void *retval_p = inet_ntop(AF_INET, &(records[i].ipaddr), addrstr, | |
623 | INET_ADDRSTRLEN); | ||
624 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | if (!retval_p) |
625 | ✗ | continue; | |
626 |
2/4✓ Branch 2 taken 1200 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1200 times.
✗ Branch 6 not taken.
|
1200 | addresses->push_back(addrstr); |
627 | } | ||
628 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1200 times.
|
1200 | if (addresses->empty()) |
629 | ✗ | return kFailMalformed; | |
630 | 1200 | return kFailOk; | |
631 | ✗ | case ARES_EBADRESP: | |
632 | // Fall through | ||
633 | case ARES_ENODATA: | ||
634 | ✗ | return kFailMalformed; | |
635 | ✗ | default: | |
636 | ✗ | return kFailOther; | |
637 | } | ||
638 | } | ||
639 | |||
640 | |||
641 | 1104 | static Failures CaresExtractIpv6(const unsigned char *abuf, | |
642 | int alen, | ||
643 | vector<string> *addresses, | ||
644 | unsigned *ttl, | ||
645 | string *fqdn) { | ||
646 | 1104 | struct hostent *host_entry = NULL; | |
647 | struct ares_addr6ttl records[CaresResolver::kMaxAddresses]; | ||
648 | 1104 | int naddrttls = CaresResolver::kMaxAddresses; | |
649 |
1/2✓ Branch 1 taken 1104 times.
✗ Branch 2 not taken.
|
1104 | const int retval = ares_parse_aaaa_reply(abuf, alen, &host_entry, records, |
650 | &naddrttls); | ||
651 | |||
652 |
1/3✓ Branch 0 taken 1104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1104 | switch (retval) { |
653 | 1104 | case ARES_SUCCESS: | |
654 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1104 times.
|
1104 | if (host_entry == NULL) |
655 | ✗ | return kFailMalformed; | |
656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1104 times.
|
1104 | if (host_entry->h_name == NULL) { |
657 | ✗ | ares_free_hostent(host_entry); | |
658 | ✗ | return kFailMalformed; | |
659 | } | ||
660 |
1/2✓ Branch 2 taken 1104 times.
✗ Branch 3 not taken.
|
1104 | *fqdn = string(host_entry->h_name); |
661 |
1/2✓ Branch 1 taken 1104 times.
✗ Branch 2 not taken.
|
1104 | ares_free_hostent(host_entry); |
662 | |||
663 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1104 times.
|
1104 | if (naddrttls <= 0) |
664 | ✗ | return kFailMalformed; | |
665 | 1104 | *ttl = unsigned(-1); | |
666 |
2/2✓ Branch 0 taken 1104 times.
✓ Branch 1 taken 1104 times.
|
2208 | for (unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) { |
667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1104 times.
|
1104 | if (records[i].ttl < 0) |
668 | ✗ | continue; | |
669 | 1104 | *ttl = std::min(unsigned(records[i].ttl), *ttl); | |
670 | |||
671 | char addrstr[INET6_ADDRSTRLEN]; | ||
672 | 1104 | const void *retval_p = inet_ntop(AF_INET6, &(records[i].ip6addr), | |
673 | addrstr, INET6_ADDRSTRLEN); | ||
674 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1104 times.
|
1104 | if (!retval_p) |
675 | ✗ | continue; | |
676 |
2/4✓ Branch 2 taken 1104 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1104 times.
✗ Branch 6 not taken.
|
1104 | addresses->push_back(addrstr); |
677 | } | ||
678 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1104 times.
|
1104 | if (addresses->empty()) |
679 | ✗ | return kFailMalformed; | |
680 | 1104 | return kFailOk; | |
681 | ✗ | case ARES_EBADRESP: | |
682 | // Fall through | ||
683 | case ARES_ENODATA: | ||
684 | ✗ | return kFailMalformed; | |
685 | ✗ | default: | |
686 | ✗ | return kFailOther; | |
687 | } | ||
688 | } | ||
689 | |||
690 | |||
691 | 10226 | CaresResolver::CaresResolver(const bool ipv4_only, | |
692 | const unsigned retries, | ||
693 | 10226 | const unsigned timeout_ms) | |
694 | : Resolver(ipv4_only, retries, timeout_ms) | ||
695 | 10226 | , channel_(NULL) | |
696 | 10226 | , lookup_options_(strdup("b")) { } | |
697 | |||
698 | |||
699 | 39124 | CaresResolver::~CaresResolver() { | |
700 |
1/2✓ Branch 0 taken 9781 times.
✗ Branch 1 not taken.
|
19562 | if (channel_) { |
701 | 19562 | ares_destroy(*channel_); | |
702 | 19562 | free(channel_); | |
703 | } | ||
704 | 19562 | free(lookup_options_); | |
705 | 39124 | } | |
706 | |||
707 | |||
708 | /** | ||
709 | * Returns a CaresResolver readily initialized, or NULL if an error occurs. | ||
710 | */ | ||
711 | 10226 | CaresResolver *CaresResolver::Create(const bool ipv4_only, | |
712 | const unsigned retries, | ||
713 | const unsigned timeout_ms) { | ||
714 | int retval; | ||
715 |
2/2✓ Branch 1 taken 49 times.
✓ Branch 2 taken 10177 times.
|
10226 | if (getenv("HOSTALIASES") == NULL) { |
716 | 49 | retval = setenv("HOSTALIASES", "/etc/hosts", 1); | |
717 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | assert(retval == 0); |
718 | } | ||
719 | |||
720 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | CaresResolver *resolver = new CaresResolver(ipv4_only, retries, timeout_ms); |
721 | 10226 | resolver->channel_ = reinterpret_cast<ares_channel *>( | |
722 | 10226 | smalloc(sizeof(ares_channel))); | |
723 | 10226 | memset(resolver->channel_, 0, sizeof(ares_channel)); | |
724 | |||
725 | struct ares_addr_node *addresses; | ||
726 | struct ares_addr_node *iter; | ||
727 | struct ares_options options; | ||
728 | int optmask; | ||
729 | 10226 | memset(&options, 0, sizeof(options)); | |
730 | 10226 | options.timeout = timeout_ms; | |
731 | 10226 | options.tries = 1 + retries; | |
732 | 10226 | options.lookups = resolver->lookup_options_; | |
733 | 10226 | optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_LOOKUPS; | |
734 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | retval = ares_init_options(resolver->channel_, &options, optmask); |
735 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10226 times.
|
10226 | if (retval != ARES_SUCCESS) |
736 | ✗ | goto create_fail; | |
737 | |||
738 | // Save search domains | ||
739 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | retval = ares_save_options(*resolver->channel_, &options, &optmask); |
740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10226 times.
|
10226 | if (retval != ARES_SUCCESS) |
741 | ✗ | goto create_fail; | |
742 |
2/2✓ Branch 0 taken 10226 times.
✓ Branch 1 taken 10226 times.
|
20452 | for (int i = 0; i < options.ndomains; ++i) { |
743 |
2/4✓ Branch 2 taken 10226 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10226 times.
✗ Branch 6 not taken.
|
10226 | resolver->domains_.push_back(options.domains[i]); |
744 | } | ||
745 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | ares_destroy_options(&options); |
746 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | resolver->system_domains_ = resolver->domains_; |
747 | |||
748 | // Save the system default resolvers | ||
749 | 10226 | addresses = NULL; | |
750 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | retval = ares_get_servers(*resolver->channel_, &addresses); |
751 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10226 times.
|
10226 | if (retval != ARES_SUCCESS) |
752 | ✗ | goto create_fail; | |
753 | 10226 | iter = addresses; | |
754 |
2/2✓ Branch 0 taken 51130 times.
✓ Branch 1 taken 10226 times.
|
61356 | while (iter) { |
755 |
2/3✓ Branch 0 taken 30678 times.
✓ Branch 1 taken 20452 times.
✗ Branch 2 not taken.
|
51130 | switch (iter->family) { |
756 | 30678 | case AF_INET: { | |
757 | char addrstr[INET_ADDRSTRLEN]; | ||
758 | 30678 | const void *retval_p = inet_ntop(AF_INET, &(iter->addr), addrstr, | |
759 | INET_ADDRSTRLEN); | ||
760 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30678 times.
|
30678 | if (!retval_p) { |
761 | ✗ | LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr, | |
762 | "invalid system name resolver"); | ||
763 | } else { | ||
764 |
3/6✓ Branch 2 taken 30678 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 30678 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 30678 times.
✗ Branch 9 not taken.
|
30678 | resolver->resolvers_.push_back(string(addrstr) + ":53"); |
765 | } | ||
766 | 30678 | break; | |
767 | } | ||
768 | 20452 | case AF_INET6: { | |
769 | char addrstr[INET6_ADDRSTRLEN]; | ||
770 | 20452 | const void *retval_p = inet_ntop(AF_INET6, &(iter->addr), addrstr, | |
771 | INET6_ADDRSTRLEN); | ||
772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20452 times.
|
20452 | if (!retval_p) { |
773 | ✗ | LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr, | |
774 | "invalid system name resolver"); | ||
775 | } else { | ||
776 |
4/8✓ Branch 2 taken 20452 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20452 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20452 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 20452 times.
✗ Branch 12 not taken.
|
20452 | resolver->resolvers_.push_back("[" + string(addrstr) + "]:53"); |
777 | } | ||
778 | 20452 | break; | |
779 | } | ||
780 | ✗ | default: | |
781 | // Never here. | ||
782 | ✗ | PANIC(NULL); | |
783 | } | ||
784 | 51130 | iter = iter->next; | |
785 | } | ||
786 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | ares_free_data(addresses); |
787 |
1/2✓ Branch 1 taken 10226 times.
✗ Branch 2 not taken.
|
10226 | resolver->system_resolvers_ = resolver->resolvers_; |
788 | |||
789 | 10226 | return resolver; | |
790 | |||
791 | ✗ | create_fail: | |
792 | ✗ | LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr, | |
793 | "failed to initialize c-ares resolver (%d - %s)", retval, | ||
794 | ares_strerror(retval)); | ||
795 | ✗ | free(resolver->channel_); | |
796 | ✗ | resolver->channel_ = NULL; | |
797 | ✗ | delete resolver; | |
798 | ✗ | return NULL; | |
799 | } | ||
800 | |||
801 | |||
802 | /** | ||
803 | * Pushes all the DNS queries into the c-ares channel and waits for the results | ||
804 | * on the file descriptors. | ||
805 | */ | ||
806 | 3623 | void CaresResolver::DoResolve(const vector<string> &names, | |
807 | const vector<bool> &skip, | ||
808 | vector<vector<string> > *ipv4_addresses, | ||
809 | vector<vector<string> > *ipv6_addresses, | ||
810 | vector<Failures> *failures, | ||
811 | vector<unsigned> *ttls, | ||
812 | vector<string> *fqdns) { | ||
813 | 3623 | const unsigned num = names.size(); | |
814 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3623 times.
|
3623 | if (num == 0) |
815 | ✗ | return; | |
816 | |||
817 |
1/2✓ Branch 2 taken 3623 times.
✗ Branch 3 not taken.
|
3623 | vector<QueryInfo *> infos_ipv4(num, NULL); |
818 |
1/2✓ Branch 2 taken 3623 times.
✗ Branch 3 not taken.
|
3623 | vector<QueryInfo *> infos_ipv6(num, NULL); |
819 | |||
820 |
2/2✓ Branch 0 taken 4538 times.
✓ Branch 1 taken 3623 times.
|
8161 | for (unsigned i = 0; i < num; ++i) { |
821 |
3/4✓ Branch 1 taken 4538 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3050 times.
✓ Branch 4 taken 1488 times.
|
4538 | if (skip[i]) |
822 | 3050 | continue; | |
823 | |||
824 |
2/2✓ Branch 1 taken 1440 times.
✓ Branch 2 taken 48 times.
|
1488 | if (!ipv4_only()) { |
825 |
2/4✓ Branch 3 taken 1440 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1440 times.
✗ Branch 7 not taken.
|
1440 | infos_ipv6[i] = new QueryInfo(&(*ipv6_addresses)[i], names[i], kRrAaaa); |
826 |
1/2✓ Branch 3 taken 1440 times.
✗ Branch 4 not taken.
|
1440 | ares_search(*channel_, names[i].c_str(), ns_c_in, ns_t_aaaa, |
827 | 1440 | CallbackCares, infos_ipv6[i]); | |
828 | } | ||
829 |
2/4✓ Branch 3 taken 1488 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1488 times.
✗ Branch 7 not taken.
|
1488 | infos_ipv4[i] = new QueryInfo(&(*ipv4_addresses)[i], names[i], kRrA); |
830 |
1/2✓ Branch 3 taken 1488 times.
✗ Branch 4 not taken.
|
1488 | ares_search(*channel_, names[i].c_str(), ns_c_in, ns_t_a, CallbackCares, |
831 | 1488 | infos_ipv4[i]); | |
832 | } | ||
833 | |||
834 | bool all_complete; | ||
835 | do { | ||
836 | 82399799 | all_complete = true; | |
837 |
1/2✓ Branch 1 taken 82399799 times.
✗ Branch 2 not taken.
|
82399799 | WaitOnCares(); |
838 |
2/2✓ Branch 0 taken 82410122 times.
✓ Branch 1 taken 3623 times.
|
82413745 | for (unsigned i = 0; i < num; ++i) { |
839 |
2/2✓ Branch 2 taken 10800 times.
✓ Branch 3 taken 82395696 times.
|
164816618 | if ((infos_ipv4[i] && !infos_ipv4[i]->complete) |
840 |
8/8✓ Branch 0 taken 82406496 times.
✓ Branch 1 taken 3626 times.
✓ Branch 3 taken 10752 times.
✓ Branch 4 taken 3674 times.
✓ Branch 6 taken 480 times.
✓ Branch 7 taken 10272 times.
✓ Branch 8 taken 82396176 times.
✓ Branch 9 taken 13946 times.
|
164816618 | || (infos_ipv6[i] && !infos_ipv6[i]->complete)) { |
841 | 82396176 | all_complete = false; | |
842 | 82396176 | break; | |
843 | } | ||
844 | } | ||
845 |
2/2✓ Branch 0 taken 82396176 times.
✓ Branch 1 taken 3623 times.
|
82399799 | } while (!all_complete); |
846 | |||
847 | // Silently ignore errors with IPv4/6 if there are at least some usable IP | ||
848 | // addresses. | ||
849 |
2/2✓ Branch 0 taken 4538 times.
✓ Branch 1 taken 3623 times.
|
8161 | for (unsigned i = 0; i < num; ++i) { |
850 |
3/4✓ Branch 1 taken 4538 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3050 times.
✓ Branch 4 taken 1488 times.
|
4538 | if (skip[i]) |
851 | 3050 | continue; | |
852 | |||
853 | 1488 | Failures status = kFailOther; | |
854 | 1488 | (*ttls)[i] = unsigned(-1); | |
855 |
1/2✓ Branch 2 taken 1488 times.
✗ Branch 3 not taken.
|
1488 | (*fqdns)[i] = ""; |
856 |
2/2✓ Branch 1 taken 1440 times.
✓ Branch 2 taken 48 times.
|
1488 | if (infos_ipv6[i]) { |
857 | 1440 | status = infos_ipv6[i]->status; | |
858 |
2/2✓ Branch 0 taken 1104 times.
✓ Branch 1 taken 336 times.
|
1440 | if (status == kFailOk) { |
859 | 1104 | (*ttls)[i] = std::min(infos_ipv6[i]->ttl, (*ttls)[i]); | |
860 |
1/2✓ Branch 3 taken 1104 times.
✗ Branch 4 not taken.
|
1104 | (*fqdns)[i] = infos_ipv6[i]->fqdn; |
861 | } | ||
862 | } | ||
863 |
1/2✓ Branch 1 taken 1488 times.
✗ Branch 2 not taken.
|
1488 | if (infos_ipv4[i]) { |
864 | 1488 | (*ttls)[i] = std::min(infos_ipv4[i]->ttl, (*ttls)[i]); | |
865 |
2/2✓ Branch 2 taken 384 times.
✓ Branch 3 taken 1104 times.
|
1488 | if ((*fqdns)[i] == "") |
866 |
1/2✓ Branch 3 taken 384 times.
✗ Branch 4 not taken.
|
384 | (*fqdns)[i] = infos_ipv4[i]->fqdn; |
867 |
2/2✓ Branch 0 taken 384 times.
✓ Branch 1 taken 1104 times.
|
1488 | if (status != kFailOk) |
868 | 384 | status = infos_ipv4[i]->status; | |
869 | } | ||
870 | 1488 | (*failures)[i] = status; | |
871 | } | ||
872 | |||
873 |
2/2✓ Branch 0 taken 4538 times.
✓ Branch 1 taken 3623 times.
|
8161 | for (unsigned i = 0; i < num; ++i) { |
874 |
2/2✓ Branch 1 taken 1488 times.
✓ Branch 2 taken 3050 times.
|
4538 | delete infos_ipv4[i]; |
875 |
2/2✓ Branch 1 taken 1440 times.
✓ Branch 2 taken 3098 times.
|
4538 | delete infos_ipv6[i]; |
876 | } | ||
877 | 3623 | } | |
878 | |||
879 | |||
880 | 144 | bool CaresResolver::SetResolvers(const vector<string> &resolvers) { | |
881 |
2/4✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 144 times.
✗ Branch 6 not taken.
|
288 | const string address_list = JoinStrings(resolvers, ","); |
882 |
1/2✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
|
144 | const int retval = ares_set_servers_csv(*channel_, address_list.c_str()); |
883 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
|
144 | if (retval != ARES_SUCCESS) |
884 | ✗ | return false; | |
885 | |||
886 |
1/2✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
|
144 | resolvers_ = resolvers; |
887 | 144 | return true; | |
888 | 144 | } | |
889 | |||
890 | |||
891 | /** | ||
892 | * Changes the options of the active channel. This is hacky and deals with | ||
893 | * c-ares internal data structures because there is no way to do it via public | ||
894 | * APIs. | ||
895 | */ | ||
896 | 96 | bool CaresResolver::SetSearchDomains(const vector<string> &domains) { | |
897 | // From ares_private.h | ||
898 | struct { | ||
899 | int flags; | ||
900 | int timeout; | ||
901 | int tries; | ||
902 | int ndots; | ||
903 | int rotate; | ||
904 | int udp_port; | ||
905 | int tcp_port; | ||
906 | int socket_send_buffer_size; | ||
907 | int socket_receive_buffer_size; | ||
908 | char **domains; | ||
909 | int ndomains; | ||
910 | // More fields come in the original data structure | ||
911 | } ares_channelhead; | ||
912 | |||
913 | 96 | memcpy(&ares_channelhead, *channel_, sizeof(ares_channelhead)); | |
914 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | if (ares_channelhead.domains) { |
915 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 96 times.
|
240 | for (int i = 0; i < ares_channelhead.ndomains; ++i) { |
916 | 144 | free(ares_channelhead.domains[i]); | |
917 | } | ||
918 | 96 | free(ares_channelhead.domains); | |
919 | 96 | ares_channelhead.domains = NULL; | |
920 | } | ||
921 | |||
922 | 96 | ares_channelhead.ndomains = static_cast<int>(domains.size()); | |
923 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 48 times.
|
96 | if (ares_channelhead.ndomains > 0) { |
924 | 48 | ares_channelhead.domains = reinterpret_cast<char **>( | |
925 | 48 | smalloc(ares_channelhead.ndomains * sizeof(char *))); | |
926 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 48 times.
|
144 | for (int i = 0; i < ares_channelhead.ndomains; ++i) { |
927 | 96 | ares_channelhead.domains[i] = strdup(domains[i].c_str()); | |
928 | } | ||
929 | } | ||
930 | |||
931 | 96 | memcpy(*channel_, &ares_channelhead, sizeof(ares_channelhead)); | |
932 | |||
933 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | domains_ = domains; |
934 | 96 | return true; | |
935 | } | ||
936 | |||
937 | |||
938 | ✗ | void CaresResolver::SetSystemResolvers() { | |
939 | ✗ | const int retval = SetResolvers(system_resolvers_); | |
940 | ✗ | assert(retval == true); | |
941 | } | ||
942 | |||
943 | |||
944 | ✗ | void CaresResolver::SetSystemSearchDomains() { | |
945 | ✗ | const int retval = SetSearchDomains(system_domains_); | |
946 | ✗ | assert(retval == true); | |
947 | } | ||
948 | |||
949 | |||
950 | /** | ||
951 | * Polls on c-ares sockets and triggers call-backs execution. Might be | ||
952 | * necessary to call this repeatadly. | ||
953 | */ | ||
954 | 82399799 | void CaresResolver::WaitOnCares() { | |
955 | // Adapted from libcurl | ||
956 | ares_socket_t socks[ARES_GETSOCK_MAXNUM]; | ||
957 | struct pollfd pfd[ARES_GETSOCK_MAXNUM]; | ||
958 |
1/2✓ Branch 1 taken 82399799 times.
✗ Branch 2 not taken.
|
82399799 | const int bitmask = ares_getsock(*channel_, socks, ARES_GETSOCK_MAXNUM); |
959 | 82399799 | unsigned num = 0; | |
960 |
1/2✓ Branch 0 taken 164796695 times.
✗ Branch 1 not taken.
|
164796695 | for (unsigned i = 0; i < ARES_GETSOCK_MAXNUM; ++i) { |
961 | 164796695 | pfd[i].events = 0; | |
962 | 164796695 | pfd[i].revents = 0; | |
963 |
2/2✓ Branch 0 taken 82396896 times.
✓ Branch 1 taken 82399799 times.
|
164796695 | if (ARES_GETSOCK_READABLE(bitmask, i)) { |
964 | 82396896 | pfd[i].fd = socks[i]; | |
965 | 82396896 | pfd[i].events |= POLLRDNORM | POLLIN; | |
966 | } | ||
967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 164796695 times.
|
164796695 | if (ARES_GETSOCK_WRITABLE(bitmask, i)) { |
968 | ✗ | pfd[i].fd = socks[i]; | |
969 | ✗ | pfd[i].events |= POLLWRNORM | POLLOUT; | |
970 | } | ||
971 |
2/2✓ Branch 0 taken 82396896 times.
✓ Branch 1 taken 82399799 times.
|
164796695 | if (pfd[i].events != 0) |
972 | 82396896 | num++; | |
973 | else | ||
974 | 82399799 | break; | |
975 | } | ||
976 | |||
977 | 82399799 | int nfds = 0; | |
978 |
2/2✓ Branch 0 taken 82396896 times.
✓ Branch 1 taken 2903 times.
|
82399799 | if (num > 0) { |
979 | do { | ||
980 |
1/2✓ Branch 2 taken 82396896 times.
✗ Branch 3 not taken.
|
82396896 | nfds = poll(pfd, num, timeout_ms()); |
981 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 82396896 times.
|
82396896 | if (nfds == -1) { |
982 | // poll must not fail for other reasons | ||
983 | ✗ | if ((errno != EAGAIN) && (errno != EINTR)) | |
984 | ✗ | PANIC(NULL); | |
985 | } | ||
986 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 82396896 times.
|
82396896 | } while (nfds == -1); |
987 | } | ||
988 | |||
989 |
2/2✓ Branch 0 taken 3191 times.
✓ Branch 1 taken 82396608 times.
|
82399799 | if (nfds == 0) { |
990 | // Call ares_process() unconditionally here, even if we simply timed out | ||
991 | // above, as otherwise the ares name resolve won't timeout. | ||
992 |
1/2✓ Branch 1 taken 3191 times.
✗ Branch 2 not taken.
|
3191 | ares_process_fd(*channel_, ARES_SOCKET_BAD, ARES_SOCKET_BAD); |
993 | } else { | ||
994 | // Go through the descriptors and ask for executing the callbacks. | ||
995 |
2/2✓ Branch 0 taken 82396608 times.
✓ Branch 1 taken 82396608 times.
|
164793216 | for (unsigned i = 0; i < num; ++i) { |
996 | 164793216 | ares_process_fd( | |
997 |
1/2✓ Branch 1 taken 82396608 times.
✗ Branch 2 not taken.
|
82396608 | *channel_, |
998 |
2/2✓ Branch 0 taken 2880 times.
✓ Branch 1 taken 82393728 times.
|
82396608 | pfd[i].revents & (POLLRDNORM | POLLIN) ? pfd[i].fd : ARES_SOCKET_BAD, |
999 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 82396608 times.
|
82396608 | pfd[i].revents & (POLLWRNORM | POLLOUT) ? pfd[i].fd |
1000 | : ARES_SOCKET_BAD); | ||
1001 | } | ||
1002 | } | ||
1003 | 82399799 | } | |
1004 | |||
1005 | |||
1006 | //------------------------------------------------------------------------------ | ||
1007 | |||
1008 | |||
1009 | /** | ||
1010 | * Opens a file descriptor to the host file that stays open until destruction. | ||
1011 | * If no path is given, the HOST_ALIASES environment variable is evaluated | ||
1012 | * followed by /etc/hosts. | ||
1013 | */ | ||
1014 | 7766 | HostfileResolver *HostfileResolver::Create(const string &path, bool ipv4_only) { | |
1015 |
1/2✓ Branch 1 taken 7766 times.
✗ Branch 2 not taken.
|
7766 | HostfileResolver *resolver = new HostfileResolver(ipv4_only); |
1016 | |||
1017 |
1/2✓ Branch 1 taken 7766 times.
✗ Branch 2 not taken.
|
7766 | string hosts_file = path; |
1018 |
2/2✓ Branch 1 taken 5558 times.
✓ Branch 2 taken 2208 times.
|
7766 | if (hosts_file == "") { |
1019 | 5558 | char *hosts_env = getenv("HOST_ALIASES"); | |
1020 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 5462 times.
|
5558 | if (hosts_env != NULL) { |
1021 |
1/2✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
|
96 | hosts_file = string(hosts_env); |
1022 | } else { | ||
1023 |
1/2✓ Branch 1 taken 5462 times.
✗ Branch 2 not taken.
|
5462 | hosts_file = "/etc/hosts"; |
1024 | } | ||
1025 | } | ||
1026 |
1/2✓ Branch 2 taken 7766 times.
✗ Branch 3 not taken.
|
7766 | resolver->fhosts_ = fopen(hosts_file.c_str(), "r"); |
1027 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 7670 times.
|
7766 | if (!resolver->fhosts_) { |
1028 |
1/2✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
|
96 | LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, "failed to read host file %s", |
1029 | hosts_file.c_str()); | ||
1030 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | delete resolver; |
1031 | 96 | return NULL; | |
1032 | } | ||
1033 | 7670 | return resolver; | |
1034 | 7766 | } | |
1035 | |||
1036 | |||
1037 | /** | ||
1038 | * Used to process longer domain names before shorter ones, in order to get | ||
1039 | * the correct fully qualified domain name. Reversed return value in order to | ||
1040 | * sort in descending order. | ||
1041 | */ | ||
1042 | 288 | static bool SortNameLength(const string &a, const string &b) { | |
1043 | 288 | const unsigned len_a = a.length(); | |
1044 | 288 | const unsigned len_b = b.length(); | |
1045 |
1/2✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
|
288 | if (len_a != len_b) |
1046 | 288 | return len_a > len_b; | |
1047 | ✗ | return a > b; | |
1048 | } | ||
1049 | |||
1050 | |||
1051 | /** | ||
1052 | * Creates a fresh reverse lookup map | ||
1053 | */ | ||
1054 | 4021 | void HostfileResolver::DoResolve(const vector<string> &names, | |
1055 | const vector<bool> &skip, | ||
1056 | vector<vector<std::string> > *ipv4_addresses, | ||
1057 | vector<vector<std::string> > *ipv6_addresses, | ||
1058 | vector<Failures> *failures, | ||
1059 | vector<unsigned> *ttls, | ||
1060 | vector<string> *fqdns) { | ||
1061 | 4021 | const unsigned num = names.size(); | |
1062 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4021 times.
|
4021 | if (num == 0) |
1063 | ✗ | return; | |
1064 | |||
1065 | 4021 | ParseHostFile(); | |
1066 |
2/2✓ Branch 0 taken 4312 times.
✓ Branch 1 taken 4021 times.
|
8333 | for (unsigned i = 0; i < num; ++i) { |
1067 |
3/4✓ Branch 1 taken 4312 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2632 times.
✓ Branch 4 taken 1680 times.
|
4312 | if (skip[i]) |
1068 | 2632 | continue; | |
1069 | |||
1070 | 1680 | vector<string> effective_names; | |
1071 |
5/6✓ Branch 2 taken 1680 times.
✗ Branch 3 not taken.
✓ Branch 8 taken 96 times.
✓ Branch 9 taken 1584 times.
✓ Branch 10 taken 96 times.
✓ Branch 11 taken 1584 times.
|
1680 | if (!names[i].empty() && (names[i][names[i].length() - 1] == '.')) { |
1072 |
2/4✓ Branch 4 taken 96 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 96 times.
✗ Branch 8 not taken.
|
96 | effective_names.push_back(names[i].substr(0, names[i].length() - 1)); |
1073 | } else { | ||
1074 |
1/2✓ Branch 2 taken 1584 times.
✗ Branch 3 not taken.
|
1584 | effective_names.push_back(names[i]); |
1075 |
2/2✓ Branch 2 taken 288 times.
✓ Branch 3 taken 1584 times.
|
1872 | for (unsigned j = 0; j < domains().size(); ++j) { |
1076 |
3/6✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 288 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 288 times.
✗ Branch 11 not taken.
|
288 | effective_names.push_back(names[i] + "." + domains()[j]); |
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | // Use the longest matching name as fqdn | ||
1081 |
1/2✓ Branch 3 taken 1680 times.
✗ Branch 4 not taken.
|
1680 | std::sort(effective_names.begin(), effective_names.end(), SortNameLength); |
1082 | |||
1083 | 1680 | (*failures)[i] = kFailUnknownHost; | |
1084 |
1/2✓ Branch 3 taken 1680 times.
✗ Branch 4 not taken.
|
1680 | (*fqdns)[i] = names[i]; |
1085 |
2/2✓ Branch 1 taken 1824 times.
✓ Branch 2 taken 480 times.
|
2304 | for (unsigned j = 0; j < effective_names.size(); ++j) { |
1086 |
1/2✓ Branch 1 taken 1824 times.
✗ Branch 2 not taken.
|
1824 | const map<string, HostEntry>::iterator iter = host_map_.find( |
1087 | 1824 | effective_names[j]); | |
1088 |
2/2✓ Branch 2 taken 1200 times.
✓ Branch 3 taken 624 times.
|
1824 | if (iter != host_map_.end()) { |
1089 |
1/2✓ Branch 7 taken 1200 times.
✗ Branch 8 not taken.
|
3600 | (*ipv4_addresses)[i].insert((*ipv4_addresses)[i].end(), |
1090 | 1200 | iter->second.ipv4_addresses.begin(), | |
1091 | 1200 | iter->second.ipv4_addresses.end()); | |
1092 |
1/2✓ Branch 7 taken 1200 times.
✗ Branch 8 not taken.
|
3600 | (*ipv6_addresses)[i].insert((*ipv6_addresses)[i].end(), |
1093 | 1200 | iter->second.ipv6_addresses.begin(), | |
1094 | 1200 | iter->second.ipv6_addresses.end()); | |
1095 | 1200 | (*ttls)[i] = min_ttl_; | |
1096 |
1/2✓ Branch 3 taken 1200 times.
✗ Branch 4 not taken.
|
1200 | (*fqdns)[i] = effective_names[j]; |
1097 | 1200 | (*failures)[i] = kFailOk; | |
1098 | 1200 | break; | |
1099 | } // Host name found | ||
1100 | } // All possible names (search domains added) | ||
1101 | 1680 | } | |
1102 | } | ||
1103 | |||
1104 | |||
1105 | 7766 | HostfileResolver::HostfileResolver(const bool ipv4_only) | |
1106 | 7766 | : Resolver(ipv4_only, 0, 0), fhosts_(NULL) { } | |
1107 | |||
1108 | |||
1109 | 31060 | HostfileResolver::~HostfileResolver() { | |
1110 |
2/2✓ Branch 0 taken 7669 times.
✓ Branch 1 taken 96 times.
|
15530 | if (fhosts_) |
1111 | 15338 | fclose(fhosts_); | |
1112 | 31060 | } | |
1113 | |||
1114 | |||
1115 | /** | ||
1116 | * TODO: this should be only necessary when the modification timestamp changed. | ||
1117 | */ | ||
1118 | 4021 | void HostfileResolver::ParseHostFile() { | |
1119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4021 times.
|
4021 | assert(fhosts_); |
1120 |
1/2✓ Branch 1 taken 4021 times.
✗ Branch 2 not taken.
|
4021 | rewind(fhosts_); |
1121 | 4021 | host_map_.clear(); | |
1122 | |||
1123 | 4021 | string line; | |
1124 |
3/4✓ Branch 1 taken 15892 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11871 times.
✓ Branch 4 taken 4021 times.
|
15892 | while (GetLineFile(fhosts_, &line)) { |
1125 | char address[kIpMaxLength + 1]; | ||
1126 | char hostname[kHostnameMaxLength + 1]; | ||
1127 | int bytes_read; | ||
1128 | 11871 | size_t str_offset = 0; | |
1129 | |||
1130 | // strip comments | ||
1131 | 11871 | const size_t hash_pos = line.find_first_of('#'); | |
1132 |
2/2✓ Branch 0 taken 480 times.
✓ Branch 1 taken 11391 times.
|
11871 | if (hash_pos != string::npos) |
1133 |
1/2✓ Branch 1 taken 480 times.
✗ Branch 2 not taken.
|
480 | line = line.substr(0, hash_pos); |
1134 | |||
1135 | // First token is an IP address | ||
1136 | 11871 | int ip_start_pos = -1, ip_end_pos = -1, scan_result; | |
1137 | 11871 | scan_result = sscanf(line.c_str(), " %n%*s%n", &ip_start_pos, &ip_end_pos); | |
1138 |
2/2✓ Branch 0 taken 672 times.
✓ Branch 1 taken 11199 times.
|
11871 | if (scan_result == EOF) |
1139 | 768 | continue; | |
1140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11199 times.
|
11199 | assert(ip_start_pos != -1); |
1141 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11199 times.
|
11199 | assert(ip_end_pos != -1); |
1142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11199 times.
|
11199 | if (ip_start_pos == ip_end_pos) |
1143 | ✗ | continue; | |
1144 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 11103 times.
|
11199 | if (ip_end_pos - ip_start_pos > kIpMaxLength) { |
1145 |
1/2✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
|
96 | LogCvmfs( |
1146 | kLogDns, kLogSyslogWarn, | ||
1147 | "Skipping line in hosts file due to invalid IP address format: %s", | ||
1148 | line.c_str()); | ||
1149 | 96 | continue; | |
1150 | } | ||
1151 | |||
1152 | 11103 | bytes_read = -1; | |
1153 | 11103 | scan_result = sscanf(line.c_str(), " %s%n", address, &bytes_read); | |
1154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11103 times.
|
11103 | assert(scan_result == 1); |
1155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11103 times.
|
11103 | assert(bytes_read != -1); |
1156 | 11103 | str_offset += bytes_read; | |
1157 | |||
1158 | // Next tokens are hostnames and aliases (we treat them as equal) | ||
1159 |
2/2✓ Branch 1 taken 30466 times.
✓ Branch 2 taken 10767 times.
|
41233 | while (str_offset < line.length()) { |
1160 | // check hostname length | ||
1161 | 30466 | int hostname_start_pos = -1, hostname_end_pos = -1; | |
1162 | 30466 | scan_result = sscanf(line.c_str() + str_offset, " %n%*s%n", | |
1163 | &hostname_start_pos, &hostname_end_pos); | ||
1164 |
2/2✓ Branch 0 taken 336 times.
✓ Branch 1 taken 30130 times.
|
30466 | if (scan_result == EOF) |
1165 | 336 | break; | |
1166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30130 times.
|
30130 | assert(hostname_start_pos != -1); |
1167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30130 times.
|
30130 | assert(hostname_end_pos != -1); |
1168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30130 times.
|
30130 | if (hostname_start_pos == hostname_end_pos) |
1169 | ✗ | break; | |
1170 | |||
1171 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 30034 times.
|
30130 | if (hostname_end_pos - hostname_start_pos > kHostnameMaxLength) { |
1172 |
1/2✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
|
96 | LogCvmfs( |
1173 | kLogDns, kLogSyslogWarn, | ||
1174 | "Skipping invalid (too long) hostname in hosts file on line: %s", | ||
1175 | line.c_str()); | ||
1176 | 96 | str_offset += hostname_end_pos; | |
1177 | 96 | continue; | |
1178 | } | ||
1179 | |||
1180 | 30034 | bytes_read = -1; | |
1181 | 30034 | scan_result = sscanf(line.c_str() + str_offset, " %s%n", hostname, | |
1182 | &bytes_read); | ||
1183 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30034 times.
|
30034 | assert(scan_result == 1); |
1184 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30034 times.
|
30034 | assert(bytes_read != -1); |
1185 | 30034 | str_offset += bytes_read; | |
1186 | |||
1187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30034 times.
|
30034 | if (hostname[strlen(hostname) - 1] == '.') |
1188 | ✗ | hostname[strlen(hostname) - 1] = 0; // strip the last character | |
1189 | |||
1190 |
2/4✓ Branch 2 taken 30034 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 30034 times.
✗ Branch 6 not taken.
|
30034 | const map<string, HostEntry>::iterator iter = host_map_.find(hostname); |
1191 |
2/2✓ Branch 2 taken 24248 times.
✓ Branch 3 taken 5786 times.
|
30034 | if (iter == host_map_.end()) { |
1192 | 24248 | HostEntry entry; | |
1193 |
4/6✓ Branch 2 taken 24248 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24248 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 18606 times.
✓ Branch 10 taken 5642 times.
|
24248 | if (IsIpv4Address(address)) |
1194 |
2/4✓ Branch 2 taken 18606 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18606 times.
✗ Branch 6 not taken.
|
18606 | entry.ipv4_addresses.push_back(address); |
1195 |
2/2✓ Branch 1 taken 5546 times.
✓ Branch 2 taken 96 times.
|
5642 | else if (!ipv4_only()) |
1196 |
2/4✓ Branch 2 taken 5546 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5546 times.
✗ Branch 6 not taken.
|
5546 | entry.ipv6_addresses.push_back(address); |
1197 |
3/6✓ Branch 2 taken 24248 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24248 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 24248 times.
✗ Branch 9 not taken.
|
24248 | host_map_[hostname] = entry; |
1198 | 24248 | } else { | |
1199 |
4/6✓ Branch 2 taken 5786 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5786 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 144 times.
✓ Branch 10 taken 5642 times.
|
5786 | if (IsIpv4Address(address)) |
1200 |
2/4✓ Branch 3 taken 144 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 144 times.
✗ Branch 7 not taken.
|
144 | iter->second.ipv4_addresses.push_back(address); |
1201 |
2/2✓ Branch 1 taken 5546 times.
✓ Branch 2 taken 96 times.
|
5642 | else if (!ipv4_only()) |
1202 |
2/4✓ Branch 3 taken 5546 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5546 times.
✗ Branch 7 not taken.
|
5546 | iter->second.ipv6_addresses.push_back(address); |
1203 | } | ||
1204 | } // Current line | ||
1205 | } // Hosts file | ||
1206 | 4021 | } | |
1207 | |||
1208 | |||
1209 | 5414 | bool HostfileResolver::SetSearchDomains(const vector<string> &domains) { | |
1210 | 5414 | domains_ = domains; | |
1211 | 5414 | return true; | |
1212 | } | ||
1213 | |||
1214 | |||
1215 | ✗ | void HostfileResolver::SetSystemSearchDomains() { | |
1216 | // TODO(jblomer) | ||
1217 | ✗ | PANIC(NULL); | |
1218 | } | ||
1219 | |||
1220 | |||
1221 | //------------------------------------------------------------------------------ | ||
1222 | |||
1223 | |||
1224 | /** | ||
1225 | * Creates hostfile and c-ares resolvers and uses c-ares resolvers search | ||
1226 | * domains for the hostfile resolver. | ||
1227 | */ | ||
1228 | 5414 | NormalResolver *NormalResolver::Create(const bool ipv4_only, | |
1229 | const unsigned retries, | ||
1230 | const unsigned timeout_ms) { | ||
1231 | 5414 | CaresResolver *cares_resolver = CaresResolver::Create(ipv4_only, retries, | |
1232 | timeout_ms); | ||
1233 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5414 times.
|
5414 | if (!cares_resolver) |
1234 | ✗ | return NULL; | |
1235 |
2/4✓ Branch 2 taken 5414 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5414 times.
✗ Branch 6 not taken.
|
5414 | HostfileResolver *hostfile_resolver = HostfileResolver::Create("", ipv4_only); |
1236 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 5366 times.
|
5414 | if (!hostfile_resolver) { |
1237 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | delete cares_resolver; |
1238 | 48 | return NULL; | |
1239 | } | ||
1240 | 5366 | const bool retval = hostfile_resolver->SetSearchDomains( | |
1241 | cares_resolver->domains()); | ||
1242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5366 times.
|
5366 | assert(retval); |
1243 | |||
1244 | 5366 | NormalResolver *normal_resolver = new NormalResolver(); | |
1245 | 5366 | normal_resolver->cares_resolver_ = cares_resolver; | |
1246 | 5366 | normal_resolver->hostfile_resolver_ = hostfile_resolver; | |
1247 | 5366 | normal_resolver->domains_ = cares_resolver->domains(); | |
1248 | 5366 | normal_resolver->resolvers_ = cares_resolver->resolvers(); | |
1249 | 5366 | normal_resolver->retries_ = cares_resolver->retries(); | |
1250 | 5366 | normal_resolver->timeout_ms_ = cares_resolver->timeout_ms(); | |
1251 | 5366 | return normal_resolver; | |
1252 | } | ||
1253 | |||
1254 | |||
1255 | /** | ||
1256 | * Makes only sense for the c-ares resolver. | ||
1257 | */ | ||
1258 | 48 | bool NormalResolver::SetResolvers(const vector<string> &resolvers) { | |
1259 | 48 | return cares_resolver_->SetResolvers(resolvers); | |
1260 | } | ||
1261 | |||
1262 | |||
1263 | /** | ||
1264 | * Set new search domains for both resolvers or for none. | ||
1265 | */ | ||
1266 | ✗ | bool NormalResolver::SetSearchDomains(const vector<string> &domains) { | |
1267 | ✗ | const vector<string> old_domains = hostfile_resolver_->domains(); | |
1268 | ✗ | bool retval = hostfile_resolver_->SetSearchDomains(domains); | |
1269 | ✗ | if (!retval) | |
1270 | ✗ | return false; | |
1271 | ✗ | retval = cares_resolver_->SetSearchDomains(domains); | |
1272 | ✗ | if (!retval) { | |
1273 | ✗ | retval = hostfile_resolver_->SetSearchDomains(old_domains); | |
1274 | ✗ | assert(retval); | |
1275 | ✗ | return false; | |
1276 | } | ||
1277 | ✗ | return true; | |
1278 | } | ||
1279 | |||
1280 | |||
1281 | ✗ | void NormalResolver::SetSystemResolvers() { | |
1282 | ✗ | cares_resolver_->SetSystemResolvers(); | |
1283 | } | ||
1284 | |||
1285 | |||
1286 | ✗ | void NormalResolver::SetSystemSearchDomains() { | |
1287 | ✗ | cares_resolver_->SetSystemSearchDomains(); | |
1288 | ✗ | const bool retval = hostfile_resolver_->SetSearchDomains( | |
1289 | ✗ | cares_resolver_->domains()); | |
1290 | ✗ | assert(retval); | |
1291 | } | ||
1292 | |||
1293 | |||
1294 | /** | ||
1295 | * First pass done by the hostfile resolver, all successfully resolved names | ||
1296 | * are skipped by the c-ares resolver. | ||
1297 | */ | ||
1298 | 2581 | void NormalResolver::DoResolve(const vector<string> &names, | |
1299 | const vector<bool> &skip, | ||
1300 | vector<vector<string> > *ipv4_addresses, | ||
1301 | vector<vector<string> > *ipv6_addresses, | ||
1302 | vector<Failures> *failures, | ||
1303 | vector<unsigned> *ttls, | ||
1304 | vector<string> *fqdns) { | ||
1305 | 2581 | const unsigned num = names.size(); | |
1306 |
1/2✓ Branch 1 taken 2581 times.
✗ Branch 2 not taken.
|
2581 | hostfile_resolver_->DoResolve(names, skip, ipv4_addresses, ipv6_addresses, |
1307 | failures, ttls, fqdns); | ||
1308 |
1/2✓ Branch 1 taken 2581 times.
✗ Branch 2 not taken.
|
2581 | vector<bool> skip_cares = skip; |
1309 |
2/2✓ Branch 0 taken 2584 times.
✓ Branch 1 taken 2581 times.
|
5165 | for (unsigned i = 0; i < num; ++i) { |
1310 |
2/2✓ Branch 1 taken 2536 times.
✓ Branch 2 taken 48 times.
|
2584 | if ((*failures)[i] == kFailOk) |
1311 |
1/2✓ Branch 1 taken 2536 times.
✗ Branch 2 not taken.
|
2536 | skip_cares[i] = true; |
1312 | } | ||
1313 |
1/2✓ Branch 1 taken 2581 times.
✗ Branch 2 not taken.
|
2581 | cares_resolver_->DoResolve(names, skip_cares, ipv4_addresses, ipv6_addresses, |
1314 | failures, ttls, fqdns); | ||
1315 | 2581 | } | |
1316 | |||
1317 | |||
1318 | 5366 | NormalResolver::NormalResolver() | |
1319 | 5366 | : Resolver(false, 0, 0), cares_resolver_(NULL), hostfile_resolver_(NULL) { } | |
1320 | |||
1321 | |||
1322 | 21460 | NormalResolver::~NormalResolver() { | |
1323 |
1/2✓ Branch 0 taken 5365 times.
✗ Branch 1 not taken.
|
10730 | delete cares_resolver_; |
1324 |
1/2✓ Branch 0 taken 5365 times.
✗ Branch 1 not taken.
|
10730 | delete hostfile_resolver_; |
1325 | 21460 | } | |
1326 | |||
1327 | } // namespace dns | ||
1328 |