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 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 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 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];
599 int retval = ares_parse_a_reply(abuf, alen, &host_entry, records, &naddrttls);
603 if (host_entry == NULL)
605 if (host_entry->h_name == NULL) {
606 ares_free_hostent(host_entry);
609 *fqdn = string(host_entry->h_name);
610 ares_free_hostent(host_entry);
615 for (
unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
616 if (records[i].ttl < 0)
618 *ttl = std::min(
unsigned(records[i].ttl), *ttl);
620 char addrstr[INET_ADDRSTRLEN];
621 const void *retval_p = inet_ntop(AF_INET, &(records[i].ipaddr), addrstr,
625 addresses->push_back(addrstr);
627 if (addresses->empty())
642 vector<string> *addresses,
645 struct hostent *host_entry = NULL;
646 struct ares_addr6ttl records[CaresResolver::kMaxAddresses];
648 int retval = ares_parse_aaaa_reply(abuf, alen, &host_entry, records,
653 if (host_entry == NULL)
655 if (host_entry->h_name == NULL) {
656 ares_free_hostent(host_entry);
659 *fqdn = string(host_entry->h_name);
660 ares_free_hostent(host_entry);
665 for (
unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
666 if (records[i].ttl < 0)
668 *ttl = std::min(
unsigned(records[i].ttl), *ttl);
670 char addrstr[INET6_ADDRSTRLEN];
671 const void *retval_p = inet_ntop(AF_INET6, &(records[i].ip6addr),
672 addrstr, INET6_ADDRSTRLEN);
675 addresses->push_back(addrstr);
677 if (addresses->empty())
692 const unsigned timeout_ms)
693 :
Resolver(ipv4_only, retries, timeout_ms)
695 , lookup_options_(strdup(
"b")) { }
712 const unsigned timeout_ms) {
714 if (getenv(
"HOSTALIASES") == NULL) {
715 retval = setenv(
"HOSTALIASES",
"/etc/hosts", 1);
720 resolver->
channel_ =
reinterpret_cast<ares_channel *
>(
721 smalloc(
sizeof(ares_channel)));
722 memset(resolver->
channel_, 0,
sizeof(ares_channel));
724 struct ares_addr_node *addresses;
725 struct ares_addr_node *iter;
726 struct ares_options options;
728 memset(&options, 0,
sizeof(options));
732 optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_LOOKUPS;
733 retval = ares_init_options(resolver->
channel_, &options, optmask);
734 if (retval != ARES_SUCCESS)
738 retval = ares_save_options(*resolver->
channel_, &options, &optmask);
739 if (retval != ARES_SUCCESS)
741 for (
int i = 0; i < options.ndomains; ++i) {
742 resolver->
domains_.push_back(options.domains[i]);
744 ares_destroy_options(&options);
749 retval = ares_get_servers(*resolver->
channel_, &addresses);
750 if (retval != ARES_SUCCESS)
754 switch (iter->family) {
756 char addrstr[INET_ADDRSTRLEN];
757 const void *retval_p = inet_ntop(AF_INET, &(iter->addr), addrstr,
761 "invalid system name resolver");
763 resolver->
resolvers_.push_back(
string(addrstr) +
":53");
768 char addrstr[INET6_ADDRSTRLEN];
769 const void *retval_p = inet_ntop(AF_INET6, &(iter->addr), addrstr,
773 "invalid system name resolver");
775 resolver->
resolvers_.push_back(
"[" +
string(addrstr) +
"]:53");
785 ares_free_data(addresses);
792 "failed to initialize c-ares resolver (%d - %s)", retval,
793 ares_strerror(retval));
806 const vector<bool> &skip,
807 vector<vector<string> > *ipv4_addresses,
808 vector<vector<string> > *ipv6_addresses,
809 vector<Failures> *failures,
810 vector<unsigned> *ttls,
811 vector<string> *fqdns) {
812 unsigned num = names.size();
816 vector<QueryInfo *> infos_ipv4(num, NULL);
817 vector<QueryInfo *> infos_ipv6(num, NULL);
819 for (
unsigned i = 0; i < num; ++i) {
824 infos_ipv6[i] =
new QueryInfo(&(*ipv6_addresses)[i], names[i],
kRrAaaa);
825 ares_search(*
channel_, names[i].c_str(), ns_c_in, ns_t_aaaa,
828 infos_ipv4[i] =
new QueryInfo(&(*ipv4_addresses)[i], names[i],
kRrA);
837 for (
unsigned i = 0; i < num; ++i) {
838 if ((infos_ipv4[i] && !infos_ipv4[i]->complete)
839 || (infos_ipv6[i] && !infos_ipv6[i]->complete)) {
840 all_complete =
false;
844 }
while (!all_complete);
848 for (
unsigned i = 0; i < num; ++i) {
853 (*ttls)[i] = unsigned(-1);
856 status = infos_ipv6[i]->status;
858 (*ttls)[i] = std::min(infos_ipv6[i]->ttl, (*ttls)[i]);
859 (*fqdns)[i] = infos_ipv6[i]->fqdn;
863 (*ttls)[i] = std::min(infos_ipv4[i]->ttl, (*ttls)[i]);
864 if ((*fqdns)[i] ==
"")
865 (*fqdns)[i] = infos_ipv4[i]->fqdn;
867 status = infos_ipv4[i]->status;
869 (*failures)[i] = status;
872 for (
unsigned i = 0; i < num; ++i) {
873 delete infos_ipv4[i];
874 delete infos_ipv6[i];
881 int retval = ares_set_servers_csv(*
channel_, address_list.c_str());
882 if (retval != ARES_SUCCESS)
905 int socket_send_buffer_size;
906 int socket_receive_buffer_size;
912 memcpy(&ares_channelhead, *
channel_,
sizeof(ares_channelhead));
913 if (ares_channelhead.domains) {
914 for (
int i = 0; i < ares_channelhead.ndomains; ++i) {
915 free(ares_channelhead.domains[i]);
917 free(ares_channelhead.domains);
918 ares_channelhead.domains = NULL;
921 ares_channelhead.ndomains =
static_cast<int>(domains.size());
922 if (ares_channelhead.ndomains > 0) {
923 ares_channelhead.domains =
reinterpret_cast<char **
>(
924 smalloc(ares_channelhead.ndomains *
sizeof(
char *)));
925 for (
int i = 0; i < ares_channelhead.ndomains; ++i) {
926 ares_channelhead.domains[i] = strdup(domains[i].c_str());
930 memcpy(*
channel_, &ares_channelhead,
sizeof(ares_channelhead));
955 ares_socket_t socks[ARES_GETSOCK_MAXNUM];
956 struct pollfd pfd[ARES_GETSOCK_MAXNUM];
957 int bitmask = ares_getsock(*
channel_, socks, ARES_GETSOCK_MAXNUM);
959 for (
unsigned i = 0; i < ARES_GETSOCK_MAXNUM; ++i) {
962 if (ARES_GETSOCK_READABLE(bitmask, i)) {
963 pfd[i].fd = socks[i];
964 pfd[i].events |= POLLRDNORM | POLLIN;
966 if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
967 pfd[i].fd = socks[i];
968 pfd[i].events |= POLLWRNORM | POLLOUT;
970 if (pfd[i].events != 0)
982 if ((errno != EAGAIN) && (errno != EINTR))
985 }
while (nfds == -1);
991 ares_process_fd(*
channel_, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
994 for (
unsigned i = 0; i < num; ++i) {
997 pfd[i].revents & (POLLRDNORM | POLLIN) ? pfd[i].fd : ARES_SOCKET_BAD,
998 pfd[i].revents & (POLLWRNORM | POLLOUT) ? pfd[i].fd
1016 string hosts_file = path;
1017 if (hosts_file ==
"") {
1018 char *hosts_env = getenv(
"HOST_ALIASES");
1019 if (hosts_env != NULL) {
1020 hosts_file = string(hosts_env);
1022 hosts_file =
"/etc/hosts";
1025 resolver->
fhosts_ = fopen(hosts_file.c_str(),
"r");
1028 hosts_file.c_str());
1042 unsigned len_a = a.length();
1043 unsigned len_b = b.length();
1045 return len_a > len_b;
1054 const vector<bool> &skip,
1055 vector<vector<std::string> > *ipv4_addresses,
1056 vector<vector<std::string> > *ipv6_addresses,
1057 vector<Failures> *failures,
1058 vector<unsigned> *ttls,
1059 vector<string> *fqdns) {
1060 unsigned num = names.size();
1065 for (
unsigned i = 0; i < num; ++i) {
1069 vector<string> effective_names;
1070 if (!names[i].empty() && (names[i][names[i].length() - 1] ==
'.')) {
1071 effective_names.push_back(names[i].substr(0, names[i].length() - 1));
1073 effective_names.push_back(names[i]);
1074 for (
unsigned j = 0; j <
domains().size(); ++j) {
1075 effective_names.push_back(names[i] +
"." +
domains()[j]);
1080 std::sort(effective_names.begin(), effective_names.end(),
SortNameLength);
1083 (*fqdns)[i] = names[i];
1084 for (
unsigned j = 0; j < effective_names.size(); ++j) {
1085 map<string, HostEntry>::iterator iter =
host_map_.find(
1086 effective_names[j]);
1088 (*ipv4_addresses)[i].insert((*ipv4_addresses)[i].end(),
1089 iter->second.ipv4_addresses.begin(),
1090 iter->second.ipv4_addresses.end());
1091 (*ipv6_addresses)[i].insert((*ipv6_addresses)[i].end(),
1092 iter->second.ipv6_addresses.begin(),
1093 iter->second.ipv6_addresses.end());
1095 (*fqdns)[i] = effective_names[j];
1105 :
Resolver(ipv4_only, 0, 0), fhosts_(NULL) { }
1127 size_t str_offset = 0;
1130 size_t hash_pos = line.find_first_of(
'#');
1131 if (hash_pos != string::npos)
1132 line = line.substr(0, hash_pos);
1135 int ip_start_pos = -1, ip_end_pos = -1, scan_result;
1136 scan_result = sscanf(line.c_str(),
" %n%*s%n", &ip_start_pos, &ip_end_pos);
1137 if (scan_result == EOF)
1139 assert(ip_start_pos != -1);
1140 assert(ip_end_pos != -1);
1141 if (ip_start_pos == ip_end_pos)
1146 "Skipping line in hosts file due to invalid IP address format: %s",
1152 scan_result = sscanf(line.c_str(),
" %s%n", address, &bytes_read);
1153 assert(scan_result == 1);
1154 assert(bytes_read != -1);
1155 str_offset += bytes_read;
1158 while (str_offset < line.length()) {
1160 int hostname_start_pos = -1, hostname_end_pos = -1;
1161 scan_result = sscanf(line.c_str() + str_offset,
" %n%*s%n",
1162 &hostname_start_pos, &hostname_end_pos);
1163 if (scan_result == EOF)
1165 assert(hostname_start_pos != -1);
1166 assert(hostname_end_pos != -1);
1167 if (hostname_start_pos == hostname_end_pos)
1173 "Skipping invalid (too long) hostname in hosts file on line: %s",
1175 str_offset += hostname_end_pos;
1180 scan_result = sscanf(line.c_str() + str_offset,
" %s%n", hostname,
1182 assert(scan_result == 1);
1183 assert(bytes_read != -1);
1184 str_offset += bytes_read;
1186 if (hostname[strlen(hostname) - 1] ==
'.')
1187 hostname[strlen(hostname) - 1] = 0;
1189 map<string, HostEntry>::iterator iter =
host_map_.find(hostname);
1201 iter->second.ipv6_addresses.push_back(address);
1229 const unsigned timeout_ms) {
1232 if (!cares_resolver)
1235 if (!hostfile_resolver) {
1236 delete cares_resolver;
1249 return normal_resolver;
1297 const vector<bool> &skip,
1298 vector<vector<string> > *ipv4_addresses,
1299 vector<vector<string> > *ipv6_addresses,
1300 vector<Failures> *failures,
1301 vector<unsigned> *ttls,
1302 vector<string> *fqdns) {
1303 unsigned num = names.size();
1305 failures, ttls, fqdns);
1306 vector<bool> skip_cares = skip;
1307 for (
unsigned i = 0; i < num; ++i) {
1308 if ((*failures)[i] ==
kFailOk)
1309 skip_cares[i] =
true;
1312 failures, ttls, fqdns);
1317 :
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,...)