blob: a31680d8513dee639ec202dbf2f8bb0b6b715379 [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}}};
48
Peter Boström0c4e06b2015-10-07 12:23:21 +020049static bool IsPrivateV4(uint32_t ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000050static in_addr ExtractMappedAddress(const in6_addr& addr);
51
Peter Boström0c4e06b2015-10-07 12:23:21 +020052uint32_t IPAddress::v4AddressAsHostOrderInteger() const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000053 if (family_ == AF_INET) {
54 return NetworkToHost32(u_.ip4.s_addr);
55 } else {
56 return 0;
57 }
58}
59
Guo-wei Shieh11477022015-08-15 09:28:41 -070060bool IPAddress::IsNil() const {
61 return IPIsUnspec(*this);
62}
63
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000064size_t IPAddress::Size() const {
65 switch (family_) {
66 case AF_INET:
67 return sizeof(in_addr);
68 case AF_INET6:
69 return sizeof(in6_addr);
70 }
71 return 0;
72}
73
74
75bool IPAddress::operator==(const IPAddress &other) const {
76 if (family_ != other.family_) {
77 return false;
78 }
79 if (family_ == AF_INET) {
80 return memcmp(&u_.ip4, &other.u_.ip4, sizeof(u_.ip4)) == 0;
81 }
82 if (family_ == AF_INET6) {
83 return memcmp(&u_.ip6, &other.u_.ip6, sizeof(u_.ip6)) == 0;
84 }
85 return family_ == AF_UNSPEC;
86}
87
88bool IPAddress::operator!=(const IPAddress &other) const {
89 return !((*this) == other);
90}
91
92bool IPAddress::operator >(const IPAddress &other) const {
93 return (*this) != other && !((*this) < other);
94}
95
96bool IPAddress::operator <(const IPAddress &other) const {
97 // IPv4 is 'less than' IPv6
98 if (family_ != other.family_) {
99 if (family_ == AF_UNSPEC) {
100 return true;
101 }
102 if (family_ == AF_INET && other.family_ == AF_INET6) {
103 return true;
104 }
105 return false;
106 }
107 // Comparing addresses of the same family.
108 switch (family_) {
109 case AF_INET: {
110 return NetworkToHost32(u_.ip4.s_addr) <
111 NetworkToHost32(other.u_.ip4.s_addr);
112 }
113 case AF_INET6: {
114 return memcmp(&u_.ip6.s6_addr, &other.u_.ip6.s6_addr, 16) < 0;
115 }
116 }
117 // Catches AF_UNSPEC and invalid addresses.
118 return false;
119}
120
121std::ostream& operator<<(std::ostream& os, const IPAddress& ip) {
122 os << ip.ToString();
123 return os;
124}
125
126in6_addr IPAddress::ipv6_address() const {
127 return u_.ip6;
128}
129
130in_addr IPAddress::ipv4_address() const {
131 return u_.ip4;
132}
133
134std::string IPAddress::ToString() const {
135 if (family_ != AF_INET && family_ != AF_INET6) {
136 return std::string();
137 }
138 char buf[INET6_ADDRSTRLEN] = {0};
139 const void* src = &u_.ip4;
140 if (family_ == AF_INET6) {
141 src = &u_.ip6;
142 }
143 if (!rtc::inet_ntop(family_, src, buf, sizeof(buf))) {
144 return std::string();
145 }
146 return std::string(buf);
147}
148
149std::string IPAddress::ToSensitiveString() const {
Peter Boströmcdb38e52015-11-26 00:35:49 +0100150#if !defined(NDEBUG)
151 // Return non-stripped in debug.
152 return ToString();
153#else
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 switch (family_) {
155 case AF_INET: {
156 std::string address = ToString();
157 size_t find_pos = address.rfind('.');
158 if (find_pos == std::string::npos)
159 return std::string();
160 address.resize(find_pos);
161 address += ".x";
162 return address;
163 }
164 case AF_INET6: {
Sergey Ulanovbeed8282016-01-13 18:14:49 -0800165 std::string result;
166 result.resize(INET6_ADDRSTRLEN);
167 in6_addr addr = ipv6_address();
168 size_t len =
169 rtc::sprintfn(&(result[0]), result.size(), "%x:%x:%x:x:x:x:x:x",
170 (addr.s6_addr[0] << 8) + addr.s6_addr[1],
171 (addr.s6_addr[2] << 8) + addr.s6_addr[3],
172 (addr.s6_addr[4] << 8) + addr.s6_addr[5]);
173 result.resize(len);
174 return result;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175 }
176 }
177 return std::string();
Peter Boströmcdb38e52015-11-26 00:35:49 +0100178#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179}
180
181IPAddress IPAddress::Normalized() const {
182 if (family_ != AF_INET6) {
183 return *this;
184 }
185 if (!IPIsV4Mapped(*this)) {
186 return *this;
187 }
188 in_addr addr = ExtractMappedAddress(u_.ip6);
189 return IPAddress(addr);
190}
191
192IPAddress IPAddress::AsIPv6Address() const {
193 if (family_ != AF_INET) {
194 return *this;
195 }
196 in6_addr v6addr = kV4MappedPrefix;
197 ::memcpy(&v6addr.s6_addr[12], &u_.ip4.s_addr, sizeof(u_.ip4.s_addr));
198 return IPAddress(v6addr);
199}
200
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000201bool InterfaceAddress::operator==(const InterfaceAddress &other) const {
202 return ipv6_flags_ == other.ipv6_flags() &&
203 static_cast<const IPAddress&>(*this) == other;
204}
205
206bool InterfaceAddress::operator!=(const InterfaceAddress &other) const {
207 return !((*this) == other);
208}
209
210const InterfaceAddress& InterfaceAddress::operator=(
211 const InterfaceAddress& other) {
212 ipv6_flags_ = other.ipv6_flags_;
213 static_cast<IPAddress&>(*this) = other;
214 return *this;
215}
216
217std::ostream& operator<<(std::ostream& os, const InterfaceAddress& ip) {
218 os << static_cast<const IPAddress&>(ip);
219
220 if (ip.family() == AF_INET6)
221 os << "|flags:0x" << std::hex << ip.ipv6_flags();
222
223 return os;
224}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225
Peter Boström0c4e06b2015-10-07 12:23:21 +0200226bool IsPrivateV4(uint32_t ip_in_host_order) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 return ((ip_in_host_order >> 24) == 127) ||
228 ((ip_in_host_order >> 24) == 10) ||
229 ((ip_in_host_order >> 20) == ((172 << 4) | 1)) ||
230 ((ip_in_host_order >> 16) == ((192 << 8) | 168)) ||
231 ((ip_in_host_order >> 16) == ((169 << 8) | 254));
232}
233
234in_addr ExtractMappedAddress(const in6_addr& in6) {
235 in_addr ipv4;
236 ::memcpy(&ipv4.s_addr, &in6.s6_addr[12], sizeof(ipv4.s_addr));
237 return ipv4;
238}
239
240bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out) {
241 if (!info || !info->ai_addr) {
242 return false;
243 }
244 if (info->ai_addr->sa_family == AF_INET) {
245 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(info->ai_addr);
246 *out = IPAddress(addr->sin_addr);
247 return true;
248 } else if (info->ai_addr->sa_family == AF_INET6) {
249 sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
250 *out = IPAddress(addr->sin6_addr);
251 return true;
252 }
253 return false;
254}
255
256bool IPFromString(const std::string& str, IPAddress* out) {
257 if (!out) {
258 return false;
259 }
260 in_addr addr;
261 if (rtc::inet_pton(AF_INET, str.c_str(), &addr) == 0) {
262 in6_addr addr6;
263 if (rtc::inet_pton(AF_INET6, str.c_str(), &addr6) == 0) {
264 *out = IPAddress();
265 return false;
266 }
267 *out = IPAddress(addr6);
268 } else {
269 *out = IPAddress(addr);
270 }
271 return true;
272}
273
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000274bool IPFromString(const std::string& str, int flags,
275 InterfaceAddress* out) {
276 IPAddress ip;
277 if (!IPFromString(str, &ip)) {
278 return false;
279 }
280
281 *out = InterfaceAddress(ip, flags);
282 return true;
283}
284
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000285bool IPIsAny(const IPAddress& ip) {
286 switch (ip.family()) {
287 case AF_INET:
288 return ip == IPAddress(INADDR_ANY);
289 case AF_INET6:
guoweis@webrtc.org59ae5ff2015-03-01 23:45:16 +0000290 return ip == IPAddress(in6addr_any) || ip == IPAddress(kV4MappedPrefix);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000291 case AF_UNSPEC:
292 return false;
293 }
294 return false;
295}
296
297bool IPIsLoopback(const IPAddress& ip) {
298 switch (ip.family()) {
299 case AF_INET: {
deadbeef99220162016-10-27 18:30:23 -0700300 return (ip.v4AddressAsHostOrderInteger() >> 24) == 127;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000301 }
302 case AF_INET6: {
303 return ip == IPAddress(in6addr_loopback);
304 }
305 }
306 return false;
307}
308
Yuwei Huangb181f712018-01-22 17:01:28 -0800309bool IPIsLinkLocal(const IPAddress& ip) {
310 switch (ip.family()) {
311 case AF_INET: {
312 uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
313 return (ip_in_host_order >> 16) == ((169 << 8) | 254);
314 }
315 case AF_INET6: {
316 // Can't use the helper because the prefix is 10 bits.
317 in6_addr addr = ip.ipv6_address();
318 return addr.s6_addr[0] == 0xFE && addr.s6_addr[1] == 0x80;
319 }
320 }
321 return false;
322}
323
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000324bool IPIsPrivate(const IPAddress& ip) {
325 switch (ip.family()) {
326 case AF_INET: {
327 return IsPrivateV4(ip.v4AddressAsHostOrderInteger());
328 }
329 case AF_INET6: {
guoweis@webrtc.orgb91d0f52015-03-17 14:43:20 +0000330 return IPIsLinkLocal(ip) || IPIsLoopback(ip);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331 }
332 }
333 return false;
334}
335
336bool IPIsUnspec(const IPAddress& ip) {
337 return ip.family() == AF_UNSPEC;
338}
339
340size_t HashIP(const IPAddress& ip) {
341 switch (ip.family()) {
342 case AF_INET: {
343 return ip.ipv4_address().s_addr;
344 }
345 case AF_INET6: {
346 in6_addr v6addr = ip.ipv6_address();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200347 const uint32_t* v6_as_ints =
348 reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000349 return v6_as_ints[0] ^ v6_as_ints[1] ^ v6_as_ints[2] ^ v6_as_ints[3];
350 }
351 }
352 return 0;
353}
354
355IPAddress TruncateIP(const IPAddress& ip, int length) {
356 if (length < 0) {
357 return IPAddress();
358 }
359 if (ip.family() == AF_INET) {
360 if (length > 31) {
361 return ip;
362 }
363 if (length == 0) {
364 return IPAddress(INADDR_ANY);
365 }
366 int mask = (0xFFFFFFFF << (32 - length));
Peter Boström0c4e06b2015-10-07 12:23:21 +0200367 uint32_t host_order_ip = NetworkToHost32(ip.ipv4_address().s_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000368 in_addr masked;
369 masked.s_addr = HostToNetwork32(host_order_ip & mask);
370 return IPAddress(masked);
371 } else if (ip.family() == AF_INET6) {
372 if (length > 127) {
373 return ip;
374 }
375 if (length == 0) {
376 return IPAddress(in6addr_any);
377 }
378 in6_addr v6addr = ip.ipv6_address();
379 int position = length / 32;
380 int inner_length = 32 - (length - (position * 32));
381 // Note: 64bit mask constant needed to allow possible 32-bit left shift.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200382 uint32_t inner_mask = 0xFFFFFFFFLL << inner_length;
383 uint32_t* v6_as_ints = reinterpret_cast<uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000384 for (int i = 0; i < 4; ++i) {
385 if (i == position) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200386 uint32_t host_order_inner = NetworkToHost32(v6_as_ints[i]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000387 v6_as_ints[i] = HostToNetwork32(host_order_inner & inner_mask);
388 } else if (i > position) {
389 v6_as_ints[i] = 0;
390 }
391 }
392 return IPAddress(v6addr);
393 }
394 return IPAddress();
395}
396
397int CountIPMaskBits(IPAddress mask) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200398 uint32_t word_to_count = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000399 int bits = 0;
400 switch (mask.family()) {
401 case AF_INET: {
402 word_to_count = NetworkToHost32(mask.ipv4_address().s_addr);
403 break;
404 }
405 case AF_INET6: {
406 in6_addr v6addr = mask.ipv6_address();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200407 const uint32_t* v6_as_ints =
408 reinterpret_cast<const uint32_t*>(&v6addr.s6_addr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000409 int i = 0;
410 for (; i < 4; ++i) {
411 if (v6_as_ints[i] != 0xFFFFFFFF) {
412 break;
413 }
414 }
415 if (i < 4) {
416 word_to_count = NetworkToHost32(v6_as_ints[i]);
417 }
418 bits = (i * 32);
419 break;
420 }
421 default: {
422 return 0;
423 }
424 }
425 if (word_to_count == 0) {
426 return bits;
427 }
428
429 // Public domain bit-twiddling hack from:
430 // http://graphics.stanford.edu/~seander/bithacks.html
431 // Counts the trailing 0s in the word.
432 unsigned int zeroes = 32;
tereliusd802b5b2016-03-01 11:07:34 -0800433 // This could also be written word_to_count &= -word_to_count, but
434 // MSVC emits warning C4146 when negating an unsigned number.
435 word_to_count &= ~word_to_count + 1; // Isolate lowest set bit.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000436 if (word_to_count) zeroes--;
437 if (word_to_count & 0x0000FFFF) zeroes -= 16;
438 if (word_to_count & 0x00FF00FF) zeroes -= 8;
439 if (word_to_count & 0x0F0F0F0F) zeroes -= 4;
440 if (word_to_count & 0x33333333) zeroes -= 2;
441 if (word_to_count & 0x55555555) zeroes -= 1;
442
443 return bits + (32 - zeroes);
444}
445
446bool IPIsHelper(const IPAddress& ip, const in6_addr& tomatch, int length) {
447 // Helper method for checking IP prefix matches (but only on whole byte
448 // lengths). Length is in bits.
449 in6_addr addr = ip.ipv6_address();
450 return ::memcmp(&addr, &tomatch, (length >> 3)) == 0;
451}
452
453bool IPIs6Bone(const IPAddress& ip) {
454 return IPIsHelper(ip, k6BonePrefix, 16);
455}
456
457bool IPIs6To4(const IPAddress& ip) {
458 return IPIsHelper(ip, k6To4Prefix, 16);
459}
460
guoweis@webrtc.orgb91d0f52015-03-17 14:43:20 +0000461// According to http://www.ietf.org/rfc/rfc2373.txt, Appendix A, page 19. An
462// address which contains MAC will have its 11th and 12th bytes as FF:FE as well
463// as the U/L bit as 1.
464bool IPIsMacBased(const IPAddress& ip) {
465 in6_addr addr = ip.ipv6_address();
466 return ((addr.s6_addr[8] & 0x02) && addr.s6_addr[11] == 0xFF &&
467 addr.s6_addr[12] == 0xFE);
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000468}
469
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000470bool IPIsSiteLocal(const IPAddress& ip) {
471 // Can't use the helper because the prefix is 10 bits.
472 in6_addr addr = ip.ipv6_address();
473 return addr.s6_addr[0] == 0xFE && (addr.s6_addr[1] & 0xC0) == 0xC0;
474}
475
476bool IPIsULA(const IPAddress& ip) {
477 // Can't use the helper because the prefix is 7 bits.
478 in6_addr addr = ip.ipv6_address();
479 return (addr.s6_addr[0] & 0xFE) == 0xFC;
480}
481
482bool IPIsTeredo(const IPAddress& ip) {
483 return IPIsHelper(ip, kTeredoPrefix, 32);
484}
485
486bool IPIsV4Compatibility(const IPAddress& ip) {
487 return IPIsHelper(ip, kV4CompatibilityPrefix, 96);
488}
489
490bool IPIsV4Mapped(const IPAddress& ip) {
491 return IPIsHelper(ip, kV4MappedPrefix, 96);
492}
493
494int IPAddressPrecedence(const IPAddress& ip) {
495 // Precedence values from RFC 3484-bis. Prefers native v4 over 6to4/Teredo.
496 if (ip.family() == AF_INET) {
497 return 30;
498 } else if (ip.family() == AF_INET6) {
499 if (IPIsLoopback(ip)) {
500 return 60;
501 } else if (IPIsULA(ip)) {
502 return 50;
503 } else if (IPIsV4Mapped(ip)) {
504 return 30;
505 } else if (IPIs6To4(ip)) {
506 return 20;
507 } else if (IPIsTeredo(ip)) {
508 return 10;
509 } else if (IPIsV4Compatibility(ip) || IPIsSiteLocal(ip) || IPIs6Bone(ip)) {
510 return 1;
511 } else {
512 // A 'normal' IPv6 address.
513 return 40;
514 }
515 }
516 return 0;
517}
518
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700519IPAddress GetLoopbackIP(int family) {
520 if (family == AF_INET) {
521 return rtc::IPAddress(INADDR_LOOPBACK);
522 }
523 if (family == AF_INET6) {
524 return rtc::IPAddress(in6addr_loopback);
525 }
526 return rtc::IPAddress();
527}
Guo-wei Shieh9af97f82015-11-10 14:47:39 -0800528
529IPAddress GetAnyIP(int family) {
530 if (family == AF_INET) {
531 return rtc::IPAddress(INADDR_ANY);
532 }
533 if (family == AF_INET6) {
534 return rtc::IPAddress(in6addr_any);
535 }
536 return rtc::IPAddress();
537}
538
tereliusd802b5b2016-03-01 11:07:34 -0800539} // namespace rtc