When reporting the server as not responding, if the hostname was

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.
This commit is contained in:
Bruce Momjian 2010-11-24 17:04:19 -05:00
parent 725d52d0c2
commit ba11258ccb
9 changed files with 313 additions and 250 deletions

View File

@ -170,11 +170,11 @@ PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand
If <literal>host</> is specified without <literal>hostaddr</>, If <literal>host</> is specified without <literal>hostaddr</>,
a host name lookup occurs. a host name lookup occurs.
If <literal>hostaddr</> is specified without <literal>host</>, If <literal>hostaddr</> is specified without <literal>host</>,
the value for <literal>hostaddr</> gives the server address. the value for <literal>hostaddr</> gives the server network address.
The connection attempt will fail in any of the cases where a The connection attempt will fail in any of the cases where a
host name is required. host name is required.
If both <literal>host</> and <literal>hostaddr</> are specified, If both <literal>host</> and <literal>hostaddr</> are specified,
the value for <literal>hostaddr</> gives the server address. the value for <literal>hostaddr</> gives the server network address.
The value for <literal>host</> is ignored unless needed for The value for <literal>host</> is ignored unless needed for
authentication or verification purposes, in which case it will be authentication or verification purposes, in which case it will be
used as the host name. Note that authentication is likely to fail used as the host name. Note that authentication is likely to fail

View File

@ -23,7 +23,7 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
oid.o oracle_compat.o pseudotypes.o rowtypes.o \ oid.o oracle_compat.o pseudotypes.o rowtypes.o \
regexp.o regproc.o ruleutils.o selfuncs.o \ regexp.o regproc.o ruleutils.o selfuncs.o \
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \ tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_net_ntop.o inet_net_pton.o \ network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \ ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o trigfuncs.o \ ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o trigfuncs.o \
tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \ tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \

View File

@ -32,21 +32,14 @@ static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 m
#include "utils/inet.h" #include "utils/inet.h"
#define NS_IN6ADDRSZ 16
#define NS_INT16SZ 2
#ifdef SPRINTF_CHAR #ifdef SPRINTF_CHAR
#define SPRINTF(x) strlen(sprintf/**/x) #define SPRINTF(x) strlen(sprintf/**/x)
#else #else
#define SPRINTF(x) ((size_t)sprintf x) #define SPRINTF(x) ((size_t)sprintf x)
#endif #endif
static char *inet_net_ntop_ipv4(const u_char *src, int bits,
char *dst, size_t size);
static char *inet_cidr_ntop_ipv4(const u_char *src, int bits, static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
char *dst, size_t size); char *dst, size_t size);
static char *inet_net_ntop_ipv6(const u_char *src, int bits,
char *dst, size_t size);
static char *inet_cidr_ntop_ipv6(const u_char *src, int bits, static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
char *dst, size_t size); char *dst, size_t size);
@ -300,231 +293,3 @@ emsgsize:
errno = EMSGSIZE; errno = EMSGSIZE;
return (NULL); return (NULL);
} }
/*
* 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);
}

View File

@ -437,4 +437,8 @@ extern void qsort_arg(void *base, size_t nel, size_t elsize,
/* port/chklocale.c */ /* port/chklocale.c */
extern int pg_get_encoding_from_locale(const char *ctype); extern int pg_get_encoding_from_locale(const char *ctype);
/* port/inet_net_ntop.c */
extern char *inet_net_ntop(int af, const void *src, int bits,
char *dst, size_t size);
#endif /* PG_PORT_H */ #endif /* PG_PORT_H */

View File

@ -795,9 +795,7 @@ extern Datum chr (PG_FUNCTION_ARGS);
extern Datum repeat(PG_FUNCTION_ARGS); extern Datum repeat(PG_FUNCTION_ARGS);
extern Datum ascii(PG_FUNCTION_ARGS); extern Datum ascii(PG_FUNCTION_ARGS);
/* inet_net_ntop.c */ /* inet_cidr_ntop.c */
extern char *inet_net_ntop(int af, const void *src, int bits,
char *dst, size_t size);
extern char *inet_cidr_ntop(int af, const void *src, int bits, extern char *inet_cidr_ntop(int af, const void *src, int bits,
char *dst, size_t size); char *dst, size_t size);

View File

@ -960,9 +960,28 @@ connectFailureMessage(PGconn *conn, int errorno)
else else
#endif /* HAVE_UNIX_SOCKETS */ #endif /* HAVE_UNIX_SOCKETS */
{ {
char host_addr[NI_MAXHOST];
bool display_host_addr;
struct sockaddr_in *host_addr_struct = (struct sockaddr_in *)
&conn->raddr.addr;
/*
* Optionally display the network address with the hostname.
* This is useful to distinguish between IPv4 and IPv6 connections.
*/
if (conn->pghostaddr != NULL)
strlcpy(host_addr, conn->pghostaddr, NI_MAXHOST);
else if (inet_net_ntop(conn->addr_cur->ai_family, &host_addr_struct->sin_addr,
host_addr_struct->sin_family == AF_INET ? 32 : 128,
host_addr, sizeof(host_addr)) == NULL)
strcpy(host_addr, "???");
display_host_addr = !conn->pghostaddr &&
strcmp(conn->pghost, host_addr) != 0;
appendPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not connect to server: %s\n" libpq_gettext("could not connect to server: %s\n"
"\tIs the server running on host \"%s\" and accepting\n" "\tIs the server running on host \"%s\" %s%s%sand accepting\n"
"\tTCP/IP connections on port %s?\n"), "\tTCP/IP connections on port %s?\n"),
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
conn->pghostaddr conn->pghostaddr
@ -970,6 +989,10 @@ connectFailureMessage(PGconn *conn, int errorno)
: (conn->pghost : (conn->pghost
? conn->pghost ? conn->pghost
: "???"), : "???"),
/* display the IP address only if not already output */
display_host_addr ? "(" : "",
display_host_addr ? host_addr : "",
display_host_addr ? ") " : "",
conn->pgport); conn->pgport);
} }
} }

View File

@ -30,7 +30,7 @@ include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS) override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS) LIBS += $(PTHREAD_LIBS)
OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o noblock.o path.o \ OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o path.o \
pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
ifneq (,$(filter $(PORTNAME),cygwin win32)) ifneq (,$(filter $(PORTNAME),cygwin win32))
OBJS += pipe.o OBJS += pipe.o

View File

@ -388,16 +388,14 @@ getnameinfo(const struct sockaddr * sa, int salen,
if (node) if (node)
{ {
int ret = -1;
if (sa->sa_family == AF_INET) if (sa->sa_family == AF_INET)
{ {
char *p; if (inet_net_ntop(AF_INET, ((struct sockaddr_in *) sa)->sin_addr,
sa->sa_family == AF_INET ? 32 : 128,
p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr); node, nodelen) == NULL)
ret = snprintf(node, nodelen, "%s", p); return EAI_MEMORY;
} }
if (ret == -1 || ret > nodelen) else
return EAI_MEMORY; return EAI_MEMORY;
} }

275
src/port/inet_net_ntop.c Normal file
View File

@ -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);
}