GCC Code Coverage Report


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