Re: IPv6 Support for INET/CIDR types. - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: IPv6 Support for INET/CIDR types.
Date
Msg-id 200110130107.f9D17aQ17607@candle.pha.pa.us
Whole thread Raw
In response to Re: IPv6 Support for INET/CIDR types.  (Paul A Vixie <vixie@vix.com>)
Responses Re: IPv6 Support for INET/CIDR types.  ("Marc G. Fournier" <scrappy@hub.org>)
Re: IPv6 Support for INET/CIDR types.  (Paul A Vixie <vixie@vix.com>)
List 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@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

pgsql-patches by date:

Previous
From: "Balaji Venkatesan"
Date:
Subject: Interchange
Next
From: "Christopher Kings-Lynne"
Date:
Subject: Re: Showing index details with \d on psql