1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is the Netscape Portable Runtime (NSPR).
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998-2000
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the MPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
40
** Description: Support for various functions unique to IPv6
45
#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
47
static PRIOMethods ipv6_to_v4_tcpMethods;
48
static PRIOMethods ipv6_to_v4_udpMethods;
49
static PRDescIdentity _pr_ipv6_to_ipv4_id;
50
extern PRBool IsValidNetAddr(const PRNetAddr *addr);
51
extern PRIPv6Addr _pr_in6addr_any;
52
extern PRIPv6Addr _pr_in6addr_loopback;
55
* convert an IPv4-mapped IPv6 addr to an IPv4 addr
57
static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
58
PRNetAddr *dst_v4addr)
62
PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
64
if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
65
srcp = src_v6addr->ipv6.ip.pr_s6_addr;
66
memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
67
} else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
68
dst_v4addr->inet.ip = htonl(INADDR_ANY);
69
} else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
70
dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
72
dst_v4addr->inet.family = PR_AF_INET;
73
dst_v4addr->inet.port = src_v6addr->ipv6.port;
77
* convert an IPv4 addr to an IPv4-mapped IPv6 addr
79
static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
80
PRNetAddr *dst_v6addr)
84
PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
85
dst_v6addr->ipv6.family = PR_AF_INET6;
86
dst_v6addr->ipv6.port = src_v4addr->inet.port;
88
if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
89
dst_v6addr->ipv6.ip = _pr_in6addr_any;
91
dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
93
memset(dstp + 10, 0xff, 2);
94
memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
98
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
99
const PRNetAddr *addr)
101
PRNetAddr tmp_ipv4addr;
102
const PRNetAddr *tmp_addrp;
103
PRFileDesc *lo = fd->lower;
105
if (PR_AF_INET6 != addr->raw.family) {
106
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
109
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
110
PR_IsNetAddrType(addr, PR_IpAddrAny)) {
111
_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
112
tmp_addrp = &tmp_ipv4addr;
114
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
117
return((lo->methods->bind)(lo,tmp_addrp));
120
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
121
PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
123
PRNetAddr tmp_ipv4addr;
124
const PRNetAddr *tmp_addrp;
126
if (PR_AF_INET6 != addr->raw.family) {
127
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
130
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
131
PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
132
_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
133
tmp_addrp = &tmp_ipv4addr;
135
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
138
return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
141
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
142
PRFileDesc *fd, const void *buf, PRInt32 amount,
143
PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
145
PRNetAddr tmp_ipv4addr;
146
const PRNetAddr *tmp_addrp;
148
if (PR_AF_INET6 != addr->raw.family) {
149
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
152
if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
153
PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
154
_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
155
tmp_addrp = &tmp_ipv4addr;
157
PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
160
return (fd->lower->methods->sendto)(
161
fd->lower, buf, amount, flags, tmp_addrp, timeout);
164
static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
165
PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
169
PRFileDesc *newstack;
170
PRNetAddr tmp_ipv4addr;
171
PRNetAddr *addrlower = NULL;
173
PR_ASSERT(fd != NULL);
174
PR_ASSERT(fd->lower != NULL);
176
newstack = PR_NEW(PRFileDesc);
177
if (NULL == newstack)
179
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
182
*newstack = *fd; /* make a copy of the accepting layer */
185
addrlower = &tmp_ipv4addr;
186
newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
193
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
195
rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
196
PR_ASSERT(PR_SUCCESS == rv);
197
return newfd; /* that's it */
200
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
201
PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
202
PRIntervalTime timeout)
206
PRNetAddr tmp_ipv4addr;
207
PRFileDesc *newstack;
209
PR_ASSERT(sd != NULL);
210
PR_ASSERT(sd->lower != NULL);
212
newstack = PR_NEW(PRFileDesc);
213
if (NULL == newstack)
215
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
218
*newstack = *sd; /* make a copy of the accepting layer */
220
nbytes = sd->lower->methods->acceptread(
221
sd->lower, nd, ipv6_raddr, buf, amount, timeout);
227
tmp_ipv4addr = **ipv6_raddr; /* copy */
228
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
230
/* this PR_PushIOLayer call cannot fail */
231
rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
232
PR_ASSERT(PR_SUCCESS == rv);
236
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
240
PRNetAddr tmp_ipv4addr;
242
result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
243
if (PR_SUCCESS == result) {
244
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
245
PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
250
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
254
PRNetAddr tmp_ipv4addr;
256
result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
257
if (PR_SUCCESS == result) {
258
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
259
PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
264
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
265
PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
266
PRIntervalTime timeout)
268
PRNetAddr tmp_ipv4addr;
271
result = (fd->lower->methods->recvfrom)(
272
fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
274
_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
275
PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
280
#if defined(_PR_INET6_PROBE)
281
PRBool _pr_ipv6_is_present;
282
extern PRBool _pr_test_ipv6_socket(void);
284
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
285
extern PRStatus _pr_find_getipnodebyname(void);
288
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
289
extern PRStatus _pr_find_getaddrinfo(void);
293
_pr_probe_ipv6_presence(void)
295
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
296
if (_pr_find_getipnodebyname() != PR_SUCCESS)
300
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
301
if (_pr_find_getaddrinfo() != PR_SUCCESS)
305
return _pr_test_ipv6_socket();
307
#endif /* _PR_INET6_PROBE */
309
PRStatus _pr_init_ipv6()
311
const PRIOMethods *stubMethods;
313
#if defined(_PR_INET6_PROBE)
314
_pr_ipv6_is_present = _pr_probe_ipv6_presence();
315
if (PR_TRUE == _pr_ipv6_is_present)
319
_pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
320
PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
322
stubMethods = PR_GetDefaultIOMethods();
324
ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */
325
/* then override the ones we care about */
326
ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
327
ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
328
ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
329
ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
330
ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
331
ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
333
ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
334
ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
336
ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */
337
/* then override the ones we care about */
338
ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
339
ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
340
ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
341
ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
342
ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
343
ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
345
ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
346
ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
351
PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
353
PRFileDesc *ipv6_fd = NULL;
356
* For platforms with no support for IPv6
357
* create layered socket for IPv4-mapped IPv6 addresses
359
if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
360
ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
361
&ipv6_to_v4_tcpMethods);
363
ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
364
&ipv6_to_v4_udpMethods);
365
if (NULL == ipv6_fd) {
368
ipv6_fd->secret = NULL;
370
if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
378
ipv6_fd->dtor(ipv6_fd);
382
#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */