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 | |