GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/network/dns.cc
Date: 2026-09-27 02:40:09
Exec Total Coverage
Lines: 616 698 88.3%
Branches: 513 806 63.6%

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