24 #include <arpa/inet.h>
25 #include <arpa/nameser.h>
54 const std::string &url,
58 *pos_begin = *pos_end = 0;
59 const unsigned len = url.size();
63 for (; i < len; ++i) {
64 if ((url[i] ==
'/') && (i < len-2) && (url[i+1] ==
'/')) {
73 for (i = *pos_begin; i < len; ++i) {
76 }
else if (url[i] ==
'@') {
85 bool in_ipv6 = (url[*pos_begin] ==
'[');
86 for (i = *pos_begin; i < len; ++i) {
93 if ((url[i] ==
':') || (url[i] ==
'/'))
99 if (*pos_end < *pos_begin)
100 *pos_end = *pos_begin = 0;
116 return url.substr(pos_begin, (pos_end - pos_begin) + 1);
129 if (pos_begin == 0 ||
130 pos_end + 2 >= url.size() ||
131 url.at(pos_end + 1) !=
':')
135 std::size_t pos_port = url.find(
"/", pos_end);
137 if (pos_port == std::string::npos)
138 retme = url.substr(pos_end + 2);
140 retme = url.substr(pos_end + 2, pos_port - pos_end - 2);
143 for (std::string::iterator it = retme.begin(); it != retme.end(); ++it)
144 if (isdigit(*it) == 0)
164 result.replace(pos_begin, (pos_end - pos_begin) + 1, ip);
173 if (!decorated_ip.empty()) {
174 if ((decorated_ip[0] ==
'[') &&
175 (decorated_ip[decorated_ip.length()-1] ==
']'))
177 return decorated_ip.substr(1, decorated_ip.length()-2);
188 const bool ignore_case =
true;
189 if (
HasPrefix(proxy,
"http://", ignore_case) ||
190 HasPrefix(proxy,
"https://", ignore_case) ||
191 (proxy ==
"DIRECT") ||
196 return "http://" + proxy;
205 const set<string> &Host::ViewBestAddresses(
IpPreference preference)
const {
209 return ipv4_addresses_;
212 return ipv4_addresses_;
213 return ipv6_addresses_;
217 void Host::CopyFrom(
const Host &other) {
231 Host Host::ExtendDeadline(
const Host &original,
unsigned seconds_from_now) {
232 Host new_host(original);
233 new_host.
id_ = atomic_xadd64(&global_id_, 1);
234 new_host.
deadline_ = time(NULL) + seconds_from_now;
245 , id_(atomic_xadd64(&global_id_, 1))
281 time_t now = time(NULL);
282 assert(now != static_cast<time_t>(-1));
311 if (!sanitizer.
IsValid(address))
316 if (octets.size() != 4)
318 for (
unsigned i = 0; i < 4; ++i) {
320 if (this_octet > 255)
335 return sanitizer.
IsValid(address);
340 const bool ipv4_only,
342 const unsigned timeout_ms)
343 : ipv4_only_(ipv4_only)
345 , timeout_ms_(timeout_ms)
347 , min_ttl_(kDefaultMinTtl)
348 , max_ttl_(kDefaultMaxTtl)
358 vector<string> names;
359 names.push_back(name);
371 unsigned num = names.size();
375 vector<vector<string> > ipv4_addresses(num);
376 vector<vector<string> > ipv6_addresses(num);
377 vector<Failures> failures(num);
378 vector<unsigned> ttls(num);
379 vector<string> fqdns(num);
380 vector<bool> skip(num);
383 for (
unsigned i = 0; i < num; ++i) {
384 if (names[i].empty()) {
387 invalid_host.
name_ =
"";
389 hosts->push_back(invalid_host);
394 ipv4_host.
name_ = names[i];
398 hosts->push_back(ipv4_host);
400 }
else if ((names[i].length() >= 3) &&
401 (names[i][0] ==
'[') &&
402 (names[i][names[i].length()-1] ==
']'))
406 ipv6_host.
name_ = names[i];
410 hosts->push_back(ipv6_host);
413 hosts->push_back(
Host());
419 names, skip, &ipv4_addresses, &ipv6_addresses, &failures, &ttls, &fqdns);
422 for (
unsigned i = 0; i < num; ++i) {
427 host.
name_ = fqdns[i];
430 unsigned effective_ttl = ttls[i];
433 }
else if (effective_ttl >
max_ttl_) {
436 host.
deadline_ = time(NULL) + effective_ttl;
447 for (
unsigned j = 0; j < ipv4_addresses[i].size(); ++j) {
450 "host name %s resolves to invalid IPv4 address %s",
451 names[i].c_str(), ipv4_addresses[i][j].c_str());
454 if (names[i] == host.
name_) {
456 names[i].c_str(), ipv4_addresses[i][j].c_str());
459 names[i].c_str(), host.
name_.c_str(), ipv4_addresses[i][j].c_str());
464 for (
unsigned j = 0; j < ipv6_addresses[i].size(); ++j) {
467 "host name %s resolves to invalid IPv6 address %s",
468 names[i].c_str(), ipv6_addresses[i][j].c_str());
472 if (names[i] == host.
name_) {
474 names[i].c_str(), ipv6_addresses[i][j].c_str());
477 names[i].c_str(), host.
name_.c_str(), ipv6_addresses[i][j].c_str());
493 std::advance(rnd_itr, random);
499 std::advance(rnd_itr, random);
552 vector<string> *addresses,
556 vector<string> *addresses,
571 QueryInfo *info =
reinterpret_cast<QueryInfo *
>(arg);
573 info->complete =
true;
577 switch (info->record) {
580 abuf, alen, info->addresses, &info->ttl, &info->fqdn);
584 abuf, alen, info->addresses, &info->ttl, &info->fqdn);
590 info->status = retval;
604 case ARES_ECONNREFUSED:
618 const unsigned char *abuf,
620 vector<string> *addresses,
624 struct hostent *host_entry = NULL;
625 struct ares_addrttl records[CaresResolver::kMaxAddresses];
627 int retval = ares_parse_a_reply(abuf, alen, &host_entry, records, &naddrttls);
631 if (host_entry == NULL)
633 if (host_entry->h_name == NULL) {
634 ares_free_hostent(host_entry);
637 *fqdn = string(host_entry->h_name);
638 ares_free_hostent(host_entry);
643 for (
unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
644 if (records[i].ttl < 0)
646 *ttl = std::min(
unsigned(records[i].ttl), *ttl);
648 char addrstr[INET_ADDRSTRLEN];
649 const void *retval_p =
650 inet_ntop(AF_INET, &(records[i].ipaddr), addrstr, INET_ADDRSTRLEN);
653 addresses->push_back(addrstr);
655 if (addresses->empty())
669 const unsigned char *abuf,
671 vector<string> *addresses,
675 struct hostent *host_entry = NULL;
676 struct ares_addr6ttl records[CaresResolver::kMaxAddresses];
679 ares_parse_aaaa_reply(abuf, alen, &host_entry, records, &naddrttls);
683 if (host_entry == NULL)
685 if (host_entry->h_name == NULL) {
686 ares_free_hostent(host_entry);
689 *fqdn = string(host_entry->h_name);
690 ares_free_hostent(host_entry);
695 for (
unsigned i = 0; i < static_cast<unsigned>(naddrttls); ++i) {
696 if (records[i].ttl < 0)
698 *ttl = std::min(
unsigned(records[i].ttl), *ttl);
700 char addrstr[INET6_ADDRSTRLEN];
701 const void *retval_p =
702 inet_ntop(AF_INET6, &(records[i].ip6addr), addrstr, INET6_ADDRSTRLEN);
705 addresses->push_back(addrstr);
707 if (addresses->empty())
721 const bool ipv4_only,
723 const unsigned timeout_ms)
724 :
Resolver(ipv4_only, retries, timeout_ms)
726 , lookup_options_(strdup(
"b"))
744 const bool ipv4_only,
746 const unsigned timeout_ms)
749 if (getenv(
"HOSTALIASES") == NULL) {
750 retval = setenv(
"HOSTALIASES",
"/etc/hosts", 1);
755 resolver->
channel_ =
reinterpret_cast<ares_channel *
>(
756 smalloc(
sizeof(ares_channel)));
757 memset(resolver->
channel_, 0,
sizeof(ares_channel));
759 struct ares_addr_node *addresses;
760 struct ares_addr_node *iter;
761 struct ares_options options;
763 memset(&options, 0,
sizeof(options));
767 optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_LOOKUPS;
768 retval = ares_init_options(resolver->
channel_, &options, optmask);
769 if (retval != ARES_SUCCESS)
773 retval = ares_save_options(*resolver->
channel_, &options, &optmask);
774 if (retval != ARES_SUCCESS)
776 for (
int i = 0; i < options.ndomains; ++i) {
777 resolver->
domains_.push_back(options.domains[i]);
779 ares_destroy_options(&options);
784 retval = ares_get_servers(*resolver->
channel_, &addresses);
785 if (retval != ARES_SUCCESS)
789 switch (iter->family) {
791 char addrstr[INET_ADDRSTRLEN];
792 const void *retval_p =
793 inet_ntop(AF_INET, &(iter->addr), addrstr, INET_ADDRSTRLEN);
796 "invalid system name resolver");
798 resolver->
resolvers_.push_back(
string(addrstr) +
":53");
803 char addrstr[INET6_ADDRSTRLEN];
804 const void *retval_p =
805 inet_ntop(AF_INET6, &(iter->addr), addrstr, INET6_ADDRSTRLEN);
808 "invalid system name resolver");
810 resolver->
resolvers_.push_back(
"[" +
string(addrstr) +
"]:53");
820 ares_free_data(addresses);
827 "failed to initialize c-ares resolver (%d - %s)",
828 retval, ares_strerror(retval));
841 const vector<string> &names,
842 const vector<bool> &skip,
843 vector<vector<string> > *ipv4_addresses,
844 vector<vector<string> > *ipv6_addresses,
845 vector<Failures> *failures,
846 vector<unsigned> *ttls,
847 vector<string> *fqdns)
849 unsigned num = names.size();
853 vector<QueryInfo *> infos_ipv4(num, NULL);
854 vector<QueryInfo *> infos_ipv6(num, NULL);
856 for (
unsigned i = 0; i < num; ++i) {
861 infos_ipv6[i] =
new QueryInfo(&(*ipv6_addresses)[i], names[i],
kRrAaaa);
862 ares_search(*
channel_, names[i].c_str(), ns_c_in, ns_t_aaaa,
865 infos_ipv4[i] =
new QueryInfo(&(*ipv4_addresses)[i], names[i],
kRrA);
866 ares_search(*
channel_, names[i].c_str(), ns_c_in, ns_t_a,
874 for (
unsigned i = 0; i < num; ++i) {
875 if ((infos_ipv4[i] && !infos_ipv4[i]->complete) ||
876 (infos_ipv6[i] && !infos_ipv6[i]->complete))
878 all_complete =
false;
882 }
while (!all_complete);
886 for (
unsigned i = 0; i < num; ++i) {
891 (*ttls)[i] = unsigned(-1);
894 status = infos_ipv6[i]->status;
896 (*ttls)[i] = std::min(infos_ipv6[i]->ttl, (*ttls)[i]);
897 (*fqdns)[i] = infos_ipv6[i]->fqdn;
901 (*ttls)[i] = std::min(infos_ipv4[i]->ttl, (*ttls)[i]);
902 if ((*fqdns)[i] ==
"")
903 (*fqdns)[i] = infos_ipv4[i]->fqdn;
905 status = infos_ipv4[i]->status;
907 (*failures)[i] = status;
910 for (
unsigned i = 0; i < num; ++i) {
911 delete infos_ipv4[i];
912 delete infos_ipv6[i];
919 int retval = ares_set_servers_csv(*
channel_, address_list.c_str());
920 if (retval != ARES_SUCCESS)
943 int socket_send_buffer_size;
944 int socket_receive_buffer_size;
950 memcpy(&ares_channelhead, *
channel_,
sizeof(ares_channelhead));
951 if (ares_channelhead.domains) {
952 for (
int i = 0; i < ares_channelhead.ndomains; ++i) {
953 free(ares_channelhead.domains[i]);
955 free(ares_channelhead.domains);
956 ares_channelhead.domains = NULL;
959 ares_channelhead.ndomains =
static_cast<int>(domains.size());
960 if (ares_channelhead.ndomains > 0) {
961 ares_channelhead.domains =
reinterpret_cast<char **
>(
962 smalloc(ares_channelhead.ndomains *
sizeof(
char *)));
963 for (
int i = 0; i < ares_channelhead.ndomains; ++i) {
964 ares_channelhead.domains[i] = strdup(domains[i].c_str());
968 memcpy(*
channel_, &ares_channelhead,
sizeof(ares_channelhead));
993 ares_socket_t socks[ARES_GETSOCK_MAXNUM];
994 struct pollfd pfd[ARES_GETSOCK_MAXNUM];
995 int bitmask = ares_getsock(*
channel_, socks, ARES_GETSOCK_MAXNUM);
997 for (
unsigned i = 0; i < ARES_GETSOCK_MAXNUM; ++i) {
1000 if (ARES_GETSOCK_READABLE(bitmask, i)) {
1001 pfd[i].fd = socks[i];
1002 pfd[i].events |= POLLRDNORM|POLLIN;
1004 if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
1005 pfd[i].fd = socks[i];
1006 pfd[i].events |= POLLWRNORM|POLLOUT;
1008 if (pfd[i].events != 0)
1020 if ((errno != EAGAIN) && (errno != EINTR))
1023 }
while (nfds == -1);
1029 ares_process_fd(*
channel_, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
1032 for (
unsigned i = 0; i < num; ++i) {
1034 pfd[i].revents & (POLLRDNORM|POLLIN) ?
1035 pfd[i].fd : ARES_SOCKET_BAD,
1036 pfd[i].revents & (POLLWRNORM|POLLOUT) ?
1037 pfd[i].fd : ARES_SOCKET_BAD);
1057 string hosts_file = path;
1058 if (hosts_file ==
"") {
1059 char *hosts_env = getenv(
"HOST_ALIASES");
1060 if (hosts_env != NULL) {
1061 hosts_file = string(hosts_env);
1063 hosts_file =
"/etc/hosts";
1066 resolver->
fhosts_ = fopen(hosts_file.c_str(),
"r");
1069 hosts_file.c_str());
1083 unsigned len_a = a.length();
1084 unsigned len_b = b.length();
1086 return len_a > len_b;
1095 const vector<string> &names,
1096 const vector<bool> &skip,
1097 vector< vector<std::string> > *ipv4_addresses,
1098 vector< vector<std::string> > *ipv6_addresses,
1099 vector<Failures> *failures,
1100 vector<unsigned> *ttls,
1101 vector<string> *fqdns)
1103 unsigned num = names.size();
1108 for (
unsigned i = 0; i < num; ++i) {
1112 vector<string> effective_names;
1113 if (!names[i].empty() && (names[i][names[i].length()-1] ==
'.')) {
1114 effective_names.push_back(names[i].substr(0, names[i].length()-1));
1116 effective_names.push_back(names[i]);
1117 for (
unsigned j = 0; j <
domains().size(); ++j) {
1118 effective_names.push_back(names[i] +
"." +
domains()[j]);
1123 std::sort(effective_names.begin(), effective_names.end(),
SortNameLength);
1126 (*fqdns)[i] = names[i];
1127 for (
unsigned j = 0; j < effective_names.size(); ++j) {
1128 map<string, HostEntry>::iterator iter =
1131 (*ipv4_addresses)[i].insert((*ipv4_addresses)[i].end(),
1132 iter->second.ipv4_addresses.begin(),
1133 iter->second.ipv4_addresses.end());
1134 (*ipv6_addresses)[i].insert((*ipv6_addresses)[i].end(),
1135 iter->second.ipv6_addresses.begin(),
1136 iter->second.ipv6_addresses.end());
1138 (*fqdns)[i] = effective_names[j];
1172 size_t str_offset = 0;
1175 size_t hash_pos = line.find_first_of(
'#');
1176 if (hash_pos != string::npos) line = line.substr(0, hash_pos);
1179 int ip_start_pos = -1, ip_end_pos = -1, scan_result;
1180 scan_result = sscanf(line.c_str(),
" %n%*s%n", &ip_start_pos, &ip_end_pos);
1181 if (scan_result == EOF)
1183 assert(ip_start_pos != -1);
1184 assert(ip_end_pos != -1);
1185 if (ip_start_pos == ip_end_pos)
1189 "Skipping line in hosts file due to invalid IP address format: %s",
1195 scan_result = sscanf(line.c_str(),
" %s%n", address, &bytes_read);
1196 assert(scan_result == 1);
1197 assert(bytes_read != -1);
1198 str_offset += bytes_read;
1201 while (str_offset < line.length()) {
1203 int hostname_start_pos = -1, hostname_end_pos = -1;
1204 scan_result = sscanf(line.c_str() + str_offset,
" %n%*s%n",
1205 &hostname_start_pos, &hostname_end_pos);
1206 if (scan_result == EOF)
1208 assert(hostname_start_pos != -1);
1209 assert(hostname_end_pos != -1);
1210 if (hostname_start_pos == hostname_end_pos)
1215 "Skipping invalid (too long) hostname in hosts file on line: %s",
1217 str_offset += hostname_end_pos;
1222 scan_result = sscanf(line.c_str() + str_offset,
" %s%n", hostname,
1224 assert(scan_result == 1);
1225 assert(bytes_read != -1);
1226 str_offset += bytes_read;
1228 if (hostname[strlen(hostname)-1] ==
'.')
1229 hostname[strlen(hostname)-1] = 0;
1231 map<string, HostEntry>::iterator iter =
host_map_.find(hostname);
1243 if (!
ipv4_only()) iter->second.ipv6_addresses.push_back(address);
1270 const bool ipv4_only,
1272 const unsigned timeout_ms)
1276 if (!cares_resolver)
1279 if (!hostfile_resolver) {
1280 delete cares_resolver;
1293 return normal_resolver;
1341 const vector<string> &names,
1342 const vector<bool> &skip,
1343 vector< vector<string> > *ipv4_addresses,
1344 vector< vector<string> > *ipv6_addresses,
1345 vector<Failures> *failures,
1346 vector<unsigned> *ttls,
1347 vector<string> *fqdns)
1349 unsigned num = names.size();
1351 failures, ttls, fqdns);
1352 vector<bool> skip_cares = skip;
1353 for (
unsigned i = 0; i < num; ++i) {
1354 if ((*failures)[i] ==
kFailOk)
1355 skip_cares[i] =
true;
1358 failures, ttls, fqdns);
1364 , cares_resolver_(NULL)
1365 , 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,...)