GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/network/dns.cc
Date: 2024-04-21 02:33:16
Exec Total Coverage
Lines: 618 703 87.9%
Branches: 509 804 63.3%

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