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