|
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 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 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 void PRNetAddrToNetAddr(const PRNetAddr *prAddr, NetAddr *addr) |
|
53 { |
|
54 if (prAddr->raw.family == PR_AF_INET) { |
|
55 addr->inet.family = AF_INET; |
|
56 addr->inet.port = prAddr->inet.port; |
|
57 addr->inet.ip = prAddr->inet.ip; |
|
58 } |
|
59 else if (prAddr->raw.family == PR_AF_INET6) { |
|
60 addr->inet6.family = AF_INET6; |
|
61 addr->inet6.port = prAddr->ipv6.port; |
|
62 addr->inet6.flowinfo = prAddr->ipv6.flowinfo; |
|
63 memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8)); |
|
64 addr->inet6.scope_id = prAddr->ipv6.scope_id; |
|
65 } |
|
66 #if defined(XP_UNIX) |
|
67 else if (prAddr->raw.family == PR_AF_LOCAL) { |
|
68 addr->local.family = AF_LOCAL; |
|
69 memcpy(addr->local.path, prAddr->local.path, sizeof(addr->local.path)); |
|
70 } |
|
71 #endif |
|
72 } |
|
73 |
|
74 // Copies the contents of a NetAddr to a PRNetAddr. |
|
75 // Does not do a ptr safety check! |
|
76 void NetAddrToPRNetAddr(const NetAddr *addr, PRNetAddr *prAddr) |
|
77 { |
|
78 if (addr->raw.family == AF_INET) { |
|
79 prAddr->inet.family = PR_AF_INET; |
|
80 prAddr->inet.port = addr->inet.port; |
|
81 prAddr->inet.ip = addr->inet.ip; |
|
82 } |
|
83 else if (addr->raw.family == AF_INET6) { |
|
84 prAddr->ipv6.family = PR_AF_INET6; |
|
85 prAddr->ipv6.port = addr->inet6.port; |
|
86 prAddr->ipv6.flowinfo = addr->inet6.flowinfo; |
|
87 memcpy(&prAddr->ipv6.ip, &addr->inet6.ip, sizeof(addr->inet6.ip.u8)); |
|
88 prAddr->ipv6.scope_id = addr->inet6.scope_id; |
|
89 } |
|
90 #if defined(XP_UNIX) |
|
91 else if (addr->raw.family == AF_LOCAL) { |
|
92 prAddr->local.family = PR_AF_LOCAL; |
|
93 memcpy(prAddr->local.path, addr->local.path, sizeof(addr->local.path)); |
|
94 } |
|
95 #endif |
|
96 } |
|
97 |
|
98 bool NetAddrToString(const NetAddr *addr, char *buf, uint32_t bufSize) |
|
99 { |
|
100 if (addr->raw.family == AF_INET) { |
|
101 if (bufSize < INET_ADDRSTRLEN) { |
|
102 return false; |
|
103 } |
|
104 struct in_addr nativeAddr = {}; |
|
105 nativeAddr.s_addr = addr->inet.ip; |
|
106 return !!inet_ntop_internal(AF_INET, &nativeAddr, buf, bufSize); |
|
107 } |
|
108 else if (addr->raw.family == AF_INET6) { |
|
109 if (bufSize < INET6_ADDRSTRLEN) { |
|
110 return false; |
|
111 } |
|
112 struct in6_addr nativeAddr = {}; |
|
113 memcpy(&nativeAddr.s6_addr, &addr->inet6.ip, sizeof(addr->inet6.ip.u8)); |
|
114 return !!inet_ntop_internal(AF_INET6, &nativeAddr, buf, bufSize); |
|
115 } |
|
116 #if defined(XP_UNIX) |
|
117 else if (addr->raw.family == AF_LOCAL) { |
|
118 if (bufSize < sizeof(addr->local.path)) { |
|
119 // Many callers don't bother checking our return value, so |
|
120 // null-terminate just in case. |
|
121 if (bufSize > 0) { |
|
122 buf[0] = '\0'; |
|
123 } |
|
124 return false; |
|
125 } |
|
126 |
|
127 // Usually, the size passed to memcpy should be the size of the |
|
128 // destination. Here, we know that the source is no larger than the |
|
129 // destination, so using the source's size is always safe, whereas |
|
130 // using the destination's size may cause us to read off the end of the |
|
131 // source. |
|
132 memcpy(buf, addr->local.path, sizeof(addr->local.path)); |
|
133 return true; |
|
134 } |
|
135 #endif |
|
136 return false; |
|
137 } |
|
138 |
|
139 bool IsLoopBackAddress(const NetAddr *addr) |
|
140 { |
|
141 if (addr->raw.family == AF_INET) { |
|
142 return (addr->inet.ip == htonl(INADDR_LOOPBACK)); |
|
143 } |
|
144 else if (addr->raw.family == AF_INET6) { |
|
145 if (IPv6ADDR_IS_LOOPBACK(&addr->inet6.ip)) { |
|
146 return true; |
|
147 } else if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) && |
|
148 IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_LOOPBACK)) { |
|
149 return true; |
|
150 } |
|
151 } |
|
152 return false; |
|
153 } |
|
154 |
|
155 bool IsIPAddrAny(const NetAddr *addr) |
|
156 { |
|
157 if (addr->raw.family == AF_INET) { |
|
158 if (addr->inet.ip == htonl(INADDR_ANY)) { |
|
159 return true; |
|
160 } |
|
161 } |
|
162 else if (addr->raw.family == AF_INET6) { |
|
163 if (IPv6ADDR_IS_UNSPECIFIED(&addr->inet6.ip)) { |
|
164 return true; |
|
165 } else if (IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip) && |
|
166 IPv6ADDR_V4MAPPED_TO_IPADDR(&addr->inet6.ip) == htonl(INADDR_ANY)) { |
|
167 return true; |
|
168 } |
|
169 } |
|
170 return false; |
|
171 } |
|
172 |
|
173 bool IsIPAddrV4Mapped(const NetAddr *addr) |
|
174 { |
|
175 if (addr->raw.family == AF_INET6) { |
|
176 return IPv6ADDR_IS_V4MAPPED(&addr->inet6.ip); |
|
177 } |
|
178 return false; |
|
179 } |
|
180 |
|
181 bool IsIPAddrLocal(const NetAddr *addr) |
|
182 { |
|
183 MOZ_ASSERT(addr); |
|
184 |
|
185 // IPv4 RFC1918 and Link Local Addresses. |
|
186 if (addr->raw.family == AF_INET) { |
|
187 uint32_t addr32 = ntohl(addr->inet.ip); |
|
188 if (addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918). |
|
189 addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918). |
|
190 addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918). |
|
191 addr32 >> 16 == 0xA9FE) { // 169.254/16 prefix (Link Local). |
|
192 return true; |
|
193 } |
|
194 } |
|
195 // IPv6 Unique and Link Local Addresses. |
|
196 if (addr->raw.family == AF_INET6) { |
|
197 uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]); |
|
198 if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address. |
|
199 addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address. |
|
200 return true; |
|
201 } |
|
202 } |
|
203 // Not an IPv4/6 local address. |
|
204 return false; |
|
205 } |
|
206 |
|
207 nsresult |
|
208 GetPort(const NetAddr *aAddr, uint16_t *aResult) |
|
209 { |
|
210 uint16_t port; |
|
211 if (aAddr->raw.family == PR_AF_INET) { |
|
212 port = aAddr->inet.port; |
|
213 } else if (aAddr->raw.family == PR_AF_INET6) { |
|
214 port = aAddr->inet6.port; |
|
215 } else { |
|
216 return NS_ERROR_NOT_INITIALIZED; |
|
217 } |
|
218 |
|
219 *aResult = ntohs(port); |
|
220 return NS_OK; |
|
221 } |
|
222 |
|
223 bool |
|
224 NetAddr::operator == (const NetAddr& other) const |
|
225 { |
|
226 if (this->raw.family != other.raw.family) { |
|
227 return false; |
|
228 } else if (this->raw.family == AF_INET) { |
|
229 return (this->inet.port == other.inet.port) && |
|
230 (this->inet.ip == other.inet.ip); |
|
231 } else if (this->raw.family == AF_INET6) { |
|
232 return (this->inet6.port == other.inet6.port) && |
|
233 (this->inet6.flowinfo == other.inet6.flowinfo) && |
|
234 (memcmp(&this->inet6.ip, &other.inet6.ip, |
|
235 sizeof(this->inet6.ip)) == 0) && |
|
236 (this->inet6.scope_id == other.inet6.scope_id); |
|
237 #if defined(XP_UNIX) |
|
238 } else if (this->raw.family == AF_LOCAL) { |
|
239 return PL_strncmp(this->local.path, other.local.path, |
|
240 ArrayLength(this->local.path)); |
|
241 #endif |
|
242 } |
|
243 return false; |
|
244 } |
|
245 |
|
246 |
|
247 |
|
248 NetAddrElement::NetAddrElement(const PRNetAddr *prNetAddr) |
|
249 { |
|
250 PRNetAddrToNetAddr(prNetAddr, &mAddress); |
|
251 } |
|
252 |
|
253 NetAddrElement::NetAddrElement(const NetAddrElement& netAddr) |
|
254 { |
|
255 mAddress = netAddr.mAddress; |
|
256 } |
|
257 |
|
258 NetAddrElement::~NetAddrElement() |
|
259 { |
|
260 } |
|
261 |
|
262 AddrInfo::AddrInfo(const char *host, const PRAddrInfo *prAddrInfo, |
|
263 bool disableIPv4, const char *cname) |
|
264 { |
|
265 MOZ_ASSERT(prAddrInfo, "Cannot construct AddrInfo with a null prAddrInfo pointer!"); |
|
266 |
|
267 Init(host, cname); |
|
268 PRNetAddr tmpAddr; |
|
269 void *iter = nullptr; |
|
270 do { |
|
271 iter = PR_EnumerateAddrInfo(iter, prAddrInfo, 0, &tmpAddr); |
|
272 if (iter && (!disableIPv4 || tmpAddr.raw.family != PR_AF_INET)) { |
|
273 NetAddrElement *addrElement = new NetAddrElement(&tmpAddr); |
|
274 mAddresses.insertBack(addrElement); |
|
275 } |
|
276 } while (iter); |
|
277 } |
|
278 |
|
279 AddrInfo::AddrInfo(const char *host, const char *cname) |
|
280 { |
|
281 Init(host, cname); |
|
282 } |
|
283 |
|
284 AddrInfo::~AddrInfo() |
|
285 { |
|
286 NetAddrElement *addrElement; |
|
287 while ((addrElement = mAddresses.popLast())) { |
|
288 delete addrElement; |
|
289 } |
|
290 moz_free(mHostName); |
|
291 moz_free(mCanonicalName); |
|
292 } |
|
293 |
|
294 void |
|
295 AddrInfo::Init(const char *host, const char *cname) |
|
296 { |
|
297 MOZ_ASSERT(host, "Cannot initialize AddrInfo with a null host pointer!"); |
|
298 |
|
299 size_t hostlen = strlen(host); |
|
300 mHostName = static_cast<char*>(moz_xmalloc(hostlen + 1)); |
|
301 memcpy(mHostName, host, hostlen + 1); |
|
302 if (cname) { |
|
303 size_t cnameLen = strlen(cname); |
|
304 mCanonicalName = static_cast<char*>(moz_xmalloc(cnameLen + 1)); |
|
305 memcpy(mCanonicalName, cname, cnameLen + 1); |
|
306 } |
|
307 else { |
|
308 mCanonicalName = nullptr; |
|
309 } |
|
310 } |
|
311 |
|
312 void |
|
313 AddrInfo::AddAddress(NetAddrElement *address) |
|
314 { |
|
315 MOZ_ASSERT(address, "Cannot add the address to an uninitialized list"); |
|
316 |
|
317 mAddresses.insertBack(address); |
|
318 } |
|
319 |
|
320 size_t |
|
321 AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const |
|
322 { |
|
323 size_t n = mallocSizeOf(this); |
|
324 n += mallocSizeOf(mHostName); |
|
325 n += mallocSizeOf(mCanonicalName); |
|
326 n += mAddresses.sizeOfExcludingThis(mallocSizeOf); |
|
327 return n; |
|
328 } |
|
329 |
|
330 } // namespace dns |
|
331 } // namespace mozilla |