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/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>
16
17 #ifdef XP_WIN
18 # include "ws2tcpip.h"
19 #endif
20
21 namespace mozilla {
22 namespace net {
23
inet_ntop_internal(int af,const void * src,char * dst,socklen_t size)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;
36 }
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;
46 }
47 }
48 return nullptr;
49 #else
50 return inet_ntop(af, src, dst, size);
51 #endif
52 }
53
54 // Copies the contents of a PRNetAddr to a NetAddr.
55 // Does not do a ptr safety check!
PRNetAddrToNetAddr(const PRNetAddr * prAddr,NetAddr * addr)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;
67 }
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));
72 }
73 #endif
74 }
75
76 extern "C" {
77 // Rust bindings
78
moz_netaddr_get_family(const NetAddr * addr)79 uint16_t moz_netaddr_get_family(const NetAddr* addr) {
80 return addr->raw.family;
81 }
82
moz_netaddr_get_network_order_ip(const NetAddr * addr)83 uint32_t moz_netaddr_get_network_order_ip(const NetAddr* addr) {
84 return addr->inet.ip;
85 }
86
moz_netaddr_get_ipv6(const NetAddr * addr)87 uint8_t const* moz_netaddr_get_ipv6(const NetAddr* addr) {
88 return addr->inet6.ip.u8;
89 }
90
moz_netaddr_get_network_order_port(const NetAddr * addr)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;
94 }
95 if (addr->raw.family == PR_AF_INET6) {
96 return addr->inet6.port;
97 }
98 return 0;
99 }
100
101 } // extern "C"
102
103 // Copies the contents of a NetAddr to a PRNetAddr.
104 // Does not do a ptr safety check!
NetAddrToPRNetAddr(const NetAddr * addr,PRNetAddr * prAddr)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;
116 }
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));
121 }
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));
126 }
127 #endif
128 }
129
ToStringBuffer(char * buf,uint32_t bufSize) const130 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;
135 }
136 struct in_addr nativeAddr = {};
137 nativeAddr.s_addr = addr->inet.ip;
138 return !!inet_ntop_internal(AF_INET, &nativeAddr, buf, bufSize);
139 }
140 if (addr->raw.family == AF_INET6) {
141 if (bufSize < INET6_ADDRSTRLEN) {
142 return false;
143 }
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);
147 }
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';
155 }
156 return false;
157 }
158
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;
166 }
167 #endif
168 return false;
169 }
170
ToString() const171 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;
177 }
178 return ""_ns;
179 }
180
IsLoopbackAddr() const181 bool NetAddr::IsLoopbackAddr() const {
182 if (IsLoopBackAddressWithoutIPv6Mapping()) {
183 return true;
184 }
185 const NetAddr* addr = this;
186 if (addr->raw.family != AF_INET6) {
187 return false;
188 }
189
190 return IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) &&
191 IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_LOOPBACK);
192 }
193
IsLoopBackAddressWithoutIPv6Mapping() const194 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;
200 }
201
202 return addr->raw.family == AF_INET6 && IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip);
203 }
204
IsLoopbackHostname(const nsACString & aAsciiHost)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;
211 }
212
213 nsAutoCString host;
214 nsContentUtils::ASCIIToLower(aAsciiHost, host);
215
216 return host.EqualsLiteral("localhost") ||
217 StringEndsWith(host, ".localhost"_ns);
218 }
219
HostIsIPLiteral(const nsACString & aAsciiHost)220 bool HostIsIPLiteral(const nsACString& aAsciiHost) {
221 NetAddr addr;
222 return NS_SUCCEEDED(addr.InitFromString(aAsciiHost));
223 }
224
IsIPAddrAny() const225 bool NetAddr::IsIPAddrAny() const {
226 if (this->raw.family == AF_INET) {
227 if (this->inet.ip == htonl(INADDR_ANY)) {
228 return true;
229 }
230 } else if (this->raw.family == AF_INET6) {
231 if (IPv6ADDR_IS_UNSPECIFIED(&this->inet6.ip)) {
232 return true;
233 }
234 if (IPv6ADDR_IS_V4MAPPED(&this->inet6.ip) &&
235 IPv6ADDR_V4MAPPED_TO_IPADDR(&this->inet6.ip) == htonl(INADDR_ANY)) {
236 return true;
237 }
238 }
239 return false;
240 }
241
NetAddr(const PRNetAddr * prAddr)242 NetAddr::NetAddr(const PRNetAddr* prAddr) { PRNetAddrToNetAddr(prAddr, this); }
243
InitFromString(const nsACString & aString,uint16_t aPort)244 nsresult NetAddr::InitFromString(const nsACString& aString, uint16_t aPort) {
245 PRNetAddr prAddr{};
246 memset(&prAddr, 0, sizeof(PRNetAddr));
247 if (PR_StringToNetAddr(PromiseFlatCString(aString).get(), &prAddr) !=
248 PR_SUCCESS) {
249 return NS_ERROR_FAILURE;
250 }
251
252 PRNetAddrToNetAddr(&prAddr, this);
253
254 if (this->raw.family == PR_AF_INET) {
255 this->inet.port = PR_htons(aPort);
256 } else if (this->raw.family == PR_AF_INET6) {
257 this->inet6.port = PR_htons(aPort);
258 }
259 return NS_OK;
260 }
261
IsIPAddrV4() const262 bool NetAddr::IsIPAddrV4() const { return this->raw.family == AF_INET; }
263
IsIPAddrV4Mapped() const264 bool NetAddr::IsIPAddrV4Mapped() const {
265 if (this->raw.family == AF_INET6) {
266 return IPv6ADDR_IS_V4MAPPED(&this->inet6.ip);
267 }
268 return false;
269 }
270
isLocalIPv4(uint32_t networkEndianIP)271 static bool isLocalIPv4(uint32_t networkEndianIP) {
272 uint32_t addr32 = ntohl(networkEndianIP);
273 return addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918).
274 addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918).
275 addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918).
276 addr32 >> 16 == 0xA9FE; // 169.254/16 prefix (Link Local).
277 }
278
IsIPAddrLocal() const279 bool NetAddr::IsIPAddrLocal() const {
280 const NetAddr* addr = this;
281
282 // IPv4 RFC1918 and Link Local Addresses.
283 if (addr->raw.family == AF_INET) {
284 return isLocalIPv4(addr->inet.ip);
285 }
286 // IPv6 Unique and Link Local Addresses.
287 // or mapped IPv4 addresses
288 if (addr->raw.family == AF_INET6) {
289 uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]);
290 if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address.
291 addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address.
292 return true;
293 }
294 if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip)) {
295 return isLocalIPv4(IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip));
296 }
297 }
298
299 // Not an IPv4/6 local address.
300 return false;
301 }
302
IsIPAddrShared() const303 bool NetAddr::IsIPAddrShared() const {
304 const NetAddr* addr = this;
305
306 // IPv4 RFC6598.
307 if (addr->raw.family == AF_INET) {
308 uint32_t addr32 = ntohl(addr->inet.ip);
309 if (addr32 >> 22 == 0x644 >> 2) { // 100.64/10 prefix (RFC 6598).
310 return true;
311 }
312 }
313
314 // Not an IPv4 shared address.
315 return false;
316 }
317
GetPort(uint16_t * aResult) const318 nsresult NetAddr::GetPort(uint16_t* aResult) const {
319 uint16_t port;
320 if (this->raw.family == PR_AF_INET) {
321 port = this->inet.port;
322 } else if (this->raw.family == PR_AF_INET6) {
323 port = this->inet6.port;
324 } else {
325 return NS_ERROR_NOT_INITIALIZED;
326 }
327
328 *aResult = ntohs(port);
329 return NS_OK;
330 }
331
operator ==(const NetAddr & other) const332 bool NetAddr::operator==(const NetAddr& other) const {
333 if (this->raw.family != other.raw.family) {
334 return false;
335 }
336 if (this->raw.family == AF_INET) {
337 return (this->inet.port == other.inet.port) &&
338 (this->inet.ip == other.inet.ip);
339 }
340 if (this->raw.family == AF_INET6) {
341 return (this->inet6.port == other.inet6.port) &&
342 (this->inet6.flowinfo == other.inet6.flowinfo) &&
343 (memcmp(&this->inet6.ip, &other.inet6.ip, sizeof(this->inet6.ip)) ==
344 0) &&
345 (this->inet6.scope_id == other.inet6.scope_id);
346 #if defined(XP_UNIX)
347 }
348 if (this->raw.family == AF_LOCAL) {
349 return strncmp(this->local.path, other.local.path,
350 ArrayLength(this->local.path));
351 #endif
352 }
353 return false;
354 }
355
operator <(const NetAddr & other) const356 bool NetAddr::operator<(const NetAddr& other) const {
357 if (this->raw.family != other.raw.family) {
358 return this->raw.family < other.raw.family;
359 }
360 if (this->raw.family == AF_INET) {
361 if (this->inet.ip == other.inet.ip) {
362 return this->inet.port < other.inet.port;
363 }
364 return this->inet.ip < other.inet.ip;
365 }
366 if (this->raw.family == AF_INET6) {
367 int cmpResult =
368 memcmp(&this->inet6.ip, &other.inet6.ip, sizeof(this->inet6.ip));
369 if (cmpResult) {
370 return cmpResult < 0;
371 }
372 if (this->inet6.port != other.inet6.port) {
373 return this->inet6.port < other.inet6.port;
374 }
375 return this->inet6.flowinfo < other.inet6.flowinfo;
376 }
377 return false;
378 }
379
AddrInfo(const nsACString & host,const PRAddrInfo * prAddrInfo,bool disableIPv4,bool filterNameCollision,const nsACString & cname)380 AddrInfo::AddrInfo(const nsACString& host, const PRAddrInfo* prAddrInfo,
381 bool disableIPv4, bool filterNameCollision,
382 const nsACString& cname)
383 : mHostName(host), mCanonicalName(cname) {
384 MOZ_ASSERT(prAddrInfo,
385 "Cannot construct AddrInfo with a null prAddrInfo pointer!");
386 const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53
387
388 PRNetAddr tmpAddr;
389 void* iter = nullptr;
390 do {
391 iter = PR_EnumerateAddrInfo(iter, prAddrInfo, 0, &tmpAddr);
392 bool addIt = iter && (!disableIPv4 || tmpAddr.raw.family != PR_AF_INET) &&
393 (!filterNameCollision || tmpAddr.raw.family != PR_AF_INET ||
394 (tmpAddr.inet.ip != nameCollisionAddr));
395 if (addIt) {
396 NetAddr elem(&tmpAddr);
397 mAddresses.AppendElement(elem);
398 }
399 } while (iter);
400 }
401
AddrInfo(const nsACString & host,const nsACString & cname,DNSResolverType aResolverType,unsigned int aTRRType,nsTArray<NetAddr> && addresses)402 AddrInfo::AddrInfo(const nsACString& host, const nsACString& cname,
403 DNSResolverType aResolverType, unsigned int aTRRType,
404 nsTArray<NetAddr>&& addresses)
405 : mHostName(host),
406 mCanonicalName(cname),
407 mResolverType(aResolverType),
408 mTRRType(aTRRType),
409 mAddresses(std::move(addresses)) {}
410
AddrInfo(const nsACString & host,DNSResolverType aResolverType,unsigned int aTRRType,nsTArray<NetAddr> && addresses,uint32_t aTTL)411 AddrInfo::AddrInfo(const nsACString& host, DNSResolverType aResolverType,
412 unsigned int aTRRType, nsTArray<NetAddr>&& addresses,
413 uint32_t aTTL)
414 : ttl(aTTL),
415 mHostName(host),
416 mCanonicalName(),
417 mResolverType(aResolverType),
418 mTRRType(aTRRType),
419 mAddresses(std::move(addresses)) {}
420
421 // deep copy constructor
AddrInfo(const AddrInfo * src)422 AddrInfo::AddrInfo(const AddrInfo* src) {
423 mHostName = src->mHostName;
424 mCanonicalName = src->mCanonicalName;
425 ttl = src->ttl;
426 mResolverType = src->mResolverType;
427 mTRRType = src->mTRRType;
428 mTrrFetchDuration = src->mTrrFetchDuration;
429 mTrrFetchDurationNetworkOnly = src->mTrrFetchDurationNetworkOnly;
430
431 mAddresses = src->mAddresses.Clone();
432 }
433
434 AddrInfo::~AddrInfo() = default;
435
SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const436 size_t AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
437 size_t n = mallocSizeOf(this);
438 n += mHostName.SizeOfExcludingThisIfUnshared(mallocSizeOf);
439 n += mCanonicalName.SizeOfExcludingThisIfUnshared(mallocSizeOf);
440 n += mAddresses.ShallowSizeOfExcludingThis(mallocSizeOf);
441 return n;
442 }
443
444 } // namespace net
445 } // namespace mozilla
446