diff options
Diffstat (limited to 'src/backend/utils/adt/network.c')
-rw-r--r-- | src/backend/utils/adt/network.c | 736 |
1 files changed, 0 insertions, 736 deletions
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c deleted file mode 100644 index 40044921747..00000000000 --- a/src/backend/utils/adt/network.c +++ /dev/null @@ -1,736 +0,0 @@ -/* - * 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/src/backend/utils/adt/network.c,v 1.34 2001/10/25 05:49:45 momjian Exp $ - * - * Jon Postel RIP 16 Oct 1998 - */ - -#include "postgres.h" - -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include "catalog/pg_type.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) - -#define ip_bits(inetptr) \ - (((inet_struct *)VARDATA(inetptr))->bits) - -#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; - - dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct)); - /* make sure any unused bits in a CIDR value are zeroed */ - MemSet(dst, 0, 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; - - return dst; -} - -/* INET address reader. */ -Datum -inet_in(PG_FUNCTION_ARGS) -{ - char *src = PG_GETARG_CSTRING(0); - - PG_RETURN_INET_P(network_in(src, 0)); -} - -/* CIDR address reader. */ -Datum -cidr_in(PG_FUNCTION_ARGS) -{ - char *src = PG_GETARG_CSTRING(0); - - PG_RETURN_INET_P(network_in(src, 1)); -} - -/* - * INET address output function. - */ -Datum -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)); -} - - -/* share code with INET case */ -Datum -cidr_out(PG_FUNCTION_ARGS) -{ - return inet_out(fcinfo); -} - - -static Datum -text_network(text *src, int type) -{ - int len = VARSIZE(src) - VARHDRSZ; - - char *str = palloc(len + 1); - - memcpy(str, VARDATA(src), len); - *(str + len) = '\0'; - - PG_RETURN_INET_P(network_in(str, type)); -} - -Datum -text_cidr(PG_FUNCTION_ARGS) -{ - return text_network(PG_GETARG_TEXT_P(0), 1); -} - -Datum -text_inet(PG_FUNCTION_ARGS) -{ - return text_network(PG_GETARG_TEXT_P(0), 0); -} - -Datum -inet_set_masklen(PG_FUNCTION_ARGS) -{ - inet *src = PG_GETARG_INET_P(0); - 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)); - memcpy(dst, src, VARHDRSZ + sizeof(inet_struct)); - - ip_bits(dst) = bits; - - PG_RETURN_INET_P(dst); -} - -/* - * Basic comparison function for sorting and inet/cidr comparisons. - * - * Comparison is first on the common bits of the network part, then on - * the length of the network part, and then on the whole unmasked address. - * The effect is that the network part is the major sort key, and for - * equal network parts we sort on the host part. Note this is only sane - * for CIDR if address bits to the right of the mask are guaranteed zero; - * otherwise logically-equal CIDRs might compare different. - */ - -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 -network_cmp(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_INT32(network_cmp_internal(a1, a2)); -} - -/* - * Boolean ordering tests. - */ -Datum -network_lt(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_BOOL(network_cmp_internal(a1, a2) < 0); -} - -Datum -network_le(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_BOOL(network_cmp_internal(a1, a2) <= 0); -} - -Datum -network_eq(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_BOOL(network_cmp_internal(a1, a2) == 0); -} - -Datum -network_ge(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_BOOL(network_cmp_internal(a1, a2) >= 0); -} - -Datum -network_gt(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_BOOL(network_cmp_internal(a1, a2) > 0); -} - -Datum -network_ne(PG_FUNCTION_ARGS) -{ - inet *a1 = PG_GETARG_INET_P(0); - inet *a2 = PG_GETARG_INET_P(1); - - PG_RETURN_BOOL(network_cmp_internal(a1, a2) != 0); -} - -/* - * Boolean network-inclusion tests. - */ -Datum -network_sub(PG_FUNCTION_ARGS) -{ - 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 -network_subeq(PG_FUNCTION_ARGS) -{ - 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 -network_sup(PG_FUNCTION_ARGS) -{ - 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 -network_supeq(PG_FUNCTION_ARGS) -{ - 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); - } -} - -/* - * Extract data from a network datatype. - */ -Datum -network_host(PG_FUNCTION_ARGS) -{ - 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) - *ptr = '\0'; - - /* Return string as a text datum */ - len = strlen(tmp); - ret = (text *) palloc(len + VARHDRSZ); - VARATT_SIZEP(ret) = len + VARHDRSZ; - memcpy(VARDATA(ret), tmp, len); - PG_RETURN_TEXT_P(ret); -} - -Datum -network_show(PG_FUNCTION_ARGS) -{ - 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); - ret = (text *) palloc(len + VARHDRSZ); - VARATT_SIZEP(ret) = len + VARHDRSZ; - memcpy(VARDATA(ret), tmp, len); - PG_RETURN_TEXT_P(ret); -} - -Datum -network_abbrev(PG_FUNCTION_ARGS) -{ - inet *ip = PG_GETARG_INET_P(0); - 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); - ret = (text *) palloc(len + VARHDRSZ); - VARATT_SIZEP(ret) = len + VARHDRSZ; - memcpy(VARDATA(ret), tmp, len); - PG_RETURN_TEXT_P(ret); -} - -Datum -network_masklen(PG_FUNCTION_ARGS) -{ - inet *ip = PG_GETARG_INET_P(0); - - PG_RETURN_INT32(ip_bits(ip)); -} - -Datum -network_broadcast(PG_FUNCTION_ARGS) -{ - inet *ip = PG_GETARG_INET_P(0); - inet *dst; - - dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct)); - /* make sure any unused bits are zeroed */ - MemSet(dst, 0, 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); -} - -Datum -network_network(PG_FUNCTION_ARGS) -{ - inet *ip = PG_GETARG_INET_P(0); - inet *dst; - - dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct)); - /* make sure any unused bits are zeroed */ - MemSet(dst, 0, 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); -} - -Datum -network_netmask(PG_FUNCTION_ARGS) -{ - inet *ip = PG_GETARG_INET_P(0); - inet *dst; - - dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct)); - /* make sure any unused bits are zeroed */ - MemSet(dst, 0, 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); -} - - -/* - * Convert a value of a network datatype to an approximate scalar value. - * This is used for estimating selectivities of inequality operators - * involving network types. - * - * Currently, inet/cidr values are simply converted to the IPv4 address; - * this will need more thought when IPv6 is supported too. MAC addresses - * are converted to their numeric equivalent as well (OK since we have a - * double to play in). - */ -double -convert_network_to_scalar(Datum value, Oid typid) -{ - switch (typid) - { - case INETOID: - 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: - { - macaddr *mac = DatumGetMacaddrP(value); - double res; - - res = (mac->a << 16) | (mac->b << 8) | (mac->c); - res *= 256 * 256 * 256; - res += (mac->d << 16) | (mac->e << 8) | (mac->f); - return res; - } - } - - /* - * Can't get here unless someone tries to use scalarltsel/scalargtsel - * on an operator with one network and one non-network operand. - */ - elog(ERROR, "convert_network_to_scalar: unsupported type %u", typid); - 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; -} - - -/* - * These functions are used by planner to generate indexscan limits - * for clauses a << b and a <<= b - */ - -/* return the minimal value for an IP on a given network */ -Datum -network_scan_first(Datum in) -{ - return DirectFunctionCall1(network_network, in); -} - -/* - * 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)); -} |