Re: IPv6 Support for INET/CIDR types.

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Paul A Vixie <vixie(at)vix(dot)com>
Cc: Vadim Kogan <vadim(at)xcf(dot)berkeley(dot)edu>, pgsql-patches(at)postgresql(dot)org
Subject: Re: IPv6 Support for INET/CIDR types.
Date: 2001-10-13 01:07:36
Message-ID: 200110130107.f9D17aQ17607@candle.pha.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches


Seems this will have to wait for 7.3.

> > 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 <sys/types.h>
> X #include <sys/socket.h>
> X #include <netinet/in.h>
> X #include <arpa/inet.h>
> X
> X #include <errno.h>
> X+#include <stdio.h>
> X+#include <string.h>
> X+#include <stdlib.h>
> 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 <sys/types.h>
> X #include <sys/socket.h>
> X #include <netinet/in.h>
> X+#include <arpa/nameser.h>
> X #include <arpa/inet.h>
> X
> X+/*#include <isc/assertions.h>*/
> X #include <assert.h>
> X #include <ctype.h>
> X #include <errno.h>
> X+#include <stdio.h>
> X+#include <string.h>
> X+#include <stdlib.h>
> 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 <sys/types.h>
> X#include <sys/socket.h>
> X#include <netinet/in.h>
> X#include <arpa/nameser.h>
> X#include <arpa/inet.h>
> X
> X#include <errno.h>
> X#include <stdio.h>
> X#include <string.h>
> X#include <stdlib.h>
> 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 <sys/types.h>
> X#include <sys/socket.h>
> X#include <netinet/in.h>
> X#include <arpa/nameser.h>
> X#include <arpa/inet.h>
> X
> X/*#include <isc/assertions.h>*/
> X#include <assert.h>
> X#include <ctype.h>
> X#include <errno.h>
> X#include <stdio.h>
> X#include <string.h>
> X#include <stdlib.h>
> 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
>
>

--
Bruce Momjian | http://candle.pha.pa.us
pgman(at)candle(dot)pha(dot)pa(dot)us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026

In response to

Responses

Browse pgsql-patches by date

  From Date Subject
Next Message Greg Sabino Mullane 2001-10-13 02:43:47 Re: Showing index details with \d on psql
Previous Message Bruce Momjian 2001-10-12 21:00:59 Re: Showing index details with \d on psql