nsprpub/pr/src/io/pripv6.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 /*
     7 ** File:        pripv6.c
     8 ** Description: Support for various functions unique to IPv6
     9 */
    10 #include "primpl.h"
    11 #include <string.h>
    13 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
    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;
    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;
    30 	PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
    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 }
    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;
    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;
    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 }
    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;
    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 }
    88 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
    89     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
    90 {
    91 	PRNetAddr tmp_ipv4addr;
    92 	const PRNetAddr *tmp_addrp;
    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 }
   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;
   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 }
   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;
   141     PR_ASSERT(fd != NULL);
   142     PR_ASSERT(fd->lower != NULL);
   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 */
   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);
   163     rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
   164     PR_ASSERT(PR_SUCCESS == rv);
   165     return newfd;  /* that's it */
   166 }
   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;
   177     PR_ASSERT(sd != NULL);
   178     PR_ASSERT(sd->lower != NULL);
   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 */
   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);
   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 }
   204 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
   205 										PRNetAddr *ipv6addr)
   206 {
   207 	PRStatus result;
   208 	PRNetAddr tmp_ipv4addr;
   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 }
   218 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
   219 										PRNetAddr *ipv6addr)
   220 {
   221 	PRStatus result;
   222 	PRNetAddr tmp_ipv4addr;
   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 }
   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;
   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 }
   248 #if defined(_PR_INET6_PROBE)
   249 static PRBool ipv6_is_present;
   250 extern PRBool _pr_test_ipv6_socket(void);
   252 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
   253 extern PRStatus _pr_find_getipnodebyname(void);
   254 #endif
   256 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
   257 extern PRStatus _pr_find_getaddrinfo(void);
   258 #endif
   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
   268 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
   269     if (_pr_find_getaddrinfo() != PR_SUCCESS)
   270         return PR_FALSE;
   271 #endif
   273     return _pr_test_ipv6_socket();
   274 }
   275 #endif  /* _PR_INET6_PROBE */
   277 static PRCallOnceType _pr_init_ipv6_once;
   279 static PRStatus PR_CALLBACK _pr_init_ipv6(void)
   280 {
   281     const PRIOMethods *stubMethods;
   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
   289     _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
   290     PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
   292 	stubMethods = PR_GetDefaultIOMethods();
   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 }
   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
   330 PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
   331 {
   332 	PRFileDesc *ipv6_fd = NULL;
   334 	if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
   335 		return PR_FAILURE;
   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;
   352 	if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
   353 		goto errorExit;
   354 	}
   356 	return PR_SUCCESS;
   357 errorExit:
   359 	if (ipv6_fd)
   360 		ipv6_fd->dtor(ipv6_fd);
   361 	return PR_FAILURE;
   362 }
   364 #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */

mercurial