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

From Paul A Vixie
Subject Re: IPv6 Support for INET/CIDR types.
Date
Msg-id 200110050838.f958crH48152@as.vix.com
Whole thread Raw
In response to Re: IPv6 Support for INET/CIDR types.  (Bruce Momjian <pgman@candle.pha.pa.us>)
Responses Re: IPv6 Support for INET/CIDR types.  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: IPv6 Support for INET/CIDR types.  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: IPv6 Support for INET/CIDR types.  (Vadim Kogan <vadim@xcf.berkeley.edu>)
List pgsql-patches
> 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


pgsql-patches by date:

Previous
From: Barry Lind
Date:
Subject: Re: Patch for handling unknown data types in jdbc driver
Next
From: Tom Lane
Date:
Subject: Re: IPv6 Support for INET/CIDR types.