24 #include <arpa/inet.h>
25 #include <arpa/nameser.h>
56 *pos_begin = *pos_end = 0;
57 const unsigned len = url.size();
61 for (; i < len; ++i) {
62 if ((url[i] ==
'/') && (i < len - 2) && (url[i + 1] ==
'/')) {
71 for (i = *pos_begin; i < len; ++i) {
74 }
else if (url[i] ==
'@') {
83 bool in_ipv6 = (url[*pos_begin] ==
'[');
84 for (i = *pos_begin; i < len; ++i) {
91 if ((url[i] ==
':') || (url[i] ==
'/'))
97 if (*pos_end < *pos_begin)
98 *pos_end = *pos_begin = 0;
114 return url.substr(pos_begin, (pos_end - pos_begin) + 1);
127 if (pos_begin == 0 || pos_end + 2 >= url.size() || url.at(pos_end + 1) !=
':')
131 const std::size_t pos_port = url.find(
"/", pos_end);
133 if (pos_port == std::string::npos)
134 retme = url.substr(pos_end + 2);
136 retme = url.substr(pos_end + 2, pos_port - pos_end - 2);
139 for (std::string::iterator it = retme.begin(); it != retme.end(); ++it)
140 if (isdigit(*it) == 0)
160 result.replace(pos_begin, (pos_end - pos_begin) + 1, ip);
169 if (!decorated_ip.empty()) {
170 if ((decorated_ip[0] ==
'[')
171 && (decorated_ip[decorated_ip.length() - 1] ==
']')) {
172 return decorated_ip.substr(1, decorated_ip.length() - 2);
183 const bool ignore_case =
true;
184 if (
HasPrefix(proxy,
"http://", ignore_case)
185 ||
HasPrefix(proxy,
"https://", ignore_case) || (proxy ==
"DIRECT")
189 return "http://" + proxy;
198 const set<string> &Host::ViewBestAddresses(
IpPreference preference)
const {
201 return ipv4_addresses_;
204 return ipv4_addresses_;
205 return ipv6_addresses_;
209 void Host::CopyFrom(
const Host &other) {
223 Host Host::ExtendDeadline(
const Host &original,
unsigned seconds_from_now) {
224 Host new_host(original);
225 new_host.
id_ = atomic_xadd64(&global_id_, 1);
226 new_host.
deadline_ = time(NULL) + seconds_from_now;
237 , id_(atomic_xadd64(&global_id_, 1))
268 const time_t now = time(NULL);
269 assert(now != static_cast<time_t>(-1));
298 if (!sanitizer.
IsValid(address))
303 if (octets.size() != 4)
305 for (
unsigned i = 0; i < 4; ++i) {
307 if (this_octet > 255)
322 return sanitizer.
IsValid(address);
328 const unsigned timeout_ms)
329 : ipv4_only_(ipv4_only)
331 , timeout_ms_(timeout_ms)
333 , min_ttl_(kDefaultMinTtl)
334 , max_ttl_(kDefaultMaxTtl) {
343 vector<string> names;
344 names.push_back(name);
356 const unsigned num = names.size();
360 vector<vector<string> > ipv4_addresses(num);
361 vector<vector<string> > ipv6_addresses(num);
362 vector<Failures> failures(num);
363 vector<unsigned> ttls(num);
364 vector<string> fqdns(num);
365 vector<bool> skip(num);
368 for (
unsigned i = 0; i < num; ++i) {
369 if (names[i].empty()) {
372 invalid_host.
name_ =
"";
374 hosts->push_back(invalid_host);
379 ipv4_host.
name_ = names[i];
383 hosts->push_back(ipv4_host);
385 }
else if ((names[i].length() >= 3) && (names[i][0] ==
'[')
386 && (names[i][names[i].length() - 1] ==
']')) {
389 ipv6_host.
name_ = names[i];
393 hosts->push_back(ipv6_host);
396 hosts->push_back(
Host());
401 DoResolve(names, skip, &ipv4_addresses, &ipv6_addresses, &failures, &ttls,
405 for (
unsigned i = 0; i < num; ++i) {
410 host.
name_ = fqdns[i];
413 unsigned effective_ttl = ttls[i];
416 }
else if (effective_ttl >
max_ttl_) {
419 host.
deadline_ = time(NULL) + effective_ttl;
430 for (
unsigned j = 0; j < ipv4_addresses[i].size(); ++j) {
433 "host name %s resolves to invalid IPv4 address %s",
434 names[i].c_str(), ipv4_addresses[i][j].c_str());
437 if (names[i] == host.
name_) {
439 ipv4_addresses[i][j].c_str());
442 names[i].c_str(), host.
name_.c_str(),
443 ipv4_addresses[i][j].c_str());
448 for (
unsigned j = 0; j < ipv6_addresses[i].size(); ++j) {
451 "host name %s resolves to invalid IPv6 address %s",
452 names[i].c_str(), ipv6_addresses[i][j].c_str());
456 if (names[i] == host.
name_) {
458 ipv6_addresses[i][j].c_str());
461 names[i].c_str(), host.
name_.c_str(),
462 ipv6_addresses[i][j].c_str());
478 std::advance(rnd_itr, random);
484 std::advance(rnd_itr, random);
533 vector<string> *addresses,
unsigned *ttl,
536 vector<string> *addresses,
unsigned *ttl,
544 void *arg,
int status,
int timeouts_ms,
unsigned char *abuf,
int alen) {
545 QueryInfo *info =
reinterpret_cast<QueryInfo *
>(arg);
547 info->complete =
true;
551 switch (info->record) {
564 info->status = retval;
578 case ARES_ECONNREFUSED:
593 vector<string> *addresses,
596 struct hostent *host_entry = NULL;
597 struct ares_addrttl records[CaresResolver::kMaxAddresses];
600 ares_parse_a_reply(abuf, alen, &host_entry, records, &naddrttls);
604 if (host_entry == NULL)
606 if (host_entry->h_name == NULL) {
607 ares_free_hostent(host_entry);
610 *fqdn = string(host_entry->h_name);
611 ares_free_hostent(host_entry);
616 for (
unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
617 if (records[i].ttl < 0)
619 *ttl = std::min(
unsigned(records[i].ttl), *ttl);
621 char addrstr[INET_ADDRSTRLEN];
622 const void *retval_p = inet_ntop(AF_INET, &(records[i].ipaddr), addrstr,
626 addresses->push_back(addrstr);
628 if (addresses->empty())
643 vector<string> *addresses,
646 struct hostent *host_entry = NULL;
647 struct ares_addr6ttl records[CaresResolver::kMaxAddresses];
650 ares_parse_aaaa_reply(abuf, alen, &host_entry, records, &naddrttls);
654 if (host_entry == NULL)
656 if (host_entry->h_name == NULL) {
657 ares_free_hostent(host_entry);
660 *fqdn = string(host_entry->h_name);
661 ares_free_hostent(host_entry);
666 for (
unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
667 if (records[i].ttl < 0)
669 *ttl = std::min(
unsigned(records[i].ttl), *ttl);
671 char addrstr[INET6_ADDRSTRLEN];
672 const void *retval_p = inet_ntop(AF_INET6, &(records[i].ip6addr),
673 addrstr, INET6_ADDRSTRLEN);
676 addresses->push_back(addrstr);
678 if (addresses->empty())
693 const unsigned timeout_ms)
694 :
Resolver(ipv4_only, retries, timeout_ms)
696 , lookup_options_(strdup(
"b")) { }
713 const unsigned timeout_ms) {
715 if (getenv(
"HOSTALIASES") == NULL) {
716 retval = setenv(
"HOSTALIASES",
"/etc/hosts", 1);
721 resolver->
channel_ =
reinterpret_cast<ares_channel *
>(
722 smalloc(
sizeof(ares_channel)));
723 memset(resolver->
channel_, 0,
sizeof(ares_channel));
725 struct ares_addr_node *addresses;
726 struct ares_addr_node *iter;
727 struct ares_options options;
729 memset(&options, 0,
sizeof(options));
733 optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_LOOKUPS;
734 retval = ares_init_options(resolver->
channel_, &options, optmask);
735 if (retval != ARES_SUCCESS)
739 retval = ares_save_options(*resolver->
channel_, &options, &optmask);
740 if (retval != ARES_SUCCESS)
742 for (
int i = 0; i < options.ndomains; ++i) {
743 resolver->
domains_.push_back(options.domains[i]);
745 ares_destroy_options(&options);
750 retval = ares_get_servers(*resolver->
channel_, &addresses);
751 if (retval != ARES_SUCCESS)
755 switch (iter->family) {
757 char addrstr[INET_ADDRSTRLEN];
758 const void *retval_p = inet_ntop(AF_INET, &(iter->addr), addrstr,
762 "invalid system name resolver");
764 resolver->
resolvers_.push_back(
string(addrstr) +
":53");
769 char addrstr[INET6_ADDRSTRLEN];
770 const void *retval_p = inet_ntop(AF_INET6, &(iter->addr), addrstr,
774 "invalid system name resolver");
776 resolver->
resolvers_.push_back(
"[" +
string(addrstr) +
"]:53");
786 ares_free_data(addresses);
793 "failed to initialize c-ares resolver (%d - %s)", retval,
794 ares_strerror(retval));
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 const unsigned num = names.size();
817 vector<QueryInfo *> infos_ipv4(num, NULL);
818 vector<QueryInfo *> infos_ipv6(num, NULL);
820 for (
unsigned i = 0; i < num; ++i) {
825 infos_ipv6[i] =
new QueryInfo(&(*ipv6_addresses)[i], names[i],
kRrAaaa);
826 ares_search(*
channel_, names[i].c_str(), ns_c_in, ns_t_aaaa,
829 infos_ipv4[i] =
new QueryInfo(&(*ipv4_addresses)[i], names[i],
kRrA);
838 for (
unsigned i = 0; i < num; ++i) {
839 if ((infos_ipv4[i] && !infos_ipv4[i]->complete)
840 || (infos_ipv6[i] && !infos_ipv6[i]->complete)) {
841 all_complete =
false;
845 }
while (!all_complete);
849 for (
unsigned i = 0; i < num; ++i) {
854 (*ttls)[i] = unsigned(-1);
857 status = infos_ipv6[i]->status;
859 (*ttls)[i] = std::min(infos_ipv6[i]->ttl, (*ttls)[i]);
860 (*fqdns)[i] = infos_ipv6[i]->fqdn;
864 (*ttls)[i] = std::min(infos_ipv4[i]->ttl, (*ttls)[i]);
865 if ((*fqdns)[i] ==
"")
866 (*fqdns)[i] = infos_ipv4[i]->fqdn;
868 status = infos_ipv4[i]->status;
870 (*failures)[i] = status;
873 for (
unsigned i = 0; i < num; ++i) {
874 delete infos_ipv4[i];
875 delete infos_ipv6[i];
881 const string address_list =
JoinStrings(resolvers,
",");
882 const int retval = ares_set_servers_csv(*
channel_, address_list.c_str());
883 if (retval != ARES_SUCCESS)
906 int socket_send_buffer_size;
907 int socket_receive_buffer_size;
913 memcpy(&ares_channelhead, *
channel_,
sizeof(ares_channelhead));
914 if (ares_channelhead.domains) {
915 for (
int i = 0; i < ares_channelhead.ndomains; ++i) {
916 free(ares_channelhead.domains[i]);
918 free(ares_channelhead.domains);
919 ares_channelhead.domains = NULL;
922 ares_channelhead.ndomains =
static_cast<int>(domains.size());
923 if (ares_channelhead.ndomains > 0) {
924 ares_channelhead.domains =
reinterpret_cast<char **
>(
925 smalloc(ares_channelhead.ndomains *
sizeof(
char *)));
926 for (
int i = 0; i < ares_channelhead.ndomains; ++i) {
927 ares_channelhead.domains[i] = strdup(domains[i].c_str());
931 memcpy(*
channel_, &ares_channelhead,
sizeof(ares_channelhead));
956 ares_socket_t socks[ARES_GETSOCK_MAXNUM];
957 struct pollfd pfd[ARES_GETSOCK_MAXNUM];
958 const int bitmask = ares_getsock(*
channel_, socks, ARES_GETSOCK_MAXNUM);
960 for (
unsigned i = 0; i < ARES_GETSOCK_MAXNUM; ++i) {
963 if (ARES_GETSOCK_READABLE(bitmask, i)) {
964 pfd[i].fd = socks[i];
965 pfd[i].events |= POLLRDNORM | POLLIN;
967 if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
968 pfd[i].fd = socks[i];
969 pfd[i].events |= POLLWRNORM | POLLOUT;
971 if (pfd[i].events != 0)
983 if ((errno != EAGAIN) && (errno != EINTR))
986 }
while (nfds == -1);
992 ares_process_fd(*
channel_, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
995 for (
unsigned i = 0; i < num; ++i) {
998 pfd[i].revents & (POLLRDNORM | POLLIN) ? pfd[i].fd : ARES_SOCKET_BAD,
999 pfd[i].revents & (POLLWRNORM | POLLOUT) ? pfd[i].fd
1017 string hosts_file = path;
1018 if (hosts_file ==
"") {
1019 char *hosts_env = getenv(
"HOST_ALIASES");
1020 if (hosts_env != NULL) {
1021 hosts_file = string(hosts_env);
1023 hosts_file =
"/etc/hosts";
1026 resolver->
fhosts_ = fopen(hosts_file.c_str(),
"r");
1029 hosts_file.c_str());
1043 const unsigned len_a = a.length();
1044 const unsigned len_b = b.length();
1046 return len_a > len_b;
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 const unsigned num = names.size();
1066 for (
unsigned i = 0; i < num; ++i) {
1070 vector<string> effective_names;
1071 if (!names[i].empty() && (names[i][names[i].length() - 1] ==
'.')) {
1072 effective_names.push_back(names[i].substr(0, names[i].length() - 1));
1074 effective_names.push_back(names[i]);
1075 for (
unsigned j = 0; j <
domains().size(); ++j) {
1076 effective_names.push_back(names[i] +
"." +
domains()[j]);
1081 std::sort(effective_names.begin(), effective_names.end(),
SortNameLength);
1084 (*fqdns)[i] = names[i];
1085 for (
unsigned j = 0; j < effective_names.size(); ++j) {
1086 const map<string, HostEntry>::iterator iter =
1089 (*ipv4_addresses)[i].insert((*ipv4_addresses)[i].end(),
1090 iter->second.ipv4_addresses.begin(),
1091 iter->second.ipv4_addresses.end());
1092 (*ipv6_addresses)[i].insert((*ipv6_addresses)[i].end(),
1093 iter->second.ipv6_addresses.begin(),
1094 iter->second.ipv6_addresses.end());
1096 (*fqdns)[i] = effective_names[j];
1106 :
Resolver(ipv4_only, 0, 0), fhosts_(NULL) { }
1128 size_t str_offset = 0;
1131 const size_t hash_pos = line.find_first_of(
'#');
1132 if (hash_pos != string::npos)
1133 line = line.substr(0, hash_pos);
1136 int ip_start_pos = -1, ip_end_pos = -1, scan_result;
1137 scan_result = sscanf(line.c_str(),
" %n%*s%n", &ip_start_pos, &ip_end_pos);
1138 if (scan_result == EOF)
1140 assert(ip_start_pos != -1);
1141 assert(ip_end_pos != -1);
1142 if (ip_start_pos == ip_end_pos)
1147 "Skipping line in hosts file due to invalid IP address format: %s",
1153 scan_result = sscanf(line.c_str(),
" %s%n", address, &bytes_read);
1154 assert(scan_result == 1);
1155 assert(bytes_read != -1);
1156 str_offset += bytes_read;
1159 while (str_offset < line.length()) {
1161 int hostname_start_pos = -1, hostname_end_pos = -1;
1162 scan_result = sscanf(line.c_str() + str_offset,
" %n%*s%n",
1163 &hostname_start_pos, &hostname_end_pos);
1164 if (scan_result == EOF)
1166 assert(hostname_start_pos != -1);
1167 assert(hostname_end_pos != -1);
1168 if (hostname_start_pos == hostname_end_pos)
1174 "Skipping invalid (too long) hostname in hosts file on line: %s",
1176 str_offset += hostname_end_pos;
1181 scan_result = sscanf(line.c_str() + str_offset,
" %s%n", hostname,
1183 assert(scan_result == 1);
1184 assert(bytes_read != -1);
1185 str_offset += bytes_read;
1187 if (hostname[strlen(hostname) - 1] ==
'.')
1188 hostname[strlen(hostname) - 1] = 0;
1190 const map<string, HostEntry>::iterator iter =
host_map_.find(hostname);
1202 iter->second.ipv6_addresses.push_back(address);
1230 const unsigned timeout_ms) {
1233 if (!cares_resolver)
1236 if (!hostfile_resolver) {
1237 delete cares_resolver;
1251 return normal_resolver;
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 const unsigned num = names.size();
1307 failures, ttls, fqdns);
1308 vector<bool> skip_cares = skip;
1309 for (
unsigned i = 0; i < num; ++i) {
1310 if ((*failures)[i] ==
kFailOk)
1311 skip_cares[i] =
true;
1314 failures, ttls, fqdns);
1319 :
Resolver(false, 0, 0), cares_resolver_(NULL), hostfile_resolver_(NULL) { }
static const int kHostnameMaxLength
virtual bool SetSearchDomains(const std::vector< std::string > &domains)
vector< string > * addresses
const char * Code2Ascii(const Failures error)
void ResolveMany(const std::vector< std::string > &names, std::vector< Host > *hosts)
Resolver returned a negative reply.
HostfileResolver * hostfile_resolver_
static NormalResolver * Create(const bool ipv4_only, const unsigned retries, const unsigned timeout_ms)
void CopyFrom(const Host &other)
string JoinStrings(const vector< string > &strings, const string &joint)
CaresResolver * cares_resolver_
bool IsIpv4Address(const std::string &address)
static void PinpointHostSubstr(const std::string &url, unsigned *pos_begin, unsigned *pos_end)
virtual bool SetSearchDomains(const std::vector< std::string > &domains)
std::vector< std::string > ipv4_addresses
Resolver returned a positive reply but without IPs.
bool IsIpv6Address(const std::string &address)
std::set< std::string > ipv6_addresses_
QueryInfo(vector< string > *a, const string &n, const ResourceRecord r)
static void CallbackCares(void *arg, int status, int timeouts_ms, unsigned char *abuf, int alen)
virtual void SetSystemResolvers()
CaresResolver(const bool ipv4_only, const unsigned retries, const unsigned timeout_ms)
assert((mem||(size==0))&&"Out Of Memory")
Resolver(const bool ipv4_only, const unsigned retries, const unsigned timeout_ms)
static const int kIpMaxLength
static HostfileResolver * Create(const std::string &path, bool ipv4_only)
string StripIp(const string &decorated_ip)
virtual ~NormalResolver()
static Failures CaresExtractIpv6(const unsigned char *abuf, int alen, vector< string > *addresses, unsigned *ttl, string *fqdn)
Host & operator=(const Host &other)
std::vector< std::string > system_resolvers_
virtual void SetSystemSearchDomains()
bool GetLineFile(FILE *f, std::string *line)
virtual void SetSystemResolvers()
std::vector< std::string > domains_
const std::vector< std::string > & resolvers() const
std::string AddDefaultScheme(const std::string &proxy)
vector< string > SplitString(const string &str, char delim)
std::map< std::string, HostEntry > host_map_
HostfileResolver(const bool ipv4_only)
virtual bool SetSearchDomains(const std::vector< std::string > &domains)
virtual void DoResolve(const std::vector< std::string > &names, const std::vector< bool > &skip, std::vector< std::vector< std::string > > *ipv4_addresses, std::vector< std::vector< std::string > > *ipv6_addresses, std::vector< Failures > *failures, std::vector< unsigned > *ttls, std::vector< std::string > *fqdns)
bool IsEquivalent(const Host &other) const
virtual bool SetResolvers(const std::vector< std::string > &resolvers)
static Failures CaresExtractIpv4(const unsigned char *abuf, int alen, vector< string > *addresses, unsigned *ttl, string *fqdn)
std::string ExtractPort(const std::string &url)
virtual void DoResolve(const std::vector< std::string > &names, const std::vector< bool > &skip, std::vector< std::vector< std::string > > *ipv4_addresses, std::vector< std::vector< std::string > > *ipv6_addresses, std::vector< Failures > *failures, std::vector< unsigned > *ttls, std::vector< std::string > *fqdns)
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
std::string ExtractHost(const std::string &url)
virtual ~HostfileResolver()
static bool SortNameLength(const string &a, const string &b)
Host Resolve(const std::string &name)
uint64_t String2Uint64(const string &value)
std::vector< std::string > resolvers_
static CaresResolver * Create(const bool ipv4_only, const unsigned retries, const unsigned timeout_ms)
virtual void DoResolve(const std::vector< std::string > &names, const std::vector< bool > &skip, std::vector< std::vector< std::string > > *ipv4_addresses, std::vector< std::vector< std::string > > *ipv6_addresses, std::vector< Failures > *failures, std::vector< unsigned > *ttls, std::vector< std::string > *fqdns)=0
std::vector< std::string > system_domains_
virtual void DoResolve(const std::vector< std::string > &names, const std::vector< bool > &skip, std::vector< std::vector< std::string > > *ipv4_addresses, std::vector< std::vector< std::string > > *ipv6_addresses, std::vector< Failures > *failures, std::vector< unsigned > *ttls, std::vector< std::string > *fqdns)
virtual void SetSystemSearchDomains()
std::set< std::string > ipv4_addresses_
virtual void SetSystemSearchDomains()
const std::vector< std::string > & domains() const
static const unsigned kMaxAddresses
std::vector< std::string > ipv6_addresses
virtual bool SetResolvers(const std::vector< std::string > &resolvers)
string RewriteUrl(const string &url, const string &ip)
uint32_t Next(const uint64_t boundary)
unsigned timeout_ms() const
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)