Directory: | cvmfs/ |
---|---|
File: | cvmfs/network/dns.cc |
Date: | 2025-07-13 02:35:07 |
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 | 5634 | static void PinpointHostSubstr(const std::string &url, | |
54 | unsigned *pos_begin, | ||
55 | unsigned *pos_end) { | ||
56 | 5634 | *pos_begin = *pos_end = 0; | |
57 | 5634 | const unsigned len = url.size(); | |
58 | 5634 | unsigned i = 0; | |
59 | |||
60 | // Search '//' in the url string and jump behind | ||
61 |
2/2✓ Branch 0 taken 35460 times.
✓ Branch 1 taken 1754 times.
|
37214 | for (; i < len; ++i) { |
62 |
8/8✓ Branch 1 taken 4478 times.
✓ Branch 2 taken 30982 times.
✓ Branch 3 taken 4018 times.
✓ Branch 4 taken 460 times.
✓ Branch 6 taken 3880 times.
✓ Branch 7 taken 138 times.
✓ Branch 8 taken 3880 times.
✓ Branch 9 taken 31580 times.
|
35460 | if ((url[i] == '/') && (i < len - 2) && (url[i + 1] == '/')) { |
63 | 3880 | i += 2; | |
64 | 3880 | *pos_begin = i; | |
65 | 3880 | break; | |
66 | } | ||
67 | } | ||
68 | |||
69 | // Search '@' within the hostname part and jump behind if present | ||
70 |
2/2✓ Branch 0 taken 3880 times.
✓ Branch 1 taken 1754 times.
|
5634 | if (*pos_begin > 0) { |
71 |
2/2✓ Branch 0 taken 34678 times.
✓ Branch 1 taken 2592 times.
|
37270 | for (i = *pos_begin; i < len; ++i) { |
72 |
2/2✓ Branch 1 taken 1058 times.
✓ Branch 2 taken 33620 times.
|
34678 | if (url[i] == '/') { |
73 | 1058 | break; | |
74 |
2/2✓ Branch 1 taken 230 times.
✓ Branch 2 taken 33390 times.
|
33620 | } else if (url[i] == '@') { |
75 | 230 | *pos_begin = ++i; | |
76 | 230 | break; | |
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // Find the end of the hostname part | ||
82 |
2/2✓ Branch 0 taken 3880 times.
✓ Branch 1 taken 1754 times.
|
5634 | if (*pos_begin > 0) { |
83 | 3880 | bool in_ipv6 = (url[*pos_begin] == '['); | |
84 |
2/2✓ Branch 0 taken 27760 times.
✓ Branch 1 taken 874 times.
|
28634 | for (i = *pos_begin; i < len; ++i) { |
85 |
2/2✓ Branch 0 taken 5060 times.
✓ Branch 1 taken 22700 times.
|
27760 | if (in_ipv6) { |
86 |
2/2✓ Branch 1 taken 4094 times.
✓ Branch 2 taken 966 times.
|
5060 | if (url[i] != ']') |
87 | 4094 | continue; | |
88 | 966 | in_ipv6 = false; | |
89 | } | ||
90 | |||
91 |
6/6✓ Branch 1 taken 21304 times.
✓ Branch 2 taken 2362 times.
✓ Branch 4 taken 644 times.
✓ Branch 5 taken 20660 times.
✓ Branch 6 taken 3006 times.
✓ Branch 7 taken 20660 times.
|
23666 | if ((url[i] == ':') || (url[i] == '/')) |
92 | 3006 | break; | |
93 | } | ||
94 |
2/2✓ Branch 0 taken 3604 times.
✓ Branch 1 taken 276 times.
|
3880 | if (!in_ipv6) |
95 | 3604 | *pos_end = i - 1; | |
96 | |||
97 |
2/2✓ Branch 0 taken 828 times.
✓ Branch 1 taken 3052 times.
|
3880 | if (*pos_end < *pos_begin) |
98 | 828 | *pos_end = *pos_begin = 0; | |
99 | } | ||
100 | 5634 | } | |
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 | 2245 | std::string ExtractHost(const std::string &url) { | |
109 | unsigned pos_begin; | ||
110 | unsigned pos_end; | ||
111 | 2245 | PinpointHostSubstr(url, &pos_begin, &pos_end); | |
112 |
2/2✓ Branch 0 taken 1110 times.
✓ Branch 1 taken 1135 times.
|
2245 | if (pos_begin == 0) |
113 |
1/2✓ Branch 2 taken 1110 times.
✗ Branch 3 not taken.
|
1110 | return ""; |
114 |
1/2✓ Branch 1 taken 1135 times.
✗ Branch 2 not taken.
|
1135 | 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 | 2453 | std::string ExtractPort(const std::string &url) { | |
124 | unsigned pos_begin; | ||
125 | unsigned pos_end; | ||
126 | 2453 | PinpointHostSubstr(url, &pos_begin, &pos_end); | |
127 |
9/10✓ Branch 0 taken 1487 times.
✓ Branch 1 taken 966 times.
✓ Branch 3 taken 1165 times.
✓ Branch 4 taken 322 times.
✓ Branch 6 taken 1165 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 138 times.
✓ Branch 9 taken 1027 times.
✓ Branch 10 taken 1426 times.
✓ Branch 11 taken 1027 times.
|
2453 | if (pos_begin == 0 || pos_end + 2 >= url.size() || url.at(pos_end + 1) != ':') |
128 |
1/2✓ Branch 2 taken 1426 times.
✗ Branch 3 not taken.
|
1426 | return ""; |
129 | |||
130 | // Do not include path | ||
131 | 1027 | const std::size_t pos_port = url.find("/", pos_end); | |
132 | 1027 | std::string retme; | |
133 |
2/2✓ Branch 0 taken 751 times.
✓ Branch 1 taken 276 times.
|
1027 | if (pos_port == std::string::npos) |
134 |
1/2✓ Branch 1 taken 751 times.
✗ Branch 2 not taken.
|
751 | retme = url.substr(pos_end + 2); |
135 | else | ||
136 |
1/2✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
|
276 | retme = url.substr(pos_end + 2, pos_port - pos_end - 2); |
137 | |||
138 | // Port is an integer | ||
139 |
2/2✓ Branch 4 taken 2222 times.
✓ Branch 5 taken 843 times.
|
3065 | for (std::string::iterator it = retme.begin(); it != retme.end(); ++it) |
140 |
2/2✓ Branch 1 taken 184 times.
✓ Branch 2 taken 2038 times.
|
2222 | if (isdigit(*it) == 0) |
141 |
1/2✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
184 | return ""; |
142 | |||
143 | 843 | return retme; | |
144 | 1027 | } | |
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 | 936 | string RewriteUrl(const string &url, const string &ip) { | |
153 | unsigned pos_begin; | ||
154 | unsigned pos_end; | ||
155 | 936 | PinpointHostSubstr(url, &pos_begin, &pos_end); | |
156 |
2/2✓ Branch 0 taken 506 times.
✓ Branch 1 taken 430 times.
|
936 | if (pos_begin == 0) |
157 |
1/2✓ Branch 1 taken 506 times.
✗ Branch 2 not taken.
|
506 | return url; |
158 | |||
159 |
1/2✓ Branch 1 taken 430 times.
✗ Branch 2 not taken.
|
430 | string result = url; |
160 |
1/2✓ Branch 1 taken 430 times.
✗ Branch 2 not taken.
|
430 | result.replace(pos_begin, (pos_end - pos_begin) + 1, ip); |
161 | 430 | return result; | |
162 | 430 | } | |
163 | |||
164 | |||
165 | /** | ||
166 | * Removes the brackets from IPv6 addresses. Leaves IPv4 addresses unchanged. | ||
167 | */ | ||
168 | 368 | string StripIp(const string &decorated_ip) { | |
169 |
2/2✓ Branch 1 taken 322 times.
✓ Branch 2 taken 46 times.
|
368 | if (!decorated_ip.empty()) { |
170 | 322 | if ((decorated_ip[0] == '[') | |
171 |
6/6✓ Branch 0 taken 184 times.
✓ Branch 1 taken 138 times.
✓ Branch 4 taken 92 times.
✓ Branch 5 taken 92 times.
✓ Branch 6 taken 92 times.
✓ Branch 7 taken 230 times.
|
322 | && (decorated_ip[decorated_ip.length() - 1] == ']')) { |
172 | 92 | return decorated_ip.substr(1, decorated_ip.length() - 2); | |
173 | } | ||
174 | } | ||
175 | 276 | return decorated_ip; | |
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Adds http:// if it is missing from proxy | ||
181 | */ | ||
182 | 1930 | std::string AddDefaultScheme(const std::string &proxy) { | |
183 | 1930 | const bool ignore_case = true; | |
184 |
4/12✓ Branch 1 taken 1930 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1930 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1792 times.
✓ Branch 8 taken 138 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
3860 | if (HasPrefix(proxy, "http://", ignore_case) |
185 |
9/19✓ Branch 2 taken 1852 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1852 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1806 times.
✓ Branch 8 taken 46 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 184 times.
✓ Branch 11 taken 1622 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1852 times.
✓ Branch 14 taken 78 times.
✓ Branch 16 taken 1930 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
|
3782 | || HasPrefix(proxy, "https://", ignore_case) || (proxy == "DIRECT") |
186 |
7/9✓ Branch 2 taken 1930 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1852 times.
✓ Branch 5 taken 78 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 46 times.
✓ Branch 8 taken 138 times.
✓ Branch 9 taken 1852 times.
✓ Branch 10 taken 78 times.
|
5712 | || proxy.empty()) { |
187 | 1792 | return proxy; | |
188 | } | ||
189 | 138 | return "http://" + proxy; | |
190 | } | ||
191 | |||
192 | |||
193 | //------------------------------------------------------------------------------ | ||
194 | |||
195 | |||
196 | atomic_int64 Host::global_id_ = 0; | ||
197 | |||
198 | 430 | const set<string> &Host::ViewBestAddresses(IpPreference preference) const { | |
199 |
2/2✓ Branch 0 taken 138 times.
✓ Branch 1 taken 138 times.
|
276 | if (((preference == kIpPreferSystem) || (preference == kIpPreferV4)) |
200 |
6/6✓ Branch 0 taken 276 times.
✓ Branch 1 taken 154 times.
✓ Branch 3 taken 200 times.
✓ Branch 4 taken 92 times.
✓ Branch 5 taken 200 times.
✓ Branch 6 taken 230 times.
|
706 | && HasIpv4()) { |
201 | 200 | return ipv4_addresses_; | |
202 | } | ||
203 |
6/6✓ Branch 0 taken 138 times.
✓ Branch 1 taken 92 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 92 times.
✓ Branch 5 taken 46 times.
✓ Branch 6 taken 184 times.
|
230 | if ((preference == kIpPreferV6) && !HasIpv6()) |
204 | 46 | return ipv4_addresses_; | |
205 | 184 | return ipv6_addresses_; | |
206 | } | ||
207 | |||
208 | |||
209 | 16382 | void Host::CopyFrom(const Host &other) { | |
210 | 16382 | deadline_ = other.deadline_; | |
211 | 16382 | id_ = other.id_; | |
212 | 16382 | ipv4_addresses_ = other.ipv4_addresses_; | |
213 | 16382 | ipv6_addresses_ = other.ipv6_addresses_; | |
214 | 16382 | name_ = other.name_; | |
215 | 16382 | status_ = other.status_; | |
216 | 16382 | } | |
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 | 46 | Host Host::ExtendDeadline(const Host &original, unsigned seconds_from_now) { | |
224 | 46 | Host new_host(original); | |
225 | 46 | new_host.id_ = atomic_xadd64(&global_id_, 1); | |
226 | 46 | new_host.deadline_ = time(NULL) + seconds_from_now; | |
227 | 46 | 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 | 9738 | Host::Host() | |
236 | 9738 | : deadline_(0) | |
237 | 9738 | , id_(atomic_xadd64(&global_id_, 1)) | |
238 | 9738 | , status_(kFailNotYetResolved) { } | |
239 | |||
240 | |||
241 |
1/2✓ Branch 4 taken 11272 times.
✗ Branch 5 not taken.
|
11272 | Host::Host(const Host &other) { CopyFrom(other); } |
242 | |||
243 | |||
244 | 5114 | Host &Host::operator=(const Host &other) { | |
245 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5110 times.
|
5114 | if (&other == this) |
246 | 4 | return *this; | |
247 | 5110 | CopyFrom(other); | |
248 | 5110 | 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 | 1012 | bool Host::IsEquivalent(const Host &other) const { | |
258 |
2/2✓ Branch 0 taken 828 times.
✓ Branch 1 taken 46 times.
|
874 | return (status_ == kFailOk) && (other.status_ == kFailOk) |
259 |
3/4✓ Branch 1 taken 828 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 736 times.
✓ Branch 5 taken 92 times.
|
828 | && (name_ == other.name_) && (ipv4_addresses_ == other.ipv4_addresses_) |
260 |
4/4✓ Branch 0 taken 874 times.
✓ Branch 1 taken 138 times.
✓ Branch 3 taken 552 times.
✓ Branch 4 taken 184 times.
|
1886 | && (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 | 660 | bool Host::IsExpired() const { | |
268 | 660 | const time_t now = time(NULL); | |
269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
|
660 | assert(now != static_cast<time_t>(-1)); |
270 | 660 | 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 | 736 | bool Host::IsValid() const { | |
280 |
2/2✓ Branch 0 taken 276 times.
✓ Branch 1 taken 460 times.
|
736 | if (status_ != kFailOk) |
281 | 276 | return false; | |
282 | |||
283 |
3/4✓ Branch 1 taken 92 times.
✓ Branch 2 taken 368 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 92 times.
|
460 | assert(!ipv4_addresses_.empty() || !ipv6_addresses_.empty()); |
284 | 460 | 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 | 20808 | bool Resolver::IsIpv4Address(const string &address) { | |
296 | // Are there any unexpected characters? | ||
297 |
2/4✓ Branch 2 taken 20808 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20808 times.
✗ Branch 6 not taken.
|
41616 | const sanitizer::InputSanitizer sanitizer("09 ."); |
298 |
3/4✓ Branch 1 taken 20808 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8582 times.
✓ Branch 4 taken 12226 times.
|
20808 | if (!sanitizer.IsValid(address)) |
299 | 8582 | return false; | |
300 | |||
301 | // 4 octets in the range 0-255? | ||
302 |
1/2✓ Branch 1 taken 12226 times.
✗ Branch 2 not taken.
|
12226 | vector<string> octets = SplitString(address, '.'); |
303 |
2/2✓ Branch 1 taken 46 times.
✓ Branch 2 taken 12180 times.
|
12226 | if (octets.size() != 4) |
304 | 46 | return false; | |
305 |
2/2✓ Branch 0 taken 48720 times.
✓ Branch 1 taken 12134 times.
|
60854 | for (unsigned i = 0; i < 4; ++i) { |
306 |
1/2✓ Branch 2 taken 48720 times.
✗ Branch 3 not taken.
|
48720 | const uint64_t this_octet = String2Uint64(octets[i]); |
307 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 48674 times.
|
48720 | if (this_octet > 255) |
308 | 46 | return false; | |
309 | } | ||
310 | |||
311 | 12134 | return true; | |
312 | 20808 | } | |
313 | |||
314 | |||
315 | /** | ||
316 | * Basic input validation to ensure that this could syntactically represent a | ||
317 | * valid IPv6 address. | ||
318 | */ | ||
319 | 2024 | bool Resolver::IsIpv6Address(const string &address) { | |
320 | // Are there any unexpected characters? | ||
321 |
2/4✓ Branch 2 taken 2024 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2024 times.
✗ Branch 6 not taken.
|
4048 | const sanitizer::InputSanitizer sanitizer("09 af AF :"); |
322 |
1/2✓ Branch 1 taken 2024 times.
✗ Branch 2 not taken.
|
4048 | return sanitizer.IsValid(address); |
323 | 2024 | } | |
324 | |||
325 | |||
326 | 14166 | Resolver::Resolver(const bool ipv4_only, | |
327 | const unsigned retries, | ||
328 | 14166 | const unsigned timeout_ms) | |
329 | 14166 | : ipv4_only_(ipv4_only) | |
330 | 14166 | , retries_(retries) | |
331 | 14166 | , timeout_ms_(timeout_ms) | |
332 | 14166 | , throttle_(0) | |
333 | 14166 | , min_ttl_(kDefaultMinTtl) | |
334 | 14166 | , max_ttl_(kDefaultMaxTtl) { | |
335 | 14166 | prng_.InitLocaltime(); | |
336 | 14166 | } | |
337 | |||
338 | |||
339 | /** | ||
340 | * Wrapper around the vector interface. | ||
341 | */ | ||
342 | 2856 | Host Resolver::Resolve(const string &name) { | |
343 | 2856 | vector<string> names; | |
344 |
1/2✓ Branch 1 taken 2856 times.
✗ Branch 2 not taken.
|
2856 | names.push_back(name); |
345 | 2856 | vector<Host> hosts; | |
346 |
1/2✓ Branch 1 taken 2856 times.
✗ Branch 2 not taken.
|
2856 | ResolveMany(names, &hosts); |
347 |
1/2✓ Branch 2 taken 2856 times.
✗ Branch 3 not taken.
|
5712 | return hosts[0]; |
348 | 2856 | } | |
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 | 3794 | void Resolver::ResolveMany(const vector<string> &names, vector<Host> *hosts) { | |
356 | 3794 | const unsigned num = names.size(); | |
357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3794 times.
|
3794 | if (num == 0) |
358 | ✗ | return; | |
359 | |||
360 |
1/2✓ Branch 2 taken 3794 times.
✗ Branch 3 not taken.
|
3794 | vector<vector<string> > ipv4_addresses(num); |
361 |
1/2✓ Branch 2 taken 3794 times.
✗ Branch 3 not taken.
|
3794 | vector<vector<string> > ipv6_addresses(num); |
362 |
1/2✓ Branch 2 taken 3794 times.
✗ Branch 3 not taken.
|
3794 | vector<Failures> failures(num); |
363 |
1/2✓ Branch 2 taken 3794 times.
✗ Branch 3 not taken.
|
3794 | vector<unsigned> ttls(num); |
364 |
1/2✓ Branch 2 taken 3794 times.
✗ Branch 3 not taken.
|
3794 | vector<string> fqdns(num); |
365 |
1/2✓ Branch 2 taken 3794 times.
✗ Branch 3 not taken.
|
3794 | vector<bool> skip(num); |
366 | |||
367 | // Deal with special names: empty, IPv4, IPv6 | ||
368 |
2/2✓ Branch 0 taken 4948 times.
✓ Branch 1 taken 3794 times.
|
8742 | for (unsigned i = 0; i < num; ++i) { |
369 |
2/2✓ Branch 2 taken 834 times.
✓ Branch 3 taken 4114 times.
|
4948 | if (names[i].empty()) { |
370 |
1/2✓ Branch 1 taken 834 times.
✗ Branch 2 not taken.
|
834 | LogCvmfs(kLogDns, kLogDebug, "empty hostname"); |
371 | 834 | Host invalid_host; | |
372 |
1/2✓ Branch 1 taken 834 times.
✗ Branch 2 not taken.
|
834 | invalid_host.name_ = ""; |
373 | 834 | invalid_host.status_ = kFailInvalidHost; | |
374 |
1/2✓ Branch 1 taken 834 times.
✗ Branch 2 not taken.
|
834 | hosts->push_back(invalid_host); |
375 |
1/2✓ Branch 1 taken 834 times.
✗ Branch 2 not taken.
|
834 | skip[i] = true; |
376 |
3/4✓ Branch 3 taken 4114 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 296 times.
✓ Branch 6 taken 3818 times.
|
4948 | } else if (IsIpv4Address(names[i])) { |
377 |
1/2✓ Branch 3 taken 296 times.
✗ Branch 4 not taken.
|
296 | LogCvmfs(kLogDns, kLogDebug, "IPv4 address %s", names[i].c_str()); |
378 | 296 | Host ipv4_host; | |
379 |
1/2✓ Branch 2 taken 296 times.
✗ Branch 3 not taken.
|
296 | ipv4_host.name_ = names[i]; |
380 | 296 | ipv4_host.status_ = kFailOk; | |
381 |
1/2✓ Branch 2 taken 296 times.
✗ Branch 3 not taken.
|
296 | ipv4_host.ipv4_addresses_.insert(names[i]); |
382 | 296 | ipv4_host.deadline_ = time(NULL) + max_ttl_; | |
383 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | hosts->push_back(ipv4_host); |
384 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | skip[i] = true; |
385 |
2/2✓ Branch 5 taken 184 times.
✓ Branch 6 taken 3404 times.
|
7702 | } else if ((names[i].length() >= 3) && (names[i][0] == '[') |
386 |
5/6✓ Branch 0 taken 3588 times.
✓ Branch 1 taken 230 times.
✓ Branch 6 taken 184 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 184 times.
✓ Branch 9 taken 3634 times.
|
7406 | && (names[i][names[i].length() - 1] == ']')) { |
387 |
1/2✓ Branch 3 taken 184 times.
✗ Branch 4 not taken.
|
184 | LogCvmfs(kLogDns, kLogDebug, "IPv6 address %s", names[i].c_str()); |
388 | 184 | Host ipv6_host; | |
389 |
1/2✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
184 | ipv6_host.name_ = names[i]; |
390 | 184 | ipv6_host.status_ = kFailOk; | |
391 |
1/2✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
184 | ipv6_host.ipv6_addresses_.insert(names[i]); |
392 | 184 | ipv6_host.deadline_ = time(NULL) + max_ttl_; | |
393 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | hosts->push_back(ipv6_host); |
394 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | skip[i] = true; |
395 | 184 | } else { | |
396 |
1/2✓ Branch 2 taken 3634 times.
✗ Branch 3 not taken.
|
3634 | hosts->push_back(Host()); |
397 |
1/2✓ Branch 1 taken 3634 times.
✗ Branch 2 not taken.
|
3634 | skip[i] = false; |
398 | } | ||
399 | } | ||
400 | |||
401 |
1/2✓ Branch 1 taken 3794 times.
✗ Branch 2 not taken.
|
3794 | DoResolve(names, skip, &ipv4_addresses, &ipv6_addresses, &failures, &ttls, |
402 | &fqdns); | ||
403 | |||
404 | // Construct host objects | ||
405 |
2/2✓ Branch 0 taken 4948 times.
✓ Branch 1 taken 3794 times.
|
8742 | for (unsigned i = 0; i < num; ++i) { |
406 |
3/5✓ Branch 1 taken 4948 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1314 times.
✓ Branch 5 taken 3634 times.
|
4948 | if (skip[i]) |
407 | 2050 | continue; | |
408 | |||
409 | 3634 | Host host; | |
410 |
1/2✓ Branch 2 taken 3634 times.
✗ Branch 3 not taken.
|
3634 | host.name_ = fqdns[i]; |
411 | 3634 | host.status_ = failures[i]; | |
412 | |||
413 | 3634 | unsigned effective_ttl = ttls[i]; | |
414 |
2/2✓ Branch 0 taken 782 times.
✓ Branch 1 taken 2852 times.
|
3634 | if (effective_ttl < min_ttl_) { |
415 | 782 | effective_ttl = min_ttl_; | |
416 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 2760 times.
|
2852 | } else if (effective_ttl > max_ttl_) { |
417 | 92 | effective_ttl = max_ttl_; | |
418 | } | ||
419 | 3634 | host.deadline_ = time(NULL) + effective_ttl; | |
420 | |||
421 |
2/2✓ Branch 0 taken 736 times.
✓ Branch 1 taken 2898 times.
|
3634 | if (host.status_ != kFailOk) { |
422 |
1/2✓ Branch 3 taken 736 times.
✗ Branch 4 not taken.
|
1472 | LogCvmfs(kLogDns, kLogDebug, "failed to resolve %s - %d (%s), ttl %u", |
423 | 736 | names[i].c_str(), host.status_, Code2Ascii(host.status_), | |
424 | effective_ttl); | ||
425 |
1/2✓ Branch 2 taken 736 times.
✗ Branch 3 not taken.
|
736 | (*hosts)[i] = host; |
426 | 736 | continue; | |
427 | } | ||
428 | |||
429 | // Verify addresses and make them readily available for curl | ||
430 |
2/2✓ Branch 2 taken 3266 times.
✓ Branch 3 taken 2898 times.
|
6164 | for (unsigned j = 0; j < ipv4_addresses[i].size(); ++j) { |
431 |
3/4✓ Branch 3 taken 3266 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 184 times.
✓ Branch 6 taken 3082 times.
|
3266 | if (!IsIpv4Address(ipv4_addresses[i][j])) { |
432 |
1/4✓ Branch 3 taken 184 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
368 | LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, |
433 | "host name %s resolves to invalid IPv4 address %s", | ||
434 | 368 | names[i].c_str(), ipv4_addresses[i][j].c_str()); | |
435 | 184 | continue; | |
436 | } | ||
437 |
2/2✓ Branch 2 taken 2806 times.
✓ Branch 3 taken 276 times.
|
3082 | if (names[i] == host.name_) { |
438 |
1/2✓ Branch 4 taken 2806 times.
✗ Branch 5 not taken.
|
2806 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s", names[i].c_str(), |
439 | 2806 | ipv4_addresses[i][j].c_str()); | |
440 | } else { | ||
441 |
1/2✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
|
552 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s -> %s", |
442 | 276 | names[i].c_str(), host.name_.c_str(), | |
443 | 276 | ipv4_addresses[i][j].c_str()); | |
444 | } | ||
445 |
1/2✓ Branch 3 taken 3082 times.
✗ Branch 4 not taken.
|
3082 | host.ipv4_addresses_.insert(ipv4_addresses[i][j]); |
446 | } | ||
447 | |||
448 |
2/2✓ Branch 2 taken 2024 times.
✓ Branch 3 taken 2898 times.
|
4922 | for (unsigned j = 0; j < ipv6_addresses[i].size(); ++j) { |
449 |
3/4✓ Branch 3 taken 2024 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 92 times.
✓ Branch 6 taken 1932 times.
|
2024 | if (!IsIpv6Address(ipv6_addresses[i][j])) { |
450 |
1/4✓ Branch 3 taken 92 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
184 | LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, |
451 | "host name %s resolves to invalid IPv6 address %s", | ||
452 | 184 | names[i].c_str(), ipv6_addresses[i][j].c_str()); | |
453 | 92 | continue; | |
454 | } | ||
455 | // For URLs we need brackets around IPv6 addresses | ||
456 |
2/2✓ Branch 2 taken 1794 times.
✓ Branch 3 taken 138 times.
|
1932 | if (names[i] == host.name_) { |
457 |
1/2✓ Branch 4 taken 1794 times.
✗ Branch 5 not taken.
|
1794 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s", names[i].c_str(), |
458 | 1794 | ipv6_addresses[i][j].c_str()); | |
459 | } else { | ||
460 |
1/2✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
|
276 | LogCvmfs(kLogDns, kLogDebug, "add address %s -> %s -> %s", |
461 | 138 | names[i].c_str(), host.name_.c_str(), | |
462 | 138 | ipv6_addresses[i][j].c_str()); | |
463 | } | ||
464 |
3/6✓ Branch 3 taken 1932 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1932 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1932 times.
✗ Branch 10 not taken.
|
1932 | host.ipv6_addresses_.insert("[" + ipv6_addresses[i][j] + "]"); |
465 | } | ||
466 | |||
467 |
6/6✓ Branch 1 taken 230 times.
✓ Branch 2 taken 2668 times.
✓ Branch 4 taken 138 times.
✓ Branch 5 taken 92 times.
✓ Branch 6 taken 138 times.
✓ Branch 7 taken 2760 times.
|
2898 | if (host.ipv4_addresses_.empty() && host.ipv6_addresses_.empty()) { |
468 |
1/2✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
|
138 | LogCvmfs(kLogDns, kLogDebug, "no addresses returned for %s", |
469 | 138 | names[i].c_str()); | |
470 | 138 | host.status_ = kFailNoAddress; | |
471 | } | ||
472 | |||
473 | // Remove surplus IP addresses | ||
474 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 2852 times.
|
2898 | if (throttle_ > 0) { |
475 |
2/2✓ Branch 1 taken 92 times.
✓ Branch 2 taken 46 times.
|
138 | while (host.ipv4_addresses_.size() > throttle_) { |
476 | 92 | const unsigned random = prng_.Next(host.ipv4_addresses_.size()); | |
477 | 92 | set<string>::iterator rnd_itr = host.ipv4_addresses_.begin(); | |
478 |
1/2✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
92 | std::advance(rnd_itr, random); |
479 |
1/2✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
92 | host.ipv4_addresses_.erase(rnd_itr); |
480 | } | ||
481 |
2/2✓ Branch 1 taken 92 times.
✓ Branch 2 taken 46 times.
|
138 | while (host.ipv6_addresses_.size() > throttle_) { |
482 | 92 | const unsigned random = prng_.Next(host.ipv6_addresses_.size()); | |
483 | 92 | set<string>::iterator rnd_itr = host.ipv6_addresses_.begin(); | |
484 |
1/2✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
92 | std::advance(rnd_itr, random); |
485 |
1/2✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
92 | host.ipv6_addresses_.erase(rnd_itr); |
486 | } | ||
487 | } | ||
488 | |||
489 |
1/2✓ Branch 2 taken 2898 times.
✗ Branch 3 not taken.
|
2898 | (*hosts)[i] = host; |
490 |
2/2✓ Branch 1 taken 2898 times.
✓ Branch 2 taken 736 times.
|
3634 | } |
491 | 3794 | } | |
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 | 2806 | QueryInfo(vector<string> *a, const string &n, const ResourceRecord r) | |
512 | 2806 | : addresses(a) | |
513 | 2806 | , complete(false) | |
514 | 2806 | , fqdn(n) | |
515 |
1/2✓ Branch 1 taken 2806 times.
✗ Branch 2 not taken.
|
2806 | , name(n) |
516 | 2806 | , record(r) | |
517 | 2806 | , status(kFailOther) | |
518 | 2806 | , 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 | 2806 | static void CallbackCares(void *arg, int status, int timeouts_ms, | |
544 | unsigned char *abuf, int alen) { | ||
545 | 2806 | QueryInfo *info = reinterpret_cast<QueryInfo *>(arg); | |
546 | |||
547 | 2806 | info->complete = true; | |
548 |
5/7✓ Branch 0 taken 2208 times.
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 368 times.
✓ Branch 4 taken 138 times.
✓ Branch 5 taken 46 times.
✗ Branch 6 not taken.
|
2806 | switch (status) { |
549 | 2208 | case ARES_SUCCESS: | |
550 | Failures retval; | ||
551 |
2/3✓ Branch 0 taken 1150 times.
✓ Branch 1 taken 1058 times.
✗ Branch 2 not taken.
|
2208 | switch (info->record) { |
552 | 1150 | case kRrA: | |
553 | 1150 | retval = CaresExtractIpv4(abuf, alen, info->addresses, &info->ttl, | |
554 | &info->fqdn); | ||
555 | 1150 | break; | |
556 | 1058 | case kRrAaaa: | |
557 | 1058 | retval = CaresExtractIpv6(abuf, alen, info->addresses, &info->ttl, | |
558 | &info->fqdn); | ||
559 | 1058 | break; | |
560 | ✗ | default: | |
561 | // Never here. | ||
562 | ✗ | PANIC(NULL); | |
563 | } | ||
564 | 2208 | info->status = retval; | |
565 | 2208 | break; | |
566 | 46 | case ARES_ENODATA: | |
567 | 46 | info->status = kFailUnknownHost; | |
568 | 46 | break; | |
569 | ✗ | case ARES_EFORMERR: | |
570 | ✗ | info->status = kFailMalformed; | |
571 | ✗ | break; | |
572 | 368 | case ARES_ENOTFOUND: | |
573 | 368 | info->status = kFailUnknownHost; | |
574 | 368 | break; | |
575 | 138 | case ARES_ETIMEOUT: | |
576 | 138 | info->status = kFailTimeout; | |
577 | 138 | break; | |
578 | 46 | case ARES_ECONNREFUSED: | |
579 | 46 | info->status = kFailInvalidResolvers; | |
580 | 46 | break; | |
581 | ✗ | default: | |
582 | ✗ | info->status = kFailOther; | |
583 | } | ||
584 | 2806 | } | |
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 | 1150 | static Failures CaresExtractIpv4(const unsigned char *abuf, | |
592 | int alen, | ||
593 | vector<string> *addresses, | ||
594 | unsigned *ttl, | ||
595 | string *fqdn) { | ||
596 | 1150 | struct hostent *host_entry = NULL; | |
597 | struct ares_addrttl records[CaresResolver::kMaxAddresses]; | ||
598 | 1150 | int naddrttls = CaresResolver::kMaxAddresses; | |
599 |
1/2✓ Branch 1 taken 1150 times.
✗ Branch 2 not taken.
|
1150 | const int retval = ares_parse_a_reply(abuf, alen, &host_entry, records, |
600 | &naddrttls); | ||
601 | |||
602 |
1/3✓ Branch 0 taken 1150 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1150 | switch (retval) { |
603 | 1150 | case ARES_SUCCESS: | |
604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1150 times.
|
1150 | if (host_entry == NULL) |
605 | ✗ | return kFailMalformed; | |
606 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1150 times.
|
1150 | if (host_entry->h_name == NULL) { |
607 | ✗ | ares_free_hostent(host_entry); | |
608 | ✗ | return kFailMalformed; | |
609 | } | ||
610 |
1/2✓ Branch 2 taken 1150 times.
✗ Branch 3 not taken.
|
1150 | *fqdn = string(host_entry->h_name); |
611 |
1/2✓ Branch 1 taken 1150 times.
✗ Branch 2 not taken.
|
1150 | ares_free_hostent(host_entry); |
612 | |||
613 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1150 times.
|
1150 | if (naddrttls <= 0) |
614 | ✗ | return kFailMalformed; | |
615 | 1150 | *ttl = unsigned(-1); | |
616 |
2/2✓ Branch 0 taken 1150 times.
✓ Branch 1 taken 1150 times.
|
2300 | for (unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) { |
617 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1150 times.
|
1150 | if (records[i].ttl < 0) |
618 | ✗ | continue; | |
619 | 1150 | *ttl = std::min(unsigned(records[i].ttl), *ttl); | |
620 | |||
621 | char addrstr[INET_ADDRSTRLEN]; | ||
622 | 1150 | 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 1150 times.
|
1150 | if (!retval_p) |
625 | ✗ | continue; | |
626 |
2/4✓ Branch 2 taken 1150 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1150 times.
✗ Branch 6 not taken.
|
1150 | addresses->push_back(addrstr); |
627 | } | ||
628 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1150 times.
|
1150 | if (addresses->empty()) |
629 | ✗ | return kFailMalformed; | |
630 | 1150 | 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 | 1058 | static Failures CaresExtractIpv6(const unsigned char *abuf, | |
642 | int alen, | ||
643 | vector<string> *addresses, | ||
644 | unsigned *ttl, | ||
645 | string *fqdn) { | ||
646 | 1058 | struct hostent *host_entry = NULL; | |
647 | struct ares_addr6ttl records[CaresResolver::kMaxAddresses]; | ||
648 | 1058 | int naddrttls = CaresResolver::kMaxAddresses; | |
649 |
1/2✓ Branch 1 taken 1058 times.
✗ Branch 2 not taken.
|
1058 | const int retval = ares_parse_aaaa_reply(abuf, alen, &host_entry, records, |
650 | &naddrttls); | ||
651 | |||
652 |
1/3✓ Branch 0 taken 1058 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1058 | switch (retval) { |
653 | 1058 | case ARES_SUCCESS: | |
654 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1058 times.
|
1058 | if (host_entry == NULL) |
655 | ✗ | return kFailMalformed; | |
656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1058 times.
|
1058 | if (host_entry->h_name == NULL) { |
657 | ✗ | ares_free_hostent(host_entry); | |
658 | ✗ | return kFailMalformed; | |
659 | } | ||
660 |
1/2✓ Branch 2 taken 1058 times.
✗ Branch 3 not taken.
|
1058 | *fqdn = string(host_entry->h_name); |
661 |
1/2✓ Branch 1 taken 1058 times.
✗ Branch 2 not taken.
|
1058 | ares_free_hostent(host_entry); |
662 | |||
663 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1058 times.
|
1058 | if (naddrttls <= 0) |
664 | ✗ | return kFailMalformed; | |
665 | 1058 | *ttl = unsigned(-1); | |
666 |
2/2✓ Branch 0 taken 1058 times.
✓ Branch 1 taken 1058 times.
|
2116 | for (unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) { |
667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1058 times.
|
1058 | if (records[i].ttl < 0) |
668 | ✗ | continue; | |
669 | 1058 | *ttl = std::min(unsigned(records[i].ttl), *ttl); | |
670 | |||
671 | char addrstr[INET6_ADDRSTRLEN]; | ||
672 | 1058 | 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 1058 times.
|
1058 | if (!retval_p) |
675 | ✗ | continue; | |
676 |
2/4✓ Branch 2 taken 1058 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1058 times.
✗ Branch 6 not taken.
|
1058 | addresses->push_back(addrstr); |
677 | } | ||
678 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1058 times.
|
1058 | if (addresses->empty()) |
679 | ✗ | return kFailMalformed; | |
680 | 1058 | 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 | 6740 | CaresResolver::CaresResolver(const bool ipv4_only, | |
692 | const unsigned retries, | ||
693 | 6740 | const unsigned timeout_ms) | |
694 | : Resolver(ipv4_only, retries, timeout_ms) | ||
695 | 6740 | , channel_(NULL) | |
696 | 6740 | , lookup_options_(strdup("b")) { } | |
697 | |||
698 | |||
699 | 26716 | CaresResolver::~CaresResolver() { | |
700 |
1/2✓ Branch 0 taken 6679 times.
✗ Branch 1 not taken.
|
13358 | if (channel_) { |
701 | 13358 | ares_destroy(*channel_); | |
702 | 13358 | free(channel_); | |
703 | } | ||
704 | 13358 | free(lookup_options_); | |
705 | 26716 | } | |
706 | |||
707 | |||
708 | /** | ||
709 | * Returns a CaresResolver readily initialized, or NULL if an error occurs. | ||
710 | */ | ||
711 | 6740 | 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 6691 times.
|
6740 | 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 6740 times.
✗ Branch 2 not taken.
|
6740 | CaresResolver *resolver = new CaresResolver(ipv4_only, retries, timeout_ms); |
721 | 6740 | resolver->channel_ = reinterpret_cast<ares_channel *>( | |
722 | 6740 | smalloc(sizeof(ares_channel))); | |
723 | 6740 | 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 | 6740 | memset(&options, 0, sizeof(options)); | |
730 | 6740 | options.timeout = timeout_ms; | |
731 | 6740 | options.tries = 1 + retries; | |
732 | 6740 | options.lookups = resolver->lookup_options_; | |
733 | 6740 | optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_LOOKUPS; | |
734 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | retval = ares_init_options(resolver->channel_, &options, optmask); |
735 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6740 times.
|
6740 | if (retval != ARES_SUCCESS) |
736 | ✗ | goto create_fail; | |
737 | |||
738 | // Save search domains | ||
739 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | retval = ares_save_options(*resolver->channel_, &options, &optmask); |
740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6740 times.
|
6740 | if (retval != ARES_SUCCESS) |
741 | ✗ | goto create_fail; | |
742 |
2/2✓ Branch 0 taken 6740 times.
✓ Branch 1 taken 6740 times.
|
13480 | for (int i = 0; i < options.ndomains; ++i) { |
743 |
2/4✓ Branch 2 taken 6740 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6740 times.
✗ Branch 6 not taken.
|
6740 | resolver->domains_.push_back(options.domains[i]); |
744 | } | ||
745 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | ares_destroy_options(&options); |
746 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | resolver->system_domains_ = resolver->domains_; |
747 | |||
748 | // Save the system default resolvers | ||
749 | 6740 | addresses = NULL; | |
750 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | retval = ares_get_servers(*resolver->channel_, &addresses); |
751 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6740 times.
|
6740 | if (retval != ARES_SUCCESS) |
752 | ✗ | goto create_fail; | |
753 | 6740 | iter = addresses; | |
754 |
2/2✓ Branch 0 taken 33700 times.
✓ Branch 1 taken 6740 times.
|
40440 | while (iter) { |
755 |
2/3✓ Branch 0 taken 20220 times.
✓ Branch 1 taken 13480 times.
✗ Branch 2 not taken.
|
33700 | switch (iter->family) { |
756 | 20220 | case AF_INET: { | |
757 | char addrstr[INET_ADDRSTRLEN]; | ||
758 | 20220 | const void *retval_p = inet_ntop(AF_INET, &(iter->addr), addrstr, | |
759 | INET_ADDRSTRLEN); | ||
760 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20220 times.
|
20220 | if (!retval_p) { |
761 | ✗ | LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr, | |
762 | "invalid system name resolver"); | ||
763 | } else { | ||
764 |
3/6✓ Branch 2 taken 20220 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20220 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20220 times.
✗ Branch 9 not taken.
|
20220 | resolver->resolvers_.push_back(string(addrstr) + ":53"); |
765 | } | ||
766 | 20220 | break; | |
767 | } | ||
768 | 13480 | case AF_INET6: { | |
769 | char addrstr[INET6_ADDRSTRLEN]; | ||
770 | 13480 | const void *retval_p = inet_ntop(AF_INET6, &(iter->addr), addrstr, | |
771 | INET6_ADDRSTRLEN); | ||
772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13480 times.
|
13480 | if (!retval_p) { |
773 | ✗ | LogCvmfs(kLogDns, kLogDebug | kLogSyslogErr, | |
774 | "invalid system name resolver"); | ||
775 | } else { | ||
776 |
4/8✓ Branch 2 taken 13480 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13480 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13480 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 13480 times.
✗ Branch 12 not taken.
|
13480 | resolver->resolvers_.push_back("[" + string(addrstr) + "]:53"); |
777 | } | ||
778 | 13480 | break; | |
779 | } | ||
780 | ✗ | default: | |
781 | // Never here. | ||
782 | ✗ | PANIC(NULL); | |
783 | } | ||
784 | 33700 | iter = iter->next; | |
785 | } | ||
786 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | ares_free_data(addresses); |
787 |
1/2✓ Branch 1 taken 6740 times.
✗ Branch 2 not taken.
|
6740 | resolver->system_resolvers_ = resolver->resolvers_; |
788 | |||
789 | 6740 | 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 | 1632 | 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 | 1632 | const unsigned num = names.size(); | |
814 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1632 times.
|
1632 | if (num == 0) |
815 | ✗ | return; | |
816 | |||
817 |
1/2✓ Branch 2 taken 1632 times.
✗ Branch 3 not taken.
|
1632 | vector<QueryInfo *> infos_ipv4(num, NULL); |
818 |
1/2✓ Branch 2 taken 1632 times.
✗ Branch 3 not taken.
|
1632 | vector<QueryInfo *> infos_ipv6(num, NULL); |
819 | |||
820 |
2/2✓ Branch 0 taken 2510 times.
✓ Branch 1 taken 1632 times.
|
4142 | for (unsigned i = 0; i < num; ++i) { |
821 |
3/4✓ Branch 1 taken 2510 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1084 times.
✓ Branch 4 taken 1426 times.
|
2510 | if (skip[i]) |
822 | 1084 | continue; | |
823 | |||
824 |
2/2✓ Branch 1 taken 1380 times.
✓ Branch 2 taken 46 times.
|
1426 | if (!ipv4_only()) { |
825 |
2/4✓ Branch 3 taken 1380 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1380 times.
✗ Branch 7 not taken.
|
1380 | infos_ipv6[i] = new QueryInfo(&(*ipv6_addresses)[i], names[i], kRrAaaa); |
826 |
1/2✓ Branch 3 taken 1380 times.
✗ Branch 4 not taken.
|
1380 | ares_search(*channel_, names[i].c_str(), ns_c_in, ns_t_aaaa, |
827 | 1380 | CallbackCares, infos_ipv6[i]); | |
828 | } | ||
829 |
2/4✓ Branch 3 taken 1426 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1426 times.
✗ Branch 7 not taken.
|
1426 | infos_ipv4[i] = new QueryInfo(&(*ipv4_addresses)[i], names[i], kRrA); |
830 |
1/2✓ Branch 3 taken 1426 times.
✗ Branch 4 not taken.
|
1426 | ares_search(*channel_, names[i].c_str(), ns_c_in, ns_t_a, CallbackCares, |
831 | 1426 | infos_ipv4[i]); | |
832 | } | ||
833 | |||
834 | bool all_complete; | ||
835 | do { | ||
836 | 79967112 | all_complete = true; | |
837 |
1/2✓ Branch 1 taken 79967112 times.
✗ Branch 2 not taken.
|
79967112 | WaitOnCares(); |
838 |
2/2✓ Branch 0 taken 79975902 times.
✓ Branch 1 taken 1632 times.
|
79977534 | for (unsigned i = 0; i < num; ++i) { |
839 |
2/2✓ Branch 2 taken 9200 times.
✓ Branch 3 taken 79965066 times.
|
159950168 | if ((infos_ipv4[i] && !infos_ipv4[i]->complete) |
840 |
8/8✓ Branch 0 taken 79974266 times.
✓ Branch 1 taken 1636 times.
✓ Branch 3 taken 9154 times.
✓ Branch 4 taken 1682 times.
✓ Branch 6 taken 414 times.
✓ Branch 7 taken 8740 times.
✓ Branch 8 taken 79965480 times.
✓ Branch 9 taken 10422 times.
|
159950168 | || (infos_ipv6[i] && !infos_ipv6[i]->complete)) { |
841 | 79965480 | all_complete = false; | |
842 | 79965480 | break; | |
843 | } | ||
844 | } | ||
845 |
2/2✓ Branch 0 taken 79965480 times.
✓ Branch 1 taken 1632 times.
|
79967112 | } 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 2510 times.
✓ Branch 1 taken 1632 times.
|
4142 | for (unsigned i = 0; i < num; ++i) { |
850 |
3/4✓ Branch 1 taken 2510 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1084 times.
✓ Branch 4 taken 1426 times.
|
2510 | if (skip[i]) |
851 | 1084 | continue; | |
852 | |||
853 | 1426 | Failures status = kFailOther; | |
854 | 1426 | (*ttls)[i] = unsigned(-1); | |
855 |
1/2✓ Branch 2 taken 1426 times.
✗ Branch 3 not taken.
|
1426 | (*fqdns)[i] = ""; |
856 |
2/2✓ Branch 1 taken 1380 times.
✓ Branch 2 taken 46 times.
|
1426 | if (infos_ipv6[i]) { |
857 | 1380 | status = infos_ipv6[i]->status; | |
858 |
2/2✓ Branch 0 taken 1058 times.
✓ Branch 1 taken 322 times.
|
1380 | if (status == kFailOk) { |
859 | 1058 | (*ttls)[i] = std::min(infos_ipv6[i]->ttl, (*ttls)[i]); | |
860 |
1/2✓ Branch 3 taken 1058 times.
✗ Branch 4 not taken.
|
1058 | (*fqdns)[i] = infos_ipv6[i]->fqdn; |
861 | } | ||
862 | } | ||
863 |
1/2✓ Branch 1 taken 1426 times.
✗ Branch 2 not taken.
|
1426 | if (infos_ipv4[i]) { |
864 | 1426 | (*ttls)[i] = std::min(infos_ipv4[i]->ttl, (*ttls)[i]); | |
865 |
2/2✓ Branch 2 taken 368 times.
✓ Branch 3 taken 1058 times.
|
1426 | if ((*fqdns)[i] == "") |
866 |
1/2✓ Branch 3 taken 368 times.
✗ Branch 4 not taken.
|
368 | (*fqdns)[i] = infos_ipv4[i]->fqdn; |
867 |
2/2✓ Branch 0 taken 368 times.
✓ Branch 1 taken 1058 times.
|
1426 | if (status != kFailOk) |
868 | 368 | status = infos_ipv4[i]->status; | |
869 | } | ||
870 | 1426 | (*failures)[i] = status; | |
871 | } | ||
872 | |||
873 |
2/2✓ Branch 0 taken 2510 times.
✓ Branch 1 taken 1632 times.
|
4142 | for (unsigned i = 0; i < num; ++i) { |
874 |
2/2✓ Branch 1 taken 1426 times.
✓ Branch 2 taken 1084 times.
|
2510 | delete infos_ipv4[i]; |
875 |
2/2✓ Branch 1 taken 1380 times.
✓ Branch 2 taken 1130 times.
|
2510 | delete infos_ipv6[i]; |
876 | } | ||
877 | 1632 | } | |
878 | |||
879 | |||
880 | 138 | bool CaresResolver::SetResolvers(const vector<string> &resolvers) { | |
881 |
2/4✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 138 times.
✗ Branch 6 not taken.
|
276 | const string address_list = JoinStrings(resolvers, ","); |
882 |
1/2✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
|
138 | const int retval = ares_set_servers_csv(*channel_, address_list.c_str()); |
883 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 138 times.
|
138 | if (retval != ARES_SUCCESS) |
884 | ✗ | return false; | |
885 | |||
886 |
1/2✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
|
138 | resolvers_ = resolvers; |
887 | 138 | return true; | |
888 | 138 | } | |
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 | 92 | 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 | 92 | memcpy(&ares_channelhead, *channel_, sizeof(ares_channelhead)); | |
914 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | if (ares_channelhead.domains) { |
915 |
2/2✓ Branch 0 taken 138 times.
✓ Branch 1 taken 92 times.
|
230 | for (int i = 0; i < ares_channelhead.ndomains; ++i) { |
916 | 138 | free(ares_channelhead.domains[i]); | |
917 | } | ||
918 | 92 | free(ares_channelhead.domains); | |
919 | 92 | ares_channelhead.domains = NULL; | |
920 | } | ||
921 | |||
922 | 92 | ares_channelhead.ndomains = static_cast<int>(domains.size()); | |
923 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
|
92 | if (ares_channelhead.ndomains > 0) { |
924 | 46 | ares_channelhead.domains = reinterpret_cast<char **>( | |
925 | 46 | smalloc(ares_channelhead.ndomains * sizeof(char *))); | |
926 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 46 times.
|
138 | for (int i = 0; i < ares_channelhead.ndomains; ++i) { |
927 | 92 | ares_channelhead.domains[i] = strdup(domains[i].c_str()); | |
928 | } | ||
929 | } | ||
930 | |||
931 | 92 | memcpy(*channel_, &ares_channelhead, sizeof(ares_channelhead)); | |
932 | |||
933 |
1/2✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
|
92 | domains_ = domains; |
934 | 92 | 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 | 79967112 | 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 79967112 times.
✗ Branch 2 not taken.
|
79967112 | const int bitmask = ares_getsock(*channel_, socks, ARES_GETSOCK_MAXNUM); |
959 | 79967112 | unsigned num = 0; | |
960 |
1/2✓ Branch 0 taken 159933282 times.
✗ Branch 1 not taken.
|
159933282 | for (unsigned i = 0; i < ARES_GETSOCK_MAXNUM; ++i) { |
961 | 159933282 | pfd[i].events = 0; | |
962 | 159933282 | pfd[i].revents = 0; | |
963 |
2/2✓ Branch 0 taken 79966170 times.
✓ Branch 1 taken 79967112 times.
|
159933282 | if (ARES_GETSOCK_READABLE(bitmask, i)) { |
964 | 79966170 | pfd[i].fd = socks[i]; | |
965 | 79966170 | pfd[i].events |= POLLRDNORM | POLLIN; | |
966 | } | ||
967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 159933282 times.
|
159933282 | 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 79966170 times.
✓ Branch 1 taken 79967112 times.
|
159933282 | if (pfd[i].events != 0) |
972 | 79966170 | num++; | |
973 | else | ||
974 | 79967112 | break; | |
975 | } | ||
976 | |||
977 | 79967112 | int nfds = 0; | |
978 |
2/2✓ Branch 0 taken 79966170 times.
✓ Branch 1 taken 942 times.
|
79967112 | if (num > 0) { |
979 | do { | ||
980 |
1/2✓ Branch 2 taken 79966170 times.
✗ Branch 3 not taken.
|
79966170 | nfds = poll(pfd, num, timeout_ms()); |
981 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79966170 times.
|
79966170 | 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 79966170 times.
|
79966170 | } while (nfds == -1); |
987 | } | ||
988 | |||
989 |
2/2✓ Branch 0 taken 1218 times.
✓ Branch 1 taken 79965894 times.
|
79967112 | 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 1218 times.
✗ Branch 2 not taken.
|
1218 | 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 79965894 times.
✓ Branch 1 taken 79965894 times.
|
159931788 | for (unsigned i = 0; i < num; ++i) { |
996 | 159931788 | ares_process_fd( | |
997 |
1/2✓ Branch 1 taken 79965894 times.
✗ Branch 2 not taken.
|
79965894 | *channel_, |
998 |
2/2✓ Branch 0 taken 2852 times.
✓ Branch 1 taken 79963042 times.
|
79965894 | pfd[i].revents & (POLLRDNORM | POLLIN) ? pfd[i].fd : ARES_SOCKET_BAD, |
999 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 79965894 times.
|
79965894 | pfd[i].revents & (POLLWRNORM | POLLOUT) ? pfd[i].fd |
1000 | : ARES_SOCKET_BAD); | ||
1001 | } | ||
1002 | } | ||
1003 | 79967112 | } | |
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 | 4748 | HostfileResolver *HostfileResolver::Create(const string &path, bool ipv4_only) { | |
1015 |
1/2✓ Branch 1 taken 4748 times.
✗ Branch 2 not taken.
|
4748 | HostfileResolver *resolver = new HostfileResolver(ipv4_only); |
1016 | |||
1017 |
1/2✓ Branch 1 taken 4748 times.
✗ Branch 2 not taken.
|
4748 | string hosts_file = path; |
1018 |
2/2✓ Branch 1 taken 2632 times.
✓ Branch 2 taken 2116 times.
|
4748 | if (hosts_file == "") { |
1019 | 2632 | char *hosts_env = getenv("HOST_ALIASES"); | |
1020 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 2540 times.
|
2632 | if (hosts_env != NULL) { |
1021 |
1/2✓ Branch 2 taken 92 times.
✗ Branch 3 not taken.
|
92 | hosts_file = string(hosts_env); |
1022 | } else { | ||
1023 |
1/2✓ Branch 1 taken 2540 times.
✗ Branch 2 not taken.
|
2540 | hosts_file = "/etc/hosts"; |
1024 | } | ||
1025 | } | ||
1026 |
1/2✓ Branch 2 taken 4748 times.
✗ Branch 3 not taken.
|
4748 | resolver->fhosts_ = fopen(hosts_file.c_str(), "r"); |
1027 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4656 times.
|
4748 | if (!resolver->fhosts_) { |
1028 |
1/2✓ Branch 2 taken 92 times.
✗ Branch 3 not taken.
|
92 | LogCvmfs(kLogDns, kLogDebug | kLogSyslogWarn, "failed to read host file %s", |
1029 | hosts_file.c_str()); | ||
1030 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | delete resolver; |
1031 | 92 | return NULL; | |
1032 | } | ||
1033 | 4656 | return resolver; | |
1034 | 4748 | } | |
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 | 276 | static bool SortNameLength(const string &a, const string &b) { | |
1043 | 276 | const unsigned len_a = a.length(); | |
1044 | 276 | const unsigned len_b = b.length(); | |
1045 |
1/2✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
|
276 | if (len_a != len_b) |
1046 | 276 | return len_a > len_b; | |
1047 | ✗ | return a > b; | |
1048 | } | ||
1049 | |||
1050 | |||
1051 | /** | ||
1052 | * Creates a fresh reverse lookup map | ||
1053 | */ | ||
1054 | 2318 | 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 | 2318 | const unsigned num = names.size(); | |
1062 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2318 times.
|
2318 | if (num == 0) |
1063 | ✗ | return; | |
1064 | |||
1065 | 2318 | ParseHostFile(); | |
1066 |
2/2✓ Branch 0 taken 2598 times.
✓ Branch 1 taken 2318 times.
|
4916 | for (unsigned i = 0; i < num; ++i) { |
1067 |
3/4✓ Branch 1 taken 2598 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 988 times.
✓ Branch 4 taken 1610 times.
|
2598 | if (skip[i]) |
1068 | 988 | continue; | |
1069 | |||
1070 | 1610 | vector<string> effective_names; | |
1071 |
5/6✓ Branch 2 taken 1610 times.
✗ Branch 3 not taken.
✓ Branch 8 taken 92 times.
✓ Branch 9 taken 1518 times.
✓ Branch 10 taken 92 times.
✓ Branch 11 taken 1518 times.
|
1610 | if (!names[i].empty() && (names[i][names[i].length() - 1] == '.')) { |
1072 |
2/4✓ Branch 4 taken 92 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 92 times.
✗ Branch 8 not taken.
|
92 | effective_names.push_back(names[i].substr(0, names[i].length() - 1)); |
1073 | } else { | ||
1074 |
1/2✓ Branch 2 taken 1518 times.
✗ Branch 3 not taken.
|
1518 | effective_names.push_back(names[i]); |
1075 |
2/2✓ Branch 2 taken 276 times.
✓ Branch 3 taken 1518 times.
|
1794 | for (unsigned j = 0; j < domains().size(); ++j) { |
1076 |
3/6✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 276 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 276 times.
✗ Branch 11 not taken.
|
276 | 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 1610 times.
✗ Branch 4 not taken.
|
1610 | std::sort(effective_names.begin(), effective_names.end(), SortNameLength); |
1082 | |||
1083 | 1610 | (*failures)[i] = kFailUnknownHost; | |
1084 |
1/2✓ Branch 3 taken 1610 times.
✗ Branch 4 not taken.
|
1610 | (*fqdns)[i] = names[i]; |
1085 |
2/2✓ Branch 1 taken 1748 times.
✓ Branch 2 taken 460 times.
|
2208 | for (unsigned j = 0; j < effective_names.size(); ++j) { |
1086 |
1/2✓ Branch 1 taken 1748 times.
✗ Branch 2 not taken.
|
1748 | const map<string, HostEntry>::iterator iter = host_map_.find( |
1087 | 1748 | effective_names[j]); | |
1088 |
2/2✓ Branch 2 taken 1150 times.
✓ Branch 3 taken 598 times.
|
1748 | if (iter != host_map_.end()) { |
1089 |
1/2✓ Branch 7 taken 1150 times.
✗ Branch 8 not taken.
|
3450 | (*ipv4_addresses)[i].insert((*ipv4_addresses)[i].end(), |
1090 | 1150 | iter->second.ipv4_addresses.begin(), | |
1091 | 1150 | iter->second.ipv4_addresses.end()); | |
1092 |
1/2✓ Branch 7 taken 1150 times.
✗ Branch 8 not taken.
|
3450 | (*ipv6_addresses)[i].insert((*ipv6_addresses)[i].end(), |
1093 | 1150 | iter->second.ipv6_addresses.begin(), | |
1094 | 1150 | iter->second.ipv6_addresses.end()); | |
1095 | 1150 | (*ttls)[i] = min_ttl_; | |
1096 |
1/2✓ Branch 3 taken 1150 times.
✗ Branch 4 not taken.
|
1150 | (*fqdns)[i] = effective_names[j]; |
1097 | 1150 | (*failures)[i] = kFailOk; | |
1098 | 1150 | break; | |
1099 | } // Host name found | ||
1100 | } // All possible names (search domains added) | ||
1101 | 1610 | } | |
1102 | } | ||
1103 | |||
1104 | |||
1105 | 4748 | HostfileResolver::HostfileResolver(const bool ipv4_only) | |
1106 | 4748 | : Resolver(ipv4_only, 0, 0), fhosts_(NULL) { } | |
1107 | |||
1108 | |||
1109 | 18988 | HostfileResolver::~HostfileResolver() { | |
1110 |
2/2✓ Branch 0 taken 4655 times.
✓ Branch 1 taken 92 times.
|
9494 | if (fhosts_) |
1111 | 9310 | fclose(fhosts_); | |
1112 | 18988 | } | |
1113 | |||
1114 | |||
1115 | /** | ||
1116 | * TODO: this should be only necessary when the modification timestamp changed. | ||
1117 | */ | ||
1118 | 2318 | void HostfileResolver::ParseHostFile() { | |
1119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2318 times.
|
2318 | assert(fhosts_); |
1120 |
1/2✓ Branch 1 taken 2318 times.
✗ Branch 2 not taken.
|
2318 | rewind(fhosts_); |
1121 | 2318 | host_map_.clear(); | |
1122 | |||
1123 | 2318 | string line; | |
1124 |
3/4✓ Branch 1 taken 9088 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6770 times.
✓ Branch 4 taken 2318 times.
|
9088 | while (GetLineFile(fhosts_, &line)) { |
1125 | char address[kIpMaxLength + 1]; | ||
1126 | char hostname[kHostnameMaxLength + 1]; | ||
1127 | int bytes_read; | ||
1128 | 6770 | size_t str_offset = 0; | |
1129 | |||
1130 | // strip comments | ||
1131 | 6770 | const size_t hash_pos = line.find_first_of('#'); | |
1132 |
2/2✓ Branch 0 taken 460 times.
✓ Branch 1 taken 6310 times.
|
6770 | if (hash_pos != string::npos) |
1133 |
1/2✓ Branch 1 taken 460 times.
✗ Branch 2 not taken.
|
460 | line = line.substr(0, hash_pos); |
1134 | |||
1135 | // First token is an IP address | ||
1136 | 6770 | int ip_start_pos = -1, ip_end_pos = -1, scan_result; | |
1137 | 6770 | scan_result = sscanf(line.c_str(), " %n%*s%n", &ip_start_pos, &ip_end_pos); | |
1138 |
2/2✓ Branch 0 taken 644 times.
✓ Branch 1 taken 6126 times.
|
6770 | if (scan_result == EOF) |
1139 | 736 | continue; | |
1140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6126 times.
|
6126 | assert(ip_start_pos != -1); |
1141 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6126 times.
|
6126 | assert(ip_end_pos != -1); |
1142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6126 times.
|
6126 | if (ip_start_pos == ip_end_pos) |
1143 | ✗ | continue; | |
1144 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 6034 times.
|
6126 | if (ip_end_pos - ip_start_pos > kIpMaxLength) { |
1145 |
1/2✓ Branch 2 taken 92 times.
✗ Branch 3 not taken.
|
92 | LogCvmfs( |
1146 | kLogDns, kLogSyslogWarn, | ||
1147 | "Skipping line in hosts file due to invalid IP address format: %s", | ||
1148 | line.c_str()); | ||
1149 | 92 | continue; | |
1150 | } | ||
1151 | |||
1152 | 6034 | bytes_read = -1; | |
1153 | 6034 | scan_result = sscanf(line.c_str(), " %s%n", address, &bytes_read); | |
1154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6034 times.
|
6034 | assert(scan_result == 1); |
1155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6034 times.
|
6034 | assert(bytes_read != -1); |
1156 | 6034 | str_offset += bytes_read; | |
1157 | |||
1158 | // Next tokens are hostnames and aliases (we treat them as equal) | ||
1159 |
2/2✓ Branch 1 taken 13842 times.
✓ Branch 2 taken 5712 times.
|
19554 | while (str_offset < line.length()) { |
1160 | // check hostname length | ||
1161 | 13842 | int hostname_start_pos = -1, hostname_end_pos = -1; | |
1162 | 13842 | scan_result = sscanf(line.c_str() + str_offset, " %n%*s%n", | |
1163 | &hostname_start_pos, &hostname_end_pos); | ||
1164 |
2/2✓ Branch 0 taken 322 times.
✓ Branch 1 taken 13520 times.
|
13842 | if (scan_result == EOF) |
1165 | 322 | break; | |
1166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13520 times.
|
13520 | assert(hostname_start_pos != -1); |
1167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13520 times.
|
13520 | assert(hostname_end_pos != -1); |
1168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13520 times.
|
13520 | if (hostname_start_pos == hostname_end_pos) |
1169 | ✗ | break; | |
1170 | |||
1171 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 13428 times.
|
13520 | if (hostname_end_pos - hostname_start_pos > kHostnameMaxLength) { |
1172 |
1/2✓ Branch 2 taken 92 times.
✗ Branch 3 not taken.
|
92 | LogCvmfs( |
1173 | kLogDns, kLogSyslogWarn, | ||
1174 | "Skipping invalid (too long) hostname in hosts file on line: %s", | ||
1175 | line.c_str()); | ||
1176 | 92 | str_offset += hostname_end_pos; | |
1177 | 92 | continue; | |
1178 | } | ||
1179 | |||
1180 | 13428 | bytes_read = -1; | |
1181 | 13428 | scan_result = sscanf(line.c_str() + str_offset, " %s%n", hostname, | |
1182 | &bytes_read); | ||
1183 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13428 times.
|
13428 | assert(scan_result == 1); |
1184 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13428 times.
|
13428 | assert(bytes_read != -1); |
1185 | 13428 | str_offset += bytes_read; | |
1186 | |||
1187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13428 times.
|
13428 | if (hostname[strlen(hostname) - 1] == '.') |
1188 | ✗ | hostname[strlen(hostname) - 1] = 0; // strip the last character | |
1189 | |||
1190 |
2/4✓ Branch 2 taken 13428 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13428 times.
✗ Branch 6 not taken.
|
13428 | const map<string, HostEntry>::iterator iter = host_map_.find(hostname); |
1191 |
2/2✓ Branch 2 taken 10954 times.
✓ Branch 3 taken 2474 times.
|
13428 | if (iter == host_map_.end()) { |
1192 | 10954 | HostEntry entry; | |
1193 |
4/6✓ Branch 2 taken 10954 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10954 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 8618 times.
✓ Branch 10 taken 2336 times.
|
10954 | if (IsIpv4Address(address)) |
1194 |
2/4✓ Branch 2 taken 8618 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8618 times.
✗ Branch 6 not taken.
|
8618 | entry.ipv4_addresses.push_back(address); |
1195 |
2/2✓ Branch 1 taken 2244 times.
✓ Branch 2 taken 92 times.
|
2336 | else if (!ipv4_only()) |
1196 |
2/4✓ Branch 2 taken 2244 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2244 times.
✗ Branch 6 not taken.
|
2244 | entry.ipv6_addresses.push_back(address); |
1197 |
3/6✓ Branch 2 taken 10954 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10954 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10954 times.
✗ Branch 9 not taken.
|
10954 | host_map_[hostname] = entry; |
1198 | 10954 | } else { | |
1199 |
4/6✓ Branch 2 taken 2474 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2474 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 138 times.
✓ Branch 10 taken 2336 times.
|
2474 | if (IsIpv4Address(address)) |
1200 |
2/4✓ Branch 3 taken 138 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 138 times.
✗ Branch 7 not taken.
|
138 | iter->second.ipv4_addresses.push_back(address); |
1201 |
2/2✓ Branch 1 taken 2244 times.
✓ Branch 2 taken 92 times.
|
2336 | else if (!ipv4_only()) |
1202 |
2/4✓ Branch 3 taken 2244 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2244 times.
✗ Branch 7 not taken.
|
2244 | iter->second.ipv6_addresses.push_back(address); |
1203 | } | ||
1204 | } // Current line | ||
1205 | } // Hosts file | ||
1206 | 2318 | } | |
1207 | |||
1208 | |||
1209 | 2494 | bool HostfileResolver::SetSearchDomains(const vector<string> &domains) { | |
1210 | 2494 | domains_ = domains; | |
1211 | 2494 | 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 | 2494 | NormalResolver *NormalResolver::Create(const bool ipv4_only, | |
1229 | const unsigned retries, | ||
1230 | const unsigned timeout_ms) { | ||
1231 | 2494 | CaresResolver *cares_resolver = CaresResolver::Create(ipv4_only, retries, | |
1232 | timeout_ms); | ||
1233 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2494 times.
|
2494 | if (!cares_resolver) |
1234 | ✗ | return NULL; | |
1235 |
2/4✓ Branch 2 taken 2494 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2494 times.
✗ Branch 6 not taken.
|
2494 | HostfileResolver *hostfile_resolver = HostfileResolver::Create("", ipv4_only); |
1236 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 2448 times.
|
2494 | if (!hostfile_resolver) { |
1237 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | delete cares_resolver; |
1238 | 46 | return NULL; | |
1239 | } | ||
1240 | 2448 | const bool retval = hostfile_resolver->SetSearchDomains( | |
1241 | cares_resolver->domains()); | ||
1242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2448 times.
|
2448 | assert(retval); |
1243 | |||
1244 | 2448 | NormalResolver *normal_resolver = new NormalResolver(); | |
1245 | 2448 | normal_resolver->cares_resolver_ = cares_resolver; | |
1246 | 2448 | normal_resolver->hostfile_resolver_ = hostfile_resolver; | |
1247 | 2448 | normal_resolver->domains_ = cares_resolver->domains(); | |
1248 | 2448 | normal_resolver->resolvers_ = cares_resolver->resolvers(); | |
1249 | 2448 | normal_resolver->retries_ = cares_resolver->retries(); | |
1250 | 2448 | normal_resolver->timeout_ms_ = cares_resolver->timeout_ms(); | |
1251 | 2448 | return normal_resolver; | |
1252 | } | ||
1253 | |||
1254 | |||
1255 | /** | ||
1256 | * Makes only sense for the c-ares resolver. | ||
1257 | */ | ||
1258 | 46 | bool NormalResolver::SetResolvers(const vector<string> &resolvers) { | |
1259 | 46 | 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 | 938 | 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 | 938 | const unsigned num = names.size(); | |
1306 |
1/2✓ Branch 1 taken 938 times.
✗ Branch 2 not taken.
|
938 | hostfile_resolver_->DoResolve(names, skip, ipv4_addresses, ipv6_addresses, |
1307 | failures, ttls, fqdns); | ||
1308 |
1/2✓ Branch 1 taken 938 times.
✗ Branch 2 not taken.
|
938 | vector<bool> skip_cares = skip; |
1309 |
2/2✓ Branch 0 taken 942 times.
✓ Branch 1 taken 938 times.
|
1880 | for (unsigned i = 0; i < num; ++i) { |
1310 |
2/2✓ Branch 1 taken 896 times.
✓ Branch 2 taken 46 times.
|
942 | if ((*failures)[i] == kFailOk) |
1311 |
1/2✓ Branch 1 taken 896 times.
✗ Branch 2 not taken.
|
896 | skip_cares[i] = true; |
1312 | } | ||
1313 |
1/2✓ Branch 1 taken 938 times.
✗ Branch 2 not taken.
|
938 | cares_resolver_->DoResolve(names, skip_cares, ipv4_addresses, ipv6_addresses, |
1314 | failures, ttls, fqdns); | ||
1315 | 938 | } | |
1316 | |||
1317 | |||
1318 | 2448 | NormalResolver::NormalResolver() | |
1319 | 2448 | : Resolver(false, 0, 0), cares_resolver_(NULL), hostfile_resolver_(NULL) { } | |
1320 | |||
1321 | |||
1322 | 9788 | NormalResolver::~NormalResolver() { | |
1323 |
1/2✓ Branch 0 taken 2447 times.
✗ Branch 1 not taken.
|
4894 | delete cares_resolver_; |
1324 |
1/2✓ Branch 0 taken 2447 times.
✗ Branch 1 not taken.
|
4894 | delete hostfile_resolver_; |
1325 | 9788 | } | |
1326 | |||
1327 | } // namespace dns | ||
1328 |