The error PR_ADDRESS_NOT_SUPPORTED_ERROR should be returned when ipv4 NSPRPUB_RELEASE_4_0_BRANCH
authorsrinivas%netscape.com
Thu, 27 Jan 2000 20:49:59 +0000
branchNSPRPUB_RELEASE_4_0_BRANCH
changeset 1106 7f4508e8ab3a474e0e3fcffc755c66c9c520760a
parent 1105 3f874c46de0c2f5111521bdb2cfc22b318cdf256
child 1107 0f4be47ea2396b84d4a47cb8676bac598142f767
push idunknown
push userunknown
push dateunknown
bugs23815
The error PR_ADDRESS_NOT_SUPPORTED_ERROR should be returned when ipv4 addresses are specified with AF_INET6 sockets. Fixed processing of loopback and unspecified addresses, for non-ipv6 platforms. Bugzilla 23815.
pr/src/io/pripv6.c
pr/src/misc/prnetdb.c
--- a/pr/src/io/pripv6.c
+++ b/pr/src/io/pripv6.c
@@ -22,93 +22,130 @@
 */
 #include "primpl.h"
 #include <string.h>
 
 static PRIOMethods ipv6_to_v4_tcpMethods;
 static PRIOMethods ipv6_to_v4_udpMethods;
 static PRDescIdentity _pr_ipv6_to_ipv4_id;
 extern PRBool IsValidNetAddr(const PRNetAddr *addr);
+extern PRIPv6Addr _pr_in6addr_any;
+extern PRIPv6Addr _pr_in6addr_loopback;
 
 /*
  * convert an IPv4-mapped IPv6 addr to an IPv4 addr
  */
-void ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
+static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
 											PRNetAddr *dst_v4addr)
 {
+const PRUint8 *srcp;
+
+	PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
+
+	if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
 #ifdef _PR_INET6
-const PRUint8 *srcp = src_v6addr->ipv6.ip.s6_addr;
+		srcp = src_v6addr->ipv6.ip.s6_addr;
 #else
-const PRUint8 *srcp = src_v6addr->ipv6.ip._pr_s6_addr;
+		srcp = src_v6addr->ipv6.ip._pr_s6_addr;
 #endif
+		memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
+    } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
+        dst_v4addr->inet.ip = htonl(INADDR_ANY);
+    } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
+        dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
+    }
 	dst_v4addr->inet.family = PR_AF_INET;
 	dst_v4addr->inet.port = src_v6addr->ipv6.port;
-	memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
 }
 
 /*
  * convert an IPv4 addr to an IPv4-mapped IPv6 addr
  */
-void ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
+static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
                                             PRNetAddr *dst_v6addr)
 {
-#ifdef _PR_INET6
-PRUint8 *dstp = dst_v6addr->ipv6.ip.s6_addr;
-#else
-PRUint8 *dstp = dst_v6addr->ipv6.ip._pr_s6_addr;
-#endif
+PRUint8 *dstp;
+
+	PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
 	dst_v6addr->ipv6.family = PR_AF_INET6;
 	dst_v6addr->ipv6.port = src_v4addr->inet.port;
-	memset(dstp, 0, 10);
-	memset(dstp + 10, 0xff, 2);
-	memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
+
+    if (htonl(INADDR_LOOPBACK) == src_v4addr->inet.ip) {
+		dst_v6addr->ipv6.ip = _pr_in6addr_loopback;
+	} else if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
+		dst_v6addr->ipv6.ip = _pr_in6addr_any;
+	} else {
+#ifdef _PR_INET6
+		dstp = dst_v6addr->ipv6.ip.s6_addr;
+#else
+		dstp = dst_v6addr->ipv6.ip._pr_s6_addr;
+#endif
+		memset(dstp, 0, 10);
+		memset(dstp + 10, 0xff, 2);
+		memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
+	}
 }
 
 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
 								const PRNetAddr *addr)
 {
 	PRNetAddr tmp_ipv4addr;
 	const PRNetAddr *tmp_addrp;
 	PRFileDesc *lo = fd->lower;
 
-	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
-		ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
+	if (PR_AF_INET6 != addr->raw.family) {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return PR_FAILURE;
+	}
+	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
+    			PR_IsNetAddrType(addr, PR_IpAddrAny)) {
+		_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
 		tmp_addrp = &tmp_ipv4addr;
 	} else {
         PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
 		return PR_FAILURE;
 	}
 	return((lo->methods->bind)(lo,tmp_addrp));
 }
 
 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
 {
 	PRNetAddr tmp_ipv4addr;
 	const PRNetAddr *tmp_addrp;
 
-	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
-		ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
+	if (PR_AF_INET6 != addr->raw.family) {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return PR_FAILURE;
+	}
+	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
+			PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
+		_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
 		tmp_addrp = &tmp_ipv4addr;
 	} else {
         PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
 		return PR_FAILURE;
 	}
 	return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
 }
 
 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
     PRFileDesc *fd, const void *buf, PRInt32 amount,
     PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
 {
 	PRNetAddr tmp_ipv4addr;
 	const PRNetAddr *tmp_addrp;
 
-	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
-		ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
+	if (PR_AF_INET6 != addr->raw.family) {
+        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
+		return PR_FAILURE;
+	}
+	if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
+			PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
+		_PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
 		tmp_addrp = &tmp_ipv4addr;
 	} else {
         PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
 		return PR_FAILURE;
 	}
     return (fd->lower->methods->sendto)(
         fd->lower, buf, amount, flags, tmp_addrp, timeout);
 }
@@ -133,17 +170,17 @@ static PRFileDesc* PR_CALLBACK Ipv6ToIpv
     *newstack = *fd;  /* make a copy of the accepting layer */
 
     newfd = (fd->lower->methods->accept)(fd->lower, &tmp_ipv4addr, timeout);
     if (NULL == newfd)
     {
         PR_DELETE(newstack);
         return NULL;
     }
-	ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
+	_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
 
     rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
     PR_ASSERT(PR_SUCCESS == rv);
     return newfd;  /* that's it */
 }
 
 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
 			PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
@@ -168,63 +205,63 @@ static PRInt32 PR_CALLBACK Ipv6ToIpv4Soc
     nbytes = sd->lower->methods->acceptread(
         sd->lower, nd, ipv6_raddr, buf, amount, timeout);
     if (-1 == nbytes)
     {
         PR_DELETE(newstack);
         return nbytes;
     }
 	tmp_ipv4addr = **ipv6_raddr;	/* copy */
-	ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
+	_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
 
     /* this PR_PushIOLayer call cannot fail */
     rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
     PR_ASSERT(PR_SUCCESS == rv);
     return nbytes;
 }
 
 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
 										PRNetAddr *ipv6addr)
 {
 	PRStatus result;
 	PRNetAddr tmp_ipv4addr;
 
 	result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
 	if (PR_SUCCESS == result) {
-		ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
+		_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
 		PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
 	}
 	return result;
 }
 
 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
 										PRNetAddr *ipv6addr)
 {
 	PRStatus result;
 	PRNetAddr tmp_ipv4addr;
 
 	result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
 	if (PR_SUCCESS == result) {
-		ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
+		_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
 		PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
 	}
 	return result;
 }
 
 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
 			PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
 				PRIntervalTime timeout)
 {
 	PRNetAddr tmp_ipv4addr;
 	PRInt32 result;
 
     result = (fd->lower->methods->recvfrom)(
         fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
 	if (-1 != result) {
-		ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
+		_PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
 		PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
 	}
 	return result;
 }
 
 PRStatus _pr_init_ipv6()
 {
 const PRIOMethods *stubMethods;
--- a/pr/src/misc/prnetdb.c
+++ b/pr/src/misc/prnetdb.c
@@ -91,48 +91,56 @@ static sigset_t timer_set;
 #define _PR_HAVE_5_ARG_GETPROTO_R
 #endif
 
 #if !defined(_PR_HAVE_GETPROTO_R)
 PRLock* _getproto_lock = NULL;
 #endif
 
 #if defined(_PR_INET6)
-const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
-const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+const struct in6_addr _pr_in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr _pr_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
 #define _PR_IN6_IS_ADDR_UNSPECIFIED	IN6_IS_ADDR_UNSPECIFIED
 #define _PR_IN6_IS_ADDR_LOOPBACK	IN6_IS_ADDR_LOOPBACK
 #define _PR_IN6_IS_ADDR_V4MAPPED	IN6_IS_ADDR_V4MAPPED
 #define _PR_IN6_IS_ADDR_V4COMPAT	IN6_IS_ADDR_V4COMPAT
 
+#if defined(SOLARIS)
+#define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->_S6_un._S6_u32[3])
+#else
 #define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->s6_addr32[3])
+#endif
 
 #else  /* _PR_INET6 */
 
-/*
- * The values at bytes 10 and 11 are compared using pointers to
- * 8-bit fields, and not 32-bit fields, to make the comparison work on
- * both big-endian and little-endian systems
- */
-
 #define _PR_IN6_IS_ADDR_UNSPECIFIED(a)			\
 				(((a)->_pr_s6_addr32[0] == 0) &&	\
 				((a)->_pr_s6_addr32[1] == 0) &&		\
 				((a)->_pr_s6_addr32[2] == 0) &&		\
 				((a)->_pr_s6_addr32[3] == 0))
  
+/*
+ * For non-ipv6 platforms, loopback address is never passed to the
+ * system, so the byte-ordering is not an issue
+ */
 #define _PR_IN6_IS_ADDR_LOOPBACK(a)				\
                (((a)->_pr_s6_addr32[0] == 0)	&&	\
                ((a)->_pr_s6_addr32[1] == 0)		&&	\
                ((a)->_pr_s6_addr32[2] == 0)		&&	\
-               ((a)->_pr_s6_addr[12] == 0)		&&	\
-               ((a)->_pr_s6_addr[13] == 0)		&&	\
-               ((a)->_pr_s6_addr[14] == 0)		&&	\
-               ((a)->_pr_s6_addr[15] == 0x01))
+               ((a)->_pr_s6_addr32[3] == 0x1))
  
+const PRIPv6Addr _pr_in6addr_any = { 0, 0, 0, 0 };
+const PRIPv6Addr _pr_in6addr_loopback = { 0, 0, 0, 0x00000001U };
+/*
+ * The values at bytes 10 and 11 are compared using pointers to
+ * 8-bit fields, and not 32-bit fields, to make the comparison work on
+ * both big-endian and little-endian systems
+ */
+
 #define _PR_IN6_IS_ADDR_V4MAPPED(a)			\
 		(((a)->_pr_s6_addr32[0] == 0) 	&&	\
 		((a)->_pr_s6_addr32[1] == 0)	&&	\
 		((a)->_pr_s6_addr[8] == 0)		&&	\
 		((a)->_pr_s6_addr[9] == 0)		&&	\
 		((a)->_pr_s6_addr[10] == 0xff)	&&	\
 		((a)->_pr_s6_addr[11] == 0xff))
 
@@ -140,17 +148,19 @@ const struct in6_addr in6addr_loopback =
 		(((a)->_pr_s6_addr32[0] == 0) &&	\
 		((a)->_pr_s6_addr32[1] == 0) &&		\
 		((a)->_pr_s6_addr32[2] == 0))
 
 #define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->_pr_s6_addr32[3])
 
 #endif /* _PR_INET6 */
 
+#if !defined(_PR_INET6)
 extern PRStatus _pr_init_ipv6();
+#endif
 
 void _PR_InitNet(void)
 {
 #if defined(XP_UNIX)
 #ifdef HAVE_NETCONFIG
 	/*
 	 * This one-liner prevents the endless re-open's and re-read's of
 	 * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc.
@@ -161,17 +171,19 @@ void _PR_InitNet(void)
 	sigaddset(&timer_set, SIGALRM);
 #endif
 #if !defined(_PR_NO_PREEMPT)
 	_pr_dnsLock = PR_NewLock();
 #endif
 #if !defined(_PR_HAVE_GETPROTO_R)
 	_getproto_lock = PR_NewLock();
 #endif
+#if !defined(_PR_INET6)
 	_pr_init_ipv6();
+#endif
 }
 
 PR_IMPLEMENT(PRStatus) PR_GetHostName(char *name, PRUint32 namelen)
 {
 #if defined(DEBUG)
     static PRBool warn = PR_TRUE;
     if (warn) warn = _PR_Obsolete("PR_GetHostName()", "PR_GetSystemInfo()");
 #endif
@@ -892,20 +904,20 @@ PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
     if (af == PR_AF_INET6)
     {
         addr->ipv6.port = htons(port);
         switch (val)
         {
         case PR_IpAddrNull:
             break;  /* don't overwrite the address */
         case PR_IpAddrAny:
-            addr->ipv6.ip = in6addr_any;
+            addr->ipv6.ip = _pr_in6addr_any;
             break;
         case PR_IpAddrLoopback:
-            addr->ipv6.ip = in6addr_loopback;
+            addr->ipv6.ip = _pr_in6addr_loopback;
             break;
         default:
             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
             rv = PR_FAILURE;
         }
     }
     else
 #else
@@ -949,19 +961,16 @@ PR_IMPLEMENT(PRStatus) PR_SetNetAddr(
         default:
             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
             rv = PR_FAILURE;
         }
     }
     return rv;
 }  /* PR_SetNetAddr */
 
-extern void ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
-                                            PRNetAddr *dst_v4addr);
-
 PR_IMPLEMENT(PRBool)
 PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val)
 {
     if (addr->raw.family == PR_AF_INET6) {
         if (val == PR_IpAddrAny) {
 			if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) {
             	return PR_TRUE;
 			} else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)