DNS.cpp (14275B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=4 sw=2 sts=2 et cin: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/net/DNS.h" 8 9 #include "mozilla/Assertions.h" 10 #include "mozilla/mozalloc.h" 11 #include "mozilla/StaticPrefs_network.h" 12 #include "nsContentUtils.h" 13 #include "nsIOService.h" 14 #include "nsPrintfCString.h" 15 #include "nsString.h" 16 #include <string.h> 17 18 #ifdef XP_WIN 19 # include "ws2tcpip.h" 20 #endif 21 22 namespace mozilla { 23 namespace net { 24 25 // Copies the contents of a PRNetAddr to a NetAddr. 26 // Does not do a ptr safety check! 27 void PRNetAddrToNetAddr(const PRNetAddr* prAddr, NetAddr* addr) { 28 if (prAddr->raw.family == PR_AF_INET) { 29 addr->inet.family = AF_INET; 30 addr->inet.port = prAddr->inet.port; 31 addr->inet.ip = prAddr->inet.ip; 32 } else if (prAddr->raw.family == PR_AF_INET6) { 33 addr->inet6.family = AF_INET6; 34 addr->inet6.port = prAddr->ipv6.port; 35 addr->inet6.flowinfo = prAddr->ipv6.flowinfo; 36 memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8)); 37 addr->inet6.scope_id = prAddr->ipv6.scope_id; 38 } 39 #if defined(XP_UNIX) 40 else if (prAddr->raw.family == PR_AF_LOCAL) { 41 addr->local.family = AF_LOCAL; 42 memcpy(addr->local.path, prAddr->local.path, sizeof(addr->local.path)); 43 } 44 #endif 45 } 46 47 extern "C" { 48 // Rust bindings 49 50 uint16_t moz_netaddr_get_family(const NetAddr* addr) { 51 return addr->raw.family; 52 } 53 54 uint32_t moz_netaddr_get_network_order_ip(const NetAddr* addr) { 55 return addr->inet.ip; 56 } 57 58 uint8_t const* moz_netaddr_get_ipv6(const NetAddr* addr) { 59 return addr->inet6.ip.u8; 60 } 61 62 uint16_t moz_netaddr_get_network_order_port(const NetAddr* addr) { 63 if (addr->raw.family == PR_AF_INET) { 64 return addr->inet.port; 65 } 66 if (addr->raw.family == PR_AF_INET6) { 67 return addr->inet6.port; 68 } 69 return 0; 70 } 71 72 } // extern "C" 73 74 // Copies the contents of a NetAddr to a PRNetAddr. 75 // Does not do a ptr safety check! 76 void NetAddrToPRNetAddr(const NetAddr* addr, PRNetAddr* prAddr) { 77 if (addr->raw.family == AF_INET) { 78 prAddr->inet.family = PR_AF_INET; 79 prAddr->inet.port = addr->inet.port; 80 prAddr->inet.ip = addr->inet.ip; 81 } else if (addr->raw.family == AF_INET6) { 82 prAddr->ipv6.family = PR_AF_INET6; 83 prAddr->ipv6.port = addr->inet6.port; 84 prAddr->ipv6.flowinfo = addr->inet6.flowinfo; 85 memcpy(&prAddr->ipv6.ip, &addr->inet6.ip, sizeof(addr->inet6.ip.u8)); 86 prAddr->ipv6.scope_id = addr->inet6.scope_id; 87 } 88 #if defined(XP_UNIX) || defined(XP_WIN) 89 else if (addr->raw.family == AF_LOCAL) { 90 prAddr->local.family = PR_AF_LOCAL; 91 memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path)); 92 } 93 #endif 94 } 95 96 bool NetAddr::ToStringBuffer(char* buf, uint32_t bufSize) const { 97 const NetAddr* addr = this; 98 if (addr->raw.family == AF_INET) { 99 if (bufSize < INET_ADDRSTRLEN) { 100 return false; 101 } 102 struct in_addr nativeAddr = {}; 103 nativeAddr.s_addr = addr->inet.ip; 104 return !!inet_ntop(AF_INET, &nativeAddr, buf, bufSize); 105 } 106 if (addr->raw.family == AF_INET6) { 107 if (bufSize < INET6_ADDRSTRLEN) { 108 return false; 109 } 110 struct in6_addr nativeAddr = {}; 111 memcpy(&nativeAddr.s6_addr, &addr->inet6.ip, sizeof(addr->inet6.ip.u8)); 112 return !!inet_ntop(AF_INET6, &nativeAddr, buf, bufSize); 113 } 114 #if defined(XP_UNIX) 115 if (addr->raw.family == AF_LOCAL) { 116 if (bufSize < sizeof(addr->local.path)) { 117 // Many callers don't bother checking our return value, so 118 // null-terminate just in case. 119 if (bufSize > 0) { 120 buf[0] = '\0'; 121 } 122 return false; 123 } 124 125 // Usually, the size passed to memcpy should be the size of the 126 // destination. Here, we know that the source is no larger than the 127 // destination, so using the source's size is always safe, whereas 128 // using the destination's size may cause us to read off the end of the 129 // source. 130 memcpy(buf, addr->local.path, sizeof(addr->local.path)); 131 return true; 132 } 133 #endif 134 return false; 135 } 136 137 nsCString NetAddr::ToString() const { 138 nsCString out; 139 out.SetLength(kNetAddrMaxCStrBufSize); 140 if (ToStringBuffer(out.BeginWriting(), kNetAddrMaxCStrBufSize)) { 141 out.SetLength(strlen(out.BeginWriting())); 142 return out; 143 } 144 return ""_ns; 145 } 146 147 void NetAddr::ToAddrPortString(nsACString& aOutput) const { 148 uint16_t port = 0; 149 GetPort(&port); 150 aOutput.Assign(nsPrintfCString("%s:%d", ToString().get(), port)); 151 } 152 153 bool NetAddr::IsLoopbackAddr() const { 154 if (IsLoopBackAddressWithoutIPv6Mapping()) { 155 return true; 156 } 157 const NetAddr* addr = this; 158 if (addr->raw.family != AF_INET6) { 159 return false; 160 } 161 162 if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip)) { 163 return IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == 164 htonl(INADDR_LOOPBACK); 165 } 166 167 // IPv6 loopback address ::1 168 uint64_t ipv6Addr1 = ntohl(addr->inet6.ip.u64[0]); 169 uint64_t ipv6Addr2 = ntohl(addr->inet6.ip.u64[1]); 170 return (ipv6Addr1 == 0 && ipv6Addr2 == 1); 171 } 172 173 bool NetAddr::IsBenchMarkingAddress() const { 174 // check for 198.18.0.0/15 175 if (this->raw.family == AF_INET) { 176 uint32_t addr = ntohl(this->inet.ip) >> 17; 177 return addr == (0xC612 >> 1); 178 } 179 180 if (IPv6ADDR_IS_V4MAPPED(&this->inet6.ip)) { 181 uint32_t addr = ntohl(IPv6ADDR_V4MAPPED_TO_IPADDR(&this->inet6.ip)) >> 17; 182 return addr == (0xC612 >> 1); 183 } 184 185 return false; 186 } 187 188 bool NetAddr::IsLoopBackAddressWithoutIPv6Mapping() const { 189 const NetAddr* addr = this; 190 if (addr->raw.family == AF_INET) { 191 // Consider 127.0.0.1/8 as loopback 192 uint32_t ipv4Addr = ntohl(addr->inet.ip); 193 return (ipv4Addr >> 24) == 127; 194 } 195 196 return addr->raw.family == AF_INET6 && IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip); 197 } 198 199 bool IsLoopbackHostname(const nsACString& aAsciiHost) { 200 // If the user has configured to proxy localhost addresses don't consider them 201 // to be secure 202 if (StaticPrefs::network_proxy_allow_hijacking_localhost() && 203 !StaticPrefs::network_proxy_testing_localhost_is_secure_when_hijacked()) { 204 return false; 205 } 206 207 nsAutoCString host; 208 nsContentUtils::ASCIIToLower(aAsciiHost, host); 209 210 return host.EqualsLiteral("localhost") || host.EqualsLiteral("localhost.") || 211 StringEndsWith(host, ".localhost"_ns) || 212 StringEndsWith(host, ".localhost."_ns); 213 } 214 215 bool HostIsIPLiteral(const nsACString& aAsciiHost) { 216 NetAddr addr; 217 return NS_SUCCEEDED(addr.InitFromString(aAsciiHost)); 218 } 219 220 bool NetAddr::IsIPAddrAny() const { 221 if (this->raw.family == AF_INET) { 222 if (this->inet.ip == htonl(INADDR_ANY)) { 223 return true; 224 } 225 } else if (this->raw.family == AF_INET6) { 226 if (IPv6ADDR_IS_UNSPECIFIED(&this->inet6.ip)) { 227 return true; 228 } 229 if (IPv6ADDR_IS_V4MAPPED(&this->inet6.ip) && 230 IPv6ADDR_V4MAPPED_TO_IPADDR(&this->inet6.ip) == htonl(INADDR_ANY)) { 231 return true; 232 } 233 } 234 return false; 235 } 236 237 NetAddr::NetAddr(const PRNetAddr* prAddr) { PRNetAddrToNetAddr(prAddr, this); } 238 239 nsILoadInfo::IPAddressSpace NetAddr::GetIpAddressSpace() const { 240 const NetAddr* addr = this; 241 if (addr->raw.family != AF_INET && addr->raw.family != AF_INET6) { 242 // We don't know the address space for non-IP addresses. 243 return nsILoadInfo::IPAddressSpace::Unknown; 244 } 245 246 nsILoadInfo::IPAddressSpace overriddenIpAddressSpace; 247 248 if (NS_SUCCEEDED(gIOService->GetOverridenIpAddressSpace( 249 &overriddenIpAddressSpace, *this))) { 250 return overriddenIpAddressSpace; 251 } 252 253 if (StaticPrefs::network_lna_benchmarking_is_local() && 254 addr->IsBenchMarkingAddress()) { 255 return nsILoadInfo::IPAddressSpace::Local; 256 } 257 258 if (addr->IsLoopbackAddr() || addr->IsIPAddrAny()) { 259 return nsILoadInfo::IPAddressSpace::Local; 260 } 261 262 if (addr->IsIPAddrLocal() || addr->IsIPAddrShared()) { 263 return nsILoadInfo::IPAddressSpace::Private; 264 } 265 266 return nsILoadInfo::IPAddressSpace::Public; 267 } 268 269 nsresult NetAddr::InitFromString(const nsACString& aString, uint16_t aPort) { 270 PRNetAddr prAddr{}; 271 memset(&prAddr, 0, sizeof(PRNetAddr)); 272 if (PR_StringToNetAddr(PromiseFlatCString(aString).get(), &prAddr) != 273 PR_SUCCESS) { 274 return NS_ERROR_FAILURE; 275 } 276 277 PRNetAddrToNetAddr(&prAddr, this); 278 279 if (this->raw.family == PR_AF_INET) { 280 this->inet.port = PR_htons(aPort); 281 } else if (this->raw.family == PR_AF_INET6) { 282 this->inet6.port = PR_htons(aPort); 283 } 284 return NS_OK; 285 } 286 287 bool NetAddr::IsIPAddrV4() const { return this->raw.family == AF_INET; } 288 289 bool NetAddr::IsIPAddrV4Mapped() const { 290 if (this->raw.family == AF_INET6) { 291 return IPv6ADDR_IS_V4MAPPED(&this->inet6.ip); 292 } 293 return false; 294 } 295 296 static bool isLocalIPv4(uint32_t networkEndianIP) { 297 uint32_t addr32 = ntohl(networkEndianIP); 298 return addr32 >> 24 == 0x00 || // 0/8 prefix (RFC 1122). 299 addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918). 300 addr32 >> 20 == 0x0AC1 || // 172.16/12 prefix (RFC 1918). 301 addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918). 302 addr32 >> 16 == 0xA9FE; // 169.254/16 prefix (Link Local). 303 } 304 305 bool NetAddr::IsIPAddrLocal() const { 306 const NetAddr* addr = this; 307 308 // An IPv4/6 any address. 309 if (IsIPAddrAny()) { 310 return true; 311 } 312 313 // IPv4 RFC1918 and Link Local Addresses. 314 if (addr->raw.family == AF_INET) { 315 return isLocalIPv4(addr->inet.ip); 316 } 317 // IPv6 Unique and Link Local Addresses. 318 // or mapped IPv4 addresses 319 if (addr->raw.family == AF_INET6) { 320 uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]); 321 if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address. 322 addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address. 323 return true; 324 } 325 if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip)) { 326 return isLocalIPv4(IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip)); 327 } 328 } 329 330 // Not an IPv4/6 local address. 331 return false; 332 } 333 334 bool NetAddr::IsIPAddrShared() const { 335 const NetAddr* addr = this; 336 337 // IPv4 RFC6598. 338 if (addr->raw.family == AF_INET) { 339 uint32_t addr32 = ntohl(addr->inet.ip); 340 if (addr32 >> 22 == 0x644 >> 2) { // 100.64/10 prefix (RFC 6598). 341 return true; 342 } 343 } 344 345 // Not an IPv4 shared address. 346 return false; 347 } 348 349 nsresult NetAddr::GetPort(uint16_t* aResult) const { 350 uint16_t port; 351 if (this->raw.family == PR_AF_INET) { 352 port = this->inet.port; 353 } else if (this->raw.family == PR_AF_INET6) { 354 port = this->inet6.port; 355 } else { 356 return NS_ERROR_NOT_INITIALIZED; 357 } 358 359 *aResult = ntohs(port); 360 return NS_OK; 361 } 362 363 bool NetAddr::operator==(const NetAddr& other) const { 364 if (this->raw.family != other.raw.family) { 365 return false; 366 } 367 if (this->raw.family == AF_INET) { 368 return (this->inet.port == other.inet.port) && 369 (this->inet.ip == other.inet.ip); 370 } 371 if (this->raw.family == AF_INET6) { 372 return (this->inet6.port == other.inet6.port) && 373 (this->inet6.flowinfo == other.inet6.flowinfo) && 374 (memcmp(&this->inet6.ip, &other.inet6.ip, sizeof(this->inet6.ip)) == 375 0) && 376 (this->inet6.scope_id == other.inet6.scope_id); 377 #if defined(XP_UNIX) 378 } 379 if (this->raw.family == AF_LOCAL) { 380 return strncmp(this->local.path, other.local.path, 381 std::size(this->local.path)); 382 #endif 383 } 384 return false; 385 } 386 387 bool NetAddr::operator<(const NetAddr& other) const { 388 if (this->raw.family != other.raw.family) { 389 return this->raw.family < other.raw.family; 390 } 391 if (this->raw.family == AF_INET) { 392 if (this->inet.ip == other.inet.ip) { 393 return this->inet.port < other.inet.port; 394 } 395 return this->inet.ip < other.inet.ip; 396 } 397 if (this->raw.family == AF_INET6) { 398 int cmpResult = 399 memcmp(&this->inet6.ip, &other.inet6.ip, sizeof(this->inet6.ip)); 400 if (cmpResult) { 401 return cmpResult < 0; 402 } 403 if (this->inet6.port != other.inet6.port) { 404 return this->inet6.port < other.inet6.port; 405 } 406 return this->inet6.flowinfo < other.inet6.flowinfo; 407 } 408 return false; 409 } 410 411 AddrInfo::AddrInfo(const nsACString& host, const PRAddrInfo* prAddrInfo, 412 bool disableIPv4, bool filterNameCollision, 413 const nsACString& cname) 414 : mHostName(host), mCanonicalName(cname) { 415 MOZ_ASSERT(prAddrInfo, 416 "Cannot construct AddrInfo with a null prAddrInfo pointer!"); 417 const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53 418 419 PRNetAddr tmpAddr; 420 void* iter = nullptr; 421 do { 422 iter = PR_EnumerateAddrInfo(iter, prAddrInfo, 0, &tmpAddr); 423 bool addIt = iter && (!disableIPv4 || tmpAddr.raw.family != PR_AF_INET) && 424 (!filterNameCollision || tmpAddr.raw.family != PR_AF_INET || 425 (tmpAddr.inet.ip != nameCollisionAddr)); 426 if (addIt) { 427 NetAddr elem(&tmpAddr); 428 mAddresses.AppendElement(elem); 429 } 430 } while (iter); 431 } 432 433 AddrInfo::AddrInfo(const nsACString& host, const nsACString& cname, 434 DNSResolverType aResolverType, unsigned int aTRRType, 435 nsTArray<NetAddr>&& addresses) 436 : mHostName(host), 437 mCanonicalName(cname), 438 mResolverType(aResolverType), 439 mTRRType(aTRRType), 440 mAddresses(std::move(addresses)) {} 441 442 AddrInfo::AddrInfo(const nsACString& host, DNSResolverType aResolverType, 443 unsigned int aTRRType, nsTArray<NetAddr>&& addresses, 444 uint32_t aTTL) 445 : ttl(aTTL), 446 mHostName(host), 447 mResolverType(aResolverType), 448 mTRRType(aTRRType), 449 mAddresses(std::move(addresses)) {} 450 451 // deep copy constructor 452 AddrInfo::AddrInfo(const AddrInfo* src) { 453 mHostName = src->mHostName; 454 mCanonicalName = src->mCanonicalName; 455 ttl = src->ttl; 456 mResolverType = src->mResolverType; 457 mTRRType = src->mTRRType; 458 mTrrFetchDuration = src->mTrrFetchDuration; 459 mTrrFetchDurationNetworkOnly = src->mTrrFetchDurationNetworkOnly; 460 461 mAddresses = src->mAddresses.Clone(); 462 } 463 464 AddrInfo::~AddrInfo() = default; 465 466 size_t AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { 467 size_t n = mallocSizeOf(this); 468 n += mHostName.SizeOfExcludingThisIfUnshared(mallocSizeOf); 469 n += mCanonicalName.SizeOfExcludingThisIfUnshared(mallocSizeOf); 470 n += mAddresses.ShallowSizeOfExcludingThis(mallocSizeOf); 471 return n; 472 } 473 474 } // namespace net 475 } // namespace mozilla