Re: IPv6 Support for INET/CIDR types.

Поиск
Список
Период
Сортировка
Искать
От
Paul A Vixie
Тема
Re: IPv6 Support for INET/CIDR types.
Дата
Msg-id
200110050838.f958crH48152@as.vix.com
Список
Дерево обсуждения
IPv6 Support for INET/CIDR types. Vadim Kogan <vadim@xcf.berkeley.edu>
Re: IPv6 Support for INET/CIDR types. Vadim Kogan <vadim@xcf.berkeley.edu>
Re: IPv6 Support for INET/CIDR types. Bruce Momjian <pgman@candle.pha.pa.us>
> What is that status of this patch?  We are near beta.

below please find a shar file containing:

	the latest patch to inet.h and network.c from vadim with a few tiny
	changes to the comments from me;

	a patch bringing inet_net_pton.c and inet_net_ntop.c up to date with
	respect to isc's changes to those files in the time since INET/CIDR
	were added, plus isc's corrected version of vadim's ipv6 changes to
	those files;

	the new files inet_cidr_pton.c and inet_cidr_ntop.c, containing isc's
	fixed version of vadim's ipv6 support for this api.

	a patch to src/backend/utils/adt/Makefile to compile the above files.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	ipv6-patch
#	inet_cidr_ntop.c
#	inet_cidr_pton.c
#
echo x - ipv6-patch
sed 's/^X//' >ipv6-patch << 'END-of-ipv6-patch'
XIndex: src/backend/utils/adt/Makefile
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/Makefile,v
Xretrieving revision 1.51
Xdiff -u -r1.51 Makefile
X--- src/backend/utils/adt/Makefile	2001/10/04 04:13:40	1.51
X+++ src/backend/utils/adt/Makefile	2001/10/05 08:31:17
X@@ -22,7 +22,9 @@
X 	oid.o oracle_compat.o \
X 	regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
X 	tid.o timestamp.o varbit.o varchar.o varlena.o version.o \
X-	network.o mac.o inet_net_ntop.o inet_net_pton.o \
X+	network.o mac.o \
X+	inet_net_ntop.o inet_net_pton.o \
X+	inet_cidr_ntop.o inet_cidr_pton.o \
X 	ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
X 	ascii.o quote.o pgstatfuncs.o encode.o
X 
XIndex: src/backend/utils/adt/inet_net_ntop.c
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/inet_net_ntop.c,v
Xretrieving revision 1.10
Xdiff -u -r1.10 inet_net_ntop.c
X--- src/backend/utils/adt/inet_net_ntop.c	2001/03/22 03:59:51	1.10
X+++ src/backend/utils/adt/inet_net_ntop.c	2001/10/05 08:31:17
X@@ -1,5 +1,5 @@
X /*
X- * Copyright (c) 1996 by Internet Software Consortium.
X+ * Copyright (c) 1996,1999 by Internet Software Consortium.
X  *
X  * Permission to use, copy, modify, and distribute this software for any
X  * purpose with or without fee is hereby granted, provided that the above
X@@ -16,34 +16,41 @@
X  */
X 
X #if defined(LIBC_SCCS) && !defined(lint)
X-static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.10 2001/03/22 03:59:51 momjian Exp $";
X-
X+static const char isc_rcsid[] = "Id: inet_net_ntop.c,v 1.8 2001/09/27 15:08:36 marka Exp $";
X+static const char rcsid[] = "$Id:$";
X #endif
X 
X+/*#include "port_before.h"*/
X+
X #include 
X #include 
X #include 
X #include 
X 
X #include 
X+#include 
X+#include 
X+#include 
X+
X+/*#include "port_after.h"*/
X 
X #include "postgres.h"
X #include "utils/builtins.h"
X 
X #ifdef SPRINTF_CHAR
X-#define SPRINTF(x) strlen(sprintf/**/x)
X+# define SPRINTF(x) strlen(sprintf/**/x)
X #else
X-#define SPRINTF(x) ((size_t)sprintf x)
X+# define SPRINTF(x) ((size_t)sprintf x)
X #endif
X 
X-static char *inet_net_ntop_ipv4(const u_char *src, int bits,
X-				   char *dst, size_t size);
X-static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
X+static char *	inet_net_ntop_ipv4(const u_char *src, int bits,
X 					char *dst, size_t size);
X+static char *	inet_net_ntop_ipv6(const u_char *src, int bits,
X+					char *dst, size_t size);
X 
X /*
X  * char *
X- * inet_cidr_ntop(af, src, bits, dst, size)
X+ * inet_net_ntop(af, src, bits, dst, size)
X  *	convert network number from network to presentation format.
X  *	generates CIDR style result always.
X  * return:
X@@ -52,167 +59,221 @@
X  *	Paul Vixie (ISC), July 1996
X  */
X char *
X-inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
X+inet_net_ntop(af, src, bits, dst, size)
X+	int af;
X+	const void *src;
X+	int bits;
X+	char *dst;
X+	size_t size;
X {
X-	switch (af)
X-	{
X-			case AF_INET:
X-			return (inet_cidr_ntop_ipv4(src, bits, dst, size));
X-		default:
X-			errno = EAFNOSUPPORT;
X-			return (NULL);
X+	switch (af) {
X+	case AF_INET:
X+		return (inet_net_ntop_ipv4(src, bits, dst, size));
X+	case AF_INET6:
X+		return (inet_net_ntop_ipv6(src, bits, dst, size));
X+	default:
X+		errno = EAFNOSUPPORT;
X+		return (NULL);
X 	}
X }
X 
X-
X /*
X  * static char *
X- * inet_cidr_ntop_ipv4(src, bits, dst, size)
X+ * inet_net_ntop_ipv4(src, bits, dst, size)
X  *	convert IPv4 network number from network to presentation format.
X  *	generates CIDR style result always.
X  * return:
X  *	pointer to dst, or NULL if an error occurred (check errno).
X  * note:
X  *	network byte order assumed.  this means 192.5.5.240/28 has
X- *	0x11110000 in its fourth octet.
X+ *	0b11110000 in its fourth octet.
X  * author:
X  *	Paul Vixie (ISC), July 1996
X  */
X static char *
X-inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
X+inet_net_ntop_ipv4(src, bits, dst, size)
X+	const u_char *src;
X+	int bits;
X+	char *dst;
X+	size_t size;
X {
X-	char	   *odst = dst;
X-	char	   *t;
X-	u_int		m;
X-	int			b;
X+	char *odst = dst;
X+	char *t;
X+	u_int m;
X+	int b;
X 
X-	if (bits < 0 || bits > 32)
X-	{
X+	if (bits < 0 || bits > 32) {
X 		errno = EINVAL;
X 		return (NULL);
X 	}
X-	if (bits == 0)
X-	{
X+
X+	if (bits == 0) {
X 		if (size < sizeof "0")
X 			goto emsgsize;
X 		*dst++ = '0';
X+		size--;
X 		*dst = '\0';
X 	}
X 
X 	/* Format whole octets. */
X-	for (b = bits / 8; b > 0; b--)
X-	{
X-		if (size < sizeof ".255")
X+	for (b = bits / 8; b > 0; b--) {
X+		if (size <= sizeof "255.")
X 			goto emsgsize;
X 		t = dst;
X-		if (dst != odst)
X-			*dst++ = '.';
X 		dst += SPRINTF((dst, "%u", *src++));
X-		size -= (size_t) (dst - t);
X+		if (b > 1) {
X+			*dst++ = '.';
X+			*dst = '\0';
X+		}
X+		size -= (size_t)(dst - t);
X 	}
X 
X 	/* Format partial octet. */
X 	b = bits % 8;
X-	if (b > 0)
X-	{
X-		if (size < sizeof ".255")
X+	if (b > 0) {
X+		if (size <= sizeof ".255")
X 			goto emsgsize;
X 		t = dst;
X 		if (dst != odst)
X 			*dst++ = '.';
X 		m = ((1 << b) - 1) << (8 - b);
X 		dst += SPRINTF((dst, "%u", *src & m));
X-		size -= (size_t) (dst - t);
X+		size -= (size_t)(dst - t);
X 	}
X 
X 	/* Format CIDR /width. */
X-	if (size < sizeof "/32")
X+	if (size <= sizeof "/32")
X 		goto emsgsize;
X 	dst += SPRINTF((dst, "/%u", bits));
X-
X 	return (odst);
X 
X-emsgsize:
X+ emsgsize:
X 	errno = EMSGSIZE;
X 	return (NULL);
X }
X 
X-
X /*
X- * char *
X- * inet_net_ntop(af, src, bits, dst, size)
X- *	convert host/network address from network to presentation format.
X- *	"src"'s size is determined from its "af".
X- * return:
X- *	pointer to dst, or NULL if an error occurred (check errno).
X- * note:
X- *	192.5.5.1/28 has a nonzero host part, which means it isn't a network
X- *	as called for by inet_net_pton() but it can be a host address with
X- *	an included netmask.
X- * author:
X- *	Paul Vixie (ISC), October 1998
X- */
X-char *
X-inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
X-{
X-	switch (af)
X-	{
X-			case AF_INET:
X-			return (inet_net_ntop_ipv4(src, bits, dst, size));
X-		default:
X-			errno = EAFNOSUPPORT;
X-			return (NULL);
X-	}
X-}
X-
X-/*
X  * static char *
X- * inet_net_ntop_ipv4(src, bits, dst, size)
X- *	convert IPv4 network address from network to presentation format.
X- *	"src"'s size is determined from its "af".
X+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
X+ *	convert IPv6 network number from network to presentation format.
X+ *	generates CIDR style result always. Picks the shortest representation
X+ *	unless the IP is really IPv4.
X+ *	always prints specified number of bits (bits).
X  * return:
X  *	pointer to dst, or NULL if an error occurred (check errno).
X  * note:
X  *	network byte order assumed.  this means 192.5.5.240/28 has
X- *	0b11110000 in its fourth octet.
X+ *	0x11110000 in its fourth octet.
X  * author:
X- *	Paul Vixie (ISC), October 1998
X+ *	Vadim Kogan (UCB), June 2001
X+ *  Original version (IPv4) by Paul Vixie (ISC), July 1996
X  */
X+
X static char *
X-inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
X-{
X-	char	   *odst = dst;
X-	char	   *t;
X-	int			len = 4;
X-	int			b;
X+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
X+	u_int	m;
X+	int	b;
X+	int	p;
X+	int	zero_s, zero_l, tmp_zero_s, tmp_zero_l;
X+	int	i;
X+	int	is_ipv4 = 0;
X+	unsigned char inbuf[16];
X+	char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
X+	char	*cp;
X+	int	words;
X+	u_char	*s;
X 
X-	if (bits < 0 || bits > 32)
X-	{
X+	if (bits < 0 || bits > 128) {
X 		errno = EINVAL;
X 		return (NULL);
X 	}
X 
X-	/* Always format all four octets, regardless of mask length. */
X-	for (b = len; b > 0; b--)
X-	{
X-		if (size < sizeof ".255")
X-			goto emsgsize;
X-		t = dst;
X-		if (dst != odst)
X-			*dst++ = '.';
X-		dst += SPRINTF((dst, "%u", *src++));
X-		size -= (size_t) (dst - t);
X-	}
X+	cp = outbuf;
X 
X-	/* don't print masklen if 32 bits */
X-	if (bits != 32)
X-	{
X-		if (size < sizeof "/32")
X-			goto emsgsize;
X-		dst += SPRINTF((dst, "/%u", bits));
X+	if (bits == 0) {
X+		*cp++ = ':';
X+		*cp++ = ':';
X+		*cp = '\0';
X+	} else {
X+		/* Copy src to private buffer.  Zero host part. */	
X+		p = (bits + 7) / 8;
X+		memcpy(inbuf, src, p);
X+		memset(inbuf + p, 0, 16 - p);
X+		b = bits % 8;
X+		if (b != 0) {
X+			m = ~0 << (8 - b);
X+			inbuf[p-1] &= m;
X+		}
X+
X+		s = inbuf;
X+
X+		/* how many words need to be displayed in output */
X+		words = (bits + 15) / 16;
X+		if (words == 1)
X+			words = 2;
X+		
X+		/* Find the longest substring of zero's */
X+		zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
X+		for (i = 0; i < (words * 2); i += 2) {
X+			if ((s[i] | s[i+1]) == 0) {
X+				if (tmp_zero_l == 0)
X+					tmp_zero_s = i / 2;
X+				tmp_zero_l++;
X+			} else {
X+				if (tmp_zero_l && zero_l < tmp_zero_l) {
X+					zero_s = tmp_zero_s;
X+					zero_l = tmp_zero_l;
X+					tmp_zero_l = 0;
X+				}
X+			}
X+		}
X+
X+		if (tmp_zero_l && zero_l < tmp_zero_l) {
X+			zero_s = tmp_zero_s;
X+			zero_l = tmp_zero_l;
X+		}
X+
X+		if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
X+		    ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
X+		    ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
X+			is_ipv4 = 1;
X+
X+		/* Format whole words. */
X+		for (p = 0; p < words; p++) {
X+			if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
X+				/* Time to skip some zeros */
X+				if (p == zero_s)
X+					*cp++ = ':';
X+				if (p == words - 1)
X+					*cp++ = ':';
X+				s++;
X+				s++;
X+				continue;
X+			}
X+
X+			if (is_ipv4 && p > 5 ) {
X+				*cp++ = (p == 6) ? ':' : '.';
X+				cp += SPRINTF((cp, "%u", *s++));
X+				/* we can potentially drop the last octet */
X+				if (p != 7 || bits > 120) {
X+					*cp++ = '.';
X+					cp += SPRINTF((cp, "%u", *s++));
X+				}
X+			} else {
X+				if (cp != outbuf)
X+					*cp++ = ':';
X+				cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
X+				s += 2;
X+			}
X+		}
X 	}
X-
X-	return (odst);
X+	/* Format CIDR /width. */
X+	SPRINTF((cp, "/%u", bits));
X+	if (strlen(outbuf) + 1 > size)
X+		goto emsgsize;
X+	strcpy(dst, outbuf);
X+	
X+	return (dst);
X 
X emsgsize:
X 	errno = EMSGSIZE;
XIndex: src/backend/utils/adt/inet_net_pton.c
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/inet_net_pton.c,v
Xretrieving revision 1.12
Xdiff -u -r1.12 inet_net_pton.c
X--- src/backend/utils/adt/inet_net_pton.c	2000/12/03 20:45:36	1.12
X+++ src/backend/utils/adt/inet_net_pton.c	2001/10/05 08:31:17
X@@ -1,5 +1,5 @@
X /*
X- * Copyright (c) 1996 by Internet Software Consortium.
X+ * Copyright (c) 1996,1999 by Internet Software Consortium.
X  *
X  * Permission to use, copy, modify, and distribute this software for any
X  * purpose with or without fee is hereby granted, provided that the above
X@@ -16,67 +16,40 @@
X  */
X 
X #if defined(LIBC_SCCS) && !defined(lint)
X-static const char rcsid[] = "$Id: inet_net_pton.c,v 1.12 2000/12/03 20:45:36 tgl Exp $";
X-
X+static const char isc_rcsid[] = "Id: inet_net_pton.c,v 1.13 2001/09/27 15:08:38 marka Exp $";
X+static const char rcsid[] = "$Id:$";
X #endif
X 
X+/*#include "port_before.h"*/
X+
X #include 
X #include 
X #include 
X+#include 
X #include 
X 
X+/*#include */
X #include 
X #include 
X #include 
X+#include 
X+#include 
X+#include 
X 
X+/*#include "port_after.h"*/
X+
X #include "postgres.h"
X #include "utils/builtins.h"
X 
X #ifdef SPRINTF_CHAR
X-#define SPRINTF(x) strlen(sprintf/**/x)
X+# define SPRINTF(x) strlen(sprintf/**/x)
X #else
X-#define SPRINTF(x) ((size_t)sprintf x)
X+# define SPRINTF(x) ((size_t)sprintf x)
X #endif
X 
X-static int	inet_net_pton_ipv4(const char *src, u_char *dst);
X-static int	inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
X-
X /*
X  * static int
X- * inet_net_pton(af, src, dst, size)
X- *	convert network number from presentation to network format.
X- *	accepts hex octets, hex strings, decimal octets, and /CIDR.
X- *	"size" is in bytes and describes "dst".
X- * return:
X- *	number of bits, either imputed classfully or specified with /CIDR,
X- *	or -1 if some failure occurred (check errno).  ENOENT means it was
X- *	not a valid network specification.
X- * author:
X- *	Paul Vixie (ISC), June 1996
X- *
X- * Changes:
X- *	I added the inet_cidr_pton function (also from Paul) and changed
X- *	the names to reflect their current use.
X- *
X- */
X-int
X-inet_net_pton(int af, const char *src, void *dst, size_t size)
X-{
X-	switch (af)
X-	{
X-			case AF_INET:
X-			return size == -1 ?
X-			inet_net_pton_ipv4(src, dst) :
X-			inet_cidr_pton_ipv4(src, dst, size);
X-		default:
X-			errno = EAFNOSUPPORT;
X-			return (-1);
X-	}
X-}
X-
X-/*
X- * static int
X- * inet_cidr_pton_ipv4(src, dst, size)
X+ * inet_net_pton_ipv4(src, dst, size)
X  *	convert IPv4 network number from presentation to network format.
X  *	accepts hex octets, hex strings, decimal octets, and /CIDR.
X  *	"size" is in bytes and describes "dst".
X@@ -86,66 +59,52 @@
X  *	not an IPv4 network specification.
X  * note:
X  *	network byte order assumed.  this means 192.5.5.240/28 has
X- *	0x11110000 in its fourth octet.
X+ *	0b11110000 in its fourth octet.
X  * author:
X  *	Paul Vixie (ISC), June 1996
X  */
X static int
X-inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
X-{
X-	static const char
X-				xdigits[] = "0123456789abcdef",
X-				digits[] = "0123456789";
X-	int			n,
X-				ch,
X-				tmp,
X-				dirty,
X-				bits;
X+inet_net_pton_ipv4( const char *src, u_char *dst, size_t size) {
X+	static const char xdigits[] = "0123456789abcdef";
X+	static const char digits[] = "0123456789";
X+	int n, ch, tmp = 0, dirty, bits;
X 	const u_char *odst = dst;
X 
X 	ch = *src++;
X 	if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
X-		&& isxdigit((unsigned char) src[1]))
X-	{
X+	    && isascii((unsigned char)(src[1]))
X+	    && isxdigit((unsigned char)(src[1]))) {
X 		/* Hexadecimal: Eat nybble string. */
X 		if (size <= 0)
X 			goto emsgsize;
X 		dirty = 0;
X-		tmp = 0;
X-		src++;					/* skip x or X. */
X-		while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
X-		{
X-			if (isupper((unsigned char) ch))
X-				ch = tolower((unsigned char) ch);
X+		src++;	/* skip x or X. */
X+		while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
X+			if (isupper(ch))
X+				ch = tolower(ch);
X 			n = strchr(xdigits, ch) - xdigits;
X 			assert(n >= 0 && n <= 15);
X 			if (dirty == 0)
X 				tmp = n;
X 			else
X 				tmp = (tmp << 4) | n;
X-			if (++dirty == 2)
X-			{
X+			if (++dirty == 2) {
X 				if (size-- <= 0)
X 					goto emsgsize;
X 				*dst++ = (u_char) tmp;
X 				dirty = 0;
X 			}
X 		}
X-		if (dirty)
X-		{						/* Odd trailing nybble? */
X+		if (dirty) {  /* Odd trailing nybble? */
X 			if (size-- <= 0)
X 				goto emsgsize;
X 			*dst++ = (u_char) (tmp << 4);
X 		}
X-	}
X-	else if (isdigit((unsigned char) ch))
X-	{
X+	} else if (isascii(ch) && isdigit(ch)) {
X 		/* Decimal: eat dotted digit string. */
X-		for (;;)
X-		{
X+		for (;;) {
X 			tmp = 0;
X-			do
X-			{
X+			do {
X 				n = strchr(digits, ch) - digits;
X 				assert(n >= 0 && n <= 9);
X 				tmp *= 10;
X@@ -153,7 +112,7 @@
X 				if (tmp > 255)
X 					goto enoent;
X 			} while ((ch = *src++) != '\0' &&
X-					 isdigit((unsigned char) ch));
X+				 isascii(ch) && isdigit(ch));
X 			if (size-- <= 0)
X 				goto emsgsize;
X 			*dst++ = (u_char) tmp;
X@@ -162,26 +121,24 @@
X 			if (ch != '.')
X 				goto enoent;
X 			ch = *src++;
X-			if (!isdigit((unsigned char) ch))
X+			if (!isascii(ch) || !isdigit(ch))
X 				goto enoent;
X 		}
X-	}
X-	else
X+	} else
X 		goto enoent;
X 
X 	bits = -1;
X-	if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
X-	{
X+	if (ch == '/' && isascii((unsigned char)(src[0])) &&
X+	    isdigit((unsigned char)(src[0])) && dst > odst) {
X 		/* CIDR width specifier.  Nothing can follow it. */
X-		ch = *src++;			/* Skip over the /. */
X+		ch = *src++;	/* Skip over the /. */
X 		bits = 0;
X-		do
X-		{
X+		do {
X 			n = strchr(digits, ch) - digits;
X 			assert(n >= 0 && n <= 9);
X 			bits *= 10;
X 			bits += n;
X-		} while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
X+		} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
X 		if (ch != '\0')
X 			goto enoent;
X 		if (bits > 32)
X@@ -196,9 +153,8 @@
X 	if (dst == odst)
X 		goto enoent;
X 	/* If no CIDR spec was given, infer width from net class. */
X-	if (bits == -1)
X-	{
X-		if (*odst >= 240)		/* Class E */
X+	if (bits == -1) {
X+		if (*odst >= 240)	/* Class E */
X 			bits = 32;
X 		else if (*odst >= 224)	/* Class D */
X 			bits = 4;
X@@ -206,133 +162,243 @@
X 			bits = 24;
X 		else if (*odst >= 128)	/* Class B */
X 			bits = 16;
X-		else
X-/* Class A */
X+		else			/* Class A */
X 			bits = 8;
X 		/* If imputed mask is narrower than specified octets, widen. */
X 		if (bits >= 8 && bits < ((dst - odst) * 8))
X 			bits = (dst - odst) * 8;
X 	}
X 	/* Extend network to cover the actual mask. */
X-	while (bits > ((dst - odst) * 8))
X-	{
X+	while (bits > ((dst - odst) * 8)) {
X 		if (size-- <= 0)
X 			goto emsgsize;
X 		*dst++ = '\0';
X 	}
X 	return (bits);
X 
X-enoent:
X+ enoent:
X 	errno = ENOENT;
X 	return (-1);
X 
X-emsgsize:
X+ emsgsize:
X 	errno = EMSGSIZE;
X 	return (-1);
X }
X 
X-/*
X- * int
X- * inet_net_pton(af, src, dst, *bits)
X- *	convert network address from presentation to network format.
X- *	accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
X- *	"dst" is assumed large enough for its "af".  "bits" is set to the
X- *	/CIDR prefix length, which can have defaults (like /32 for IPv4).
X- * return:
X- *	-1 if an error occurred (inspect errno; ENOENT means bad format).
X- *	0 if successful conversion occurred.
X- * note:
X- *	192.5.5.1/28 has a nonzero host part, which means it isn't a network
X- *	as called for by inet_cidr_pton() but it can be a host address with
X- *	an included netmask.
X- * author:
X- *	Paul Vixie (ISC), October 1998
X- */
X static int
X-inet_net_pton_ipv4(const char *src, u_char *dst)
X-{
X+getbits(const char *src, int *bitsp) {
X 	static const char digits[] = "0123456789";
X-	const u_char *odst = dst;
X-	int			n,
X-				ch,
X-				tmp,
X-				bits;
X-	size_t		size = 4;
X-
X-	/* Get the mantissa. */
X-	while (ch = *src++, isdigit((unsigned char) ch))
X-	{
X-		tmp = 0;
X-		do
X-		{
X-			n = strchr(digits, ch) - digits;
X-			assert(n >= 0 && n <= 9);
X-			tmp *= 10;
X-			tmp += n;
X-			if (tmp > 255)
X-				goto enoent;
X-		} while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
X-		if (size-- == 0)
X-			goto emsgsize;
X-		*dst++ = (u_char) tmp;
X-		if (ch == '\0' || ch == '/')
X-			break;
X-		if (ch != '.')
X-			goto enoent;
X+	int n;
X+	int val;
X+	char ch;
X+
X+	val = 0;
X+	n = 0;
X+	while ((ch = *src++) != '\0') {
X+		const char *pch;
X+
X+		pch = strchr(digits, ch);
X+		if (pch != NULL) {
X+			if (n++ != 0 && val == 0)	/* no leading zeros */
X+				return (0);
X+			val *= 10;
X+			val += (pch - digits);
X+			if (val > 128)			/* range */
X+				return (0);
X+			continue;
X+		}
X+		return (0);
X 	}
X+	if (n == 0)
X+		return (0);
X+	*bitsp = val;
X+	return (1);
X+}
X 
X-	/* Get the prefix length if any. */
X-	bits = -1;
X-	if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
X-	{
X-		/* CIDR width specifier.  Nothing can follow it. */
X-		ch = *src++;			/* Skip over the /. */
X-		bits = 0;
X-		do
X-		{
X-			n = strchr(digits, ch) - digits;
X-			assert(n >= 0 && n <= 9);
X-			bits *= 10;
X-			bits += n;
X-		} while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
X-		if (ch != '\0')
X-			goto enoent;
X-		if (bits > 32)
X-			goto emsgsize;
X+static int
X+getv4(const char *src, u_char *dst, int *bitsp) {
X+	static const char digits[] = "0123456789";
X+	u_char *odst = dst;
X+	int n;
X+	u_int val;
X+	char ch;
X+
X+	val = 0;
X+	n = 0;
X+	while ((ch = *src++) != '\0') {
X+		const char *pch;
X+
X+		pch = strchr(digits, ch);
X+		if (pch != NULL) {
X+			if (n++ != 0 && val == 0)	/* no leading zeros */
X+				return (0);
X+			val *= 10;
X+			val += (pch - digits);
X+			if (val > 255)			/* range */
X+				return (0);
X+			continue;
X+		}
X+		if (ch == '.' || ch == '/') {
X+			if (dst - odst > 3)		/* too many octets? */
X+				return (0);
X+			*dst++ = val;
X+			if (ch == '/')
X+				return (getbits(src, bitsp));
X+			val = 0;
X+			n = 0;
X+			continue;
X+		}
X+		return (0);
X 	}
X+	if (n == 0)
X+		return (0);
X+	if (dst - odst > 3)		/* too many octets? */
X+		return (0);
X+	*dst++ = val;
X+	return (1);
X+}
X 
X-	/* Firey death and destruction unless we prefetched EOS. */
X-	if (ch != '\0')
X+static int
X+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
X+	static const char xdigits_l[] = "0123456789abcdef",
X+			  xdigits_u[] = "0123456789ABCDEF";
X+	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
X+	const char *xdigits, *curtok;
X+	int ch, saw_xdigit;
X+	u_int val;
X+	int digits;
X+	int bits;
X+	size_t bytes;
X+	int words;
X+	int ipv4;
X+
X+	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
X+	endp = tp + NS_IN6ADDRSZ;
X+	colonp = NULL;
X+	/* Leading :: requires some special handling. */
X+	if (*src == ':')
X+		if (*++src != ':')
X+			goto enoent;
X+	curtok = src;
X+	saw_xdigit = 0;
X+	val = 0;
X+	digits = 0;
X+	bits = -1;
X+	ipv4 = 0;
X+	while ((ch = *src++) != '\0') {
X+		const char *pch;
X+
X+		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
X+			pch = strchr((xdigits = xdigits_u), ch);
X+		if (pch != NULL) {
X+			val <<= 4;
X+			val |= (pch - xdigits);
X+			if (++digits > 4)
X+				goto enoent;
X+			saw_xdigit = 1;
X+			continue;
X+		}
X+		if (ch == ':') {
X+			curtok = src;
X+			if (!saw_xdigit) {
X+				if (colonp)
X+					goto enoent;
X+				colonp = tp;
X+				continue;
X+			} else if (*src == '\0')
X+				goto enoent;
X+			if (tp + NS_INT16SZ > endp)
X+				return (0);
X+			*tp++ = (u_char) (val >> 8) & 0xff;
X+			*tp++ = (u_char) val & 0xff;
X+			saw_xdigit = 0;
X+			digits = 0;
X+			val = 0;
X+			continue;
X+		}
X+		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
X+		     getv4(curtok, tp, &bits) > 0) {
X+			tp += NS_INADDRSZ;
X+			saw_xdigit = 0;
X+			ipv4 = 1;
X+			break;	/* '\0' was seen by inet_pton4(). */
X+		}
X+		if (ch == '/' && getbits(src, &bits) > 0)
X+			break;
X 		goto enoent;
X-
X-	/* Prefix length can default to /32 only if all four octets spec'd. */
X-	if (bits == -1)
X-	{
X-		if (dst - odst == 4)
X-			bits = 32;
X-		else
X+	}
X+	if (saw_xdigit) {
X+		if (tp + NS_INT16SZ > endp)
X 			goto enoent;
X+		*tp++ = (u_char) (val >> 8) & 0xff;
X+		*tp++ = (u_char) val & 0xff;
X 	}
X+	if (bits == -1)
X+		bits = 128;
X 
X-	/* If nothing was written to the destination, we found no address. */
X-	if (dst == odst)
X-		goto enoent;
X+	words = (bits + 15) / 16;
X+	if (words < 2)
X+		words = 2;
X+	if (ipv4)
X+		words = 8;
X+	endp =  tmp + 2 * words;
X+
X+	if (colonp != NULL) {
X+		/*
X+		 * Since some memmove()'s erroneously fail to handle
X+		 * overlapping regions, we'll do the shift by hand.
X+		 */
X+		const int n = tp - colonp;
X+		int i;
X 
X-	/* If prefix length overspecifies mantissa, life is bad. */
X-	if ((bits / 8) > (dst - odst))
X+		if (tp == endp)
X+			goto enoent;
X+		for (i = 1; i <= n; i++) {
X+			endp[- i] = colonp[n - i];
X+			colonp[n - i] = 0;
X+		}
X+		tp = endp;
X+	}
X+	if (tp != endp)
X 		goto enoent;
X-
X-	/* Extend address to four octets. */
X-	while (size-- > 0)
X-		*dst++ = 0;
X 
X-	return bits;
X+	bytes = (bits + 7) / 8;
X+	if (bytes > size)
X+		goto emsgsize;
X+	memcpy(dst, tmp, bytes);
X+	return (bits);
X 
X-enoent:
X+ enoent:
X 	errno = ENOENT;
X 	return (-1);
X 
X-emsgsize:
X+ emsgsize:
X 	errno = EMSGSIZE;
X 	return (-1);
X+}
X+
X+/*
X+ * int
X+ * inet_net_pton(af, src, dst, size)
X+ *	convert network number from presentation to network format.
X+ *	accepts hex octets, hex strings, decimal octets, and /CIDR.
X+ *	"size" is in bytes and describes "dst".
X+ * return:
X+ *	number of bits, either imputed classfully or specified with /CIDR,
X+ *	or -1 if some failure occurred (check errno).  ENOENT means it was
X+ *	not a valid network specification.
X+ * author:
X+ *	Paul Vixie (ISC), June 1996
X+ */
X+int
X+inet_net_pton(int af, const char *src, void *dst, size_t size) {
X+	switch (af) {
X+	case AF_INET:
X+		return (inet_net_pton_ipv4(src, dst, size));
X+	case AF_INET6:
X+		return (inet_net_pton_ipv6(src, dst, size));
X+	default:
X+		errno = EAFNOSUPPORT;
X+		return (-1);
X+	}
X }
XIndex: src/backend/utils/adt/network.c
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/network.c,v
Xretrieving revision 1.33
Xdiff -u -r1.33 network.c
X--- src/backend/utils/adt/network.c	2001/08/27 20:03:38	1.33
X+++ src/backend/utils/adt/network.c	2001/10/05 08:31:18
X@@ -1,7 +1,5 @@
X /*
X- *	PostgreSQL type definitions for the INET type.	This
X- *	is for IP V4 CIDR notation, but prepared for V6: just
X- *	add the necessary bits where the comments indicate.
X+ *	PostgreSQL type definitions for the INET type.
X  *
X  *	$Header: /projects/cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.33 2001/08/27 20:03:38 tgl Exp $
X  *
X@@ -21,17 +19,26 @@
X #include "utils/inet.h"
X 
X 
X+#ifndef INET6_ADDRSTRLEN
X+#define INET6_ADDRSTRLEN	46
X+#endif
X+
X+#define INET6_CIDRSTRLEN	(INET6_ADDRSTRLEN + 4)
X+
X static Datum text_network(text *src, int type);
X static int32 network_cmp_internal(inet *a1, inet *a2);
X static int	v4bitncmp(unsigned long a1, unsigned long a2, int bits);
X static bool v4addressOK(unsigned long a1, int bits);
X+static int	v6bitncmp(unsigned int *a1, unsigned int *a2, int bits);
X+static bool	v6addressOK(unsigned int *a1, int bits);
X 
X /*
X- *	Access macros.	Add IPV6 support.
X+ *	Access macros.
X  */
X 
X #define ip_addrsize(inetptr) \
X-	(((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1)
X+	(((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : \
X+		(((inet_struct *)VARDATA(inetptr))->family == AF_INET6 ? 16 : -1 ))
X 
X #define ip_family(inetptr) \
X 	(((inet_struct *)VARDATA(inetptr))->family)
X@@ -39,12 +46,33 @@
X #define ip_bits(inetptr) \
X 	(((inet_struct *)VARDATA(inetptr))->bits)
X 
X+#define ip_ipv4bits(inetptr) \
X+	(ip_bits(inetptr) - (ip_family(inetptr) == AF_INET6 ? 96 : 0))
X+	
X #define ip_type(inetptr) \
X 	(((inet_struct *)VARDATA(inetptr))->type)
X 
X #define ip_v4addr(inetptr) \
X 	(((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
X 
X+#define ip_v6addr(inetptr) \
X+	(((inet_struct *)VARDATA(inetptr))->addr.ipv6_addr)
X+
X+#define ip_v4inv6addr(inetptr) \
X+	(((inet_struct *)VARDATA(inetptr))->addr.ipv6_addr[ 3 ])
X+
X+#define ip_v4addr_always(inetptr) \
X+	(ip_family(inetptr) == AF_INET ? ip_v4addr(inetptr) \
X+	 : ip_v4inv6addr(inetptr))
X+
X+#define ip_is_ipv4(inetptr) \
X+	(ip_family(inetptr) == AF_INET || \
X+		(ip_family(inetptr) == AF_INET6 && \
X+		 ip_v6addr(inetptr)[0] == 0 && \
X+		 ip_v6addr(inetptr)[1] == 0 && \
X+		 (ip_v6addr(inetptr)[2] == 0 || \
X+		  ntohl(ip_v6addr(inetptr)[2]) == 0xFFFF) ))
X+
X /* Common input routine */
X static inet *
X network_in(char *src, int type)
X@@ -63,17 +91,25 @@
X 	if ((bits < 0) || (bits > 32))
X 	{
X 		/* Go for an IPV6 address here, before faulting out: */
X-		elog(ERROR, "invalid %s value '%s'",
X-			 type ? "CIDR" : "INET", src);
X+		ip_family(dst) = AF_INET6;
X+		bits = inet_net_pton(ip_family(dst), src, &ip_v6addr(dst),
X+							 type ? ip_addrsize(dst) : -1);
X+		if ((bits < 0) || (bits > 128)) {
X+			elog(ERROR, "invalid %s value '%s'",
X+				 type ? "CIDR" : "INET", src);
X+		}
X 	}
X 
X 	/*
X 	 * Error check: CIDR values must not have any bits set beyond the
X-	 * masklen. XXX this code is not IPV6 ready.
X+	 * masklen.
X 	 */
X 	if (type)
X 	{
X-		if (!v4addressOK(ip_v4addr(dst), bits))
X+		if (
X+			!(ip_family(dst) == AF_INET && v4addressOK(ip_v4addr(dst), bits)) &&
X+			!(ip_family(dst) == AF_INET6 && v6addressOK(ip_v6addr(dst), bits))
X+		)
X 			elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src);
X 	}
X 
X@@ -111,19 +147,17 @@
X inet_out(PG_FUNCTION_ARGS)
X {
X 	inet	   *src = PG_GETARG_INET_P(0);
X-	char		tmp[sizeof("255.255.255.255/32")];
X+	char		tmp[INET6_CIDRSTRLEN];
X 	char	   *dst;
X 	int			len;
X 
X-	if (ip_family(src) == AF_INET)
X+	if (ip_family(src) == AF_INET || ip_family(src) == AF_INET6)
X 	{
X-		/* It's an IP V4 address: */
X-
X 		/*
X 		 * Use inet style for both inet and cidr, since we don't want
X 		 * abbreviated CIDR style here.
X 		 */
X-		dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
X+		dst = inet_net_ntop(ip_family(src), &ip_v4addr(src), ip_bits(src),
X 							tmp, sizeof(tmp));
X 		if (dst == NULL)
X 			elog(ERROR, "unable to print address (%s)", strerror(errno));
X@@ -135,7 +169,6 @@
X 		}
X 	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(src));
X 
X 	PG_RETURN_CSTRING(pstrdup(tmp));
X@@ -222,9 +255,55 @@
X 			return order;
X 		return v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), 32);
X 	}
X+	else if (ip_family(a1) == AF_INET6 && ip_family(a2) == AF_INET6)
X+	{
X+		int			order;
X+
X+		order = v6bitncmp(ip_v6addr(a1), ip_v6addr(a2),
X+						  Min(ip_bits(a1), ip_bits(a2)));
X+		if (order != 0)
X+			return order;
X+		order = ((int) ip_bits(a1)) - ((int) ip_bits(a2));
X+		if (order != 0)
X+			return order;
X+		return v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), 128);
X+	}
X+	else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+	{
X+		/* Be smart and compare IP V4 with IP V6 */
X+		int			order;
X+
X+		
X+		order = v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2),
X+						  Min(ip_ipv4bits(a1), ip_ipv4bits(a2)));
X+		if (order != 0)
X+			return order;
X+		order = ((int) ip_ipv4bits(a1)) - ((int) ip_ipv4bits(a2));
X+		if (order != 0)
X+			return order;
X+		return v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), 32);
X+	}
X 	else
X 	{
X-		/* Go for an IPV6 address here, before faulting out: */
X+		elog( DEBUG, "----" );
X+		if( ip_family(a1) == AF_INET )
X+			elog( DEBUG, "Pure IPv4" );
X+		else
X+			elog( DEBUG, "0: 0x%X, 1: 0x%X, 2: 0x%X, 3: 0x%X",
X+				ip_v6addr(a1)[0],
X+				ip_v6addr(a1)[1],
X+				ip_v6addr(a1)[2],
X+				ip_v6addr(a1)[3] );
X+				
X+		if( ip_family(a2) == AF_INET )
X+			elog( DEBUG, "Pure IPv4" );
X+		else
X+			elog( DEBUG, "0: 0x%X, 1: 0x%X, 2: 0x%X, 3: 0x%X",
X+				ip_v6addr(a2)[0],
X+				ip_v6addr(a2)[1],
X+				ip_v6addr(a2)[2],
X+				ip_v6addr(a2)[3] );
X+				
X 		elog(ERROR, "cannot compare address families %d and %d",
X 			 ip_family(a1), ip_family(a2));
X 		return 0;				/* keep compiler quiet */
X@@ -311,9 +390,18 @@
X 		PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
X 		   && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
X 	}
X+	else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+	{
X+		PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
X+		   && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+	}
X+	else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+	{
X+		PG_RETURN_BOOL(ip_ipv4bits(a1) > ip_ipv4bits(a2)
X+			&& v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a2)) == 0);
X+	}
X 	else
X 	{
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "cannot compare address families %d and %d",
X 			 ip_family(a1), ip_family(a2));
X 		PG_RETURN_BOOL(false);
X@@ -331,9 +419,18 @@
X 		PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
X 		   && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
X 	}
X+	else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+	{
X+		PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
X+		   && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+	}
X+	else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+	{
X+		PG_RETURN_BOOL(ip_ipv4bits(a1) >= ip_ipv4bits(a2)
X+			&& v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a2)) == 0);
X+	}
X 	else
X 	{
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "cannot compare address families %d and %d",
X 			 ip_family(a1), ip_family(a2));
X 		PG_RETURN_BOOL(false);
X@@ -351,9 +448,18 @@
X 		PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
X 		   && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
X 	}
X+	else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+	{
X+		PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
X+		   && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+	}
X+	else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+	{
X+		PG_RETURN_BOOL(ip_ipv4bits(a1) < ip_ipv4bits(a2)
X+			&& v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a1)) == 0);
X+	}
X 	else
X 	{
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "cannot compare address families %d and %d",
X 			 ip_family(a1), ip_family(a2));
X 		PG_RETURN_BOOL(false);
X@@ -371,9 +477,18 @@
X 		PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
X 		   && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
X 	}
X+	else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+	{
X+		PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
X+		   && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+	}
X+	else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+	{
X+		PG_RETURN_BOOL(ip_ipv4bits(a1) <= ip_ipv4bits(a2)
X+			&& v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a1)) == 0);
X+	}
X 	else
X 	{
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "cannot compare address families %d and %d",
X 			 ip_family(a1), ip_family(a2));
X 		PG_RETURN_BOOL(false);
X@@ -390,17 +505,17 @@
X 	text	   *ret;
X 	int			len;
X 	char	   *ptr,
X-				tmp[sizeof("255.255.255.255/32")];
X+				tmp[INET6_CIDRSTRLEN];
X 
X-	if (ip_family(ip) == AF_INET)
X+	if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6)
X 	{
X-		/* It's an IP V4 address: */
X-		/* force display of 32 bits, regardless of masklen... */
X-		if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
X+		/* force display of 32/128 bits, regardless of masklen... */
X+		if (inet_net_ntop(ip_family(ip), &ip_v4addr(ip),
X+						  (ip_family(ip) == AF_INET ? 32 : 128),
X+						  tmp, sizeof(tmp)) == NULL)
X 			elog(ERROR, "unable to print host (%s)", strerror(errno));
X 	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(ip));
X 
X 	/* Suppress /n if present (shouldn't happen now) */
X@@ -421,13 +536,12 @@
X 	inet	   *ip = PG_GETARG_INET_P(0);
X 	text	   *ret;
X 	int			len;
X-	char		tmp[sizeof("255.255.255.255/32")];
X+	char		tmp[INET6_CIDRSTRLEN];
X 
X-	if (ip_family(ip) == AF_INET)
X+	if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6)
X 	{
X-		/* It's an IP V4 address: */
X-		/* force display of 32 bits, regardless of masklen... */
X-		if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
X+		/* force display of 32/128 bits, regardless of masklen... */
X+		if (inet_net_ntop(ip_family(ip), &ip_v4addr(ip), (ip_family(ip) == AF_INET ? 32 : 128), tmp, sizeof(tmp)) == NULL)
X 			elog(ERROR, "unable to print host (%s)", strerror(errno));
X 		/* Add /n if not present (which it won't be) */
X 		if (strchr(tmp, '/') == NULL)
X@@ -437,7 +551,6 @@
X 		}
X 	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(ip));
X 
X 	/* Return string as a text datum */
X@@ -455,23 +568,21 @@
X 	text	   *ret;
X 	char	   *dst;
X 	int			len;
X-	char		tmp[sizeof("255.255.255.255/32")];
X+	char		tmp[INET6_CIDRSTRLEN];
X 
X-	if (ip_family(ip) == AF_INET)
X+	if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6)
X 	{
X-		/* It's an IP V4 address: */
X 		if (ip_type(ip))
X-			dst = inet_cidr_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip),
X+			dst = inet_cidr_ntop(ip_family(ip), &ip_v4addr(ip), ip_bits(ip),
X 								 tmp, sizeof(tmp));
X 		else
X-			dst = inet_net_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip),
X+			dst = inet_net_ntop(ip_family(ip), &ip_v4addr(ip), ip_bits(ip),
X 								tmp, sizeof(tmp));
X 
X 		if (dst == NULL)
X 			elog(ERROR, "unable to print address (%s)", strerror(errno));
X 	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(ip));
X 
X 	/* Return string as a text datum */
X@@ -516,8 +627,19 @@
X 
X 		ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask);
X 	}
X+	else if (ip_family(ip) == AF_INET6) {
X+		/* It's an IP V6 address: */
X+
X+		/* "There are no broadcast addresses in IPv6, their function being
X+			superseded by multicast addresses." (RFC2373) */
X+		/* I think use of solicited-node address (FF02:0:0:0:0:1:FFXX:XXXX) here is appropriate */
X+		unsigned long mask = 0x00ffffff;
X+		ip_v6addr(dst)[0] = htonl(0xff02);
X+		ip_v6addr(dst)[1] = 0;
X+		ip_v6addr(dst)[2] = htonl(1);
X+		ip_v6addr(dst)[3] = htonl(0xff000000 | (ntohl(ip_v4addr_always(ip)) & mask));
X+	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(ip));
X 
X 	ip_family(dst) = ip_family(ip);
X@@ -556,8 +678,41 @@
X 
X 		ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask);
X 	}
X+	else if(ip_family(ip) == AF_INET6) {
X+		/* It's an IP V6 address: */
X+		unsigned long mask = 0xffffffff;
X+		
X+		/* Ok, let's do this in 4 steps... */
X+		if(ip_bits(ip) > 96)
X+		{
X+			mask <<= (128 - ip_bits(ip));
X+			ip_v6addr(dst)[0] = htonl(ntohl(ip_v6addr(ip)[0]) & mask);
X+			memset(ip_v6addr(dst) + 1, 0, sizeof(int) * 3);
X+		}
X+		else if(ip_bits(ip) > 64)
X+		{
X+			ip_v6addr(dst)[0] = ip_v6addr(ip)[0];
X+			mask <<= (96 - ip_bits(ip));
X+			ip_v6addr(dst)[1] = htonl(ntohl(ip_v6addr(ip)[1]) & mask);
X+			memset(ip_v6addr(dst) + 2, 0, sizeof(int) * 2);
X+		}
X+		else if(ip_bits(ip) > 32)
X+		{
X+			memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 2);
X+			mask <<= (64 - ip_bits(ip));
X+			ip_v6addr(dst)[2] = htonl(ntohl(ip_v6addr(ip)[2]) & mask);
X+			ip_v6addr(dst)[3] = 0;
X+		}
X+		else if(ip_bits(ip) > 0 )
X+		{
X+			memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 3);
X+			mask <<= (32 - ip_bits(ip));
X+			ip_v6addr(dst)[3] = htonl(ntohl(ip_v6addr(ip)[3]) & mask);
X+		}
X+		else
X+			memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 4);
X+	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(ip));
X 
X 	ip_family(dst) = ip_family(ip);
X@@ -598,8 +753,44 @@
X 
X 		ip_bits(dst) = 32;
X 	}
X+	else if (ip_family(ip) == AF_INET6)
X+	{
X+		/* It's an IP V6 address: */
X+		unsigned long mask = 0xffffffff;
X+		
X+		/* Ok, let's do this in 4 steps... */
X+		if(ip_bits(ip) > 96)
X+		{
X+			mask <<= (128 - ip_bits(ip));
X+			ip_v6addr(dst)[0] = htonl(mask);
X+			memset(ip_v6addr(dst) + 1, 0, sizeof(int) * 3);
X+		}
X+		else if(ip_bits(ip) > 64)
X+		{
X+			ip_v6addr(dst)[0] = 0xffffffff;
X+			mask <<= (96 - ip_bits(ip));
X+			ip_v6addr(dst)[1] = htonl(mask);
X+			memset(ip_v6addr(dst) + 2, 0, sizeof(int) * 2);
X+		}
X+		else if(ip_bits(ip) > 32)
X+		{
X+			memset(ip_v6addr(dst), 0xff, sizeof(int) * 2);
X+			mask <<= (64 - ip_bits(ip));
X+			ip_v6addr(dst)[2] = htonl(mask);
X+			ip_v6addr(dst)[3] = 0;
X+		}
X+		else if(ip_bits(ip) > 0 )
X+		{
X+			memset(ip_v6addr(dst), 0xff, sizeof(int) * 3);
X+			mask <<= (32 - ip_bits(ip));
X+			ip_v6addr(dst)[3] = htonl(mask);
X+		}
X+		else
X+			memset(ip_v6addr(dst), 0xff, sizeof(int) * 4);
X+		
X+		ip_bits(dst) = 128;
X+	}
X 	else
X-		/* Go for an IPV6 address here, before faulting out: */
X 		elog(ERROR, "unknown address family (%d)", ip_family(ip));
X 
X 	ip_family(dst) = ip_family(ip);
X@@ -661,7 +852,7 @@
X 
X 
X /*
X- *	Bitwise comparison for V4 addresses.  Add V6 implementation!
X+ *	Bitwise comparison for IP V4 addresses.
X  */
X 
X static int
X@@ -687,6 +878,34 @@
X }
X 
X /*
X+ *	Bitwise comparison for IP V6 addresses.
X+ */
X+
X+static int
X+v6bitncmp(unsigned int *a1, unsigned int *a2, int bits)
X+{
X+	unsigned int mask;
X+	unsigned int tmp1, tmp2;
X+	int i;
X+	
X+	for( i = 0; bits > 0 && i < 4; i++, bits -= 32 ) {
X+		if( bits > 32 )
X+			mask = 0xffffffff;
X+		else if( bits > 0 )
X+			mask = 0xffffffff << (32 - bits);
X+		else
X+			mask = 0;
X+		tmp1 = ntohl(a1[i]);
X+		tmp2 = ntohl(a2[i]);
X+		if( ( tmp1 & mask ) < ( tmp2 & mask ) )
X+			return -1;
X+		else if( ( tmp1 & mask ) > ( tmp2 & mask ) )
X+			return 1;
X+	}
X+	return 0;
X+}
X+
X+/*
X  * Returns true if given address fits fully within the specified bit width.
X  */
X static bool
X@@ -706,6 +925,29 @@
X 	if ((a1 & mask) == a1)
X 		return true;
X 	return false;
X+}
X+
X+/*
X+ * Returns true if given address fits fully within the specified bit width.
X+ */
X+static bool
X+v6addressOK(unsigned int *a1, int bits)
X+{
X+	unsigned int tmp1, mask;
X+	int i;
X+	
X+	for( i = 0; bits > 0 && i < 4; i++, bits -= 32 ) {
X+		if( bits > 32 )
X+			mask = 0xffffffff;
X+		else if( bits > 0 )
X+			mask = 0xffffffff << (32 - bits);
X+		else
X+			mask = 0;
X+		tmp1 = ntohl(a1[i]);
X+		if( ( tmp1 & mask ) != tmp1 )
X+			return false;
X+	}
X+	return true;
X }
X 
X 
XIndex: src/include/utils/inet.h
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/include/utils/inet.h,v
Xretrieving revision 1.10
Xdiff -u -r1.10 inet.h
X--- src/include/utils/inet.h	2001/03/22 04:01:12	1.10
X+++ src/include/utils/inet.h	2001/10/05 08:31:25
X@@ -25,8 +25,8 @@
X 	unsigned char type;
X 	union
X 	{
X-		unsigned int ipv4_addr; /* network byte order */
X-		/* add IPV6 address type here */
X+		unsigned int ipv4_addr;		/* network byte order */
X+		unsigned int ipv6_addr[4];	/* network byte order */
X 	}			addr;
X } inet_struct;
X 
END-of-ipv6-patch
echo x - inet_cidr_ntop.c
sed 's/^X//' >inet_cidr_ntop.c << 'END-of-inet_cidr_ntop.c'
X/*
X * Copyright (c) 1998,1999 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic const char isc_rcsid[] = "Id: inet_cidr_ntop.c,v 8.7 2001/09/28 05:19:36 marka Exp $";
Xstatic const char rcsid[] = "$Id:$";
X#endif
X
X/*#include "port_before.h"*/
X
X#include 
X#include 
X#include 
X#include 
X#include 
X
X#include 
X#include 
X#include 
X#include 
X
X/*#include "port_after.h"*/
X
X#include "postgres.h"
X#include "utils/builtins.h"
X
X#ifdef SPRINTF_CHAR
X# define SPRINTF(x) strlen(sprintf/**/x)
X#else
X# define SPRINTF(x) ((size_t)sprintf x)
X#endif
X
Xstatic char *	inet_cidr_ntop_ipv4(const u_char *src, int bits,
X					 char *dst, size_t size);
Xstatic char *	inet_cidr_ntop_ipv6(const u_char *src, int bits,
X					 char *dst, size_t size);
X
X/*
X * char *
X * inet_cidr_ntop(af, src, bits, dst, size)
X *	convert network address from network to presentation format.
X *	"src"'s size is determined from its "af".
X * return:
X *	pointer to dst, or NULL if an error occurred (check errno).
X * note:
X *	192.5.5.1/28 has a nonzero host part, which means it isn't a network
X *	as called for by inet_net_ntop() but it can be a host address with
X *	an included netmask.
X * author:
X *	Paul Vixie (ISC), October 1998
X */
Xchar *
Xinet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
X	switch (af) {
X	case AF_INET:
X		return (inet_cidr_ntop_ipv4(src, bits, dst, size));
X	case AF_INET6:
X		return (inet_cidr_ntop_ipv6(src, bits, dst, size));
X	default:
X		errno = EAFNOSUPPORT;
X		return (NULL);
X	}
X}
X
Xstatic int
Xdecoct(const u_char *src, int bytes, char *dst, size_t size) {
X	char *odst = dst;
X	char *t;
X	int b;
X
X	for (b = 1; b <= bytes; b++) {
X		if (size < sizeof "255.")
X			return (0);
X		t = dst;
X		dst += SPRINTF((dst, "%u", *src++));
X		if (b != bytes) {
X			*dst++ = '.';
X			*dst = '\0';
X		}
X		size -= (size_t)(dst - t);
X	}
X	return (dst - odst);
X}
X
X/*
X * static char *
X * inet_cidr_ntop_ipv4(src, bits, dst, size)
X *	convert IPv4 network address from network to presentation format.
X *	"src"'s size is determined from its "af".
X * return:
X *	pointer to dst, or NULL if an error occurred (check errno).
X * note:
X *	network byte order assumed.  this means 192.5.5.240/28 has
X *	0b11110000 in its fourth octet.
X * author:
X *	Paul Vixie (ISC), October 1998
X */
Xstatic char *
Xinet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
X	char *odst = dst;
X	size_t len = 4;
X	size_t b;
X	size_t bytes;
X
X	if ((bits < -1) || (bits > 32)) {
X		errno = EINVAL;
X		return (NULL);
X	}
X
X	/* Find number of significant bytes in address. */
X	if (bits == -1)
X		len = 4;
X	else
X		for (len = 1, b = 1 ; b < 4; b++)
X			if (*(src + b))
X				len = b + 1;
X
X	/* Format whole octets plus nonzero trailing octets. */
X	bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
X	if (len > bytes)
X		bytes = len;
X	b = decoct(src, bytes, dst, size);
X	if (b == 0)
X		goto emsgsize;
X	dst += b;
X	size -= b;
X
X	if (bits != -1) {
X		/* Format CIDR /width. */
X		if (size < sizeof "/32")
X			goto emsgsize;
X		dst += SPRINTF((dst, "/%u", bits));
X	}
X
X	return (odst);
X
X emsgsize:
X	errno = EMSGSIZE;
X	return (NULL);
X}
X 
Xstatic char *
Xinet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
X	/*
X	 * Note that int32_t and int16_t need only be "at least" large enough
X	 * to contain a value of the specified size.  On some systems, like
X	 * Crays, there is no such thing as an integer variable with 16 bits.
X	 * Keep this in mind if you think this function should have been coded
X	 * to use pointer overlays.  All the world's not a VAX.
X	 */
X	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
X	char *tp;
X	struct { int base, len; } best, cur;
X	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
X	int i;
X
X	if ((bits < -1) || (bits > 128)) {
X		errno = EINVAL;
X		return (NULL);
X	}
X
X	/*
X	 * Preprocess:
X	 *	Copy the input (bytewise) array into a wordwise array.
X	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
X	 */
X	memset(words, '\0', sizeof words);
X	for (i = 0; i < NS_IN6ADDRSZ; i++)
X		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
X	best.base = -1;
X	cur.base = -1;
X	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
X		if (words[i] == 0) {
X			if (cur.base == -1)
X				cur.base = i, cur.len = 1;
X			else
X				cur.len++;
X		} else {
X			if (cur.base != -1) {
X				if (best.base == -1 || cur.len > best.len)
X					best = cur;
X				cur.base = -1;
X			}
X		}
X	}
X	if (cur.base != -1) {
X		if (best.base == -1 || cur.len > best.len)
X			best = cur;
X	}
X	if (best.base != -1 && best.len < 2)
X		best.base = -1;
X
X	/*
X	 * Format the result.
X	 */
X	tp = tmp;
X	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
X		/* Are we inside the best run of 0x00's? */
X		if (best.base != -1 && i >= best.base &&
X		    i < (best.base + best.len)) {
X			if (i == best.base)
X				*tp++ = ':';
X			continue;
X		}
X		/* Are we following an initial run of 0x00s or any real hex? */
X		if (i != 0)
X			*tp++ = ':';
X		/* Is this address an encapsulated IPv4? */
X		if (i == 6 && best.base == 0 && (best.len == 6 ||
X		    (best.len == 7 && words[7] != 0x0001) ||
X		    (best.len == 5 && words[5] == 0xffff))) {
X			int n;
X
X			if (src[15] || bits == -1 || bits > 120)
X				n = 4;
X			else if (src[14] || bits > 112)
X				n = 3;
X			else
X				n = 2;
X			n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
X			if (n == 0) {
X				errno = EMSGSIZE;
X				return (NULL);
X			}
X			tp += strlen(tp);
X			break;
X		}
X		tp += SPRINTF((tp, "%x", words[i]));
X	}
X
X	/* Was it a trailing run of 0x00's? */
X	if (best.base != -1 && (best.base + best.len) == 
X	    (NS_IN6ADDRSZ / NS_INT16SZ))
X		*tp++ = ':';
X	*tp = '\0';
X
X	if (bits != -1)
X		tp += SPRINTF((tp, "/%u", bits));
X
X	/*
X	 * Check for overflow, copy, and we're done.
X	 */
X	if ((size_t)(tp - tmp) > size) {
X		errno = EMSGSIZE;
X		return (NULL);
X	}
X	strcpy(dst, tmp);
X	return (dst);
X}
END-of-inet_cidr_ntop.c
echo x - inet_cidr_pton.c
sed 's/^X//' >inet_cidr_pton.c << 'END-of-inet_cidr_pton.c'
X/*
X * Copyright (c) 1998,1999 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic const char isc_rcsid[] = "Id: inet_cidr_pton.c,v 8.7 2001/09/28 04:21:28 marka Exp $";
Xstatic const char rcsid[] = "$Id:$";
X#endif
X
X/*#include "port_before.h"*/
X
X#include 
X#include 
X#include 
X#include 
X#include 
X
X/*#include */
X#include 
X#include 
X#include 
X#include 
X#include 
X#include 
X
X/*#include "port_after.h"*/
X
X#include "postgres.h"
X#include "utils/builtins.h"
X
X#ifdef SPRINTF_CHAR
X# define SPRINTF(x) strlen(sprintf/**/x)
X#else
X# define SPRINTF(x) ((size_t)sprintf x)
X#endif
X
Xstatic int	inet_cidr_pton_ipv4(const char *src, u_char *dst,
X					 int *bits, int ipv6);
Xstatic int	inet_cidr_pton_ipv6(const char *src, u_char *dst,
X					 int *bits);
X
Xstatic int	getbits(const char *, int ipv6);
X
X/*
X * int
X * inet_cidr_pton(af, src, dst, *bits)
X *	convert network address from presentation to network format.
X *	accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
X *	"dst" is assumed large enough for its "af".  "bits" is set to the
X *	/CIDR prefix length, which can have defaults (like /32 for IPv4).
X * return:
X *	-1 if an error occurred (inspect errno; ENOENT means bad format).
X *	0 if successful conversion occurred.
X * note:
X *	192.5.5.1/28 has a nonzero host part, which means it isn't a network
X *	as called for by inet_net_pton() but it can be a host address with
X *	an included netmask.
X * author:
X *	Paul Vixie (ISC), October 1998
X */
Xint
Xinet_cidr_pton(int af, const char *src, void *dst, int *bits) {
X	switch (af) {
X	case AF_INET:
X		return (inet_cidr_pton_ipv4(src, dst, bits, 0));
X	case AF_INET6:
X		return (inet_cidr_pton_ipv6(src, dst, bits));
X	default:
X		errno = EAFNOSUPPORT;
X		return (-1);
X	}
X}
X
Xstatic const char digits[] = "0123456789";
X
Xstatic int
Xinet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
X	const u_char *odst = dst;
X	int n, ch, tmp, bits;
X	size_t size = 4;
X
X	/* Get the mantissa. */
X	while (ch = *src++, (isascii(ch) && isdigit(ch))) {
X		tmp = 0;
X		do {
X			n = strchr(digits, ch) - digits;
X			assert(n >= 0 && n <= 9);
X			tmp *= 10;
X			tmp += n;
X			if (tmp > 255)
X				goto enoent;
X		} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
X		if (size-- == 0)
X			goto emsgsize;
X		*dst++ = (u_char) tmp;
X		if (ch == '\0' || ch == '/')
X			break;
X		if (ch != '.')
X			goto enoent;
X	}
X
X	/* Get the prefix length if any. */
X	bits = -1;
X	if (ch == '/' && dst > odst) {
X		bits = getbits(src, ipv6);
X		if (bits == -2)
X			goto enoent;
X	} else if (ch != '\0')
X		goto enoent;
X
X	/* Prefix length can default to /32 only if all four octets spec'd. */
X	if (bits == -1) {
X		if (dst - odst == 4)
X			bits = ipv6 ? 128 : 32;
X		else
X			goto enoent;
X	}
X
X	/* If nothing was written to the destination, we found no address. */
X	if (dst == odst)
X		goto enoent;
X
X	/* If prefix length overspecifies mantissa, life is bad. */
X	if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
X		goto enoent;
X
X	/* Extend address to four octets. */
X	while (size-- > 0)
X		*dst++ = 0;
X
X	*pbits = bits;
X	return (0);
X
X enoent:
X	errno = ENOENT;
X	return (-1);
X
X emsgsize:
X	errno = EMSGSIZE;
X	return (-1);
X}
X
Xstatic int
Xinet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
X	static const char xdigits_l[] = "0123456789abcdef",
X			  xdigits_u[] = "0123456789ABCDEF";
X	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
X	const char *xdigits, *curtok;
X	int ch, saw_xdigit;
X	u_int val;
X	int bits;
X
X	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
X	endp = tp + NS_IN6ADDRSZ;
X	colonp = NULL;
X	/* Leading :: requires some special handling. */
X	if (*src == ':')
X		if (*++src != ':')
X			return (0);
X	curtok = src;
X	saw_xdigit = 0;
X	val = 0;
X	bits = -1;
X	while ((ch = *src++) != '\0') {
X		const char *pch;
X
X		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
X			pch = strchr((xdigits = xdigits_u), ch);
X		if (pch != NULL) {
X			val <<= 4;
X			val |= (pch - xdigits);
X			if (val > 0xffff)
X				return (0);
X			saw_xdigit = 1;
X			continue;
X		}
X		if (ch == ':') {
X			curtok = src;
X			if (!saw_xdigit) {
X				if (colonp)
X					return (0);
X				colonp = tp;
X				continue;
X			} else if (*src == '\0') {
X				return (0);
X			}
X			if (tp + NS_INT16SZ > endp)
X				return (0);
X			*tp++ = (u_char) (val >> 8) & 0xff;
X			*tp++ = (u_char) val & 0xff;
X			saw_xdigit = 0;
X			val = 0;
X			continue;
X		}
X		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
X		    inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
X			tp += NS_INADDRSZ;
X			saw_xdigit = 0;
X			break;	/* '\0' was seen by inet_pton4(). */
X		}
X		if (ch == '/') {
X			bits = getbits(src, 1);
X			if (bits == -2)
X				goto enoent;
X			break;
X		}
X		goto enoent;
X	}
X	if (saw_xdigit) {
X		if (tp + NS_INT16SZ > endp)
X			goto emsgsize;
X		*tp++ = (u_char) (val >> 8) & 0xff;
X		*tp++ = (u_char) val & 0xff;
X	}
X	if (colonp != NULL) {
X		/*
X		 * Since some memmove()'s erroneously fail to handle
X		 * overlapping regions, we'll do the shift by hand.
X		 */
X		const int n = tp - colonp;
X		int i;
X
X		if (tp == endp)
X			goto enoent;
X		for (i = 1; i <= n; i++) {
X			endp[- i] = colonp[n - i];
X			colonp[n - i] = 0;
X		}
X		tp = endp;
X	}
X
X	memcpy(dst, tmp, NS_IN6ADDRSZ);
X
X	*pbits = bits;
X	return (0);
X
X enoent:
X	errno = ENOENT;
X	return (-1);
X
X emsgsize:
X	errno = EMSGSIZE;
X	return (-1);
X}
X
Xint
Xgetbits(const char *src, int ipv6) {
X	int bits = 0;
X	char *cp, ch;
X	
X	if (*src == '\0')			/* syntax */
X		return (-2);
X	do {
X		ch = *src++;
X		cp = strchr(digits, ch);
X		if (cp == NULL)			/* syntax */
X			return (-2);
X		bits *= 10;
X		bits += cp - digits;
X		if (bits == 0 && *src != '\0')	/* no leading zeros */
X			return (-2);
X		if (bits > (ipv6 ? 128 : 32))	/* range error */
X			return (-2);
X	} while (*src != '\0');
X
X	return (bits);
X}
END-of-inet_cidr_pton.c
exit

В списке pgsql-patches по дате отправления
От: Barry Lind
Дата:
От: Tom Lane
Дата:
FAQ