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 * src/port/inet_net_ntop.c
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 $";
27 #include "postgres_fe.h"
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
35 #include "utils/inet.h"
38 * In a frontend build, we can't include inet.h, but we still need to have
39 * sensible definitions of these two constants. Note that pg_inet_net_ntop()
40 * assumes that PGSQL_AF_INET is equal to AF_INET.
42 #define PGSQL_AF_INET (AF_INET + 0)
43 #define PGSQL_AF_INET6 (AF_INET + 1)
47 #define NS_IN6ADDRSZ 16
51 #define SPRINTF(x) strlen(sprintf/**/x)
53 #define SPRINTF(x) ((size_t)sprintf x)
56 static char *inet_net_ntop_ipv4(const u_char
*src
, int bits
,
57 char *dst
, size_t size
);
58 static char *inet_net_ntop_ipv6(const u_char
*src
, int bits
,
59 char *dst
, size_t size
);
64 * pg_inet_net_ntop(af, src, bits, dst, size)
65 * convert host/network address from network to presentation format.
66 * "src"'s size is determined from its "af".
68 * pointer to dst, or NULL if an error occurred (check errno).
70 * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
71 * as called for by pg_inet_net_pton() but it can be a host address with
72 * an included netmask.
74 * Paul Vixie (ISC), October 1998
77 pg_inet_net_ntop(int af
, const void *src
, int bits
, char *dst
, size_t size
)
80 * We need to cover both the address family constants used by the PG inet
81 * type (PGSQL_AF_INET and PGSQL_AF_INET6) and those used by the system
82 * libraries (AF_INET and AF_INET6). We can safely assume PGSQL_AF_INET
83 * == AF_INET, but the INET6 constants are very likely to be different. If
84 * AF_INET6 isn't defined, silently ignore it.
89 return (inet_net_ntop_ipv4(src
, bits
, dst
, size
));
91 #if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
94 return (inet_net_ntop_ipv6(src
, bits
, dst
, size
));
103 * inet_net_ntop_ipv4(src, bits, dst, size)
104 * convert IPv4 network address from network to presentation format.
105 * "src"'s size is determined from its "af".
107 * pointer to dst, or NULL if an error occurred (check errno).
109 * network byte order assumed. this means 192.5.5.240/28 has
110 * 0b11110000 in its fourth octet.
112 * Paul Vixie (ISC), October 1998
115 inet_net_ntop_ipv4(const u_char
*src
, int bits
, char *dst
, size_t size
)
122 if (bits
< 0 || bits
> 32)
128 /* Always format all four octets, regardless of mask length. */
129 for (b
= len
; b
> 0; b
--)
131 if (size
<= sizeof ".255")
136 dst
+= SPRINTF((dst
, "%u", *src
++));
137 size
-= (size_t) (dst
- t
);
140 /* don't print masklen if 32 bits */
143 if (size
<= sizeof "/32")
145 dst
+= SPRINTF((dst
, "/%u", bits
));
156 decoct(const u_char
*src
, int bytes
, char *dst
, size_t size
)
162 for (b
= 1; b
<= bytes
; b
++)
164 if (size
<= sizeof "255.")
167 dst
+= SPRINTF((dst
, "%u", *src
++));
173 size
-= (size_t) (dst
- t
);
179 inet_net_ntop_ipv6(const u_char
*src
, int bits
, char *dst
, size_t size
)
182 * Note that int32_t and int16_t need only be "at least" large enough to
183 * contain a value of the specified size. On some systems, like Crays,
184 * there is no such thing as an integer variable with 16 bits. Keep this
185 * in mind if you think this function should have been coded to use
186 * pointer overlays. All the world's not a VAX.
188 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
195 u_int words
[NS_IN6ADDRSZ
/ NS_INT16SZ
];
198 if ((bits
< -1) || (bits
> 128))
205 * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
206 * the longest run of 0x00's in src[] for :: shorthanding.
208 memset(words
, '\0', sizeof words
);
209 for (i
= 0; i
< NS_IN6ADDRSZ
; i
++)
210 words
[i
/ 2] |= (src
[i
] << ((1 - (i
% 2)) << 3));
215 for (i
= 0; i
< (NS_IN6ADDRSZ
/ NS_INT16SZ
); i
++)
220 cur
.base
= i
, cur
.len
= 1;
228 if (best
.base
== -1 || cur
.len
> best
.len
)
236 if (best
.base
== -1 || cur
.len
> best
.len
)
239 if (best
.base
!= -1 && best
.len
< 2)
246 for (i
= 0; i
< (NS_IN6ADDRSZ
/ NS_INT16SZ
); i
++)
248 /* Are we inside the best run of 0x00's? */
249 if (best
.base
!= -1 && i
>= best
.base
&&
250 i
< (best
.base
+ best
.len
))
256 /* Are we following an initial run of 0x00s or any real hex? */
259 /* Is this address an encapsulated IPv4? */
260 if (i
== 6 && best
.base
== 0 && (best
.len
== 6 ||
261 (best
.len
== 7 && words
[7] != 0x0001) ||
262 (best
.len
== 5 && words
[5] == 0xffff)))
266 n
= decoct(src
+ 12, 4, tp
, sizeof tmp
- (tp
- tmp
));
275 tp
+= SPRINTF((tp
, "%x", words
[i
]));
278 /* Was it a trailing run of 0x00's? */
279 if (best
.base
!= -1 && (best
.base
+ best
.len
) ==
280 (NS_IN6ADDRSZ
/ NS_INT16SZ
))
284 if (bits
!= -1 && bits
!= 128)
285 tp
+= SPRINTF((tp
, "/%u", bits
));
288 * Check for overflow, copy, and we're done.
290 if ((size_t) (tp
- tmp
) > size
)