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