Re: IPv6 Support for INET/CIDR types. - Mailing list pgsql-patches
From | Paul A Vixie |
---|---|
Subject | Re: IPv6 Support for INET/CIDR types. |
Date | |
Msg-id | 200110050838.f958crH48152@as.vix.com Whole thread Raw |
In response to | Re: IPv6 Support for INET/CIDR types. (Bruce Momjian <pgman@candle.pha.pa.us>) |
Responses |
Re: IPv6 Support for INET/CIDR types.
Re: IPv6 Support for INET/CIDR types. Re: IPv6 Support for INET/CIDR types. |
List | pgsql-patches |
> What is that status of this patch? We are near beta. below please find a shar file containing: the latest patch to inet.h and network.c from vadim with a few tiny changes to the comments from me; a patch bringing inet_net_pton.c and inet_net_ntop.c up to date with respect to isc's changes to those files in the time since INET/CIDR were added, plus isc's corrected version of vadim's ipv6 changes to those files; the new files inet_cidr_pton.c and inet_cidr_ntop.c, containing isc's fixed version of vadim's ipv6 support for this api. a patch to src/backend/utils/adt/Makefile to compile the above files. # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # ipv6-patch # inet_cidr_ntop.c # inet_cidr_pton.c # echo x - ipv6-patch sed 's/^X//' >ipv6-patch << 'END-of-ipv6-patch' XIndex: src/backend/utils/adt/Makefile X=================================================================== XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/Makefile,v Xretrieving revision 1.51 Xdiff -u -r1.51 Makefile X--- src/backend/utils/adt/Makefile 2001/10/04 04:13:40 1.51 X+++ src/backend/utils/adt/Makefile 2001/10/05 08:31:17 X@@ -22,7 +22,9 @@ X oid.o oracle_compat.o \ X regexp.o regproc.o ruleutils.o selfuncs.o sets.o \ X tid.o timestamp.o varbit.o varchar.o varlena.o version.o \ X- network.o mac.o inet_net_ntop.o inet_net_pton.o \ X+ network.o mac.o \ X+ inet_net_ntop.o inet_net_pton.o \ X+ inet_cidr_ntop.o inet_cidr_pton.o \ X ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \ X ascii.o quote.o pgstatfuncs.o encode.o X XIndex: src/backend/utils/adt/inet_net_ntop.c X=================================================================== XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/inet_net_ntop.c,v Xretrieving revision 1.10 Xdiff -u -r1.10 inet_net_ntop.c X--- src/backend/utils/adt/inet_net_ntop.c 2001/03/22 03:59:51 1.10 X+++ src/backend/utils/adt/inet_net_ntop.c 2001/10/05 08:31:17 X@@ -1,5 +1,5 @@ X /* X- * Copyright (c) 1996 by Internet Software Consortium. X+ * Copyright (c) 1996,1999 by Internet Software Consortium. X * X * Permission to use, copy, modify, and distribute this software for any X * purpose with or without fee is hereby granted, provided that the above X@@ -16,34 +16,41 @@ X */ X X #if defined(LIBC_SCCS) && !defined(lint) X-static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.10 2001/03/22 03:59:51 momjian Exp $"; X- X+static const char isc_rcsid[] = "Id: inet_net_ntop.c,v 1.8 2001/09/27 15:08:36 marka Exp $"; X+static const char rcsid[] = "$Id:$"; X #endif X X+/*#include "port_before.h"*/ X+ X #include <sys/types.h> X #include <sys/socket.h> X #include <netinet/in.h> X #include <arpa/inet.h> X X #include <errno.h> X+#include <stdio.h> X+#include <string.h> X+#include <stdlib.h> X+ X+/*#include "port_after.h"*/ X X #include "postgres.h" X #include "utils/builtins.h" X X #ifdef SPRINTF_CHAR X-#define SPRINTF(x) strlen(sprintf/**/x) X+# define SPRINTF(x) strlen(sprintf/**/x) X #else X-#define SPRINTF(x) ((size_t)sprintf x) X+# define SPRINTF(x) ((size_t)sprintf x) X #endif X X-static char *inet_net_ntop_ipv4(const u_char *src, int bits, X- char *dst, size_t size); X-static char *inet_cidr_ntop_ipv4(const u_char *src, int bits, X+static char * inet_net_ntop_ipv4(const u_char *src, int bits, X char *dst, size_t size); X+static char * inet_net_ntop_ipv6(const u_char *src, int bits, X+ char *dst, size_t size); X X /* X * char * X- * inet_cidr_ntop(af, src, bits, dst, size) X+ * inet_net_ntop(af, src, bits, dst, size) X * convert network number from network to presentation format. X * generates CIDR style result always. X * return: X@@ -52,167 +59,221 @@ X * Paul Vixie (ISC), July 1996 X */ X char * X-inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) X+inet_net_ntop(af, src, bits, dst, size) X+ int af; X+ const void *src; X+ int bits; X+ char *dst; X+ size_t size; X { X- switch (af) X- { X- case AF_INET: X- return (inet_cidr_ntop_ipv4(src, bits, dst, size)); X- default: X- errno = EAFNOSUPPORT; X- return (NULL); X+ switch (af) { X+ case AF_INET: X+ return (inet_net_ntop_ipv4(src, bits, dst, size)); X+ case AF_INET6: X+ return (inet_net_ntop_ipv6(src, bits, dst, size)); X+ default: X+ errno = EAFNOSUPPORT; X+ return (NULL); X } X } X X- X /* X * static char * X- * inet_cidr_ntop_ipv4(src, bits, dst, size) X+ * inet_net_ntop_ipv4(src, bits, dst, size) X * convert IPv4 network number from network to presentation format. X * generates CIDR style result always. X * return: X * pointer to dst, or NULL if an error occurred (check errno). X * note: X * network byte order assumed. this means 192.5.5.240/28 has X- * 0x11110000 in its fourth octet. X+ * 0b11110000 in its fourth octet. X * author: X * Paul Vixie (ISC), July 1996 X */ X static char * X-inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) X+inet_net_ntop_ipv4(src, bits, dst, size) X+ const u_char *src; X+ int bits; X+ char *dst; X+ size_t size; X { X- char *odst = dst; X- char *t; X- u_int m; X- int b; X+ char *odst = dst; X+ char *t; X+ u_int m; X+ int b; X X- if (bits < 0 || bits > 32) X- { X+ if (bits < 0 || bits > 32) { X errno = EINVAL; X return (NULL); X } X- if (bits == 0) X- { X+ X+ if (bits == 0) { X if (size < sizeof "0") X goto emsgsize; X *dst++ = '0'; X+ size--; X *dst = '\0'; X } X X /* Format whole octets. */ X- for (b = bits / 8; b > 0; b--) X- { X- if (size < sizeof ".255") X+ for (b = bits / 8; b > 0; b--) { X+ if (size <= sizeof "255.") X goto emsgsize; X t = dst; X- if (dst != odst) X- *dst++ = '.'; X dst += SPRINTF((dst, "%u", *src++)); X- size -= (size_t) (dst - t); X+ if (b > 1) { X+ *dst++ = '.'; X+ *dst = '\0'; X+ } X+ size -= (size_t)(dst - t); X } X X /* Format partial octet. */ X b = bits % 8; X- if (b > 0) X- { X- if (size < sizeof ".255") X+ if (b > 0) { X+ if (size <= sizeof ".255") X goto emsgsize; X t = dst; X if (dst != odst) X *dst++ = '.'; X m = ((1 << b) - 1) << (8 - b); X dst += SPRINTF((dst, "%u", *src & m)); X- size -= (size_t) (dst - t); X+ size -= (size_t)(dst - t); X } X X /* Format CIDR /width. */ X- if (size < sizeof "/32") X+ if (size <= sizeof "/32") X goto emsgsize; X dst += SPRINTF((dst, "/%u", bits)); X- X return (odst); X X-emsgsize: X+ emsgsize: X errno = EMSGSIZE; X return (NULL); X } X X- X /* X- * char * X- * inet_net_ntop(af, src, bits, dst, size) X- * convert host/network address from network to presentation format. X- * "src"'s size is determined from its "af". X- * return: X- * pointer to dst, or NULL if an error occurred (check errno). X- * note: X- * 192.5.5.1/28 has a nonzero host part, which means it isn't a network X- * as called for by inet_net_pton() but it can be a host address with X- * an included netmask. X- * author: X- * Paul Vixie (ISC), October 1998 X- */ X-char * X-inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) X-{ X- switch (af) X- { X- case AF_INET: X- return (inet_net_ntop_ipv4(src, bits, dst, size)); X- default: X- errno = EAFNOSUPPORT; X- return (NULL); X- } X-} X- X-/* X * static char * X- * inet_net_ntop_ipv4(src, bits, dst, size) X- * convert IPv4 network address from network to presentation format. X- * "src"'s size is determined from its "af". X+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size) X+ * convert IPv6 network number from network to presentation format. X+ * generates CIDR style result always. Picks the shortest representation X+ * unless the IP is really IPv4. X+ * always prints specified number of bits (bits). X * return: X * pointer to dst, or NULL if an error occurred (check errno). X * note: X * network byte order assumed. this means 192.5.5.240/28 has X- * 0b11110000 in its fourth octet. X+ * 0x11110000 in its fourth octet. X * author: X- * Paul Vixie (ISC), October 1998 X+ * Vadim Kogan (UCB), June 2001 X+ * Original version (IPv4) by Paul Vixie (ISC), July 1996 X */ X+ X static char * X-inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) X-{ X- char *odst = dst; X- char *t; X- int len = 4; X- int b; X+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { X+ u_int m; X+ int b; X+ int p; X+ int zero_s, zero_l, tmp_zero_s, tmp_zero_l; X+ int i; X+ int is_ipv4 = 0; X+ unsigned char inbuf[16]; X+ char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; X+ char *cp; X+ int words; X+ u_char *s; X X- if (bits < 0 || bits > 32) X- { X+ if (bits < 0 || bits > 128) { X errno = EINVAL; X return (NULL); X } X X- /* Always format all four octets, regardless of mask length. */ X- for (b = len; b > 0; b--) X- { X- if (size < sizeof ".255") X- goto emsgsize; X- t = dst; X- if (dst != odst) X- *dst++ = '.'; X- dst += SPRINTF((dst, "%u", *src++)); X- size -= (size_t) (dst - t); X- } X+ cp = outbuf; X X- /* don't print masklen if 32 bits */ X- if (bits != 32) X- { X- if (size < sizeof "/32") X- goto emsgsize; X- dst += SPRINTF((dst, "/%u", bits)); X+ if (bits == 0) { X+ *cp++ = ':'; X+ *cp++ = ':'; X+ *cp = '\0'; X+ } else { X+ /* Copy src to private buffer. Zero host part. */ X+ p = (bits + 7) / 8; X+ memcpy(inbuf, src, p); X+ memset(inbuf + p, 0, 16 - p); X+ b = bits % 8; X+ if (b != 0) { X+ m = ~0 << (8 - b); X+ inbuf[p-1] &= m; X+ } X+ X+ s = inbuf; X+ X+ /* how many words need to be displayed in output */ X+ words = (bits + 15) / 16; X+ if (words == 1) X+ words = 2; X+ X+ /* Find the longest substring of zero's */ X+ zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0; X+ for (i = 0; i < (words * 2); i += 2) { X+ if ((s[i] | s[i+1]) == 0) { X+ if (tmp_zero_l == 0) X+ tmp_zero_s = i / 2; X+ tmp_zero_l++; X+ } else { X+ if (tmp_zero_l && zero_l < tmp_zero_l) { X+ zero_s = tmp_zero_s; X+ zero_l = tmp_zero_l; X+ tmp_zero_l = 0; X+ } X+ } X+ } X+ X+ if (tmp_zero_l && zero_l < tmp_zero_l) { X+ zero_s = tmp_zero_s; X+ zero_l = tmp_zero_l; X+ } X+ X+ if (zero_l != words && zero_s == 0 && ((zero_l == 6) || X+ ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) || X+ ((zero_l == 7 && s[14] != 0 && s[15] != 1))))) X+ is_ipv4 = 1; X+ X+ /* Format whole words. */ X+ for (p = 0; p < words; p++) { X+ if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) { X+ /* Time to skip some zeros */ X+ if (p == zero_s) X+ *cp++ = ':'; X+ if (p == words - 1) X+ *cp++ = ':'; X+ s++; X+ s++; X+ continue; X+ } X+ X+ if (is_ipv4 && p > 5 ) { X+ *cp++ = (p == 6) ? ':' : '.'; X+ cp += SPRINTF((cp, "%u", *s++)); X+ /* we can potentially drop the last octet */ X+ if (p != 7 || bits > 120) { X+ *cp++ = '.'; X+ cp += SPRINTF((cp, "%u", *s++)); X+ } X+ } else { X+ if (cp != outbuf) X+ *cp++ = ':'; X+ cp += SPRINTF((cp, "%x", *s * 256 + s[1])); X+ s += 2; X+ } X+ } X } X- X- return (odst); X+ /* Format CIDR /width. */ X+ SPRINTF((cp, "/%u", bits)); X+ if (strlen(outbuf) + 1 > size) X+ goto emsgsize; X+ strcpy(dst, outbuf); X+ X+ return (dst); X X emsgsize: X errno = EMSGSIZE; XIndex: src/backend/utils/adt/inet_net_pton.c X=================================================================== XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/inet_net_pton.c,v Xretrieving revision 1.12 Xdiff -u -r1.12 inet_net_pton.c X--- src/backend/utils/adt/inet_net_pton.c 2000/12/03 20:45:36 1.12 X+++ src/backend/utils/adt/inet_net_pton.c 2001/10/05 08:31:17 X@@ -1,5 +1,5 @@ X /* X- * Copyright (c) 1996 by Internet Software Consortium. X+ * Copyright (c) 1996,1999 by Internet Software Consortium. X * X * Permission to use, copy, modify, and distribute this software for any X * purpose with or without fee is hereby granted, provided that the above X@@ -16,67 +16,40 @@ X */ X X #if defined(LIBC_SCCS) && !defined(lint) X-static const char rcsid[] = "$Id: inet_net_pton.c,v 1.12 2000/12/03 20:45:36 tgl Exp $"; X- X+static const char isc_rcsid[] = "Id: inet_net_pton.c,v 1.13 2001/09/27 15:08:38 marka Exp $"; X+static const char rcsid[] = "$Id:$"; X #endif X X+/*#include "port_before.h"*/ X+ X #include <sys/types.h> X #include <sys/socket.h> X #include <netinet/in.h> X+#include <arpa/nameser.h> X #include <arpa/inet.h> X X+/*#include <isc/assertions.h>*/ X #include <assert.h> X #include <ctype.h> X #include <errno.h> X+#include <stdio.h> X+#include <string.h> X+#include <stdlib.h> X X+/*#include "port_after.h"*/ X+ X #include "postgres.h" X #include "utils/builtins.h" X X #ifdef SPRINTF_CHAR X-#define SPRINTF(x) strlen(sprintf/**/x) X+# define SPRINTF(x) strlen(sprintf/**/x) X #else X-#define SPRINTF(x) ((size_t)sprintf x) X+# define SPRINTF(x) ((size_t)sprintf x) X #endif X X-static int inet_net_pton_ipv4(const char *src, u_char *dst); X-static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size); X- X /* X * static int X- * inet_net_pton(af, src, dst, size) X- * convert network number from presentation to network format. X- * accepts hex octets, hex strings, decimal octets, and /CIDR. X- * "size" is in bytes and describes "dst". X- * return: X- * number of bits, either imputed classfully or specified with /CIDR, X- * or -1 if some failure occurred (check errno). ENOENT means it was X- * not a valid network specification. X- * author: X- * Paul Vixie (ISC), June 1996 X- * X- * Changes: X- * I added the inet_cidr_pton function (also from Paul) and changed X- * the names to reflect their current use. X- * X- */ X-int X-inet_net_pton(int af, const char *src, void *dst, size_t size) X-{ X- switch (af) X- { X- case AF_INET: X- return size == -1 ? X- inet_net_pton_ipv4(src, dst) : X- inet_cidr_pton_ipv4(src, dst, size); X- default: X- errno = EAFNOSUPPORT; X- return (-1); X- } X-} X- X-/* X- * static int X- * inet_cidr_pton_ipv4(src, dst, size) X+ * inet_net_pton_ipv4(src, dst, size) X * convert IPv4 network number from presentation to network format. X * accepts hex octets, hex strings, decimal octets, and /CIDR. X * "size" is in bytes and describes "dst". X@@ -86,66 +59,52 @@ X * not an IPv4 network specification. X * note: X * network byte order assumed. this means 192.5.5.240/28 has X- * 0x11110000 in its fourth octet. X+ * 0b11110000 in its fourth octet. X * author: X * Paul Vixie (ISC), June 1996 X */ X static int X-inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size) X-{ X- static const char X- xdigits[] = "0123456789abcdef", X- digits[] = "0123456789"; X- int n, X- ch, X- tmp, X- dirty, X- bits; X+inet_net_pton_ipv4( const char *src, u_char *dst, size_t size) { X+ static const char xdigits[] = "0123456789abcdef"; X+ static const char digits[] = "0123456789"; X+ int n, ch, tmp = 0, dirty, bits; X const u_char *odst = dst; X X ch = *src++; X if (ch == '0' && (src[0] == 'x' || src[0] == 'X') X- && isxdigit((unsigned char) src[1])) X- { X+ && isascii((unsigned char)(src[1])) X+ && isxdigit((unsigned char)(src[1]))) { X /* Hexadecimal: Eat nybble string. */ X if (size <= 0) X goto emsgsize; X dirty = 0; X- tmp = 0; X- src++; /* skip x or X. */ X- while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch)) X- { X- if (isupper((unsigned char) ch)) X- ch = tolower((unsigned char) ch); X+ src++; /* skip x or X. */ X+ while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) { X+ if (isupper(ch)) X+ ch = tolower(ch); X n = strchr(xdigits, ch) - xdigits; X assert(n >= 0 && n <= 15); X if (dirty == 0) X tmp = n; X else X tmp = (tmp << 4) | n; X- if (++dirty == 2) X- { X+ if (++dirty == 2) { X if (size-- <= 0) X goto emsgsize; X *dst++ = (u_char) tmp; X dirty = 0; X } X } X- if (dirty) X- { /* Odd trailing nybble? */ X+ if (dirty) { /* Odd trailing nybble? */ X if (size-- <= 0) X goto emsgsize; X *dst++ = (u_char) (tmp << 4); X } X- } X- else if (isdigit((unsigned char) ch)) X- { X+ } else if (isascii(ch) && isdigit(ch)) { X /* Decimal: eat dotted digit string. */ X- for (;;) X- { X+ for (;;) { X tmp = 0; X- do X- { X+ do { X n = strchr(digits, ch) - digits; X assert(n >= 0 && n <= 9); X tmp *= 10; X@@ -153,7 +112,7 @@ X if (tmp > 255) X goto enoent; X } while ((ch = *src++) != '\0' && X- isdigit((unsigned char) ch)); X+ isascii(ch) && isdigit(ch)); X if (size-- <= 0) X goto emsgsize; X *dst++ = (u_char) tmp; X@@ -162,26 +121,24 @@ X if (ch != '.') X goto enoent; X ch = *src++; X- if (!isdigit((unsigned char) ch)) X+ if (!isascii(ch) || !isdigit(ch)) X goto enoent; X } X- } X- else X+ } else X goto enoent; X X bits = -1; X- if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst) X- { X+ if (ch == '/' && isascii((unsigned char)(src[0])) && X+ isdigit((unsigned char)(src[0])) && dst > odst) { X /* CIDR width specifier. Nothing can follow it. */ X- ch = *src++; /* Skip over the /. */ X+ ch = *src++; /* Skip over the /. */ X bits = 0; X- do X- { X+ do { X n = strchr(digits, ch) - digits; X assert(n >= 0 && n <= 9); X bits *= 10; X bits += n; X- } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch)); X+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); X if (ch != '\0') X goto enoent; X if (bits > 32) X@@ -196,9 +153,8 @@ X if (dst == odst) X goto enoent; X /* If no CIDR spec was given, infer width from net class. */ X- if (bits == -1) X- { X- if (*odst >= 240) /* Class E */ X+ if (bits == -1) { X+ if (*odst >= 240) /* Class E */ X bits = 32; X else if (*odst >= 224) /* Class D */ X bits = 4; X@@ -206,133 +162,243 @@ X bits = 24; X else if (*odst >= 128) /* Class B */ X bits = 16; X- else X-/* Class A */ X+ else /* Class A */ X bits = 8; X /* If imputed mask is narrower than specified octets, widen. */ X if (bits >= 8 && bits < ((dst - odst) * 8)) X bits = (dst - odst) * 8; X } X /* Extend network to cover the actual mask. */ X- while (bits > ((dst - odst) * 8)) X- { X+ while (bits > ((dst - odst) * 8)) { X if (size-- <= 0) X goto emsgsize; X *dst++ = '\0'; X } X return (bits); X X-enoent: X+ enoent: X errno = ENOENT; X return (-1); X X-emsgsize: X+ emsgsize: X errno = EMSGSIZE; X return (-1); X } X X-/* X- * int X- * inet_net_pton(af, src, dst, *bits) X- * convert network address from presentation to network format. X- * accepts inet_pton()'s input for this "af" plus trailing "/CIDR". X- * "dst" is assumed large enough for its "af". "bits" is set to the X- * /CIDR prefix length, which can have defaults (like /32 for IPv4). X- * return: X- * -1 if an error occurred (inspect errno; ENOENT means bad format). X- * 0 if successful conversion occurred. X- * note: X- * 192.5.5.1/28 has a nonzero host part, which means it isn't a network X- * as called for by inet_cidr_pton() but it can be a host address with X- * an included netmask. X- * author: X- * Paul Vixie (ISC), October 1998 X- */ X static int X-inet_net_pton_ipv4(const char *src, u_char *dst) X-{ X+getbits(const char *src, int *bitsp) { X static const char digits[] = "0123456789"; X- const u_char *odst = dst; X- int n, X- ch, X- tmp, X- bits; X- size_t size = 4; X- X- /* Get the mantissa. */ X- while (ch = *src++, isdigit((unsigned char) ch)) X- { X- tmp = 0; X- do X- { X- n = strchr(digits, ch) - digits; X- assert(n >= 0 && n <= 9); X- tmp *= 10; X- tmp += n; X- if (tmp > 255) X- goto enoent; X- } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch)); X- if (size-- == 0) X- goto emsgsize; X- *dst++ = (u_char) tmp; X- if (ch == '\0' || ch == '/') X- break; X- if (ch != '.') X- goto enoent; X+ int n; X+ int val; X+ char ch; X+ X+ val = 0; X+ n = 0; X+ while ((ch = *src++) != '\0') { X+ const char *pch; X+ X+ pch = strchr(digits, ch); X+ if (pch != NULL) { X+ if (n++ != 0 && val == 0) /* no leading zeros */ X+ return (0); X+ val *= 10; X+ val += (pch - digits); X+ if (val > 128) /* range */ X+ return (0); X+ continue; X+ } X+ return (0); X } X+ if (n == 0) X+ return (0); X+ *bitsp = val; X+ return (1); X+} X X- /* Get the prefix length if any. */ X- bits = -1; X- if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst) X- { X- /* CIDR width specifier. Nothing can follow it. */ X- ch = *src++; /* Skip over the /. */ X- bits = 0; X- do X- { X- n = strchr(digits, ch) - digits; X- assert(n >= 0 && n <= 9); X- bits *= 10; X- bits += n; X- } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch)); X- if (ch != '\0') X- goto enoent; X- if (bits > 32) X- goto emsgsize; X+static int X+getv4(const char *src, u_char *dst, int *bitsp) { X+ static const char digits[] = "0123456789"; X+ u_char *odst = dst; X+ int n; X+ u_int val; X+ char ch; X+ X+ val = 0; X+ n = 0; X+ while ((ch = *src++) != '\0') { X+ const char *pch; X+ X+ pch = strchr(digits, ch); X+ if (pch != NULL) { X+ if (n++ != 0 && val == 0) /* no leading zeros */ X+ return (0); X+ val *= 10; X+ val += (pch - digits); X+ if (val > 255) /* range */ X+ return (0); X+ continue; X+ } X+ if (ch == '.' || ch == '/') { X+ if (dst - odst > 3) /* too many octets? */ X+ return (0); X+ *dst++ = val; X+ if (ch == '/') X+ return (getbits(src, bitsp)); X+ val = 0; X+ n = 0; X+ continue; X+ } X+ return (0); X } X+ if (n == 0) X+ return (0); X+ if (dst - odst > 3) /* too many octets? */ X+ return (0); X+ *dst++ = val; X+ return (1); X+} X X- /* Firey death and destruction unless we prefetched EOS. */ X- if (ch != '\0') X+static int X+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) { X+ static const char xdigits_l[] = "0123456789abcdef", X+ xdigits_u[] = "0123456789ABCDEF"; X+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; X+ const char *xdigits, *curtok; X+ int ch, saw_xdigit; X+ u_int val; X+ int digits; X+ int bits; X+ size_t bytes; X+ int words; X+ int ipv4; X+ X+ memset((tp = tmp), '\0', NS_IN6ADDRSZ); X+ endp = tp + NS_IN6ADDRSZ; X+ colonp = NULL; X+ /* Leading :: requires some special handling. */ X+ if (*src == ':') X+ if (*++src != ':') X+ goto enoent; X+ curtok = src; X+ saw_xdigit = 0; X+ val = 0; X+ digits = 0; X+ bits = -1; X+ ipv4 = 0; X+ while ((ch = *src++) != '\0') { X+ const char *pch; X+ X+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) X+ pch = strchr((xdigits = xdigits_u), ch); X+ if (pch != NULL) { X+ val <<= 4; X+ val |= (pch - xdigits); X+ if (++digits > 4) X+ goto enoent; X+ saw_xdigit = 1; X+ continue; X+ } X+ if (ch == ':') { X+ curtok = src; X+ if (!saw_xdigit) { X+ if (colonp) X+ goto enoent; X+ colonp = tp; X+ continue; X+ } else if (*src == '\0') X+ goto enoent; X+ if (tp + NS_INT16SZ > endp) X+ return (0); X+ *tp++ = (u_char) (val >> 8) & 0xff; X+ *tp++ = (u_char) val & 0xff; X+ saw_xdigit = 0; X+ digits = 0; X+ val = 0; X+ continue; X+ } X+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && X+ getv4(curtok, tp, &bits) > 0) { X+ tp += NS_INADDRSZ; X+ saw_xdigit = 0; X+ ipv4 = 1; X+ break; /* '\0' was seen by inet_pton4(). */ X+ } X+ if (ch == '/' && getbits(src, &bits) > 0) X+ break; X goto enoent; X- X- /* Prefix length can default to /32 only if all four octets spec'd. */ X- if (bits == -1) X- { X- if (dst - odst == 4) X- bits = 32; X- else X+ } X+ if (saw_xdigit) { X+ if (tp + NS_INT16SZ > endp) X goto enoent; X+ *tp++ = (u_char) (val >> 8) & 0xff; X+ *tp++ = (u_char) val & 0xff; X } X+ if (bits == -1) X+ bits = 128; X X- /* If nothing was written to the destination, we found no address. */ X- if (dst == odst) X- goto enoent; X+ words = (bits + 15) / 16; X+ if (words < 2) X+ words = 2; X+ if (ipv4) X+ words = 8; X+ endp = tmp + 2 * words; X+ X+ if (colonp != NULL) { X+ /* X+ * Since some memmove()'s erroneously fail to handle X+ * overlapping regions, we'll do the shift by hand. X+ */ X+ const int n = tp - colonp; X+ int i; X X- /* If prefix length overspecifies mantissa, life is bad. */ X- if ((bits / 8) > (dst - odst)) X+ if (tp == endp) X+ goto enoent; X+ for (i = 1; i <= n; i++) { X+ endp[- i] = colonp[n - i]; X+ colonp[n - i] = 0; X+ } X+ tp = endp; X+ } X+ if (tp != endp) X goto enoent; X- X- /* Extend address to four octets. */ X- while (size-- > 0) X- *dst++ = 0; X X- return bits; X+ bytes = (bits + 7) / 8; X+ if (bytes > size) X+ goto emsgsize; X+ memcpy(dst, tmp, bytes); X+ return (bits); X X-enoent: X+ enoent: X errno = ENOENT; X return (-1); X X-emsgsize: X+ emsgsize: X errno = EMSGSIZE; X return (-1); X+} X+ X+/* X+ * int X+ * inet_net_pton(af, src, dst, size) X+ * convert network number from presentation to network format. X+ * accepts hex octets, hex strings, decimal octets, and /CIDR. X+ * "size" is in bytes and describes "dst". X+ * return: X+ * number of bits, either imputed classfully or specified with /CIDR, X+ * or -1 if some failure occurred (check errno). ENOENT means it was X+ * not a valid network specification. X+ * author: X+ * Paul Vixie (ISC), June 1996 X+ */ X+int X+inet_net_pton(int af, const char *src, void *dst, size_t size) { X+ switch (af) { X+ case AF_INET: X+ return (inet_net_pton_ipv4(src, dst, size)); X+ case AF_INET6: X+ return (inet_net_pton_ipv6(src, dst, size)); X+ default: X+ errno = EAFNOSUPPORT; X+ return (-1); X+ } X } XIndex: src/backend/utils/adt/network.c X=================================================================== XRCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/network.c,v Xretrieving revision 1.33 Xdiff -u -r1.33 network.c X--- src/backend/utils/adt/network.c 2001/08/27 20:03:38 1.33 X+++ src/backend/utils/adt/network.c 2001/10/05 08:31:18 X@@ -1,7 +1,5 @@ X /* X- * PostgreSQL type definitions for the INET type. This X- * is for IP V4 CIDR notation, but prepared for V6: just X- * add the necessary bits where the comments indicate. X+ * PostgreSQL type definitions for the INET type. X * X * $Header: /projects/cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.33 2001/08/27 20:03:38 tgl Exp $ X * X@@ -21,17 +19,26 @@ X #include "utils/inet.h" X X X+#ifndef INET6_ADDRSTRLEN X+#define INET6_ADDRSTRLEN 46 X+#endif X+ X+#define INET6_CIDRSTRLEN (INET6_ADDRSTRLEN + 4) X+ X static Datum text_network(text *src, int type); X static int32 network_cmp_internal(inet *a1, inet *a2); X static int v4bitncmp(unsigned long a1, unsigned long a2, int bits); X static bool v4addressOK(unsigned long a1, int bits); X+static int v6bitncmp(unsigned int *a1, unsigned int *a2, int bits); X+static bool v6addressOK(unsigned int *a1, int bits); X X /* X- * Access macros. Add IPV6 support. X+ * Access macros. X */ X X #define ip_addrsize(inetptr) \ X- (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1) X+ (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : \ X+ (((inet_struct *)VARDATA(inetptr))->family == AF_INET6 ? 16 : -1 )) X X #define ip_family(inetptr) \ X (((inet_struct *)VARDATA(inetptr))->family) X@@ -39,12 +46,33 @@ X #define ip_bits(inetptr) \ X (((inet_struct *)VARDATA(inetptr))->bits) X X+#define ip_ipv4bits(inetptr) \ X+ (ip_bits(inetptr) - (ip_family(inetptr) == AF_INET6 ? 96 : 0)) X+ X #define ip_type(inetptr) \ X (((inet_struct *)VARDATA(inetptr))->type) X X #define ip_v4addr(inetptr) \ X (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr) X X+#define ip_v6addr(inetptr) \ X+ (((inet_struct *)VARDATA(inetptr))->addr.ipv6_addr) X+ X+#define ip_v4inv6addr(inetptr) \ X+ (((inet_struct *)VARDATA(inetptr))->addr.ipv6_addr[ 3 ]) X+ X+#define ip_v4addr_always(inetptr) \ X+ (ip_family(inetptr) == AF_INET ? ip_v4addr(inetptr) \ X+ : ip_v4inv6addr(inetptr)) X+ X+#define ip_is_ipv4(inetptr) \ X+ (ip_family(inetptr) == AF_INET || \ X+ (ip_family(inetptr) == AF_INET6 && \ X+ ip_v6addr(inetptr)[0] == 0 && \ X+ ip_v6addr(inetptr)[1] == 0 && \ X+ (ip_v6addr(inetptr)[2] == 0 || \ X+ ntohl(ip_v6addr(inetptr)[2]) == 0xFFFF) )) X+ X /* Common input routine */ X static inet * X network_in(char *src, int type) X@@ -63,17 +91,25 @@ X if ((bits < 0) || (bits > 32)) X { X /* Go for an IPV6 address here, before faulting out: */ X- elog(ERROR, "invalid %s value '%s'", X- type ? "CIDR" : "INET", src); X+ ip_family(dst) = AF_INET6; X+ bits = inet_net_pton(ip_family(dst), src, &ip_v6addr(dst), X+ type ? ip_addrsize(dst) : -1); X+ if ((bits < 0) || (bits > 128)) { X+ elog(ERROR, "invalid %s value '%s'", X+ type ? "CIDR" : "INET", src); X+ } X } X X /* X * Error check: CIDR values must not have any bits set beyond the X- * masklen. XXX this code is not IPV6 ready. X+ * masklen. X */ X if (type) X { X- if (!v4addressOK(ip_v4addr(dst), bits)) X+ if ( X+ !(ip_family(dst) == AF_INET && v4addressOK(ip_v4addr(dst), bits)) && X+ !(ip_family(dst) == AF_INET6 && v6addressOK(ip_v6addr(dst), bits)) X+ ) X elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src); X } X X@@ -111,19 +147,17 @@ X inet_out(PG_FUNCTION_ARGS) X { X inet *src = PG_GETARG_INET_P(0); X- char tmp[sizeof("255.255.255.255/32")]; X+ char tmp[INET6_CIDRSTRLEN]; X char *dst; X int len; X X- if (ip_family(src) == AF_INET) X+ if (ip_family(src) == AF_INET || ip_family(src) == AF_INET6) X { X- /* It's an IP V4 address: */ X- X /* X * Use inet style for both inet and cidr, since we don't want X * abbreviated CIDR style here. X */ X- dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src), X+ dst = inet_net_ntop(ip_family(src), &ip_v4addr(src), ip_bits(src), X tmp, sizeof(tmp)); X if (dst == NULL) X elog(ERROR, "unable to print address (%s)", strerror(errno)); X@@ -135,7 +169,6 @@ X } X } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(src)); X X PG_RETURN_CSTRING(pstrdup(tmp)); X@@ -222,9 +255,55 @@ X return order; X return v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), 32); X } X+ else if (ip_family(a1) == AF_INET6 && ip_family(a2) == AF_INET6) X+ { X+ int order; X+ X+ order = v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), X+ Min(ip_bits(a1), ip_bits(a2))); X+ if (order != 0) X+ return order; X+ order = ((int) ip_bits(a1)) - ((int) ip_bits(a2)); X+ if (order != 0) X+ return order; X+ return v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), 128); X+ } X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2)) X+ { X+ /* Be smart and compare IP V4 with IP V6 */ X+ int order; X+ X+ X+ order = v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), X+ Min(ip_ipv4bits(a1), ip_ipv4bits(a2))); X+ if (order != 0) X+ return order; X+ order = ((int) ip_ipv4bits(a1)) - ((int) ip_ipv4bits(a2)); X+ if (order != 0) X+ return order; X+ return v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), 32); X+ } X else X { X- /* Go for an IPV6 address here, before faulting out: */ X+ elog( DEBUG, "----" ); X+ if( ip_family(a1) == AF_INET ) X+ elog( DEBUG, "Pure IPv4" ); X+ else X+ elog( DEBUG, "0: 0x%X, 1: 0x%X, 2: 0x%X, 3: 0x%X", X+ ip_v6addr(a1)[0], X+ ip_v6addr(a1)[1], X+ ip_v6addr(a1)[2], X+ ip_v6addr(a1)[3] ); X+ X+ if( ip_family(a2) == AF_INET ) X+ elog( DEBUG, "Pure IPv4" ); X+ else X+ elog( DEBUG, "0: 0x%X, 1: 0x%X, 2: 0x%X, 3: 0x%X", X+ ip_v6addr(a2)[0], X+ ip_v6addr(a2)[1], X+ ip_v6addr(a2)[2], X+ ip_v6addr(a2)[3] ); X+ X elog(ERROR, "cannot compare address families %d and %d", X ip_family(a1), ip_family(a2)); X return 0; /* keep compiler quiet */ X@@ -311,9 +390,18 @@ X PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0); X } X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6)) X+ { X+ PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0); X+ } X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2)) X+ { X+ PG_RETURN_BOOL(ip_ipv4bits(a1) > ip_ipv4bits(a2) X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a2)) == 0); X+ } X else X { X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "cannot compare address families %d and %d", X ip_family(a1), ip_family(a2)); X PG_RETURN_BOOL(false); X@@ -331,9 +419,18 @@ X PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0); X } X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6)) X+ { X+ PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0); X+ } X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2)) X+ { X+ PG_RETURN_BOOL(ip_ipv4bits(a1) >= ip_ipv4bits(a2) X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a2)) == 0); X+ } X else X { X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "cannot compare address families %d and %d", X ip_family(a1), ip_family(a2)); X PG_RETURN_BOOL(false); X@@ -351,9 +448,18 @@ X PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0); X } X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6)) X+ { X+ PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0); X+ } X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2)) X+ { X+ PG_RETURN_BOOL(ip_ipv4bits(a1) < ip_ipv4bits(a2) X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a1)) == 0); X+ } X else X { X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "cannot compare address families %d and %d", X ip_family(a1), ip_family(a2)); X PG_RETURN_BOOL(false); X@@ -371,9 +477,18 @@ X PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) X && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0); X } X+ else if ((ip_family(a1) == AF_INET6) && (ip_family(a2) == AF_INET6)) X+ { X+ PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) X+ && v6bitncmp(ip_v6addr(a1), ip_v6addr(a2), ip_bits(a2)) == 0); X+ } X+ else if (ip_is_ipv4(a1) && ip_is_ipv4(a2)) X+ { X+ PG_RETURN_BOOL(ip_ipv4bits(a1) <= ip_ipv4bits(a2) X+ && v4bitncmp(ip_v4addr_always(a1), ip_v4addr_always(a2), ip_ipv4bits(a1)) == 0); X+ } X else X { X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "cannot compare address families %d and %d", X ip_family(a1), ip_family(a2)); X PG_RETURN_BOOL(false); X@@ -390,17 +505,17 @@ X text *ret; X int len; X char *ptr, X- tmp[sizeof("255.255.255.255/32")]; X+ tmp[INET6_CIDRSTRLEN]; X X- if (ip_family(ip) == AF_INET) X+ if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6) X { X- /* It's an IP V4 address: */ X- /* force display of 32 bits, regardless of masklen... */ X- if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL) X+ /* force display of 32/128 bits, regardless of masklen... */ X+ if (inet_net_ntop(ip_family(ip), &ip_v4addr(ip), X+ (ip_family(ip) == AF_INET ? 32 : 128), X+ tmp, sizeof(tmp)) == NULL) X elog(ERROR, "unable to print host (%s)", strerror(errno)); X } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(ip)); X X /* Suppress /n if present (shouldn't happen now) */ X@@ -421,13 +536,12 @@ X inet *ip = PG_GETARG_INET_P(0); X text *ret; X int len; X- char tmp[sizeof("255.255.255.255/32")]; X+ char tmp[INET6_CIDRSTRLEN]; X X- if (ip_family(ip) == AF_INET) X+ if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6) X { X- /* It's an IP V4 address: */ X- /* force display of 32 bits, regardless of masklen... */ X- if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL) X+ /* force display of 32/128 bits, regardless of masklen... */ X+ if (inet_net_ntop(ip_family(ip), &ip_v4addr(ip), (ip_family(ip) == AF_INET ? 32 : 128), tmp, sizeof(tmp)) == NULL) X elog(ERROR, "unable to print host (%s)", strerror(errno)); X /* Add /n if not present (which it won't be) */ X if (strchr(tmp, '/') == NULL) X@@ -437,7 +551,6 @@ X } X } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(ip)); X X /* Return string as a text datum */ X@@ -455,23 +568,21 @@ X text *ret; X char *dst; X int len; X- char tmp[sizeof("255.255.255.255/32")]; X+ char tmp[INET6_CIDRSTRLEN]; X X- if (ip_family(ip) == AF_INET) X+ if (ip_family(ip) == AF_INET || ip_family(ip) == AF_INET6) X { X- /* It's an IP V4 address: */ X if (ip_type(ip)) X- dst = inet_cidr_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip), X+ dst = inet_cidr_ntop(ip_family(ip), &ip_v4addr(ip), ip_bits(ip), X tmp, sizeof(tmp)); X else X- dst = inet_net_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip), X+ dst = inet_net_ntop(ip_family(ip), &ip_v4addr(ip), ip_bits(ip), X tmp, sizeof(tmp)); X X if (dst == NULL) X elog(ERROR, "unable to print address (%s)", strerror(errno)); X } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(ip)); X X /* Return string as a text datum */ X@@ -516,8 +627,19 @@ X X ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask); X } X+ else if (ip_family(ip) == AF_INET6) { X+ /* It's an IP V6 address: */ X+ X+ /* "There are no broadcast addresses in IPv6, their function being X+ superseded by multicast addresses." (RFC2373) */ X+ /* I think use of solicited-node address (FF02:0:0:0:0:1:FFXX:XXXX) here is appropriate */ X+ unsigned long mask = 0x00ffffff; X+ ip_v6addr(dst)[0] = htonl(0xff02); X+ ip_v6addr(dst)[1] = 0; X+ ip_v6addr(dst)[2] = htonl(1); X+ ip_v6addr(dst)[3] = htonl(0xff000000 | (ntohl(ip_v4addr_always(ip)) & mask)); X+ } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(ip)); X X ip_family(dst) = ip_family(ip); X@@ -556,8 +678,41 @@ X X ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask); X } X+ else if(ip_family(ip) == AF_INET6) { X+ /* It's an IP V6 address: */ X+ unsigned long mask = 0xffffffff; X+ X+ /* Ok, let's do this in 4 steps... */ X+ if(ip_bits(ip) > 96) X+ { X+ mask <<= (128 - ip_bits(ip)); X+ ip_v6addr(dst)[0] = htonl(ntohl(ip_v6addr(ip)[0]) & mask); X+ memset(ip_v6addr(dst) + 1, 0, sizeof(int) * 3); X+ } X+ else if(ip_bits(ip) > 64) X+ { X+ ip_v6addr(dst)[0] = ip_v6addr(ip)[0]; X+ mask <<= (96 - ip_bits(ip)); X+ ip_v6addr(dst)[1] = htonl(ntohl(ip_v6addr(ip)[1]) & mask); X+ memset(ip_v6addr(dst) + 2, 0, sizeof(int) * 2); X+ } X+ else if(ip_bits(ip) > 32) X+ { X+ memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 2); X+ mask <<= (64 - ip_bits(ip)); X+ ip_v6addr(dst)[2] = htonl(ntohl(ip_v6addr(ip)[2]) & mask); X+ ip_v6addr(dst)[3] = 0; X+ } X+ else if(ip_bits(ip) > 0 ) X+ { X+ memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 3); X+ mask <<= (32 - ip_bits(ip)); X+ ip_v6addr(dst)[3] = htonl(ntohl(ip_v6addr(ip)[3]) & mask); X+ } X+ else X+ memcpy(ip_v6addr(dst), ip_v6addr(ip), sizeof(int) * 4); X+ } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(ip)); X X ip_family(dst) = ip_family(ip); X@@ -598,8 +753,44 @@ X X ip_bits(dst) = 32; X } X+ else if (ip_family(ip) == AF_INET6) X+ { X+ /* It's an IP V6 address: */ X+ unsigned long mask = 0xffffffff; X+ X+ /* Ok, let's do this in 4 steps... */ X+ if(ip_bits(ip) > 96) X+ { X+ mask <<= (128 - ip_bits(ip)); X+ ip_v6addr(dst)[0] = htonl(mask); X+ memset(ip_v6addr(dst) + 1, 0, sizeof(int) * 3); X+ } X+ else if(ip_bits(ip) > 64) X+ { X+ ip_v6addr(dst)[0] = 0xffffffff; X+ mask <<= (96 - ip_bits(ip)); X+ ip_v6addr(dst)[1] = htonl(mask); X+ memset(ip_v6addr(dst) + 2, 0, sizeof(int) * 2); X+ } X+ else if(ip_bits(ip) > 32) X+ { X+ memset(ip_v6addr(dst), 0xff, sizeof(int) * 2); X+ mask <<= (64 - ip_bits(ip)); X+ ip_v6addr(dst)[2] = htonl(mask); X+ ip_v6addr(dst)[3] = 0; X+ } X+ else if(ip_bits(ip) > 0 ) X+ { X+ memset(ip_v6addr(dst), 0xff, sizeof(int) * 3); X+ mask <<= (32 - ip_bits(ip)); X+ ip_v6addr(dst)[3] = htonl(mask); X+ } X+ else X+ memset(ip_v6addr(dst), 0xff, sizeof(int) * 4); X+ X+ ip_bits(dst) = 128; X+ } X else X- /* Go for an IPV6 address here, before faulting out: */ X elog(ERROR, "unknown address family (%d)", ip_family(ip)); X X ip_family(dst) = ip_family(ip); X@@ -661,7 +852,7 @@ X X X /* X- * Bitwise comparison for V4 addresses. Add V6 implementation! X+ * Bitwise comparison for IP V4 addresses. X */ X X static int X@@ -687,6 +878,34 @@ X } X X /* X+ * Bitwise comparison for IP V6 addresses. X+ */ X+ X+static int X+v6bitncmp(unsigned int *a1, unsigned int *a2, int bits) X+{ X+ unsigned int mask; X+ unsigned int tmp1, tmp2; X+ int i; X+ X+ for( i = 0; bits > 0 && i < 4; i++, bits -= 32 ) { X+ if( bits > 32 ) X+ mask = 0xffffffff; X+ else if( bits > 0 ) X+ mask = 0xffffffff << (32 - bits); X+ else X+ mask = 0; X+ tmp1 = ntohl(a1[i]); X+ tmp2 = ntohl(a2[i]); X+ if( ( tmp1 & mask ) < ( tmp2 & mask ) ) X+ return -1; X+ else if( ( tmp1 & mask ) > ( tmp2 & mask ) ) X+ return 1; X+ } X+ return 0; X+} X+ X+/* X * Returns true if given address fits fully within the specified bit width. X */ X static bool X@@ -706,6 +925,29 @@ X if ((a1 & mask) == a1) X return true; X return false; X+} X+ X+/* X+ * Returns true if given address fits fully within the specified bit width. X+ */ X+static bool X+v6addressOK(unsigned int *a1, int bits) X+{ X+ unsigned int tmp1, mask; X+ int i; X+ X+ for( i = 0; bits > 0 && i < 4; i++, bits -= 32 ) { X+ if( bits > 32 ) X+ mask = 0xffffffff; X+ else if( bits > 0 ) X+ mask = 0xffffffff << (32 - bits); X+ else X+ mask = 0; X+ tmp1 = ntohl(a1[i]); X+ if( ( tmp1 & mask ) != tmp1 ) X+ return false; X+ } X+ return true; X } X X XIndex: src/include/utils/inet.h X=================================================================== XRCS file: /projects/cvsroot/pgsql/src/include/utils/inet.h,v Xretrieving revision 1.10 Xdiff -u -r1.10 inet.h X--- src/include/utils/inet.h 2001/03/22 04:01:12 1.10 X+++ src/include/utils/inet.h 2001/10/05 08:31:25 X@@ -25,8 +25,8 @@ X unsigned char type; X union X { X- unsigned int ipv4_addr; /* network byte order */ X- /* add IPV6 address type here */ X+ unsigned int ipv4_addr; /* network byte order */ X+ unsigned int ipv6_addr[4]; /* network byte order */ X } addr; X } inet_struct; X END-of-ipv6-patch echo x - inet_cidr_ntop.c sed 's/^X//' >inet_cidr_ntop.c << 'END-of-inet_cidr_ntop.c' X/* X * Copyright (c) 1998,1999 by Internet Software Consortium. X * X * Permission to use, copy, modify, and distribute this software for any X * purpose with or without fee is hereby granted, provided that the above X * copyright notice and this permission notice appear in all copies. X * X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS X * SOFTWARE. X */ X X#if defined(LIBC_SCCS) && !defined(lint) Xstatic const char isc_rcsid[] = "Id: inet_cidr_ntop.c,v 8.7 2001/09/28 05:19:36 marka Exp $"; Xstatic const char rcsid[] = "$Id:$"; X#endif X X/*#include "port_before.h"*/ X X#include <sys/types.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <arpa/nameser.h> X#include <arpa/inet.h> X X#include <errno.h> X#include <stdio.h> X#include <string.h> X#include <stdlib.h> X X/*#include "port_after.h"*/ X X#include "postgres.h" X#include "utils/builtins.h" X X#ifdef SPRINTF_CHAR X# define SPRINTF(x) strlen(sprintf/**/x) X#else X# define SPRINTF(x) ((size_t)sprintf x) X#endif X Xstatic char * inet_cidr_ntop_ipv4(const u_char *src, int bits, X char *dst, size_t size); Xstatic char * inet_cidr_ntop_ipv6(const u_char *src, int bits, X char *dst, size_t size); X X/* X * char * X * inet_cidr_ntop(af, src, bits, dst, size) X * convert network address from network to presentation format. X * "src"'s size is determined from its "af". X * return: X * pointer to dst, or NULL if an error occurred (check errno). X * note: X * 192.5.5.1/28 has a nonzero host part, which means it isn't a network X * as called for by inet_net_ntop() but it can be a host address with X * an included netmask. X * author: X * Paul Vixie (ISC), October 1998 X */ Xchar * Xinet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) { X switch (af) { X case AF_INET: X return (inet_cidr_ntop_ipv4(src, bits, dst, size)); X case AF_INET6: X return (inet_cidr_ntop_ipv6(src, bits, dst, size)); X default: X errno = EAFNOSUPPORT; X return (NULL); X } X} X Xstatic int Xdecoct(const u_char *src, int bytes, char *dst, size_t size) { X char *odst = dst; X char *t; X int b; X X for (b = 1; b <= bytes; b++) { X if (size < sizeof "255.") X return (0); X t = dst; X dst += SPRINTF((dst, "%u", *src++)); X if (b != bytes) { X *dst++ = '.'; X *dst = '\0'; X } X size -= (size_t)(dst - t); X } X return (dst - odst); X} X X/* X * static char * X * inet_cidr_ntop_ipv4(src, bits, dst, size) X * convert IPv4 network address from network to presentation format. X * "src"'s size is determined from its "af". X * return: X * pointer to dst, or NULL if an error occurred (check errno). X * note: X * network byte order assumed. this means 192.5.5.240/28 has X * 0b11110000 in its fourth octet. X * author: X * Paul Vixie (ISC), October 1998 X */ Xstatic char * Xinet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) { X char *odst = dst; X size_t len = 4; X size_t b; X size_t bytes; X X if ((bits < -1) || (bits > 32)) { X errno = EINVAL; X return (NULL); X } X X /* Find number of significant bytes in address. */ X if (bits == -1) X len = 4; X else X for (len = 1, b = 1 ; b < 4; b++) X if (*(src + b)) X len = b + 1; X X /* Format whole octets plus nonzero trailing octets. */ X bytes = (((bits <= 0) ? 1 : bits) + 7) / 8; X if (len > bytes) X bytes = len; X b = decoct(src, bytes, dst, size); X if (b == 0) X goto emsgsize; X dst += b; X size -= b; X X if (bits != -1) { X /* Format CIDR /width. */ X if (size < sizeof "/32") X goto emsgsize; X dst += SPRINTF((dst, "/%u", bits)); X } X X return (odst); X X emsgsize: X errno = EMSGSIZE; X return (NULL); X} X Xstatic char * Xinet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { X /* X * Note that int32_t and int16_t need only be "at least" large enough X * to contain a value of the specified size. On some systems, like X * Crays, there is no such thing as an integer variable with 16 bits. X * Keep this in mind if you think this function should have been coded X * to use pointer overlays. All the world's not a VAX. X */ X char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; X char *tp; X struct { int base, len; } best, cur; X u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; X int i; X X if ((bits < -1) || (bits > 128)) { X errno = EINVAL; X return (NULL); X } X X /* X * Preprocess: X * Copy the input (bytewise) array into a wordwise array. X * Find the longest run of 0x00's in src[] for :: shorthanding. X */ X memset(words, '\0', sizeof words); X for (i = 0; i < NS_IN6ADDRSZ; i++) X words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); X best.base = -1; X cur.base = -1; X for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { X if (words[i] == 0) { X if (cur.base == -1) X cur.base = i, cur.len = 1; X else X cur.len++; X } else { X if (cur.base != -1) { X if (best.base == -1 || cur.len > best.len) X best = cur; X cur.base = -1; X } X } X } X if (cur.base != -1) { X if (best.base == -1 || cur.len > best.len) X best = cur; X } X if (best.base != -1 && best.len < 2) X best.base = -1; X X /* X * Format the result. X */ X tp = tmp; X for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { X /* Are we inside the best run of 0x00's? */ X if (best.base != -1 && i >= best.base && X i < (best.base + best.len)) { X if (i == best.base) X *tp++ = ':'; X continue; X } X /* Are we following an initial run of 0x00s or any real hex? */ X if (i != 0) X *tp++ = ':'; X /* Is this address an encapsulated IPv4? */ X if (i == 6 && best.base == 0 && (best.len == 6 || X (best.len == 7 && words[7] != 0x0001) || X (best.len == 5 && words[5] == 0xffff))) { X int n; X X if (src[15] || bits == -1 || bits > 120) X n = 4; X else if (src[14] || bits > 112) X n = 3; X else X n = 2; X n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp)); X if (n == 0) { X errno = EMSGSIZE; X return (NULL); X } X tp += strlen(tp); X break; X } X tp += SPRINTF((tp, "%x", words[i])); X } X X /* Was it a trailing run of 0x00's? */ X if (best.base != -1 && (best.base + best.len) == X (NS_IN6ADDRSZ / NS_INT16SZ)) X *tp++ = ':'; X *tp = '\0'; X X if (bits != -1) X tp += SPRINTF((tp, "/%u", bits)); X X /* X * Check for overflow, copy, and we're done. X */ X if ((size_t)(tp - tmp) > size) { X errno = EMSGSIZE; X return (NULL); X } X strcpy(dst, tmp); X return (dst); X} END-of-inet_cidr_ntop.c echo x - inet_cidr_pton.c sed 's/^X//' >inet_cidr_pton.c << 'END-of-inet_cidr_pton.c' X/* X * Copyright (c) 1998,1999 by Internet Software Consortium. X * X * Permission to use, copy, modify, and distribute this software for any X * purpose with or without fee is hereby granted, provided that the above X * copyright notice and this permission notice appear in all copies. X * X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS X * SOFTWARE. X */ X X#if defined(LIBC_SCCS) && !defined(lint) Xstatic const char isc_rcsid[] = "Id: inet_cidr_pton.c,v 8.7 2001/09/28 04:21:28 marka Exp $"; Xstatic const char rcsid[] = "$Id:$"; X#endif X X/*#include "port_before.h"*/ X X#include <sys/types.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <arpa/nameser.h> X#include <arpa/inet.h> X X/*#include <isc/assertions.h>*/ X#include <assert.h> X#include <ctype.h> X#include <errno.h> X#include <stdio.h> X#include <string.h> X#include <stdlib.h> X X/*#include "port_after.h"*/ X X#include "postgres.h" X#include "utils/builtins.h" X X#ifdef SPRINTF_CHAR X# define SPRINTF(x) strlen(sprintf/**/x) X#else X# define SPRINTF(x) ((size_t)sprintf x) X#endif X Xstatic int inet_cidr_pton_ipv4(const char *src, u_char *dst, X int *bits, int ipv6); Xstatic int inet_cidr_pton_ipv6(const char *src, u_char *dst, X int *bits); X Xstatic int getbits(const char *, int ipv6); X X/* X * int X * inet_cidr_pton(af, src, dst, *bits) X * convert network address from presentation to network format. X * accepts inet_pton()'s input for this "af" plus trailing "/CIDR". X * "dst" is assumed large enough for its "af". "bits" is set to the X * /CIDR prefix length, which can have defaults (like /32 for IPv4). X * return: X * -1 if an error occurred (inspect errno; ENOENT means bad format). X * 0 if successful conversion occurred. X * note: X * 192.5.5.1/28 has a nonzero host part, which means it isn't a network X * as called for by inet_net_pton() but it can be a host address with X * an included netmask. X * author: X * Paul Vixie (ISC), October 1998 X */ Xint Xinet_cidr_pton(int af, const char *src, void *dst, int *bits) { X switch (af) { X case AF_INET: X return (inet_cidr_pton_ipv4(src, dst, bits, 0)); X case AF_INET6: X return (inet_cidr_pton_ipv6(src, dst, bits)); X default: X errno = EAFNOSUPPORT; X return (-1); X } X} X Xstatic const char digits[] = "0123456789"; X Xstatic int Xinet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) { X const u_char *odst = dst; X int n, ch, tmp, bits; X size_t size = 4; X X /* Get the mantissa. */ X while (ch = *src++, (isascii(ch) && isdigit(ch))) { X tmp = 0; X do { X n = strchr(digits, ch) - digits; X assert(n >= 0 && n <= 9); X tmp *= 10; X tmp += n; X if (tmp > 255) X goto enoent; X } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); X if (size-- == 0) X goto emsgsize; X *dst++ = (u_char) tmp; X if (ch == '\0' || ch == '/') X break; X if (ch != '.') X goto enoent; X } X X /* Get the prefix length if any. */ X bits = -1; X if (ch == '/' && dst > odst) { X bits = getbits(src, ipv6); X if (bits == -2) X goto enoent; X } else if (ch != '\0') X goto enoent; X X /* Prefix length can default to /32 only if all four octets spec'd. */ X if (bits == -1) { X if (dst - odst == 4) X bits = ipv6 ? 128 : 32; X else X goto enoent; X } X X /* If nothing was written to the destination, we found no address. */ X if (dst == odst) X goto enoent; X X /* If prefix length overspecifies mantissa, life is bad. */ X if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst)) X goto enoent; X X /* Extend address to four octets. */ X while (size-- > 0) X *dst++ = 0; X X *pbits = bits; X return (0); X X enoent: X errno = ENOENT; X return (-1); X X emsgsize: X errno = EMSGSIZE; X return (-1); X} X Xstatic int Xinet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) { X static const char xdigits_l[] = "0123456789abcdef", X xdigits_u[] = "0123456789ABCDEF"; X u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; X const char *xdigits, *curtok; X int ch, saw_xdigit; X u_int val; X int bits; X X memset((tp = tmp), '\0', NS_IN6ADDRSZ); X endp = tp + NS_IN6ADDRSZ; X colonp = NULL; X /* Leading :: requires some special handling. */ X if (*src == ':') X if (*++src != ':') X return (0); X curtok = src; X saw_xdigit = 0; X val = 0; X bits = -1; X while ((ch = *src++) != '\0') { X const char *pch; X X if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) X pch = strchr((xdigits = xdigits_u), ch); X if (pch != NULL) { X val <<= 4; X val |= (pch - xdigits); X if (val > 0xffff) X return (0); X saw_xdigit = 1; X continue; X } X if (ch == ':') { X curtok = src; X if (!saw_xdigit) { X if (colonp) X return (0); X colonp = tp; X continue; X } else if (*src == '\0') { X return (0); X } X if (tp + NS_INT16SZ > endp) X return (0); X *tp++ = (u_char) (val >> 8) & 0xff; X *tp++ = (u_char) val & 0xff; X saw_xdigit = 0; X val = 0; X continue; X } X if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && X inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) { X tp += NS_INADDRSZ; X saw_xdigit = 0; X break; /* '\0' was seen by inet_pton4(). */ X } X if (ch == '/') { X bits = getbits(src, 1); X if (bits == -2) X goto enoent; X break; X } X goto enoent; X } X if (saw_xdigit) { X if (tp + NS_INT16SZ > endp) X goto emsgsize; X *tp++ = (u_char) (val >> 8) & 0xff; X *tp++ = (u_char) val & 0xff; X } X if (colonp != NULL) { X /* X * Since some memmove()'s erroneously fail to handle X * overlapping regions, we'll do the shift by hand. X */ X const int n = tp - colonp; X int i; X X if (tp == endp) X goto enoent; X for (i = 1; i <= n; i++) { X endp[- i] = colonp[n - i]; X colonp[n - i] = 0; X } X tp = endp; X } X X memcpy(dst, tmp, NS_IN6ADDRSZ); X X *pbits = bits; X return (0); X X enoent: X errno = ENOENT; X return (-1); X X emsgsize: X errno = EMSGSIZE; X return (-1); X} X Xint Xgetbits(const char *src, int ipv6) { X int bits = 0; X char *cp, ch; X X if (*src == '\0') /* syntax */ X return (-2); X do { X ch = *src++; X cp = strchr(digits, ch); X if (cp == NULL) /* syntax */ X return (-2); X bits *= 10; X bits += cp - digits; X if (bits == 0 && *src != '\0') /* no leading zeros */ X return (-2); X if (bits > (ipv6 ? 128 : 32)) /* range error */ X return (-2); X } while (*src != '\0'); X X return (bits); X} END-of-inet_cidr_pton.c exit
pgsql-patches by date: