LCOV - code coverage report
Current view: top level - nsprpub/pr/src/io - pripv6.c (source / functions) Hit Total Coverage
Test: output.info Lines: 9 156 5.8 %
Date: 2017-07-14 16:53:18 Functions: 3 14 21.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13