Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / utils / adt / inet_net_ntop.c
blob9dde495ae72325538ff9e22e2acedf56fc32f6e0
1 /*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996,1999 by Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $PostgreSQL$
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
22 #endif
24 #include "postgres.h"
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
31 #include "utils/builtins.h"
32 #include "utils/inet.h"
35 #define NS_IN6ADDRSZ 16
36 #define NS_INT16SZ 2
38 #ifdef SPRINTF_CHAR
39 #define SPRINTF(x) strlen(sprintf/**/x)
40 #else
41 #define SPRINTF(x) ((size_t)sprintf x)
42 #endif
44 static char *inet_net_ntop_ipv4(const u_char *src, int bits,
45 char *dst, size_t size);
46 static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
47 char *dst, size_t size);
48 static char *inet_net_ntop_ipv6(const u_char *src, int bits,
49 char *dst, size_t size);
50 static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
51 char *dst, size_t size);
54 * char *
55 * inet_cidr_ntop(af, src, bits, dst, size)
56 * convert network number from network to presentation format.
57 * generates CIDR style result always.
58 * return:
59 * pointer to dst, or NULL if an error occurred (check errno).
60 * author:
61 * Paul Vixie (ISC), July 1996
63 char *
64 inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
66 switch (af)
68 case PGSQL_AF_INET:
69 return (inet_cidr_ntop_ipv4(src, bits, dst, size));
70 case PGSQL_AF_INET6:
71 return (inet_cidr_ntop_ipv6(src, bits, dst, size));
72 default:
73 errno = EAFNOSUPPORT;
74 return (NULL);
80 * static char *
81 * inet_cidr_ntop_ipv4(src, bits, dst, size)
82 * convert IPv4 network number from network to presentation format.
83 * generates CIDR style result always.
84 * return:
85 * pointer to dst, or NULL if an error occurred (check errno).
86 * note:
87 * network byte order assumed. this means 192.5.5.240/28 has
88 * 0b11110000 in its fourth octet.
89 * author:
90 * Paul Vixie (ISC), July 1996
92 static char *
93 inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
95 char *odst = dst;
96 char *t;
97 u_int m;
98 int b;
100 if (bits < 0 || bits > 32)
102 errno = EINVAL;
103 return (NULL);
106 if (bits == 0)
108 if (size < sizeof "0")
109 goto emsgsize;
110 *dst++ = '0';
111 size--;
112 *dst = '\0';
115 /* Format whole octets. */
116 for (b = bits / 8; b > 0; b--)
118 if (size <= sizeof "255.")
119 goto emsgsize;
120 t = dst;
121 dst += SPRINTF((dst, "%u", *src++));
122 if (b > 1)
124 *dst++ = '.';
125 *dst = '\0';
127 size -= (size_t) (dst - t);
130 /* Format partial octet. */
131 b = bits % 8;
132 if (b > 0)
134 if (size <= sizeof ".255")
135 goto emsgsize;
136 t = dst;
137 if (dst != odst)
138 *dst++ = '.';
139 m = ((1 << b) - 1) << (8 - b);
140 dst += SPRINTF((dst, "%u", *src & m));
141 size -= (size_t) (dst - t);
144 /* Format CIDR /width. */
145 if (size <= sizeof "/32")
146 goto emsgsize;
147 dst += SPRINTF((dst, "/%u", bits));
148 return (odst);
150 emsgsize:
151 errno = EMSGSIZE;
152 return (NULL);
156 * static char *
157 * inet_cidr_ntop_ipv6(src, bits, fakebits, dst, size)
158 * convert IPv6 network number from network to presentation format.
159 * generates CIDR style result always. Picks the shortest representation
160 * unless the IP is really IPv4.
161 * always prints specified number of bits (bits).
162 * return:
163 * pointer to dst, or NULL if an error occurred (check errno).
164 * note:
165 * network byte order assumed. this means 192.5.5.240/28 has
166 * 0x11110000 in its fourth octet.
167 * author:
168 * Vadim Kogan (UCB), June 2001
169 * Original version (IPv4) by Paul Vixie (ISC), July 1996
172 static char *
173 inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
175 u_int m;
176 int b;
177 int p;
178 int zero_s,
179 zero_l,
180 tmp_zero_s,
181 tmp_zero_l;
182 int i;
183 int is_ipv4 = 0;
184 unsigned char inbuf[16];
185 char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
186 char *cp;
187 int words;
188 u_char *s;
190 if (bits < 0 || bits > 128)
192 errno = EINVAL;
193 return (NULL);
196 cp = outbuf;
198 if (bits == 0)
200 *cp++ = ':';
201 *cp++ = ':';
202 *cp = '\0';
204 else
206 /* Copy src to private buffer. Zero host part. */
207 p = (bits + 7) / 8;
208 memcpy(inbuf, src, p);
209 memset(inbuf + p, 0, 16 - p);
210 b = bits % 8;
211 if (b != 0)
213 m = ~0 << (8 - b);
214 inbuf[p - 1] &= m;
217 s = inbuf;
219 /* how many words need to be displayed in output */
220 words = (bits + 15) / 16;
221 if (words == 1)
222 words = 2;
224 /* Find the longest substring of zero's */
225 zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
226 for (i = 0; i < (words * 2); i += 2)
228 if ((s[i] | s[i + 1]) == 0)
230 if (tmp_zero_l == 0)
231 tmp_zero_s = i / 2;
232 tmp_zero_l++;
234 else
236 if (tmp_zero_l && zero_l < tmp_zero_l)
238 zero_s = tmp_zero_s;
239 zero_l = tmp_zero_l;
240 tmp_zero_l = 0;
245 if (tmp_zero_l && zero_l < tmp_zero_l)
247 zero_s = tmp_zero_s;
248 zero_l = tmp_zero_l;
251 if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
252 ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
253 ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
254 is_ipv4 = 1;
256 /* Format whole words. */
257 for (p = 0; p < words; p++)
259 if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
261 /* Time to skip some zeros */
262 if (p == zero_s)
263 *cp++ = ':';
264 if (p == words - 1)
265 *cp++ = ':';
266 s++;
267 s++;
268 continue;
271 if (is_ipv4 && p > 5)
273 *cp++ = (p == 6) ? ':' : '.';
274 cp += SPRINTF((cp, "%u", *s++));
275 /* we can potentially drop the last octet */
276 if (p != 7 || bits > 120)
278 *cp++ = '.';
279 cp += SPRINTF((cp, "%u", *s++));
282 else
284 if (cp != outbuf)
285 *cp++ = ':';
286 cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
287 s += 2;
291 /* Format CIDR /width. */
292 (void) SPRINTF((cp, "/%u", bits));
293 if (strlen(outbuf) + 1 > size)
294 goto emsgsize;
295 strcpy(dst, outbuf);
297 return (dst);
299 emsgsize:
300 errno = EMSGSIZE;
301 return (NULL);
306 * char *
307 * inet_net_ntop(af, src, bits, dst, size)
308 * convert host/network address from network to presentation format.
309 * "src"'s size is determined from its "af".
310 * return:
311 * pointer to dst, or NULL if an error occurred (check errno).
312 * note:
313 * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
314 * as called for by inet_net_pton() but it can be a host address with
315 * an included netmask.
316 * author:
317 * Paul Vixie (ISC), October 1998
319 char *
320 inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
322 switch (af)
324 case PGSQL_AF_INET:
325 return (inet_net_ntop_ipv4(src, bits, dst, size));
326 case PGSQL_AF_INET6:
327 return (inet_net_ntop_ipv6(src, bits, dst, size));
328 default:
329 errno = EAFNOSUPPORT;
330 return (NULL);
335 * static char *
336 * inet_net_ntop_ipv4(src, bits, dst, size)
337 * convert IPv4 network address from network to presentation format.
338 * "src"'s size is determined from its "af".
339 * return:
340 * pointer to dst, or NULL if an error occurred (check errno).
341 * note:
342 * network byte order assumed. this means 192.5.5.240/28 has
343 * 0b11110000 in its fourth octet.
344 * author:
345 * Paul Vixie (ISC), October 1998
347 static char *
348 inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
350 char *odst = dst;
351 char *t;
352 int len = 4;
353 int b;
355 if (bits < 0 || bits > 32)
357 errno = EINVAL;
358 return (NULL);
361 /* Always format all four octets, regardless of mask length. */
362 for (b = len; b > 0; b--)
364 if (size <= sizeof ".255")
365 goto emsgsize;
366 t = dst;
367 if (dst != odst)
368 *dst++ = '.';
369 dst += SPRINTF((dst, "%u", *src++));
370 size -= (size_t) (dst - t);
373 /* don't print masklen if 32 bits */
374 if (bits != 32)
376 if (size <= sizeof "/32")
377 goto emsgsize;
378 dst += SPRINTF((dst, "/%u", bits));
381 return (odst);
383 emsgsize:
384 errno = EMSGSIZE;
385 return (NULL);
388 static int
389 decoct(const u_char *src, int bytes, char *dst, size_t size)
391 char *odst = dst;
392 char *t;
393 int b;
395 for (b = 1; b <= bytes; b++)
397 if (size <= sizeof "255.")
398 return (0);
399 t = dst;
400 dst += SPRINTF((dst, "%u", *src++));
401 if (b != bytes)
403 *dst++ = '.';
404 *dst = '\0';
406 size -= (size_t) (dst - t);
408 return (dst - odst);
411 static char *
412 inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
415 * Note that int32_t and int16_t need only be "at least" large enough to
416 * contain a value of the specified size. On some systems, like Crays,
417 * there is no such thing as an integer variable with 16 bits. Keep this
418 * in mind if you think this function should have been coded to use
419 * pointer overlays. All the world's not a VAX.
421 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
422 char *tp;
423 struct
425 int base,
426 len;
427 } best, cur;
428 u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
429 int i;
431 if ((bits < -1) || (bits > 128))
433 errno = EINVAL;
434 return (NULL);
438 * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
439 * the longest run of 0x00's in src[] for :: shorthanding.
441 memset(words, '\0', sizeof words);
442 for (i = 0; i < NS_IN6ADDRSZ; i++)
443 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
444 best.base = -1;
445 cur.base = -1;
446 best.len = 0;
447 cur.len = 0;
448 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
450 if (words[i] == 0)
452 if (cur.base == -1)
453 cur.base = i, cur.len = 1;
454 else
455 cur.len++;
457 else
459 if (cur.base != -1)
461 if (best.base == -1 || cur.len > best.len)
462 best = cur;
463 cur.base = -1;
467 if (cur.base != -1)
469 if (best.base == -1 || cur.len > best.len)
470 best = cur;
472 if (best.base != -1 && best.len < 2)
473 best.base = -1;
476 * Format the result.
478 tp = tmp;
479 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
481 /* Are we inside the best run of 0x00's? */
482 if (best.base != -1 && i >= best.base &&
483 i < (best.base + best.len))
485 if (i == best.base)
486 *tp++ = ':';
487 continue;
489 /* Are we following an initial run of 0x00s or any real hex? */
490 if (i != 0)
491 *tp++ = ':';
492 /* Is this address an encapsulated IPv4? */
493 if (i == 6 && best.base == 0 && (best.len == 6 ||
494 (best.len == 7 && words[7] != 0x0001) ||
495 (best.len == 5 && words[5] == 0xffff)))
497 int n;
499 n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp));
500 if (n == 0)
502 errno = EMSGSIZE;
503 return (NULL);
505 tp += strlen(tp);
506 break;
508 tp += SPRINTF((tp, "%x", words[i]));
511 /* Was it a trailing run of 0x00's? */
512 if (best.base != -1 && (best.base + best.len) ==
513 (NS_IN6ADDRSZ / NS_INT16SZ))
514 *tp++ = ':';
515 *tp = '\0';
517 if (bits != -1 && bits != 128)
518 tp += SPRINTF((tp, "/%u", bits));
521 * Check for overflow, copy, and we're done.
523 if ((size_t) (tp - tmp) > size)
525 errno = EMSGSIZE;
526 return (NULL);
528 strcpy(dst, tmp);
529 return (dst);