GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/network/dns.cc
Date: 2026-09-13 02:40:16
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 4702 static void PinpointHostSubstr(const std::string &url,
62 unsigned *pos_begin,
63 unsigned *pos_end) {
64 4702 *pos_begin = *pos_end = 0;
65 4702 const unsigned len = url.size();
66 4702 unsigned i = 0;
67
68 // Search '//' in the url string and jump behind
69
2/2
✓ Branch 0 taken 28824 times.
✓ Branch 1 taken 1583 times.
30407 for (; i < len; ++i) {
70
8/8
✓ Branch 1 taken 3340 times.
✓ Branch 2 taken 25484 times.
✓ Branch 3 taken 3170 times.
✓ Branch 4 taken 170 times.
✓ Branch 6 taken 3119 times.
✓ Branch 7 taken 51 times.
✓ Branch 8 taken 3119 times.
✓ Branch 9 taken 25705 times.
28824 if ((url[i] == '/') && (i < len - 2) && (url[i + 1] == '/')) {
71 3119 i += 2;
72 3119 *pos_begin = i;
73 3119 break;
74 }
75 }
76
77 // Search '@' within the hostname part and jump behind if present
78
2/2
✓ Branch 0 taken 3119 times.
✓ Branch 1 taken 1583 times.
4702 if (*pos_begin > 0) {
79
2/2
✓ Branch 0 taken 36407 times.
✓ Branch 1 taken 2643 times.
39050 for (i = *pos_begin; i < len; ++i) {
80
2/2
✓ Branch 1 taken 391 times.
✓ Branch 2 taken 36016 times.
36407 if (url[i] == '/') {
81 391 break;
82
2/2
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 35931 times.
36016 } else if (url[i] == '@') {
83 85 *pos_begin = ++i;
84 85 break;
85 }
86 }
87 }
88
89 // Find the end of the hostname part
90
2/2
✓ Branch 0 taken 3119 times.
✓ Branch 1 taken 1583 times.
4702 if (*pos_begin > 0) {
91 3119 bool in_ipv6 = (url[*pos_begin] == '[');
92
2/2
✓ Branch 0 taken 27110 times.
✓ Branch 1 taken 323 times.
27433 for (i = *pos_begin; i < len; ++i) {
93
2/2
✓ Branch 0 taken 1870 times.
✓ Branch 1 taken 25240 times.
27110 if (in_ipv6) {
94
2/2
✓ Branch 1 taken 1513 times.
✓ Branch 2 taken 357 times.
1870 if (url[i] != ']')
95 1513 continue;
96 357 in_ipv6 = false;
97 }
98
99
6/6
✓ Branch 1 taken 23039 times.
✓ Branch 2 taken 2558 times.
✓ Branch 4 taken 238 times.
✓ Branch 5 taken 22801 times.
✓ Branch 6 taken 2796 times.
✓ Branch 7 taken 22801 times.
25597 if ((url[i] == ':') || (url[i] == '/'))
100 2796 break;
101 }
102
2/2
✓ Branch 0 taken 3017 times.
✓ Branch 1 taken 102 times.
3119 if (!in_ipv6)
103 3017 *pos_end = i - 1;
104
105
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 2813 times.
3119 if (*pos_end < *pos_begin)
106 306 *pos_end = *pos_begin = 0;
107 }
108 4702 }
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 2607 std::string ExtractHost(const std::string &url) {
117 unsigned pos_begin;
118 unsigned pos_end;
119 2607 PinpointHostSubstr(url, &pos_begin, &pos_end);
120
2/2
✓ Branch 0 taken 1345 times.
✓ Branch 1 taken 1262 times.
2607 if (pos_begin == 0)
121
1/2
✓ Branch 2 taken 1345 times.
✗ Branch 3 not taken.
1345 return "";
122
1/2
✓ Branch 1 taken 1262 times.
✗ Branch 2 not taken.
1262 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 1751 std::string ExtractPort(const std::string &url) {
132 unsigned pos_begin;
133 unsigned pos_end;
134 1751 PinpointHostSubstr(url, &pos_begin, &pos_end);
135
9/10
✓ Branch 0 taken 1394 times.
✓ Branch 1 taken 357 times.
✓ Branch 3 taken 1275 times.
✓ Branch 4 taken 119 times.
✓ Branch 6 taken 1275 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 51 times.
✓ Branch 9 taken 1224 times.
✓ Branch 10 taken 527 times.
✓ Branch 11 taken 1224 times.
1751 if (pos_begin == 0 || pos_end + 2 >= url.size() || url.at(pos_end + 1) != ':')
136
1/2
✓ Branch 2 taken 527 times.
✗ Branch 3 not taken.
527 return "";
137
138 // Do not include path
139 1224 const std::size_t pos_port = url.find("/", pos_end);
140 1224 std::string retme;
141
2/2
✓ Branch 0 taken 1122 times.
✓ Branch 1 taken 102 times.
1224 if (pos_port == std::string::npos)
142
1/2
✓ Branch 1 taken 1122 times.
✗ Branch 2 not taken.
1122 retme = url.substr(pos_end + 2);
143 else
144
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 retme = url.substr(pos_end + 2, pos_port - pos_end - 2);
145
146 // Port is an integer
147
2/2
✓ Branch 4 taken 4199 times.
✓ Branch 5 taken 1156 times.
5355 for (std::string::iterator it = retme.begin(); it != retme.end(); ++it)
148
2/2
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 4131 times.
4199 if (isdigit(*it) == 0)
149
1/2
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 return "";
150
151 1156 return retme;
152 1224 }
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 344 string RewriteUrl(const string &url, const string &ip) {
161 unsigned pos_begin;
162 unsigned pos_end;
163 344 PinpointHostSubstr(url, &pos_begin, &pos_end);
164
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 157 times.
344 if (pos_begin == 0)
165
1/2
✓ Branch 1 taken 187 times.
✗ Branch 2 not taken.
187 return url;
166
167
1/2
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
157 string result = url;
168
1/2
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
157 result.replace(pos_begin, (pos_end - pos_begin) + 1, ip);
169 157 return result;
170 157 }
171
172
173 /**
174 * Removes the brackets from IPv6 addresses. Leaves IPv4 addresses unchanged.
175 */
176 136 string StripIp(const string &decorated_ip) {
177
2/2
✓ Branch 1 taken 119 times.
✓ Branch 2 taken 17 times.
136 if (!decorated_ip.empty()) {
178 119 if ((decorated_ip[0] == '[')
179
6/6
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 51 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 85 times.
119 && (decorated_ip[decorated_ip.length() - 1] == ']')) {
180 34 return decorated_ip.substr(1, decorated_ip.length() - 2);
181 }
182 }
183 102 return decorated_ip;
184 }
185
186
187 /**
188 * Adds http:// if it is missing from proxy
189 */
190 2579 std::string AddDefaultScheme(const std::string &proxy) {
191 2579 const bool ignore_case = true;
192
4/12
✓ Branch 1 taken 2579 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2579 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2528 times.
✓ Branch 8 taken 51 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
5158 if (HasPrefix(proxy, "http://", ignore_case)
193
9/19
✓ Branch 2 taken 2554 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2554 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2537 times.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 68 times.
✓ Branch 11 taken 2469 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2554 times.
✓ Branch 14 taken 25 times.
✓ Branch 16 taken 2579 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
5133 || HasPrefix(proxy, "https://", ignore_case) || (proxy == "DIRECT")
194
7/9
✓ Branch 2 taken 2579 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2554 times.
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 17 times.
✓ Branch 8 taken 51 times.
✓ Branch 9 taken 2554 times.
✓ Branch 10 taken 25 times.
7712 || proxy.empty()) {
195 2528 return proxy;
196 }
197 51 return "http://" + proxy;
198 }
199
200
201 //------------------------------------------------------------------------------
202
203
204 atomic_int64 Host::global_id_ = 0;
205
206 157 const set<string> &Host::ViewBestAddresses(IpPreference preference) const {
207
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
102 if (((preference == kIpPreferSystem) || (preference == kIpPreferV4))
208
6/6
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 55 times.
✓ Branch 3 taken 72 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 72 times.
✓ Branch 6 taken 85 times.
259 && HasIpv4()) {
209 72 return ipv4_addresses_;
210 }
211
6/6
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 34 times.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 68 times.
85 if ((preference == kIpPreferV6) && !HasIpv6())
212 17 return ipv4_addresses_;
213 68 return ipv6_addresses_;
214 }
215
216
217 9652 void Host::CopyFrom(const Host &other) {
218 9652 deadline_ = other.deadline_;
219 9652 id_ = other.id_;
220 9652 ipv4_addresses_ = other.ipv4_addresses_;
221 9652 ipv6_addresses_ = other.ipv6_addresses_;
222 9652 name_ = other.name_;
223 9652 status_ = other.status_;
224 9652 }
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 17 Host Host::ExtendDeadline(const Host &original, unsigned seconds_from_now) {
232 17 Host new_host(original);
233 17 new_host.id_ = atomic_xadd64(&global_id_, 1);
234 17 new_host.deadline_ = time(NULL) + seconds_from_now;
235 17 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 5635 Host::Host()
244 5635 : deadline_(0)
245 5635 , id_(atomic_xadd64(&global_id_, 1))
246 5635 , status_(kFailNotYetResolved) { }
247
248
249
1/2
✓ Branch 4 taken 7764 times.
✗ Branch 5 not taken.
7764 Host::Host(const Host &other) { CopyFrom(other); }
250
251
252 1889 Host &Host::operator=(const Host &other) {
253
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1888 times.
1889 if (&other == this)
254 1 return *this;
255 1888 CopyFrom(other);
256 1888 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 374 bool Host::IsEquivalent(const Host &other) const {
266
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 17 times.
323 return (status_ == kFailOk) && (other.status_ == kFailOk)
267
3/4
✓ Branch 1 taken 306 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 272 times.
✓ Branch 5 taken 34 times.
306 && (name_ == other.name_) && (ipv4_addresses_ == other.ipv4_addresses_)
268
4/4
✓ Branch 0 taken 323 times.
✓ Branch 1 taken 51 times.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 68 times.
697 && (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 242 bool Host::IsExpired() const {
276 242 const time_t now = time(NULL);
277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 assert(now != static_cast<time_t>(-1));
278 242 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 272 bool Host::IsValid() const {
288
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 170 times.
272 if (status_ != kFailOk)
289 102 return false;
290
291
3/4
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 136 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
170 assert(!ipv4_addresses_.empty() || !ipv6_addresses_.empty());
292 170 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 17139 bool Resolver::IsIpv4Address(const string &address) {
304 // Are there any unexpected characters?
305
2/4
✓ Branch 2 taken 17139 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 17139 times.
✗ Branch 6 not taken.
34278 const sanitizer::InputSanitizer sanitizer("09 .");
306
3/4
✓ Branch 1 taken 17139 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6905 times.
✓ Branch 4 taken 10234 times.
17139 if (!sanitizer.IsValid(address))
307 6905 return false;
308
309 // 4 octets in the range 0-255?
310
1/2
✓ Branch 1 taken 10234 times.
✗ Branch 2 not taken.
10234 vector<string> octets = SplitString(address, '.');
311
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 10217 times.
10234 if (octets.size() != 4)
312 17 return false;
313
2/2
✓ Branch 0 taken 40868 times.
✓ Branch 1 taken 10200 times.
51068 for (unsigned i = 0; i < 4; ++i) {
314
1/2
✓ Branch 2 taken 40868 times.
✗ Branch 3 not taken.
40868 const uint64_t this_octet = String2Uint64(octets[i]);
315
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 40851 times.
40868 if (this_octet > 255)
316 17 return false;
317 }
318
319 10200 return true;
320 17139 }
321
322
323 /**
324 * Basic input validation to ensure that this could syntactically represent a
325 * valid IPv6 address.
326 */
327 714 bool Resolver::IsIpv6Address(const string &address) {
328 // Are there any unexpected characters?
329
2/4
✓ Branch 2 taken 714 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 714 times.
✗ Branch 6 not taken.
1428 const sanitizer::InputSanitizer sanitizer("09 af AF :");
330
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
1428 return sanitizer.IsValid(address);
331 714 }
332
333
334 11348 Resolver::Resolver(const bool ipv4_only,
335 const unsigned retries,
336 11348 const unsigned timeout_ms)
337 11348 : ipv4_only_(ipv4_only)
338 11348 , retries_(retries)
339 11348 , timeout_ms_(timeout_ms)
340 11348 , throttle_(0)
341 11348 , min_ttl_(kDefaultMinTtl)
342 11348 , max_ttl_(kDefaultMaxTtl) {
343 11348 prng_.InitLocaltime();
344 11348 }
345
346
347 /**
348 * Wrapper around the vector interface.
349 */
350 1224 Host Resolver::Resolve(const string &name) {
351 1224 vector<string> names;
352
1/2
✓ Branch 1 taken 1224 times.
✗ Branch 2 not taken.
1224 names.push_back(name);
353 1224 vector<Host> hosts;
354
1/2
✓ Branch 1 taken 1224 times.
✗ Branch 2 not taken.
1224 ResolveMany(names, &hosts);
355
1/2
✓ Branch 2 taken 1224 times.
✗ Branch 3 not taken.
2448 return hosts[0];
356 1224 }
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 2504 void Resolver::ResolveMany(const vector<string> &names, vector<Host> *hosts) {
364 2504 const unsigned num = names.size();
365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2504 times.
2504 if (num == 0)
366 return;
367
368
1/2
✓ Branch 2 taken 2504 times.
✗ Branch 3 not taken.
2504 vector<vector<string> > ipv4_addresses(num);
369
1/2
✓ Branch 2 taken 2504 times.
✗ Branch 3 not taken.
2504 vector<vector<string> > ipv6_addresses(num);
370
1/2
✓ Branch 2 taken 2504 times.
✗ Branch 3 not taken.
2504 vector<Failures> failures(num);
371
1/2
✓ Branch 2 taken 2504 times.
✗ Branch 3 not taken.
2504 vector<unsigned> ttls(num);
372
1/2
✓ Branch 2 taken 2504 times.
✗ Branch 3 not taken.
2504 vector<string> fqdns(num);
373
1/2
✓ Branch 2 taken 2504 times.
✗ Branch 3 not taken.
2504 vector<bool> skip(num);
374
375 // Deal with special names: empty, IPv4, IPv6
376
2/2
✓ Branch 0 taken 2930 times.
✓ Branch 1 taken 2504 times.
5434 for (unsigned i = 0; i < num; ++i) {
377
2/2
✓ Branch 2 taken 1243 times.
✓ Branch 3 taken 1687 times.
2930 if (names[i].empty()) {
378
1/2
✓ Branch 1 taken 1243 times.
✗ Branch 2 not taken.
1243 LogCvmfs(kLogDns, kLogDebug, "empty hostname");
379 1243 Host invalid_host;
380
1/2
✓ Branch 1 taken 1243 times.
✗ Branch 2 not taken.
1243 invalid_host.name_ = "";
381 1243 invalid_host.status_ = kFailInvalidHost;
382
1/2
✓ Branch 1 taken 1243 times.
✗ Branch 2 not taken.
1243 hosts->push_back(invalid_host);
383
1/2
✓ Branch 1 taken 1243 times.
✗ Branch 2 not taken.
1243 skip[i] = true;
384
3/4
✓ Branch 3 taken 1687 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 276 times.
✓ Branch 6 taken 1411 times.
2930 } else if (IsIpv4Address(names[i])) {
385
1/2
✓ Branch 3 taken 276 times.
✗ Branch 4 not taken.
276 LogCvmfs(kLogDns, kLogDebug, "IPv4 address %s", names[i].c_str());
386 276 Host ipv4_host;
387
1/2
✓ Branch 2 taken 276 times.
✗ Branch 3 not taken.
276 ipv4_host.name_ = names[i];
388 276 ipv4_host.status_ = kFailOk;
389
1/2
✓ Branch 2 taken 276 times.
✗ Branch 3 not taken.
276 ipv4_host.ipv4_addresses_.insert(names[i]);
390 276 ipv4_host.deadline_ = time(NULL) + max_ttl_;
391
1/2
✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
276 hosts->push_back(ipv4_host);
392
1/2
✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
276 skip[i] = true;
393
2/2
✓ Branch 5 taken 68 times.
✓ Branch 6 taken 1258 times.
3013 } else if ((names[i].length() >= 3) && (names[i][0] == '[')
394
5/6
✓ Branch 0 taken 1326 times.
✓ Branch 1 taken 85 times.
✓ Branch 6 taken 68 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 68 times.
✓ Branch 9 taken 1343 times.
2737 && (names[i][names[i].length() - 1] == ']')) {
395
1/2
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
68 LogCvmfs(kLogDns, kLogDebug, "IPv6 address %s", names[i].c_str());
396 68 Host ipv6_host;
397
1/2
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 ipv6_host.name_ = names[i];
398 68 ipv6_host.status_ = kFailOk;
399
1/2
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 ipv6_host.ipv6_addresses_.insert(names[i]);
400 68 ipv6_host.deadline_ = time(NULL) + max_ttl_;
401
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 hosts->push_back(ipv6_host);
402
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 skip[i] = true;
403 68 } else {
404
1/2
✓ Branch 2 taken 1343 times.
✗ Branch 3 not taken.
1343 hosts->push_back(Host());
405
1/2
✓ Branch 1 taken 1343 times.
✗ Branch 2 not taken.
1343 skip[i] = false;
406 }
407 }
408
409
1/2
✓ Branch 1 taken 2504 times.
✗ Branch 2 not taken.
2504 DoResolve(names, skip, &ipv4_addresses, &ipv6_addresses, &failures, &ttls,
410 &fqdns);
411
412 // Construct host objects
413
2/2
✓ Branch 0 taken 2930 times.
✓ Branch 1 taken 2504 times.
5434 for (unsigned i = 0; i < num; ++i) {
414
3/5
✓ Branch 1 taken 2930 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1587 times.
✓ Branch 5 taken 1343 times.
2930 if (skip[i])
415 1910 continue;
416
417 1343 Host host;
418
1/2
✓ Branch 2 taken 1343 times.
✗ Branch 3 not taken.
1343 host.name_ = fqdns[i];
419 1343 host.status_ = failures[i];
420
421 1343 unsigned effective_ttl = ttls[i];
422
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 1003 times.
1343 if (effective_ttl < min_ttl_) {
423 340 effective_ttl = min_ttl_;
424
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 969 times.
1003 } else if (effective_ttl > max_ttl_) {
425 34 effective_ttl = max_ttl_;
426 }
427 1343 host.deadline_ = time(NULL) + effective_ttl;
428
429
2/2
✓ Branch 0 taken 323 times.
✓ Branch 1 taken 1020 times.
1343 if (host.status_ != kFailOk) {
430
1/2
✓ Branch 3 taken 323 times.
✗ Branch 4 not taken.
646 LogCvmfs(kLogDns, kLogDebug, "failed to resolve %s - %d (%s), ttl %u",
431 323 names[i].c_str(), host.status_, Code2Ascii(host.status_),
432 effective_ttl);
433
1/2
✓ Branch 2 taken 323 times.
✗ Branch 3 not taken.
323 (*hosts)[i] = host;
434 323 continue;
435 }
436
437 // Verify addresses and make them readily available for curl
438
2/2
✓ Branch 2 taken 1156 times.
✓ Branch 3 taken 1020 times.
2176 for (unsigned j = 0; j < ipv4_addresses[i].size(); ++j) {
439
3/4
✓ Branch 3 taken 1156 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 68 times.
✓ Branch 6 taken 1088 times.
1156 if (!IsIpv4Address(ipv4_addresses[i][j])) {
440
1/4
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
136 LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn,
441 "host name %s resolves to invalid IPv4 address %s",
442 136 names[i].c_str(), ipv4_addresses[i][j].c_str());
443 68 continue;
444 }
445
2/2
✓ Branch 2 taken 1037 times.
✓ Branch 3 taken 51 times.
1088 if (names[i] == host.name_) {
446
1/2
✓ Branch 4 taken 1037 times.
✗ Branch 5 not taken.
1037 LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s", names[i].c_str(),
447 1037 ipv4_addresses[i][j].c_str());
448 } else {
449
1/2
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
102 LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s -> %s",
450 51 names[i].c_str(), host.name_.c_str(),
451 51 ipv4_addresses[i][j].c_str());
452 }
453
1/2
✓ Branch 3 taken 1088 times.
✗ Branch 4 not taken.
1088 host.ipv4_addresses_.insert(ipv4_addresses[i][j]);
454 }
455
456
2/2
✓ Branch 2 taken 714 times.
✓ Branch 3 taken 1020 times.
1734 for (unsigned j = 0; j < ipv6_addresses[i].size(); ++j) {
457
3/4
✓ Branch 3 taken 714 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 680 times.
714 if (!IsIpv6Address(ipv6_addresses[i][j])) {
458
1/4
✓ Branch 3 taken 34 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
68 LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn,
459 "host name %s resolves to invalid IPv6 address %s",
460 68 names[i].c_str(), ipv6_addresses[i][j].c_str());
461 34 continue;
462 }
463 // For URLs we need brackets around IPv6 addresses
464
2/2
✓ Branch 2 taken 663 times.
✓ Branch 3 taken 17 times.
680 if (names[i] == host.name_) {
465
1/2
✓ Branch 4 taken 663 times.
✗ Branch 5 not taken.
663 LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s", names[i].c_str(),
466 663 ipv6_addresses[i][j].c_str());
467 } else {
468
1/2
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
34 LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s -> %s",
469 17 names[i].c_str(), host.name_.c_str(),
470 17 ipv6_addresses[i][j].c_str());
471 }
472
3/6
✓ Branch 3 taken 680 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 680 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 680 times.
✗ Branch 10 not taken.
680 host.ipv6_addresses_.insert("[" + ipv6_addresses[i][j] + "]");
473 }
474
475
6/6
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 935 times.
✓ Branch 4 taken 51 times.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 51 times.
✓ Branch 7 taken 969 times.
1020 if (host.ipv4_addresses_.empty() && host.ipv6_addresses_.empty()) {
476
1/2
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
51 LogCvmfs(kLogDns, kLogDebug, "no addresses returned for %s",
477 51 names[i].c_str());
478 51 host.status_ = kFailNoAddress;
479 }
480
481 // Remove surplus IP addresses
482
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1003 times.
1020 if (throttle_ > 0) {
483
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 17 times.
51 while (host.ipv4_addresses_.size() > throttle_) {
484 34 const unsigned random = prng_.Next(host.ipv4_addresses_.size());
485 34 set<string>::iterator rnd_itr = host.ipv4_addresses_.begin();
486
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 std::advance(rnd_itr, random);
487
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 host.ipv4_addresses_.erase(rnd_itr);
488 }
489
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 17 times.
51 while (host.ipv6_addresses_.size() > throttle_) {
490 34 const unsigned random = prng_.Next(host.ipv6_addresses_.size());
491 34 set<string>::iterator rnd_itr = host.ipv6_addresses_.begin();
492
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 std::advance(rnd_itr, random);
493
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 host.ipv6_addresses_.erase(rnd_itr);
494 }
495 }
496
497
1/2
✓ Branch 2 taken 1020 times.
✗ Branch 3 not taken.
1020 (*hosts)[i] = host;
498
2/2
✓ Branch 1 taken 1020 times.
✓ Branch 2 taken 323 times.
1343 }
499 2504 }
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 1037 QueryInfo(vector<string> *a, const string &n, const ResourceRecord r)
520 1037 : addresses(a)
521 1037 , complete(false)
522 1037 , fqdn(n)
523
1/2
✓ Branch 1 taken 1037 times.
✗ Branch 2 not taken.
1037 , name(n)
524 1037 , record(r)
525 1037 , status(kFailOther)
526 1037 , 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 1037 static void CallbackCares(void *arg, int status, int timeouts_ms,
552 unsigned char *abuf, int alen) {
553 1037 QueryInfo *info = reinterpret_cast<QueryInfo *>(arg);
554
555 1037 info->complete = true;
556
5/7
✓ Branch 0 taken 731 times.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 34 times.
✗ Branch 6 not taken.
1037 switch (status) {
557 731 case ARES_SUCCESS:
558 Failures retval;
559
2/3
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
731 switch (info->record) {
560 374 case kRrA:
561 374 retval = CaresExtractIpv4(abuf, alen, info->addresses, &info->ttl,
562 &info->fqdn);
563 374 break;
564 357 case kRrAaaa:
565 357 retval = CaresExtractIpv6(abuf, alen, info->addresses, &info->ttl,
566 &info->fqdn);
567 357 break;
568 default:
569 // Never here.
570 PANIC(NULL);
571 }
572 731 info->status = retval;
573 731 break;
574 34 case ARES_ENODATA:
575 34 info->status = kFailUnknownHost;
576 34 break;
577 case ARES_EFORMERR:
578 info->status = kFailMalformed;
579 break;
580 204 case ARES_ENOTFOUND:
581 204 info->status = kFailUnknownHost;
582 204 break;
583 34 case ARES_ETIMEOUT:
584 34 info->status = kFailTimeout;
585 34 break;
586 34 case ARES_ECONNREFUSED:
587 34 info->status = kFailInvalidResolvers;
588 34 break;
589 default:
590 info->status = kFailOther;
591 }
592 1037 }
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 374 static Failures CaresExtractIpv4(const unsigned char *abuf,
600 int alen,
601 vector<string> *addresses,
602 unsigned *ttl,
603 string *fqdn) {
604 374 struct hostent *host_entry = NULL;
605 struct ares_addrttl records[CaresResolver::kMaxAddresses];
606 374 int naddrttls = CaresResolver::kMaxAddresses;
607
1/2
✓ Branch 1 taken 374 times.
✗ Branch 2 not taken.
374 const int retval = ares_parse_a_reply(abuf, alen, &host_entry, records,
608 &naddrttls);
609
610
1/3
✓ Branch 0 taken 374 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
374 switch (retval) {
611 374 case ARES_SUCCESS:
612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 374 times.
374 if (host_entry == NULL)
613 return kFailMalformed;
614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 374 times.
374 if (host_entry->h_name == NULL) {
615 ares_free_hostent(host_entry);
616 return kFailMalformed;
617 }
618
1/2
✓ Branch 2 taken 374 times.
✗ Branch 3 not taken.
374 *fqdn = string(host_entry->h_name);
619
1/2
✓ Branch 1 taken 374 times.
✗ Branch 2 not taken.
374 ares_free_hostent(host_entry);
620
621
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 374 times.
374 if (naddrttls <= 0)
622 return kFailMalformed;
623 374 *ttl = unsigned(-1);
624
2/2
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 374 times.
748 for (unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 374 times.
374 if (records[i].ttl < 0)
626 continue;
627 374 *ttl = std::min(unsigned(records[i].ttl), *ttl);
628
629 char addrstr[INET_ADDRSTRLEN];
630 374 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 374 times.
374 if (!retval_p)
633 continue;
634
2/4
✓ Branch 2 taken 374 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 374 times.
✗ Branch 6 not taken.
374 addresses->push_back(addrstr);
635 }
636
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 374 times.
374 if (addresses->empty())
637 return kFailMalformed;
638 374 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 357 static Failures CaresExtractIpv6(const unsigned char *abuf,
650 int alen,
651 vector<string> *addresses,
652 unsigned *ttl,
653 string *fqdn) {
654 357 struct hostent *host_entry = NULL;
655 struct ares_addr6ttl records[CaresResolver::kMaxAddresses];
656 357 int naddrttls = CaresResolver::kMaxAddresses;
657
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 const int retval = ares_parse_aaaa_reply(abuf, alen, &host_entry, records,
658 &naddrttls);
659
660
1/3
✓ Branch 0 taken 357 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
357 switch (retval) {
661 357 case ARES_SUCCESS:
662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357 times.
357 if (host_entry == NULL)
663 return kFailMalformed;
664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357 times.
357 if (host_entry->h_name == NULL) {
665 ares_free_hostent(host_entry);
666 return kFailMalformed;
667 }
668
1/2
✓ Branch 2 taken 357 times.
✗ Branch 3 not taken.
357 *fqdn = string(host_entry->h_name);
669
1/2
✓ Branch 1 taken 357 times.
✗ Branch 2 not taken.
357 ares_free_hostent(host_entry);
670
671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357 times.
357 if (naddrttls <= 0)
672 return kFailMalformed;
673 357 *ttl = unsigned(-1);
674
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 357 times.
714 for (unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357 times.
357 if (records[i].ttl < 0)
676 continue;
677 357 *ttl = std::min(unsigned(records[i].ttl), *ttl);
678
679 char addrstr[INET6_ADDRSTRLEN];
680 357 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 357 times.
357 if (!retval_p)
683 continue;
684
2/4
✓ Branch 2 taken 357 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 357 times.
✗ Branch 6 not taken.
357 addresses->push_back(addrstr);
685 }
686
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 357 times.
357 if (addresses->empty())
687 return kFailMalformed;
688 357 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 4661 CaresResolver::CaresResolver(const bool ipv4_only,
700 const unsigned retries,
701 4661 const unsigned timeout_ms)
702 : Resolver(ipv4_only, retries, timeout_ms)
703 4661 , channel_(NULL)
704 4661 , lookup_options_(strdup("b")) { }
705
706
707 17756 CaresResolver::~CaresResolver() {
708
1/2
✓ Branch 0 taken 4439 times.
✗ Branch 1 not taken.
8878 if (channel_) {
709 8878 ares_destroy(*channel_);
710 8878 free(channel_);
711 }
712 8878 free(lookup_options_);
713 17756 }
714
715
716 /**
717 * Returns a CaresResolver readily initialized, or NULL if an error occurs.
718 */
719 4661 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 4612 times.
4661 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 4661 times.
✗ Branch 2 not taken.
4661 CaresResolver *resolver = new CaresResolver(ipv4_only, retries, timeout_ms);
729 4661 resolver->channel_ = reinterpret_cast<ares_channel *>(
730 4661 smalloc(sizeof(ares_channel)));
731 4661 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 4661 memset(&options, 0, sizeof(options));
738 4661 options.timeout = timeout_ms;
739 4661 options.tries = 1 + retries;
740 4661 options.lookups = resolver->lookup_options_;
741 4661 optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_LOOKUPS;
742
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 retval = ares_init_options(resolver->channel_, &options, optmask);
743
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4661 times.
4661 if (retval != ARES_SUCCESS)
744 goto create_fail;
745
746 // Save search domains
747
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 retval = ares_save_options(*resolver->channel_, &options, &optmask);
748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4661 times.
4661 if (retval != ARES_SUCCESS)
749 goto create_fail;
750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4661 times.
4661 for (int i = 0; i < options.ndomains; ++i) {
751 resolver->domains_.push_back(options.domains[i]);
752 }
753
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 ares_destroy_options(&options);
754
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 resolver->system_domains_ = resolver->domains_;
755
756 // Save the system default resolvers
757 4661 addresses = NULL;
758
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 retval = ares_get_servers(*resolver->channel_, &addresses);
759
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4661 times.
4661 if (retval != ARES_SUCCESS)
760 goto create_fail;
761 4661 iter = addresses;
762
2/2
✓ Branch 0 taken 23305 times.
✓ Branch 1 taken 4661 times.
27966 while (iter) {
763
2/3
✓ Branch 0 taken 13983 times.
✓ Branch 1 taken 9322 times.
✗ Branch 2 not taken.
23305 switch (iter->family) {
764 13983 case AF_INET: {
765 char addrstr[INET_ADDRSTRLEN];
766 13983 const void *retval_p = inet_ntop(AF_INET, &(iter->addr), addrstr,
767 INET_ADDRSTRLEN);
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13983 times.
13983 if (!retval_p) {
769 LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr,
770 "invalid system name resolver");
771 } else {
772
3/6
✓ Branch 2 taken 13983 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13983 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13983 times.
✗ Branch 9 not taken.
13983 resolver->resolvers_.push_back(string(addrstr) + ":53");
773 }
774 13983 break;
775 }
776 9322 case AF_INET6: {
777 char addrstr[INET6_ADDRSTRLEN];
778 9322 const void *retval_p = inet_ntop(AF_INET6, &(iter->addr), addrstr,
779 INET6_ADDRSTRLEN);
780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9322 times.
9322 if (!retval_p) {
781 LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr,
782 "invalid system name resolver");
783 } else {
784
4/8
✓ Branch 2 taken 9322 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9322 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 9322 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 9322 times.
✗ Branch 12 not taken.
9322 resolver->resolvers_.push_back("[" + string(addrstr) + "]:53");
785 }
786 9322 break;
787 }
788 default:
789 // Never here.
790 PANIC(NULL);
791 }
792 23305 iter = iter->next;
793 }
794
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 ares_free_data(addresses);
795
1/2
✓ Branch 1 taken 4661 times.
✗ Branch 2 not taken.
4661 resolver->system_resolvers_ = resolver->resolvers_;
796
797 4661 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 1705 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 1705 const unsigned num = names.size();
822
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1705 times.
1705 if (num == 0)
823 return;
824
825
1/2
✓ Branch 2 taken 1705 times.
✗ Branch 3 not taken.
1705 vector<QueryInfo *> infos_ipv4(num, NULL);
826
1/2
✓ Branch 2 taken 1705 times.
✗ Branch 3 not taken.
1705 vector<QueryInfo *> infos_ipv6(num, NULL);
827
828
2/2
✓ Branch 0 taken 2029 times.
✓ Branch 1 taken 1705 times.
3734 for (unsigned i = 0; i < num; ++i) {
829
3/4
✓ Branch 1 taken 2029 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1502 times.
✓ Branch 4 taken 527 times.
2029 if (skip[i])
830 1502 continue;
831
832
2/2
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 17 times.
527 if (!ipv4_only()) {
833
2/4
✓ Branch 3 taken 510 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 510 times.
✗ Branch 7 not taken.
510 infos_ipv6[i] = new QueryInfo(&(*ipv6_addresses)[i], names[i], kRrAaaa);
834
1/2
✓ Branch 3 taken 510 times.
✗ Branch 4 not taken.
510 ares_search(*channel_, names[i].c_str(), ns_c_in, ns_t_aaaa,
835 510 CallbackCares, infos_ipv6[i]);
836 }
837
2/4
✓ Branch 3 taken 527 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 527 times.
✗ Branch 7 not taken.
527 infos_ipv4[i] = new QueryInfo(&(*ipv4_addresses)[i], names[i], kRrA);
838
1/2
✓ Branch 3 taken 527 times.
✗ Branch 4 not taken.
527 ares_search(*channel_, names[i].c_str(), ns_c_in, ns_t_a, CallbackCares,
839 527 infos_ipv4[i]);
840 }
841
842 bool all_complete;
843 do {
844 41157855 all_complete = true;
845
1/2
✓ Branch 1 taken 41157855 times.
✗ Branch 2 not taken.
41157855 WaitOnCares();
846
2/2
✓ Branch 0 taken 41158417 times.
✓ Branch 1 taken 1705 times.
41160122 for (unsigned i = 0; i < num; ++i) {
847
2/2
✓ Branch 2 taken 918 times.
✓ Branch 3 taken 41155929 times.
82315264 if ((infos_ipv4[i] && !infos_ipv4[i]->complete)
848
8/8
✓ Branch 0 taken 41156847 times.
✓ Branch 1 taken 1570 times.
✓ Branch 3 taken 901 times.
✓ Branch 4 taken 1587 times.
✓ Branch 6 taken 221 times.
✓ Branch 7 taken 680 times.
✓ Branch 8 taken 41156150 times.
✓ Branch 9 taken 2267 times.
82315264 || (infos_ipv6[i] && !infos_ipv6[i]->complete)) {
849 41156150 all_complete = false;
850 41156150 break;
851 }
852 }
853
2/2
✓ Branch 0 taken 41156150 times.
✓ Branch 1 taken 1705 times.
41157855 } 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 2029 times.
✓ Branch 1 taken 1705 times.
3734 for (unsigned i = 0; i < num; ++i) {
858
3/4
✓ Branch 1 taken 2029 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1502 times.
✓ Branch 4 taken 527 times.
2029 if (skip[i])
859 1502 continue;
860
861 527 Failures status = kFailOther;
862 527 (*ttls)[i] = unsigned(-1);
863
1/2
✓ Branch 2 taken 527 times.
✗ Branch 3 not taken.
527 (*fqdns)[i] = "";
864
2/2
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 17 times.
527 if (infos_ipv6[i]) {
865 510 status = infos_ipv6[i]->status;
866
2/2
✓ Branch 0 taken 357 times.
✓ Branch 1 taken 153 times.
510 if (status == kFailOk) {
867 357 (*ttls)[i] = std::min(infos_ipv6[i]->ttl, (*ttls)[i]);
868
1/2
✓ Branch 3 taken 357 times.
✗ Branch 4 not taken.
357 (*fqdns)[i] = infos_ipv6[i]->fqdn;
869 }
870 }
871
1/2
✓ Branch 1 taken 527 times.
✗ Branch 2 not taken.
527 if (infos_ipv4[i]) {
872 527 (*ttls)[i] = std::min(infos_ipv4[i]->ttl, (*ttls)[i]);
873
2/2
✓ Branch 2 taken 170 times.
✓ Branch 3 taken 357 times.
527 if ((*fqdns)[i] == "")
874
1/2
✓ Branch 3 taken 170 times.
✗ Branch 4 not taken.
170 (*fqdns)[i] = infos_ipv4[i]->fqdn;
875
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 357 times.
527 if (status != kFailOk)
876 170 status = infos_ipv4[i]->status;
877 }
878 527 (*failures)[i] = status;
879 }
880
881
2/2
✓ Branch 0 taken 2029 times.
✓ Branch 1 taken 1705 times.
3734 for (unsigned i = 0; i < num; ++i) {
882
2/2
✓ Branch 1 taken 527 times.
✓ Branch 2 taken 1502 times.
2029 delete infos_ipv4[i];
883
2/2
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 1519 times.
2029 delete infos_ipv6[i];
884 }
885 1705 }
886
887
888 51 bool CaresResolver::SetResolvers(const vector<string> &resolvers) {
889
2/4
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 51 times.
✗ Branch 6 not taken.
102 const string address_list = JoinStrings(resolvers, ",");
890
1/2
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
51 const int retval = ares_set_servers_csv(*channel_, address_list.c_str());
891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (retval != ARES_SUCCESS)
892 return false;
893
894
1/2
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
51 resolvers_ = resolvers;
895 51 return true;
896 51 }
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 34 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 34 memcpy(&ares_channelhead, *channel_, sizeof(ares_channelhead));
922
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 if (ares_channelhead.domains) {
923
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 17 times.
51 for (int i = 0; i < ares_channelhead.ndomains; ++i) {
924 34 free(ares_channelhead.domains[i]);
925 }
926 17 free(ares_channelhead.domains);
927 17 ares_channelhead.domains = NULL;
928 }
929
930 34 ares_channelhead.ndomains = static_cast<int>(domains.size());
931
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 if (ares_channelhead.ndomains > 0) {
932 17 ares_channelhead.domains = reinterpret_cast<char **>(
933 17 smalloc(ares_channelhead.ndomains * sizeof(char *)));
934
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 17 times.
51 for (int i = 0; i < ares_channelhead.ndomains; ++i) {
935 34 ares_channelhead.domains[i] = strdup(domains[i].c_str());
936 }
937 }
938
939 34 memcpy(*channel_, &ares_channelhead, sizeof(ares_channelhead));
940
941
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
34 domains_ = domains;
942 34 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 41157855 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 41157855 times.
✗ Branch 2 not taken.
41157855 const int bitmask = ares_getsock(*channel_, socks, ARES_GETSOCK_MAXNUM);
967 41157855 unsigned num = 0;
968
1/2
✓ Branch 0 taken 120612778 times.
✗ Branch 1 not taken.
120612778 for (unsigned i = 0; i < ARES_GETSOCK_MAXNUM; ++i) {
969 120612778 pfd[i].events = 0;
970 120612778 pfd[i].revents = 0;
971
2/2
✓ Branch 0 taken 79454923 times.
✓ Branch 1 taken 41157855 times.
120612778 if (ARES_GETSOCK_READABLE(bitmask, i)) {
972 79454923 pfd[i].fd = socks[i];
973 79454923 pfd[i].events |= POLLRDNORM | POLLIN;
974 }
975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120612778 times.
120612778 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 79454923 times.
✓ Branch 1 taken 41157855 times.
120612778 if (pfd[i].events != 0)
980 79454923 num++;
981 else
982 41157855 break;
983 }
984
985 41157855 int nfds = 0;
986
2/2
✓ Branch 0 taken 41156320 times.
✓ Branch 1 taken 1535 times.
41157855 if (num > 0) {
987 do {
988
1/2
✓ Branch 2 taken 41156320 times.
✗ Branch 3 not taken.
41156320 nfds = poll(pfd, num, timeout_ms());
989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41156320 times.
41156320 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 41156320 times.
41156320 } while (nfds == -1);
995 }
996
997
2/2
✓ Branch 0 taken 1535 times.
✓ Branch 1 taken 41156320 times.
41157855 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 1535 times.
✗ Branch 2 not taken.
1535 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 79454923 times.
✓ Branch 1 taken 41156320 times.
120611243 for (unsigned i = 0; i < num; ++i) {
1004 158909846 ares_process_fd(
1005
1/2
✓ Branch 1 taken 79454923 times.
✗ Branch 2 not taken.
79454923 *channel_,
1006
2/2
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 79454413 times.
79454923 pfd[i].revents & (POLLRDNORM | POLLIN) ? pfd[i].fd : ARES_SOCKET_BAD,
1007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79454923 times.
79454923 pfd[i].revents & (POLLWRNORM | POLLOUT) ? pfd[i].fd
1008 : ARES_SOCKET_BAD);
1009 }
1010 }
1011 41157855 }
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 3726 HostfileResolver *HostfileResolver::Create(const string &path, bool ipv4_only) {
1023
1/2
✓ Branch 1 taken 3726 times.
✗ Branch 2 not taken.
3726 HostfileResolver *resolver = new HostfileResolver(ipv4_only);
1024
1025
1/2
✓ Branch 1 taken 3726 times.
✗ Branch 2 not taken.
3726 string hosts_file = path;
1026
2/2
✓ Branch 1 taken 2944 times.
✓ Branch 2 taken 782 times.
3726 if (hosts_file == "") {
1027 2944 char *hosts_env = getenv("HOST_ALIASES");
1028
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 2910 times.
2944 if (hosts_env != NULL) {
1029
1/2
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
34 hosts_file = string(hosts_env);
1030 } else {
1031
1/2
✓ Branch 1 taken 2910 times.
✗ Branch 2 not taken.
2910 hosts_file = "/etc/hosts";
1032 }
1033 }
1034
1/2
✓ Branch 2 taken 3726 times.
✗ Branch 3 not taken.
3726 resolver->fhosts_ = fopen(hosts_file.c_str(), "r");
1035
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 3692 times.
3726 if (!resolver->fhosts_) {
1036
1/2
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
34 LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, "failed to read host file %s",
1037 hosts_file.c_str());
1038
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 delete resolver;
1039 34 return NULL;
1040 }
1041 3692 return resolver;
1042 3726 }
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 51 static bool SortNameLength(const string &a, const string &b) {
1051 51 const unsigned len_a = a.length();
1052 51 const unsigned len_b = b.length();
1053
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
51 if (len_a != len_b)
1054 51 return len_a > len_b;
1055 return a > b;
1056 }
1057
1058
1059 /**
1060 * Creates a fresh reverse lookup map
1061 */
1062 1790 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 1790 const unsigned num = names.size();
1070
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1790 times.
1790 if (num == 0)
1071 return;
1072
1073 1790 ParseHostFile();
1074
2/2
✓ Branch 0 taken 1893 times.
✓ Branch 1 taken 1790 times.
3683 for (unsigned i = 0; i < num; ++i) {
1075
3/4
✓ Branch 1 taken 1893 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1298 times.
✓ Branch 4 taken 595 times.
1893 if (skip[i])
1076 1298 continue;
1077
1078 595 vector<string> effective_names;
1079
5/6
✓ Branch 2 taken 595 times.
✗ Branch 3 not taken.
✓ Branch 8 taken 34 times.
✓ Branch 9 taken 561 times.
✓ Branch 10 taken 34 times.
✓ Branch 11 taken 561 times.
595 if (!names[i].empty() && (names[i][names[i].length() - 1] == '.')) {
1080
2/4
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 34 times.
✗ Branch 8 not taken.
34 effective_names.push_back(names[i].substr(0, names[i].length() - 1));
1081 } else {
1082
1/2
✓ Branch 2 taken 561 times.
✗ Branch 3 not taken.
561 effective_names.push_back(names[i]);
1083
2/2
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 561 times.
612 for (unsigned j = 0; j < domains().size(); ++j) {
1084
3/6
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 51 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 51 times.
✗ Branch 11 not taken.
51 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 595 times.
✗ Branch 4 not taken.
595 std::sort(effective_names.begin(), effective_names.end(), SortNameLength);
1090
1091 595 (*failures)[i] = kFailUnknownHost;
1092
1/2
✓ Branch 3 taken 595 times.
✗ Branch 4 not taken.
595 (*fqdns)[i] = names[i];
1093
2/2
✓ Branch 1 taken 595 times.
✓ Branch 2 taken 170 times.
765 for (unsigned j = 0; j < effective_names.size(); ++j) {
1094
1/2
✓ Branch 1 taken 595 times.
✗ Branch 2 not taken.
595 const map<string, HostEntry>::iterator iter = host_map_.find(
1095 595 effective_names[j]);
1096
2/2
✓ Branch 2 taken 425 times.
✓ Branch 3 taken 170 times.
595 if (iter != host_map_.end()) {
1097
1/2
✓ Branch 7 taken 425 times.
✗ Branch 8 not taken.
1275 (*ipv4_addresses)[i].insert((*ipv4_addresses)[i].end(),
1098 425 iter->second.ipv4_addresses.begin(),
1099 425 iter->second.ipv4_addresses.end());
1100
1/2
✓ Branch 7 taken 425 times.
✗ Branch 8 not taken.
1275 (*ipv6_addresses)[i].insert((*ipv6_addresses)[i].end(),
1101 425 iter->second.ipv6_addresses.begin(),
1102 425 iter->second.ipv6_addresses.end());
1103 425 (*ttls)[i] = min_ttl_;
1104
1/2
✓ Branch 3 taken 425 times.
✗ Branch 4 not taken.
425 (*fqdns)[i] = effective_names[j];
1105 425 (*failures)[i] = kFailOk;
1106 425 break;
1107 } // Host name found
1108 } // All possible names (search domains added)
1109 595 }
1110 }
1111
1112
1113 3726 HostfileResolver::HostfileResolver(const bool ipv4_only)
1114 3726 : Resolver(ipv4_only, 0, 0), fhosts_(NULL) { }
1115
1116
1117 14900 HostfileResolver::~HostfileResolver() {
1118
2/2
✓ Branch 0 taken 3691 times.
✓ Branch 1 taken 34 times.
7450 if (fhosts_)
1119 7382 fclose(fhosts_);
1120 14900 }
1121
1122
1123 /**
1124 * TODO: this should be only necessary when the modification timestamp changed.
1125 */
1126 1790 void HostfileResolver::ParseHostFile() {
1127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1790 times.
1790 assert(fhosts_);
1128
1/2
✓ Branch 1 taken 1790 times.
✗ Branch 2 not taken.
1790 rewind(fhosts_);
1129 1790 host_map_.clear();
1130
1131 1790 string line;
1132
3/4
✓ Branch 1 taken 7092 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5302 times.
✓ Branch 4 taken 1790 times.
7092 while (GetLineFile(fhosts_, &line)) {
1133 char address[kIpMaxLength + 1];
1134 char hostname[kHostnameMaxLength + 1];
1135 int bytes_read;
1136 5302 size_t str_offset = 0;
1137
1138 // strip comments
1139 5302 const size_t hash_pos = line.find_first_of('#');
1140
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 5132 times.
5302 if (hash_pos != string::npos)
1141
1/2
✓ Branch 1 taken 170 times.
✗ Branch 2 not taken.
170 line = line.substr(0, hash_pos);
1142
1143 // First token is an IP address
1144 5302 int ip_start_pos = -1, ip_end_pos = -1, scan_result;
1145 5302 scan_result = sscanf(line.c_str(), " %n%*s%n", &ip_start_pos, &ip_end_pos);
1146
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 5064 times.
5302 if (scan_result == EOF)
1147 272 continue;
1148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5064 times.
5064 assert(ip_start_pos != -1);
1149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5064 times.
5064 assert(ip_end_pos != -1);
1150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5064 times.
5064 if (ip_start_pos == ip_end_pos)
1151 continue;
1152
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 5030 times.
5064 if (ip_end_pos - ip_start_pos > kIpMaxLength) {
1153
1/2
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
34 LogCvmfs(
1154 kLogDns, kLogSyslogWarn,
1155 "Skipping line in hosts file due to invalid IP address format: %s",
1156 line.c_str());
1157 34 continue;
1158 }
1159
1160 5030 bytes_read = -1;
1161 5030 scan_result = sscanf(line.c_str(), " %s%n", address, &bytes_read);
1162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5030 times.
5030 assert(scan_result == 1);
1163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5030 times.
5030 assert(bytes_read != -1);
1164 5030 str_offset += bytes_read;
1165
1166 // Next tokens are hostnames and aliases (we treat them as equal)
1167
2/2
✓ Branch 1 taken 14449 times.
✓ Branch 2 taken 4911 times.
19360 while (str_offset < line.length()) {
1168 // check hostname length
1169 14449 int hostname_start_pos = -1, hostname_end_pos = -1;
1170 14449 scan_result = sscanf(line.c_str() + str_offset, " %n%*s%n",
1171 &hostname_start_pos, &hostname_end_pos);
1172
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 14330 times.
14449 if (scan_result == EOF)
1173 119 break;
1174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14330 times.
14330 assert(hostname_start_pos != -1);
1175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14330 times.
14330 assert(hostname_end_pos != -1);
1176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14330 times.
14330 if (hostname_start_pos == hostname_end_pos)
1177 break;
1178
1179
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 14296 times.
14330 if (hostname_end_pos - hostname_start_pos > kHostnameMaxLength) {
1180
1/2
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
34 LogCvmfs(
1181 kLogDns, kLogSyslogWarn,
1182 "Skipping invalid (too long) hostname in hosts file on line: %s",
1183 line.c_str());
1184 34 str_offset += hostname_end_pos;
1185 34 continue;
1186 }
1187
1188 14296 bytes_read = -1;
1189 14296 scan_result = sscanf(line.c_str() + str_offset, " %s%n", hostname,
1190 &bytes_read);
1191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14296 times.
14296 assert(scan_result == 1);
1192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14296 times.
14296 assert(bytes_read != -1);
1193 14296 str_offset += bytes_read;
1194
1195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14296 times.
14296 if (hostname[strlen(hostname) - 1] == '.')
1196 hostname[strlen(hostname) - 1] = 0; // strip the last character
1197
1198
2/4
✓ Branch 2 taken 14296 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 14296 times.
✗ Branch 6 not taken.
14296 const map<string, HostEntry>::iterator iter = host_map_.find(hostname);
1199
2/2
✓ Branch 2 taken 11515 times.
✓ Branch 3 taken 2781 times.
14296 if (iter == host_map_.end()) {
1200 11515 HostEntry entry;
1201
4/6
✓ Branch 2 taken 11515 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11515 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 8785 times.
✓ Branch 10 taken 2730 times.
11515 if (IsIpv4Address(address))
1202
2/4
✓ Branch 2 taken 8785 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8785 times.
✗ Branch 6 not taken.
8785 entry.ipv4_addresses.push_back(address);
1203
2/2
✓ Branch 1 taken 2696 times.
✓ Branch 2 taken 34 times.
2730 else if (!ipv4_only())
1204
2/4
✓ Branch 2 taken 2696 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2696 times.
✗ Branch 6 not taken.
2696 entry.ipv6_addresses.push_back(address);
1205
3/6
✓ Branch 2 taken 11515 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11515 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 11515 times.
✗ Branch 9 not taken.
11515 host_map_[hostname] = entry;
1206 11515 } else {
1207
4/6
✓ Branch 2 taken 2781 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2781 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 51 times.
✓ Branch 10 taken 2730 times.
2781 if (IsIpv4Address(address))
1208
2/4
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
51 iter->second.ipv4_addresses.push_back(address);
1209
2/2
✓ Branch 1 taken 2696 times.
✓ Branch 2 taken 34 times.
2730 else if (!ipv4_only())
1210
2/4
✓ Branch 3 taken 2696 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2696 times.
✗ Branch 7 not taken.
2696 iter->second.ipv6_addresses.push_back(address);
1211 }
1212 } // Current line
1213 } // Hosts file
1214 1790 }
1215
1216
1217 2893 bool HostfileResolver::SetSearchDomains(const vector<string> &domains) {
1218 2893 domains_ = domains;
1219 2893 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 2893 NormalResolver *NormalResolver::Create(const bool ipv4_only,
1237 const unsigned retries,
1238 const unsigned timeout_ms) {
1239 2893 CaresResolver *cares_resolver = CaresResolver::Create(ipv4_only, retries,
1240 timeout_ms);
1241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2893 times.
2893 if (!cares_resolver)
1242 return NULL;
1243
2/4
✓ Branch 2 taken 2893 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2893 times.
✗ Branch 6 not taken.
2893 HostfileResolver *hostfile_resolver = HostfileResolver::Create("", ipv4_only);
1244
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 2876 times.
2893 if (!hostfile_resolver) {
1245
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 delete cares_resolver;
1246 17 return NULL;
1247 }
1248 2876 const bool retval = hostfile_resolver->SetSearchDomains(
1249 cares_resolver->domains());
1250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2876 times.
2876 assert(retval);
1251
1252 2876 NormalResolver *normal_resolver = new NormalResolver();
1253 2876 normal_resolver->cares_resolver_ = cares_resolver;
1254 2876 normal_resolver->hostfile_resolver_ = hostfile_resolver;
1255 2876 normal_resolver->domains_ = cares_resolver->domains();
1256 2876 normal_resolver->resolvers_ = cares_resolver->resolvers();
1257 2876 normal_resolver->retries_ = cares_resolver->retries();
1258 2876 normal_resolver->timeout_ms_ = cares_resolver->timeout_ms();
1259 2876 return normal_resolver;
1260 }
1261
1262
1263 /**
1264 * Makes only sense for the c-ares resolver.
1265 */
1266 17 bool NormalResolver::SetResolvers(const vector<string> &resolvers) {
1267 17 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 1280 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 1280 const unsigned num = names.size();
1314
1/2
✓ Branch 1 taken 1280 times.
✗ Branch 2 not taken.
1280 hostfile_resolver_->DoResolve(names, skip, ipv4_addresses, ipv6_addresses,
1315 failures, ttls, fqdns);
1316
1/2
✓ Branch 1 taken 1280 times.
✗ Branch 2 not taken.
1280 vector<bool> skip_cares = skip;
1317
2/2
✓ Branch 0 taken 1281 times.
✓ Branch 1 taken 1280 times.
2561 for (unsigned i = 0; i < num; ++i) {
1318
2/2
✓ Branch 1 taken 1264 times.
✓ Branch 2 taken 17 times.
1281 if ((*failures)[i] == kFailOk)
1319
1/2
✓ Branch 1 taken 1264 times.
✗ Branch 2 not taken.
1264 skip_cares[i] = true;
1320 }
1321
1/2
✓ Branch 1 taken 1280 times.
✗ Branch 2 not taken.
1280 cares_resolver_->DoResolve(names, skip_cares, ipv4_addresses, ipv6_addresses,
1322 failures, ttls, fqdns);
1323 1280 }
1324
1325
1326 2876 NormalResolver::NormalResolver()
1327 2876 : Resolver(false, 0, 0), cares_resolver_(NULL), hostfile_resolver_(NULL) { }
1328
1329
1330 11500 NormalResolver::~NormalResolver() {
1331
1/2
✓ Branch 0 taken 2875 times.
✗ Branch 1 not taken.
5750 delete cares_resolver_;
1332
1/2
✓ Branch 0 taken 2875 times.
✗ Branch 1 not taken.
5750 delete hostfile_resolver_;
1333 11500 }
1334
1335 } // namespace dns
1336