Wed, 31 Dec 2014 06:55:46 +0100
Added tag TORBROWSER_REPLICA for changeset 6474c204b198
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/. */
5 #include "mozilla/net/DNS.h"
7 #include "mozilla/Assertions.h"
8 #include "mozilla/mozalloc.h"
9 #include "mozilla/ArrayUtils.h"
10 #include <string.h>
12 #ifdef XP_WIN
13 #include "ws2tcpip.h"
14 #endif
16 namespace mozilla {
17 namespace net {
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
181 bool IsIPAddrLocal(const NetAddr *addr)
182 {
183 MOZ_ASSERT(addr);
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 }
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 }
219 *aResult = ntohs(port);
220 return NS_OK;
221 }
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 }
248 NetAddrElement::NetAddrElement(const PRNetAddr *prNetAddr)
249 {
250 PRNetAddrToNetAddr(prNetAddr, &mAddress);
251 }
253 NetAddrElement::NetAddrElement(const NetAddrElement& netAddr)
254 {
255 mAddress = netAddr.mAddress;
256 }
258 NetAddrElement::~NetAddrElement()
259 {
260 }
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!");
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 }
279 AddrInfo::AddrInfo(const char *host, const char *cname)
280 {
281 Init(host, cname);
282 }
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 }
294 void
295 AddrInfo::Init(const char *host, const char *cname)
296 {
297 MOZ_ASSERT(host, "Cannot initialize AddrInfo with a null host pointer!");
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 }
312 void
313 AddrInfo::AddAddress(NetAddrElement *address)
314 {
315 MOZ_ASSERT(address, "Cannot add the address to an uninitialized list");
317 mAddresses.insertBack(address);
318 }
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 }
330 } // namespace dns
331 } // namespace mozilla