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