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"
18 # include "ws2tcpip.h"
24 const char* inet_ntop_internal(int af
, const void* src
, char* dst
,
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
);
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
);
50 return inet_ntop(af
, src
, dst
, size
);
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
;
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
));
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
) {
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
;
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
;
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
));
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
) {
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
) {
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
);
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.
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
164 memcpy(buf
, addr
->local
.path
, sizeof(addr
->local
.path
));
171 nsCString
NetAddr::ToString() const {
173 out
.SetLength(kNetAddrMaxCStrBufSize
);
174 if (ToStringBuffer(out
.BeginWriting(), kNetAddrMaxCStrBufSize
)) {
175 out
.SetLength(strlen(out
.BeginWriting()));
181 bool NetAddr::IsLoopbackAddr() const {
182 if (IsLoopBackAddressWithoutIPv6Mapping()) {
185 const NetAddr
* addr
= this;
186 if (addr
->raw
.family
!= AF_INET6
) {
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
208 if (StaticPrefs::network_proxy_allow_hijacking_localhost() &&
209 !StaticPrefs::network_proxy_testing_localhost_is_secure_when_hijacked()) {
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
) {
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
)) {
231 } else if (this->raw
.family
== AF_INET6
) {
232 if (IPv6ADDR_IS_UNSPECIFIED(&this->inet6
.ip
)) {
235 if (IPv6ADDR_IS_V4MAPPED(&this->inet6
.ip
) &&
236 IPv6ADDR_V4MAPPED_TO_IPADDR(&this->inet6
.ip
) == htonl(INADDR_ANY
)) {
243 NetAddr::NetAddr(const PRNetAddr
* prAddr
) { PRNetAddrToNetAddr(prAddr
, this); }
245 nsresult
NetAddr::InitFromString(const nsACString
& aString
, uint16_t aPort
) {
247 memset(&prAddr
, 0, sizeof(PRNetAddr
));
248 if (PR_StringToNetAddr(PromiseFlatCString(aString
).get(), &prAddr
) !=
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
);
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
);
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.
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.
304 bool NetAddr::IsIPAddrShared() const {
305 const NetAddr
* addr
= this;
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).
315 // Not an IPv4 shared address.
319 nsresult
NetAddr::GetPort(uint16_t* aResult
) const {
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
;
326 return NS_ERROR_NOT_INITIALIZED
;
329 *aResult
= ntohs(port
);
333 bool NetAddr::operator==(const NetAddr
& other
) const {
334 if (this->raw
.family
!= other
.raw
.family
) {
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
)) ==
346 (this->inet6
.scope_id
== other
.inet6
.scope_id
);
349 if (this->raw
.family
== AF_LOCAL
) {
350 return strncmp(this->local
.path
, other
.local
.path
,
351 ArrayLength(this->local
.path
));
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
) {
369 memcmp(&this->inet6
.ip
, &other
.inet6
.ip
, sizeof(this->inet6
.ip
));
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
;
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
390 void* iter
= nullptr;
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
));
397 NetAddr
elem(&tmpAddr
);
398 mAddresses
.AppendElement(elem
);
403 AddrInfo::AddrInfo(const nsACString
& host
, const nsACString
& cname
,
404 DNSResolverType aResolverType
, unsigned int aTRRType
,
405 nsTArray
<NetAddr
>&& addresses
)
407 mCanonicalName(cname
),
408 mResolverType(aResolverType
),
410 mAddresses(std::move(addresses
)) {}
412 AddrInfo::AddrInfo(const nsACString
& host
, DNSResolverType aResolverType
,
413 unsigned int aTRRType
, nsTArray
<NetAddr
>&& addresses
,
418 mResolverType(aResolverType
),
420 mAddresses(std::move(addresses
)) {}
422 // deep copy constructor
423 AddrInfo::AddrInfo(const AddrInfo
* src
) {
424 mHostName
= src
->mHostName
;
425 mCanonicalName
= src
->mCanonicalName
;
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
);
446 } // namespace mozilla