| 1 | /* | 
|---|
| 2 | *	PostgreSQL type definitions for the INET and CIDR types. | 
|---|
| 3 | * | 
|---|
| 4 | *	src/backend/utils/adt/network.c | 
|---|
| 5 | * | 
|---|
| 6 | *	Jon Postel RIP 16 Oct 1998 | 
|---|
| 7 | */ | 
|---|
| 8 |  | 
|---|
| 9 | #include "postgres.h" | 
|---|
| 10 |  | 
|---|
| 11 | #include <sys/socket.h> | 
|---|
| 12 | #include <netinet/in.h> | 
|---|
| 13 | #include <arpa/inet.h> | 
|---|
| 14 |  | 
|---|
| 15 | #include "access/stratnum.h" | 
|---|
| 16 | #include "catalog/pg_opfamily.h" | 
|---|
| 17 | #include "catalog/pg_type.h" | 
|---|
| 18 | #include "common/ip.h" | 
|---|
| 19 | #include "libpq/libpq-be.h" | 
|---|
| 20 | #include "libpq/pqformat.h" | 
|---|
| 21 | #include "miscadmin.h" | 
|---|
| 22 | #include "nodes/makefuncs.h" | 
|---|
| 23 | #include "nodes/nodeFuncs.h" | 
|---|
| 24 | #include "nodes/supportnodes.h" | 
|---|
| 25 | #include "utils/builtins.h" | 
|---|
| 26 | #include "utils/fmgroids.h" | 
|---|
| 27 | #include "utils/hashutils.h" | 
|---|
| 28 | #include "utils/inet.h" | 
|---|
| 29 | #include "utils/lsyscache.h" | 
|---|
| 30 |  | 
|---|
| 31 |  | 
|---|
| 32 | static int32 network_cmp_internal(inet *a1, inet *a2); | 
|---|
| 33 | static List *match_network_function(Node *leftop, | 
|---|
| 34 | Node *rightop, | 
|---|
| 35 | int indexarg, | 
|---|
| 36 | Oid funcid, | 
|---|
| 37 | Oid opfamily); | 
|---|
| 38 | static List *match_network_subset(Node *leftop, | 
|---|
| 39 | Node *rightop, | 
|---|
| 40 | bool is_eq, | 
|---|
| 41 | Oid opfamily); | 
|---|
| 42 | static bool addressOK(unsigned char *a, int bits, int family); | 
|---|
| 43 | static inet *internal_inetpl(inet *ip, int64 addend); | 
|---|
| 44 |  | 
|---|
| 45 |  | 
|---|
| 46 | /* | 
|---|
| 47 | * Common INET/CIDR input routine | 
|---|
| 48 | */ | 
|---|
| 49 | static inet * | 
|---|
| 50 | network_in(char *src, bool is_cidr) | 
|---|
| 51 | { | 
|---|
| 52 | int			bits; | 
|---|
| 53 | inet	   *dst; | 
|---|
| 54 |  | 
|---|
| 55 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 56 |  | 
|---|
| 57 | /* | 
|---|
| 58 | * First, check to see if this is an IPv6 or IPv4 address.  IPv6 addresses | 
|---|
| 59 | * will have a : somewhere in them (several, in fact) so if there is one | 
|---|
| 60 | * present, assume it's V6, otherwise assume it's V4. | 
|---|
| 61 | */ | 
|---|
| 62 |  | 
|---|
| 63 | if (strchr(src, ':') != NULL) | 
|---|
| 64 | ip_family(dst) = PGSQL_AF_INET6; | 
|---|
| 65 | else | 
|---|
| 66 | ip_family(dst) = PGSQL_AF_INET; | 
|---|
| 67 |  | 
|---|
| 68 | bits = inet_net_pton(ip_family(dst), src, ip_addr(dst), | 
|---|
| 69 | is_cidr ? ip_addrsize(dst) : -1); | 
|---|
| 70 | if ((bits < 0) || (bits > ip_maxbits(dst))) | 
|---|
| 71 | ereport(ERROR, | 
|---|
| 72 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | 
|---|
| 73 | /* translator: first %s is inet or cidr */ | 
|---|
| 74 | errmsg( "invalid input syntax for type %s: \"%s\"", | 
|---|
| 75 | is_cidr ? "cidr": "inet", src))); | 
|---|
| 76 |  | 
|---|
| 77 | /* | 
|---|
| 78 | * Error check: CIDR values must not have any bits set beyond the masklen. | 
|---|
| 79 | */ | 
|---|
| 80 | if (is_cidr) | 
|---|
| 81 | { | 
|---|
| 82 | if (!addressOK(ip_addr(dst), bits, ip_family(dst))) | 
|---|
| 83 | ereport(ERROR, | 
|---|
| 84 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | 
|---|
| 85 | errmsg( "invalid cidr value: \"%s\"", src), | 
|---|
| 86 | errdetail( "Value has bits set to right of mask."))); | 
|---|
| 87 | } | 
|---|
| 88 |  | 
|---|
| 89 | ip_bits(dst) = bits; | 
|---|
| 90 | SET_INET_VARSIZE(dst); | 
|---|
| 91 |  | 
|---|
| 92 | return dst; | 
|---|
| 93 | } | 
|---|
| 94 |  | 
|---|
| 95 | Datum | 
|---|
| 96 | inet_in(PG_FUNCTION_ARGS) | 
|---|
| 97 | { | 
|---|
| 98 | char	   *src = PG_GETARG_CSTRING(0); | 
|---|
| 99 |  | 
|---|
| 100 | PG_RETURN_INET_P(network_in(src, false)); | 
|---|
| 101 | } | 
|---|
| 102 |  | 
|---|
| 103 | Datum | 
|---|
| 104 | cidr_in(PG_FUNCTION_ARGS) | 
|---|
| 105 | { | 
|---|
| 106 | char	   *src = PG_GETARG_CSTRING(0); | 
|---|
| 107 |  | 
|---|
| 108 | PG_RETURN_INET_P(network_in(src, true)); | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 |  | 
|---|
| 112 | /* | 
|---|
| 113 | * Common INET/CIDR output routine | 
|---|
| 114 | */ | 
|---|
| 115 | static char * | 
|---|
| 116 | network_out(inet *src, bool is_cidr) | 
|---|
| 117 | { | 
|---|
| 118 | char		tmp[sizeof( "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; | 
|---|
| 119 | char	   *dst; | 
|---|
| 120 | int			len; | 
|---|
| 121 |  | 
|---|
| 122 | dst = inet_net_ntop(ip_family(src), ip_addr(src), ip_bits(src), | 
|---|
| 123 | tmp, sizeof(tmp)); | 
|---|
| 124 | if (dst == NULL) | 
|---|
| 125 | ereport(ERROR, | 
|---|
| 126 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 127 | errmsg( "could not format inet value: %m"))); | 
|---|
| 128 |  | 
|---|
| 129 | /* For CIDR, add /n if not present */ | 
|---|
| 130 | if (is_cidr && strchr(tmp, '/') == NULL) | 
|---|
| 131 | { | 
|---|
| 132 | len = strlen(tmp); | 
|---|
| 133 | snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src)); | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | return pstrdup(tmp); | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | Datum | 
|---|
| 140 | inet_out(PG_FUNCTION_ARGS) | 
|---|
| 141 | { | 
|---|
| 142 | inet	   *src = PG_GETARG_INET_PP(0); | 
|---|
| 143 |  | 
|---|
| 144 | PG_RETURN_CSTRING(network_out(src, false)); | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|
| 147 | Datum | 
|---|
| 148 | cidr_out(PG_FUNCTION_ARGS) | 
|---|
| 149 | { | 
|---|
| 150 | inet	   *src = PG_GETARG_INET_PP(0); | 
|---|
| 151 |  | 
|---|
| 152 | PG_RETURN_CSTRING(network_out(src, true)); | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|
| 155 |  | 
|---|
| 156 | /* | 
|---|
| 157 | *		network_recv		- converts external binary format to inet | 
|---|
| 158 | * | 
|---|
| 159 | * The external representation is (one byte apiece for) | 
|---|
| 160 | * family, bits, is_cidr, address length, address in network byte order. | 
|---|
| 161 | * | 
|---|
| 162 | * Presence of is_cidr is largely for historical reasons, though it might | 
|---|
| 163 | * allow some code-sharing on the client side.  We send it correctly on | 
|---|
| 164 | * output, but ignore the value on input. | 
|---|
| 165 | */ | 
|---|
| 166 | static inet * | 
|---|
| 167 | network_recv(StringInfo buf, bool is_cidr) | 
|---|
| 168 | { | 
|---|
| 169 | inet	   *addr; | 
|---|
| 170 | char	   *addrptr; | 
|---|
| 171 | int			bits; | 
|---|
| 172 | int			nb, | 
|---|
| 173 | i; | 
|---|
| 174 |  | 
|---|
| 175 | /* make sure any unused bits in a CIDR value are zeroed */ | 
|---|
| 176 | addr = (inet *) palloc0(sizeof(inet)); | 
|---|
| 177 |  | 
|---|
| 178 | ip_family(addr) = pq_getmsgbyte(buf); | 
|---|
| 179 | if (ip_family(addr) != PGSQL_AF_INET && | 
|---|
| 180 | ip_family(addr) != PGSQL_AF_INET6) | 
|---|
| 181 | ereport(ERROR, | 
|---|
| 182 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 183 | /* translator: %s is inet or cidr */ | 
|---|
| 184 | errmsg( "invalid address family in external \"%s\" value", | 
|---|
| 185 | is_cidr ? "cidr": "inet"))); | 
|---|
| 186 | bits = pq_getmsgbyte(buf); | 
|---|
| 187 | if (bits < 0 || bits > ip_maxbits(addr)) | 
|---|
| 188 | ereport(ERROR, | 
|---|
| 189 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 190 | /* translator: %s is inet or cidr */ | 
|---|
| 191 | errmsg( "invalid bits in external \"%s\" value", | 
|---|
| 192 | is_cidr ? "cidr": "inet"))); | 
|---|
| 193 | ip_bits(addr) = bits; | 
|---|
| 194 | i = pq_getmsgbyte(buf);		/* ignore is_cidr */ | 
|---|
| 195 | nb = pq_getmsgbyte(buf); | 
|---|
| 196 | if (nb != ip_addrsize(addr)) | 
|---|
| 197 | ereport(ERROR, | 
|---|
| 198 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 199 | /* translator: %s is inet or cidr */ | 
|---|
| 200 | errmsg( "invalid length in external \"%s\" value", | 
|---|
| 201 | is_cidr ? "cidr": "inet"))); | 
|---|
| 202 |  | 
|---|
| 203 | addrptr = (char *) ip_addr(addr); | 
|---|
| 204 | for (i = 0; i < nb; i++) | 
|---|
| 205 | addrptr[i] = pq_getmsgbyte(buf); | 
|---|
| 206 |  | 
|---|
| 207 | /* | 
|---|
| 208 | * Error check: CIDR values must not have any bits set beyond the masklen. | 
|---|
| 209 | */ | 
|---|
| 210 | if (is_cidr) | 
|---|
| 211 | { | 
|---|
| 212 | if (!addressOK(ip_addr(addr), bits, ip_family(addr))) | 
|---|
| 213 | ereport(ERROR, | 
|---|
| 214 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 215 | errmsg( "invalid external \"cidr\" value"), | 
|---|
| 216 | errdetail( "Value has bits set to right of mask."))); | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | SET_INET_VARSIZE(addr); | 
|---|
| 220 |  | 
|---|
| 221 | return addr; | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | Datum | 
|---|
| 225 | inet_recv(PG_FUNCTION_ARGS) | 
|---|
| 226 | { | 
|---|
| 227 | StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0); | 
|---|
| 228 |  | 
|---|
| 229 | PG_RETURN_INET_P(network_recv(buf, false)); | 
|---|
| 230 | } | 
|---|
| 231 |  | 
|---|
| 232 | Datum | 
|---|
| 233 | cidr_recv(PG_FUNCTION_ARGS) | 
|---|
| 234 | { | 
|---|
| 235 | StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0); | 
|---|
| 236 |  | 
|---|
| 237 | PG_RETURN_INET_P(network_recv(buf, true)); | 
|---|
| 238 | } | 
|---|
| 239 |  | 
|---|
| 240 |  | 
|---|
| 241 | /* | 
|---|
| 242 | *		network_send		- converts inet to binary format | 
|---|
| 243 | */ | 
|---|
| 244 | static bytea * | 
|---|
| 245 | network_send(inet *addr, bool is_cidr) | 
|---|
| 246 | { | 
|---|
| 247 | StringInfoData buf; | 
|---|
| 248 | char	   *addrptr; | 
|---|
| 249 | int			nb, | 
|---|
| 250 | i; | 
|---|
| 251 |  | 
|---|
| 252 | pq_begintypsend(&buf); | 
|---|
| 253 | pq_sendbyte(&buf, ip_family(addr)); | 
|---|
| 254 | pq_sendbyte(&buf, ip_bits(addr)); | 
|---|
| 255 | pq_sendbyte(&buf, is_cidr); | 
|---|
| 256 | nb = ip_addrsize(addr); | 
|---|
| 257 | if (nb < 0) | 
|---|
| 258 | nb = 0; | 
|---|
| 259 | pq_sendbyte(&buf, nb); | 
|---|
| 260 | addrptr = (char *) ip_addr(addr); | 
|---|
| 261 | for (i = 0; i < nb; i++) | 
|---|
| 262 | pq_sendbyte(&buf, addrptr[i]); | 
|---|
| 263 | return pq_endtypsend(&buf); | 
|---|
| 264 | } | 
|---|
| 265 |  | 
|---|
| 266 | Datum | 
|---|
| 267 | inet_send(PG_FUNCTION_ARGS) | 
|---|
| 268 | { | 
|---|
| 269 | inet	   *addr = PG_GETARG_INET_PP(0); | 
|---|
| 270 |  | 
|---|
| 271 | PG_RETURN_BYTEA_P(network_send(addr, false)); | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | Datum | 
|---|
| 275 | cidr_send(PG_FUNCTION_ARGS) | 
|---|
| 276 | { | 
|---|
| 277 | inet	   *addr = PG_GETARG_INET_PP(0); | 
|---|
| 278 |  | 
|---|
| 279 | PG_RETURN_BYTEA_P(network_send(addr, true)); | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 |  | 
|---|
| 283 | Datum | 
|---|
| 284 | inet_to_cidr(PG_FUNCTION_ARGS) | 
|---|
| 285 | { | 
|---|
| 286 | inet	   *src = PG_GETARG_INET_PP(0); | 
|---|
| 287 | int			bits; | 
|---|
| 288 |  | 
|---|
| 289 | bits = ip_bits(src); | 
|---|
| 290 |  | 
|---|
| 291 | /* safety check */ | 
|---|
| 292 | if ((bits < 0) || (bits > ip_maxbits(src))) | 
|---|
| 293 | elog(ERROR, "invalid inet bit length: %d", bits); | 
|---|
| 294 |  | 
|---|
| 295 | PG_RETURN_INET_P(cidr_set_masklen_internal(src, bits)); | 
|---|
| 296 | } | 
|---|
| 297 |  | 
|---|
| 298 | Datum | 
|---|
| 299 | inet_set_masklen(PG_FUNCTION_ARGS) | 
|---|
| 300 | { | 
|---|
| 301 | inet	   *src = PG_GETARG_INET_PP(0); | 
|---|
| 302 | int			bits = PG_GETARG_INT32(1); | 
|---|
| 303 | inet	   *dst; | 
|---|
| 304 |  | 
|---|
| 305 | if (bits == -1) | 
|---|
| 306 | bits = ip_maxbits(src); | 
|---|
| 307 |  | 
|---|
| 308 | if ((bits < 0) || (bits > ip_maxbits(src))) | 
|---|
| 309 | ereport(ERROR, | 
|---|
| 310 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 
|---|
| 311 | errmsg( "invalid mask length: %d", bits))); | 
|---|
| 312 |  | 
|---|
| 313 | /* clone the original data */ | 
|---|
| 314 | dst = (inet *) palloc(VARSIZE_ANY(src)); | 
|---|
| 315 | memcpy(dst, src, VARSIZE_ANY(src)); | 
|---|
| 316 |  | 
|---|
| 317 | ip_bits(dst) = bits; | 
|---|
| 318 |  | 
|---|
| 319 | PG_RETURN_INET_P(dst); | 
|---|
| 320 | } | 
|---|
| 321 |  | 
|---|
| 322 | Datum | 
|---|
| 323 | cidr_set_masklen(PG_FUNCTION_ARGS) | 
|---|
| 324 | { | 
|---|
| 325 | inet	   *src = PG_GETARG_INET_PP(0); | 
|---|
| 326 | int			bits = PG_GETARG_INT32(1); | 
|---|
| 327 |  | 
|---|
| 328 | if (bits == -1) | 
|---|
| 329 | bits = ip_maxbits(src); | 
|---|
| 330 |  | 
|---|
| 331 | if ((bits < 0) || (bits > ip_maxbits(src))) | 
|---|
| 332 | ereport(ERROR, | 
|---|
| 333 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 
|---|
| 334 | errmsg( "invalid mask length: %d", bits))); | 
|---|
| 335 |  | 
|---|
| 336 | PG_RETURN_INET_P(cidr_set_masklen_internal(src, bits)); | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | /* | 
|---|
| 340 | * Copy src and set mask length to 'bits' (which must be valid for the family) | 
|---|
| 341 | */ | 
|---|
| 342 | inet * | 
|---|
| 343 | cidr_set_masklen_internal(const inet *src, int bits) | 
|---|
| 344 | { | 
|---|
| 345 | inet	   *dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 346 |  | 
|---|
| 347 | ip_family(dst) = ip_family(src); | 
|---|
| 348 | ip_bits(dst) = bits; | 
|---|
| 349 |  | 
|---|
| 350 | if (bits > 0) | 
|---|
| 351 | { | 
|---|
| 352 | Assert(bits <= ip_maxbits(dst)); | 
|---|
| 353 |  | 
|---|
| 354 | /* Clone appropriate bytes of the address, leaving the rest 0 */ | 
|---|
| 355 | memcpy(ip_addr(dst), ip_addr(src), (bits + 7) / 8); | 
|---|
| 356 |  | 
|---|
| 357 | /* Clear any unwanted bits in the last partial byte */ | 
|---|
| 358 | if (bits % 8) | 
|---|
| 359 | ip_addr(dst)[bits / 8] &= ~(0xFF >> (bits % 8)); | 
|---|
| 360 | } | 
|---|
| 361 |  | 
|---|
| 362 | /* Set varlena header correctly */ | 
|---|
| 363 | SET_INET_VARSIZE(dst); | 
|---|
| 364 |  | 
|---|
| 365 | return dst; | 
|---|
| 366 | } | 
|---|
| 367 |  | 
|---|
| 368 | /* | 
|---|
| 369 | *	Basic comparison function for sorting and inet/cidr comparisons. | 
|---|
| 370 | * | 
|---|
| 371 | * Comparison is first on the common bits of the network part, then on | 
|---|
| 372 | * the length of the network part, and then on the whole unmasked address. | 
|---|
| 373 | * The effect is that the network part is the major sort key, and for | 
|---|
| 374 | * equal network parts we sort on the host part.  Note this is only sane | 
|---|
| 375 | * for CIDR if address bits to the right of the mask are guaranteed zero; | 
|---|
| 376 | * otherwise logically-equal CIDRs might compare different. | 
|---|
| 377 | */ | 
|---|
| 378 |  | 
|---|
| 379 | static int32 | 
|---|
| 380 | network_cmp_internal(inet *a1, inet *a2) | 
|---|
| 381 | { | 
|---|
| 382 | if (ip_family(a1) == ip_family(a2)) | 
|---|
| 383 | { | 
|---|
| 384 | int			order; | 
|---|
| 385 |  | 
|---|
| 386 | order = bitncmp(ip_addr(a1), ip_addr(a2), | 
|---|
| 387 | Min(ip_bits(a1), ip_bits(a2))); | 
|---|
| 388 | if (order != 0) | 
|---|
| 389 | return order; | 
|---|
| 390 | order = ((int) ip_bits(a1)) - ((int) ip_bits(a2)); | 
|---|
| 391 | if (order != 0) | 
|---|
| 392 | return order; | 
|---|
| 393 | return bitncmp(ip_addr(a1), ip_addr(a2), ip_maxbits(a1)); | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 | return ip_family(a1) - ip_family(a2); | 
|---|
| 397 | } | 
|---|
| 398 |  | 
|---|
| 399 | Datum | 
|---|
| 400 | network_cmp(PG_FUNCTION_ARGS) | 
|---|
| 401 | { | 
|---|
| 402 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 403 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 404 |  | 
|---|
| 405 | PG_RETURN_INT32(network_cmp_internal(a1, a2)); | 
|---|
| 406 | } | 
|---|
| 407 |  | 
|---|
| 408 | /* | 
|---|
| 409 | *	Boolean ordering tests. | 
|---|
| 410 | */ | 
|---|
| 411 | Datum | 
|---|
| 412 | network_lt(PG_FUNCTION_ARGS) | 
|---|
| 413 | { | 
|---|
| 414 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 415 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 416 |  | 
|---|
| 417 | PG_RETURN_BOOL(network_cmp_internal(a1, a2) < 0); | 
|---|
| 418 | } | 
|---|
| 419 |  | 
|---|
| 420 | Datum | 
|---|
| 421 | network_le(PG_FUNCTION_ARGS) | 
|---|
| 422 | { | 
|---|
| 423 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 424 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 425 |  | 
|---|
| 426 | PG_RETURN_BOOL(network_cmp_internal(a1, a2) <= 0); | 
|---|
| 427 | } | 
|---|
| 428 |  | 
|---|
| 429 | Datum | 
|---|
| 430 | network_eq(PG_FUNCTION_ARGS) | 
|---|
| 431 | { | 
|---|
| 432 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 433 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 434 |  | 
|---|
| 435 | PG_RETURN_BOOL(network_cmp_internal(a1, a2) == 0); | 
|---|
| 436 | } | 
|---|
| 437 |  | 
|---|
| 438 | Datum | 
|---|
| 439 | network_ge(PG_FUNCTION_ARGS) | 
|---|
| 440 | { | 
|---|
| 441 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 442 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 443 |  | 
|---|
| 444 | PG_RETURN_BOOL(network_cmp_internal(a1, a2) >= 0); | 
|---|
| 445 | } | 
|---|
| 446 |  | 
|---|
| 447 | Datum | 
|---|
| 448 | network_gt(PG_FUNCTION_ARGS) | 
|---|
| 449 | { | 
|---|
| 450 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 451 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 452 |  | 
|---|
| 453 | PG_RETURN_BOOL(network_cmp_internal(a1, a2) > 0); | 
|---|
| 454 | } | 
|---|
| 455 |  | 
|---|
| 456 | Datum | 
|---|
| 457 | network_ne(PG_FUNCTION_ARGS) | 
|---|
| 458 | { | 
|---|
| 459 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 460 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 461 |  | 
|---|
| 462 | PG_RETURN_BOOL(network_cmp_internal(a1, a2) != 0); | 
|---|
| 463 | } | 
|---|
| 464 |  | 
|---|
| 465 | /* | 
|---|
| 466 | * MIN/MAX support functions. | 
|---|
| 467 | */ | 
|---|
| 468 | Datum | 
|---|
| 469 | network_smaller(PG_FUNCTION_ARGS) | 
|---|
| 470 | { | 
|---|
| 471 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 472 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 473 |  | 
|---|
| 474 | if (network_cmp_internal(a1, a2) < 0) | 
|---|
| 475 | PG_RETURN_INET_P(a1); | 
|---|
| 476 | else | 
|---|
| 477 | PG_RETURN_INET_P(a2); | 
|---|
| 478 | } | 
|---|
| 479 |  | 
|---|
| 480 | Datum | 
|---|
| 481 | network_larger(PG_FUNCTION_ARGS) | 
|---|
| 482 | { | 
|---|
| 483 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 484 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 485 |  | 
|---|
| 486 | if (network_cmp_internal(a1, a2) > 0) | 
|---|
| 487 | PG_RETURN_INET_P(a1); | 
|---|
| 488 | else | 
|---|
| 489 | PG_RETURN_INET_P(a2); | 
|---|
| 490 | } | 
|---|
| 491 |  | 
|---|
| 492 | /* | 
|---|
| 493 | * Support function for hash indexes on inet/cidr. | 
|---|
| 494 | */ | 
|---|
| 495 | Datum | 
|---|
| 496 | hashinet(PG_FUNCTION_ARGS) | 
|---|
| 497 | { | 
|---|
| 498 | inet	   *addr = PG_GETARG_INET_PP(0); | 
|---|
| 499 | int			addrsize = ip_addrsize(addr); | 
|---|
| 500 |  | 
|---|
| 501 | /* XXX this assumes there are no pad bytes in the data structure */ | 
|---|
| 502 | return hash_any((unsigned char *) VARDATA_ANY(addr), addrsize + 2); | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 | Datum | 
|---|
| 506 | hashinetextended(PG_FUNCTION_ARGS) | 
|---|
| 507 | { | 
|---|
| 508 | inet	   *addr = PG_GETARG_INET_PP(0); | 
|---|
| 509 | int			addrsize = ip_addrsize(addr); | 
|---|
| 510 |  | 
|---|
| 511 | return hash_any_extended((unsigned char *) VARDATA_ANY(addr), addrsize + 2, | 
|---|
| 512 | PG_GETARG_INT64(1)); | 
|---|
| 513 | } | 
|---|
| 514 |  | 
|---|
| 515 | /* | 
|---|
| 516 | *	Boolean network-inclusion tests. | 
|---|
| 517 | */ | 
|---|
| 518 | Datum | 
|---|
| 519 | network_sub(PG_FUNCTION_ARGS) | 
|---|
| 520 | { | 
|---|
| 521 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 522 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 523 |  | 
|---|
| 524 | if (ip_family(a1) == ip_family(a2)) | 
|---|
| 525 | { | 
|---|
| 526 | PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) && | 
|---|
| 527 | bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0); | 
|---|
| 528 | } | 
|---|
| 529 |  | 
|---|
| 530 | PG_RETURN_BOOL(false); | 
|---|
| 531 | } | 
|---|
| 532 |  | 
|---|
| 533 | Datum | 
|---|
| 534 | network_subeq(PG_FUNCTION_ARGS) | 
|---|
| 535 | { | 
|---|
| 536 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 537 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 538 |  | 
|---|
| 539 | if (ip_family(a1) == ip_family(a2)) | 
|---|
| 540 | { | 
|---|
| 541 | PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) && | 
|---|
| 542 | bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0); | 
|---|
| 543 | } | 
|---|
| 544 |  | 
|---|
| 545 | PG_RETURN_BOOL(false); | 
|---|
| 546 | } | 
|---|
| 547 |  | 
|---|
| 548 | Datum | 
|---|
| 549 | network_sup(PG_FUNCTION_ARGS) | 
|---|
| 550 | { | 
|---|
| 551 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 552 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 553 |  | 
|---|
| 554 | if (ip_family(a1) == ip_family(a2)) | 
|---|
| 555 | { | 
|---|
| 556 | PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) && | 
|---|
| 557 | bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0); | 
|---|
| 558 | } | 
|---|
| 559 |  | 
|---|
| 560 | PG_RETURN_BOOL(false); | 
|---|
| 561 | } | 
|---|
| 562 |  | 
|---|
| 563 | Datum | 
|---|
| 564 | network_supeq(PG_FUNCTION_ARGS) | 
|---|
| 565 | { | 
|---|
| 566 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 567 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 568 |  | 
|---|
| 569 | if (ip_family(a1) == ip_family(a2)) | 
|---|
| 570 | { | 
|---|
| 571 | PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) && | 
|---|
| 572 | bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0); | 
|---|
| 573 | } | 
|---|
| 574 |  | 
|---|
| 575 | PG_RETURN_BOOL(false); | 
|---|
| 576 | } | 
|---|
| 577 |  | 
|---|
| 578 | Datum | 
|---|
| 579 | network_overlap(PG_FUNCTION_ARGS) | 
|---|
| 580 | { | 
|---|
| 581 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 582 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 583 |  | 
|---|
| 584 | if (ip_family(a1) == ip_family(a2)) | 
|---|
| 585 | { | 
|---|
| 586 | PG_RETURN_BOOL(bitncmp(ip_addr(a1), ip_addr(a2), | 
|---|
| 587 | Min(ip_bits(a1), ip_bits(a2))) == 0); | 
|---|
| 588 | } | 
|---|
| 589 |  | 
|---|
| 590 | PG_RETURN_BOOL(false); | 
|---|
| 591 | } | 
|---|
| 592 |  | 
|---|
| 593 | /* | 
|---|
| 594 | * Planner support function for network subset/superset operators | 
|---|
| 595 | */ | 
|---|
| 596 | Datum | 
|---|
| 597 | network_subset_support(PG_FUNCTION_ARGS) | 
|---|
| 598 | { | 
|---|
| 599 | Node	   *rawreq = (Node *) PG_GETARG_POINTER(0); | 
|---|
| 600 | Node	   *ret = NULL; | 
|---|
| 601 |  | 
|---|
| 602 | if (IsA(rawreq, SupportRequestIndexCondition)) | 
|---|
| 603 | { | 
|---|
| 604 | /* Try to convert operator/function call to index conditions */ | 
|---|
| 605 | SupportRequestIndexCondition *req = (SupportRequestIndexCondition *) rawreq; | 
|---|
| 606 |  | 
|---|
| 607 | if (is_opclause(req->node)) | 
|---|
| 608 | { | 
|---|
| 609 | OpExpr	   *clause = (OpExpr *) req->node; | 
|---|
| 610 |  | 
|---|
| 611 | Assert(list_length(clause->args) == 2); | 
|---|
| 612 | ret = (Node *) | 
|---|
| 613 | match_network_function((Node *) linitial(clause->args), | 
|---|
| 614 | (Node *) lsecond(clause->args), | 
|---|
| 615 | req->indexarg, | 
|---|
| 616 | req->funcid, | 
|---|
| 617 | req->opfamily); | 
|---|
| 618 | } | 
|---|
| 619 | else if (is_funcclause(req->node))	/* be paranoid */ | 
|---|
| 620 | { | 
|---|
| 621 | FuncExpr   *clause = (FuncExpr *) req->node; | 
|---|
| 622 |  | 
|---|
| 623 | Assert(list_length(clause->args) == 2); | 
|---|
| 624 | ret = (Node *) | 
|---|
| 625 | match_network_function((Node *) linitial(clause->args), | 
|---|
| 626 | (Node *) lsecond(clause->args), | 
|---|
| 627 | req->indexarg, | 
|---|
| 628 | req->funcid, | 
|---|
| 629 | req->opfamily); | 
|---|
| 630 | } | 
|---|
| 631 | } | 
|---|
| 632 |  | 
|---|
| 633 | PG_RETURN_POINTER(ret); | 
|---|
| 634 | } | 
|---|
| 635 |  | 
|---|
| 636 | /* | 
|---|
| 637 | * match_network_function | 
|---|
| 638 | *	  Try to generate an indexqual for a network subset/superset function. | 
|---|
| 639 | * | 
|---|
| 640 | * This layer is just concerned with identifying the function and swapping | 
|---|
| 641 | * the arguments if necessary. | 
|---|
| 642 | */ | 
|---|
| 643 | static List * | 
|---|
| 644 | match_network_function(Node *leftop, | 
|---|
| 645 | Node *rightop, | 
|---|
| 646 | int indexarg, | 
|---|
| 647 | Oid funcid, | 
|---|
| 648 | Oid opfamily) | 
|---|
| 649 | { | 
|---|
| 650 | switch (funcid) | 
|---|
| 651 | { | 
|---|
| 652 | case F_NETWORK_SUB: | 
|---|
| 653 | /* indexkey must be on the left */ | 
|---|
| 654 | if (indexarg != 0) | 
|---|
| 655 | return NIL; | 
|---|
| 656 | return match_network_subset(leftop, rightop, false, opfamily); | 
|---|
| 657 |  | 
|---|
| 658 | case F_NETWORK_SUBEQ: | 
|---|
| 659 | /* indexkey must be on the left */ | 
|---|
| 660 | if (indexarg != 0) | 
|---|
| 661 | return NIL; | 
|---|
| 662 | return match_network_subset(leftop, rightop, true, opfamily); | 
|---|
| 663 |  | 
|---|
| 664 | case F_NETWORK_SUP: | 
|---|
| 665 | /* indexkey must be on the right */ | 
|---|
| 666 | if (indexarg != 1) | 
|---|
| 667 | return NIL; | 
|---|
| 668 | return match_network_subset(rightop, leftop, false, opfamily); | 
|---|
| 669 |  | 
|---|
| 670 | case F_NETWORK_SUPEQ: | 
|---|
| 671 | /* indexkey must be on the right */ | 
|---|
| 672 | if (indexarg != 1) | 
|---|
| 673 | return NIL; | 
|---|
| 674 | return match_network_subset(rightop, leftop, true, opfamily); | 
|---|
| 675 |  | 
|---|
| 676 | default: | 
|---|
| 677 |  | 
|---|
| 678 | /* | 
|---|
| 679 | * We'd only get here if somebody attached this support function | 
|---|
| 680 | * to an unexpected function.  Maybe we should complain, but for | 
|---|
| 681 | * now, do nothing. | 
|---|
| 682 | */ | 
|---|
| 683 | return NIL; | 
|---|
| 684 | } | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | /* | 
|---|
| 688 | * match_network_subset | 
|---|
| 689 | *	  Try to generate an indexqual for a network subset function. | 
|---|
| 690 | */ | 
|---|
| 691 | static List * | 
|---|
| 692 | match_network_subset(Node *leftop, | 
|---|
| 693 | Node *rightop, | 
|---|
| 694 | bool is_eq, | 
|---|
| 695 | Oid opfamily) | 
|---|
| 696 | { | 
|---|
| 697 | List	   *result; | 
|---|
| 698 | Datum		rightopval; | 
|---|
| 699 | Oid			datatype = INETOID; | 
|---|
| 700 | Oid			opr1oid; | 
|---|
| 701 | Oid			opr2oid; | 
|---|
| 702 | Datum		opr1right; | 
|---|
| 703 | Datum		opr2right; | 
|---|
| 704 | Expr	   *expr; | 
|---|
| 705 |  | 
|---|
| 706 | /* | 
|---|
| 707 | * Can't do anything with a non-constant or NULL comparison value. | 
|---|
| 708 | * | 
|---|
| 709 | * Note that since we restrict ourselves to cases with a hard constant on | 
|---|
| 710 | * the RHS, it's a-fortiori a pseudoconstant, and we don't need to worry | 
|---|
| 711 | * about verifying that. | 
|---|
| 712 | */ | 
|---|
| 713 | if (!IsA(rightop, Const) || | 
|---|
| 714 | ((Const *) rightop)->constisnull) | 
|---|
| 715 | return NIL; | 
|---|
| 716 | rightopval = ((Const *) rightop)->constvalue; | 
|---|
| 717 |  | 
|---|
| 718 | /* | 
|---|
| 719 | * Must check that index's opfamily supports the operators we will want to | 
|---|
| 720 | * apply. | 
|---|
| 721 | * | 
|---|
| 722 | * We insist on the opfamily being the specific one we expect, else we'd | 
|---|
| 723 | * do the wrong thing if someone were to make a reverse-sort opfamily with | 
|---|
| 724 | * the same operators. | 
|---|
| 725 | */ | 
|---|
| 726 | if (opfamily != NETWORK_BTREE_FAM_OID) | 
|---|
| 727 | return NIL; | 
|---|
| 728 |  | 
|---|
| 729 | /* | 
|---|
| 730 | * create clause "key >= network_scan_first( rightopval )", or ">" if the | 
|---|
| 731 | * operator disallows equality. | 
|---|
| 732 | * | 
|---|
| 733 | * Note: seeing that this function supports only fixed values for opfamily | 
|---|
| 734 | * and datatype, we could just hard-wire the operator OIDs instead of | 
|---|
| 735 | * looking them up.  But for now it seems better to be general. | 
|---|
| 736 | */ | 
|---|
| 737 | if (is_eq) | 
|---|
| 738 | { | 
|---|
| 739 | opr1oid = get_opfamily_member(opfamily, datatype, datatype, | 
|---|
| 740 | BTGreaterEqualStrategyNumber); | 
|---|
| 741 | if (opr1oid == InvalidOid) | 
|---|
| 742 | elog(ERROR, "no >= operator for opfamily %u", opfamily); | 
|---|
| 743 | } | 
|---|
| 744 | else | 
|---|
| 745 | { | 
|---|
| 746 | opr1oid = get_opfamily_member(opfamily, datatype, datatype, | 
|---|
| 747 | BTGreaterStrategyNumber); | 
|---|
| 748 | if (opr1oid == InvalidOid) | 
|---|
| 749 | elog(ERROR, "no > operator for opfamily %u", opfamily); | 
|---|
| 750 | } | 
|---|
| 751 |  | 
|---|
| 752 | opr1right = network_scan_first(rightopval); | 
|---|
| 753 |  | 
|---|
| 754 | expr = make_opclause(opr1oid, BOOLOID, false, | 
|---|
| 755 | (Expr *) leftop, | 
|---|
| 756 | (Expr *) makeConst(datatype, -1, | 
|---|
| 757 | InvalidOid, /* not collatable */ | 
|---|
| 758 | -1, opr1right, | 
|---|
| 759 | false, false), | 
|---|
| 760 | InvalidOid, InvalidOid); | 
|---|
| 761 | result = list_make1(expr); | 
|---|
| 762 |  | 
|---|
| 763 | /* create clause "key <= network_scan_last( rightopval )" */ | 
|---|
| 764 |  | 
|---|
| 765 | opr2oid = get_opfamily_member(opfamily, datatype, datatype, | 
|---|
| 766 | BTLessEqualStrategyNumber); | 
|---|
| 767 | if (opr2oid == InvalidOid) | 
|---|
| 768 | elog(ERROR, "no <= operator for opfamily %u", opfamily); | 
|---|
| 769 |  | 
|---|
| 770 | opr2right = network_scan_last(rightopval); | 
|---|
| 771 |  | 
|---|
| 772 | expr = make_opclause(opr2oid, BOOLOID, false, | 
|---|
| 773 | (Expr *) leftop, | 
|---|
| 774 | (Expr *) makeConst(datatype, -1, | 
|---|
| 775 | InvalidOid, /* not collatable */ | 
|---|
| 776 | -1, opr2right, | 
|---|
| 777 | false, false), | 
|---|
| 778 | InvalidOid, InvalidOid); | 
|---|
| 779 | result = lappend(result, expr); | 
|---|
| 780 |  | 
|---|
| 781 | return result; | 
|---|
| 782 | } | 
|---|
| 783 |  | 
|---|
| 784 |  | 
|---|
| 785 | /* | 
|---|
| 786 | * Extract data from a network datatype. | 
|---|
| 787 | */ | 
|---|
| 788 | Datum | 
|---|
| 789 | network_host(PG_FUNCTION_ARGS) | 
|---|
| 790 | { | 
|---|
| 791 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 792 | char	   *ptr; | 
|---|
| 793 | char		tmp[sizeof( "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; | 
|---|
| 794 |  | 
|---|
| 795 | /* force display of max bits, regardless of masklen... */ | 
|---|
| 796 | if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip), | 
|---|
| 797 | tmp, sizeof(tmp)) == NULL) | 
|---|
| 798 | ereport(ERROR, | 
|---|
| 799 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 800 | errmsg( "could not format inet value: %m"))); | 
|---|
| 801 |  | 
|---|
| 802 | /* Suppress /n if present (shouldn't happen now) */ | 
|---|
| 803 | if ((ptr = strchr(tmp, '/')) != NULL) | 
|---|
| 804 | *ptr = '\0'; | 
|---|
| 805 |  | 
|---|
| 806 | PG_RETURN_TEXT_P(cstring_to_text(tmp)); | 
|---|
| 807 | } | 
|---|
| 808 |  | 
|---|
| 809 | /* | 
|---|
| 810 | * network_show implements the inet and cidr casts to text.  This is not | 
|---|
| 811 | * quite the same behavior as network_out, hence we can't drop it in favor | 
|---|
| 812 | * of CoerceViaIO. | 
|---|
| 813 | */ | 
|---|
| 814 | Datum | 
|---|
| 815 | network_show(PG_FUNCTION_ARGS) | 
|---|
| 816 | { | 
|---|
| 817 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 818 | int			len; | 
|---|
| 819 | char		tmp[sizeof( "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; | 
|---|
| 820 |  | 
|---|
| 821 | if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip), | 
|---|
| 822 | tmp, sizeof(tmp)) == NULL) | 
|---|
| 823 | ereport(ERROR, | 
|---|
| 824 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 825 | errmsg( "could not format inet value: %m"))); | 
|---|
| 826 |  | 
|---|
| 827 | /* Add /n if not present (which it won't be) */ | 
|---|
| 828 | if (strchr(tmp, '/') == NULL) | 
|---|
| 829 | { | 
|---|
| 830 | len = strlen(tmp); | 
|---|
| 831 | snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip)); | 
|---|
| 832 | } | 
|---|
| 833 |  | 
|---|
| 834 | PG_RETURN_TEXT_P(cstring_to_text(tmp)); | 
|---|
| 835 | } | 
|---|
| 836 |  | 
|---|
| 837 | Datum | 
|---|
| 838 | inet_abbrev(PG_FUNCTION_ARGS) | 
|---|
| 839 | { | 
|---|
| 840 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 841 | char	   *dst; | 
|---|
| 842 | char		tmp[sizeof( "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; | 
|---|
| 843 |  | 
|---|
| 844 | dst = inet_net_ntop(ip_family(ip), ip_addr(ip), | 
|---|
| 845 | ip_bits(ip), tmp, sizeof(tmp)); | 
|---|
| 846 |  | 
|---|
| 847 | if (dst == NULL) | 
|---|
| 848 | ereport(ERROR, | 
|---|
| 849 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 850 | errmsg( "could not format inet value: %m"))); | 
|---|
| 851 |  | 
|---|
| 852 | PG_RETURN_TEXT_P(cstring_to_text(tmp)); | 
|---|
| 853 | } | 
|---|
| 854 |  | 
|---|
| 855 | Datum | 
|---|
| 856 | cidr_abbrev(PG_FUNCTION_ARGS) | 
|---|
| 857 | { | 
|---|
| 858 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 859 | char	   *dst; | 
|---|
| 860 | char		tmp[sizeof( "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; | 
|---|
| 861 |  | 
|---|
| 862 | dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip), | 
|---|
| 863 | ip_bits(ip), tmp, sizeof(tmp)); | 
|---|
| 864 |  | 
|---|
| 865 | if (dst == NULL) | 
|---|
| 866 | ereport(ERROR, | 
|---|
| 867 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), | 
|---|
| 868 | errmsg( "could not format cidr value: %m"))); | 
|---|
| 869 |  | 
|---|
| 870 | PG_RETURN_TEXT_P(cstring_to_text(tmp)); | 
|---|
| 871 | } | 
|---|
| 872 |  | 
|---|
| 873 | Datum | 
|---|
| 874 | network_masklen(PG_FUNCTION_ARGS) | 
|---|
| 875 | { | 
|---|
| 876 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 877 |  | 
|---|
| 878 | PG_RETURN_INT32(ip_bits(ip)); | 
|---|
| 879 | } | 
|---|
| 880 |  | 
|---|
| 881 | Datum | 
|---|
| 882 | network_family(PG_FUNCTION_ARGS) | 
|---|
| 883 | { | 
|---|
| 884 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 885 |  | 
|---|
| 886 | switch (ip_family(ip)) | 
|---|
| 887 | { | 
|---|
| 888 | case PGSQL_AF_INET: | 
|---|
| 889 | PG_RETURN_INT32(4); | 
|---|
| 890 | break; | 
|---|
| 891 | case PGSQL_AF_INET6: | 
|---|
| 892 | PG_RETURN_INT32(6); | 
|---|
| 893 | break; | 
|---|
| 894 | default: | 
|---|
| 895 | PG_RETURN_INT32(0); | 
|---|
| 896 | break; | 
|---|
| 897 | } | 
|---|
| 898 | } | 
|---|
| 899 |  | 
|---|
| 900 | Datum | 
|---|
| 901 | network_broadcast(PG_FUNCTION_ARGS) | 
|---|
| 902 | { | 
|---|
| 903 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 904 | inet	   *dst; | 
|---|
| 905 | int			byte; | 
|---|
| 906 | int			bits; | 
|---|
| 907 | int			maxbytes; | 
|---|
| 908 | unsigned char mask; | 
|---|
| 909 | unsigned char *a, | 
|---|
| 910 | *b; | 
|---|
| 911 |  | 
|---|
| 912 | /* make sure any unused bits are zeroed */ | 
|---|
| 913 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 914 |  | 
|---|
| 915 | maxbytes = ip_addrsize(ip); | 
|---|
| 916 | bits = ip_bits(ip); | 
|---|
| 917 | a = ip_addr(ip); | 
|---|
| 918 | b = ip_addr(dst); | 
|---|
| 919 |  | 
|---|
| 920 | for (byte = 0; byte < maxbytes; byte++) | 
|---|
| 921 | { | 
|---|
| 922 | if (bits >= 8) | 
|---|
| 923 | { | 
|---|
| 924 | mask = 0x00; | 
|---|
| 925 | bits -= 8; | 
|---|
| 926 | } | 
|---|
| 927 | else if (bits == 0) | 
|---|
| 928 | mask = 0xff; | 
|---|
| 929 | else | 
|---|
| 930 | { | 
|---|
| 931 | mask = 0xff >> bits; | 
|---|
| 932 | bits = 0; | 
|---|
| 933 | } | 
|---|
| 934 |  | 
|---|
| 935 | b[byte] = a[byte] | mask; | 
|---|
| 936 | } | 
|---|
| 937 |  | 
|---|
| 938 | ip_family(dst) = ip_family(ip); | 
|---|
| 939 | ip_bits(dst) = ip_bits(ip); | 
|---|
| 940 | SET_INET_VARSIZE(dst); | 
|---|
| 941 |  | 
|---|
| 942 | PG_RETURN_INET_P(dst); | 
|---|
| 943 | } | 
|---|
| 944 |  | 
|---|
| 945 | Datum | 
|---|
| 946 | network_network(PG_FUNCTION_ARGS) | 
|---|
| 947 | { | 
|---|
| 948 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 949 | inet	   *dst; | 
|---|
| 950 | int			byte; | 
|---|
| 951 | int			bits; | 
|---|
| 952 | unsigned char mask; | 
|---|
| 953 | unsigned char *a, | 
|---|
| 954 | *b; | 
|---|
| 955 |  | 
|---|
| 956 | /* make sure any unused bits are zeroed */ | 
|---|
| 957 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 958 |  | 
|---|
| 959 | bits = ip_bits(ip); | 
|---|
| 960 | a = ip_addr(ip); | 
|---|
| 961 | b = ip_addr(dst); | 
|---|
| 962 |  | 
|---|
| 963 | byte = 0; | 
|---|
| 964 |  | 
|---|
| 965 | while (bits) | 
|---|
| 966 | { | 
|---|
| 967 | if (bits >= 8) | 
|---|
| 968 | { | 
|---|
| 969 | mask = 0xff; | 
|---|
| 970 | bits -= 8; | 
|---|
| 971 | } | 
|---|
| 972 | else | 
|---|
| 973 | { | 
|---|
| 974 | mask = 0xff << (8 - bits); | 
|---|
| 975 | bits = 0; | 
|---|
| 976 | } | 
|---|
| 977 |  | 
|---|
| 978 | b[byte] = a[byte] & mask; | 
|---|
| 979 | byte++; | 
|---|
| 980 | } | 
|---|
| 981 |  | 
|---|
| 982 | ip_family(dst) = ip_family(ip); | 
|---|
| 983 | ip_bits(dst) = ip_bits(ip); | 
|---|
| 984 | SET_INET_VARSIZE(dst); | 
|---|
| 985 |  | 
|---|
| 986 | PG_RETURN_INET_P(dst); | 
|---|
| 987 | } | 
|---|
| 988 |  | 
|---|
| 989 | Datum | 
|---|
| 990 | network_netmask(PG_FUNCTION_ARGS) | 
|---|
| 991 | { | 
|---|
| 992 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 993 | inet	   *dst; | 
|---|
| 994 | int			byte; | 
|---|
| 995 | int			bits; | 
|---|
| 996 | unsigned char mask; | 
|---|
| 997 | unsigned char *b; | 
|---|
| 998 |  | 
|---|
| 999 | /* make sure any unused bits are zeroed */ | 
|---|
| 1000 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 1001 |  | 
|---|
| 1002 | bits = ip_bits(ip); | 
|---|
| 1003 | b = ip_addr(dst); | 
|---|
| 1004 |  | 
|---|
| 1005 | byte = 0; | 
|---|
| 1006 |  | 
|---|
| 1007 | while (bits) | 
|---|
| 1008 | { | 
|---|
| 1009 | if (bits >= 8) | 
|---|
| 1010 | { | 
|---|
| 1011 | mask = 0xff; | 
|---|
| 1012 | bits -= 8; | 
|---|
| 1013 | } | 
|---|
| 1014 | else | 
|---|
| 1015 | { | 
|---|
| 1016 | mask = 0xff << (8 - bits); | 
|---|
| 1017 | bits = 0; | 
|---|
| 1018 | } | 
|---|
| 1019 |  | 
|---|
| 1020 | b[byte] = mask; | 
|---|
| 1021 | byte++; | 
|---|
| 1022 | } | 
|---|
| 1023 |  | 
|---|
| 1024 | ip_family(dst) = ip_family(ip); | 
|---|
| 1025 | ip_bits(dst) = ip_maxbits(ip); | 
|---|
| 1026 | SET_INET_VARSIZE(dst); | 
|---|
| 1027 |  | 
|---|
| 1028 | PG_RETURN_INET_P(dst); | 
|---|
| 1029 | } | 
|---|
| 1030 |  | 
|---|
| 1031 | Datum | 
|---|
| 1032 | network_hostmask(PG_FUNCTION_ARGS) | 
|---|
| 1033 | { | 
|---|
| 1034 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1035 | inet	   *dst; | 
|---|
| 1036 | int			byte; | 
|---|
| 1037 | int			bits; | 
|---|
| 1038 | int			maxbytes; | 
|---|
| 1039 | unsigned char mask; | 
|---|
| 1040 | unsigned char *b; | 
|---|
| 1041 |  | 
|---|
| 1042 | /* make sure any unused bits are zeroed */ | 
|---|
| 1043 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 1044 |  | 
|---|
| 1045 | maxbytes = ip_addrsize(ip); | 
|---|
| 1046 | bits = ip_maxbits(ip) - ip_bits(ip); | 
|---|
| 1047 | b = ip_addr(dst); | 
|---|
| 1048 |  | 
|---|
| 1049 | byte = maxbytes - 1; | 
|---|
| 1050 |  | 
|---|
| 1051 | while (bits) | 
|---|
| 1052 | { | 
|---|
| 1053 | if (bits >= 8) | 
|---|
| 1054 | { | 
|---|
| 1055 | mask = 0xff; | 
|---|
| 1056 | bits -= 8; | 
|---|
| 1057 | } | 
|---|
| 1058 | else | 
|---|
| 1059 | { | 
|---|
| 1060 | mask = 0xff >> (8 - bits); | 
|---|
| 1061 | bits = 0; | 
|---|
| 1062 | } | 
|---|
| 1063 |  | 
|---|
| 1064 | b[byte] = mask; | 
|---|
| 1065 | byte--; | 
|---|
| 1066 | } | 
|---|
| 1067 |  | 
|---|
| 1068 | ip_family(dst) = ip_family(ip); | 
|---|
| 1069 | ip_bits(dst) = ip_maxbits(ip); | 
|---|
| 1070 | SET_INET_VARSIZE(dst); | 
|---|
| 1071 |  | 
|---|
| 1072 | PG_RETURN_INET_P(dst); | 
|---|
| 1073 | } | 
|---|
| 1074 |  | 
|---|
| 1075 | /* | 
|---|
| 1076 | * Returns true if the addresses are from the same family, or false.  Used to | 
|---|
| 1077 | * check that we can create a network which contains both of the networks. | 
|---|
| 1078 | */ | 
|---|
| 1079 | Datum | 
|---|
| 1080 | inet_same_family(PG_FUNCTION_ARGS) | 
|---|
| 1081 | { | 
|---|
| 1082 | inet	   *a1 = PG_GETARG_INET_PP(0); | 
|---|
| 1083 | inet	   *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 1084 |  | 
|---|
| 1085 | PG_RETURN_BOOL(ip_family(a1) == ip_family(a2)); | 
|---|
| 1086 | } | 
|---|
| 1087 |  | 
|---|
| 1088 | /* | 
|---|
| 1089 | * Returns the smallest CIDR which contains both of the inputs. | 
|---|
| 1090 | */ | 
|---|
| 1091 | Datum | 
|---|
| 1092 | inet_merge(PG_FUNCTION_ARGS) | 
|---|
| 1093 | { | 
|---|
| 1094 | inet	   *a1 = PG_GETARG_INET_PP(0), | 
|---|
| 1095 | *a2 = PG_GETARG_INET_PP(1); | 
|---|
| 1096 | int			commonbits; | 
|---|
| 1097 |  | 
|---|
| 1098 | if (ip_family(a1) != ip_family(a2)) | 
|---|
| 1099 | ereport(ERROR, | 
|---|
| 1100 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 
|---|
| 1101 | errmsg( "cannot merge addresses from different families"))); | 
|---|
| 1102 |  | 
|---|
| 1103 | commonbits = bitncommon(ip_addr(a1), ip_addr(a2), | 
|---|
| 1104 | Min(ip_bits(a1), ip_bits(a2))); | 
|---|
| 1105 |  | 
|---|
| 1106 | PG_RETURN_INET_P(cidr_set_masklen_internal(a1, commonbits)); | 
|---|
| 1107 | } | 
|---|
| 1108 |  | 
|---|
| 1109 | /* | 
|---|
| 1110 | * Convert a value of a network datatype to an approximate scalar value. | 
|---|
| 1111 | * This is used for estimating selectivities of inequality operators | 
|---|
| 1112 | * involving network types. | 
|---|
| 1113 | * | 
|---|
| 1114 | * On failure (e.g., unsupported typid), set *failure to true; | 
|---|
| 1115 | * otherwise, that variable is not changed. | 
|---|
| 1116 | */ | 
|---|
| 1117 | double | 
|---|
| 1118 | convert_network_to_scalar(Datum value, Oid typid, bool *failure) | 
|---|
| 1119 | { | 
|---|
| 1120 | switch (typid) | 
|---|
| 1121 | { | 
|---|
| 1122 | case INETOID: | 
|---|
| 1123 | case CIDROID: | 
|---|
| 1124 | { | 
|---|
| 1125 | inet	   *ip = DatumGetInetPP(value); | 
|---|
| 1126 | int			len; | 
|---|
| 1127 | double		res; | 
|---|
| 1128 | int			i; | 
|---|
| 1129 |  | 
|---|
| 1130 | /* | 
|---|
| 1131 | * Note that we don't use the full address for IPv6. | 
|---|
| 1132 | */ | 
|---|
| 1133 | if (ip_family(ip) == PGSQL_AF_INET) | 
|---|
| 1134 | len = 4; | 
|---|
| 1135 | else | 
|---|
| 1136 | len = 5; | 
|---|
| 1137 |  | 
|---|
| 1138 | res = ip_family(ip); | 
|---|
| 1139 | for (i = 0; i < len; i++) | 
|---|
| 1140 | { | 
|---|
| 1141 | res *= 256; | 
|---|
| 1142 | res += ip_addr(ip)[i]; | 
|---|
| 1143 | } | 
|---|
| 1144 | return res; | 
|---|
| 1145 | } | 
|---|
| 1146 | case MACADDROID: | 
|---|
| 1147 | { | 
|---|
| 1148 | macaddr    *mac = DatumGetMacaddrP(value); | 
|---|
| 1149 | double		res; | 
|---|
| 1150 |  | 
|---|
| 1151 | res = (mac->a << 16) | (mac->b << 8) | (mac->c); | 
|---|
| 1152 | res *= 256 * 256 * 256; | 
|---|
| 1153 | res += (mac->d << 16) | (mac->e << 8) | (mac->f); | 
|---|
| 1154 | return res; | 
|---|
| 1155 | } | 
|---|
| 1156 | case MACADDR8OID: | 
|---|
| 1157 | { | 
|---|
| 1158 | macaddr8   *mac = DatumGetMacaddr8P(value); | 
|---|
| 1159 | double		res; | 
|---|
| 1160 |  | 
|---|
| 1161 | res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d); | 
|---|
| 1162 | res *= ((double) 256) * 256 * 256 * 256; | 
|---|
| 1163 | res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h); | 
|---|
| 1164 | return res; | 
|---|
| 1165 | } | 
|---|
| 1166 | } | 
|---|
| 1167 |  | 
|---|
| 1168 | *failure = true; | 
|---|
| 1169 | return 0; | 
|---|
| 1170 | } | 
|---|
| 1171 |  | 
|---|
| 1172 | /* | 
|---|
| 1173 | * int | 
|---|
| 1174 | * bitncmp(l, r, n) | 
|---|
| 1175 | *		compare bit masks l and r, for n bits. | 
|---|
| 1176 | * return: | 
|---|
| 1177 | *		<0, >0, or 0 in the libc tradition. | 
|---|
| 1178 | * note: | 
|---|
| 1179 | *		network byte order assumed.  this means 192.5.5.240/28 has | 
|---|
| 1180 | *		0x11110000 in its fourth octet. | 
|---|
| 1181 | * author: | 
|---|
| 1182 | *		Paul Vixie (ISC), June 1996 | 
|---|
| 1183 | */ | 
|---|
| 1184 | int | 
|---|
| 1185 | bitncmp(const unsigned char *l, const unsigned char *r, int n) | 
|---|
| 1186 | { | 
|---|
| 1187 | unsigned int lb, | 
|---|
| 1188 | rb; | 
|---|
| 1189 | int			x, | 
|---|
| 1190 | b; | 
|---|
| 1191 |  | 
|---|
| 1192 | b = n / 8; | 
|---|
| 1193 | x = memcmp(l, r, b); | 
|---|
| 1194 | if (x || (n % 8) == 0) | 
|---|
| 1195 | return x; | 
|---|
| 1196 |  | 
|---|
| 1197 | lb = l[b]; | 
|---|
| 1198 | rb = r[b]; | 
|---|
| 1199 | for (b = n % 8; b > 0; b--) | 
|---|
| 1200 | { | 
|---|
| 1201 | if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb)) | 
|---|
| 1202 | { | 
|---|
| 1203 | if (IS_HIGHBIT_SET(lb)) | 
|---|
| 1204 | return 1; | 
|---|
| 1205 | return -1; | 
|---|
| 1206 | } | 
|---|
| 1207 | lb <<= 1; | 
|---|
| 1208 | rb <<= 1; | 
|---|
| 1209 | } | 
|---|
| 1210 | return 0; | 
|---|
| 1211 | } | 
|---|
| 1212 |  | 
|---|
| 1213 | /* | 
|---|
| 1214 | * bitncommon: compare bit masks l and r, for up to n bits. | 
|---|
| 1215 | * | 
|---|
| 1216 | * Returns the number of leading bits that match (0 to n). | 
|---|
| 1217 | */ | 
|---|
| 1218 | int | 
|---|
| 1219 | bitncommon(const unsigned char *l, const unsigned char *r, int n) | 
|---|
| 1220 | { | 
|---|
| 1221 | int			byte, | 
|---|
| 1222 | nbits; | 
|---|
| 1223 |  | 
|---|
| 1224 | /* number of bits to examine in last byte */ | 
|---|
| 1225 | nbits = n % 8; | 
|---|
| 1226 |  | 
|---|
| 1227 | /* check whole bytes */ | 
|---|
| 1228 | for (byte = 0; byte < n / 8; byte++) | 
|---|
| 1229 | { | 
|---|
| 1230 | if (l[byte] != r[byte]) | 
|---|
| 1231 | { | 
|---|
| 1232 | /* at least one bit in the last byte is not common */ | 
|---|
| 1233 | nbits = 7; | 
|---|
| 1234 | break; | 
|---|
| 1235 | } | 
|---|
| 1236 | } | 
|---|
| 1237 |  | 
|---|
| 1238 | /* check bits in last partial byte */ | 
|---|
| 1239 | if (nbits != 0) | 
|---|
| 1240 | { | 
|---|
| 1241 | /* calculate diff of first non-matching bytes */ | 
|---|
| 1242 | unsigned int diff = l[byte] ^ r[byte]; | 
|---|
| 1243 |  | 
|---|
| 1244 | /* compare the bits from the most to the least */ | 
|---|
| 1245 | while ((diff >> (8 - nbits)) != 0) | 
|---|
| 1246 | nbits--; | 
|---|
| 1247 | } | 
|---|
| 1248 |  | 
|---|
| 1249 | return (8 * byte) + nbits; | 
|---|
| 1250 | } | 
|---|
| 1251 |  | 
|---|
| 1252 |  | 
|---|
| 1253 | /* | 
|---|
| 1254 | * Verify a CIDR address is OK (doesn't have bits set past the masklen) | 
|---|
| 1255 | */ | 
|---|
| 1256 | static bool | 
|---|
| 1257 | addressOK(unsigned char *a, int bits, int family) | 
|---|
| 1258 | { | 
|---|
| 1259 | int			byte; | 
|---|
| 1260 | int			nbits; | 
|---|
| 1261 | int			maxbits; | 
|---|
| 1262 | int			maxbytes; | 
|---|
| 1263 | unsigned char mask; | 
|---|
| 1264 |  | 
|---|
| 1265 | if (family == PGSQL_AF_INET) | 
|---|
| 1266 | { | 
|---|
| 1267 | maxbits = 32; | 
|---|
| 1268 | maxbytes = 4; | 
|---|
| 1269 | } | 
|---|
| 1270 | else | 
|---|
| 1271 | { | 
|---|
| 1272 | maxbits = 128; | 
|---|
| 1273 | maxbytes = 16; | 
|---|
| 1274 | } | 
|---|
| 1275 | Assert(bits <= maxbits); | 
|---|
| 1276 |  | 
|---|
| 1277 | if (bits == maxbits) | 
|---|
| 1278 | return true; | 
|---|
| 1279 |  | 
|---|
| 1280 | byte = bits / 8; | 
|---|
| 1281 |  | 
|---|
| 1282 | nbits = bits % 8; | 
|---|
| 1283 | mask = 0xff; | 
|---|
| 1284 | if (bits != 0) | 
|---|
| 1285 | mask >>= nbits; | 
|---|
| 1286 |  | 
|---|
| 1287 | while (byte < maxbytes) | 
|---|
| 1288 | { | 
|---|
| 1289 | if ((a[byte] & mask) != 0) | 
|---|
| 1290 | return false; | 
|---|
| 1291 | mask = 0xff; | 
|---|
| 1292 | byte++; | 
|---|
| 1293 | } | 
|---|
| 1294 |  | 
|---|
| 1295 | return true; | 
|---|
| 1296 | } | 
|---|
| 1297 |  | 
|---|
| 1298 |  | 
|---|
| 1299 | /* | 
|---|
| 1300 | * These functions are used by planner to generate indexscan limits | 
|---|
| 1301 | * for clauses a << b and a <<= b | 
|---|
| 1302 | */ | 
|---|
| 1303 |  | 
|---|
| 1304 | /* return the minimal value for an IP on a given network */ | 
|---|
| 1305 | Datum | 
|---|
| 1306 | network_scan_first(Datum in) | 
|---|
| 1307 | { | 
|---|
| 1308 | return DirectFunctionCall1(network_network, in); | 
|---|
| 1309 | } | 
|---|
| 1310 |  | 
|---|
| 1311 | /* | 
|---|
| 1312 | * return "last" IP on a given network. It's the broadcast address, | 
|---|
| 1313 | * however, masklen has to be set to its max bits, since | 
|---|
| 1314 | * 192.168.0.255/24 is considered less than 192.168.0.255/32 | 
|---|
| 1315 | * | 
|---|
| 1316 | * inet_set_masklen() hacked to max out the masklength to 128 for IPv6 | 
|---|
| 1317 | * and 32 for IPv4 when given '-1' as argument. | 
|---|
| 1318 | */ | 
|---|
| 1319 | Datum | 
|---|
| 1320 | network_scan_last(Datum in) | 
|---|
| 1321 | { | 
|---|
| 1322 | return DirectFunctionCall2(inet_set_masklen, | 
|---|
| 1323 | DirectFunctionCall1(network_broadcast, in), | 
|---|
| 1324 | Int32GetDatum(-1)); | 
|---|
| 1325 | } | 
|---|
| 1326 |  | 
|---|
| 1327 |  | 
|---|
| 1328 | /* | 
|---|
| 1329 | * IP address that the client is connecting from (NULL if Unix socket) | 
|---|
| 1330 | */ | 
|---|
| 1331 | Datum | 
|---|
| 1332 | inet_client_addr(PG_FUNCTION_ARGS) | 
|---|
| 1333 | { | 
|---|
| 1334 | Port	   *port = MyProcPort; | 
|---|
| 1335 | char		remote_host[NI_MAXHOST]; | 
|---|
| 1336 | int			ret; | 
|---|
| 1337 |  | 
|---|
| 1338 | if (port == NULL) | 
|---|
| 1339 | PG_RETURN_NULL(); | 
|---|
| 1340 |  | 
|---|
| 1341 | switch (port->raddr.addr.ss_family) | 
|---|
| 1342 | { | 
|---|
| 1343 | case AF_INET: | 
|---|
| 1344 | #ifdef HAVE_IPV6 | 
|---|
| 1345 | case AF_INET6: | 
|---|
| 1346 | #endif | 
|---|
| 1347 | break; | 
|---|
| 1348 | default: | 
|---|
| 1349 | PG_RETURN_NULL(); | 
|---|
| 1350 | } | 
|---|
| 1351 |  | 
|---|
| 1352 | remote_host[0] = '\0'; | 
|---|
| 1353 |  | 
|---|
| 1354 | ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, | 
|---|
| 1355 | remote_host, sizeof(remote_host), | 
|---|
| 1356 | NULL, 0, | 
|---|
| 1357 | NI_NUMERICHOST | NI_NUMERICSERV); | 
|---|
| 1358 | if (ret != 0) | 
|---|
| 1359 | PG_RETURN_NULL(); | 
|---|
| 1360 |  | 
|---|
| 1361 | clean_ipv6_addr(port->raddr.addr.ss_family, remote_host); | 
|---|
| 1362 |  | 
|---|
| 1363 | PG_RETURN_INET_P(network_in(remote_host, false)); | 
|---|
| 1364 | } | 
|---|
| 1365 |  | 
|---|
| 1366 |  | 
|---|
| 1367 | /* | 
|---|
| 1368 | * port that the client is connecting from (NULL if Unix socket) | 
|---|
| 1369 | */ | 
|---|
| 1370 | Datum | 
|---|
| 1371 | inet_client_port(PG_FUNCTION_ARGS) | 
|---|
| 1372 | { | 
|---|
| 1373 | Port	   *port = MyProcPort; | 
|---|
| 1374 | char		remote_port[NI_MAXSERV]; | 
|---|
| 1375 | int			ret; | 
|---|
| 1376 |  | 
|---|
| 1377 | if (port == NULL) | 
|---|
| 1378 | PG_RETURN_NULL(); | 
|---|
| 1379 |  | 
|---|
| 1380 | switch (port->raddr.addr.ss_family) | 
|---|
| 1381 | { | 
|---|
| 1382 | case AF_INET: | 
|---|
| 1383 | #ifdef HAVE_IPV6 | 
|---|
| 1384 | case AF_INET6: | 
|---|
| 1385 | #endif | 
|---|
| 1386 | break; | 
|---|
| 1387 | default: | 
|---|
| 1388 | PG_RETURN_NULL(); | 
|---|
| 1389 | } | 
|---|
| 1390 |  | 
|---|
| 1391 | remote_port[0] = '\0'; | 
|---|
| 1392 |  | 
|---|
| 1393 | ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, | 
|---|
| 1394 | NULL, 0, | 
|---|
| 1395 | remote_port, sizeof(remote_port), | 
|---|
| 1396 | NI_NUMERICHOST | NI_NUMERICSERV); | 
|---|
| 1397 | if (ret != 0) | 
|---|
| 1398 | PG_RETURN_NULL(); | 
|---|
| 1399 |  | 
|---|
| 1400 | PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port))); | 
|---|
| 1401 | } | 
|---|
| 1402 |  | 
|---|
| 1403 |  | 
|---|
| 1404 | /* | 
|---|
| 1405 | * IP address that the server accepted the connection on (NULL if Unix socket) | 
|---|
| 1406 | */ | 
|---|
| 1407 | Datum | 
|---|
| 1408 | inet_server_addr(PG_FUNCTION_ARGS) | 
|---|
| 1409 | { | 
|---|
| 1410 | Port	   *port = MyProcPort; | 
|---|
| 1411 | char		local_host[NI_MAXHOST]; | 
|---|
| 1412 | int			ret; | 
|---|
| 1413 |  | 
|---|
| 1414 | if (port == NULL) | 
|---|
| 1415 | PG_RETURN_NULL(); | 
|---|
| 1416 |  | 
|---|
| 1417 | switch (port->laddr.addr.ss_family) | 
|---|
| 1418 | { | 
|---|
| 1419 | case AF_INET: | 
|---|
| 1420 | #ifdef HAVE_IPV6 | 
|---|
| 1421 | case AF_INET6: | 
|---|
| 1422 | #endif | 
|---|
| 1423 | break; | 
|---|
| 1424 | default: | 
|---|
| 1425 | PG_RETURN_NULL(); | 
|---|
| 1426 | } | 
|---|
| 1427 |  | 
|---|
| 1428 | local_host[0] = '\0'; | 
|---|
| 1429 |  | 
|---|
| 1430 | ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen, | 
|---|
| 1431 | local_host, sizeof(local_host), | 
|---|
| 1432 | NULL, 0, | 
|---|
| 1433 | NI_NUMERICHOST | NI_NUMERICSERV); | 
|---|
| 1434 | if (ret != 0) | 
|---|
| 1435 | PG_RETURN_NULL(); | 
|---|
| 1436 |  | 
|---|
| 1437 | clean_ipv6_addr(port->laddr.addr.ss_family, local_host); | 
|---|
| 1438 |  | 
|---|
| 1439 | PG_RETURN_INET_P(network_in(local_host, false)); | 
|---|
| 1440 | } | 
|---|
| 1441 |  | 
|---|
| 1442 |  | 
|---|
| 1443 | /* | 
|---|
| 1444 | * port that the server accepted the connection on (NULL if Unix socket) | 
|---|
| 1445 | */ | 
|---|
| 1446 | Datum | 
|---|
| 1447 | inet_server_port(PG_FUNCTION_ARGS) | 
|---|
| 1448 | { | 
|---|
| 1449 | Port	   *port = MyProcPort; | 
|---|
| 1450 | char		local_port[NI_MAXSERV]; | 
|---|
| 1451 | int			ret; | 
|---|
| 1452 |  | 
|---|
| 1453 | if (port == NULL) | 
|---|
| 1454 | PG_RETURN_NULL(); | 
|---|
| 1455 |  | 
|---|
| 1456 | switch (port->laddr.addr.ss_family) | 
|---|
| 1457 | { | 
|---|
| 1458 | case AF_INET: | 
|---|
| 1459 | #ifdef HAVE_IPV6 | 
|---|
| 1460 | case AF_INET6: | 
|---|
| 1461 | #endif | 
|---|
| 1462 | break; | 
|---|
| 1463 | default: | 
|---|
| 1464 | PG_RETURN_NULL(); | 
|---|
| 1465 | } | 
|---|
| 1466 |  | 
|---|
| 1467 | local_port[0] = '\0'; | 
|---|
| 1468 |  | 
|---|
| 1469 | ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen, | 
|---|
| 1470 | NULL, 0, | 
|---|
| 1471 | local_port, sizeof(local_port), | 
|---|
| 1472 | NI_NUMERICHOST | NI_NUMERICSERV); | 
|---|
| 1473 | if (ret != 0) | 
|---|
| 1474 | PG_RETURN_NULL(); | 
|---|
| 1475 |  | 
|---|
| 1476 | PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port))); | 
|---|
| 1477 | } | 
|---|
| 1478 |  | 
|---|
| 1479 |  | 
|---|
| 1480 | Datum | 
|---|
| 1481 | inetnot(PG_FUNCTION_ARGS) | 
|---|
| 1482 | { | 
|---|
| 1483 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1484 | inet	   *dst; | 
|---|
| 1485 |  | 
|---|
| 1486 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 1487 |  | 
|---|
| 1488 | { | 
|---|
| 1489 | int			nb = ip_addrsize(ip); | 
|---|
| 1490 | unsigned char *pip = ip_addr(ip); | 
|---|
| 1491 | unsigned char *pdst = ip_addr(dst); | 
|---|
| 1492 |  | 
|---|
| 1493 | while (nb-- > 0) | 
|---|
| 1494 | pdst[nb] = ~pip[nb]; | 
|---|
| 1495 | } | 
|---|
| 1496 | ip_bits(dst) = ip_bits(ip); | 
|---|
| 1497 |  | 
|---|
| 1498 | ip_family(dst) = ip_family(ip); | 
|---|
| 1499 | SET_INET_VARSIZE(dst); | 
|---|
| 1500 |  | 
|---|
| 1501 | PG_RETURN_INET_P(dst); | 
|---|
| 1502 | } | 
|---|
| 1503 |  | 
|---|
| 1504 |  | 
|---|
| 1505 | Datum | 
|---|
| 1506 | inetand(PG_FUNCTION_ARGS) | 
|---|
| 1507 | { | 
|---|
| 1508 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1509 | inet	   *ip2 = PG_GETARG_INET_PP(1); | 
|---|
| 1510 | inet	   *dst; | 
|---|
| 1511 |  | 
|---|
| 1512 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 1513 |  | 
|---|
| 1514 | if (ip_family(ip) != ip_family(ip2)) | 
|---|
| 1515 | ereport(ERROR, | 
|---|
| 1516 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 
|---|
| 1517 | errmsg( "cannot AND inet values of different sizes"))); | 
|---|
| 1518 | else | 
|---|
| 1519 | { | 
|---|
| 1520 | int			nb = ip_addrsize(ip); | 
|---|
| 1521 | unsigned char *pip = ip_addr(ip); | 
|---|
| 1522 | unsigned char *pip2 = ip_addr(ip2); | 
|---|
| 1523 | unsigned char *pdst = ip_addr(dst); | 
|---|
| 1524 |  | 
|---|
| 1525 | while (nb-- > 0) | 
|---|
| 1526 | pdst[nb] = pip[nb] & pip2[nb]; | 
|---|
| 1527 | } | 
|---|
| 1528 | ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); | 
|---|
| 1529 |  | 
|---|
| 1530 | ip_family(dst) = ip_family(ip); | 
|---|
| 1531 | SET_INET_VARSIZE(dst); | 
|---|
| 1532 |  | 
|---|
| 1533 | PG_RETURN_INET_P(dst); | 
|---|
| 1534 | } | 
|---|
| 1535 |  | 
|---|
| 1536 |  | 
|---|
| 1537 | Datum | 
|---|
| 1538 | inetor(PG_FUNCTION_ARGS) | 
|---|
| 1539 | { | 
|---|
| 1540 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1541 | inet	   *ip2 = PG_GETARG_INET_PP(1); | 
|---|
| 1542 | inet	   *dst; | 
|---|
| 1543 |  | 
|---|
| 1544 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 1545 |  | 
|---|
| 1546 | if (ip_family(ip) != ip_family(ip2)) | 
|---|
| 1547 | ereport(ERROR, | 
|---|
| 1548 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 
|---|
| 1549 | errmsg( "cannot OR inet values of different sizes"))); | 
|---|
| 1550 | else | 
|---|
| 1551 | { | 
|---|
| 1552 | int			nb = ip_addrsize(ip); | 
|---|
| 1553 | unsigned char *pip = ip_addr(ip); | 
|---|
| 1554 | unsigned char *pip2 = ip_addr(ip2); | 
|---|
| 1555 | unsigned char *pdst = ip_addr(dst); | 
|---|
| 1556 |  | 
|---|
| 1557 | while (nb-- > 0) | 
|---|
| 1558 | pdst[nb] = pip[nb] | pip2[nb]; | 
|---|
| 1559 | } | 
|---|
| 1560 | ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); | 
|---|
| 1561 |  | 
|---|
| 1562 | ip_family(dst) = ip_family(ip); | 
|---|
| 1563 | SET_INET_VARSIZE(dst); | 
|---|
| 1564 |  | 
|---|
| 1565 | PG_RETURN_INET_P(dst); | 
|---|
| 1566 | } | 
|---|
| 1567 |  | 
|---|
| 1568 |  | 
|---|
| 1569 | static inet * | 
|---|
| 1570 | internal_inetpl(inet *ip, int64 addend) | 
|---|
| 1571 | { | 
|---|
| 1572 | inet	   *dst; | 
|---|
| 1573 |  | 
|---|
| 1574 | dst = (inet *) palloc0(sizeof(inet)); | 
|---|
| 1575 |  | 
|---|
| 1576 | { | 
|---|
| 1577 | int			nb = ip_addrsize(ip); | 
|---|
| 1578 | unsigned char *pip = ip_addr(ip); | 
|---|
| 1579 | unsigned char *pdst = ip_addr(dst); | 
|---|
| 1580 | int			carry = 0; | 
|---|
| 1581 |  | 
|---|
| 1582 | while (nb-- > 0) | 
|---|
| 1583 | { | 
|---|
| 1584 | carry = pip[nb] + (int) (addend & 0xFF) + carry; | 
|---|
| 1585 | pdst[nb] = (unsigned char) (carry & 0xFF); | 
|---|
| 1586 | carry >>= 8; | 
|---|
| 1587 |  | 
|---|
| 1588 | /* | 
|---|
| 1589 | * We have to be careful about right-shifting addend because | 
|---|
| 1590 | * right-shift isn't portable for negative values, while simply | 
|---|
| 1591 | * dividing by 256 doesn't work (the standard rounding is in the | 
|---|
| 1592 | * wrong direction, besides which there may be machines out there | 
|---|
| 1593 | * that round the wrong way).  So, explicitly clear the low-order | 
|---|
| 1594 | * byte to remove any doubt about the correct result of the | 
|---|
| 1595 | * division, and then divide rather than shift. | 
|---|
| 1596 | */ | 
|---|
| 1597 | addend &= ~((int64) 0xFF); | 
|---|
| 1598 | addend /= 0x100; | 
|---|
| 1599 | } | 
|---|
| 1600 |  | 
|---|
| 1601 | /* | 
|---|
| 1602 | * At this point we should have addend and carry both zero if original | 
|---|
| 1603 | * addend was >= 0, or addend -1 and carry 1 if original addend was < | 
|---|
| 1604 | * 0.  Anything else means overflow. | 
|---|
| 1605 | */ | 
|---|
| 1606 | if (!((addend == 0 && carry == 0) || | 
|---|
| 1607 | (addend == -1 && carry == 1))) | 
|---|
| 1608 | ereport(ERROR, | 
|---|
| 1609 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), | 
|---|
| 1610 | errmsg( "result is out of range"))); | 
|---|
| 1611 | } | 
|---|
| 1612 |  | 
|---|
| 1613 | ip_bits(dst) = ip_bits(ip); | 
|---|
| 1614 | ip_family(dst) = ip_family(ip); | 
|---|
| 1615 | SET_INET_VARSIZE(dst); | 
|---|
| 1616 |  | 
|---|
| 1617 | return dst; | 
|---|
| 1618 | } | 
|---|
| 1619 |  | 
|---|
| 1620 |  | 
|---|
| 1621 | Datum | 
|---|
| 1622 | inetpl(PG_FUNCTION_ARGS) | 
|---|
| 1623 | { | 
|---|
| 1624 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1625 | int64		addend = PG_GETARG_INT64(1); | 
|---|
| 1626 |  | 
|---|
| 1627 | PG_RETURN_INET_P(internal_inetpl(ip, addend)); | 
|---|
| 1628 | } | 
|---|
| 1629 |  | 
|---|
| 1630 |  | 
|---|
| 1631 | Datum | 
|---|
| 1632 | inetmi_int8(PG_FUNCTION_ARGS) | 
|---|
| 1633 | { | 
|---|
| 1634 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1635 | int64		addend = PG_GETARG_INT64(1); | 
|---|
| 1636 |  | 
|---|
| 1637 | PG_RETURN_INET_P(internal_inetpl(ip, -addend)); | 
|---|
| 1638 | } | 
|---|
| 1639 |  | 
|---|
| 1640 |  | 
|---|
| 1641 | Datum | 
|---|
| 1642 | inetmi(PG_FUNCTION_ARGS) | 
|---|
| 1643 | { | 
|---|
| 1644 | inet	   *ip = PG_GETARG_INET_PP(0); | 
|---|
| 1645 | inet	   *ip2 = PG_GETARG_INET_PP(1); | 
|---|
| 1646 | int64		res = 0; | 
|---|
| 1647 |  | 
|---|
| 1648 | if (ip_family(ip) != ip_family(ip2)) | 
|---|
| 1649 | ereport(ERROR, | 
|---|
| 1650 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | 
|---|
| 1651 | errmsg( "cannot subtract inet values of different sizes"))); | 
|---|
| 1652 | else | 
|---|
| 1653 | { | 
|---|
| 1654 | /* | 
|---|
| 1655 | * We form the difference using the traditional complement, increment, | 
|---|
| 1656 | * and add rule, with the increment part being handled by starting the | 
|---|
| 1657 | * carry off at 1.  If you don't think integer arithmetic is done in | 
|---|
| 1658 | * two's complement, too bad. | 
|---|
| 1659 | */ | 
|---|
| 1660 | int			nb = ip_addrsize(ip); | 
|---|
| 1661 | int			byte = 0; | 
|---|
| 1662 | unsigned char *pip = ip_addr(ip); | 
|---|
| 1663 | unsigned char *pip2 = ip_addr(ip2); | 
|---|
| 1664 | int			carry = 1; | 
|---|
| 1665 |  | 
|---|
| 1666 | while (nb-- > 0) | 
|---|
| 1667 | { | 
|---|
| 1668 | int			lobyte; | 
|---|
| 1669 |  | 
|---|
| 1670 | carry = pip[nb] + (~pip2[nb] & 0xFF) + carry; | 
|---|
| 1671 | lobyte = carry & 0xFF; | 
|---|
| 1672 | if (byte < sizeof(int64)) | 
|---|
| 1673 | { | 
|---|
| 1674 | res |= ((int64) lobyte) << (byte * 8); | 
|---|
| 1675 | } | 
|---|
| 1676 | else | 
|---|
| 1677 | { | 
|---|
| 1678 | /* | 
|---|
| 1679 | * Input wider than int64: check for overflow.  All bytes to | 
|---|
| 1680 | * the left of what will fit should be 0 or 0xFF, depending on | 
|---|
| 1681 | * sign of the now-complete result. | 
|---|
| 1682 | */ | 
|---|
| 1683 | if ((res < 0) ? (lobyte != 0xFF) : (lobyte != 0)) | 
|---|
| 1684 | ereport(ERROR, | 
|---|
| 1685 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), | 
|---|
| 1686 | errmsg( "result is out of range"))); | 
|---|
| 1687 | } | 
|---|
| 1688 | carry >>= 8; | 
|---|
| 1689 | byte++; | 
|---|
| 1690 | } | 
|---|
| 1691 |  | 
|---|
| 1692 | /* | 
|---|
| 1693 | * If input is narrower than int64, overflow is not possible, but we | 
|---|
| 1694 | * have to do proper sign extension. | 
|---|
| 1695 | */ | 
|---|
| 1696 | if (carry == 0 && byte < sizeof(int64)) | 
|---|
| 1697 | res |= ((uint64) (int64) -1) << (byte * 8); | 
|---|
| 1698 | } | 
|---|
| 1699 |  | 
|---|
| 1700 | PG_RETURN_INT64(res); | 
|---|
| 1701 | } | 
|---|
| 1702 |  | 
|---|
| 1703 |  | 
|---|
| 1704 | /* | 
|---|
| 1705 | * clean_ipv6_addr --- remove any '%zone' part from an IPv6 address string | 
|---|
| 1706 | * | 
|---|
| 1707 | * XXX This should go away someday! | 
|---|
| 1708 | * | 
|---|
| 1709 | * This is a kluge needed because we don't yet support zones in stored inet | 
|---|
| 1710 | * values.  Since the result of getnameinfo() might include a zone spec, | 
|---|
| 1711 | * call this to remove it anywhere we want to feed getnameinfo's output to | 
|---|
| 1712 | * network_in.  Beats failing entirely. | 
|---|
| 1713 | * | 
|---|
| 1714 | * An alternative approach would be to let network_in ignore %-parts for | 
|---|
| 1715 | * itself, but that would mean we'd silently drop zone specs in user input, | 
|---|
| 1716 | * which seems not such a good idea. | 
|---|
| 1717 | */ | 
|---|
| 1718 | void | 
|---|
| 1719 | clean_ipv6_addr(int addr_family, char *addr) | 
|---|
| 1720 | { | 
|---|
| 1721 | #ifdef HAVE_IPV6 | 
|---|
| 1722 | if (addr_family == AF_INET6) | 
|---|
| 1723 | { | 
|---|
| 1724 | char	   *pct = strchr(addr, '%'); | 
|---|
| 1725 |  | 
|---|
| 1726 | if (pct) | 
|---|
| 1727 | *pct = '\0'; | 
|---|
| 1728 | } | 
|---|
| 1729 | #endif | 
|---|
| 1730 | } | 
|---|
| 1731 |  | 
|---|