From: | Paul A Vixie <vixie(at)vix(dot)com> |
---|---|
To: | Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us> |
Cc: | Vadim Kogan <vadim(at)xcf(dot)berkeley(dot)edu>, pgsql-patches(at)postgresql(dot)org |
Subject: | Re: IPv6 Support for INET/CIDR types. |
Date: | 2001-10-05 08:38:53 |
Message-ID: | 200110050838.f958crH48152@as.vix.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | 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
From | Date | Subject | |
---|---|---|---|
Next Message | Tom Lane | 2001-10-05 13:55:15 | Re: IPv6 Support for INET/CIDR types. |
Previous Message | Bruce Momjian | 2001-10-05 02:38:40 | Re: [HACKERS] Problem on AIX with current |