blob: 3f7698acb3bed64a624ecc30c4602759f9272834 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#if defined(WEBRTC_POSIX)
12#include <sys/types.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#ifdef OPENBSD
16#include <netinet/in_systm.h>
17#endif
18#ifndef __native_client__
19#include <netinet/ip.h>
20#endif
21#include <arpa/inet.h>
22#include <netdb.h>
23#include <unistd.h>
24#endif
25
26#include <stdio.h>
27
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/byteorder.h"
29#include "rtc_base/checks.h"
30#include "rtc_base/ipaddress.h"
31#include "rtc_base/logging.h"
32#include "rtc_base/nethelpers.h"
33#include "rtc_base/stringutils.h"
Mirko Bonadeie0623852018-02-01 11:17:40 +010034
35#if defined(WEBRTC_WIN)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "rtc_base/win32.h"
Mirko Bonadeie0623852018-02-01 11:17:40 +010037#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000038
39namespace rtc {
40
41// Prefixes used for categorizing IPv6 addresses.
42static const in6_addr kV4MappedPrefix = {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 0xFF, 0xFF, 0}}};
44static const in6_addr k6To4Prefix = {{{0x20, 0x02, 0}}};
45static const in6_addr kTeredoPrefix = {{{0x20, 0x01, 0x00, 0x00}}};
46static const in6_addr kV4CompatibilityPrefix = {{{0}}};
47static const in6_addr k6BonePrefix = {{{0x3f, 0xfe, 0}}};
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +010048static const in6_addr kPrivateNetworkPrefix = {{{0xFD}}};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +010050static bool IPIsHelper(const IPAddress& ip,
51 const in6_addr& tomatch, int length);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000052static in_addr ExtractMappedAddress(const in6_addr& addr);
53
Peter Boström0c4e06b2015-10-07 12:23:21 +020054uint32_t IPAddress::v4AddressAsHostOrderInteger() const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055 if (family_ == AF_INET) {
56 return NetworkToHost32(u_.ip4.s_addr);
57 } else {
58 return 0;
59 }
60}
61
Guo-wei Shieh11477022015-08-15 09:28:41 -070062bool IPAddress::IsNil() const {
63 return IPIsUnspec(*this);
64}
65
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066size_t IPAddress::Size() const {
67 switch (family_) {
68 case AF_INET:
69 return sizeof(in_addr);
70 case AF_INET6:
71 return sizeof(in6_addr);
72 }
73 return 0;
74}
75
76
77bool IPAddress::operator==(const IPAddress &other) const {
78 if (family_ != other.family_) {
79 return false;
80 }
81 if (family_ == AF_INET) {
82 return memcmp(&u_.ip4, &other.u_.ip4, sizeof(u_.ip4)) == 0;
83 }
84 if (family_ == AF_INET6) {
85 return memcmp(&u_.ip6, &other.u_.ip6, sizeof(u_.ip6)) == 0;
86 }
87 return family_ == AF_UNSPEC;
88}
89
90bool IPAddress::operator!=(const IPAddress &other) const {
91 return !((*this) == other);
92}
93
94bool IPAddress::operator >(const IPAddress &other) const {
95 return (*this) != other && !((*this) < other);
96}
97
98bool IPAddress::operator <(const IPAddress &other) const {
99 // IPv4 is 'less than' IPv6
100 if (family_ != other.family_) {
101 if (family_ == AF_UNSPEC) {
102 return true;
103 }
104 if (family_ == AF_INET && other.family_ == AF_INET6) {
105 return true;
106 }
107 return false;
108 }
109 // Comparing addresses of the same family.
110 switch (family_) {
111 case AF_INET: {
112 return NetworkToHost32(u_.ip4.s_addr) <
113 NetworkToHost32(other.u_.ip4.s_addr);
114 }
115 case AF_INET6: {
116 return memcmp(&u_.ip6.s6_addr, &other.u_.ip6.s6_addr, 16) < 0;
117 }
118 }
119 // Catches AF_UNSPEC and invalid addresses.
120 return false;
121}
122
123std::ostream& operator<<(std::ostream& os, const IPAddress& ip) {
124 os << ip.ToString();
125 return os;
126}
127
128in6_addr IPAddress::ipv6_address() const {
129 return u_.ip6;
130}
131
132in_addr IPAddress::ipv4_address() const {
133 return u_.ip4;
134}
135
136std::string IPAddress::ToString() const {
137 if (family_ != AF_INET && family_ != AF_INET6) {
138 return std::string();
139 }
140 char buf[INET6_ADDRSTRLEN] = {0};
141 const void* src = &u_.ip4;
142 if (family_ == AF_INET6) {
143 src = &u_.ip6;
144 }
145 if (!rtc::inet_ntop(family_, src, buf, sizeof(buf))) {
146 return std::string();
147 }
148 return std::string(buf);
149}
150
151std::string IPAddress::ToSensitiveString() const {
Peter Boströmcdb38e52015-11-26 00:35:49 +0100152#if !defined(NDEBUG)
153 // Return non-stripped in debug.
154 return ToString();
155#else
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 switch (family_) {
157 case AF_INET: {
158 std::string address = ToString();
159 size_t find_pos = address.rfind('.');
160 if (find_pos == std::string::npos)
161 return std::string();
162 address.resize(find_pos);
163 address += ".x";
164 return address;
165 }
166 case AF_INET6: {
Sergey Ulanovbeed8282016-01-13 18:14:49 -0800167 std::string result;
168 result.resize(INET6_ADDRSTRLEN);
169 in6_addr addr = ipv6_address();
170 size_t len =
171 rtc::sprintfn(&(result[0]), result.size(), "%x:%x:%x:x:x:x:x:x",
172 (addr.s6_addr[0] << 8) + addr.s6_addr[1],
173 (addr.s6_addr[2] << 8) + addr.s6_addr[3],
174 (addr.s6_addr[4] << 8) + addr.s6_addr[5]);
175 result.resize(len);
176 return result;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000177 }
178 }
179 return std::string();
Peter Boströmcdb38e52015-11-26 00:35:49 +0100180#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000181}
182
183IPAddress IPAddress::Normalized() const {
184 if (family_ != AF_INET6) {
185 return *this;
186 }
187 if (!IPIsV4Mapped(*this)) {
188 return *this;
189 }
190 in_addr addr = ExtractMappedAddress(u_.ip6);
191 return IPAddress(addr);
192}
193
194IPAddress IPAddress::AsIPv6Address() const {
195 if (family_ != AF_INET) {
196 return *this;
197 }
198 in6_addr v6addr = kV4MappedPrefix;
199 ::memcpy(&v6addr.s6_addr[12], &u_.ip4.s_addr, sizeof(u_.ip4.s_addr));
200 return IPAddress(v6addr);
201}
202
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000203bool InterfaceAddress::operator==(const InterfaceAddress &other) const {
204 return ipv6_flags_ == other.ipv6_flags() &&
205 static_cast<const IPAddress&>(*this) == other;
206}
207
208bool InterfaceAddress::operator!=(const InterfaceAddress &other) const {
209 return !((*this) == other);
210}
211
212const InterfaceAddress& InterfaceAddress::operator=(
213 const InterfaceAddress& other) {
214 ipv6_flags_ = other.ipv6_flags_;
215 static_cast<IPAddress&>(*this) = other;
216 return *this;
217}
218
219std::ostream& operator<<(std::ostream& os, const InterfaceAddress& ip) {
Jonas Olsson74395342018-04-03 12:22:07 +0200220 return os << ip.ToString();
221}
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000222
Jonas Olsson74395342018-04-03 12:22:07 +0200223std::string InterfaceAddress::ToString() const {
224 std::string result = IPAddress::ToString();
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000225
Jonas Olsson74395342018-04-03 12:22:07 +0200226 if (family() == AF_INET6)
227 result += "|flags:0x" + rtc::ToHex(ipv6_flags());
228
229 return result;
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000230}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100232static bool IPIsPrivateNetworkV4(const IPAddress& ip) {
233 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
234 return ((ip_in_host_order >> 24) == 10) ||
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235 ((ip_in_host_order >> 20) == ((172 << 4) | 1)) ||
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100236 ((ip_in_host_order >> 16) == ((192 << 8) | 168));
237}
238
239static bool IPIsPrivateNetworkV6(const IPAddress& ip) {
240 return IPIsHelper(ip, kPrivateNetworkPrefix, 8);
241}
242
243bool IPIsPrivateNetwork(const IPAddress& ip) {
244 switch (ip.family()) {
245 case AF_INET: {
246 return IPIsPrivateNetworkV4(ip);
247 }
248 case AF_INET6: {
249 return IPIsPrivateNetworkV6(ip);
250 }
251 }
252 return false;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000253}
254
255in_addr ExtractMappedAddress(const in6_addr& in6) {
256 in_addr ipv4;
257 ::memcpy(&ipv4.s_addr, &in6.s6_addr[12], sizeof(ipv4.s_addr));
258 return ipv4;
259}
260
261bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out) {
262 if (!info || !info->ai_addr) {
263 return false;
264 }
265 if (info->ai_addr->sa_family == AF_INET) {
266 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(info->ai_addr);
267 *out = IPAddress(addr->sin_addr);
268 return true;
269 } else if (info->ai_addr->sa_family == AF_INET6) {
270 sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
271 *out = IPAddress(addr->sin6_addr);
272 return true;
273 }
274 return false;
275}
276
277bool IPFromString(const std::string& str, IPAddress* out) {
278 if (!out) {
279 return false;
280 }
281 in_addr addr;
282 if (rtc::inet_pton(AF_INET, str.c_str(), &addr) == 0) {
283 in6_addr addr6;
284 if (rtc::inet_pton(AF_INET6, str.c_str(), &addr6) == 0) {
285 *out = IPAddress();
286 return false;
287 }
288 *out = IPAddress(addr6);
289 } else {
290 *out = IPAddress(addr);
291 }
292 return true;
293}
294
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000295bool IPFromString(const std::string& str, int flags,
296 InterfaceAddress* out) {
297 IPAddress ip;
298 if (!IPFromString(str, &ip)) {
299 return false;
300 }
301
302 *out = InterfaceAddress(ip, flags);
303 return true;
304}
305
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306bool IPIsAny(const IPAddress& ip) {
307 switch (ip.family()) {
308 case AF_INET:
309 return ip == IPAddress(INADDR_ANY);
310 case AF_INET6:
guoweis@webrtc.org59ae5ff2015-03-01 23:45:16 +0000311 return ip == IPAddress(in6addr_any) || ip == IPAddress(kV4MappedPrefix);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312 case AF_UNSPEC:
313 return false;
314 }
315 return false;
316}
317
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100318static bool IPIsLoopbackV4(const IPAddress& ip) {
319 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
320 return ((ip_in_host_order >> 24) == 127);
321}
322
323static bool IPIsLoopbackV6(const IPAddress& ip) {
324 return ip == IPAddress(in6addr_loopback);
325}
326
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327bool IPIsLoopback(const IPAddress& ip) {
328 switch (ip.family()) {
329 case AF_INET: {
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100330 return IPIsLoopbackV4(ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331 }
332 case AF_INET6: {
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100333 return IPIsLoopbackV6(ip);
Yuwei Huangb181f712018-01-22 17:01:28 -0800334 }
335 }
336 return false;
337}
338
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000339bool IPIsPrivate(const IPAddress& ip) {
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100340 return IPIsLinkLocal(ip) || IPIsLoopback(ip) || IPIsPrivateNetwork(ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341}
342
343bool IPIsUnspec(const IPAddress& ip) {
344 return ip.family() == AF_UNSPEC;
345}
346
347size_t HashIP(const IPAddress& ip) {
348 switch (ip.family()) {
349 case AF_INET: {
350 return ip.ipv4_address().s_addr;
351 }
352 case AF_INET6: {
353 in6_addr v6addr = ip.ipv6_address();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200354 const uint32_t* v6_as_ints =
355 reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000356 return v6_as_ints[0] ^ v6_as_ints[1] ^ v6_as_ints[2] ^ v6_as_ints[3];
357 }
358 }
359 return 0;
360}
361
362IPAddress TruncateIP(const IPAddress& ip, int length) {
363 if (length < 0) {
364 return IPAddress();
365 }
366 if (ip.family() == AF_INET) {
367 if (length > 31) {
368 return ip;
369 }
370 if (length == 0) {
371 return IPAddress(INADDR_ANY);
372 }
373 int mask = (0xFFFFFFFF << (32 - length));
Peter Boström0c4e06b2015-10-07 12:23:21 +0200374 uint32_t host_order_ip = NetworkToHost32(ip.ipv4_address().s_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000375 in_addr masked;
376 masked.s_addr = HostToNetwork32(host_order_ip & mask);
377 return IPAddress(masked);
378 } else if (ip.family() == AF_INET6) {
379 if (length > 127) {
380 return ip;
381 }
382 if (length == 0) {
383 return IPAddress(in6addr_any);
384 }
385 in6_addr v6addr = ip.ipv6_address();
386 int position = length / 32;
387 int inner_length = 32 - (length - (position * 32));
388 // Note: 64bit mask constant needed to allow possible 32-bit left shift.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200389 uint32_t inner_mask = 0xFFFFFFFFLL << inner_length;
390 uint32_t* v6_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000391 for (int i = 0; i < 4; ++i) {
392 if (i == position) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200393 uint32_t host_order_inner = NetworkToHost32(v6_as_ints[i]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000394 v6_as_ints[i] = HostToNetwork32(host_order_inner & inner_mask);
395 } else if (i > position) {
396 v6_as_ints[i] = 0;
397 }
398 }
399 return IPAddress(v6addr);
400 }
401 return IPAddress();
402}
403
404int CountIPMaskBits(IPAddress mask) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200405 uint32_t word_to_count = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000406 int bits = 0;
407 switch (mask.family()) {
408 case AF_INET: {
409 word_to_count = NetworkToHost32(mask.ipv4_address().s_addr);
410 break;
411 }
412 case AF_INET6: {
413 in6_addr v6addr = mask.ipv6_address();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200414 const uint32_t* v6_as_ints =
415 reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000416 int i = 0;
417 for (; i < 4; ++i) {
418 if (v6_as_ints[i] != 0xFFFFFFFF) {
419 break;
420 }
421 }
422 if (i < 4) {
423 word_to_count = NetworkToHost32(v6_as_ints[i]);
424 }
425 bits = (i * 32);
426 break;
427 }
428 default: {
429 return 0;
430 }
431 }
432 if (word_to_count == 0) {
433 return bits;
434 }
435
436 // Public domain bit-twiddling hack from:
437 // http://graphics.stanford.edu/~seander/bithacks.html
438 // Counts the trailing 0s in the word.
439 unsigned int zeroes = 32;
tereliusd802b5b2016-03-01 11:07:34 -0800440 // This could also be written word_to_count &= -word_to_count, but
441 // MSVC emits warning C4146 when negating an unsigned number.
442 word_to_count &= ~word_to_count + 1; // Isolate lowest set bit.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000443 if (word_to_count) zeroes--;
444 if (word_to_count & 0x0000FFFF) zeroes -= 16;
445 if (word_to_count & 0x00FF00FF) zeroes -= 8;
446 if (word_to_count & 0x0F0F0F0F) zeroes -= 4;
447 if (word_to_count & 0x33333333) zeroes -= 2;
448 if (word_to_count & 0x55555555) zeroes -= 1;
449
450 return bits + (32 - zeroes);
451}
452
453bool IPIsHelper(const IPAddress& ip, const in6_addr& tomatch, int length) {
454 // Helper method for checking IP prefix matches (but only on whole byte
455 // lengths). Length is in bits.
456 in6_addr addr = ip.ipv6_address();
457 return ::memcmp(&addr, &tomatch, (length >> 3)) == 0;
458}
459
460bool IPIs6Bone(const IPAddress& ip) {
461 return IPIsHelper(ip, k6BonePrefix, 16);
462}
463
464bool IPIs6To4(const IPAddress& ip) {
465 return IPIsHelper(ip, k6To4Prefix, 16);
466}
467
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100468static bool IPIsLinkLocalV4(const IPAddress& ip) {
469 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
470 return ((ip_in_host_order >> 16) == ((169 << 8) | 254));
471}
472
473static bool IPIsLinkLocalV6(const IPAddress& ip) {
474 // Can't use the helper because the prefix is 10 bits.
475 in6_addr addr = ip.ipv6_address();
476 return (addr.s6_addr[0] == 0xFE) && ((addr.s6_addr[1] & 0xC0) == 0x80);
477}
478
479bool IPIsLinkLocal(const IPAddress& ip) {
480 switch (ip.family()) {
481 case AF_INET: {
482 return IPIsLinkLocalV4(ip);
483 }
484 case AF_INET6: {
485 return IPIsLinkLocalV6(ip);
486 }
487 }
488 return false;
489}
490
guoweis@webrtc.orgb91d0f52015-03-17 14:43:20 +0000491// According to http://www.ietf.org/rfc/rfc2373.txt, Appendix A, page 19. An
492// address which contains MAC will have its 11th and 12th bytes as FF:FE as well
493// as the U/L bit as 1.
494bool IPIsMacBased(const IPAddress& ip) {
495 in6_addr addr = ip.ipv6_address();
496 return ((addr.s6_addr[8] & 0x02) && addr.s6_addr[11] == 0xFF &&
497 addr.s6_addr[12] == 0xFE);
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000498}
499
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000500bool IPIsSiteLocal(const IPAddress& ip) {
501 // Can't use the helper because the prefix is 10 bits.
502 in6_addr addr = ip.ipv6_address();
503 return addr.s6_addr[0] == 0xFE && (addr.s6_addr[1] & 0xC0) == 0xC0;
504}
505
506bool IPIsULA(const IPAddress& ip) {
507 // Can't use the helper because the prefix is 7 bits.
508 in6_addr addr = ip.ipv6_address();
509 return (addr.s6_addr[0] & 0xFE) == 0xFC;
510}
511
512bool IPIsTeredo(const IPAddress& ip) {
513 return IPIsHelper(ip, kTeredoPrefix, 32);
514}
515
516bool IPIsV4Compatibility(const IPAddress& ip) {
517 return IPIsHelper(ip, kV4CompatibilityPrefix, 96);
518}
519
520bool IPIsV4Mapped(const IPAddress& ip) {
521 return IPIsHelper(ip, kV4MappedPrefix, 96);
522}
523
524int IPAddressPrecedence(const IPAddress& ip) {
525 // Precedence values from RFC 3484-bis. Prefers native v4 over 6to4/Teredo.
526 if (ip.family() == AF_INET) {
527 return 30;
528 } else if (ip.family() == AF_INET6) {
529 if (IPIsLoopback(ip)) {
530 return 60;
531 } else if (IPIsULA(ip)) {
532 return 50;
533 } else if (IPIsV4Mapped(ip)) {
534 return 30;
535 } else if (IPIs6To4(ip)) {
536 return 20;
537 } else if (IPIsTeredo(ip)) {
538 return 10;
539 } else if (IPIsV4Compatibility(ip) || IPIsSiteLocal(ip) || IPIs6Bone(ip)) {
540 return 1;
541 } else {
542 // A 'normal' IPv6 address.
543 return 40;
544 }
545 }
546 return 0;
547}
548
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700549IPAddress GetLoopbackIP(int family) {
550 if (family == AF_INET) {
551 return rtc::IPAddress(INADDR_LOOPBACK);
552 }
553 if (family == AF_INET6) {
554 return rtc::IPAddress(in6addr_loopback);
555 }
556 return rtc::IPAddress();
557}
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800558
559IPAddress GetAnyIP(int family) {
560 if (family == AF_INET) {
561 return rtc::IPAddress(INADDR_ANY);
562 }
563 if (family == AF_INET6) {
564 return rtc::IPAddress(in6addr_any);
565 }
566 return rtc::IPAddress();
567}
568
tereliusd802b5b2016-03-01 11:07:34 -0800569} // namespace rtc