~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-updates

« back to all changes in this revision

Viewing changes to src/libs/xpcom18a4/nsprpub/pr/src/io/pripv6.c

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
4
 *
 
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/
 
9
 *
 
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
 
13
 * License.
 
14
 *
 
15
 * The Original Code is the Netscape Portable Runtime (NSPR).
 
16
 *
 
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.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
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.
 
35
 *
 
36
 * ***** END LICENSE BLOCK ***** */
 
37
 
 
38
/*
 
39
** File:        pripv6.c
 
40
** Description: Support for various functions unique to IPv6
 
41
*/
 
42
#include "primpl.h"
 
43
#include <string.h>
 
44
 
 
45
#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
 
46
 
 
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;
 
53
 
 
54
/*
 
55
 * convert an IPv4-mapped IPv6 addr to an IPv4 addr
 
56
 */
 
57
static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
 
58
                                                                                        PRNetAddr *dst_v4addr)
 
59
{
 
60
const PRUint8 *srcp;
 
61
 
 
62
        PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
 
63
 
 
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);
 
71
    }
 
72
        dst_v4addr->inet.family = PR_AF_INET;
 
73
        dst_v4addr->inet.port = src_v6addr->ipv6.port;
 
74
}
 
75
 
 
76
/*
 
77
 * convert an IPv4 addr to an IPv4-mapped IPv6 addr
 
78
 */
 
79
static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
 
80
                                            PRNetAddr *dst_v6addr)
 
81
{
 
82
PRUint8 *dstp;
 
83
 
 
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;
 
87
 
 
88
        if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
 
89
                dst_v6addr->ipv6.ip = _pr_in6addr_any;
 
90
        } else {
 
91
                dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
 
92
                memset(dstp, 0, 10);
 
93
                memset(dstp + 10, 0xff, 2);
 
94
                memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
 
95
        }
 
96
}
 
97
 
 
98
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
 
99
                                                                const PRNetAddr *addr)
 
100
{
 
101
        PRNetAddr tmp_ipv4addr;
 
102
        const PRNetAddr *tmp_addrp;
 
103
        PRFileDesc *lo = fd->lower;
 
104
 
 
105
        if (PR_AF_INET6 != addr->raw.family) {
 
106
        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
 
107
                return PR_FAILURE;
 
108
        }
 
109
        if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
 
110
                        PR_IsNetAddrType(addr, PR_IpAddrAny)) {
 
111
                _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
 
112
                tmp_addrp = &tmp_ipv4addr;
 
113
        } else {
 
114
        PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
 
115
                return PR_FAILURE;
 
116
        }
 
117
        return((lo->methods->bind)(lo,tmp_addrp));
 
118
}
 
119
 
 
120
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
 
121
    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
 
122
{
 
123
        PRNetAddr tmp_ipv4addr;
 
124
        const PRNetAddr *tmp_addrp;
 
125
 
 
126
        if (PR_AF_INET6 != addr->raw.family) {
 
127
        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
 
128
                return PR_FAILURE;
 
129
        }
 
130
        if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
 
131
                        PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
 
132
                _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
 
133
                tmp_addrp = &tmp_ipv4addr;
 
134
        } else {
 
135
        PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
 
136
                return PR_FAILURE;
 
137
        }
 
138
        return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
 
139
}
 
140
 
 
141
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
 
142
    PRFileDesc *fd, const void *buf, PRInt32 amount,
 
143
    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
 
144
{
 
145
        PRNetAddr tmp_ipv4addr;
 
146
        const PRNetAddr *tmp_addrp;
 
147
 
 
148
        if (PR_AF_INET6 != addr->raw.family) {
 
149
        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
 
150
                return PR_FAILURE;
 
151
        }
 
152
        if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
 
153
                        PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
 
154
                _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
 
155
                tmp_addrp = &tmp_ipv4addr;
 
156
        } else {
 
157
        PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
 
158
                return PR_FAILURE;
 
159
        }
 
160
    return (fd->lower->methods->sendto)(
 
161
        fd->lower, buf, amount, flags, tmp_addrp, timeout);
 
162
}
 
163
 
 
164
static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
 
165
    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
 
166
{
 
167
    PRStatus rv;
 
168
    PRFileDesc *newfd;
 
169
    PRFileDesc *newstack;
 
170
        PRNetAddr tmp_ipv4addr;
 
171
    PRNetAddr *addrlower = NULL;
 
172
 
 
173
    PR_ASSERT(fd != NULL);
 
174
    PR_ASSERT(fd->lower != NULL);
 
175
 
 
176
    newstack = PR_NEW(PRFileDesc);
 
177
    if (NULL == newstack)
 
178
    {
 
179
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
180
        return NULL;
 
181
    }
 
182
    *newstack = *fd;  /* make a copy of the accepting layer */
 
183
 
 
184
    if (addr)
 
185
        addrlower = &tmp_ipv4addr;
 
186
    newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
 
187
    if (NULL == newfd)
 
188
    {
 
189
        PR_DELETE(newstack);
 
190
        return NULL;
 
191
    }
 
192
    if (addr)
 
193
        _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
 
194
 
 
195
    rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
 
196
    PR_ASSERT(PR_SUCCESS == rv);
 
197
    return newfd;  /* that's it */
 
198
}
 
199
 
 
200
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
 
201
                        PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
 
202
                                                        PRIntervalTime timeout)
 
203
{
 
204
    PRInt32 nbytes;
 
205
    PRStatus rv;
 
206
        PRNetAddr tmp_ipv4addr;
 
207
    PRFileDesc *newstack;
 
208
 
 
209
    PR_ASSERT(sd != NULL);
 
210
    PR_ASSERT(sd->lower != NULL);
 
211
 
 
212
    newstack = PR_NEW(PRFileDesc);
 
213
    if (NULL == newstack)
 
214
    {
 
215
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
216
        return -1;
 
217
    }
 
218
    *newstack = *sd;  /* make a copy of the accepting layer */
 
219
 
 
220
    nbytes = sd->lower->methods->acceptread(
 
221
        sd->lower, nd, ipv6_raddr, buf, amount, timeout);
 
222
    if (-1 == nbytes)
 
223
    {
 
224
        PR_DELETE(newstack);
 
225
        return nbytes;
 
226
    }
 
227
        tmp_ipv4addr = **ipv6_raddr;    /* copy */
 
228
        _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
 
229
 
 
230
    /* this PR_PushIOLayer call cannot fail */
 
231
    rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
 
232
    PR_ASSERT(PR_SUCCESS == rv);
 
233
    return nbytes;
 
234
}
 
235
 
 
236
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
 
237
                                                                                PRNetAddr *ipv6addr)
 
238
{
 
239
        PRStatus result;
 
240
        PRNetAddr tmp_ipv4addr;
 
241
 
 
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);
 
246
        }
 
247
        return result;
 
248
}
 
249
 
 
250
static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
 
251
                                                                                PRNetAddr *ipv6addr)
 
252
{
 
253
        PRStatus result;
 
254
        PRNetAddr tmp_ipv4addr;
 
255
 
 
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);
 
260
        }
 
261
        return result;
 
262
}
 
263
 
 
264
static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
 
265
                        PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
 
266
                                PRIntervalTime timeout)
 
267
{
 
268
        PRNetAddr tmp_ipv4addr;
 
269
        PRInt32 result;
 
270
 
 
271
    result = (fd->lower->methods->recvfrom)(
 
272
        fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
 
273
        if (-1 != result) {
 
274
                _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
 
275
                PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
 
276
        }
 
277
        return result;
 
278
}
 
279
 
 
280
#if defined(_PR_INET6_PROBE)
 
281
PRBool _pr_ipv6_is_present;
 
282
extern PRBool _pr_test_ipv6_socket(void);
 
283
 
 
284
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
 
285
extern PRStatus _pr_find_getipnodebyname(void);
 
286
#endif
 
287
 
 
288
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
 
289
extern PRStatus _pr_find_getaddrinfo(void);
 
290
#endif
 
291
 
 
292
static PRBool
 
293
_pr_probe_ipv6_presence(void)
 
294
{
 
295
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
 
296
    if (_pr_find_getipnodebyname() != PR_SUCCESS)
 
297
        return PR_FALSE;
 
298
#endif
 
299
 
 
300
#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
 
301
    if (_pr_find_getaddrinfo() != PR_SUCCESS)
 
302
        return PR_FALSE;
 
303
#endif
 
304
 
 
305
    return _pr_test_ipv6_socket();
 
306
}
 
307
#endif  /* _PR_INET6_PROBE */
 
308
 
 
309
PRStatus _pr_init_ipv6()
 
310
{
 
311
    const PRIOMethods *stubMethods;
 
312
 
 
313
#if defined(_PR_INET6_PROBE)
 
314
    _pr_ipv6_is_present = _pr_probe_ipv6_presence();
 
315
    if (PR_TRUE == _pr_ipv6_is_present)
 
316
        return PR_SUCCESS;
 
317
#endif
 
318
 
 
319
    _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
 
320
    PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
 
321
 
 
322
        stubMethods = PR_GetDefaultIOMethods();
 
323
 
 
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;
 
332
/*
 
333
        ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
 
334
        ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
 
335
*/
 
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;
 
344
/*
 
345
        ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
 
346
        ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
 
347
*/
 
348
        return PR_SUCCESS;
 
349
}
 
350
 
 
351
PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
 
352
{
 
353
        PRFileDesc *ipv6_fd = NULL;
 
354
 
 
355
        /*
 
356
         * For platforms with no support for IPv6 
 
357
         * create layered socket for IPv4-mapped IPv6 addresses
 
358
         */
 
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);
 
362
        else
 
363
                ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
 
364
                                                                        &ipv6_to_v4_udpMethods);
 
365
        if (NULL == ipv6_fd) {
 
366
                goto errorExit;
 
367
        } 
 
368
        ipv6_fd->secret = NULL;
 
369
 
 
370
        if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
 
371
                goto errorExit;
 
372
        }
 
373
 
 
374
        return PR_SUCCESS;
 
375
errorExit:
 
376
 
 
377
        if (ipv6_fd)
 
378
                ipv6_fd->dtor(ipv6_fd);
 
379
        return PR_FAILURE;
 
380
}
 
381
 
 
382
#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */