pripv6.c (11674B)
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 const PRIPv6Addr _pr_in6addr_any; 20 extern const 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 const PRUint8* srcp; 28 29 PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family); 30 31 if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) { 32 srcp = src_v6addr->ipv6.ip.pr_s6_addr; 33 memcpy((char*)&dst_v4addr->inet.ip, srcp + 12, 4); 34 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) { 35 dst_v4addr->inet.ip = htonl(INADDR_ANY); 36 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) { 37 dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK); 38 } 39 dst_v4addr->inet.family = PR_AF_INET; 40 dst_v4addr->inet.port = src_v6addr->ipv6.port; 41 } 42 43 /* 44 * convert an IPv4 addr to an IPv4-mapped IPv6 addr 45 */ 46 static void _PR_ConvertToIpv6NetAddr(const PRNetAddr* src_v4addr, 47 PRNetAddr* dst_v6addr) { 48 PRUint8* dstp; 49 50 PR_ASSERT(PR_AF_INET == src_v4addr->inet.family); 51 dst_v6addr->ipv6.family = PR_AF_INET6; 52 dst_v6addr->ipv6.port = src_v4addr->inet.port; 53 54 if (htonl(INADDR_ANY) == src_v4addr->inet.ip) { 55 dst_v6addr->ipv6.ip = _pr_in6addr_any; 56 } else { 57 dstp = dst_v6addr->ipv6.ip.pr_s6_addr; 58 memset(dstp, 0, 10); 59 memset(dstp + 10, 0xff, 2); 60 memcpy(dstp + 12, (char*)&src_v4addr->inet.ip, 4); 61 } 62 } 63 64 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc* fd, 65 const PRNetAddr* addr) { 66 PRNetAddr tmp_ipv4addr; 67 const PRNetAddr* tmp_addrp; 68 PRFileDesc* lo = fd->lower; 69 70 if (PR_AF_INET6 != addr->raw.family) { 71 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 72 return PR_FAILURE; 73 } 74 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || 75 PR_IsNetAddrType(addr, PR_IpAddrAny)) { 76 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); 77 tmp_addrp = &tmp_ipv4addr; 78 } else { 79 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); 80 return PR_FAILURE; 81 } 82 return ((lo->methods->bind)(lo, tmp_addrp)); 83 } 84 85 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(PRFileDesc* fd, 86 const PRNetAddr* addr, 87 PRIntervalTime timeout) { 88 PRNetAddr tmp_ipv4addr; 89 const PRNetAddr* tmp_addrp; 90 91 if (PR_AF_INET6 != addr->raw.family) { 92 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 93 return PR_FAILURE; 94 } 95 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || 96 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { 97 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); 98 tmp_addrp = &tmp_ipv4addr; 99 } else { 100 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); 101 return PR_FAILURE; 102 } 103 return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout); 104 } 105 106 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(PRFileDesc* fd, 107 const void* buf, 108 PRInt32 amount, PRIntn flags, 109 const PRNetAddr* addr, 110 PRIntervalTime timeout) { 111 PRNetAddr tmp_ipv4addr; 112 const PRNetAddr* tmp_addrp; 113 114 if (PR_AF_INET6 != addr->raw.family) { 115 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); 116 return PR_FAILURE; 117 } 118 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || 119 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { 120 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); 121 tmp_addrp = &tmp_ipv4addr; 122 } else { 123 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); 124 return PR_FAILURE; 125 } 126 return (fd->lower->methods->sendto)(fd->lower, buf, amount, flags, tmp_addrp, 127 timeout); 128 } 129 130 static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept(PRFileDesc* fd, 131 PRNetAddr* addr, 132 PRIntervalTime timeout) { 133 PRStatus rv; 134 PRFileDesc* newfd; 135 PRFileDesc* newstack; 136 PRNetAddr tmp_ipv4addr; 137 PRNetAddr* addrlower = NULL; 138 139 PR_ASSERT(fd != NULL); 140 PR_ASSERT(fd->lower != NULL); 141 142 newstack = PR_NEW(PRFileDesc); 143 if (NULL == newstack) { 144 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 145 return NULL; 146 } 147 *newstack = *fd; /* make a copy of the accepting layer */ 148 149 if (addr) { 150 addrlower = &tmp_ipv4addr; 151 } 152 newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout); 153 if (NULL == newfd) { 154 PR_DELETE(newstack); 155 return NULL; 156 } 157 if (addr) { 158 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr); 159 } 160 161 rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); 162 PR_ASSERT(PR_SUCCESS == rv); 163 return newfd; /* that's it */ 164 } 165 166 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc* sd, 167 PRFileDesc** nd, 168 PRNetAddr** ipv6_raddr, 169 void* buf, PRInt32 amount, 170 PRIntervalTime timeout) { 171 PRInt32 nbytes; 172 PRStatus rv; 173 PRNetAddr tmp_ipv4addr; 174 PRFileDesc* newstack; 175 176 PR_ASSERT(sd != NULL); 177 PR_ASSERT(sd->lower != NULL); 178 179 newstack = PR_NEW(PRFileDesc); 180 if (NULL == newstack) { 181 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 182 return -1; 183 } 184 *newstack = *sd; /* make a copy of the accepting layer */ 185 186 nbytes = sd->lower->methods->acceptread(sd->lower, nd, ipv6_raddr, buf, 187 amount, timeout); 188 if (-1 == nbytes) { 189 PR_DELETE(newstack); 190 return nbytes; 191 } 192 tmp_ipv4addr = **ipv6_raddr; /* copy */ 193 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr); 194 195 /* this PR_PushIOLayer call cannot fail */ 196 rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); 197 PR_ASSERT(PR_SUCCESS == rv); 198 return nbytes; 199 } 200 201 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc* fd, 202 PRNetAddr* ipv6addr) { 203 PRStatus result; 204 PRNetAddr tmp_ipv4addr; 205 206 result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr); 207 if (PR_SUCCESS == result) { 208 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); 209 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); 210 } 211 return result; 212 } 213 214 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc* fd, 215 PRNetAddr* ipv6addr) { 216 PRStatus result; 217 PRNetAddr tmp_ipv4addr; 218 219 result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr); 220 if (PR_SUCCESS == result) { 221 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); 222 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); 223 } 224 return result; 225 } 226 227 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc* fd, void* buf, 228 PRInt32 amount, 229 PRIntn flags, 230 PRNetAddr* ipv6addr, 231 PRIntervalTime timeout) { 232 PRNetAddr tmp_ipv4addr; 233 PRInt32 result; 234 235 result = (fd->lower->methods->recvfrom)(fd->lower, buf, amount, flags, 236 &tmp_ipv4addr, timeout); 237 if (-1 != result) { 238 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); 239 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); 240 } 241 return result; 242 } 243 244 # if defined(_PR_INET6_PROBE) 245 static PRBool ipv6_is_present; 246 PR_EXTERN(PRBool) _pr_test_ipv6_socket(void); 247 248 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) 249 extern PRStatus _pr_find_getipnodebyname(void); 250 # endif 251 252 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) 253 extern PRStatus _pr_find_getaddrinfo(void); 254 # endif 255 256 static PRBool _pr_probe_ipv6_presence(void) { 257 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) 258 if (_pr_find_getipnodebyname() != PR_SUCCESS) { 259 return PR_FALSE; 260 } 261 # endif 262 263 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) 264 if (_pr_find_getaddrinfo() != PR_SUCCESS) { 265 return PR_FALSE; 266 } 267 # endif 268 269 return _pr_test_ipv6_socket(); 270 } 271 # endif /* _PR_INET6_PROBE */ 272 273 static PRCallOnceType _pr_init_ipv6_once; 274 275 static PRStatus PR_CALLBACK _pr_init_ipv6(void) { 276 const PRIOMethods* stubMethods; 277 278 # if defined(_PR_INET6_PROBE) 279 ipv6_is_present = _pr_probe_ipv6_presence(); 280 if (ipv6_is_present) { 281 return PR_SUCCESS; 282 } 283 # endif 284 285 _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer"); 286 PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id); 287 288 stubMethods = PR_GetDefaultIOMethods(); 289 290 ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */ 291 /* then override the ones we care about */ 292 ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect; 293 ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind; 294 ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept; 295 ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead; 296 ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName; 297 ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; 298 /* 299 ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; 300 ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; 301 */ 302 ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */ 303 /* then override the ones we care about */ 304 ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect; 305 ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind; 306 ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo; 307 ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom; 308 ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName; 309 ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; 310 /* 311 ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; 312 ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; 313 */ 314 return PR_SUCCESS; 315 } 316 317 # if defined(_PR_INET6_PROBE) 318 PRBool _pr_ipv6_is_present(void) { 319 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) { 320 return PR_FALSE; 321 } 322 return ipv6_is_present; 323 } 324 # endif 325 326 PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd) { 327 PRFileDesc* ipv6_fd = NULL; 328 329 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) { 330 return PR_FAILURE; 331 } 332 333 /* 334 * For platforms with no support for IPv6 335 * create layered socket for IPv4-mapped IPv6 addresses 336 */ 337 if (fd->methods->file_type == PR_DESC_SOCKET_TCP) 338 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, &ipv6_to_v4_tcpMethods); 339 else 340 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, &ipv6_to_v4_udpMethods); 341 if (NULL == ipv6_fd) { 342 goto errorExit; 343 } 344 ipv6_fd->secret = NULL; 345 346 if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) { 347 goto errorExit; 348 } 349 350 return PR_SUCCESS; 351 errorExit: 352 353 if (ipv6_fd) { 354 ipv6_fd->dtor(ipv6_fd); 355 } 356 return PR_FAILURE; 357 } 358 359 #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */