blob: d441f075f8e2e7f280b9350096107fc5130b702a [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) {
220 os << static_cast<const IPAddress&>(ip);
221
222 if (ip.family() == AF_INET6)
223 os << "|flags:0x" << std::hex << ip.ipv6_flags();
224
225 return os;
226}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100228static bool IPIsPrivateNetworkV4(const IPAddress& ip) {
229 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
230 return ((ip_in_host_order >> 24) == 10) ||
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 ((ip_in_host_order >> 20) == ((172 << 4) | 1)) ||
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100232 ((ip_in_host_order >> 16) == ((192 << 8) | 168));
233}
234
235static bool IPIsPrivateNetworkV6(const IPAddress& ip) {
236 return IPIsHelper(ip, kPrivateNetworkPrefix, 8);
237}
238
239bool IPIsPrivateNetwork(const IPAddress& ip) {
240 switch (ip.family()) {
241 case AF_INET: {
242 return IPIsPrivateNetworkV4(ip);
243 }
244 case AF_INET6: {
245 return IPIsPrivateNetworkV6(ip);
246 }
247 }
248 return false;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000249}
250
251in_addr ExtractMappedAddress(const in6_addr& in6) {
252 in_addr ipv4;
253 ::memcpy(&ipv4.s_addr, &in6.s6_addr[12], sizeof(ipv4.s_addr));
254 return ipv4;
255}
256
257bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out) {
258 if (!info || !info->ai_addr) {
259 return false;
260 }
261 if (info->ai_addr->sa_family == AF_INET) {
262 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(info->ai_addr);
263 *out = IPAddress(addr->sin_addr);
264 return true;
265 } else if (info->ai_addr->sa_family == AF_INET6) {
266 sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
267 *out = IPAddress(addr->sin6_addr);
268 return true;
269 }
270 return false;
271}
272
273bool IPFromString(const std::string& str, IPAddress* out) {
274 if (!out) {
275 return false;
276 }
277 in_addr addr;
278 if (rtc::inet_pton(AF_INET, str.c_str(), &addr) == 0) {
279 in6_addr addr6;
280 if (rtc::inet_pton(AF_INET6, str.c_str(), &addr6) == 0) {
281 *out = IPAddress();
282 return false;
283 }
284 *out = IPAddress(addr6);
285 } else {
286 *out = IPAddress(addr);
287 }
288 return true;
289}
290
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000291bool IPFromString(const std::string& str, int flags,
292 InterfaceAddress* out) {
293 IPAddress ip;
294 if (!IPFromString(str, &ip)) {
295 return false;
296 }
297
298 *out = InterfaceAddress(ip, flags);
299 return true;
300}
301
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302bool IPIsAny(const IPAddress& ip) {
303 switch (ip.family()) {
304 case AF_INET:
305 return ip == IPAddress(INADDR_ANY);
306 case AF_INET6:
guoweis@webrtc.org59ae5ff2015-03-01 23:45:16 +0000307 return ip == IPAddress(in6addr_any) || ip == IPAddress(kV4MappedPrefix);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000308 case AF_UNSPEC:
309 return false;
310 }
311 return false;
312}
313
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100314static bool IPIsLoopbackV4(const IPAddress& ip) {
315 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
316 return ((ip_in_host_order >> 24) == 127);
317}
318
319static bool IPIsLoopbackV6(const IPAddress& ip) {
320 return ip == IPAddress(in6addr_loopback);
321}
322
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000323bool IPIsLoopback(const IPAddress& ip) {
324 switch (ip.family()) {
325 case AF_INET: {
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100326 return IPIsLoopbackV4(ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327 }
328 case AF_INET6: {
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100329 return IPIsLoopbackV6(ip);
Yuwei Huangb181f712018-01-22 17:01:28 -0800330 }
331 }
332 return false;
333}
334
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000335bool IPIsPrivate(const IPAddress& ip) {
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100336 return IPIsLinkLocal(ip) || IPIsLoopback(ip) || IPIsPrivateNetwork(ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000337}
338
339bool IPIsUnspec(const IPAddress& ip) {
340 return ip.family() == AF_UNSPEC;
341}
342
343size_t HashIP(const IPAddress& ip) {
344 switch (ip.family()) {
345 case AF_INET: {
346 return ip.ipv4_address().s_addr;
347 }
348 case AF_INET6: {
349 in6_addr v6addr = ip.ipv6_address();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200350 const uint32_t* v6_as_ints =
351 reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000352 return v6_as_ints[0] ^ v6_as_ints[1] ^ v6_as_ints[2] ^ v6_as_ints[3];
353 }
354 }
355 return 0;
356}
357
358IPAddress TruncateIP(const IPAddress& ip, int length) {
359 if (length < 0) {
360 return IPAddress();
361 }
362 if (ip.family() == AF_INET) {
363 if (length > 31) {
364 return ip;
365 }
366 if (length == 0) {
367 return IPAddress(INADDR_ANY);
368 }
369 int mask = (0xFFFFFFFF << (32 - length));
Peter Boström0c4e06b2015-10-07 12:23:21 +0200370 uint32_t host_order_ip = NetworkToHost32(ip.ipv4_address().s_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000371 in_addr masked;
372 masked.s_addr = HostToNetwork32(host_order_ip & mask);
373 return IPAddress(masked);
374 } else if (ip.family() == AF_INET6) {
375 if (length > 127) {
376 return ip;
377 }
378 if (length == 0) {
379 return IPAddress(in6addr_any);
380 }
381 in6_addr v6addr = ip.ipv6_address();
382 int position = length / 32;
383 int inner_length = 32 - (length - (position * 32));
384 // Note: 64bit mask constant needed to allow possible 32-bit left shift.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200385 uint32_t inner_mask = 0xFFFFFFFFLL << inner_length;
386 uint32_t* v6_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000387 for (int i = 0; i < 4; ++i) {
388 if (i == position) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200389 uint32_t host_order_inner = NetworkToHost32(v6_as_ints[i]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000390 v6_as_ints[i] = HostToNetwork32(host_order_inner & inner_mask);
391 } else if (i > position) {
392 v6_as_ints[i] = 0;
393 }
394 }
395 return IPAddress(v6addr);
396 }
397 return IPAddress();
398}
399
400int CountIPMaskBits(IPAddress mask) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200401 uint32_t word_to_count = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000402 int bits = 0;
403 switch (mask.family()) {
404 case AF_INET: {
405 word_to_count = NetworkToHost32(mask.ipv4_address().s_addr);
406 break;
407 }
408 case AF_INET6: {
409 in6_addr v6addr = mask.ipv6_address();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200410 const uint32_t* v6_as_ints =
411 reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000412 int i = 0;
413 for (; i < 4; ++i) {
414 if (v6_as_ints[i] != 0xFFFFFFFF) {
415 break;
416 }
417 }
418 if (i < 4) {
419 word_to_count = NetworkToHost32(v6_as_ints[i]);
420 }
421 bits = (i * 32);
422 break;
423 }
424 default: {
425 return 0;
426 }
427 }
428 if (word_to_count == 0) {
429 return bits;
430 }
431
432 // Public domain bit-twiddling hack from:
433 // http://graphics.stanford.edu/~seander/bithacks.html
434 // Counts the trailing 0s in the word.
435 unsigned int zeroes = 32;
tereliusd802b5b2016-03-01 11:07:34 -0800436 // This could also be written word_to_count &= -word_to_count, but
437 // MSVC emits warning C4146 when negating an unsigned number.
438 word_to_count &= ~word_to_count + 1; // Isolate lowest set bit.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000439 if (word_to_count) zeroes--;
440 if (word_to_count & 0x0000FFFF) zeroes -= 16;
441 if (word_to_count & 0x00FF00FF) zeroes -= 8;
442 if (word_to_count & 0x0F0F0F0F) zeroes -= 4;
443 if (word_to_count & 0x33333333) zeroes -= 2;
444 if (word_to_count & 0x55555555) zeroes -= 1;
445
446 return bits + (32 - zeroes);
447}
448
449bool IPIsHelper(const IPAddress& ip, const in6_addr& tomatch, int length) {
450 // Helper method for checking IP prefix matches (but only on whole byte
451 // lengths). Length is in bits.
452 in6_addr addr = ip.ipv6_address();
453 return ::memcmp(&addr, &tomatch, (length >> 3)) == 0;
454}
455
456bool IPIs6Bone(const IPAddress& ip) {
457 return IPIsHelper(ip, k6BonePrefix, 16);
458}
459
460bool IPIs6To4(const IPAddress& ip) {
461 return IPIsHelper(ip, k6To4Prefix, 16);
462}
463
Daniel Lazarenko2870b0a2018-01-25 10:30:22 +0100464static bool IPIsLinkLocalV4(const IPAddress& ip) {
465 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
466 return ((ip_in_host_order >> 16) == ((169 << 8) | 254));
467}
468
469static bool IPIsLinkLocalV6(const IPAddress& ip) {
470 // Can't use the helper because the prefix is 10 bits.
471 in6_addr addr = ip.ipv6_address();
472 return (addr.s6_addr[0] == 0xFE) && ((addr.s6_addr[1] & 0xC0) == 0x80);
473}
474
475bool IPIsLinkLocal(const IPAddress& ip) {
476 switch (ip.family()) {
477 case AF_INET: {
478 return IPIsLinkLocalV4(ip);
479 }
480 case AF_INET6: {
481 return IPIsLinkLocalV6(ip);
482 }
483 }
484 return false;
485}
486
guoweis@webrtc.orgb91d0f52015-03-17 14:43:20 +0000487// According to http://www.ietf.org/rfc/rfc2373.txt, Appendix A, page 19. An
488// address which contains MAC will have its 11th and 12th bytes as FF:FE as well
489// as the U/L bit as 1.
490bool IPIsMacBased(const IPAddress& ip) {
491 in6_addr addr = ip.ipv6_address();
492 return ((addr.s6_addr[8] & 0x02) && addr.s6_addr[11] == 0xFF &&
493 addr.s6_addr[12] == 0xFE);
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000494}
495
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000496bool IPIsSiteLocal(const IPAddress& ip) {
497 // Can't use the helper because the prefix is 10 bits.
498 in6_addr addr = ip.ipv6_address();
499 return addr.s6_addr[0] == 0xFE && (addr.s6_addr[1] & 0xC0) == 0xC0;
500}
501
502bool IPIsULA(const IPAddress& ip) {
503 // Can't use the helper because the prefix is 7 bits.
504 in6_addr addr = ip.ipv6_address();
505 return (addr.s6_addr[0] & 0xFE) == 0xFC;
506}
507
508bool IPIsTeredo(const IPAddress& ip) {
509 return IPIsHelper(ip, kTeredoPrefix, 32);
510}
511
512bool IPIsV4Compatibility(const IPAddress& ip) {
513 return IPIsHelper(ip, kV4CompatibilityPrefix, 96);
514}
515
516bool IPIsV4Mapped(const IPAddress& ip) {
517 return IPIsHelper(ip, kV4MappedPrefix, 96);
518}
519
520int IPAddressPrecedence(const IPAddress& ip) {
521 // Precedence values from RFC 3484-bis. Prefers native v4 over 6to4/Teredo.
522 if (ip.family() == AF_INET) {
523 return 30;
524 } else if (ip.family() == AF_INET6) {
525 if (IPIsLoopback(ip)) {
526 return 60;
527 } else if (IPIsULA(ip)) {
528 return 50;
529 } else if (IPIsV4Mapped(ip)) {
530 return 30;
531 } else if (IPIs6To4(ip)) {
532 return 20;
533 } else if (IPIsTeredo(ip)) {
534 return 10;
535 } else if (IPIsV4Compatibility(ip) || IPIsSiteLocal(ip) || IPIs6Bone(ip)) {
536 return 1;
537 } else {
538 // A 'normal' IPv6 address.
539 return 40;
540 }
541 }
542 return 0;
543}
544
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700545IPAddress GetLoopbackIP(int family) {
546 if (family == AF_INET) {
547 return rtc::IPAddress(INADDR_LOOPBACK);
548 }
549 if (family == AF_INET6) {
550 return rtc::IPAddress(in6addr_loopback);
551 }
552 return rtc::IPAddress();
553}
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800554
555IPAddress GetAnyIP(int family) {
556 if (family == AF_INET) {
557 return rtc::IPAddress(INADDR_ANY);
558 }
559 if (family == AF_INET6) {
560 return rtc::IPAddress(in6addr_any);
561 }
562 return rtc::IPAddress();
563}
564
tereliusd802b5b2016-03-01 11:07:34 -0800565} // namespace rtc