/* * PostgreSQL type definitions for the INET and CIDR types. * * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.74.2.1 2009/10/08 04:46:30 heikki Exp $ * * Jon Postel RIP 16 Oct 1998 */ #include "postgres.h" #include #include #include #include "access/hash.h" #include "catalog/pg_type.h" #include "libpq/ip.h" #include "libpq/libpq-be.h" #include "libpq/pqformat.h" #include "miscadmin.h" #include "utils/builtins.h" #include "utils/inet.h" 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); static inet *internal_inetpl(inet *ip, int64 addend); /* * Access macros. We use VARDATA_ANY so that we can process short-header * varlena values without detoasting them. This requires a trick: * VARDATA_ANY assumes the varlena header is already filled in, which is * not the case when constructing a new value (until SET_INET_VARSIZE is * called, which we typically can't do till the end). Therefore, we * always initialize the newly-allocated value to zeroes (using palloc0). * A zero length word will look like the not-1-byte case to VARDATA_ANY, * and so we correctly construct an uncompressed value. * * Note that ip_maxbits() and SET_INET_VARSIZE() require * the family field to be set correctly. */ #define ip_family(inetptr) \ (((inet_struct *) VARDATA_ANY(inetptr))->family) #define ip_bits(inetptr) \ (((inet_struct *) VARDATA_ANY(inetptr))->bits) #define ip_addr(inetptr) \ (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr) #define ip_maxbits(inetptr) \ (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128) #define SET_INET_VARSIZE(dst) \ SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \ ip_addrsize(dst)) /* * Return the number of bytes of address 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 0; } } /* * Common INET/CIDR input routine */ static inet * network_in(char *src, bool is_cidr) { int bits; inet *dst; dst = (inet *) palloc0(sizeof(inet)); /* * 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), is_cidr ? ip_addrsize(dst) : -1); if ((bits < 0) || (bits > ip_maxbits(dst))) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), /* translator: first %s is inet or cidr */ errmsg("invalid input syntax for type %s: \"%s\"", is_cidr ? "cidr" : "inet", src))); /* * Error check: CIDR values must not have any bits set beyond the masklen. */ if (is_cidr) { if (!addressOK(ip_addr(dst), bits, ip_family(dst))) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid cidr value: \"%s\"", src), errdetail("Value has bits set to right of mask."))); } ip_bits(dst) = bits; SET_INET_VARSIZE(dst); return dst; } Datum inet_in(PG_FUNCTION_ARGS) { char *src = PG_GETARG_CSTRING(0); PG_RETURN_INET_P(network_in(src, false)); } Datum cidr_in(PG_FUNCTION_ARGS) { char *src = PG_GETARG_CSTRING(0); PG_RETURN_INET_P(network_in(src, true)); } /* * Common INET/CIDR output routine */ static char * network_out(inet *src, bool is_cidr) { 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) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("could not format inet value: %m"))); /* For CIDR, add /n if not present */ if (is_cidr && strchr(tmp, '/') == NULL) { len = strlen(tmp); snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src)); } return pstrdup(tmp); } Datum inet_out(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_P(0); PG_RETURN_CSTRING(network_out(src, false)); } Datum cidr_out(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_P(0); PG_RETURN_CSTRING(network_out(src, true)); } /* * network_recv - converts external binary format to inet * * The external representation is (one byte apiece for) * family, bits, is_cidr, address length, address in network byte order. * * Presence of is_cidr is largely for historical reasons, though it might * allow some code-sharing on the client side. We send it correctly on * output, but ignore the value on input. */ static inet * network_recv(StringInfo buf, bool is_cidr) { inet *addr; char *addrptr; int bits; int nb, i; /* make sure any unused bits in a CIDR value are zeroed */ addr = (inet *) palloc0(sizeof(inet)); ip_family(addr) = pq_getmsgbyte(buf); if (ip_family(addr) != PGSQL_AF_INET && ip_family(addr) != PGSQL_AF_INET6) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), /* translator: %s is inet or cidr */ errmsg("invalid address family in external \"%s\" value", is_cidr ? "cidr" : "inet"))); bits = pq_getmsgbyte(buf); if (bits < 0 || bits > ip_maxbits(addr)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), /* translator: %s is inet or cidr */ errmsg("invalid bits in external \"%s\" value", is_cidr ? "cidr" : "inet"))); ip_bits(addr) = bits; i = pq_getmsgbyte(buf); /* ignore is_cidr */ nb = pq_getmsgbyte(buf); if (nb != ip_addrsize(addr)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), /* translator: %s is inet or cidr */ errmsg("invalid length in external \"%s\" value", is_cidr ? "cidr" : "inet"))); addrptr = (char *) ip_addr(addr); for (i = 0; i < nb; i++) addrptr[i] = pq_getmsgbyte(buf); /* * Error check: CIDR values must not have any bits set beyond the masklen. */ if (is_cidr) { if (!addressOK(ip_addr(addr), bits, ip_family(addr))) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid external \"cidr\" value"), errdetail("Value has bits set to right of mask."))); } SET_INET_VARSIZE(addr); return addr; } Datum inet_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_INET_P(network_recv(buf, false)); } Datum cidr_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_INET_P(network_recv(buf, true)); } /* * network_send - converts inet to binary format */ static bytea * network_send(inet *addr, bool is_cidr) { StringInfoData buf; char *addrptr; int nb, i; pq_begintypsend(&buf); pq_sendbyte(&buf, ip_family(addr)); pq_sendbyte(&buf, ip_bits(addr)); pq_sendbyte(&buf, is_cidr); nb = ip_addrsize(addr); if (nb < 0) nb = 0; pq_sendbyte(&buf, nb); addrptr = (char *) ip_addr(addr); for (i = 0; i < nb; i++) pq_sendbyte(&buf, addrptr[i]); return pq_endtypsend(&buf); } Datum inet_send(PG_FUNCTION_ARGS) { inet *addr = PG_GETARG_INET_P(0); PG_RETURN_BYTEA_P(network_send(addr, false)); } Datum cidr_send(PG_FUNCTION_ARGS) { inet *addr = PG_GETARG_INET_P(0); PG_RETURN_BYTEA_P(network_send(addr, true)); } Datum inet_to_cidr(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_P(0); inet *dst; int bits; int byte; int nbits; int maxbytes; bits = ip_bits(src); /* safety check */ if ((bits < 0) || (bits > ip_maxbits(src))) elog(ERROR, "invalid inet bit length: %d", bits); /* clone the original data */ dst = (inet *) palloc(VARSIZE_ANY(src)); memcpy(dst, src, VARSIZE_ANY(src)); /* zero out any bits to the right of the netmask */ byte = bits / 8; nbits = bits % 8; /* clear the first byte, this might be a partial byte */ if (nbits != 0) { ip_addr(dst)[byte] &=~(0xFF >> nbits); byte ++; } /* clear remaining bytes */ maxbytes = ip_addrsize(dst); while (byte ip_maxbits(src))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid mask length: %d", bits))); /* clone the original data */ dst = (inet *) palloc(VARSIZE_ANY(src)); memcpy(dst, src, VARSIZE_ANY(src)); ip_bits(dst) = bits; PG_RETURN_INET_P(dst); } Datum cidr_set_masklen(PG_FUNCTION_ARGS) { inet *src = PG_GETARG_INET_P(0); int bits = PG_GETARG_INT32(1); inet *dst; int byte; int nbits; int maxbytes; if (bits == -1) bits = ip_maxbits(src); if ((bits < 0) || (bits > ip_maxbits(src))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid mask length: %d", bits))); /* clone the original data */ dst = (inet *) palloc(VARSIZE_ANY(src)); memcpy(dst, src, VARSIZE_ANY(src)); ip_bits(dst) = bits; /* zero out any bits to the right of the new netmask */ byte = bits / 8; nbits = bits % 8; /* clear the first byte, this might be a partial byte */ if (nbits != 0) { ip_addr(dst)[byte] &=~(0xFF >> nbits); byte ++; } /* clear remaining bytes */ maxbytes = ip_addrsize(dst); while (byte = 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); } /* * Support function for hash indexes on inet/cidr. */ Datum hashinet(PG_FUNCTION_ARGS) { inet *addr = PG_GETARG_INET_P(0); int addrsize = ip_addrsize(addr); /* XXX this assumes there are no pad bytes in the data structure */ return hash_any((unsigned char *) VARDATA_ANY(addr), addrsize + 2); } /* * 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) == 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 network_subeq(PG_FUNCTION_ARGS) { 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 network_sup(PG_FUNCTION_ARGS) { 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 network_supeq(PG_FUNCTION_ARGS) { 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); } /* * Extract data from a network datatype. */ Datum network_host(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); 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) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("could not format inet value: %m"))); /* Suppress /n if present (shouldn't happen now) */ if ((ptr = strchr(tmp, '/')) != NULL) *ptr = '\0'; PG_RETURN_TEXT_P(cstring_to_text(tmp)); } /* * network_show implements the inet and cidr casts to text. This is not * quite the same behavior as network_out, hence we can't drop it in favor * of CoerceViaIO. */ Datum network_show(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); 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) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("could not format inet value: %m"))); /* 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)); } PG_RETURN_TEXT_P(cstring_to_text(tmp)); } Datum inet_abbrev(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); char *dst; char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; dst = inet_net_ntop(ip_family(ip), ip_addr(ip), ip_bits(ip), tmp, sizeof(tmp)); if (dst == NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("could not format inet value: %m"))); PG_RETURN_TEXT_P(cstring_to_text(tmp)); } Datum cidr_abbrev(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); char *dst; char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip), ip_bits(ip), tmp, sizeof(tmp)); if (dst == NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("could not format cidr value: %m"))); PG_RETURN_TEXT_P(cstring_to_text(tmp)); } Datum network_masklen(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); PG_RETURN_INT32(ip_bits(ip)); } 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(sizeof(inet)); 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 = 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); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } Datum network_network(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *dst; int byte; int bits; unsigned char mask; unsigned char *a, *b; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(sizeof(inet)); 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); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } Datum network_netmask(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *dst; int byte; int bits; unsigned char mask; unsigned char *b; /* make sure any unused bits are zeroed */ dst = (inet *) palloc0(sizeof(inet)); 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_maxbits(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } Datum network_hostmask(PG_FUNCTION_ARGS) { 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(sizeof(inet)); if (ip_family(ip) == PGSQL_AF_INET) maxbytes = 4; else maxbytes = 16; bits = ip_maxbits(ip) - ip_bits(ip); b = ip_addr(dst); byte = maxbytes - 1; 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_maxbits(ip); SET_INET_VARSIZE(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. */ double convert_network_to_scalar(Datum value, Oid typid) { switch (typid) { case INETOID: case CIDROID: { inet *ip = DatumGetInetP(value); int len; double res; int i; /* * Note that we don't use the full address for IPv6. */ 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: { 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, "unsupported type: %u", typid); 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 || (n % 8) == 0) return x; lb = ((const u_char *) l)[b]; rb = ((const u_char *) r)[b]; for (b = n % 8; b > 0; b--) { if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb)) { if (IS_HIGHBIT_SET(lb)) 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 true; byte = bits / 8; nbits = bits % 8; mask = 0xff; if (bits != 0) mask >>= nbits; while (byte raddr.addr.ss_family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; default: PG_RETURN_NULL(); } remote_host[0] = '\0'; ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, remote_host, sizeof(remote_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); clean_ipv6_addr(port->raddr.addr.ss_family, remote_host); PG_RETURN_INET_P(network_in(remote_host, false)); } /* * port that the client is connecting from (NULL if Unix socket) */ Datum inet_client_port(PG_FUNCTION_ARGS) { Port *port = MyProcPort; char remote_port[NI_MAXSERV]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->raddr.addr.ss_family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; default: PG_RETURN_NULL(); } remote_port[0] = '\0'; ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, NULL, 0, remote_port, sizeof(remote_port), NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port))); } /* * IP address that the server accepted the connection on (NULL if Unix socket) */ Datum inet_server_addr(PG_FUNCTION_ARGS) { Port *port = MyProcPort; char local_host[NI_MAXHOST]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->laddr.addr.ss_family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; default: PG_RETURN_NULL(); } local_host[0] = '\0'; ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen, local_host, sizeof(local_host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); clean_ipv6_addr(port->laddr.addr.ss_family, local_host); PG_RETURN_INET_P(network_in(local_host, false)); } /* * port that the server accepted the connection on (NULL if Unix socket) */ Datum inet_server_port(PG_FUNCTION_ARGS) { Port *port = MyProcPort; char local_port[NI_MAXSERV]; int ret; if (port == NULL) PG_RETURN_NULL(); switch (port->laddr.addr.ss_family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; default: PG_RETURN_NULL(); } local_port[0] = '\0'; ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen, NULL, 0, local_port, sizeof(local_port), NI_NUMERICHOST | NI_NUMERICSERV); if (ret) PG_RETURN_NULL(); PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port))); } Datum inetnot(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *dst; dst = (inet *) palloc0(sizeof(inet)); { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pdst = ip_addr(dst); while (nb-- > 0) pdst[nb] = ~pip[nb]; } ip_bits(dst) = ip_bits(ip); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } Datum inetand(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *ip2 = PG_GETARG_INET_P(1); inet *dst; dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot AND inet values of different sizes"))); else { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); unsigned char *pdst = ip_addr(dst); while (nb-- > 0) pdst[nb] = pip[nb] & pip2[nb]; } ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } Datum inetor(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *ip2 = PG_GETARG_INET_P(1); inet *dst; dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot OR inet values of different sizes"))); else { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); unsigned char *pdst = ip_addr(dst); while (nb-- > 0) pdst[nb] = pip[nb] | pip2[nb]; } ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } static inet * internal_inetpl(inet *ip, int64 addend) { inet *dst; dst = (inet *) palloc0(sizeof(inet)); { int nb = ip_addrsize(ip); unsigned char *pip = ip_addr(ip); unsigned char *pdst = ip_addr(dst); int carry = 0; while (nb-- > 0) { carry = pip[nb] + (int) (addend & 0xFF) + carry; pdst[nb] = (unsigned char) (carry & 0xFF); carry >>= 8; /* * We have to be careful about right-shifting addend because * right-shift isn't portable for negative values, while simply * dividing by 256 doesn't work (the standard rounding is in the * wrong direction, besides which there may be machines out there * that round the wrong way). So, explicitly clear the low-order * byte to remove any doubt about the correct result of the * division, and then divide rather than shift. */ addend &= ~((int64) 0xFF); addend /= 0x100; } /* * At this point we should have addend and carry both zero if original * addend was >= 0, or addend -1 and carry 1 if original addend was < * 0. Anything else means overflow. */ if (!((addend == 0 && carry == 0) || (addend == -1 && carry == 1))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); } ip_bits(dst) = ip_bits(ip); ip_family(dst) = ip_family(ip); SET_INET_VARSIZE(dst); return dst; } Datum inetpl(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); int64 addend = PG_GETARG_INT64(1); PG_RETURN_INET_P(internal_inetpl(ip, addend)); } Datum inetmi_int8(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); int64 addend = PG_GETARG_INT64(1); PG_RETURN_INET_P(internal_inetpl(ip, -addend)); } Datum inetmi(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); inet *ip2 = PG_GETARG_INET_P(1); int64 res = 0; if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot subtract inet values of different sizes"))); else { /* * We form the difference using the traditional complement, increment, * and add rule, with the increment part being handled by starting the * carry off at 1. If you don't think integer arithmetic is done in * two's complement, too bad. */ int nb = ip_addrsize(ip); int byte = 0; unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); int carry = 1; while (nb-- > 0) { int lobyte; carry = pip[nb] + (~pip2[nb] & 0xFF) + carry; lobyte = carry & 0xFF; if (byte >= 8; byte ++; } /* * If input is narrower than int64, overflow is not possible, but we * have to do proper sign extension. */ if (carry == 0 && byte