comparison nspr/pr/src/io/pripv6.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*
7 ** File: pripv6.c
8 ** Description: Support for various functions unique to IPv6
9 */
10 #include "primpl.h"
11 #include <string.h>
12
13 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
14
15 static PRIOMethods ipv6_to_v4_tcpMethods;
16 static PRIOMethods ipv6_to_v4_udpMethods;
17 static PRDescIdentity _pr_ipv6_to_ipv4_id;
18 extern PRBool IsValidNetAddr(const PRNetAddr *addr);
19 extern PRIPv6Addr _pr_in6addr_any;
20 extern PRIPv6Addr _pr_in6addr_loopback;
21
22 /*
23 * convert an IPv4-mapped IPv6 addr to an IPv4 addr
24 */
25 static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
26 PRNetAddr *dst_v4addr)
27 {
28 const PRUint8 *srcp;
29
30 PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
31
32 if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
33 srcp = src_v6addr->ipv6.ip.pr_s6_addr;
34 memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
35 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
36 dst_v4addr->inet.ip = htonl(INADDR_ANY);
37 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
38 dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
39 }
40 dst_v4addr->inet.family = PR_AF_INET;
41 dst_v4addr->inet.port = src_v6addr->ipv6.port;
42 }
43
44 /*
45 * convert an IPv4 addr to an IPv4-mapped IPv6 addr
46 */
47 static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
48 PRNetAddr *dst_v6addr)
49 {
50 PRUint8 *dstp;
51
52 PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
53 dst_v6addr->ipv6.family = PR_AF_INET6;
54 dst_v6addr->ipv6.port = src_v4addr->inet.port;
55
56 if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
57 dst_v6addr->ipv6.ip = _pr_in6addr_any;
58 } else {
59 dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
60 memset(dstp, 0, 10);
61 memset(dstp + 10, 0xff, 2);
62 memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
63 }
64 }
65
66 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
67 const PRNetAddr *addr)
68 {
69 PRNetAddr tmp_ipv4addr;
70 const PRNetAddr *tmp_addrp;
71 PRFileDesc *lo = fd->lower;
72
73 if (PR_AF_INET6 != addr->raw.family) {
74 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
75 return PR_FAILURE;
76 }
77 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
78 PR_IsNetAddrType(addr, PR_IpAddrAny)) {
79 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
80 tmp_addrp = &tmp_ipv4addr;
81 } else {
82 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
83 return PR_FAILURE;
84 }
85 return((lo->methods->bind)(lo,tmp_addrp));
86 }
87
88 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
89 PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
90 {
91 PRNetAddr tmp_ipv4addr;
92 const PRNetAddr *tmp_addrp;
93
94 if (PR_AF_INET6 != addr->raw.family) {
95 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
96 return PR_FAILURE;
97 }
98 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
99 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
100 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
101 tmp_addrp = &tmp_ipv4addr;
102 } else {
103 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
104 return PR_FAILURE;
105 }
106 return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
107 }
108
109 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
110 PRFileDesc *fd, const void *buf, PRInt32 amount,
111 PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
112 {
113 PRNetAddr tmp_ipv4addr;
114 const PRNetAddr *tmp_addrp;
115
116 if (PR_AF_INET6 != addr->raw.family) {
117 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
118 return PR_FAILURE;
119 }
120 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
121 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
122 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
123 tmp_addrp = &tmp_ipv4addr;
124 } else {
125 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
126 return PR_FAILURE;
127 }
128 return (fd->lower->methods->sendto)(
129 fd->lower, buf, amount, flags, tmp_addrp, timeout);
130 }
131
132 static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
133 PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
134 {
135 PRStatus rv;
136 PRFileDesc *newfd;
137 PRFileDesc *newstack;
138 PRNetAddr tmp_ipv4addr;
139 PRNetAddr *addrlower = NULL;
140
141 PR_ASSERT(fd != NULL);
142 PR_ASSERT(fd->lower != NULL);
143
144 newstack = PR_NEW(PRFileDesc);
145 if (NULL == newstack)
146 {
147 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
148 return NULL;
149 }
150 *newstack = *fd; /* make a copy of the accepting layer */
151
152 if (addr)
153 addrlower = &tmp_ipv4addr;
154 newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
155 if (NULL == newfd)
156 {
157 PR_DELETE(newstack);
158 return NULL;
159 }
160 if (addr)
161 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
162
163 rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
164 PR_ASSERT(PR_SUCCESS == rv);
165 return newfd; /* that's it */
166 }
167
168 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
169 PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
170 PRIntervalTime timeout)
171 {
172 PRInt32 nbytes;
173 PRStatus rv;
174 PRNetAddr tmp_ipv4addr;
175 PRFileDesc *newstack;
176
177 PR_ASSERT(sd != NULL);
178 PR_ASSERT(sd->lower != NULL);
179
180 newstack = PR_NEW(PRFileDesc);
181 if (NULL == newstack)
182 {
183 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
184 return -1;
185 }
186 *newstack = *sd; /* make a copy of the accepting layer */
187
188 nbytes = sd->lower->methods->acceptread(
189 sd->lower, nd, ipv6_raddr, buf, amount, timeout);
190 if (-1 == nbytes)
191 {
192 PR_DELETE(newstack);
193 return nbytes;
194 }
195 tmp_ipv4addr = **ipv6_raddr; /* copy */
196 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
197
198 /* this PR_PushIOLayer call cannot fail */
199 rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
200 PR_ASSERT(PR_SUCCESS == rv);
201 return nbytes;
202 }
203
204 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
205 PRNetAddr *ipv6addr)
206 {
207 PRStatus result;
208 PRNetAddr tmp_ipv4addr;
209
210 result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
211 if (PR_SUCCESS == result) {
212 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
213 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
214 }
215 return result;
216 }
217
218 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
219 PRNetAddr *ipv6addr)
220 {
221 PRStatus result;
222 PRNetAddr tmp_ipv4addr;
223
224 result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
225 if (PR_SUCCESS == result) {
226 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
227 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
228 }
229 return result;
230 }
231
232 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
233 PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
234 PRIntervalTime timeout)
235 {
236 PRNetAddr tmp_ipv4addr;
237 PRInt32 result;
238
239 result = (fd->lower->methods->recvfrom)(
240 fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
241 if (-1 != result) {
242 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
243 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
244 }
245 return result;
246 }
247
248 #if defined(_PR_INET6_PROBE)
249 static PRBool ipv6_is_present;
250 extern PRBool _pr_test_ipv6_socket(void);
251
252 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
253 extern PRStatus _pr_find_getipnodebyname(void);
254 #endif
255
256 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
257 extern PRStatus _pr_find_getaddrinfo(void);
258 #endif
259
260 static PRBool
261 _pr_probe_ipv6_presence(void)
262 {
263 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
264 if (_pr_find_getipnodebyname() != PR_SUCCESS)
265 return PR_FALSE;
266 #endif
267
268 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
269 if (_pr_find_getaddrinfo() != PR_SUCCESS)
270 return PR_FALSE;
271 #endif
272
273 return _pr_test_ipv6_socket();
274 }
275 #endif /* _PR_INET6_PROBE */
276
277 static PRCallOnceType _pr_init_ipv6_once;
278
279 static PRStatus PR_CALLBACK _pr_init_ipv6(void)
280 {
281 const PRIOMethods *stubMethods;
282
283 #if defined(_PR_INET6_PROBE)
284 ipv6_is_present = _pr_probe_ipv6_presence();
285 if (ipv6_is_present)
286 return PR_SUCCESS;
287 #endif
288
289 _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
290 PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
291
292 stubMethods = PR_GetDefaultIOMethods();
293
294 ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */
295 /* then override the ones we care about */
296 ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
297 ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
298 ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
299 ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
300 ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
301 ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
302 /*
303 ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
304 ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
305 */
306 ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */
307 /* then override the ones we care about */
308 ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
309 ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
310 ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
311 ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
312 ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName;
313 ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
314 /*
315 ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
316 ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
317 */
318 return PR_SUCCESS;
319 }
320
321 #if defined(_PR_INET6_PROBE)
322 PRBool _pr_ipv6_is_present(void)
323 {
324 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
325 return PR_FALSE;
326 return ipv6_is_present;
327 }
328 #endif
329
330 PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
331 {
332 PRFileDesc *ipv6_fd = NULL;
333
334 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
335 return PR_FAILURE;
336
337 /*
338 * For platforms with no support for IPv6
339 * create layered socket for IPv4-mapped IPv6 addresses
340 */
341 if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
342 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
343 &ipv6_to_v4_tcpMethods);
344 else
345 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
346 &ipv6_to_v4_udpMethods);
347 if (NULL == ipv6_fd) {
348 goto errorExit;
349 }
350 ipv6_fd->secret = NULL;
351
352 if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
353 goto errorExit;
354 }
355
356 return PR_SUCCESS;
357 errorExit:
358
359 if (ipv6_fd)
360 ipv6_fd->dtor(ipv6_fd);
361 return PR_FAILURE;
362 }
363
364 #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)