Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "mozilla/net/DNS.h"
6 :
7 : #include "mozilla/Assertions.h"
8 : #include "mozilla/mozalloc.h"
9 : #include "mozilla/ArrayUtils.h"
10 : #include <string.h>
11 :
12 : #ifdef XP_WIN
13 : #include "ws2tcpip.h"
14 : #endif
15 :
16 : namespace mozilla {
17 : namespace net {
18 :
19 0 : const char *inet_ntop_internal(int af, const void *src, char *dst, socklen_t size)
20 : {
21 : #ifdef XP_WIN
22 : if (af == AF_INET) {
23 : struct sockaddr_in s;
24 : memset(&s, 0, sizeof(s));
25 : s.sin_family = AF_INET;
26 : memcpy(&s.sin_addr, src, sizeof(struct in_addr));
27 : int result = getnameinfo((struct sockaddr *)&s, sizeof(struct sockaddr_in),
28 : dst, size, nullptr, 0, NI_NUMERICHOST);
29 : if (result == 0) {
30 : return dst;
31 : }
32 : }
33 : else if (af == AF_INET6) {
34 : struct sockaddr_in6 s;
35 : memset(&s, 0, sizeof(s));
36 : s.sin6_family = AF_INET6;
37 : memcpy(&s.sin6_addr, src, sizeof(struct in_addr6));
38 : int result = getnameinfo((struct sockaddr *)&s, sizeof(struct sockaddr_in6),
39 : dst, size, nullptr, 0, NI_NUMERICHOST);
40 : if (result == 0) {
41 : return dst;
42 : }
43 : }
44 : return nullptr;
45 : #else
46 0 : return inet_ntop(af, src, dst, size);
47 : #endif
48 : }
49 :
50 : // Copies the contents of a PRNetAddr to a NetAddr.
51 : // Does not do a ptr safety check!
52 6 : void PRNetAddrToNetAddr(const PRNetAddr *prAddr, NetAddr *addr)
53 : {
54 6 : if (prAddr->raw.family == PR_AF_INET) {
55 6 : addr->inet.family = AF_INET;
56 6 : addr->inet.port = prAddr->inet.port;
57 6 : addr->inet.ip = prAddr->inet.ip;
58 : }
59 0 : else if (prAddr->raw.family == PR_AF_INET6) {
60 0 : addr->inet6.family = AF_INET6;
61 0 : addr->inet6.port = prAddr->ipv6.port;
62 0 : addr->inet6.flowinfo = prAddr->ipv6.flowinfo;
63 0 : memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8));
64 0 : addr->inet6.scope_id = prAddr->ipv6.scope_id;
65 : }
66 : #if defined(XP_UNIX)
67 0 : else if (prAddr->raw.family == PR_AF_LOCAL) {
68 0 : addr->local.family = AF_LOCAL;
69 0 : memcpy(addr->local.path, prAddr->local.path, sizeof(addr->local.path));
70 : }
71 : #endif
72 6 : }
73 :
74 : // Copies the contents of a NetAddr to a PRNetAddr.
75 : // Does not do a ptr safety check!
76 3 : void NetAddrToPRNetAddr(const NetAddr *addr, PRNetAddr *prAddr)
77 : {
78 3 : if (addr->raw.family == AF_INET) {
79 3 : prAddr->inet.family = PR_AF_INET;
80 3 : prAddr->inet.port = addr->inet.port;
81 3 : prAddr->inet.ip = addr->inet.ip;
82 : }
83 0 : else if (addr->raw.family == AF_INET6) {
84 0 : prAddr->ipv6.family = PR_AF_INET6;
85 0 : prAddr->ipv6.port = addr->inet6.port;
86 0 : prAddr->ipv6.flowinfo = addr->inet6.flowinfo;
87 0 : memcpy(&prAddr->ipv6.ip, &addr->inet6.ip, sizeof(addr->inet6.ip.u8));
88 0 : prAddr->ipv6.scope_id = addr->inet6.scope_id;
89 : }
90 : #if defined(XP_UNIX)
91 0 : else if (addr->raw.family == AF_LOCAL) {
92 0 : prAddr->local.family = PR_AF_LOCAL;
93 0 : memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path));
94 : }
95 : #elif defined(XP_WIN)
96 : else if (addr->raw.family == AF_LOCAL) {
97 : prAddr->local.family = PR_AF_LOCAL;
98 : memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path));
99 : }
100 : #endif
101 3 : }
102 :
103 0 : bool NetAddrToString(const NetAddr *addr, char *buf, uint32_t bufSize)
104 : {
105 0 : if (addr->raw.family == AF_INET) {
106 0 : if (bufSize < INET_ADDRSTRLEN) {
107 0 : return false;
108 : }
109 0 : struct in_addr nativeAddr = {};
110 0 : nativeAddr.s_addr = addr->inet.ip;
111 0 : return !!inet_ntop_internal(AF_INET, &nativeAddr, buf, bufSize);
112 : }
113 0 : if (addr->raw.family == AF_INET6) {
114 0 : if (bufSize < INET6_ADDRSTRLEN) {
115 0 : return false;
116 : }
117 0 : struct in6_addr nativeAddr = {};
118 0 : memcpy(&nativeAddr.s6_addr, &addr->inet6.ip, sizeof(addr->inet6.ip.u8));
119 0 : return !!inet_ntop_internal(AF_INET6, &nativeAddr, buf, bufSize);
120 : }
121 : #if defined(XP_UNIX)
122 0 : else if (addr->raw.family == AF_LOCAL) {
123 0 : if (bufSize < sizeof(addr->local.path)) {
124 : // Many callers don't bother checking our return value, so
125 : // null-terminate just in case.
126 0 : if (bufSize > 0) {
127 0 : buf[0] = '\0';
128 : }
129 0 : return false;
130 : }
131 :
132 : // Usually, the size passed to memcpy should be the size of the
133 : // destination. Here, we know that the source is no larger than the
134 : // destination, so using the source's size is always safe, whereas
135 : // using the destination's size may cause us to read off the end of the
136 : // source.
137 0 : memcpy(buf, addr->local.path, sizeof(addr->local.path));
138 0 : return true;
139 : }
140 : #endif
141 0 : return false;
142 : }
143 :
144 3 : bool IsLoopBackAddress(const NetAddr *addr)
145 : {
146 3 : if (addr->raw.family == AF_INET) {
147 3 : return (addr->inet.ip == htonl(INADDR_LOOPBACK));
148 : }
149 0 : if (addr->raw.family == AF_INET6) {
150 0 : if (IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip)) {
151 0 : return true;
152 : }
153 0 : if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) &&
154 0 : IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_LOOPBACK)) {
155 0 : return true;
156 : }
157 : }
158 0 : return false;
159 : }
160 :
161 0 : bool IsIPAddrAny(const NetAddr *addr)
162 : {
163 0 : if (addr->raw.family == AF_INET) {
164 0 : if (addr->inet.ip == htonl(INADDR_ANY)) {
165 0 : return true;
166 : }
167 : }
168 0 : else if (addr->raw.family == AF_INET6) {
169 0 : if (IPv6ADDR_IS_UNSPECIFIED(&addr->inet6.ip)) {
170 0 : return true;
171 : }
172 0 : if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) &&
173 0 : IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_ANY)) {
174 0 : return true;
175 : }
176 : }
177 0 : return false;
178 : }
179 :
180 0 : bool IsIPAddrV4Mapped(const NetAddr *addr)
181 : {
182 0 : if (addr->raw.family == AF_INET6) {
183 0 : return IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip);
184 : }
185 0 : return false;
186 : }
187 :
188 1 : bool IsIPAddrLocal(const NetAddr *addr)
189 : {
190 1 : MOZ_ASSERT(addr);
191 :
192 : // IPv4 RFC1918 and Link Local Addresses.
193 1 : if (addr->raw.family == AF_INET) {
194 1 : uint32_t addr32 = ntohl(addr->inet.ip);
195 2 : if (addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918).
196 2 : addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918).
197 2 : addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918).
198 1 : addr32 >> 16 == 0xA9FE) { // 169.254/16 prefix (Link Local).
199 0 : return true;
200 : }
201 : }
202 : // IPv6 Unique and Link Local Addresses.
203 1 : if (addr->raw.family == AF_INET6) {
204 0 : uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]);
205 0 : if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address.
206 0 : addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address.
207 0 : return true;
208 : }
209 : }
210 : // Not an IPv4/6 local address.
211 1 : return false;
212 : }
213 :
214 : nsresult
215 0 : GetPort(const NetAddr *aAddr, uint16_t *aResult)
216 : {
217 : uint16_t port;
218 0 : if (aAddr->raw.family == PR_AF_INET) {
219 0 : port = aAddr->inet.port;
220 0 : } else if (aAddr->raw.family == PR_AF_INET6) {
221 0 : port = aAddr->inet6.port;
222 : } else {
223 0 : return NS_ERROR_NOT_INITIALIZED;
224 : }
225 :
226 0 : *aResult = ntohs(port);
227 0 : return NS_OK;
228 : }
229 :
230 : bool
231 0 : NetAddr::operator == (const NetAddr& other) const
232 : {
233 0 : if (this->raw.family != other.raw.family) {
234 0 : return false;
235 : }
236 0 : if (this->raw.family == AF_INET) {
237 0 : return (this->inet.port == other.inet.port) &&
238 0 : (this->inet.ip == other.inet.ip);
239 : }
240 0 : if (this->raw.family == AF_INET6) {
241 0 : return (this->inet6.port == other.inet6.port) &&
242 0 : (this->inet6.flowinfo == other.inet6.flowinfo) &&
243 0 : (memcmp(&this->inet6.ip, &other.inet6.ip,
244 0 : sizeof(this->inet6.ip)) == 0) &&
245 0 : (this->inet6.scope_id == other.inet6.scope_id);
246 : #if defined(XP_UNIX)
247 : }
248 0 : if (this->raw.family == AF_LOCAL) {
249 0 : return PL_strncmp(this->local.path, other.local.path,
250 0 : ArrayLength(this->local.path));
251 : #endif
252 : }
253 0 : return false;
254 : }
255 :
256 : bool
257 0 : NetAddr::operator < (const NetAddr& other) const
258 : {
259 0 : if (this->raw.family != other.raw.family) {
260 0 : return this->raw.family < other.raw.family;
261 : }
262 0 : if (this->raw.family == AF_INET) {
263 0 : if (this->inet.ip == other.inet.ip) {
264 0 : return this->inet.port < other.inet.port;
265 : }
266 0 : return this->inet.ip < other.inet.ip;
267 : }
268 0 : if (this->raw.family == AF_INET6) {
269 0 : int cmpResult = memcmp(&this->inet6.ip, &other.inet6.ip,
270 0 : sizeof(this->inet6.ip));
271 0 : if (cmpResult) {
272 0 : return cmpResult < 0;
273 : }
274 0 : if (this->inet6.port != other.inet6.port) {
275 0 : return this->inet6.port < other.inet6.port;
276 : }
277 0 : return this->inet6.flowinfo < other.inet6.flowinfo;
278 : }
279 0 : return false;
280 : }
281 :
282 1 : NetAddrElement::NetAddrElement(const PRNetAddr *prNetAddr)
283 : {
284 1 : PRNetAddrToNetAddr(prNetAddr, &mAddress);
285 1 : }
286 :
287 1 : NetAddrElement::NetAddrElement(const NetAddrElement& netAddr)
288 : {
289 1 : mAddress = netAddr.mAddress;
290 1 : }
291 :
292 : NetAddrElement::~NetAddrElement() = default;
293 :
294 1 : AddrInfo::AddrInfo(const char *host, const PRAddrInfo *prAddrInfo,
295 1 : bool disableIPv4, bool filterNameCollision, const char *cname)
296 : : mHostName(nullptr)
297 : , mCanonicalName(nullptr)
298 1 : , ttl(NO_TTL_DATA)
299 : {
300 1 : MOZ_ASSERT(prAddrInfo, "Cannot construct AddrInfo with a null prAddrInfo pointer!");
301 1 : const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53
302 :
303 1 : Init(host, cname);
304 : PRNetAddr tmpAddr;
305 1 : void *iter = nullptr;
306 1 : do {
307 2 : iter = PR_EnumerateAddrInfo(iter, prAddrInfo, 0, &tmpAddr);
308 1 : bool addIt = iter &&
309 4 : (!disableIPv4 || tmpAddr.raw.family != PR_AF_INET) &&
310 4 : (!filterNameCollision || tmpAddr.raw.family != PR_AF_INET || (tmpAddr.inet.ip != nameCollisionAddr));
311 2 : if (addIt) {
312 1 : auto *addrElement = new NetAddrElement(&tmpAddr);
313 1 : mAddresses.insertBack(addrElement);
314 : }
315 2 : } while (iter);
316 1 : }
317 :
318 1 : AddrInfo::AddrInfo(const char *host, const char *cname)
319 : : mHostName(nullptr)
320 : , mCanonicalName(nullptr)
321 1 : , ttl(NO_TTL_DATA)
322 : {
323 1 : Init(host, cname);
324 1 : }
325 :
326 0 : AddrInfo::~AddrInfo()
327 : {
328 : NetAddrElement *addrElement;
329 0 : while ((addrElement = mAddresses.popLast())) {
330 0 : delete addrElement;
331 : }
332 0 : free(mHostName);
333 0 : free(mCanonicalName);
334 0 : }
335 :
336 : void
337 2 : AddrInfo::Init(const char *host, const char *cname)
338 : {
339 2 : MOZ_ASSERT(host, "Cannot initialize AddrInfo with a null host pointer!");
340 :
341 2 : ttl = NO_TTL_DATA;
342 2 : size_t hostlen = strlen(host);
343 2 : mHostName = static_cast<char*>(moz_xmalloc(hostlen + 1));
344 2 : memcpy(mHostName, host, hostlen + 1);
345 2 : if (cname) {
346 0 : size_t cnameLen = strlen(cname);
347 0 : mCanonicalName = static_cast<char*>(moz_xmalloc(cnameLen + 1));
348 0 : memcpy(mCanonicalName, cname, cnameLen + 1);
349 : }
350 : else {
351 2 : mCanonicalName = nullptr;
352 : }
353 2 : }
354 :
355 : void
356 1 : AddrInfo::AddAddress(NetAddrElement *address)
357 : {
358 1 : MOZ_ASSERT(address, "Cannot add the address to an uninitialized list");
359 :
360 1 : mAddresses.insertBack(address);
361 1 : }
362 :
363 : size_t
364 0 : AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
365 : {
366 0 : size_t n = mallocSizeOf(this);
367 0 : n += mallocSizeOf(mHostName);
368 0 : n += mallocSizeOf(mCanonicalName);
369 0 : n += mAddresses.sizeOfExcludingThis(mallocSizeOf);
370 0 : return n;
371 : }
372 :
373 : } // namespace net
374 : } // namespace mozilla
|