mirror of https://github.com/postgres/postgres
supplied, also print the IP address. This allows IPv4 and IPv6 failures to be distinguished. Also useful when a hostname resolves to multiple IP addresses. Also, remove use of inet_ntoa() and use our own inet_net_ntop() in all places, including in libpq, because it is thread-safe.pull/1/head
parent
725d52d0c2
commit
ba11258ccb
@ -0,0 +1,275 @@ |
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
||||
* Copyright (c) 1996,1999 by Internet Software Consortium. |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
* |
||||
* src/backend/utils/adt/inet_net_ntop.c |
||||
*/ |
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint) |
||||
static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $"; |
||||
#endif |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
|
||||
#include "utils/inet.h" |
||||
|
||||
|
||||
#define NS_IN6ADDRSZ 16 |
||||
#define NS_INT16SZ 2 |
||||
|
||||
#ifdef SPRINTF_CHAR |
||||
#define SPRINTF(x) strlen(sprintf/**/x) |
||||
#else |
||||
#define SPRINTF(x) ((size_t)sprintf x) |
||||
#endif |
||||
|
||||
static char *inet_net_ntop_ipv4(const u_char *src, int bits, |
||||
char *dst, size_t size); |
||||
static char *inet_net_ntop_ipv6(const u_char *src, int bits, |
||||
char *dst, size_t size); |
||||
|
||||
|
||||
/*
|
||||
* char * |
||||
* inet_net_ntop(af, src, bits, dst, size) |
||||
* convert host/network address from network to presentation format. |
||||
* "src"'s size is determined from its "af". |
||||
* return: |
||||
* pointer to dst, or NULL if an error occurred (check errno). |
||||
* note: |
||||
* 192.5.5.1/28 has a nonzero host part, which means it isn't a network |
||||
* as called for by inet_net_pton() but it can be a host address with |
||||
* an included netmask. |
||||
* author: |
||||
* Paul Vixie (ISC), October 1998 |
||||
*/ |
||||
char * |
||||
inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) |
||||
{ |
||||
switch (af) |
||||
{ |
||||
case PGSQL_AF_INET: |
||||
return (inet_net_ntop_ipv4(src, bits, dst, size)); |
||||
case PGSQL_AF_INET6: |
||||
return (inet_net_ntop_ipv6(src, bits, dst, size)); |
||||
default: |
||||
errno = EAFNOSUPPORT; |
||||
return (NULL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* static char * |
||||
* inet_net_ntop_ipv4(src, bits, dst, size) |
||||
* convert IPv4 network address from network to presentation format. |
||||
* "src"'s size is determined from its "af". |
||||
* return: |
||||
* pointer to dst, or NULL if an error occurred (check errno). |
||||
* note: |
||||
* network byte order assumed. this means 192.5.5.240/28 has |
||||
* 0b11110000 in its fourth octet. |
||||
* author: |
||||
* Paul Vixie (ISC), October 1998 |
||||
*/ |
||||
static char * |
||||
inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) |
||||
{ |
||||
char *odst = dst; |
||||
char *t; |
||||
int len = 4; |
||||
int b; |
||||
|
||||
if (bits < 0 || bits > 32) |
||||
{ |
||||
errno = EINVAL; |
||||
return (NULL); |
||||
} |
||||
|
||||
/* Always format all four octets, regardless of mask length. */ |
||||
for (b = len; b > 0; b--) |
||||
{ |
||||
if (size <= sizeof ".255") |
||||
goto emsgsize; |
||||
t = dst; |
||||
if (dst != odst) |
||||
*dst++ = '.'; |
||||
dst += SPRINTF((dst, "%u", *src++)); |
||||
size -= (size_t) (dst - t); |
||||
} |
||||
|
||||
/* don't print masklen if 32 bits */ |
||||
if (bits != 32) |
||||
{ |
||||
if (size <= sizeof "/32") |
||||
goto emsgsize; |
||||
dst += SPRINTF((dst, "/%u", bits)); |
||||
} |
||||
|
||||
return (odst); |
||||
|
||||
emsgsize: |
||||
errno = EMSGSIZE; |
||||
return (NULL); |
||||
} |
||||
|
||||
static int |
||||
decoct(const u_char *src, int bytes, char *dst, size_t size) |
||||
{ |
||||
char *odst = dst; |
||||
char *t; |
||||
int b; |
||||
|
||||
for (b = 1; b <= bytes; b++) |
||||
{ |
||||
if (size <= sizeof "255.") |
||||
return (0); |
||||
t = dst; |
||||
dst += SPRINTF((dst, "%u", *src++)); |
||||
if (b != bytes) |
||||
{ |
||||
*dst++ = '.'; |
||||
*dst = '\0'; |
||||
} |
||||
size -= (size_t) (dst - t); |
||||
} |
||||
return (dst - odst); |
||||
} |
||||
|
||||
static char * |
||||
inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) |
||||
{ |
||||
/*
|
||||
* Note that int32_t and int16_t need only be "at least" large enough to |
||||
* contain a value of the specified size. On some systems, like Crays, |
||||
* there is no such thing as an integer variable with 16 bits. Keep this |
||||
* in mind if you think this function should have been coded to use |
||||
* pointer overlays. All the world's not a VAX. |
||||
*/ |
||||
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; |
||||
char *tp; |
||||
struct |
||||
{ |
||||
int base, |
||||
len; |
||||
} best, cur; |
||||
u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; |
||||
int i; |
||||
|
||||
if ((bits < -1) || (bits > 128)) |
||||
{ |
||||
errno = EINVAL; |
||||
return (NULL); |
||||
} |
||||
|
||||
/*
|
||||
* Preprocess: Copy the input (bytewise) array into a wordwise array. Find |
||||
* the longest run of 0x00's in src[] for :: shorthanding. |
||||
*/ |
||||
memset(words, '\0', sizeof words); |
||||
for (i = 0; i < NS_IN6ADDRSZ; i++) |
||||
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); |
||||
best.base = -1; |
||||
cur.base = -1; |
||||
best.len = 0; |
||||
cur.len = 0; |
||||
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) |
||||
{ |
||||
if (words[i] == 0) |
||||
{ |
||||
if (cur.base == -1) |
||||
cur.base = i, cur.len = 1; |
||||
else |
||||
cur.len++; |
||||
} |
||||
else |
||||
{ |
||||
if (cur.base != -1) |
||||
{ |
||||
if (best.base == -1 || cur.len > best.len) |
||||
best = cur; |
||||
cur.base = -1; |
||||
} |
||||
} |
||||
} |
||||
if (cur.base != -1) |
||||
{ |
||||
if (best.base == -1 || cur.len > best.len) |
||||
best = cur; |
||||
} |
||||
if (best.base != -1 && best.len < 2) |
||||
best.base = -1; |
||||
|
||||
/*
|
||||
* Format the result. |
||||
*/ |
||||
tp = tmp; |
||||
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) |
||||
{ |
||||
/* Are we inside the best run of 0x00's? */ |
||||
if (best.base != -1 && i >= best.base && |
||||
i < (best.base + best.len)) |
||||
{ |
||||
if (i == best.base) |
||||
*tp++ = ':'; |
||||
continue; |
||||
} |
||||
/* Are we following an initial run of 0x00s or any real hex? */ |
||||
if (i != 0) |
||||
*tp++ = ':'; |
||||
/* Is this address an encapsulated IPv4? */ |
||||
if (i == 6 && best.base == 0 && (best.len == 6 || |
||||
(best.len == 7 && words[7] != 0x0001) || |
||||
(best.len == 5 && words[5] == 0xffff))) |
||||
{ |
||||
int n; |
||||
|
||||
n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp)); |
||||
if (n == 0) |
||||
{ |
||||
errno = EMSGSIZE; |
||||
return (NULL); |
||||
} |
||||
tp += strlen(tp); |
||||
break; |
||||
} |
||||
tp += SPRINTF((tp, "%x", words[i])); |
||||
} |
||||
|
||||
/* Was it a trailing run of 0x00's? */ |
||||
if (best.base != -1 && (best.base + best.len) == |
||||
(NS_IN6ADDRSZ / NS_INT16SZ)) |
||||
*tp++ = ':'; |
||||
*tp = '\0'; |
||||
|
||||
if (bits != -1 && bits != 128) |
||||
tp += SPRINTF((tp, "/%u", bits)); |
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done. |
||||
*/ |
||||
if ((size_t) (tp - tmp) > size) |
||||
{ |
||||
errno = EMSGSIZE; |
||||
return (NULL); |
||||
} |
||||
strcpy(dst, tmp); |
||||
return (dst); |
||||
} |
||||
|
||||
Loading…
Reference in new issue