GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/dns.cc
Date: 2023-02-05 02:36:10
Exec Total Coverage
Lines: 612 697 87.8%
Branches: 503 796 63.2%

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