Bug 1838739 - Initialize result of SetAsGPUOutOfMemoryError. r=webgpu-reviewers,nical
[gecko.git] / netwerk / dns / DNS.cpp
blobbf20dd0e040ac5dcc96cca7bfb8346da320d488a
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/. */
7 #include "mozilla/net/DNS.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/Assertions.h"
11 #include "mozilla/mozalloc.h"
12 #include "mozilla/StaticPrefs_network.h"
13 #include "nsContentUtils.h"
14 #include "nsString.h"
15 #include <string.h>
17 #ifdef XP_WIN
18 # include "ws2tcpip.h"
19 #endif
21 namespace mozilla {
22 namespace net {
24 const char* inet_ntop_internal(int af, const void* src, char* dst,
25 socklen_t size) {
26 #ifdef XP_WIN
27 if (af == AF_INET) {
28 struct sockaddr_in s;
29 memset(&s, 0, sizeof(s));
30 s.sin_family = AF_INET;
31 memcpy(&s.sin_addr, src, sizeof(struct in_addr));
32 int result = getnameinfo((struct sockaddr*)&s, sizeof(struct sockaddr_in),
33 dst, size, nullptr, 0, NI_NUMERICHOST);
34 if (result == 0) {
35 return dst;
37 } else if (af == AF_INET6) {
38 struct sockaddr_in6 s;
39 memset(&s, 0, sizeof(s));
40 s.sin6_family = AF_INET6;
41 memcpy(&s.sin6_addr, src, sizeof(struct in_addr6));
42 int result = getnameinfo((struct sockaddr*)&s, sizeof(struct sockaddr_in6),
43 dst, size, nullptr, 0, NI_NUMERICHOST);
44 if (result == 0) {
45 return dst;
48 return nullptr;
49 #else
50 return inet_ntop(af, src, dst, size);
51 #endif
54 // Copies the contents of a PRNetAddr to a NetAddr.
55 // Does not do a ptr safety check!
56 void PRNetAddrToNetAddr(const PRNetAddr* prAddr, NetAddr* addr) {
57 if (prAddr->raw.family == PR_AF_INET) {
58 addr->inet.family = AF_INET;
59 addr->inet.port = prAddr->inet.port;
60 addr->inet.ip = prAddr->inet.ip;
61 } else if (prAddr->raw.family == PR_AF_INET6) {
62 addr->inet6.family = AF_INET6;
63 addr->inet6.port = prAddr->ipv6.port;
64 addr->inet6.flowinfo = prAddr->ipv6.flowinfo;
65 memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8));
66 addr->inet6.scope_id = prAddr->ipv6.scope_id;
68 #if defined(XP_UNIX)
69 else if (prAddr->raw.family == PR_AF_LOCAL) {
70 addr->local.family = AF_LOCAL;
71 memcpy(addr->local.path, prAddr->local.path, sizeof(addr->local.path));
73 #endif
76 extern "C" {
77 // Rust bindings
79 uint16_t moz_netaddr_get_family(const NetAddr* addr) {
80 return addr->raw.family;
83 uint32_t moz_netaddr_get_network_order_ip(const NetAddr* addr) {
84 return addr->inet.ip;
87 uint8_t const* moz_netaddr_get_ipv6(const NetAddr* addr) {
88 return addr->inet6.ip.u8;
91 uint16_t moz_netaddr_get_network_order_port(const NetAddr* addr) {
92 if (addr->raw.family == PR_AF_INET) {
93 return addr->inet.port;
95 if (addr->raw.family == PR_AF_INET6) {
96 return addr->inet6.port;
98 return 0;
101 } // extern "C"
103 // Copies the contents of a NetAddr to a PRNetAddr.
104 // Does not do a ptr safety check!
105 void NetAddrToPRNetAddr(const NetAddr* addr, PRNetAddr* prAddr) {
106 if (addr->raw.family == AF_INET) {
107 prAddr->inet.family = PR_AF_INET;
108 prAddr->inet.port = addr->inet.port;
109 prAddr->inet.ip = addr->inet.ip;
110 } else if (addr->raw.family == AF_INET6) {
111 prAddr->ipv6.family = PR_AF_INET6;
112 prAddr->ipv6.port = addr->inet6.port;
113 prAddr->ipv6.flowinfo = addr->inet6.flowinfo;
114 memcpy(&prAddr->ipv6.ip, &addr->inet6.ip, sizeof(addr->inet6.ip.u8));
115 prAddr->ipv6.scope_id = addr->inet6.scope_id;
117 #if defined(XP_UNIX)
118 else if (addr->raw.family == AF_LOCAL) {
119 prAddr->local.family = PR_AF_LOCAL;
120 memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path));
122 #elif defined(XP_WIN)
123 else if (addr->raw.family == AF_LOCAL) {
124 prAddr->local.family = PR_AF_LOCAL;
125 memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path));
127 #endif
130 bool NetAddr::ToStringBuffer(char* buf, uint32_t bufSize) const {
131 const NetAddr* addr = this;
132 if (addr->raw.family == AF_INET) {
133 if (bufSize < INET_ADDRSTRLEN) {
134 return false;
136 struct in_addr nativeAddr = {};
137 nativeAddr.s_addr = addr->inet.ip;
138 return !!inet_ntop_internal(AF_INET, &nativeAddr, buf, bufSize);
140 if (addr->raw.family == AF_INET6) {
141 if (bufSize < INET6_ADDRSTRLEN) {
142 return false;
144 struct in6_addr nativeAddr = {};
145 memcpy(&nativeAddr.s6_addr, &addr->inet6.ip, sizeof(addr->inet6.ip.u8));
146 return !!inet_ntop_internal(AF_INET6, &nativeAddr, buf, bufSize);
148 #if defined(XP_UNIX)
149 if (addr->raw.family == AF_LOCAL) {
150 if (bufSize < sizeof(addr->local.path)) {
151 // Many callers don't bother checking our return value, so
152 // null-terminate just in case.
153 if (bufSize > 0) {
154 buf[0] = '\0';
156 return false;
159 // Usually, the size passed to memcpy should be the size of the
160 // destination. Here, we know that the source is no larger than the
161 // destination, so using the source's size is always safe, whereas
162 // using the destination's size may cause us to read off the end of the
163 // source.
164 memcpy(buf, addr->local.path, sizeof(addr->local.path));
165 return true;
167 #endif
168 return false;
171 nsCString NetAddr::ToString() const {
172 nsCString out;
173 out.SetLength(kNetAddrMaxCStrBufSize);
174 if (ToStringBuffer(out.BeginWriting(), kNetAddrMaxCStrBufSize)) {
175 out.SetLength(strlen(out.BeginWriting()));
176 return out;
178 return ""_ns;
181 bool NetAddr::IsLoopbackAddr() const {
182 if (IsLoopBackAddressWithoutIPv6Mapping()) {
183 return true;
185 const NetAddr* addr = this;
186 if (addr->raw.family != AF_INET6) {
187 return false;
190 return IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) &&
191 IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_LOOPBACK);
194 bool NetAddr::IsLoopBackAddressWithoutIPv6Mapping() const {
195 const NetAddr* addr = this;
196 if (addr->raw.family == AF_INET) {
197 // Consider 127.0.0.1/8 as loopback
198 uint32_t ipv4Addr = ntohl(addr->inet.ip);
199 return (ipv4Addr >> 24) == 127;
202 return addr->raw.family == AF_INET6 && IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip);
205 bool IsLoopbackHostname(const nsACString& aAsciiHost) {
206 // If the user has configured to proxy localhost addresses don't consider them
207 // to be secure
208 if (StaticPrefs::network_proxy_allow_hijacking_localhost() &&
209 !StaticPrefs::network_proxy_testing_localhost_is_secure_when_hijacked()) {
210 return false;
213 nsAutoCString host;
214 nsContentUtils::ASCIIToLower(aAsciiHost, host);
216 return host.EqualsLiteral("localhost") || host.EqualsLiteral("localhost.") ||
217 StringEndsWith(host, ".localhost"_ns) ||
218 StringEndsWith(host, ".localhost."_ns);
221 bool HostIsIPLiteral(const nsACString& aAsciiHost) {
222 NetAddr addr;
223 return NS_SUCCEEDED(addr.InitFromString(aAsciiHost));
226 bool NetAddr::IsIPAddrAny() const {
227 if (this->raw.family == AF_INET) {
228 if (this->inet.ip == htonl(INADDR_ANY)) {
229 return true;
231 } else if (this->raw.family == AF_INET6) {
232 if (IPv6ADDR_IS_UNSPECIFIED(&this->inet6.ip)) {
233 return true;
235 if (IPv6ADDR_IS_V4MAPPED(&this->inet6.ip) &&
236 IPv6ADDR_V4MAPPED_TO_IPADDR(&this->inet6.ip) == htonl(INADDR_ANY)) {
237 return true;
240 return false;
243 NetAddr::NetAddr(const PRNetAddr* prAddr) { PRNetAddrToNetAddr(prAddr, this); }
245 nsresult NetAddr::InitFromString(const nsACString& aString, uint16_t aPort) {
246 PRNetAddr prAddr{};
247 memset(&prAddr, 0, sizeof(PRNetAddr));
248 if (PR_StringToNetAddr(PromiseFlatCString(aString).get(), &prAddr) !=
249 PR_SUCCESS) {
250 return NS_ERROR_FAILURE;
253 PRNetAddrToNetAddr(&prAddr, this);
255 if (this->raw.family == PR_AF_INET) {
256 this->inet.port = PR_htons(aPort);
257 } else if (this->raw.family == PR_AF_INET6) {
258 this->inet6.port = PR_htons(aPort);
260 return NS_OK;
263 bool NetAddr::IsIPAddrV4() const { return this->raw.family == AF_INET; }
265 bool NetAddr::IsIPAddrV4Mapped() const {
266 if (this->raw.family == AF_INET6) {
267 return IPv6ADDR_IS_V4MAPPED(&this->inet6.ip);
269 return false;
272 static bool isLocalIPv4(uint32_t networkEndianIP) {
273 uint32_t addr32 = ntohl(networkEndianIP);
274 return addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918).
275 addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918).
276 addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918).
277 addr32 >> 16 == 0xA9FE; // 169.254/16 prefix (Link Local).
280 bool NetAddr::IsIPAddrLocal() const {
281 const NetAddr* addr = this;
283 // IPv4 RFC1918 and Link Local Addresses.
284 if (addr->raw.family == AF_INET) {
285 return isLocalIPv4(addr->inet.ip);
287 // IPv6 Unique and Link Local Addresses.
288 // or mapped IPv4 addresses
289 if (addr->raw.family == AF_INET6) {
290 uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]);
291 if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address.
292 addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address.
293 return true;
295 if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip)) {
296 return isLocalIPv4(IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip));
300 // Not an IPv4/6 local address.
301 return false;
304 bool NetAddr::IsIPAddrShared() const {
305 const NetAddr* addr = this;
307 // IPv4 RFC6598.
308 if (addr->raw.family == AF_INET) {
309 uint32_t addr32 = ntohl(addr->inet.ip);
310 if (addr32 >> 22 == 0x644 >> 2) { // 100.64/10 prefix (RFC 6598).
311 return true;
315 // Not an IPv4 shared address.
316 return false;
319 nsresult NetAddr::GetPort(uint16_t* aResult) const {
320 uint16_t port;
321 if (this->raw.family == PR_AF_INET) {
322 port = this->inet.port;
323 } else if (this->raw.family == PR_AF_INET6) {
324 port = this->inet6.port;
325 } else {
326 return NS_ERROR_NOT_INITIALIZED;
329 *aResult = ntohs(port);
330 return NS_OK;
333 bool NetAddr::operator==(const NetAddr& other) const {
334 if (this->raw.family != other.raw.family) {
335 return false;
337 if (this->raw.family == AF_INET) {
338 return (this->inet.port == other.inet.port) &&
339 (this->inet.ip == other.inet.ip);
341 if (this->raw.family == AF_INET6) {
342 return (this->inet6.port == other.inet6.port) &&
343 (this->inet6.flowinfo == other.inet6.flowinfo) &&
344 (memcmp(&this->inet6.ip, &other.inet6.ip, sizeof(this->inet6.ip)) ==
345 0) &&
346 (this->inet6.scope_id == other.inet6.scope_id);
347 #if defined(XP_UNIX)
349 if (this->raw.family == AF_LOCAL) {
350 return strncmp(this->local.path, other.local.path,
351 ArrayLength(this->local.path));
352 #endif
354 return false;
357 bool NetAddr::operator<(const NetAddr& other) const {
358 if (this->raw.family != other.raw.family) {
359 return this->raw.family < other.raw.family;
361 if (this->raw.family == AF_INET) {
362 if (this->inet.ip == other.inet.ip) {
363 return this->inet.port < other.inet.port;
365 return this->inet.ip < other.inet.ip;
367 if (this->raw.family == AF_INET6) {
368 int cmpResult =
369 memcmp(&this->inet6.ip, &other.inet6.ip, sizeof(this->inet6.ip));
370 if (cmpResult) {
371 return cmpResult < 0;
373 if (this->inet6.port != other.inet6.port) {
374 return this->inet6.port < other.inet6.port;
376 return this->inet6.flowinfo < other.inet6.flowinfo;
378 return false;
381 AddrInfo::AddrInfo(const nsACString& host, const PRAddrInfo* prAddrInfo,
382 bool disableIPv4, bool filterNameCollision,
383 const nsACString& cname)
384 : mHostName(host), mCanonicalName(cname) {
385 MOZ_ASSERT(prAddrInfo,
386 "Cannot construct AddrInfo with a null prAddrInfo pointer!");
387 const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53
389 PRNetAddr tmpAddr;
390 void* iter = nullptr;
391 do {
392 iter = PR_EnumerateAddrInfo(iter, prAddrInfo, 0, &tmpAddr);
393 bool addIt = iter && (!disableIPv4 || tmpAddr.raw.family != PR_AF_INET) &&
394 (!filterNameCollision || tmpAddr.raw.family != PR_AF_INET ||
395 (tmpAddr.inet.ip != nameCollisionAddr));
396 if (addIt) {
397 NetAddr elem(&tmpAddr);
398 mAddresses.AppendElement(elem);
400 } while (iter);
403 AddrInfo::AddrInfo(const nsACString& host, const nsACString& cname,
404 DNSResolverType aResolverType, unsigned int aTRRType,
405 nsTArray<NetAddr>&& addresses)
406 : mHostName(host),
407 mCanonicalName(cname),
408 mResolverType(aResolverType),
409 mTRRType(aTRRType),
410 mAddresses(std::move(addresses)) {}
412 AddrInfo::AddrInfo(const nsACString& host, DNSResolverType aResolverType,
413 unsigned int aTRRType, nsTArray<NetAddr>&& addresses,
414 uint32_t aTTL)
415 : ttl(aTTL),
416 mHostName(host),
417 mCanonicalName(),
418 mResolverType(aResolverType),
419 mTRRType(aTRRType),
420 mAddresses(std::move(addresses)) {}
422 // deep copy constructor
423 AddrInfo::AddrInfo(const AddrInfo* src) {
424 mHostName = src->mHostName;
425 mCanonicalName = src->mCanonicalName;
426 ttl = src->ttl;
427 mResolverType = src->mResolverType;
428 mTRRType = src->mTRRType;
429 mTrrFetchDuration = src->mTrrFetchDuration;
430 mTrrFetchDurationNetworkOnly = src->mTrrFetchDurationNetworkOnly;
432 mAddresses = src->mAddresses.Clone();
435 AddrInfo::~AddrInfo() = default;
437 size_t AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
438 size_t n = mallocSizeOf(this);
439 n += mHostName.SizeOfExcludingThisIfUnshared(mallocSizeOf);
440 n += mCanonicalName.SizeOfExcludingThisIfUnshared(mallocSizeOf);
441 n += mAddresses.ShallowSizeOfExcludingThis(mallocSizeOf);
442 return n;
445 } // namespace net
446 } // namespace mozilla