Index: doc/src/sgml/datatype.sgml =================================================================== RCS file: /cvsroot/pgsql-server/doc/src/sgml/datatype.sgml,v retrieving revision 1.116 diff -c -c -r1.116 datatype.sgml *** doc/src/sgml/datatype.sgml 13 Mar 2003 01:30:27 -0000 1.116 --- doc/src/sgml/datatype.sgml 12 Jun 2003 05:13:12 -0000 *************** *** 100,106 **** cidr ! IP network address --- 100,106 ---- cidr ! IPv4 or IPc6 network address *************** *** 124,130 **** inet ! IP host address --- 124,130 ---- inet ! IPv4 or IPv6 host address *************** *** 2394,2400 **** ! PostgreSQL offers data types to store IP and MAC addresses, shown in . It is preferable to use these types over plain text types, because these types offer input error checking and several specialized --- 2394,2400 ---- ! PostgreSQL offers data types to store IPv4, IPv6, and MAC addresses, shown in . It is preferable to use these types over plain text types, because these types offer input error checking and several specialized *************** *** 2415,2428 **** cidr ! 12 bytes ! IPv4 networks inet ! 12 bytes ! IPv4 hosts and networks --- 2415,2428 ---- cidr ! 12 or 24 bytes ! valid IPv4 or IPv6 networks inet ! 12 or 24 bytes ! valid IPv4 or IPv6 hosts or networks *************** *** 2436,2442 **** ! IPv6 is not yet supported. --- 2436,2445 ---- ! When sorting inet or cidr data types, ! IPv4 addresses will always sort before IPv6 addresses, including ! IPv4 addresses encapsulated or mapped into IPv6 addresses, such as ! ::10.2.3.4 or ::ffff::10.4.3.2. *************** *** 2448,2473 **** ! The inet type holds an IP host address, and optionally the identity of the subnet it is in, all in one field. ! The subnet identity is represented by stating how many bits of ! the host address represent the network address (the ! netmask). If the netmask is 32, then the value ! does not indicate a subnet, only a single host. Note that if you ! want to accept networks only, you should use the cidr type rather than inet. ! The input format for this type is x.x.x.x/y where x.x.x.x is an IP address and ! y is the number of ! bits in the netmask. If the /y part is left off, then the ! netmask is 32, and the value represents just a single host. ! On display, the /y ! portion is suppressed if the netmask is 32. --- 2451,2481 ---- ! The inet type holds an IPv4 or IPv6 host address, and optionally the identity of the subnet it is in, all in one field. ! The subnet identity is represented by stating how many bits of the ! the host address represent the network address ! (the netmask). If the netmask is 32 and the address is ! IPv4, then the value does not indicate a subnet, only a single host. ! In IPv6, the address length is 128 bits. ! Note that if you want to accept networks only, you should use the cidr type rather than inet. ! The input format for this type is ! address/y ! where ! address ! is an IPv4 or IPv6 address and ! y ! is the number of bits in the netmask. If the ! /y ! part is left off, then the ! netmask is 32 for IPv4 and 128 for IPv6, and the value represents ! just a single host. On display, the ! /y ! portion is suppressed if the netmask specifies a single host. *************** *** 2479,2490 **** ! The cidr type holds an IP network specification. Input and output formats follow Classless Internet Domain Routing conventions. The format for specifying networks is x.x.x.x/y where x.x.x.x is the network and y is the number of bits in the netmask. If y is omitted, it is calculated using assumptions from the older classful network numbering system, except --- 2487,2499 ---- ! The cidr type holds an IPv4 or IPv6 network specification. Input and output formats follow Classless Internet Domain Routing conventions. The format for specifying networks is address/y where address is the network represented as an ! IPv4 or IPv6 address, and y is the number of bits in the netmask. If y is omitted, it is calculated using assumptions from the older classful network numbering system, except *************** *** 2563,2568 **** --- 2572,2599 ---- 10.0.0.0/8 10/8 + + 10.1.2.3/32 + 10.1.2.3/32 + 10.1.2.3/32 + + 2001:4f8:3:ba::/64 + 2001:4f8:3:ba::/64 + 2001:4f8:3:ba::/64 + + + 2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128 + 2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128 + 2001:4f8:3:ba:2e0:81ff:fe22:d1f1 + + + ::ffff:1.2.3.0/120 + ::ffff:1.2.3.0/120 + ::ffff:1.2.3/120 + + ::ffff:1.2.3.0/128 + ::ffff:1.2.3.0/128 + ::ffff:1.2.3.0/128 Index: doc/src/sgml/func.sgml =================================================================== RCS file: /cvsroot/pgsql-server/doc/src/sgml/func.sgml,v retrieving revision 1.154 diff -c -c -r1.154 func.sgml *** doc/src/sgml/func.sgml 5 May 2003 15:08:49 -0000 1.154 --- doc/src/sgml/func.sgml 12 Jun 2003 05:13:18 -0000 *************** *** 5804,5809 **** --- 5804,5814 ---- inet '192.168.1.5' < inet '192.168.1.6' + < + Less than + inet '1111::2222' < inet '2222::1111' + + <= is less than or equal inet '192.168.1.5' <= inet '192.168.1.5' Index: src/backend/utils/adt/inet_net_ntop.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/inet_net_ntop.c,v retrieving revision 1.12 diff -c -c -r1.12 inet_net_ntop.c *** src/backend/utils/adt/inet_net_ntop.c 2 Sep 2002 02:47:04 -0000 1.12 --- src/backend/utils/adt/inet_net_ntop.c 12 Jun 2003 05:13:19 -0000 *************** *** 27,34 **** --- 27,38 ---- #include + #include "utils/inet.h" #include "utils/builtins.h" + #define NS_IN6ADDRSZ 16 + #define NS_INT16SZ 2 + #ifdef SPRINTF_CHAR #define SPRINTF(x) strlen(sprintf/**/x) #else *************** *** 36,44 **** #endif static char *inet_net_ntop_ipv4(const u_char *src, int bits, ! char *dst, size_t size); static char *inet_cidr_ntop_ipv4(const u_char *src, int bits, ! char *dst, size_t size); /* * char * --- 40,52 ---- #endif static char *inet_net_ntop_ipv4(const u_char *src, int bits, ! char *dst, size_t size); static char *inet_cidr_ntop_ipv4(const u_char *src, int bits, ! char *dst, size_t size); ! static char *inet_net_ntop_ipv6(const u_char *src, int bits, ! char *dst, size_t size); ! static char *inet_cidr_ntop_ipv6(const u_char *src, int bits, ! char *dst, size_t size); /* * char * *************** *** 55,62 **** { switch (af) { ! case AF_INET: return (inet_cidr_ntop_ipv4(src, bits, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); --- 63,72 ---- { switch (af) { ! case PGSQL_AF_INET: return (inet_cidr_ntop_ipv4(src, bits, dst, size)); + case PGSQL_AF_INET6: + return (inet_cidr_ntop_ipv6(src, bits, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); *************** *** 136,141 **** --- 146,293 ---- return (NULL); } + /* + * static char * + * inet_net_ntop_ipv6(src, bits, fakebits, dst, size) + * convert IPv6 network number from network to presentation format. + * generates CIDR style result always. Picks the shortest representation + * unless the IP is really IPv4. + * always prints specified number of bits (bits). + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0x11110000 in its fourth octet. + * author: + * Vadim Kogan (UCB), June 2001 + * Original version (IPv4) by Paul Vixie (ISC), July 1996 + */ + + static char * + inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) + { + u_int m; + int b; + int p; + int zero_s, zero_l, tmp_zero_s, tmp_zero_l; + int i; + int is_ipv4 = 0; + int double_colon = 0; + unsigned char inbuf[16]; + char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; + char *cp; + int words; + u_char *s; + + if (bits < 0 || bits > 128) { + errno = EINVAL; + return (NULL); + } + + cp = outbuf; + double_colon = 0; + + if (bits == 0) { + *cp++ = ':'; + *cp++ = ':'; + *cp = '\0'; + double_colon = 1; + } else { + /* Copy src to private buffer. Zero host part. */ + p = (bits + 7) / 8; + memcpy(inbuf, src, p); + memset(inbuf + p, 0, 16 - p); + b = bits % 8; + if (b != 0) { + m = ~0 << (8 - b); + inbuf[p-1] &= m; + } + + s = inbuf; + + /* how many words need to be displayed in output */ + words = (bits + 15) / 16; + if (words == 1) + words = 2; + + /* Find the longest substring of zero's */ + zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0; + for (i = 0; i < (words * 2); i += 2) { + if ((s[i] | s[i+1]) == 0) { + if (tmp_zero_l == 0) + tmp_zero_s = i / 2; + tmp_zero_l++; + } else { + if (tmp_zero_l && zero_l < tmp_zero_l) { + zero_s = tmp_zero_s; + zero_l = tmp_zero_l; + tmp_zero_l = 0; + } + } + } + + if (tmp_zero_l && zero_l < tmp_zero_l) { + zero_s = tmp_zero_s; + zero_l = tmp_zero_l; + } + + if (zero_l != words && zero_s == 0 && ((zero_l == 6) || + ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) || + ((zero_l == 7 && s[14] != 0 && s[15] != 1))))) + is_ipv4 = 1; + + /* Format whole words. */ + for (p = 0; p < words; p++) { + if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) { + /* Time to skip some zeros */ + if (p == zero_s) + *cp++ = ':'; + if (p == words - 1) { + *cp++ = ':'; + double_colon = 1; + } + s++; + s++; + continue; + } + + if (is_ipv4 && p > 5 ) { + *cp++ = (p == 6) ? ':' : '.'; + cp += SPRINTF((cp, "%u", *s++)); + /* we can potentially drop the last octet */ + if (p != 7 || bits > 120) { + *cp++ = '.'; + cp += SPRINTF((cp, "%u", *s++)); + } + } else { + if (cp != outbuf) + *cp++ = ':'; + cp += SPRINTF((cp, "%x", *s * 256 + s[1])); + s += 2; + } + } + } + + if (!double_colon) { + if (bits < 128 - 32) + cp += SPRINTF((cp, "::", bits)); + else if (bits < 128 - 16) + cp += SPRINTF((cp, ":0", bits)); + } + + /* Format CIDR /width. */ + SPRINTF((cp, "/%u", bits)); + + if (strlen(outbuf) + 1 > size) + goto emsgsize; + strcpy(dst, outbuf); + + return (dst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); + } /* * char * *************** *** 156,163 **** { switch (af) { ! case AF_INET: return (inet_net_ntop_ipv4(src, bits, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); --- 308,317 ---- { switch (af) { ! case PGSQL_AF_INET: return (inet_net_ntop_ipv4(src, bits, dst, size)); + case PGSQL_AF_INET6: + return (inet_net_ntop_ipv6(src, bits, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); *************** *** 216,219 **** --- 370,497 ---- emsgsize: errno = EMSGSIZE; return (NULL); + } + + static int + decoct(const u_char *src, int bytes, char *dst, size_t size) { + char *odst = dst; + char *t; + int b; + + for (b = 1; b <= bytes; b++) { + if (size < sizeof "255.") + return (0); + t = dst; + dst += SPRINTF((dst, "%u", *src++)); + if (b != bytes) { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - t); + } + return (dst - odst); + } + + static char * + inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) + { + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; + char *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + if ((bits < -1) || (bits > 128)) { + errno = EINVAL; + return (NULL); + } + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + int n; + + n = decoct(src+12, 4, tp, sizeof tmp - (tp - tmp)); + if (n == 0) { + errno = EMSGSIZE; + return (NULL); + } + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp = '\0'; + + if (bits != -1 && bits != 128) + tp += SPRINTF((tp, "/%u", bits)); + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = EMSGSIZE; + return (NULL); + } + strcpy(dst, tmp); + return (dst); } Index: src/backend/utils/adt/inet_net_pton.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/inet_net_pton.c,v retrieving revision 1.14 diff -c -c -r1.14 inet_net_pton.c *** src/backend/utils/adt/inet_net_pton.c 2 Sep 2002 02:47:04 -0000 1.14 --- src/backend/utils/adt/inet_net_pton.c 12 Jun 2003 05:13:19 -0000 *************** *** 29,44 **** #include #include ! #include "utils/builtins.h" ! #ifdef SPRINTF_CHAR ! #define SPRINTF(x) strlen(sprintf/**/x) ! #else ! #define SPRINTF(x) ((size_t)sprintf x) ! #endif static int inet_net_pton_ipv4(const char *src, u_char *dst); static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size); /* * static int --- 29,42 ---- #include #include ! #include "utils/inet.h" ! #include "utils/builtins.h" static int inet_net_pton_ipv4(const char *src, u_char *dst); static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size); + static int inet_net_pton_ipv6(const char *src, u_char *dst); + static int inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size); /* * static int *************** *** 63,72 **** { switch (af) { ! case AF_INET: return size == -1 ? inet_net_pton_ipv4(src, dst) : inet_cidr_pton_ipv4(src, dst, size); default: errno = EAFNOSUPPORT; return (-1); --- 61,74 ---- { switch (af) { ! case PGSQL_AF_INET: return size == -1 ? inet_net_pton_ipv4(src, dst) : inet_cidr_pton_ipv4(src, dst, size); + case PGSQL_AF_INET6: + return size == -1 ? + inet_net_pton_ipv6(src, dst) : + inet_cidr_pton_ipv6(src, dst, size); default: errno = EAFNOSUPPORT; return (-1); *************** *** 332,337 **** --- 334,535 ---- return (-1); emsgsize: + errno = EMSGSIZE; + return (-1); + } + + static int + getbits(const char *src, int *bitsp) { + static const char digits[] = "0123456789"; + int n; + int val; + char ch; + + val = 0; + n = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if (pch != NULL) { + if (n++ != 0 && val == 0) /* no leading zeros */ + return (0); + val *= 10; + val += (pch - digits); + if (val > 128) /* range */ + return (0); + continue; + } + return (0); + } + if (n == 0) + return (0); + *bitsp = val; + return (1); + } + + static int + getv4(const char *src, u_char *dst, int *bitsp) { + static const char digits[] = "0123456789"; + u_char *odst = dst; + int n; + u_int val; + char ch; + + val = 0; + n = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + pch = strchr(digits, ch); + if (pch != NULL) { + if (n++ != 0 && val == 0) /* no leading zeros */ + return (0); + val *= 10; + val += (pch - digits); + if (val > 255) /* range */ + return (0); + continue; + } + if (ch == '.' || ch == '/') { + if (dst - odst > 3) /* too many octets? */ + return (0); + *dst++ = val; + if (ch == '/') + return (getbits(src, bitsp)); + val = 0; + n = 0; + continue; + } + return (0); + } + if (n == 0) + return (0); + if (dst - odst > 3) /* too many octets? */ + return (0); + *dst++ = val; + return (1); + } + + static int + inet_net_pton_ipv6(const char *src, u_char *dst) + { + return inet_cidr_pton_ipv6(src, dst, 16); + } + + #define NS_IN6ADDRSZ 16 + #define NS_INT16SZ 2 + #define NS_INADDRSZ 4 + + static int + inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + int digits; + int bits; + + if (size < NS_IN6ADDRSZ) + goto emsgsize; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + goto enoent; + curtok = src; + saw_xdigit = 0; + val = 0; + digits = 0; + bits = -1; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++digits > 4) + goto enoent; + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + goto enoent; + colonp = tp; + continue; + } else if (*src == '\0') + goto enoent; + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + digits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + getv4(curtok, tp, &bits) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + if (ch == '/' && getbits(src, &bits) > 0) + break; + goto enoent; + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + goto enoent; + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (bits == -1) + bits = 128; + + endp = tmp + 16; + + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + goto enoent; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + goto enoent; + + /* + * Copy out the result. + */ + memcpy(dst, tmp, NS_IN6ADDRSZ); + + return (bits); + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: errno = EMSGSIZE; return (-1); } Index: src/backend/utils/adt/network.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/network.c,v retrieving revision 1.41 diff -c -c -r1.41 network.c *** src/backend/utils/adt/network.c 13 May 2003 18:03:07 -0000 1.41 --- src/backend/utils/adt/network.c 12 Jun 2003 05:13:20 -0000 *************** *** 1,7 **** /* ! * PostgreSQL type definitions for the INET type. This ! * is for IP V4 CIDR notation, but prepared for V6: just ! * add the necessary bits where the comments indicate. * * $Header: /cvsroot/pgsql-server/src/backend/utils/adt/network.c,v 1.41 2003/05/13 18:03:07 tgl Exp $ * --- 1,5 ---- /* ! * PostgreSQL type definitions for the INET and CIDR types. * * $Header: /cvsroot/pgsql-server/src/backend/utils/adt/network.c,v 1.41 2003/05/13 18:03:07 tgl Exp $ * *************** *** 15,38 **** #include #include #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "utils/builtins.h" #include "utils/inet.h" - static Datum text_network(text *src, int type); static int32 network_cmp_internal(inet *a1, inet *a2); ! static int v4bitncmp(unsigned long a1, unsigned long a2, int bits); ! static bool v4addressOK(unsigned long a1, int bits); /* ! * Access macros. Add IPV6 support. */ - #define ip_addrsize(inetptr) \ - (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1) - #define ip_family(inetptr) \ (((inet_struct *)VARDATA(inetptr))->family) --- 13,35 ---- #include #include + #include + #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "utils/builtins.h" #include "utils/inet.h" static Datum text_network(text *src, int type); static int32 network_cmp_internal(inet *a1, inet *a2); ! static int bitncmp(void *l, void *r, int n); ! static bool addressOK(unsigned char *a, int bits, int family); ! static int ip_addrsize(inet *inetptr); /* ! * Access macros. */ #define ip_family(inetptr) \ (((inet_struct *)VARDATA(inetptr))->family) *************** *** 42,83 **** #define ip_type(inetptr) \ (((inet_struct *)VARDATA(inetptr))->type) ! #define ip_v4addr(inetptr) \ ! (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr) /* Common input routine */ static inet * network_in(char *src, int type) { ! int bits; inet *dst; /* make sure any unused bits in a CIDR value are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! /* First, try for an IP V4 address: */ ! ip_family(dst) = AF_INET; ! bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ! type ? ip_addrsize(dst) : -1); ! if ((bits < 0) || (bits > 32)) ! { ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "invalid %s value '%s'", ! type ? "CIDR" : "INET", src); } /* ! * Error check: CIDR values must not have any bits set beyond the ! * masklen. XXX this code is not IPV6 ready. */ if (type) { ! if (!v4addressOK(ip_v4addr(dst), bits)) elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src); } VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); ip_bits(dst) = bits; ip_type(dst) = type; --- 39,107 ---- #define ip_type(inetptr) \ (((inet_struct *)VARDATA(inetptr))->type) ! #define ip_addr(inetptr) \ ! (((inet_struct *)VARDATA(inetptr))->ip_addr) ! ! #define ip_maxbits(inetptr) \ ! (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128) ! ! /* ! * Now, as a function! ! * Return the number of bytes of storage needed for this data type. ! */ ! static int ! ip_addrsize(inet *inetptr) ! { ! switch (ip_family(inetptr)) { ! case PGSQL_AF_INET: ! return 4; ! case PGSQL_AF_INET6: ! return 16; ! default: ! return -1; ! } ! } /* Common input routine */ static inet * network_in(char *src, int type) { ! int bits; inet *dst; /* make sure any unused bits in a CIDR value are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! /* ! * First, check to see if this is an IPv6 or IPv4 address. IPv6 ! * addresses will have a : somewhere in them (several, in fact) so ! * if there is one present, assume it's V6, otherwise assume it's V4. ! */ ! ! if (strchr(src, ':') != NULL) { ! ip_family(dst) = PGSQL_AF_INET6; ! } else { ! ip_family(dst) = PGSQL_AF_INET; } + bits = inet_net_pton(ip_family(dst), src, ip_addr(dst), + type ? ip_addrsize(dst) : -1); + if ((bits < 0) || (bits > ip_maxbits(dst))) + elog(ERROR, "invalid %s value '%s'", + type ? "CIDR" : "INET", src); + /* ! * Error check: CIDR values must not have any bits set beyond ! * the masklen. */ if (type) { ! if (!addressOK(ip_addr(dst), bits, ip_family(dst))) elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src); } VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *) &ip_addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); ip_bits(dst) = bits; ip_type(dst) = type; *************** *** 110,141 **** inet_out(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_P(0); ! char tmp[sizeof("255.255.255.255/32")]; char *dst; int len; ! if (ip_family(src) == AF_INET) { ! /* It's an IP V4 address: */ ! ! /* ! * Use inet style for both inet and cidr, since we don't want ! * abbreviated CIDR style here. ! */ ! dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src), ! tmp, sizeof(tmp)); ! if (dst == NULL) ! elog(ERROR, "unable to print address (%s)", strerror(errno)); ! /* For CIDR, add /n if not present */ ! if (ip_type(src) && strchr(tmp, '/') == NULL) ! { ! len = strlen(tmp); ! snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src)); ! } } - else - /* Go for an IPV6 address here, before faulting out: */ - elog(ERROR, "unknown address family (%d)", ip_family(src)); PG_RETURN_CSTRING(pstrdup(tmp)); } --- 134,153 ---- inet_out(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_P(0); ! char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; char *dst; int len; ! dst = inet_net_ntop(ip_family(src), ip_addr(src), ip_bits(src), ! tmp, sizeof(tmp)); ! if (dst == NULL) ! elog(ERROR, "unable to print address (%s)", strerror(errno)); ! /* For CIDR, add /n if not present */ ! if (ip_type(src) && strchr(tmp, '/') == NULL) { ! len = strlen(tmp); ! snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src)); } PG_RETURN_CSTRING(pstrdup(tmp)); } *************** *** 257,262 **** --- 269,275 ---- PG_RETURN_INET_P(network_in(str, type)); } + Datum text_cidr(PG_FUNCTION_ARGS) { *************** *** 276,283 **** int bits = PG_GETARG_INT32(1); inet *dst; ! if ((bits < 0) || (bits > 32)) /* no support for v6 yet */ ! elog(ERROR, "set_masklen - invalid value '%d'", bits); /* clone the original data */ dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct)); --- 289,299 ---- int bits = PG_GETARG_INT32(1); inet *dst; ! if ( bits == -1 ) ! bits = ip_maxbits(src); ! ! if ((bits < 0) || (bits > ip_maxbits(src))) ! elog(ERROR, "set_masklen - invalid value '%d'", bits); /* clone the original data */ dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct)); *************** *** 302,327 **** static int32 network_cmp_internal(inet *a1, inet *a2) { ! if (ip_family(a1) == AF_INET && ip_family(a2) == AF_INET) { int order; ! order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ! Min(ip_bits(a1), ip_bits(a2))); if (order != 0) return order; order = ((int) ip_bits(a1)) - ((int) ip_bits(a2)); if (order != 0) return order; ! return v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), 32); ! } ! else ! { ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "cannot compare address families %d and %d", ! ip_family(a1), ip_family(a2)); ! return 0; /* keep compiler quiet */ } } Datum --- 318,338 ---- static int32 network_cmp_internal(inet *a1, inet *a2) { ! if (ip_family(a1) == ip_family(a2)) { int order; ! order = bitncmp(ip_addr(a1), ip_addr(a2), ! Min(ip_bits(a1), ip_bits(a2))); if (order != 0) return order; order = ((int) ip_bits(a1)) - ((int) ip_bits(a2)); if (order != 0) return order; ! return bitncmp(ip_addr(a1), ip_addr(a2), ip_maxbits(a1)); } + + return ip_family(a1) - ip_family(a2); } Datum *************** *** 399,416 **** inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) { PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) ! && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0); ! } ! else ! { ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "cannot compare address families %d and %d", ! ip_family(a1), ip_family(a2)); ! PG_RETURN_BOOL(false); } } Datum --- 410,422 ---- inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) ! && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0); } + + PG_RETURN_BOOL(false); } Datum *************** *** 419,436 **** inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) { PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) ! && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0); ! } ! else ! { ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "cannot compare address families %d and %d", ! ip_family(a1), ip_family(a2)); ! PG_RETURN_BOOL(false); } } Datum --- 425,437 ---- inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) ! && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0); } + + PG_RETURN_BOOL(false); } Datum *************** *** 439,456 **** inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) { PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) ! && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0); ! } ! else ! { ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "cannot compare address families %d and %d", ! ip_family(a1), ip_family(a2)); ! PG_RETURN_BOOL(false); } } Datum --- 440,452 ---- inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) ! && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0); } + + PG_RETURN_BOOL(false); } Datum *************** *** 459,476 **** inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) { PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) ! && v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0); ! } ! else ! { ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "cannot compare address families %d and %d", ! ip_family(a1), ip_family(a2)); ! PG_RETURN_BOOL(false); } } /* --- 455,467 ---- inet *a1 = PG_GETARG_INET_P(0); inet *a2 = PG_GETARG_INET_P(1); ! if (ip_family(a1) == ip_family(a2)) { PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) ! && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0); } + + PG_RETURN_BOOL(false); } /* *************** *** 482,500 **** inet *ip = PG_GETARG_INET_P(0); text *ret; int len; ! char *ptr, ! tmp[sizeof("255.255.255.255/32")]; ! if (ip_family(ip) == AF_INET) ! { ! /* It's an IP V4 address: */ ! /* force display of 32 bits, regardless of masklen... */ ! if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL) ! elog(ERROR, "unable to print host (%s)", strerror(errno)); ! } ! else ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "unknown address family (%d)", ip_family(ip)); /* Suppress /n if present (shouldn't happen now) */ if ((ptr = strchr(tmp, '/')) != NULL) --- 473,485 ---- inet *ip = PG_GETARG_INET_P(0); text *ret; int len; ! char *ptr; ! char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; ! /* force display of max bits, regardless of masklen... */ ! if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip), ! tmp, sizeof(tmp)) == NULL) ! elog(ERROR, "unable to print host (%s)", strerror(errno)); /* Suppress /n if present (shouldn't happen now) */ if ((ptr = strchr(tmp, '/')) != NULL) *************** *** 514,537 **** inet *ip = PG_GETARG_INET_P(0); text *ret; int len; ! char tmp[sizeof("255.255.255.255/32")]; ! if (ip_family(ip) == AF_INET) { ! /* It's an IP V4 address: */ ! /* force display of 32 bits, regardless of masklen... */ ! if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL) ! elog(ERROR, "unable to print host (%s)", strerror(errno)); ! /* Add /n if not present (which it won't be) */ ! if (strchr(tmp, '/') == NULL) ! { ! len = strlen(tmp); ! snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip)); ! } } - else - /* Go for an IPV6 address here, before faulting out: */ - elog(ERROR, "unknown address family (%d)", ip_family(ip)); /* Return string as a text datum */ len = strlen(tmp); --- 499,515 ---- inet *ip = PG_GETARG_INET_P(0); text *ret; int len; ! char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; ! if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip), ! tmp, sizeof(tmp)) == NULL) ! elog(ERROR, "unable to print host (%s)", strerror(errno)); ! /* Add /n if not present (which it won't be) */ ! if (strchr(tmp, '/') == NULL) { ! len = strlen(tmp); ! snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip)); } /* Return string as a text datum */ len = strlen(tmp); *************** *** 548,571 **** text *ret; char *dst; int len; ! char tmp[sizeof("255.255.255.255/32")]; ! if (ip_family(ip) == AF_INET) ! { ! /* It's an IP V4 address: */ ! if (ip_type(ip)) ! dst = inet_cidr_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip), ! tmp, sizeof(tmp)); ! else ! dst = inet_net_ntop(AF_INET, &ip_v4addr(ip), ip_bits(ip), ! tmp, sizeof(tmp)); ! ! if (dst == NULL) ! elog(ERROR, "unable to print address (%s)", strerror(errno)); ! } ! else ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "unknown address family (%d)", ip_family(ip)); /* Return string as a text datum */ len = strlen(tmp); --- 526,543 ---- text *ret; char *dst; int len; ! char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; ! if (ip_type(ip)) ! dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip), ! ip_bits(ip), tmp, sizeof(tmp)); ! else ! dst = inet_net_ntop(ip_family(ip), ip_addr(ip), ! ip_bits(ip), tmp, sizeof(tmp)); ! ! if (dst == NULL) ! elog(ERROR, "unable to print address (%s)", ! strerror(errno)); /* Return string as a text datum */ len = strlen(tmp); *************** *** 584,622 **** } Datum network_broadcast(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *dst; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! if (ip_family(ip) == AF_INET) ! { ! /* It's an IP V4 address: */ ! unsigned long mask = 0xffffffff; ! ! /* ! * Shifting by 32 or more bits does not yield portable results, so ! * don't try it. ! */ ! if (ip_bits(ip) < 32) ! mask >>= ip_bits(ip); ! else ! mask = 0; ! ! ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask); } - else - /* Go for an IPV6 address here, before faulting out: */ - elog(ERROR, "unknown address family (%d)", ip_family(ip)); ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_bits(ip); ip_type(dst) = 0; VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); PG_RETURN_INET_P(dst); --- 556,621 ---- } Datum + network_family(PG_FUNCTION_ARGS) + { + inet *ip = PG_GETARG_INET_P(0); + + switch (ip_family(ip)) { + case PGSQL_AF_INET: + PG_RETURN_INT32(4); + break; + case PGSQL_AF_INET6: + PG_RETURN_INT32(6); + break; + default: + PG_RETURN_INT32(0); + break; + } + } + + Datum network_broadcast(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *dst; + int byte; + int bits; + int maxbytes; + unsigned char mask; + unsigned char *a, *b; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! if (ip_family(ip) == PGSQL_AF_INET) { ! maxbytes = 4; ! } else { ! maxbytes = 16; ! } ! ! bits = ip_bits(ip); ! a = ip_addr(ip); ! b = ip_addr(dst); ! ! for (byte = 0 ; byte < maxbytes ; byte++) { ! if (bits >= 8) { ! mask = 0x00; ! bits -= 8; ! } else if (bits == 0) { ! mask = 0xff; ! } else { ! mask = 0xff >> bits; ! bits = 0; ! } ! ! b[byte] = a[byte] | mask; } ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_bits(ip); ip_type(dst) = 0; VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *)ip_addr(dst) - (char *)VARDATA(dst)) + ip_addrsize(dst); PG_RETURN_INET_P(dst); *************** *** 627,661 **** { inet *ip = PG_GETARG_INET_P(0); inet *dst; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! if (ip_family(ip) == AF_INET) ! { ! /* It's an IP V4 address: */ ! unsigned long mask = 0xffffffff; ! ! /* ! * Shifting by 32 or more bits does not yield portable results, so ! * don't try it. ! */ ! if (ip_bits(ip) > 0) ! mask <<= (32 - ip_bits(ip)); ! else ! mask = 0; ! ! ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask); } - else - /* Go for an IPV6 address here, before faulting out: */ - elog(ERROR, "unknown address family (%d)", ip_family(ip)); ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_bits(ip); ip_type(dst) = 1; VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); PG_RETURN_INET_P(dst); --- 626,669 ---- { inet *ip = PG_GETARG_INET_P(0); inet *dst; + int byte; + int bits; + int maxbytes; + unsigned char mask; + unsigned char *a, *b; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! if (ip_family(ip) == PGSQL_AF_INET) { ! maxbytes = 4; ! } else { ! maxbytes = 16; ! } ! ! bits = ip_bits(ip); ! a = ip_addr(ip); ! b = ip_addr(dst); ! ! byte = 0; ! while (bits) { ! if (bits >= 8) { ! mask = 0xff; ! bits -= 8; ! } else { ! mask = 0xff << (8 - bits); ! bits = 0; ! } ! ! b[byte] = a[byte] & mask; ! byte++; } ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_bits(ip); ip_type(dst) = 1; VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *)ip_addr(dst) - (char *)VARDATA(dst)) + ip_addrsize(dst); PG_RETURN_INET_P(dst); *************** *** 666,701 **** { inet *ip = PG_GETARG_INET_P(0); inet *dst; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! if (ip_family(ip) == AF_INET) ! { ! /* It's an IP V4 address: */ ! unsigned long mask = 0xffffffff; ! ! /* ! * Shifting by 32 or more bits does not yield portable results, so ! * don't try it. ! */ ! if (ip_bits(ip) > 0) ! mask <<= (32 - ip_bits(ip)); ! else ! mask = 0; ! ! ip_v4addr(dst) = htonl(mask); ! ! ip_bits(dst) = 32; } - else - /* Go for an IPV6 address here, before faulting out: */ - elog(ERROR, "unknown address family (%d)", ip_family(ip)); ip_family(dst) = ip_family(ip); ip_type(dst) = 0; VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); PG_RETURN_INET_P(dst); --- 674,716 ---- { inet *ip = PG_GETARG_INET_P(0); inet *dst; + int byte; + int bits; + int maxbytes; + unsigned char mask; + unsigned char *b; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); ! if (ip_family(ip) == PGSQL_AF_INET) { ! maxbytes = 4; ! } else { ! maxbytes = 16; ! } ! ! bits = ip_bits(ip); ! b = ip_addr(dst); ! ! byte = 0; ! while (bits) { ! if (bits >= 8) { ! mask = 0xff; ! bits -= 8; ! } else { ! mask = 0xff << (8 - bits); ! bits = 0; ! } ! ! b[byte] = mask; ! byte++; } ip_family(dst) = ip_family(ip); + ip_bits(dst) = ip_bits(ip); ip_type(dst) = 0; VARATT_SIZEP(dst) = VARHDRSZ ! + ((char *)ip_addr(dst) - (char *)VARDATA(dst)) + ip_addrsize(dst); PG_RETURN_INET_P(dst); *************** *** 760,771 **** case CIDROID: { inet *ip = DatumGetInetP(value); ! ! if (ip_family(ip) == AF_INET) ! return (double) ip_v4addr(ip); else ! /* Go for an IPV6 address here, before faulting out: */ ! elog(ERROR, "unknown address family (%d)", ip_family(ip)); break; } case MACADDROID: --- 775,800 ---- case CIDROID: { inet *ip = DatumGetInetP(value); ! int len; ! double res; ! int i; ! ! /* ! * Note that we don't use the full address ! * here. ! */ ! if (ip_family(ip) == PGSQL_AF_INET) ! len = 4; else ! len = 5; ! ! res = ip_family(ip); ! for (i = 0 ; i < len ; i++) { ! res *= 256; ! res += ip_addr(ip)[i]; ! } ! return res; ! break; } case MACADDROID: *************** *** 788,840 **** return 0; } - /* ! * Bitwise comparison for V4 addresses. Add V6 implementation! */ - static int ! v4bitncmp(unsigned long a1, unsigned long a2, int bits) { ! unsigned long mask; ! /* ! * Shifting by 32 or more bits does not yield portable results, so ! * don't try it. ! */ ! if (bits > 0) ! mask = (0xFFFFFFFFL << (32 - bits)) & 0xFFFFFFFFL; ! else ! mask = 0; ! a1 = ntohl(a1); ! a2 = ntohl(a2); ! if ((a1 & mask) < (a2 & mask)) ! return (-1); ! else if ((a1 & mask) > (a2 & mask)) ! return (1); return (0); } - /* - * Returns true if given address fits fully within the specified bit width. - */ static bool ! v4addressOK(unsigned long a1, int bits) { ! unsigned long mask; ! /* ! * Shifting by 32 or more bits does not yield portable results, so ! * don't try it. ! */ ! if (bits > 0) ! mask = (0xFFFFFFFFL << (32 - bits)) & 0xFFFFFFFFL; ! else ! mask = 0; ! a1 = ntohl(a1); ! if ((a1 & mask) == a1) ! return true; ! return false; } --- 817,894 ---- return 0; } /* ! * int ! * bitncmp(l, r, n) ! * compare bit masks l and r, for n bits. ! * return: ! * -1, 1, or 0 in the libc tradition. ! * note: ! * network byte order assumed. this means 192.5.5.240/28 has ! * 0x11110000 in its fourth octet. ! * author: ! * Paul Vixie (ISC), June 1996 */ static int ! bitncmp(void *l, void *r, int n) { ! u_int lb, rb; ! int x, b; ! b = n / 8; ! x = memcmp(l, r, b); ! if (x) ! return (x); ! ! lb = ((const u_char *)l)[b]; ! rb = ((const u_char *)r)[b]; ! for (b = n % 8; b > 0; b--) { ! if ((lb & 0x80) != (rb & 0x80)) { ! if (lb & 0x80) ! return (1); ! return (-1); ! } ! lb <<= 1; ! rb <<= 1; ! } return (0); } static bool ! addressOK(unsigned char *a, int bits, int family) { ! int byte; ! int nbits; ! int maxbits; ! int maxbytes; ! unsigned char mask; ! ! if (family == PGSQL_AF_INET) { ! maxbits = 32; ! maxbytes = 4; ! } else { ! maxbits = 128; ! maxbytes = 16; ! } ! assert(bits <= maxbits); ! ! if (bits == maxbits) ! return 1; ! ! byte = (bits + 7) / 8; ! nbits = bits % 8; ! mask = 0xff; ! if (bits != 0) ! mask >>= nbits; ! ! while (byte < maxbytes) { ! if ((a[byte] & mask) != 0) ! return 0; ! mask = 0xff; ! byte++; ! } ! return 1; } *************** *** 852,866 **** /* * return "last" IP on a given network. It's the broadcast address, ! * however, masklen has to be set to 32, since * 192.168.0.255/24 is considered less than 192.168.0.255/32 * ! * NB: this is not IPv6 ready ... */ Datum network_scan_last(Datum in) { return DirectFunctionCall2(inet_set_masklen, DirectFunctionCall1(network_broadcast, in), ! Int32GetDatum(32)); } --- 906,921 ---- /* * return "last" IP on a given network. It's the broadcast address, ! * however, masklen has to be set to its max btis, since * 192.168.0.255/24 is considered less than 192.168.0.255/32 * ! * inet_set_masklen() hacked to max out the masklength to 128 for IPv6 ! * and 32 for IPv4 when given '-1' as argument. */ Datum network_scan_last(Datum in) { return DirectFunctionCall2(inet_set_masklen, DirectFunctionCall1(network_broadcast, in), ! Int32GetDatum(-1)); } Index: src/include/catalog/catversion.h =================================================================== RCS file: /cvsroot/pgsql-server/src/include/catalog/catversion.h,v retrieving revision 1.198 diff -c -c -r1.198 catversion.h *** src/include/catalog/catversion.h 6 Jun 2003 15:04:02 -0000 1.198 --- src/include/catalog/catversion.h 12 Jun 2003 05:13:20 -0000 *************** *** 53,58 **** */ /* yyyymmddN */ ! #define CATALOG_VERSION_NO 200306051 #endif --- 53,58 ---- */ /* yyyymmddN */ ! #define CATALOG_VERSION_NO 200306121 #endif Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v retrieving revision 1.303 diff -c -c -r1.303 pg_proc.h *** src/include/catalog/pg_proc.h 11 Jun 2003 09:23:55 -0000 1.303 --- src/include/catalog/pg_proc.h 12 Jun 2003 05:13:24 -0000 *************** *** 2377,2382 **** --- 2377,2384 ---- DESCR("show address octets only"); DATA(insert OID = 730 ( text PGNSP PGUID 12 f f t f i 1 25 "869" network_show - _null_ )); DESCR("show all parts of inet/cidr value"); + DATA(insert OID = 715 ( family PGNSP PGUID 12 f f t f i 1 23 "869" network_family - _null_ )); + DESCR("return address family (4 for IPv4, 6 for IPv6)"); DATA(insert OID = 1362 ( hostmask PGNSP PGUID 12 f f t f i 1 869 "869" network_hostmask - _null_ )); DESCR("hostmask of address"); DATA(insert OID = 1713 ( inet PGNSP PGUID 12 f f t f i 1 869 "25" text_inet - _null_ )); Index: src/include/utils/builtins.h =================================================================== RCS file: /cvsroot/pgsql-server/src/include/utils/builtins.h,v retrieving revision 1.219 diff -c -c -r1.219 builtins.h *** src/include/utils/builtins.h 26 May 2003 00:11:28 -0000 1.219 --- src/include/utils/builtins.h 12 Jun 2003 05:13:25 -0000 *************** *** 644,649 **** --- 644,650 ---- extern Datum network_netmask(PG_FUNCTION_ARGS); extern Datum network_hostmask(PG_FUNCTION_ARGS); extern Datum network_masklen(PG_FUNCTION_ARGS); + extern Datum network_family(PG_FUNCTION_ARGS); extern Datum network_broadcast(PG_FUNCTION_ARGS); extern Datum network_host(PG_FUNCTION_ARGS); extern Datum network_show(PG_FUNCTION_ARGS); Index: src/include/utils/inet.h =================================================================== RCS file: /cvsroot/pgsql-server/src/include/utils/inet.h,v retrieving revision 1.13 diff -c -c -r1.13 inet.h *** src/include/utils/inet.h 20 Jun 2002 20:29:53 -0000 1.13 --- src/include/utils/inet.h 12 Jun 2003 05:13:25 -0000 *************** *** 23,34 **** unsigned char family; unsigned char bits; unsigned char type; ! union ! { ! unsigned int ipv4_addr; /* network byte order */ ! /* add IPV6 address type here */ ! } addr; } inet_struct; /* * Both INET and CIDR addresses are represented within Postgres as varlena --- 23,40 ---- unsigned char family; unsigned char bits; unsigned char type; ! unsigned char ip_addr[16]; /* 128 bits of address */ } inet_struct; + + /* + * Referencing all of the non-AF_INET types to AF_INET lets us work on + * machines which may not have the appropriate address family (like + * inet6 addresses when AF_INET6 isn't present) but doesn't cause a + * dump/reload requirement. Existing databases used AF_INET for the family + * type on disk. + */ + #define PGSQL_AF_INET (AF_INET + 0) + #define PGSQL_AF_INET6 (AF_INET + 1) /* * Both INET and CIDR addresses are represented within Postgres as varlena Index: src/test/regress/expected/inet.out =================================================================== RCS file: /cvsroot/pgsql-server/src/test/regress/expected/inet.out,v retrieving revision 1.15 diff -c -c -r1.15 inet.out *** src/test/regress/expected/inet.out 15 Jan 2003 20:01:01 -0000 1.15 --- src/test/regress/expected/inet.out 12 Jun 2003 05:13:26 -0000 *************** *** 19,128 **** INSERT INTO INET_TBL (c, i) VALUES ('10', '10.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8'); -- check that CIDR rejects invalid input: INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226'); ERROR: invalid CIDR value '192.168.1.2/24': has bits set to right of mask -- check that CIDR rejects invalid input when converting from text: INSERT INTO INET_TBL (c, i) VALUES (cidr('192.168.1.2/24'), '192.168.1.226'); ERROR: invalid CIDR value '192.168.1.2/24': has bits set to right of mask SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; ! ten | cidr | inet ! -----+----------------+------------------ ! | 192.168.1.0/24 | 192.168.1.226/24 ! | 192.168.1.0/24 | 192.168.1.226 ! | 192.168.1.0/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/25 ! | 192.168.1.0/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/25 ! | 10.0.0.0/8 | 10.1.2.3/8 ! | 10.0.0.0/32 | 10.1.2.3/8 ! | 10.1.2.3/32 | 10.1.2.3 ! | 10.1.2.0/24 | 10.1.2.3/24 ! | 10.1.0.0/16 | 10.1.2.3/16 ! | 10.0.0.0/8 | 10.1.2.3/8 ! | 10.0.0.0/8 | 11.1.2.3/8 ! | 10.0.0.0/8 | 9.1.2.3/8 ! (14 rows) -- now test some support functions ! SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL; ! ten | inet | host | text ! -----+------------------+---------------+------------------ ! | 192.168.1.226/24 | 192.168.1.226 | 192.168.1.226/24 ! | 192.168.1.226 | 192.168.1.226 | 192.168.1.226/32 ! | 192.168.1.0/24 | 192.168.1.0 | 192.168.1.0/24 ! | 192.168.1.0/25 | 192.168.1.0 | 192.168.1.0/25 ! | 192.168.1.255/24 | 192.168.1.255 | 192.168.1.255/24 ! | 192.168.1.255/25 | 192.168.1.255 | 192.168.1.255/25 ! | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 ! | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 ! | 10.1.2.3 | 10.1.2.3 | 10.1.2.3/32 ! | 10.1.2.3/24 | 10.1.2.3 | 10.1.2.3/24 ! | 10.1.2.3/16 | 10.1.2.3 | 10.1.2.3/16 ! | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 ! | 11.1.2.3/8 | 11.1.2.3 | 11.1.2.3/8 ! | 9.1.2.3/8 | 9.1.2.3 | 9.1.2.3/8 ! (14 rows) SELECT '' AS ten, c AS cidr, broadcast(c), i AS inet, broadcast(i) FROM INET_TBL; ! ten | cidr | broadcast | inet | broadcast ! -----+----------------+------------------+------------------+------------------ ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226 | 192.168.1.226 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/25 | 192.168.1.127/25 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/25 | 192.168.1.255/25 ! | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 ! | 10.0.0.0/32 | 10.0.0.0 | 10.1.2.3/8 | 10.255.255.255/8 ! | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3 ! | 10.1.2.0/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24 ! | 10.1.0.0/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16 ! | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 ! | 10.0.0.0/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8 ! | 10.0.0.0/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8 ! (14 rows) SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", i AS inet, network(i) AS "network(inet)" FROM INET_TBL; ! ten | cidr | network(cidr) | inet | network(inet) ! -----+----------------+----------------+------------------+------------------ ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226 | 192.168.1.226/32 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/25 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/25 | 192.168.1.128/25 ! | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 ! | 10.0.0.0/32 | 10.0.0.0/32 | 10.1.2.3/8 | 10.0.0.0/8 ! | 10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3/32 ! | 10.1.2.0/24 | 10.1.2.0/24 | 10.1.2.3/24 | 10.1.2.0/24 ! | 10.1.0.0/16 | 10.1.0.0/16 | 10.1.2.3/16 | 10.1.0.0/16 ! | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 ! | 10.0.0.0/8 | 10.0.0.0/8 | 11.1.2.3/8 | 11.0.0.0/8 ! | 10.0.0.0/8 | 10.0.0.0/8 | 9.1.2.3/8 | 9.0.0.0/8 ! (14 rows) SELECT '' AS ten, c AS cidr, masklen(c) AS "masklen(cidr)", i AS inet, masklen(i) AS "masklen(inet)" FROM INET_TBL; ! ten | cidr | masklen(cidr) | inet | masklen(inet) ! -----+----------------+---------------+------------------+--------------- ! | 192.168.1.0/24 | 24 | 192.168.1.226/24 | 24 ! | 192.168.1.0/24 | 24 | 192.168.1.226 | 32 ! | 192.168.1.0/24 | 24 | 192.168.1.0/24 | 24 ! | 192.168.1.0/24 | 24 | 192.168.1.0/25 | 25 ! | 192.168.1.0/24 | 24 | 192.168.1.255/24 | 24 ! | 192.168.1.0/24 | 24 | 192.168.1.255/25 | 25 ! | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8 ! | 10.0.0.0/32 | 32 | 10.1.2.3/8 | 8 ! | 10.1.2.3/32 | 32 | 10.1.2.3 | 32 ! | 10.1.2.0/24 | 24 | 10.1.2.3/24 | 24 ! | 10.1.0.0/16 | 16 | 10.1.2.3/16 | 16 ! | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8 ! | 10.0.0.0/8 | 8 | 11.1.2.3/8 | 8 ! | 10.0.0.0/8 | 8 | 9.1.2.3/8 | 8 ! (14 rows) SELECT '' AS four, c AS cidr, masklen(c) AS "masklen(cidr)", i AS inet, masklen(i) AS "masklen(inet)" FROM INET_TBL --- 19,150 ---- INSERT INTO INET_TBL (c, i) VALUES ('10', '10.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8'); + INSERT INTO INET_TBL (c, i) VALUES ('10:23::f1', '10:23::f1/64'); + INSERT INTO INET_TBL (c, i) VALUES ('10:23::8000/113', '10:23::ffff'); + INSERT INTO INET_TBL (c, i) VALUES ('::ffff:1.2.3.4', '::4.3.2.1/24'); -- check that CIDR rejects invalid input: INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226'); ERROR: invalid CIDR value '192.168.1.2/24': has bits set to right of mask + INSERT INTO INET_TBL (c, i) VALUES ('1234::1234::1234', '::1.2.3.4'); + ERROR: invalid CIDR value '1234::1234::1234' -- check that CIDR rejects invalid input when converting from text: INSERT INTO INET_TBL (c, i) VALUES (cidr('192.168.1.2/24'), '192.168.1.226'); ERROR: invalid CIDR value '192.168.1.2/24': has bits set to right of mask + INSERT INTO INET_TBL (c, i) VALUES (cidr('ffff:ffff:ffff:ffff::/24'), '::192.168.1.226'); + ERROR: invalid CIDR value 'ffff:ffff:ffff:ffff::/24': has bits set to right of mask SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; ! ten | cidr | inet ! -----+--------------------+------------------ ! | 192.168.1.0/24 | 192.168.1.226/24 ! | 192.168.1.0/24 | 192.168.1.226 ! | 192.168.1.0/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/25 ! | 192.168.1.0/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/25 ! | 10.0.0.0/8 | 10.1.2.3/8 ! | 10.0.0.0/32 | 10.1.2.3/8 ! | 10.1.2.3/32 | 10.1.2.3 ! | 10.1.2.0/24 | 10.1.2.3/24 ! | 10.1.0.0/16 | 10.1.2.3/16 ! | 10.0.0.0/8 | 10.1.2.3/8 ! | 10.0.0.0/8 | 11.1.2.3/8 ! | 10.0.0.0/8 | 9.1.2.3/8 ! | 10:23::f1/128 | 10:23::f1/64 ! | 10:23::8000/113 | 10:23::ffff ! | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 ! (17 rows) -- now test some support functions ! SELECT '' AS ten, i AS inet, host(i), text(i), family(i) FROM INET_TBL; ! ten | inet | host | text | family ! -----+------------------+---------------+------------------+-------- ! | 192.168.1.226/24 | 192.168.1.226 | 192.168.1.226/24 | 4 ! | 192.168.1.226 | 192.168.1.226 | 192.168.1.226/32 | 4 ! | 192.168.1.0/24 | 192.168.1.0 | 192.168.1.0/24 | 4 ! | 192.168.1.0/25 | 192.168.1.0 | 192.168.1.0/25 | 4 ! | 192.168.1.255/24 | 192.168.1.255 | 192.168.1.255/24 | 4 ! | 192.168.1.255/25 | 192.168.1.255 | 192.168.1.255/25 | 4 ! | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 4 ! | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 4 ! | 10.1.2.3 | 10.1.2.3 | 10.1.2.3/32 | 4 ! | 10.1.2.3/24 | 10.1.2.3 | 10.1.2.3/24 | 4 ! | 10.1.2.3/16 | 10.1.2.3 | 10.1.2.3/16 | 4 ! | 10.1.2.3/8 | 10.1.2.3 | 10.1.2.3/8 | 4 ! | 11.1.2.3/8 | 11.1.2.3 | 11.1.2.3/8 | 4 ! | 9.1.2.3/8 | 9.1.2.3 | 9.1.2.3/8 | 4 ! | 10:23::f1/64 | 10:23::f1 | 10:23::f1/64 | 6 ! | 10:23::ffff | 10:23::ffff | 10:23::ffff/128 | 6 ! | ::4.3.2.1/24 | ::4.3.2.1 | ::4.3.2.1/24 | 6 ! (17 rows) SELECT '' AS ten, c AS cidr, broadcast(c), i AS inet, broadcast(i) FROM INET_TBL; ! ten | cidr | broadcast | inet | broadcast ! -----+--------------------+------------------+------------------+--------------------------------------- ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226 | 192.168.1.226 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/25 | 192.168.1.127/25 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 | 192.168.1.255/24 ! | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/25 | 192.168.1.255/25 ! | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 ! | 10.0.0.0/32 | 10.0.0.0 | 10.1.2.3/8 | 10.255.255.255/8 ! | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3 ! | 10.1.2.0/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24 ! | 10.1.0.0/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16 ! | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 ! | 10.0.0.0/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8 ! | 10.0.0.0/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8 ! | 10:23::f1/128 | 10:23::f1 | 10:23::f1/64 | 10:23::ffff:ffff:ffff:ffff/64 ! | 10:23::8000/113 | 10:23::ffff/113 | 10:23::ffff | 10:23::ffff ! | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4 | ::4.3.2.1/24 | 0:ff:ffff:ffff:ffff:ffff:ffff:ffff/24 ! (17 rows) SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", i AS inet, network(i) AS "network(inet)" FROM INET_TBL; ! ten | cidr | network(cidr) | inet | network(inet) ! -----+--------------------+--------------------+------------------+------------------ ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226 | 192.168.1.226/32 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/25 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 ! | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/25 | 192.168.1.128/25 ! | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 ! | 10.0.0.0/32 | 10.0.0.0/32 | 10.1.2.3/8 | 10.0.0.0/8 ! | 10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3/32 ! | 10.1.2.0/24 | 10.1.2.0/24 | 10.1.2.3/24 | 10.1.2.0/24 ! | 10.1.0.0/16 | 10.1.0.0/16 | 10.1.2.3/16 | 10.1.0.0/16 ! | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 ! | 10.0.0.0/8 | 10.0.0.0/8 | 11.1.2.3/8 | 11.0.0.0/8 ! | 10.0.0.0/8 | 10.0.0.0/8 | 9.1.2.3/8 | 9.0.0.0/8 ! | 10:23::f1/128 | 10:23::f1/128 | 10:23::f1/64 | 10:23::/64 ! | 10:23::8000/113 | 10:23::8000/113 | 10:23::ffff | 10:23::ffff/128 ! | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 | ::/24 ! (17 rows) SELECT '' AS ten, c AS cidr, masklen(c) AS "masklen(cidr)", i AS inet, masklen(i) AS "masklen(inet)" FROM INET_TBL; ! ten | cidr | masklen(cidr) | inet | masklen(inet) ! -----+--------------------+---------------+------------------+--------------- ! | 192.168.1.0/24 | 24 | 192.168.1.226/24 | 24 ! | 192.168.1.0/24 | 24 | 192.168.1.226 | 32 ! | 192.168.1.0/24 | 24 | 192.168.1.0/24 | 24 ! | 192.168.1.0/24 | 24 | 192.168.1.0/25 | 25 ! | 192.168.1.0/24 | 24 | 192.168.1.255/24 | 24 ! | 192.168.1.0/24 | 24 | 192.168.1.255/25 | 25 ! | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8 ! | 10.0.0.0/32 | 32 | 10.1.2.3/8 | 8 ! | 10.1.2.3/32 | 32 | 10.1.2.3 | 32 ! | 10.1.2.0/24 | 24 | 10.1.2.3/24 | 24 ! | 10.1.0.0/16 | 16 | 10.1.2.3/16 | 16 ! | 10.0.0.0/8 | 8 | 10.1.2.3/8 | 8 ! | 10.0.0.0/8 | 8 | 11.1.2.3/8 | 8 ! | 10.0.0.0/8 | 8 | 9.1.2.3/8 | 8 ! | 10:23::f1/128 | 128 | 10:23::f1/64 | 64 ! | 10:23::8000/113 | 113 | 10:23::ffff | 128 ! | ::ffff:1.2.3.4/128 | 128 | ::4.3.2.1/24 | 24 ! (17 rows) SELECT '' AS four, c AS cidr, masklen(c) AS "masklen(cidr)", i AS inet, masklen(i) AS "masklen(inet)" FROM INET_TBL *************** *** 149,171 **** i << c AS sb, i <<= c AS sbe, i >> c AS sup, i >>= c AS spe FROM INET_TBL; ! ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe ! -----+------------------+----------------+----+----+----+----+----+----+----+-----+-----+----- ! | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t ! | 192.168.1.226 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f ! | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t ! | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f ! | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t ! | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f ! | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t ! | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t ! | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t ! | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t ! | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t ! | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t ! | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f ! | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f ! (14 rows) -- check the conversion to/from text and set_netmask SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL; --- 171,196 ---- i << c AS sb, i <<= c AS sbe, i >> c AS sup, i >>= c AS spe FROM INET_TBL; ! ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe ! -----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+----- ! | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t ! | 192.168.1.226 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f ! | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t ! | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f ! | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t ! | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f ! | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t ! | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t ! | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t ! | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t ! | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t ! | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t ! | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f ! | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f ! | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t ! | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f ! | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t ! (17 rows) -- check the conversion to/from text and set_netmask SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL; *************** *** 185,191 **** | 10.1.2.3/24 | 11.1.2.3/24 | 9.1.2.3/24 ! (14 rows) -- check that index works correctly CREATE INDEX inet_idx1 ON inet_tbl(i); --- 210,219 ---- | 10.1.2.3/24 | 11.1.2.3/24 | 9.1.2.3/24 ! | 10:23::f1/24 ! | 10:23::ffff/24 ! | ::4.3.2.1/24 ! (17 rows) -- check that index works correctly CREATE INDEX inet_idx1 ON inet_tbl(i); Index: src/test/regress/sql/inet.sql =================================================================== RCS file: /cvsroot/pgsql-server/src/test/regress/sql/inet.sql,v retrieving revision 1.9 diff -c -c -r1.9 inet.sql *** src/test/regress/sql/inet.sql 15 Jan 2003 20:01:01 -0000 1.9 --- src/test/regress/sql/inet.sql 12 Jun 2003 05:13:26 -0000 *************** *** 20,35 **** INSERT INTO INET_TBL (c, i) VALUES ('10', '10.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8'); -- check that CIDR rejects invalid input: INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226'); -- check that CIDR rejects invalid input when converting from text: INSERT INTO INET_TBL (c, i) VALUES (cidr('192.168.1.2/24'), '192.168.1.226'); ! SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; -- now test some support functions ! SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL; SELECT '' AS ten, c AS cidr, broadcast(c), i AS inet, broadcast(i) FROM INET_TBL; SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", --- 20,39 ---- INSERT INTO INET_TBL (c, i) VALUES ('10', '10.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8'); INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8'); + INSERT INTO INET_TBL (c, i) VALUES ('10:23::f1', '10:23::f1/64'); + INSERT INTO INET_TBL (c, i) VALUES ('10:23::8000/113', '10:23::ffff'); + INSERT INTO INET_TBL (c, i) VALUES ('::ffff:1.2.3.4', '::4.3.2.1/24'); -- check that CIDR rejects invalid input: INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226'); + INSERT INTO INET_TBL (c, i) VALUES ('1234::1234::1234', '::1.2.3.4'); -- check that CIDR rejects invalid input when converting from text: INSERT INTO INET_TBL (c, i) VALUES (cidr('192.168.1.2/24'), '192.168.1.226'); ! INSERT INTO INET_TBL (c, i) VALUES (cidr('ffff:ffff:ffff:ffff::/24'), '::192.168.1.226'); SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; -- now test some support functions ! SELECT '' AS ten, i AS inet, host(i), text(i), family(i) FROM INET_TBL; SELECT '' AS ten, c AS cidr, broadcast(c), i AS inet, broadcast(i) FROM INET_TBL; SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",