1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/io/pripv6.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,364 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** File: pripv6.c 1.11 +** Description: Support for various functions unique to IPv6 1.12 +*/ 1.13 +#include "primpl.h" 1.14 +#include <string.h> 1.15 + 1.16 +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) 1.17 + 1.18 +static PRIOMethods ipv6_to_v4_tcpMethods; 1.19 +static PRIOMethods ipv6_to_v4_udpMethods; 1.20 +static PRDescIdentity _pr_ipv6_to_ipv4_id; 1.21 +extern PRBool IsValidNetAddr(const PRNetAddr *addr); 1.22 +extern PRIPv6Addr _pr_in6addr_any; 1.23 +extern PRIPv6Addr _pr_in6addr_loopback; 1.24 + 1.25 +/* 1.26 + * convert an IPv4-mapped IPv6 addr to an IPv4 addr 1.27 + */ 1.28 +static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr, 1.29 + PRNetAddr *dst_v4addr) 1.30 +{ 1.31 +const PRUint8 *srcp; 1.32 + 1.33 + PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family); 1.34 + 1.35 + if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) { 1.36 + srcp = src_v6addr->ipv6.ip.pr_s6_addr; 1.37 + memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4); 1.38 + } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) { 1.39 + dst_v4addr->inet.ip = htonl(INADDR_ANY); 1.40 + } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) { 1.41 + dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK); 1.42 + } 1.43 + dst_v4addr->inet.family = PR_AF_INET; 1.44 + dst_v4addr->inet.port = src_v6addr->ipv6.port; 1.45 +} 1.46 + 1.47 +/* 1.48 + * convert an IPv4 addr to an IPv4-mapped IPv6 addr 1.49 + */ 1.50 +static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr, 1.51 + PRNetAddr *dst_v6addr) 1.52 +{ 1.53 +PRUint8 *dstp; 1.54 + 1.55 + PR_ASSERT(PR_AF_INET == src_v4addr->inet.family); 1.56 + dst_v6addr->ipv6.family = PR_AF_INET6; 1.57 + dst_v6addr->ipv6.port = src_v4addr->inet.port; 1.58 + 1.59 + if (htonl(INADDR_ANY) == src_v4addr->inet.ip) { 1.60 + dst_v6addr->ipv6.ip = _pr_in6addr_any; 1.61 + } else { 1.62 + dstp = dst_v6addr->ipv6.ip.pr_s6_addr; 1.63 + memset(dstp, 0, 10); 1.64 + memset(dstp + 10, 0xff, 2); 1.65 + memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4); 1.66 + } 1.67 +} 1.68 + 1.69 +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd, 1.70 + const PRNetAddr *addr) 1.71 +{ 1.72 + PRNetAddr tmp_ipv4addr; 1.73 + const PRNetAddr *tmp_addrp; 1.74 + PRFileDesc *lo = fd->lower; 1.75 + 1.76 + if (PR_AF_INET6 != addr->raw.family) { 1.77 + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 1.78 + return PR_FAILURE; 1.79 + } 1.80 + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || 1.81 + PR_IsNetAddrType(addr, PR_IpAddrAny)) { 1.82 + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); 1.83 + tmp_addrp = &tmp_ipv4addr; 1.84 + } else { 1.85 + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); 1.86 + return PR_FAILURE; 1.87 + } 1.88 + return((lo->methods->bind)(lo,tmp_addrp)); 1.89 +} 1.90 + 1.91 +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect( 1.92 + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) 1.93 +{ 1.94 + PRNetAddr tmp_ipv4addr; 1.95 + const PRNetAddr *tmp_addrp; 1.96 + 1.97 + if (PR_AF_INET6 != addr->raw.family) { 1.98 + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 1.99 + return PR_FAILURE; 1.100 + } 1.101 + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || 1.102 + PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { 1.103 + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); 1.104 + tmp_addrp = &tmp_ipv4addr; 1.105 + } else { 1.106 + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); 1.107 + return PR_FAILURE; 1.108 + } 1.109 + return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout); 1.110 +} 1.111 + 1.112 +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo( 1.113 + PRFileDesc *fd, const void *buf, PRInt32 amount, 1.114 + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) 1.115 +{ 1.116 + PRNetAddr tmp_ipv4addr; 1.117 + const PRNetAddr *tmp_addrp; 1.118 + 1.119 + if (PR_AF_INET6 != addr->raw.family) { 1.120 + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 1.121 + return PR_FAILURE; 1.122 + } 1.123 + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || 1.124 + PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { 1.125 + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); 1.126 + tmp_addrp = &tmp_ipv4addr; 1.127 + } else { 1.128 + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); 1.129 + return PR_FAILURE; 1.130 + } 1.131 + return (fd->lower->methods->sendto)( 1.132 + fd->lower, buf, amount, flags, tmp_addrp, timeout); 1.133 +} 1.134 + 1.135 +static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept ( 1.136 + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) 1.137 +{ 1.138 + PRStatus rv; 1.139 + PRFileDesc *newfd; 1.140 + PRFileDesc *newstack; 1.141 + PRNetAddr tmp_ipv4addr; 1.142 + PRNetAddr *addrlower = NULL; 1.143 + 1.144 + PR_ASSERT(fd != NULL); 1.145 + PR_ASSERT(fd->lower != NULL); 1.146 + 1.147 + newstack = PR_NEW(PRFileDesc); 1.148 + if (NULL == newstack) 1.149 + { 1.150 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.151 + return NULL; 1.152 + } 1.153 + *newstack = *fd; /* make a copy of the accepting layer */ 1.154 + 1.155 + if (addr) 1.156 + addrlower = &tmp_ipv4addr; 1.157 + newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout); 1.158 + if (NULL == newfd) 1.159 + { 1.160 + PR_DELETE(newstack); 1.161 + return NULL; 1.162 + } 1.163 + if (addr) 1.164 + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr); 1.165 + 1.166 + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); 1.167 + PR_ASSERT(PR_SUCCESS == rv); 1.168 + return newfd; /* that's it */ 1.169 +} 1.170 + 1.171 +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd, 1.172 + PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount, 1.173 + PRIntervalTime timeout) 1.174 +{ 1.175 + PRInt32 nbytes; 1.176 + PRStatus rv; 1.177 + PRNetAddr tmp_ipv4addr; 1.178 + PRFileDesc *newstack; 1.179 + 1.180 + PR_ASSERT(sd != NULL); 1.181 + PR_ASSERT(sd->lower != NULL); 1.182 + 1.183 + newstack = PR_NEW(PRFileDesc); 1.184 + if (NULL == newstack) 1.185 + { 1.186 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.187 + return -1; 1.188 + } 1.189 + *newstack = *sd; /* make a copy of the accepting layer */ 1.190 + 1.191 + nbytes = sd->lower->methods->acceptread( 1.192 + sd->lower, nd, ipv6_raddr, buf, amount, timeout); 1.193 + if (-1 == nbytes) 1.194 + { 1.195 + PR_DELETE(newstack); 1.196 + return nbytes; 1.197 + } 1.198 + tmp_ipv4addr = **ipv6_raddr; /* copy */ 1.199 + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr); 1.200 + 1.201 + /* this PR_PushIOLayer call cannot fail */ 1.202 + rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); 1.203 + PR_ASSERT(PR_SUCCESS == rv); 1.204 + return nbytes; 1.205 +} 1.206 + 1.207 +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd, 1.208 + PRNetAddr *ipv6addr) 1.209 +{ 1.210 + PRStatus result; 1.211 + PRNetAddr tmp_ipv4addr; 1.212 + 1.213 + result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr); 1.214 + if (PR_SUCCESS == result) { 1.215 + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); 1.216 + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); 1.217 + } 1.218 + return result; 1.219 +} 1.220 + 1.221 +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd, 1.222 + PRNetAddr *ipv6addr) 1.223 +{ 1.224 + PRStatus result; 1.225 + PRNetAddr tmp_ipv4addr; 1.226 + 1.227 + result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr); 1.228 + if (PR_SUCCESS == result) { 1.229 + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); 1.230 + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); 1.231 + } 1.232 + return result; 1.233 +} 1.234 + 1.235 +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf, 1.236 + PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr, 1.237 + PRIntervalTime timeout) 1.238 +{ 1.239 + PRNetAddr tmp_ipv4addr; 1.240 + PRInt32 result; 1.241 + 1.242 + result = (fd->lower->methods->recvfrom)( 1.243 + fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout); 1.244 + if (-1 != result) { 1.245 + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); 1.246 + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); 1.247 + } 1.248 + return result; 1.249 +} 1.250 + 1.251 +#if defined(_PR_INET6_PROBE) 1.252 +static PRBool ipv6_is_present; 1.253 +extern PRBool _pr_test_ipv6_socket(void); 1.254 + 1.255 +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.256 +extern PRStatus _pr_find_getipnodebyname(void); 1.257 +#endif 1.258 + 1.259 +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) 1.260 +extern PRStatus _pr_find_getaddrinfo(void); 1.261 +#endif 1.262 + 1.263 +static PRBool 1.264 +_pr_probe_ipv6_presence(void) 1.265 +{ 1.266 +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) 1.267 + if (_pr_find_getipnodebyname() != PR_SUCCESS) 1.268 + return PR_FALSE; 1.269 +#endif 1.270 + 1.271 +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) 1.272 + if (_pr_find_getaddrinfo() != PR_SUCCESS) 1.273 + return PR_FALSE; 1.274 +#endif 1.275 + 1.276 + return _pr_test_ipv6_socket(); 1.277 +} 1.278 +#endif /* _PR_INET6_PROBE */ 1.279 + 1.280 +static PRCallOnceType _pr_init_ipv6_once; 1.281 + 1.282 +static PRStatus PR_CALLBACK _pr_init_ipv6(void) 1.283 +{ 1.284 + const PRIOMethods *stubMethods; 1.285 + 1.286 +#if defined(_PR_INET6_PROBE) 1.287 + ipv6_is_present = _pr_probe_ipv6_presence(); 1.288 + if (ipv6_is_present) 1.289 + return PR_SUCCESS; 1.290 +#endif 1.291 + 1.292 + _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer"); 1.293 + PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id); 1.294 + 1.295 + stubMethods = PR_GetDefaultIOMethods(); 1.296 + 1.297 + ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */ 1.298 + /* then override the ones we care about */ 1.299 + ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect; 1.300 + ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind; 1.301 + ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept; 1.302 + ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead; 1.303 + ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName; 1.304 + ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; 1.305 +/* 1.306 + ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; 1.307 + ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; 1.308 +*/ 1.309 + ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */ 1.310 + /* then override the ones we care about */ 1.311 + ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect; 1.312 + ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind; 1.313 + ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo; 1.314 + ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom; 1.315 + ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName; 1.316 + ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; 1.317 +/* 1.318 + ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; 1.319 + ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; 1.320 +*/ 1.321 + return PR_SUCCESS; 1.322 +} 1.323 + 1.324 +#if defined(_PR_INET6_PROBE) 1.325 +PRBool _pr_ipv6_is_present(void) 1.326 +{ 1.327 + if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) 1.328 + return PR_FALSE; 1.329 + return ipv6_is_present; 1.330 +} 1.331 +#endif 1.332 + 1.333 +PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd) 1.334 +{ 1.335 + PRFileDesc *ipv6_fd = NULL; 1.336 + 1.337 + if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) 1.338 + return PR_FAILURE; 1.339 + 1.340 + /* 1.341 + * For platforms with no support for IPv6 1.342 + * create layered socket for IPv4-mapped IPv6 addresses 1.343 + */ 1.344 + if (fd->methods->file_type == PR_DESC_SOCKET_TCP) 1.345 + ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, 1.346 + &ipv6_to_v4_tcpMethods); 1.347 + else 1.348 + ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, 1.349 + &ipv6_to_v4_udpMethods); 1.350 + if (NULL == ipv6_fd) { 1.351 + goto errorExit; 1.352 + } 1.353 + ipv6_fd->secret = NULL; 1.354 + 1.355 + if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) { 1.356 + goto errorExit; 1.357 + } 1.358 + 1.359 + return PR_SUCCESS; 1.360 +errorExit: 1.361 + 1.362 + if (ipv6_fd) 1.363 + ipv6_fd->dtor(ipv6_fd); 1.364 + return PR_FAILURE; 1.365 +} 1.366 + 1.367 +#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */