OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
address_util.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 #include "base/address_util.h"
5 
6 #include <endian.h>
7 #include <boost/algorithm/string.hpp>
8 #include <boost/asio/io_service.hpp>
9 #include <boost/asio/ip/tcp.hpp>
10 #include <boost/asio/ip/host_name.hpp>
11 #include <boost/foreach.hpp>
12 
13 /* Returns true if the given IPv4 address is member of the IPv4 subnet
14  * indicated by IPv4 address and prefix length. Otherwise returns false.
15  * We convert both the input IPv4 addresses to their subnet addresses and
16  * then compare with each other to conclude whether the IPv4 address is
17  * member of the subnet or not.
18  */
20  const Ip4Address &ip, const Ip4Address &prefix_ip, uint16_t plen) {
21  Ip4Address prefix = Address::GetIp4SubnetAddress(prefix_ip, plen);
22  return ((prefix.to_ulong() | ~(0xFFFFFFFF << (32 - plen))) ==
23  (ip.to_ulong() | ~(0xFFFFFFFF << (32 - plen))));
24 }
25 
26 /* Returns true if the given IPv6 address is member of the IPv6 subnet
27  * indicated by IPv6 address and prefix length. Otherwise returns false.
28  */
30  const Ip6Address &ip, const Ip6Address &subnet, uint8_t plen) {
31  Ip6Address mask = Address::GetIp6SubnetAddress(subnet, plen);
33  return (ip1 == mask);
34 }
35 
36 /*
37  * Returns the canonical hostname (FQDN)
38 */
39 
40 std::string ResolveCanonicalName()
41 {
42  boost::asio::io_context io_service;
43  boost::system::error_code error;
44  boost::asio::ip::tcp::resolver resolver (io_service);
45  boost::asio::ip::tcp::resolver::query query(boost::asio::ip::host_name(),
46  "", boost::asio::ip::resolver_query_base::canonical_name);
47  boost::asio::ip::tcp::resolver::iterator iter =
48  resolver.resolve (query,error), end;
49  if (error) {
50  return boost::asio::ip::host_name();
51  }
52  while (iter != end) {
53  if (iter->host_name() != "") {
54  return iter->host_name();
55  }
56  iter++;
57  }
58  return boost::asio::ip::host_name();
59 }
60 
61 /*
62  * Returns the canonical hostname (FQDN) by IPv4 address
63 */
64 std::string ResolveCanonicalName(const std::string& ipv4)
65 {
66  if (boost::starts_with(ipv4, "127."))
67  return "localhost";
68  boost::asio::ip::tcp::endpoint endpoint;
69  boost::asio::io_context io_service;
70  boost::asio::ip::address_v4 ip =
71  boost::asio::ip::address_v4::from_string(ipv4);
72  endpoint.address(ip);
73  boost::asio::ip::tcp::resolver resolver(io_service);
74  boost::asio::ip::tcp::resolver::iterator iter =
75  resolver.resolve (endpoint), end;
76  while (iter != end){
77  if(iter->host_name() != ""){
78  return iter->host_name();
79  }
80  iter++;
81  }
82  return boost::asio::ip::host_name();
83 }
84 
85 /* This variant passes all tests
86  * To be covered by more tests later
87  * Returns the canonical hostname (FQDN) by IPv6 address
88 */
89 std::string ResolveCanonicalNameIPv6(const std::string& ipv6)
90 {
91  std::string loc_ip = ipv6;
92  if (boost::starts_with(loc_ip, "::1"))
93  return "localhost";
94  unsigned int perc_pos = loc_ip.find("%");
95  if (perc_pos != std::string::npos) {
96  loc_ip = loc_ip.substr(0,perc_pos);
97  }
98  return loc_ip;
99 // Next code is incompatible with schema_transformer:
100 // boost::asio::ip::tcp::endpoint endpoint;
101 // boost::asio::io_context io_service;
102 // boost::asio::ip::address_v6 ip =
103 // boost::asio::ip::address_v6::from_string(loc_ip);
104 // endpoint.address(ip);
105 // boost::asio::ip::tcp::resolver resolver(io_service);
106 // boost::asio::ip::tcp::resolver::iterator iter =
107 // resolver.resolve (endpoint), end;
108 // while (iter != end){
109 // if(iter->host_name() != ""){
110 // return iter->host_name();
111 // }
112 // iter++;
113 // }
114 // return boost::asio::ip::host_name();
115 }
116 
117 /*
118  * Returns boost::asio::ip::address if given string is either valid
119  * IPv4, IPv6 or a resolvable FQDN
120 */
121 
123  const std::string &ip_address_str,
124  boost::system::error_code *ec) {
125  IpAddress addr =
126  boost::asio::ip::address::from_string(ip_address_str, *ec);
127  boost::system::error_code error_code = *ec;
128  if (error_code.value() != 0) {
129  boost::asio::io_context io_service;
130  std::string ip_string = GetHostIp(&io_service, ip_address_str);
131  addr = boost::asio::ip::address::from_string(ip_string, *ec);
132  }
133  return addr;
134 }
135 
137  const Ip4Address &ip_prefix, uint16_t plen) {
138  Ip4Address subnet(ip_prefix.to_ulong() | ~(0xFFFFFFFF << (32 - plen)));
139  return subnet;
140 }
141 
142 // Validate IPv4/IPv6 address string.
143 bool ValidateIPAddressString(std::string ip_address_str,
144  std::string *error_msg) {
145  boost::system::error_code error;
146  AddressFromString(ip_address_str, &error);
147  if (error.value() != 0) {
148  std::ostringstream out;
149  out << "Invalid IP address: " << ip_address_str << std::endl;
150  *error_msg = out.str();
151  return false;
152  }
153  return true;
154 }
155 
156 IpAddress PrefixToIpNetmask(uint32_t prefix_len) {
157  uint32_t mask;
158 
159  if (prefix_len == 0) {
160  mask = 0;
161  } else {
162  mask = (~((1 << (32 - prefix_len)) - 1));
163  }
164  return IpAddress(Ip4Address(mask));
165 }
166 
167 uint32_t NetmaskToPrefix(uint32_t netmask) {
168  uint32_t count = 0;
169 
170  while (netmask) {
171  count++;
172  netmask = (netmask - 1) & netmask;
173  }
174  return count;
175 }
176 
178  if (plen == 0) {
179  return IpAddress(Ip6Address());
180  }
181 
182  if (plen == 128) {
183  boost::system::error_code ec;
184  Ip6Address all_fs = Ip6Address::from_string
185  ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", ec);
186  return IpAddress(all_fs);
187  }
188 
189  Ip6Address::bytes_type bytes;
190 
191  int index = (int) (plen / 8);
192  int remain_mask = plen % 8;
193 
194  for (int i = 0; i < index; i++) {
195  bytes.at(i) = 0xff;
196  }
197 
198  switch (remain_mask) {
199  case 0:
200  bytes.at(index++) = 0;
201  break;
202  case 1:
203  bytes.at(index++) = 0x80;
204  break;
205  case 2:
206  bytes.at(index++) = 0xc0;
207  break;
208  case 3:
209  bytes.at(index++) = 0xe0;
210  break;
211  case 4:
212  bytes.at(index++) = 0xf0;
213  break;
214  case 5:
215  bytes.at(index++) = 0xf8;
216  break;
217  case 6:
218  bytes.at(index++) = 0xfc;
219  break;
220  case 7:
221  bytes.at(index++) = 0xfe;
222  break;
223  }
224 
225  for (int i = index; i < 16; ++i) {
226  bytes.at(i) = 0;
227  }
228 
229  return IpAddress(Ip6Address(bytes));
230 }
231 
232 // Validate a list of <ip-address>:<port> endpoints.
233 bool ValidateServerEndpoints(std::vector<std::string> list,
234  std::string *error_msg) {
235  std::ostringstream out;
236 
237  BOOST_FOREACH(std::string endpoint, list) {
238  std::vector<std::string> tokens;
239  boost::split(tokens, endpoint, boost::is_any_of(":"));
240  if (tokens.size() != 2) {
241  out << "Invalid endpoint " << endpoint << std::endl;
242  *error_msg = out.str();
243  return false;
244  }
245 
246  boost::system::error_code error;
247  AddressFromString(tokens[0], &error);
248 
249  if (error) {
250  out << "Invalid IP address: " << tokens[0] << std::endl;
251  *error_msg = out.str();
252  return false;
253  }
254 
255  unsigned long port = strtoul(tokens[1].c_str(), NULL, 0);
256  if (errno || port > 0xffFF) {
257  out << "Invalid port : " << tokens[1];
258  if (errno) {
259  out << " " << strerror(errno) << std::endl;
260  }
261  *error_msg = out.str();
262  return false;
263  }
264  }
265 
266  return true;
267 }
268 
269 // Return IP address string for a host if it is resolvable, empty string
270 // otherwise.
271 std::string GetHostIp(boost::asio::io_context *io_service,
272  const std::string &hostname) {
273  boost::asio::ip::tcp::resolver::iterator iter, end;
274  boost::system::error_code error;
275  boost::asio::ip::tcp::resolver resolver(*io_service);
276  boost::asio::ip::tcp::resolver::query query(hostname, "");
277 
278  std::string result;
279 
280  iter = resolver.resolve(query, error);
281  if (error) {
282  return result;
283  }
284 
285  for (; iter != end; ++iter) {
286  const boost::asio::ip::address &addr = iter->endpoint().address();
287  if (addr.is_v6()) {
288  boost::asio::ip::address_v6 addr6 = addr.to_v6();
289  if (addr6.is_link_local()) {
290  continue;
291  }
292  }
293  result = addr.to_string();
294  if (addr.is_v4()) {
295  return result;
296  }
297  }
298  return result;
299 }
300 
301 //
302 // Get VN name from routing instance
303 //
304 std::string GetVNFromRoutingInstance(const std::string &vn) {
305  std::vector<std::string> tokens;
306  boost::split(tokens, vn, boost::is_any_of(":"), boost::token_compress_on);
307  if (tokens.size() < 3) return "";
308  return tokens[0] + ":" + tokens[1] + ":" + tokens[2];
309 }
310 
311 void IpToU64(const IpAddress &sip, const IpAddress &dip,
312  uint64_t *sip_u, uint64_t *sip_l,
313  uint64_t *dip_u, uint64_t *dip_l) {
314  if (sip.is_v4()) {
315  *sip_l = htonl(sip.to_v4().to_ulong());
316  *sip_u = 0;
317  } else {
318  uint64_t data[2];
319  Ip6AddressToU64Array(sip.to_v6(), data, 2);
320  *sip_u = data[0];
321  *sip_l = data[1];
322  }
323 
324  if (dip.is_v4()) {
325  *dip_l = htonl(dip.to_v4().to_ulong());
326  *dip_u = 0;
327  } else {
328  uint64_t data[2];
329  Ip6AddressToU64Array(dip.to_v6(), data, 2);
330  *dip_u = data[0];
331  *dip_l = data[1];
332  }
333 }
334 
335 void U64ToIpv6(uint64_t upper, uint64_t lower, IpAddress *ip) {
336  boost::asio::ip::address_v6::bytes_type bytes;
337  const unsigned char *ptr = (const unsigned char *)&lower;
338  for (unsigned int i = 0; i < sizeof(uint64_t); i++) {
339  bytes[i] = ptr[i];
340  }
341  ptr = (const unsigned char *)&upper;
342  for (unsigned int i = 0; i < sizeof(uint64_t); i++) {
343  bytes[8 + i] = ptr[i];
344  }
345  *ip = Ip6Address(bytes);
346 }
347 
348 void U64ToIp(uint64_t sip_u, uint64_t sip_l, uint64_t dip_u, uint64_t dip_l,
349  int family, IpAddress *sip, IpAddress *dip) {
350  if (family == Address::INET) {
351  *sip = Ip4Address(ntohl(sip_l & 0xFFFFFFFF));
352  *dip = Ip4Address(ntohl(dip_l & 0xFFFFFFFF));
353  } else {
354  U64ToIpv6(sip_u, sip_l, sip);
355  U64ToIpv6(dip_u, dip_l, dip);
356  }
357 }
358 
359 void Ip6AddressToU64Array(const Ip6Address &addr, uint64_t *arr, int size) {
360  unsigned char b[16];
361  uint64_t ip;
362  unsigned int i, j, k;
363 
364  if (size != 2)
365  return;
366 
367  memcpy(b, addr.to_bytes().data(), sizeof(b));
368 
369  for (i = 0, j = 0, k = 0; i < 4; i++, j = j+4) {
370  ip = 0;
371 
372  ip = ((((uint32_t)b[j]) << 24) & 0xFF000000) |
373  ((((uint32_t)b[j+1]) << 16) & 0x00FF0000) |
374  ((((uint32_t)b[j+2]) << 8) & 0x0000FF00) |
375  (((uint32_t)b[j+3]) & 0x000000FF);
376 
377  if (i >= 2)
378  k = 1;
379 
380  if (i%2) {
381  arr[k] = arr[k] | (ip & 0x00000000FFFFFFFFU);
382  } else {
383  arr[k] = (ip << 32) & 0xFFFFFFFF00000000U;
384  }
385  }
386 
387 
388  arr[0] = htobe64(arr[0]);
389  arr[1] = htobe64(arr[1]);
390 }
391 
392 std::string VectorIpv6ToString(const std::vector<signed char> &ipv6) {
393 
394  if (ipv6.size() != 16) {
395  return "0000:0000:0000:0000";
396  }
397  std::ostringstream strm;
398  int count = 1;
399  for(std::vector<signed char>::const_iterator it = ipv6.begin();
400  it != ipv6.end(); ++it) {
401  strm << std::hex << (int)((uint8_t) *it);
402  if((count % 4) ==0)
403  strm << ":";
404  count++;
405  }
406  return strm.str();
407 }
Ip4Address GetIp4SubnetBroadcastAddress(const Ip4Address &ip_prefix, uint16_t plen)
bool IsIp4SubnetMember(const Ip4Address &ip, const Ip4Address &prefix_ip, uint16_t plen)
Definition: address_util.cc:19
void IpToU64(const IpAddress &sip, const IpAddress &dip, uint64_t *sip_u, uint64_t *sip_l, uint64_t *dip_u, uint64_t *dip_l)
boost::asio::ip::address IpAddress
Definition: address.h:13
std::string GetVNFromRoutingInstance(const std::string &vn)
void U64ToIpv6(uint64_t upper, uint64_t lower, IpAddress *ip)
bool ValidateServerEndpoints(std::vector< std::string > list, std::string *error_msg)
static Ip4Address GetIp4SubnetAddress(const Ip4Address &prefix, uint16_t plen)
Definition: address.cc:179
static Ip6Address GetIp6SubnetAddress(const Ip6Address &prefix, uint16_t plen)
Definition: address.cc:200
std::string ResolveCanonicalNameIPv6(const std::string &ipv6)
Definition: address_util.cc:89
boost::asio::ip::address_v6 Ip6Address
Definition: address.h:15
std::string VectorIpv6ToString(const std::vector< signed char > &ipv6)
void Ip6AddressToU64Array(const Ip6Address &addr, uint64_t *arr, int size)
IpAddress PrefixToIp6Netmask(uint32_t plen)
std::string ResolveCanonicalName()
Definition: address_util.cc:40
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
IpAddress AddressFromString(const std::string &ip_address_str, boost::system::error_code *ec)
bool ValidateIPAddressString(std::string ip_address_str, std::string *error_msg)
std::string GetHostIp(boost::asio::io_context *io_service, const std::string &hostname)
void U64ToIp(uint64_t sip_u, uint64_t sip_l, uint64_t dip_u, uint64_t dip_l, int family, IpAddress *sip, IpAddress *dip)
uint32_t NetmaskToPrefix(uint32_t netmask)
IpAddress PrefixToIpNetmask(uint32_t prefix_len)
bool IsIp6SubnetMember(const Ip6Address &ip, const Ip6Address &subnet, uint8_t plen)
Definition: address_util.cc:29