IPv6 Support for INET/CIDR types.
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.
**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.
Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.
Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...
Vadim.
Ok, fine, I'm a retard. Sorry. This time there IS an attachment.
On Sun, Aug 05, 2001 at 11:27:07PM -0700, Vadim Kogan wrote:
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...Vadim.
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
Vadim.
Attachments:
postgresql-7.1.2-ipv6.difftext/plain; charset=us-asciiDownload+728-41
Can I have a version of this that can be applied? 7.2 beta will start
on Monday.
-- Start of PGP signed section.
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...Vadim.
-- End of PGP section.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
we're working this into a BIND release and will have the official ISC
version of these diffs to the inet_*() functions within a day or so.
the inet_*() functions are meant to be transitive, and the existing IPv4
entry points all are, so we're changing these contributed IPv6 entry points
to also be transitive, then we'll ship them.
as soon as we have something we're happy with i'll drop you a copy.
Show quoted text
From: Bruce Momjian <pgman@candle.pha.pa.us>
Message-Id: <200109062045.f86KjPV21792@candle.pha.pa.us>
Subject: Re: [PATCHES] IPv6 Support for INET/CIDR types.
In-Reply-To: <20010805232707.S32686@scam.xcf.berkeley.edu> "from Vadim Kogan
at Aug 5, 2001 11:27:07 pm"
To: Vadim Kogan <vadim@xcf.berkeley.edu>
Date: Thu, 6 Sep 2001 16:45:25 -0400 (EDT)
CC: pgsql-patches@postgresql.org, Paul A Vixie <vixie@mfnx.net>
X-Mailer: ELM [version 2.4ME+ PL90 (25)]
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCIICan I have a version of this that can be applied? 7.2 beta will start
on Monday.-- Start of PGP signed section.
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...Vadim.
-- End of PGP section.
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
There are bugs there! I know for sure.
I agree that the preferred way would be to have ISC release first and then
incorporate that. Once ISC releases the inet_* stuff, I can generate diff
based on that (with postgres-specific stuff).
I will try my best to send the latest version that I'm using. There are
still bugs there I think. But if enough people try enough random IPs/etc.
eventually all broken special cases will be fixed.
On Thu, Sep 06, 2001 at 02:10:37PM -0700, Paul A Vixie wrote:
we're working this into a BIND release and will have the official ISC
version of these diffs to the inet_*() functions within a day or so.the inet_*() functions are meant to be transitive, and the existing IPv4
entry points all are, so we're changing these contributed IPv6 entry points
to also be transitive, then we'll ship them.as soon as we have something we're happy with i'll drop you a copy.
From: Bruce Momjian <pgman@candle.pha.pa.us>
Message-Id: <200109062045.f86KjPV21792@candle.pha.pa.us>
Subject: Re: [PATCHES] IPv6 Support for INET/CIDR types.
In-Reply-To: <20010805232707.S32686@scam.xcf.berkeley.edu> "from Vadim Kogan
at Aug 5, 2001 11:27:07 pm"
To: Vadim Kogan <vadim@xcf.berkeley.edu>
Date: Thu, 6 Sep 2001 16:45:25 -0400 (EDT)
CC: pgsql-patches@postgresql.org, Paul A Vixie <vixie@mfnx.net>
X-Mailer: ELM [version 2.4ME+ PL90 (25)]
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCIICan I have a version of this that can be applied? 7.2 beta will start
on Monday.-- Start of PGP signed section.
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...Vadim.
-- End of PGP section.
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Vadim.
Do we have patch we can apply here?
There are bugs there! I know for sure.
I agree that the preferred way would be to have ISC release first and then
incorporate that. Once ISC releases the inet_* stuff, I can generate diff
based on that (with postgres-specific stuff).I will try my best to send the latest version that I'm using. There are
still bugs there I think. But if enough people try enough random IPs/etc.
eventually all broken special cases will be fixed.On Thu, Sep 06, 2001 at 02:10:37PM -0700, Paul A Vixie wrote:
we're working this into a BIND release and will have the official ISC
version of these diffs to the inet_*() functions within a day or so.the inet_*() functions are meant to be transitive, and the existing IPv4
entry points all are, so we're changing these contributed IPv6 entry points
to also be transitive, then we'll ship them.as soon as we have something we're happy with i'll drop you a copy.
From: Bruce Momjian <pgman@candle.pha.pa.us>
Message-Id: <200109062045.f86KjPV21792@candle.pha.pa.us>
Subject: Re: [PATCHES] IPv6 Support for INET/CIDR types.
In-Reply-To: <20010805232707.S32686@scam.xcf.berkeley.edu> "from Vadim Kogan
at Aug 5, 2001 11:27:07 pm"
To: Vadim Kogan <vadim@xcf.berkeley.edu>
Date: Thu, 6 Sep 2001 16:45:25 -0400 (EDT)
CC: pgsql-patches@postgresql.org, Paul A Vixie <vixie@mfnx.net>
X-Mailer: ELM [version 2.4ME+ PL90 (25)]
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCIICan I have a version of this that can be applied? 7.2 beta will start
on Monday.-- Start of PGP signed section.
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...Vadim.
-- End of PGP section.
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026Vadim.
-- End of PGP section, PGP failed!
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
yes. is the cvs-pserver up to date wrt pre-7.2?
Yes, it should be. There is a new path:
:pserver:anoncvs@anoncvs.postgresql.org:/projects/cvsroot
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
What is that status of this patch? We are near beta.
we're working this into a BIND release and will have the official ISC
version of these diffs to the inet_*() functions within a day or so.the inet_*() functions are meant to be transitive, and the existing IPv4
entry points all are, so we're changing these contributed IPv6 entry points
to also be transitive, then we'll ship them.as soon as we have something we're happy with i'll drop you a copy.
From: Bruce Momjian <pgman@candle.pha.pa.us>
Message-Id: <200109062045.f86KjPV21792@candle.pha.pa.us>
Subject: Re: [PATCHES] IPv6 Support for INET/CIDR types.
In-Reply-To: <20010805232707.S32686@scam.xcf.berkeley.edu> "from Vadim Kogan
at Aug 5, 2001 11:27:07 pm"
To: Vadim Kogan <vadim@xcf.berkeley.edu>
Date: Thu, 6 Sep 2001 16:45:25 -0400 (EDT)
CC: pgsql-patches@postgresql.org, Paul A Vixie <vixie@mfnx.net>
X-Mailer: ELM [version 2.4ME+ PL90 (25)]
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCIICan I have a version of this that can be applied? 7.2 beta will start
on Monday.-- Start of PGP signed section.
Attached is a patch that adds IPv6 support for inet and cidr datatypes. All
the functionality that was available for IPv4 is available for IPv6. In
addition comparison between IPv4 and IPv4-in-IPv6 addresses is available.**** WARNING: THIS PATCH HAS NOT BEEN TESTED ENOUGH! ****
(There is still some minor debug stuff left and such)
The patch is not likely to kill any of your data, but it could crash your
backend.Due to me being relatively busy lately, I was hoping that other people might
want to help me test the patch. If you have a problem, just email me what
you were doing and I will try to reproduce and fix it. Hopefully we can get
this small patch to the point of being stable soon enough and have it
included in the main tree.Paul: I suppose you can take a look at inet_{net,cidr}_{pton,ntop} stuff,
test it and eventually include with your code. Sorry for the delay, I had
this part more or less ready a while back, but never had time to finish the
postgres-specific part...Vadim.
-- End of PGP section.
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to majordomo@postgresql.org so that your
message can get through to the mailing list cleanly
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
On Wed, Oct 03, 2001 at 01:53:58PM -0700, Paul A Vixie wrote:
we have a version of this code plus some bug fixes in bind 8.3.0-T2A,
which i'm about to submit to you along with the glue code.
Does that mean that you'll send the whole thing and I shouldn't send
anything?
Vadim.
Import Notes
Reply to msg id not found: 200110032053.f93KrwH16003@as.vix.comReference msg id not found: pgman@candle.pha.pa.usReference msg id not found: 200110032053.f93KrwH16003@as.vix.com | Resolved by subject fallback
we have a version of this code plus some bug fixes in bind 8.3.0-T2A,
which i'm about to submit to you along with the glue code.
On Wed, Oct 03, 2001 at 03:31:49PM -0700, Paul A Vixie wrote:
Does that mean that you'll send the whole thing and I shouldn't send anything?
i'd like to do it all from here if possible.
Ok, cool with me.
Vadim.
Import Notes
Reply to msg id not found: 200110032231.f93MVnH17513@as.vix.comReference msg id not found: vadim@xcf.berkeley.eduReference msg id not found: 200110032231.f93MVnH17513@as.vix.com | Resolved by subject fallback
Does that mean that you'll send the whole thing and I shouldn't send anything?
i'd like to do it all from here if possible.
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
Paul A Vixie <vixie@vix.com> writes:
below please find a shar file containing [ ipv6 support ]
Lovely! Will review and commit this today if possible.
Could we trouble you for appropriate additions to the regression tests
and documentation, as well?
regards, tom lane
Seems this will have to wait for 7.3.
What is that status of this patch? We are near beta.
below please find a shar file containing:
the latest patch to inet.h and network.c from vadim with a few tiny
changes to the comments from me;a patch bringing inet_net_pton.c and inet_net_ntop.c up to date with
respect to isc's changes to those files in the time since INET/CIDR
were added, plus isc's corrected version of vadim's ipv6 changes to
those files;the new files inet_cidr_pton.c and inet_cidr_ntop.c, containing isc's
fixed version of vadim's ipv6 support for this api.a patch to src/backend/utils/adt/Makefile to compile the above files.
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# ipv6-patch
# inet_cidr_ntop.c
# inet_cidr_pton.c
#
echo x - ipv6-patch
sed 's/^X//' >ipv6-patch << 'END-of-ipv6-patch'
XIndex: src/backend/utils/adt/Makefile
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/Makefile,v
Xretrieving revision 1.51
Xdiff -u -r1.51 Makefile
X--- src/backend/utils/adt/Makefile 2001/10/04 04:13:40 1.51
X+++ src/backend/utils/adt/Makefile 2001/10/05 08:31:17
X@@ -22,7 +22,9 @@
X oid.o oracle_compat.o \
X regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
X tid.o timestamp.o varbit.o varchar.o varlena.o version.o \
X- network.o mac.o inet_net_ntop.o inet_net_pton.o \
X+ network.o mac.o \
X+ inet_net_ntop.o inet_net_pton.o \
X+ inet_cidr_ntop.o inet_cidr_pton.o \
X ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
X ascii.o quote.o pgstatfuncs.o encode.o
X
XIndex: src/backend/utils/adt/inet_net_ntop.c
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/inet_net_ntop.c,v
Xretrieving revision 1.10
Xdiff -u -r1.10 inet_net_ntop.c
X--- src/backend/utils/adt/inet_net_ntop.c 2001/03/22 03:59:51 1.10
X+++ src/backend/utils/adt/inet_net_ntop.c 2001/10/05 08:31:17
X@@ -1,5 +1,5 @@
X /*
X- * Copyright (c) 1996 by Internet Software Consortium.
X+ * Copyright (c) 1996,1999 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X@@ -16,34 +16,41 @@
X */
X
X #if defined(LIBC_SCCS) && !defined(lint)
X-static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.10 2001/03/22 03:59:51 momjian Exp $";
X-
X+static const char isc_rcsid[] = "Id: inet_net_ntop.c,v 1.8 2001/09/27 15:08:36 marka Exp $";
X+static const char rcsid[] = "$Id:$";
X #endif
X
X+/*#include "port_before.h"*/
X+
X #include <sys/types.h>
X #include <sys/socket.h>
X #include <netinet/in.h>
X #include <arpa/inet.h>
X
X #include <errno.h>
X+#include <stdio.h>
X+#include <string.h>
X+#include <stdlib.h>
X+
X+/*#include "port_after.h"*/
X
X #include "postgres.h"
X #include "utils/builtins.h"
X
X #ifdef SPRINTF_CHAR
X-#define SPRINTF(x) strlen(sprintf/**/x)
X+# define SPRINTF(x) strlen(sprintf/**/x)
X #else
X-#define SPRINTF(x) ((size_t)sprintf x)
X+# define SPRINTF(x) ((size_t)sprintf x)
X #endif
X
X-static char *inet_net_ntop_ipv4(const u_char *src, int bits,
X- char *dst, size_t size);
X-static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
X+static char * inet_net_ntop_ipv4(const u_char *src, int bits,
X char *dst, size_t size);
X+static char * inet_net_ntop_ipv6(const u_char *src, int bits,
X+ char *dst, size_t size);
X
X /*
X * char *
X- * inet_cidr_ntop(af, src, bits, dst, size)
X+ * inet_net_ntop(af, src, bits, dst, size)
X * convert network number from network to presentation format.
X * generates CIDR style result always.
X * return:
X@@ -52,167 +59,221 @@
X * Paul Vixie (ISC), July 1996
X */
X char *
X-inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
X+inet_net_ntop(af, src, bits, dst, size)
X+ int af;
X+ const void *src;
X+ int bits;
X+ char *dst;
X+ size_t size;
X {
X- switch (af)
X- {
X- case AF_INET:
X- return (inet_cidr_ntop_ipv4(src, bits, dst, size));
X- default:
X- errno = EAFNOSUPPORT;
X- return (NULL);
X+ switch (af) {
X+ case AF_INET:
X+ return (inet_net_ntop_ipv4(src, bits, dst, size));
X+ case AF_INET6:
X+ return (inet_net_ntop_ipv6(src, bits, dst, size));
X+ default:
X+ errno = EAFNOSUPPORT;
X+ return (NULL);
X }
X }
X
X-
X /*
X * static char *
X- * inet_cidr_ntop_ipv4(src, bits, dst, size)
X+ * inet_net_ntop_ipv4(src, bits, dst, size)
X * convert IPv4 network number from network to presentation format.
X * generates CIDR style result always.
X * return:
X * pointer to dst, or NULL if an error occurred (check errno).
X * note:
X * network byte order assumed. this means 192.5.5.240/28 has
X- * 0x11110000 in its fourth octet.
X+ * 0b11110000 in its fourth octet.
X * author:
X * Paul Vixie (ISC), July 1996
X */
X static char *
X-inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
X+inet_net_ntop_ipv4(src, bits, dst, size)
X+ const u_char *src;
X+ int bits;
X+ char *dst;
X+ size_t size;
X {
X- char *odst = dst;
X- char *t;
X- u_int m;
X- int b;
X+ char *odst = dst;
X+ char *t;
X+ u_int m;
X+ int b;
X
X- if (bits < 0 || bits > 32)
X- {
X+ if (bits < 0 || bits > 32) {
X errno = EINVAL;
X return (NULL);
X }
X- if (bits == 0)
X- {
X+
X+ if (bits == 0) {
X if (size < sizeof "0")
X goto emsgsize;
X *dst++ = '0';
X+ size--;
X *dst = '\0';
X }
X
X /* Format whole octets. */
X- for (b = bits / 8; b > 0; b--)
X- {
X- if (size < sizeof ".255")
X+ for (b = bits / 8; b > 0; b--) {
X+ if (size <= sizeof "255.")
X goto emsgsize;
X t = dst;
X- if (dst != odst)
X- *dst++ = '.';
X dst += SPRINTF((dst, "%u", *src++));
X- size -= (size_t) (dst - t);
X+ if (b > 1) {
X+ *dst++ = '.';
X+ *dst = '\0';
X+ }
X+ size -= (size_t)(dst - t);
X }
X
X /* Format partial octet. */
X b = bits % 8;
X- if (b > 0)
X- {
X- if (size < sizeof ".255")
X+ if (b > 0) {
X+ if (size <= sizeof ".255")
X goto emsgsize;
X t = dst;
X if (dst != odst)
X *dst++ = '.';
X m = ((1 << b) - 1) << (8 - b);
X dst += SPRINTF((dst, "%u", *src & m));
X- size -= (size_t) (dst - t);
X+ size -= (size_t)(dst - t);
X }
X
X /* Format CIDR /width. */
X- if (size < sizeof "/32")
X+ if (size <= sizeof "/32")
X goto emsgsize;
X dst += SPRINTF((dst, "/%u", bits));
X-
X return (odst);
X
X-emsgsize:
X+ emsgsize:
X errno = EMSGSIZE;
X return (NULL);
X }
X
X-
X /*
X- * char *
X- * inet_net_ntop(af, src, bits, dst, size)
X- * convert host/network address from network to presentation format.
X- * "src"'s size is determined from its "af".
X- * return:
X- * pointer to dst, or NULL if an error occurred (check errno).
X- * note:
X- * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
X- * as called for by inet_net_pton() but it can be a host address with
X- * an included netmask.
X- * author:
X- * Paul Vixie (ISC), October 1998
X- */
X-char *
X-inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
X-{
X- switch (af)
X- {
X- case AF_INET:
X- return (inet_net_ntop_ipv4(src, bits, dst, size));
X- default:
X- errno = EAFNOSUPPORT;
X- return (NULL);
X- }
X-}
X-
X-/*
X * static char *
X- * inet_net_ntop_ipv4(src, bits, dst, size)
X- * convert IPv4 network address from network to presentation format.
X- * "src"'s size is determined from its "af".
X+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
X+ * convert IPv6 network number from network to presentation format.
X+ * generates CIDR style result always. Picks the shortest representation
X+ * unless the IP is really IPv4.
X+ * always prints specified number of bits (bits).
X * return:
X * pointer to dst, or NULL if an error occurred (check errno).
X * note:
X * network byte order assumed. this means 192.5.5.240/28 has
X- * 0b11110000 in its fourth octet.
X+ * 0x11110000 in its fourth octet.
X * author:
X- * Paul Vixie (ISC), October 1998
X+ * Vadim Kogan (UCB), June 2001
X+ * Original version (IPv4) by Paul Vixie (ISC), July 1996
X */
X+
X static char *
X-inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
X-{
X- char *odst = dst;
X- char *t;
X- int len = 4;
X- int b;
X+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
X+ u_int m;
X+ int b;
X+ int p;
X+ int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
X+ int i;
X+ int is_ipv4 = 0;
X+ unsigned char inbuf[16];
X+ char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
X+ char *cp;
X+ int words;
X+ u_char *s;
X
X- if (bits < 0 || bits > 32)
X- {
X+ if (bits < 0 || bits > 128) {
X errno = EINVAL;
X return (NULL);
X }
X
X- /* Always format all four octets, regardless of mask length. */
X- for (b = len; b > 0; b--)
X- {
X- if (size < sizeof ".255")
X- goto emsgsize;
X- t = dst;
X- if (dst != odst)
X- *dst++ = '.';
X- dst += SPRINTF((dst, "%u", *src++));
X- size -= (size_t) (dst - t);
X- }
X+ cp = outbuf;
X
X- /* don't print masklen if 32 bits */
X- if (bits != 32)
X- {
X- if (size < sizeof "/32")
X- goto emsgsize;
X- dst += SPRINTF((dst, "/%u", bits));
X+ if (bits == 0) {
X+ *cp++ = ':';
X+ *cp++ = ':';
X+ *cp = '\0';
X+ } else {
X+ /* Copy src to private buffer. Zero host part. */
X+ p = (bits + 7) / 8;
X+ memcpy(inbuf, src, p);
X+ memset(inbuf + p, 0, 16 - p);
X+ b = bits % 8;
X+ if (b != 0) {
X+ m = ~0 << (8 - b);
X+ inbuf[p-1] &= m;
X+ }
X+
X+ s = inbuf;
X+
X+ /* how many words need to be displayed in output */
X+ words = (bits + 15) / 16;
X+ if (words == 1)
X+ words = 2;
X+
X+ /* Find the longest substring of zero's */
X+ zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
X+ for (i = 0; i < (words * 2); i += 2) {
X+ if ((s[i] | s[i+1]) == 0) {
X+ if (tmp_zero_l == 0)
X+ tmp_zero_s = i / 2;
X+ tmp_zero_l++;
X+ } else {
X+ if (tmp_zero_l && zero_l < tmp_zero_l) {
X+ zero_s = tmp_zero_s;
X+ zero_l = tmp_zero_l;
X+ tmp_zero_l = 0;
X+ }
X+ }
X+ }
X+
X+ if (tmp_zero_l && zero_l < tmp_zero_l) {
X+ zero_s = tmp_zero_s;
X+ zero_l = tmp_zero_l;
X+ }
X+
X+ if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
X+ ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
X+ ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
X+ is_ipv4 = 1;
X+
X+ /* Format whole words. */
X+ for (p = 0; p < words; p++) {
X+ if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
X+ /* Time to skip some zeros */
X+ if (p == zero_s)
X+ *cp++ = ':';
X+ if (p == words - 1)
X+ *cp++ = ':';
X+ s++;
X+ s++;
X+ continue;
X+ }
X+
X+ if (is_ipv4 && p > 5 ) {
X+ *cp++ = (p == 6) ? ':' : '.';
X+ cp += SPRINTF((cp, "%u", *s++));
X+ /* we can potentially drop the last octet */
X+ if (p != 7 || bits > 120) {
X+ *cp++ = '.';
X+ cp += SPRINTF((cp, "%u", *s++));
X+ }
X+ } else {
X+ if (cp != outbuf)
X+ *cp++ = ':';
X+ cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
X+ s += 2;
X+ }
X+ }
X }
X-
X- return (odst);
X+ /* Format CIDR /width. */
X+ SPRINTF((cp, "/%u", bits));
X+ if (strlen(outbuf) + 1 > size)
X+ goto emsgsize;
X+ strcpy(dst, outbuf);
X+
X+ return (dst);
X
X emsgsize:
X errno = EMSGSIZE;
XIndex: src/backend/utils/adt/inet_net_pton.c
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/inet_net_pton.c,v
Xretrieving revision 1.12
Xdiff -u -r1.12 inet_net_pton.c
X--- src/backend/utils/adt/inet_net_pton.c 2000/12/03 20:45:36 1.12
X+++ src/backend/utils/adt/inet_net_pton.c 2001/10/05 08:31:17
X@@ -1,5 +1,5 @@
X /*
X- * Copyright (c) 1996 by Internet Software Consortium.
X+ * Copyright (c) 1996,1999 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X@@ -16,67 +16,40 @@
X */
X
X #if defined(LIBC_SCCS) && !defined(lint)
X-static const char rcsid[] = "$Id: inet_net_pton.c,v 1.12 2000/12/03 20:45:36 tgl Exp $";
X-
X+static const char isc_rcsid[] = "Id: inet_net_pton.c,v 1.13 2001/09/27 15:08:38 marka Exp $";
X+static const char rcsid[] = "$Id:$";
X #endif
X
X+/*#include "port_before.h"*/
X+
X #include <sys/types.h>
X #include <sys/socket.h>
X #include <netinet/in.h>
X+#include <arpa/nameser.h>
X #include <arpa/inet.h>
X
X+/*#include <isc/assertions.h>*/
X #include <assert.h>
X #include <ctype.h>
X #include <errno.h>
X+#include <stdio.h>
X+#include <string.h>
X+#include <stdlib.h>
X
X+/*#include "port_after.h"*/
X+
X #include "postgres.h"
X #include "utils/builtins.h"
X
X #ifdef SPRINTF_CHAR
X-#define SPRINTF(x) strlen(sprintf/**/x)
X+# define SPRINTF(x) strlen(sprintf/**/x)
X #else
X-#define SPRINTF(x) ((size_t)sprintf x)
X+# define SPRINTF(x) ((size_t)sprintf x)
X #endif
X
X-static int inet_net_pton_ipv4(const char *src, u_char *dst);
X-static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
X-
X /*
X * static int
X- * inet_net_pton(af, src, dst, size)
X- * convert network number from presentation to network format.
X- * accepts hex octets, hex strings, decimal octets, and /CIDR.
X- * "size" is in bytes and describes "dst".
X- * return:
X- * number of bits, either imputed classfully or specified with /CIDR,
X- * or -1 if some failure occurred (check errno). ENOENT means it was
X- * not a valid network specification.
X- * author:
X- * Paul Vixie (ISC), June 1996
X- *
X- * Changes:
X- * I added the inet_cidr_pton function (also from Paul) and changed
X- * the names to reflect their current use.
X- *
X- */
X-int
X-inet_net_pton(int af, const char *src, void *dst, size_t size)
X-{
X- switch (af)
X- {
X- case AF_INET:
X- return size == -1 ?
X- inet_net_pton_ipv4(src, dst) :
X- inet_cidr_pton_ipv4(src, dst, size);
X- default:
X- errno = EAFNOSUPPORT;
X- return (-1);
X- }
X-}
X-
X-/*
X- * static int
X- * inet_cidr_pton_ipv4(src, dst, size)
X+ * inet_net_pton_ipv4(src, dst, size)
X * convert IPv4 network number from presentation to network format.
X * accepts hex octets, hex strings, decimal octets, and /CIDR.
X * "size" is in bytes and describes "dst".
X@@ -86,66 +59,52 @@
X * not an IPv4 network specification.
X * note:
X * network byte order assumed. this means 192.5.5.240/28 has
X- * 0x11110000 in its fourth octet.
X+ * 0b11110000 in its fourth octet.
X * author:
X * Paul Vixie (ISC), June 1996
X */
X static int
X-inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
X-{
X- static const char
X- xdigits[] = "0123456789abcdef",
X- digits[] = "0123456789";
X- int n,
X- ch,
X- tmp,
X- dirty,
X- bits;
X+inet_net_pton_ipv4( const char *src, u_char *dst, size_t size) {
X+ static const char xdigits[] = "0123456789abcdef";
X+ static const char digits[] = "0123456789";
X+ int n, ch, tmp = 0, dirty, bits;
X const u_char *odst = dst;
X
X ch = *src++;
X if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
X- && isxdigit((unsigned char) src[1]))
X- {
X+ && isascii((unsigned char)(src[1]))
X+ && isxdigit((unsigned char)(src[1]))) {
X /* Hexadecimal: Eat nybble string. */
X if (size <= 0)
X goto emsgsize;
X dirty = 0;
X- tmp = 0;
X- src++; /* skip x or X. */
X- while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
X- {
X- if (isupper((unsigned char) ch))
X- ch = tolower((unsigned char) ch);
X+ src++; /* skip x or X. */
X+ while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
X+ if (isupper(ch))
X+ ch = tolower(ch);
X n = strchr(xdigits, ch) - xdigits;
X assert(n >= 0 && n <= 15);
X if (dirty == 0)
X tmp = n;
X else
X tmp = (tmp << 4) | n;
X- if (++dirty == 2)
X- {
X+ if (++dirty == 2) {
X if (size-- <= 0)
X goto emsgsize;
X *dst++ = (u_char) tmp;
X dirty = 0;
X }
X }
X- if (dirty)
X- { /* Odd trailing nybble? */
X+ if (dirty) { /* Odd trailing nybble? */
X if (size-- <= 0)
X goto emsgsize;
X *dst++ = (u_char) (tmp << 4);
X }
X- }
X- else if (isdigit((unsigned char) ch))
X- {
X+ } else if (isascii(ch) && isdigit(ch)) {
X /* Decimal: eat dotted digit string. */
X- for (;;)
X- {
X+ for (;;) {
X tmp = 0;
X- do
X- {
X+ do {
X n = strchr(digits, ch) - digits;
X assert(n >= 0 && n <= 9);
X tmp *= 10;
X@@ -153,7 +112,7 @@
X if (tmp > 255)
X goto enoent;
X } while ((ch = *src++) != '\0' &&
X- isdigit((unsigned char) ch));
X+ isascii(ch) && isdigit(ch));
X if (size-- <= 0)
X goto emsgsize;
X *dst++ = (u_char) tmp;
X@@ -162,26 +121,24 @@
X if (ch != '.')
X goto enoent;
X ch = *src++;
X- if (!isdigit((unsigned char) ch))
X+ if (!isascii(ch) || !isdigit(ch))
X goto enoent;
X }
X- }
X- else
X+ } else
X goto enoent;
X
X bits = -1;
X- if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
X- {
X+ if (ch == '/' && isascii((unsigned char)(src[0])) &&
X+ isdigit((unsigned char)(src[0])) && dst > odst) {
X /* CIDR width specifier. Nothing can follow it. */
X- ch = *src++; /* Skip over the /. */
X+ ch = *src++; /* Skip over the /. */
X bits = 0;
X- do
X- {
X+ do {
X n = strchr(digits, ch) - digits;
X assert(n >= 0 && n <= 9);
X bits *= 10;
X bits += n;
X- } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
X+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
X if (ch != '\0')
X goto enoent;
X if (bits > 32)
X@@ -196,9 +153,8 @@
X if (dst == odst)
X goto enoent;
X /* If no CIDR spec was given, infer width from net class. */
X- if (bits == -1)
X- {
X- if (*odst >= 240) /* Class E */
X+ if (bits == -1) {
X+ if (*odst >= 240) /* Class E */
X bits = 32;
X else if (*odst >= 224) /* Class D */
X bits = 4;
X@@ -206,133 +162,243 @@
X bits = 24;
X else if (*odst >= 128) /* Class B */
X bits = 16;
X- else
X-/* Class A */
X+ else /* Class A */
X bits = 8;
X /* If imputed mask is narrower than specified octets, widen. */
X if (bits >= 8 && bits < ((dst - odst) * 8))
X bits = (dst - odst) * 8;
X }
X /* Extend network to cover the actual mask. */
X- while (bits > ((dst - odst) * 8))
X- {
X+ while (bits > ((dst - odst) * 8)) {
X if (size-- <= 0)
X goto emsgsize;
X *dst++ = '\0';
X }
X return (bits);
X
X-enoent:
X+ enoent:
X errno = ENOENT;
X return (-1);
X
X-emsgsize:
X+ emsgsize:
X errno = EMSGSIZE;
X return (-1);
X }
X
X-/*
X- * int
X- * inet_net_pton(af, src, dst, *bits)
X- * convert network address from presentation to network format.
X- * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
X- * "dst" is assumed large enough for its "af". "bits" is set to the
X- * /CIDR prefix length, which can have defaults (like /32 for IPv4).
X- * return:
X- * -1 if an error occurred (inspect errno; ENOENT means bad format).
X- * 0 if successful conversion occurred.
X- * note:
X- * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
X- * as called for by inet_cidr_pton() but it can be a host address with
X- * an included netmask.
X- * author:
X- * Paul Vixie (ISC), October 1998
X- */
X static int
X-inet_net_pton_ipv4(const char *src, u_char *dst)
X-{
X+getbits(const char *src, int *bitsp) {
X static const char digits[] = "0123456789";
X- const u_char *odst = dst;
X- int n,
X- ch,
X- tmp,
X- bits;
X- size_t size = 4;
X-
X- /* Get the mantissa. */
X- while (ch = *src++, isdigit((unsigned char) ch))
X- {
X- tmp = 0;
X- do
X- {
X- n = strchr(digits, ch) - digits;
X- assert(n >= 0 && n <= 9);
X- tmp *= 10;
X- tmp += n;
X- if (tmp > 255)
X- goto enoent;
X- } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
X- if (size-- == 0)
X- goto emsgsize;
X- *dst++ = (u_char) tmp;
X- if (ch == '\0' || ch == '/')
X- break;
X- if (ch != '.')
X- goto enoent;
X+ int n;
X+ int val;
X+ char ch;
X+
X+ val = 0;
X+ n = 0;
X+ while ((ch = *src++) != '\0') {
X+ const char *pch;
X+
X+ pch = strchr(digits, ch);
X+ if (pch != NULL) {
X+ if (n++ != 0 && val == 0) /* no leading zeros */
X+ return (0);
X+ val *= 10;
X+ val += (pch - digits);
X+ if (val > 128) /* range */
X+ return (0);
X+ continue;
X+ }
X+ return (0);
X }
X+ if (n == 0)
X+ return (0);
X+ *bitsp = val;
X+ return (1);
X+}
X
X- /* Get the prefix length if any. */
X- bits = -1;
X- if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
X- {
X- /* CIDR width specifier. Nothing can follow it. */
X- ch = *src++; /* Skip over the /. */
X- bits = 0;
X- do
X- {
X- n = strchr(digits, ch) - digits;
X- assert(n >= 0 && n <= 9);
X- bits *= 10;
X- bits += n;
X- } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
X- if (ch != '\0')
X- goto enoent;
X- if (bits > 32)
X- goto emsgsize;
X+static int
X+getv4(const char *src, u_char *dst, int *bitsp) {
X+ static const char digits[] = "0123456789";
X+ u_char *odst = dst;
X+ int n;
X+ u_int val;
X+ char ch;
X+
X+ val = 0;
X+ n = 0;
X+ while ((ch = *src++) != '\0') {
X+ const char *pch;
X+
X+ pch = strchr(digits, ch);
X+ if (pch != NULL) {
X+ if (n++ != 0 && val == 0) /* no leading zeros */
X+ return (0);
X+ val *= 10;
X+ val += (pch - digits);
X+ if (val > 255) /* range */
X+ return (0);
X+ continue;
X+ }
X+ if (ch == '.' || ch == '/') {
X+ if (dst - odst > 3) /* too many octets? */
X+ return (0);
X+ *dst++ = val;
X+ if (ch == '/')
X+ return (getbits(src, bitsp));
X+ val = 0;
X+ n = 0;
X+ continue;
X+ }
X+ return (0);
X }
X+ if (n == 0)
X+ return (0);
X+ if (dst - odst > 3) /* too many octets? */
X+ return (0);
X+ *dst++ = val;
X+ return (1);
X+}
X
X- /* Firey death and destruction unless we prefetched EOS. */
X- if (ch != '\0')
X+static int
X+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
X+ static const char xdigits_l[] = "0123456789abcdef",
X+ xdigits_u[] = "0123456789ABCDEF";
X+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
X+ const char *xdigits, *curtok;
X+ int ch, saw_xdigit;
X+ u_int val;
X+ int digits;
X+ int bits;
X+ size_t bytes;
X+ int words;
X+ int ipv4;
X+
X+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
X+ endp = tp + NS_IN6ADDRSZ;
X+ colonp = NULL;
X+ /* Leading :: requires some special handling. */
X+ if (*src == ':')
X+ if (*++src != ':')
X+ goto enoent;
X+ curtok = src;
X+ saw_xdigit = 0;
X+ val = 0;
X+ digits = 0;
X+ bits = -1;
X+ ipv4 = 0;
X+ while ((ch = *src++) != '\0') {
X+ const char *pch;
X+
X+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
X+ pch = strchr((xdigits = xdigits_u), ch);
X+ if (pch != NULL) {
X+ val <<= 4;
X+ val |= (pch - xdigits);
X+ if (++digits > 4)
X+ goto enoent;
X+ saw_xdigit = 1;
X+ continue;
X+ }
X+ if (ch == ':') {
X+ curtok = src;
X+ if (!saw_xdigit) {
X+ if (colonp)
X+ goto enoent;
X+ colonp = tp;
X+ continue;
X+ } else if (*src == '\0')
X+ goto enoent;
X+ if (tp + NS_INT16SZ > endp)
X+ return (0);
X+ *tp++ = (u_char) (val >> 8) & 0xff;
X+ *tp++ = (u_char) val & 0xff;
X+ saw_xdigit = 0;
X+ digits = 0;
X+ val = 0;
X+ continue;
X+ }
X+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
X+ getv4(curtok, tp, &bits) > 0) {
X+ tp += NS_INADDRSZ;
X+ saw_xdigit = 0;
X+ ipv4 = 1;
X+ break; /* '\0' was seen by inet_pton4(). */
X+ }
X+ if (ch == '/' && getbits(src, &bits) > 0)
X+ break;
X goto enoent;
X-
X- /* Prefix length can default to /32 only if all four octets spec'd. */
X- if (bits == -1)
X- {
X- if (dst - odst == 4)
X- bits = 32;
X- else
X+ }
X+ if (saw_xdigit) {
X+ if (tp + NS_INT16SZ > endp)
X goto enoent;
X+ *tp++ = (u_char) (val >> 8) & 0xff;
X+ *tp++ = (u_char) val & 0xff;
X }
X+ if (bits == -1)
X+ bits = 128;
X
X- /* If nothing was written to the destination, we found no address. */
X- if (dst == odst)
X- goto enoent;
X+ words = (bits + 15) / 16;
X+ if (words < 2)
X+ words = 2;
X+ if (ipv4)
X+ words = 8;
X+ endp = tmp + 2 * words;
X+
X+ if (colonp != NULL) {
X+ /*
X+ * Since some memmove()'s erroneously fail to handle
X+ * overlapping regions, we'll do the shift by hand.
X+ */
X+ const int n = tp - colonp;
X+ int i;
X
X- /* If prefix length overspecifies mantissa, life is bad. */
X- if ((bits / 8) > (dst - odst))
X+ if (tp == endp)
X+ goto enoent;
X+ for (i = 1; i <= n; i++) {
X+ endp[- i] = colonp[n - i];
X+ colonp[n - i] = 0;
X+ }
X+ tp = endp;
X+ }
X+ if (tp != endp)
X goto enoent;
X-
X- /* Extend address to four octets. */
X- while (size-- > 0)
X- *dst++ = 0;
X
X- return bits;
X+ bytes = (bits + 7) / 8;
X+ if (bytes > size)
X+ goto emsgsize;
X+ memcpy(dst, tmp, bytes);
X+ return (bits);
X
X-enoent:
X+ enoent:
X errno = ENOENT;
X return (-1);
X
X-emsgsize:
X+ emsgsize:
X errno = EMSGSIZE;
X return (-1);
X+}
X+
X+/*
X+ * int
X+ * inet_net_pton(af, src, dst, size)
X+ * convert network number from presentation to network format.
X+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
X+ * "size" is in bytes and describes "dst".
X+ * return:
X+ * number of bits, either imputed classfully or specified with /CIDR,
X+ * or -1 if some failure occurred (check errno). ENOENT means it was
X+ * not a valid network specification.
X+ * author:
X+ * Paul Vixie (ISC), June 1996
X+ */
X+int
X+inet_net_pton(int af, const char *src, void *dst, size_t size) {
X+ switch (af) {
X+ case AF_INET:
X+ return (inet_net_pton_ipv4(src, dst, size));
X+ case AF_INET6:
X+ return (inet_net_pton_ipv6(src, dst, size));
X+ default:
X+ errno = EAFNOSUPPORT;
X+ return (-1);
X+ }
X }
XIndex: src/backend/utils/adt/network.c
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/network.c,v
Xretrieving revision 1.33
Xdiff -u -r1.33 network.c
X--- src/backend/utils/adt/network.c 2001/08/27 20:03:38 1.33
X+++ src/backend/utils/adt/network.c 2001/10/05 08:31:18
X@@ -1,7 +1,5 @@
X /*
X- * PostgreSQL type definitions for the INET type. This
X- * is for IP V4 CIDR notation, but prepared for V6: just
X- * add the necessary bits where the comments indicate.
X+ * PostgreSQL type definitions for the INET type.
X *
X * $Header: /projects/cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.33 2001/08/27 20:03:38 tgl Exp $
X *
X@@ -21,17 +19,26 @@
X #include "utils/inet.h"
X
X
X+#ifndef INET6_ADDRSTRLEN
X+#define INET6_ADDRSTRLEN 46
X+#endif
X+
X+#define INET6_CIDRSTRLEN (INET6_ADDRSTRLEN + 4)
X+
X static Datum text_network(text *src, int type);
X static int32 network_cmp_internal(inet *a1, inet *a2);
X static int v4bitncmp(unsigned long a1, unsigned long a2, int bits);
X static bool v4addressOK(unsigned long a1, int bits);
X+static int v6bitncmp(unsigned int *a1, unsigned int *a2, int bits);
X+static bool v6addressOK(unsigned int *a1, int bits);
X
X /*
X- * Access macros. Add IPV6 support.
X+ * Access macros.
X */
X
X #define ip_addrsize(inetptr) \
X- (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1)
X+ (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : \
X+ (((inet_struct *)VARDATA(inetptr))->family == AF_INET6 ? 16 : -1 ))
X
X #define ip_family(inetptr) \
X (((inet_struct *)VARDATA(inetptr))->family)
X@@ -39,12 +46,33 @@
X #define ip_bits(inetptr) \
X (((inet_struct *)VARDATA(inetptr))->bits)
X
X+#define ip_ipv4bits(inetptr) \
X+ (ip_bits(inetptr) - (ip_family(inetptr) == AF_INET6 ? 96 : 0))
X+
X #define ip_type(inetptr) \
X (((inet_struct *)VARDATA(inetptr))->type)
X
X #define ip_v4addr(inetptr) \
X (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
X
X+#define ip_v6addr(inetptr) \
X+ (((inet_struct *)VARDATA(inetptr))->addr.ipv6_addr)
X+
X+#define ip_v4inv6addr(inetptr) \
X+ (((inet_struct *)VARDATA(inetptr))->addr.ipv6_addr[ 3 ])
X+
X+#define ip_v4addr_always(inetptr) \
X+ (ip_family(inetptr) == AF_INET ? ip_v4addr(inetptr) \
X+ : ip_v4inv6addr(inetptr))
X+
X+#define ip_is_ipv4(inetptr) \
X+ (ip_family(inetptr) == AF_INET || \
X+ (ip_family(inetptr) == AF_INET6 && \
X+ ip_v6addr(inetptr)[0] == 0 && \
X+ ip_v6addr(inetptr)[1] == 0 && \
X+ (ip_v6addr(inetptr)[2] == 0 || \
X+ ntohl(ip_v6addr(inetptr)[2]) == 0xFFFF) ))
X+
X /* Common input routine */
X static inet *
X network_in(char *src, int type)
X@@ -63,17 +91,25 @@
X if ((bits < 0) || (bits > 32))
X {
X /* Go for an IPV6 address here, before faulting out: */
X- elog(ERROR, "invalid %s value '%s'",
X- type ? "CIDR" : "INET", src);
X+ ip_family(dst) = AF_INET6;
X+ bits = inet_net_pton(ip_family(dst), src, &ip_v6addr(dst),
X+ type ? ip_addrsize(dst) : -1);
X+ if ((bits < 0) || (bits > 128)) {
X+ elog(ERROR, "invalid %s value '%s'",
X+ type ? "CIDR" : "INET", src);
X+ }
X }
X
X /*
X * Error check: CIDR values must not have any bits set beyond the
X- * masklen. XXX this code is not IPV6 ready.
X+ * masklen.
X */
X if (type)
X {
X- if (!v4addressOK(ip_v4addr(dst), bits))
X+ if (
X+ !(ip_family(dst) == AF_INET && v4addressOK(ip_v4addr(dst), bits)) &&
X+ !(ip_family(dst) == AF_INET6 && v6addressOK(ip_v6addr(dst), bits))
X+ )
X elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src);
X }
X
X@@ -111,19 +147,17 @@
X inet_out(PG_FUNCTION_ARGS)
X {
X inet *src = PG_GETARG_INET_P(0);
X- char tmp[sizeof("255.255.255.255/32")];
X+ char tmp[INET6_CIDRSTRLEN];
X char *dst;
X int len;
X
X- if (ip_family(src) == AF_INET)
X+ if (ip_family(src) == AF_INET || ip_family(src) == AF_INET6)
X {
X- /* It's an IP V4 address: */
X-
X /*
X * Use inet style for both inet and cidr, since we don't want
X * abbreviated CIDR style here.
X */
X- dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
X+ dst = inet_net_ntop(ip_family(src), &ip_v4addr(src), ip_bits(src),
X tmp, sizeof(tmp));
X if (dst == NULL)
X elog(ERROR, "unable to print address (%s)", strerror(errno));
X@@ -135,7 +169,6 @@
X }
X }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(src));
X
X PG_RETURN_CSTRING(pstrdup(tmp));
X@@ -222,9 +255,55 @@
X return order;
X return v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), 32);
X }
X+ else if (ip_family(a1) == AF_INET6 && ip_family(a2) == AF_INET6)
X+ {
X+ int order;
X+
X+ order = v6bitncmp(ip_v6addr(a1), ip_v6addr(a2),
X+ Min(ip_bits(a1), ip_bits(a2)));
X+ if (order != 0)
X+ return order;
X+ order = ((int) ip_bits(a1)) - ((int) ip_bits(a2));
X+ if (order != 0)
X+ return order;
X+ return v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), 128);
X+ }
X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+ {
X+ /* Be smart and compare IP V4 with IP V6 */
X+ int order;
X+
X+
X+ order = v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2),
X+ Min(ip_ipv4bits(a1), ip_ipv4bits(a2)));
X+ if (order != 0)
X+ return order;
X+ order = ((int) ip_ipv4bits(a1)) - ((int) ip_ipv4bits(a2));
X+ if (order != 0)
X+ return order;
X+ return v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), 32);
X+ }
X else
X {
X- /* Go for an IPV6 address here, before faulting out: */
X+ elog( DEBUG, "----" );
X+ if( ip_family(a1) == AF_INET )
X+ elog( DEBUG, "Pure IPv4" );
X+ else
X+ elog( DEBUG, "0: 0x%X, 1: 0x%X, 2: 0x%X, 3: 0x%X",
X+ ip_v6addr(a1)[0],
X+ ip_v6addr(a1)[1],
X+ ip_v6addr(a1)[2],
X+ ip_v6addr(a1)[3] );
X+
X+ if( ip_family(a2) == AF_INET )
X+ elog( DEBUG, "Pure IPv4" );
X+ else
X+ elog( DEBUG, "0: 0x%X, 1: 0x%X, 2: 0x%X, 3: 0x%X",
X+ ip_v6addr(a2)[0],
X+ ip_v6addr(a2)[1],
X+ ip_v6addr(a2)[2],
X+ ip_v6addr(a2)[3] );
X+
X elog(ERROR, "cannot compare address families %d and %d",
X ip_family(a1), ip_family(a2));
X return 0; /* keep compiler quiet */
X@@ -311,9 +390,18 @@
X PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
X }
X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+ {
X+ PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+ }
X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+ {
X+ PG_RETURN_BOOL(ip_ipv4bits(a1) > ip_ipv4bits(a2)
X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a2)) == 0);
X+ }
X else
X {
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "cannot compare address families %d and %d",
X ip_family(a1), ip_family(a2));
X PG_RETURN_BOOL(false);
X@@ -331,9 +419,18 @@
X PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
X }
X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+ {
X+ PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+ }
X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+ {
X+ PG_RETURN_BOOL(ip_ipv4bits(a1) >= ip_ipv4bits(a2)
X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a2)) == 0);
X+ }
X else
X {
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "cannot compare address families %d and %d",
X ip_family(a1), ip_family(a2));
X PG_RETURN_BOOL(false);
X@@ -351,9 +448,18 @@
X PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
X }
X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+ {
X+ PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+ }
X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+ {
X+ PG_RETURN_BOOL(ip_ipv4bits(a1) < ip_ipv4bits(a2)
X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a1)) == 0);
X+ }
X else
X {
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "cannot compare address families %d and %d",
X ip_family(a1), ip_family(a2));
X PG_RETURN_BOOL(false);
X@@ -371,9 +477,18 @@
X PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
X }
X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6))
X+ {
X+ PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0);
X+ }
X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2))
X+ {
X+ PG_RETURN_BOOL(ip_ipv4bits(a1) <= ip_ipv4bits(a2)
X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a1)) == 0);
X+ }
X else
X {
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "cannot compare address families %d and %d",
X ip_family(a1), ip_family(a2));
X PG_RETURN_BOOL(false);
X@@ -390,17 +505,17 @@
X text *ret;
X int len;
X char *ptr,
X- tmp[sizeof("255.255.255.255/32")];
X+ tmp[INET6_CIDRSTRLEN];
X
X- if (ip_family(ip) == AF_INET)
X+ if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6)
X {
X- /* It's an IP V4 address: */
X- /* force display of 32 bits, regardless of masklen... */
X- if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
X+ /* force display of 32/128 bits, regardless of masklen... */
X+ if (inet_net_ntop(ip_family(ip), &ip_v4addr(ip),
X+ (ip_family(ip) == AF_INET ? 32 : 128),
X+ tmp, sizeof(tmp)) == NULL)
X elog(ERROR, "unable to print host (%s)", strerror(errno));
X }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(ip));
X
X /* Suppress /n if present (shouldn't happen now) */
X@@ -421,13 +536,12 @@
X inet *ip = PG_GETARG_INET_P(0);
X text *ret;
X int len;
X- char tmp[sizeof("255.255.255.255/32")];
X+ char tmp[INET6_CIDRSTRLEN];
X
X- if (ip_family(ip) == AF_INET)
X+ if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6)
X {
X- /* It's an IP V4 address: */
X- /* force display of 32 bits, regardless of masklen... */
X- if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
X+ /* force display of 32/128 bits, regardless of masklen... */
X+ if (inet_net_ntop(ip_family(ip), &ip_v4addr(ip), (ip_family(ip) == AF_INET ? 32 : 128), tmp, sizeof(tmp)) == NULL)
X elog(ERROR, "unable to print host (%s)", strerror(errno));
X /* Add /n if not present (which it won't be) */
X if (strchr(tmp, '/') == NULL)
X@@ -437,7 +551,6 @@
X }
X }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(ip));
X
X /* Return string as a text datum */
X@@ -455,23 +568,21 @@
X text *ret;
X char *dst;
X int len;
X- char tmp[sizeof("255.255.255.255/32")];
X+ char tmp[INET6_CIDRSTRLEN];
X
X- if (ip_family(ip) == AF_INET)
X+ if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6)
X {
X- /* It's an IP V4 address: */
X if (ip_type(ip))
X- dst = inet_cidr_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip),
X+ dst = inet_cidr_ntop(ip_family(ip), &ip_v4addr(ip), ip_bits(ip),
X tmp, sizeof(tmp));
X else
X- dst = inet_net_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip),
X+ dst = inet_net_ntop(ip_family(ip), &ip_v4addr(ip), ip_bits(ip),
X tmp, sizeof(tmp));
X
X if (dst == NULL)
X elog(ERROR, "unable to print address (%s)", strerror(errno));
X }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(ip));
X
X /* Return string as a text datum */
X@@ -516,8 +627,19 @@
X
X ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask);
X }
X+ else if (ip_family(ip) == AF_INET6) {
X+ /* It's an IP V6 address: */
X+
X+ /* "There are no broadcast addresses in IPv6, their function being
X+ superseded by multicast addresses." (RFC2373) */
X+ /* I think use of solicited-node address (FF02:0:0:0:0:1:FFXX:XXXX) here is appropriate */
X+ unsigned long mask = 0x00ffffff;
X+ ip_v6addr(dst)[0] = htonl(0xff02);
X+ ip_v6addr(dst)[1] = 0;
X+ ip_v6addr(dst)[2] = htonl(1);
X+ ip_v6addr(dst)[3] = htonl(0xff000000 | (ntohl(ip_v4addr_always(ip)) & mask));
X+ }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(ip));
X
X ip_family(dst) = ip_family(ip);
X@@ -556,8 +678,41 @@
X
X ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask);
X }
X+ else if(ip_family(ip) == AF_INET6) {
X+ /* It's an IP V6 address: */
X+ unsigned long mask = 0xffffffff;
X+
X+ /* Ok, let's do this in 4 steps... */
X+ if(ip_bits(ip) > 96)
X+ {
X+ mask <<= (128 - ip_bits(ip));
X+ ip_v6addr(dst)[0] = htonl(ntohl(ip_v6addr(ip)[0]) & mask);
X+ memset(ip_v6addr(dst) + 1, 0, sizeof(int) * 3);
X+ }
X+ else if(ip_bits(ip) > 64)
X+ {
X+ ip_v6addr(dst)[0] = ip_v6addr(ip)[0];
X+ mask <<= (96 - ip_bits(ip));
X+ ip_v6addr(dst)[1] = htonl(ntohl(ip_v6addr(ip)[1]) & mask);
X+ memset(ip_v6addr(dst) + 2, 0, sizeof(int) * 2);
X+ }
X+ else if(ip_bits(ip) > 32)
X+ {
X+ memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 2);
X+ mask <<= (64 - ip_bits(ip));
X+ ip_v6addr(dst)[2] = htonl(ntohl(ip_v6addr(ip)[2]) & mask);
X+ ip_v6addr(dst)[3] = 0;
X+ }
X+ else if(ip_bits(ip) > 0 )
X+ {
X+ memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 3);
X+ mask <<= (32 - ip_bits(ip));
X+ ip_v6addr(dst)[3] = htonl(ntohl(ip_v6addr(ip)[3]) & mask);
X+ }
X+ else
X+ memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 4);
X+ }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(ip));
X
X ip_family(dst) = ip_family(ip);
X@@ -598,8 +753,44 @@
X
X ip_bits(dst) = 32;
X }
X+ else if (ip_family(ip) == AF_INET6)
X+ {
X+ /* It's an IP V6 address: */
X+ unsigned long mask = 0xffffffff;
X+
X+ /* Ok, let's do this in 4 steps... */
X+ if(ip_bits(ip) > 96)
X+ {
X+ mask <<= (128 - ip_bits(ip));
X+ ip_v6addr(dst)[0] = htonl(mask);
X+ memset(ip_v6addr(dst) + 1, 0, sizeof(int) * 3);
X+ }
X+ else if(ip_bits(ip) > 64)
X+ {
X+ ip_v6addr(dst)[0] = 0xffffffff;
X+ mask <<= (96 - ip_bits(ip));
X+ ip_v6addr(dst)[1] = htonl(mask);
X+ memset(ip_v6addr(dst) + 2, 0, sizeof(int) * 2);
X+ }
X+ else if(ip_bits(ip) > 32)
X+ {
X+ memset(ip_v6addr(dst), 0xff, sizeof(int) * 2);
X+ mask <<= (64 - ip_bits(ip));
X+ ip_v6addr(dst)[2] = htonl(mask);
X+ ip_v6addr(dst)[3] = 0;
X+ }
X+ else if(ip_bits(ip) > 0 )
X+ {
X+ memset(ip_v6addr(dst), 0xff, sizeof(int) * 3);
X+ mask <<= (32 - ip_bits(ip));
X+ ip_v6addr(dst)[3] = htonl(mask);
X+ }
X+ else
X+ memset(ip_v6addr(dst), 0xff, sizeof(int) * 4);
X+
X+ ip_bits(dst) = 128;
X+ }
X else
X- /* Go for an IPV6 address here, before faulting out: */
X elog(ERROR, "unknown address family (%d)", ip_family(ip));
X
X ip_family(dst) = ip_family(ip);
X@@ -661,7 +852,7 @@
X
X
X /*
X- * Bitwise comparison for V4 addresses. Add V6 implementation!
X+ * Bitwise comparison for IP V4 addresses.
X */
X
X static int
X@@ -687,6 +878,34 @@
X }
X
X /*
X+ * Bitwise comparison for IP V6 addresses.
X+ */
X+
X+static int
X+v6bitncmp(unsigned int *a1, unsigned int *a2, int bits)
X+{
X+ unsigned int mask;
X+ unsigned int tmp1, tmp2;
X+ int i;
X+
X+ for( i = 0; bits > 0 && i < 4; i++, bits -= 32 ) {
X+ if( bits > 32 )
X+ mask = 0xffffffff;
X+ else if( bits > 0 )
X+ mask = 0xffffffff << (32 - bits);
X+ else
X+ mask = 0;
X+ tmp1 = ntohl(a1[i]);
X+ tmp2 = ntohl(a2[i]);
X+ if( ( tmp1 & mask ) < ( tmp2 & mask ) )
X+ return -1;
X+ else if( ( tmp1 & mask ) > ( tmp2 & mask ) )
X+ return 1;
X+ }
X+ return 0;
X+}
X+
X+/*
X * Returns true if given address fits fully within the specified bit width.
X */
X static bool
X@@ -706,6 +925,29 @@
X if ((a1 & mask) == a1)
X return true;
X return false;
X+}
X+
X+/*
X+ * Returns true if given address fits fully within the specified bit width.
X+ */
X+static bool
X+v6addressOK(unsigned int *a1, int bits)
X+{
X+ unsigned int tmp1, mask;
X+ int i;
X+
X+ for( i = 0; bits > 0 && i < 4; i++, bits -= 32 ) {
X+ if( bits > 32 )
X+ mask = 0xffffffff;
X+ else if( bits > 0 )
X+ mask = 0xffffffff << (32 - bits);
X+ else
X+ mask = 0;
X+ tmp1 = ntohl(a1[i]);
X+ if( ( tmp1 & mask ) != tmp1 )
X+ return false;
X+ }
X+ return true;
X }
X
X
XIndex: src/include/utils/inet.h
X===================================================================
XRCS file: /projects/cvsroot/pgsql/src/include/utils/inet.h,v
Xretrieving revision 1.10
Xdiff -u -r1.10 inet.h
X--- src/include/utils/inet.h 2001/03/22 04:01:12 1.10
X+++ src/include/utils/inet.h 2001/10/05 08:31:25
X@@ -25,8 +25,8 @@
X unsigned char type;
X union
X {
X- unsigned int ipv4_addr; /* network byte order */
X- /* add IPV6 address type here */
X+ unsigned int ipv4_addr; /* network byte order */
X+ unsigned int ipv6_addr[4]; /* network byte order */
X } addr;
X } inet_struct;
X
END-of-ipv6-patch
echo x - inet_cidr_ntop.c
sed 's/^X//' >inet_cidr_ntop.c << 'END-of-inet_cidr_ntop.c'
X/*
X * Copyright (c) 1998,1999 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic const char isc_rcsid[] = "Id: inet_cidr_ntop.c,v 8.7 2001/09/28 05:19:36 marka Exp $";
Xstatic const char rcsid[] = "$Id:$";
X#endif
X
X/*#include "port_before.h"*/
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/nameser.h>
X#include <arpa/inet.h>
X
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X
X/*#include "port_after.h"*/
X
X#include "postgres.h"
X#include "utils/builtins.h"
X
X#ifdef SPRINTF_CHAR
X# define SPRINTF(x) strlen(sprintf/**/x)
X#else
X# define SPRINTF(x) ((size_t)sprintf x)
X#endif
X
Xstatic char * inet_cidr_ntop_ipv4(const u_char *src, int bits,
X char *dst, size_t size);
Xstatic char * inet_cidr_ntop_ipv6(const u_char *src, int bits,
X char *dst, size_t size);
X
X/*
X * char *
X * inet_cidr_ntop(af, src, bits, dst, size)
X * convert network address from network to presentation format.
X * "src"'s size is determined from its "af".
X * return:
X * pointer to dst, or NULL if an error occurred (check errno).
X * note:
X * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
X * as called for by inet_net_ntop() but it can be a host address with
X * an included netmask.
X * author:
X * Paul Vixie (ISC), October 1998
X */
Xchar *
Xinet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
X switch (af) {
X case AF_INET:
X return (inet_cidr_ntop_ipv4(src, bits, dst, size));
X case AF_INET6:
X return (inet_cidr_ntop_ipv6(src, bits, dst, size));
X default:
X errno = EAFNOSUPPORT;
X return (NULL);
X }
X}
X
Xstatic int
Xdecoct(const u_char *src, int bytes, char *dst, size_t size) {
X char *odst = dst;
X char *t;
X int b;
X
X for (b = 1; b <= bytes; b++) {
X if (size < sizeof "255.")
X return (0);
X t = dst;
X dst += SPRINTF((dst, "%u", *src++));
X if (b != bytes) {
X *dst++ = '.';
X *dst = '\0';
X }
X size -= (size_t)(dst - t);
X }
X return (dst - odst);
X}
X
X/*
X * static char *
X * inet_cidr_ntop_ipv4(src, bits, dst, size)
X * convert IPv4 network address from network to presentation format.
X * "src"'s size is determined from its "af".
X * return:
X * pointer to dst, or NULL if an error occurred (check errno).
X * note:
X * network byte order assumed. this means 192.5.5.240/28 has
X * 0b11110000 in its fourth octet.
X * author:
X * Paul Vixie (ISC), October 1998
X */
Xstatic char *
Xinet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
X char *odst = dst;
X size_t len = 4;
X size_t b;
X size_t bytes;
X
X if ((bits < -1) || (bits > 32)) {
X errno = EINVAL;
X return (NULL);
X }
X
X /* Find number of significant bytes in address. */
X if (bits == -1)
X len = 4;
X else
X for (len = 1, b = 1 ; b < 4; b++)
X if (*(src + b))
X len = b + 1;
X
X /* Format whole octets plus nonzero trailing octets. */
X bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
X if (len > bytes)
X bytes = len;
X b = decoct(src, bytes, dst, size);
X if (b == 0)
X goto emsgsize;
X dst += b;
X size -= b;
X
X if (bits != -1) {
X /* Format CIDR /width. */
X if (size < sizeof "/32")
X goto emsgsize;
X dst += SPRINTF((dst, "/%u", bits));
X }
X
X return (odst);
X
X emsgsize:
X errno = EMSGSIZE;
X return (NULL);
X}
X
Xstatic char *
Xinet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
X /*
X * Note that int32_t and int16_t need only be "at least" large enough
X * to contain a value of the specified size. On some systems, like
X * Crays, there is no such thing as an integer variable with 16 bits.
X * Keep this in mind if you think this function should have been coded
X * to use pointer overlays. All the world's not a VAX.
X */
X char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
X char *tp;
X struct { int base, len; } best, cur;
X u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
X int i;
X
X if ((bits < -1) || (bits > 128)) {
X errno = EINVAL;
X return (NULL);
X }
X
X /*
X * Preprocess:
X * Copy the input (bytewise) array into a wordwise array.
X * Find the longest run of 0x00's in src[] for :: shorthanding.
X */
X memset(words, '\0', sizeof words);
X for (i = 0; i < NS_IN6ADDRSZ; i++)
X words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
X best.base = -1;
X cur.base = -1;
X for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
X if (words[i] == 0) {
X if (cur.base == -1)
X cur.base = i, cur.len = 1;
X else
X cur.len++;
X } else {
X if (cur.base != -1) {
X if (best.base == -1 || cur.len > best.len)
X best = cur;
X cur.base = -1;
X }
X }
X }
X if (cur.base != -1) {
X if (best.base == -1 || cur.len > best.len)
X best = cur;
X }
X if (best.base != -1 && best.len < 2)
X best.base = -1;
X
X /*
X * Format the result.
X */
X tp = tmp;
X for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
X /* Are we inside the best run of 0x00's? */
X if (best.base != -1 && i >= best.base &&
X i < (best.base + best.len)) {
X if (i == best.base)
X *tp++ = ':';
X continue;
X }
X /* Are we following an initial run of 0x00s or any real hex? */
X if (i != 0)
X *tp++ = ':';
X /* Is this address an encapsulated IPv4? */
X if (i == 6 && best.base == 0 && (best.len == 6 ||
X (best.len == 7 && words[7] != 0x0001) ||
X (best.len == 5 && words[5] == 0xffff))) {
X int n;
X
X if (src[15] || bits == -1 || bits > 120)
X n = 4;
X else if (src[14] || bits > 112)
X n = 3;
X else
X n = 2;
X n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
X if (n == 0) {
X errno = EMSGSIZE;
X return (NULL);
X }
X tp += strlen(tp);
X break;
X }
X tp += SPRINTF((tp, "%x", words[i]));
X }
X
X /* Was it a trailing run of 0x00's? */
X if (best.base != -1 && (best.base + best.len) ==
X (NS_IN6ADDRSZ / NS_INT16SZ))
X *tp++ = ':';
X *tp = '\0';
X
X if (bits != -1)
X tp += SPRINTF((tp, "/%u", bits));
X
X /*
X * Check for overflow, copy, and we're done.
X */
X if ((size_t)(tp - tmp) > size) {
X errno = EMSGSIZE;
X return (NULL);
X }
X strcpy(dst, tmp);
X return (dst);
X}
END-of-inet_cidr_ntop.c
echo x - inet_cidr_pton.c
sed 's/^X//' >inet_cidr_pton.c << 'END-of-inet_cidr_pton.c'
X/*
X * Copyright (c) 1998,1999 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic const char isc_rcsid[] = "Id: inet_cidr_pton.c,v 8.7 2001/09/28 04:21:28 marka Exp $";
Xstatic const char rcsid[] = "$Id:$";
X#endif
X
X/*#include "port_before.h"*/
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/nameser.h>
X#include <arpa/inet.h>
X
X/*#include <isc/assertions.h>*/
X#include <assert.h>
X#include <ctype.h>
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X
X/*#include "port_after.h"*/
X
X#include "postgres.h"
X#include "utils/builtins.h"
X
X#ifdef SPRINTF_CHAR
X# define SPRINTF(x) strlen(sprintf/**/x)
X#else
X# define SPRINTF(x) ((size_t)sprintf x)
X#endif
X
Xstatic int inet_cidr_pton_ipv4(const char *src, u_char *dst,
X int *bits, int ipv6);
Xstatic int inet_cidr_pton_ipv6(const char *src, u_char *dst,
X int *bits);
X
Xstatic int getbits(const char *, int ipv6);
X
X/*
X * int
X * inet_cidr_pton(af, src, dst, *bits)
X * convert network address from presentation to network format.
X * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
X * "dst" is assumed large enough for its "af". "bits" is set to the
X * /CIDR prefix length, which can have defaults (like /32 for IPv4).
X * return:
X * -1 if an error occurred (inspect errno; ENOENT means bad format).
X * 0 if successful conversion occurred.
X * note:
X * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
X * as called for by inet_net_pton() but it can be a host address with
X * an included netmask.
X * author:
X * Paul Vixie (ISC), October 1998
X */
Xint
Xinet_cidr_pton(int af, const char *src, void *dst, int *bits) {
X switch (af) {
X case AF_INET:
X return (inet_cidr_pton_ipv4(src, dst, bits, 0));
X case AF_INET6:
X return (inet_cidr_pton_ipv6(src, dst, bits));
X default:
X errno = EAFNOSUPPORT;
X return (-1);
X }
X}
X
Xstatic const char digits[] = "0123456789";
X
Xstatic int
Xinet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
X const u_char *odst = dst;
X int n, ch, tmp, bits;
X size_t size = 4;
X
X /* Get the mantissa. */
X while (ch = *src++, (isascii(ch) && isdigit(ch))) {
X tmp = 0;
X do {
X n = strchr(digits, ch) - digits;
X assert(n >= 0 && n <= 9);
X tmp *= 10;
X tmp += n;
X if (tmp > 255)
X goto enoent;
X } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
X if (size-- == 0)
X goto emsgsize;
X *dst++ = (u_char) tmp;
X if (ch == '\0' || ch == '/')
X break;
X if (ch != '.')
X goto enoent;
X }
X
X /* Get the prefix length if any. */
X bits = -1;
X if (ch == '/' && dst > odst) {
X bits = getbits(src, ipv6);
X if (bits == -2)
X goto enoent;
X } else if (ch != '\0')
X goto enoent;
X
X /* Prefix length can default to /32 only if all four octets spec'd. */
X if (bits == -1) {
X if (dst - odst == 4)
X bits = ipv6 ? 128 : 32;
X else
X goto enoent;
X }
X
X /* If nothing was written to the destination, we found no address. */
X if (dst == odst)
X goto enoent;
X
X /* If prefix length overspecifies mantissa, life is bad. */
X if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
X goto enoent;
X
X /* Extend address to four octets. */
X while (size-- > 0)
X *dst++ = 0;
X
X *pbits = bits;
X return (0);
X
X enoent:
X errno = ENOENT;
X return (-1);
X
X emsgsize:
X errno = EMSGSIZE;
X return (-1);
X}
X
Xstatic int
Xinet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
X static const char xdigits_l[] = "0123456789abcdef",
X xdigits_u[] = "0123456789ABCDEF";
X u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
X const char *xdigits, *curtok;
X int ch, saw_xdigit;
X u_int val;
X int bits;
X
X memset((tp = tmp), '\0', NS_IN6ADDRSZ);
X endp = tp + NS_IN6ADDRSZ;
X colonp = NULL;
X /* Leading :: requires some special handling. */
X if (*src == ':')
X if (*++src != ':')
X return (0);
X curtok = src;
X saw_xdigit = 0;
X val = 0;
X bits = -1;
X while ((ch = *src++) != '\0') {
X const char *pch;
X
X if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
X pch = strchr((xdigits = xdigits_u), ch);
X if (pch != NULL) {
X val <<= 4;
X val |= (pch - xdigits);
X if (val > 0xffff)
X return (0);
X saw_xdigit = 1;
X continue;
X }
X if (ch == ':') {
X curtok = src;
X if (!saw_xdigit) {
X if (colonp)
X return (0);
X colonp = tp;
X continue;
X } else if (*src == '\0') {
X return (0);
X }
X if (tp + NS_INT16SZ > endp)
X return (0);
X *tp++ = (u_char) (val >> 8) & 0xff;
X *tp++ = (u_char) val & 0xff;
X saw_xdigit = 0;
X val = 0;
X continue;
X }
X if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
X inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
X tp += NS_INADDRSZ;
X saw_xdigit = 0;
X break; /* '\0' was seen by inet_pton4(). */
X }
X if (ch == '/') {
X bits = getbits(src, 1);
X if (bits == -2)
X goto enoent;
X break;
X }
X goto enoent;
X }
X if (saw_xdigit) {
X if (tp + NS_INT16SZ > endp)
X goto emsgsize;
X *tp++ = (u_char) (val >> 8) & 0xff;
X *tp++ = (u_char) val & 0xff;
X }
X if (colonp != NULL) {
X /*
X * Since some memmove()'s erroneously fail to handle
X * overlapping regions, we'll do the shift by hand.
X */
X const int n = tp - colonp;
X int i;
X
X if (tp == endp)
X goto enoent;
X for (i = 1; i <= n; i++) {
X endp[- i] = colonp[n - i];
X colonp[n - i] = 0;
X }
X tp = endp;
X }
X
X memcpy(dst, tmp, NS_IN6ADDRSZ);
X
X *pbits = bits;
X return (0);
X
X enoent:
X errno = ENOENT;
X return (-1);
X
X emsgsize:
X errno = EMSGSIZE;
X return (-1);
X}
X
Xint
Xgetbits(const char *src, int ipv6) {
X int bits = 0;
X char *cp, ch;
X
X if (*src == '\0') /* syntax */
X return (-2);
X do {
X ch = *src++;
X cp = strchr(digits, ch);
X if (cp == NULL) /* syntax */
X return (-2);
X bits *= 10;
X bits += cp - digits;
X if (bits == 0 && *src != '\0') /* no leading zeros */
X return (-2);
X if (bits > (ipv6 ? 128 : 32)) /* range error */
X return (-2);
X } while (*src != '\0');
X
X return (bits);
X}
END-of-inet_cidr_pton.c
exit
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Seems this will have to wait for 7.3.
seems so. i'm going to redo network.c.
On Fri, 12 Oct 2001, Bruce Momjian wrote:
Seems this will have to wait for 7.3.
Why?
and, to be a bit more riendly to those of us stuck on 56k lines, could you
avoid re-sending, repeatedly, large patch files?
Seems this will have to wait for 7.3.
Why?
because i didn't get it fixed in time.
and, to be a bit more riendly to those of us stuck on 56k lines, could you
avoid re-sending, repeatedly, large patch files?
sorry.
"Marc G. Fournier" <scrappy@hub.org> writes:
On Fri, 12 Oct 2001, Bruce Momjian wrote:
Seems this will have to wait for 7.3.
Why?
Because Paul's not yet responded to my gripes of (now) 10 days ago.
The patch as given reverts the I/O behavior of the inet datatypes
to what it originally was, rather than the compromise behavior that
was hammered out at great length before 7.1. (I'd give a link to
those discussions if fts.postgresql.org were working :-()
and, to be a bit more riendly to those of us stuck on 56k lines, could you
avoid re-sending, repeatedly, large patch files?
I agree on that one ...
regards, tom lane