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.
88 return (inet_net_ntop_ipv4(src
, bits
, dst
, size
));
90 #if AF_INET6 != PGSQL_AF_INET6
93 return (inet_net_ntop_ipv6(src
, bits
, dst
, size
));
102 * inet_net_ntop_ipv4(src, bits, dst, size)
103 * convert IPv4 network address from network to presentation format.
104 * "src"'s size is determined from its "af".
106 * pointer to dst, or NULL if an error occurred (check errno).
108 * network byte order assumed. this means 192.5.5.240/28 has
109 * 0b11110000 in its fourth octet.
111 * Paul Vixie (ISC), October 1998
114 inet_net_ntop_ipv4(const u_char
*src
, int bits
, char *dst
, size_t size
)
121 if (bits
< 0 || bits
> 32)
127 /* Always format all four octets, regardless of mask length. */
128 for (b
= len
; b
> 0; b
--)
130 if (size
<= sizeof ".255")
135 dst
+= SPRINTF((dst
, "%u", *src
++));
136 size
-= (size_t) (dst
- t
);
139 /* don't print masklen if 32 bits */
142 if (size
<= sizeof "/32")
144 dst
+= SPRINTF((dst
, "/%u", bits
));
155 decoct(const u_char
*src
, int bytes
, char *dst
, size_t size
)
161 for (b
= 1; b
<= bytes
; b
++)
163 if (size
<= sizeof "255.")
166 dst
+= SPRINTF((dst
, "%u", *src
++));
172 size
-= (size_t) (dst
- t
);
178 inet_net_ntop_ipv6(const u_char
*src
, int bits
, char *dst
, size_t size
)
181 * Note that int32_t and int16_t need only be "at least" large enough to
182 * contain a value of the specified size. On some systems, like Crays,
183 * there is no such thing as an integer variable with 16 bits. Keep this
184 * in mind if you think this function should have been coded to use
185 * pointer overlays. All the world's not a VAX.
187 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
194 u_int words
[NS_IN6ADDRSZ
/ NS_INT16SZ
];
197 if ((bits
< -1) || (bits
> 128))
204 * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
205 * the longest run of 0x00's in src[] for :: shorthanding.
207 memset(words
, '\0', sizeof words
);
208 for (i
= 0; i
< NS_IN6ADDRSZ
; i
++)
209 words
[i
/ 2] |= (src
[i
] << ((1 - (i
% 2)) << 3));
214 for (i
= 0; i
< (NS_IN6ADDRSZ
/ NS_INT16SZ
); i
++)
219 cur
.base
= i
, cur
.len
= 1;
227 if (best
.base
== -1 || cur
.len
> best
.len
)
235 if (best
.base
== -1 || cur
.len
> best
.len
)
238 if (best
.base
!= -1 && best
.len
< 2)
245 for (i
= 0; i
< (NS_IN6ADDRSZ
/ NS_INT16SZ
); i
++)
247 /* Are we inside the best run of 0x00's? */
248 if (best
.base
!= -1 && i
>= best
.base
&&
249 i
< (best
.base
+ best
.len
))
255 /* Are we following an initial run of 0x00s or any real hex? */
258 /* Is this address an encapsulated IPv4? */
259 if (i
== 6 && best
.base
== 0 && (best
.len
== 6 ||
260 (best
.len
== 7 && words
[7] != 0x0001) ||
261 (best
.len
== 5 && words
[5] == 0xffff)))
265 n
= decoct(src
+ 12, 4, tp
, sizeof tmp
- (tp
- tmp
));
274 tp
+= SPRINTF((tp
, "%x", words
[i
]));
277 /* Was it a trailing run of 0x00's? */
278 if (best
.base
!= -1 && (best
.base
+ best
.len
) ==
279 (NS_IN6ADDRSZ
/ NS_INT16SZ
))
283 if (bits
!= -1 && bits
!= 128)
284 tp
+= SPRINTF((tp
, "/%u", bits
));
287 * Check for overflow, copy, and we're done.
289 if ((size_t) (tp
- tmp
) > size
)