GCC Code Coverage Report


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