irods  4.2.8
About: iRODS (the integrated Rule Oriented Data System) is a distributed data-management system for creating data grids, digital libraries, persistent archives, and real-time data systems.
  Fossies Dox: irods-4.2.8.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

irods_hostname.cpp
Go to the documentation of this file.
1 #include <arpa/inet.h>
2 #include <ifaddrs.h>
3 #include <iostream>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <netdb.h>
7 #include <cstring>
8 #include <algorithm>
9 #include <cerrno>
10 #include <array>
11 #include <utility>
12 #include <iterator>
13 #include <vector>
14 #include <thread>
15 #include <chrono>
16 
17 #include "irods_exception.hpp"
18 #include "rodsErrorTable.h"
19 #include "rodsLog.h"
20 
21 bool
22 operator==(const struct in_addr& lhs, const struct in_addr& rhs) {
23  return lhs.s_addr == rhs.s_addr;
24 }
25 
26 bool
27 operator==(const struct in6_addr& lhs, const struct in6_addr& rhs) {
28  return std::equal(std::begin(lhs.s6_addr), std::end(lhs.s6_addr), std::begin(rhs.s6_addr));
29 }
30 
31 namespace {
32  std::string
33  to_string(const struct in_addr& address) {
34  std::array<char, INET_ADDRSTRLEN> display_address;
35  const char* ntop_ret = inet_ntop(AF_INET, &address, display_address.data(), sizeof(display_address));
36  if (ntop_ret) {
37  return ntop_ret;
38  } else {
39  std::stringstream s;
40  s << "inet_ntop failed: " << errno;
41  THROW( SYS_INTERNAL_ERR, s.str() );
42  }
43  }
44 
45  std::string
46  to_string(const struct in6_addr& address) {
47  std::array<char, INET6_ADDRSTRLEN> display_address;
48  const char* ntop_ret = inet_ntop(AF_INET6, &address, display_address.data(), sizeof(display_address));
49  if (ntop_ret) {
50  return ntop_ret;
51  } else {
52  std::stringstream s;
53  s << "inet_ntop failed: " << errno;
54  THROW( SYS_INTERNAL_ERR, s.str() );
55  }
56  }
57 
58 
59 
60  bool
61  is_loopback(const struct in_addr& v4_addr) {
62  return (ntohl(v4_addr.s_addr) & 0xFF000000) == 0x7F000000;
63  }
64 
65 // as of 1.60, boost::asio::ip::address_v6::is_loopback() does not check for ipv4-mapped loopback
66  bool
67  is_loopback(const struct in6_addr& v6_addr) {
68  const unsigned char (&addr_bytes)[16] = v6_addr.s6_addr;
69  const bool is_v6_loopback =
70  addr_bytes[ 0] == 0 && addr_bytes[ 1] == 0 && addr_bytes[ 2] == 0 && addr_bytes[ 3] == 0 &&
71  addr_bytes[ 4] == 0 && addr_bytes[ 5] == 0 && addr_bytes[ 6] == 0 && addr_bytes[ 7] == 0 &&
72  addr_bytes[ 8] == 0 && addr_bytes[ 9] == 0 && addr_bytes[10] == 0 && addr_bytes[11] == 0 &&
73  addr_bytes[12] == 0 && addr_bytes[13] == 0 && addr_bytes[14] == 0 && addr_bytes[15] == 1;
74  const bool is_v4_mapped_loopback =
75  addr_bytes[ 0] == 0 && addr_bytes[ 1] == 0 && addr_bytes[ 2] == 0 && addr_bytes[ 3] == 0 &&
76  addr_bytes[ 4] == 0 && addr_bytes[ 5] == 0 && addr_bytes[ 6] == 0 && addr_bytes[ 7] == 0 &&
77  addr_bytes[ 8] == 0 && addr_bytes[ 9] == 0 && addr_bytes[10] == 255 && addr_bytes[11] == 255 &&
78  addr_bytes[12] == 127;
79  return is_v6_loopback || is_v4_mapped_loopback;
80  }
81 
82  std::pair<std::vector<struct in_addr>, std::vector<struct in6_addr>>
83  get_local_ipv4_and_ipv6_addresses() {
84  std::pair<std::vector<struct in_addr>, std::vector<struct in6_addr>> ret;
85 
86  struct ifaddrs* addrs;
87  const int getifa_ret = getifaddrs(&addrs);
88  if (getifa_ret == 0) {
89  struct ifaddrs* tmp = addrs;
90  while (tmp) {
91  if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) {
92  struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
93  ret.first.push_back(pAddr->sin_addr);
94  } else if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) {
95  struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr;
96  ret.second.push_back(pAddr->sin6_addr);
97  }
98  tmp = tmp->ifa_next;
99  }
100  freeifaddrs(addrs);
101  } else {
102  std::stringstream s;
103  s << "getifaddrs failed, errno: " << errno;
104  THROW( SYS_INTERNAL_ERR, s.str() );
105  }
106  return ret;
107  }
108 
109  void
110  print_local_ipv4_and_ipv6_addresses(void) {
111  auto ipv4_and_ipv6_addresses = get_local_ipv4_and_ipv6_addresses();
112  for (const auto& v4_addr : ipv4_and_ipv6_addresses.first) {
113  std::cout << to_string(v4_addr) << std::endl;
114  }
115  for (const auto& v6_addr : ipv4_and_ipv6_addresses.second) {
116  std::cout << to_string(v6_addr) << std::endl;
117  }
118  }
119 
120  int
121  getaddrinfo_with_retry(const char* node, const char* service,
122  const struct addrinfo* hints, struct addrinfo **res) {
123  const int max_retry = 50;
124  for (int i=0; i<max_retry; ++i) {
125  const int gai_ret = getaddrinfo(node, service, hints, res);
126  if (gai_ret != EAI_AGAIN) {
127  return gai_ret;
128  }
129  std::this_thread::sleep_for(std::chrono::milliseconds(10));
130  }
131  return EAI_AGAIN;
132  }
133 
134  std::pair<std::vector<struct in_addr>, std::vector<struct in6_addr>>
135  get_remote_ipv4_and_ipv6_addresses(const char* hostname) {
136  std::pair<std::vector<struct in_addr>, std::vector<struct in6_addr>> ret;
137 
138  struct addrinfo hints;
139  std::memset(&hints, 0, sizeof(hints));
140  hints.ai_family = AF_UNSPEC;
141  hints.ai_socktype = SOCK_STREAM;
142  hints.ai_protocol = IPPROTO_TCP;
143  hints.ai_flags = 0;
144  struct addrinfo *res;
145  const int gai_ret = getaddrinfo_with_retry(hostname, nullptr, &hints, &res);
146  if (gai_ret==0) {
147  struct addrinfo* p = res;
148  while (p) {
149  if (p->ai_family == AF_INET) {
150  struct sockaddr_in* sinp = reinterpret_cast<struct sockaddr_in*>(p->ai_addr);
151  ret.first.push_back(sinp->sin_addr);
152  } else if (p->ai_family == AF_INET6) {
153  struct sockaddr_in6* sin6p = reinterpret_cast<struct sockaddr_in6*>(p->ai_addr);
154  ret.second.push_back(sin6p->sin6_addr);
155  } else {
156  rodsLog( LOG_ERROR, "unknown ai_family: %d", p->ai_family );
157  }
158  p = p->ai_next;
159  }
160  freeaddrinfo(res);
161  } else {
162  std::stringstream s;
163  s << "gai error: " << gai_ret << " " << gai_strerror(gai_ret);
164  THROW( SYS_INTERNAL_ERR, s.str() );
165  }
166  return ret;
167  }
168 
169  void
170  print_remote_ipv4_and_ipv6_addresses(const char* hostname) {
171  auto ipv4_and_ipv6_addresses = get_remote_ipv4_and_ipv6_addresses(hostname);
172  for (const auto& v4_addr : ipv4_and_ipv6_addresses.first) {
173  std::cout << to_string(v4_addr) << std::endl;
174  }
175 
176  for (const auto& v6_addr : ipv4_and_ipv6_addresses.second) {
177  std::cout << to_string(v6_addr) << std::endl;
178  }
179  }
180 
181  template <typename T>
182  bool resolves_local(const std::vector<T>& local_addresses, const std::vector<T>& remote_addresses) {
183  for (const auto& remote_address : remote_addresses) {
184  if (is_loopback(remote_address)) {
185  return true;
186  }
187  if (std::find(local_addresses.cbegin(), local_addresses.cend(), remote_address) != local_addresses.cend()) {
188  return true;
189  }
190  }
191  return false;
192  }
193 }
194 
195 bool
196 hostname_resolves_to_local_address(const char* hostname) {
197  const auto remote_addresses = get_remote_ipv4_and_ipv6_addresses(hostname);
198  const auto local_addresses = get_local_ipv4_and_ipv6_addresses();
199  if (resolves_local(local_addresses.first, remote_addresses.first)) {
200  return true;
201  }
202  if (resolves_local(local_addresses.second, remote_addresses.second)) {
203  return true;
204  }
205  return false;
206 }
rodsLog
void rodsLog(int level, const char *formatStr,...)
Definition: rodsLog.cpp:86
THROW
#define THROW(_code, _msg)
Definition: irods_exception.hpp:68
irods_exception.hpp
pid_age.p
p
Definition: pid_age.py:13
node
Definition: restructs.hpp:244
LOG_ERROR
#define LOG_ERROR
Definition: rodsLog.h:43
SYS_INTERNAL_ERR
@ SYS_INTERNAL_ERR
Definition: rodsErrorTable.h:211
irods::experimental::filesystem::client::end
auto end(const collection_iterator &) noexcept -> const collection_iterator
Definition: collection_iterator.hpp:88
irods::experimental::filesystem::client::begin
auto begin(collection_iterator _iter) noexcept -> collection_iterator
Definition: collection_iterator.hpp:83
hostname_resolves_to_local_address
bool hostname_resolves_to_local_address(const char *hostname)
Definition: irods_hostname.cpp:196
rodsLog.h
getaddrinfo_with_retry
int getaddrinfo_with_retry(const char *_node, const char *_service, const struct addrinfo *_hints, struct addrinfo **_res)
Definition: rcMisc.cpp:4537
rodsErrorTable.h
operator==
bool operator==(const struct in_addr &lhs, const struct in_addr &rhs)
Definition: irods_hostname.cpp:22