GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/network/dns.cc
Date: 2025-09-14 02:35:40
Exec Total Coverage
Lines: 617 698 88.4%
Branches: 515 806 63.9%

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