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