diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 5cc81bbe26..c95fc4fd64 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -170,11 +170,11 @@ PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand If host is specified without hostaddr, a host name lookup occurs. If hostaddr is specified without host, - the value for hostaddr gives the server address. + the value for hostaddr gives the server network address. The connection attempt will fail in any of the cases where a host name is required. If both host and hostaddr are specified, - the value for hostaddr gives the server address. + the value for hostaddr gives the server network address. The value for host is ignored unless needed for authentication or verification purposes, in which case it will be used as the host name. Note that authentication is likely to fail diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index be272b51d9..ce28abd9fe 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -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 \ regexp.o regproc.o ruleutils.o selfuncs.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 \ 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 \ diff --git a/src/backend/utils/adt/inet_net_ntop.c b/src/backend/utils/adt/inet_cidr_ntop.c similarity index 55% rename from src/backend/utils/adt/inet_net_ntop.c rename to src/backend/utils/adt/inet_cidr_ntop.c index 3d7fb65889..5f2a3d361d 100644 --- a/src/backend/utils/adt/inet_net_ntop.c +++ b/src/backend/utils/adt/inet_cidr_ntop.c @@ -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" -#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_cidr_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); static char *inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size); @@ -300,231 +293,3 @@ emsgsize: errno = EMSGSIZE; 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); -} diff --git a/src/include/port.h b/src/include/port.h index 204876888a..0cfbed83d4 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -437,4 +437,8 @@ extern void qsort_arg(void *base, size_t nel, size_t elsize, /* port/chklocale.c */ 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 */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index bad0a8ebdf..a2fb7494cb 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -795,9 +795,7 @@ extern Datum chr (PG_FUNCTION_ARGS); extern Datum repeat(PG_FUNCTION_ARGS); extern Datum ascii(PG_FUNCTION_ARGS); -/* inet_net_ntop.c */ -extern char *inet_net_ntop(int af, const void *src, int bits, - char *dst, size_t size); +/* inet_cidr_ntop.c */ extern char *inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size); diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 8f318a1a8c..8011604e5c 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -960,9 +960,28 @@ connectFailureMessage(PGconn *conn, int errorno) else #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, 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"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), conn->pghostaddr @@ -970,6 +989,10 @@ connectFailureMessage(PGconn *conn, int errorno) : (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); } } diff --git a/src/port/Makefile b/src/port/Makefile index 327ec7246c..711f633089 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -30,7 +30,7 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS) 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 ifneq (,$(filter $(PORTNAME),cygwin win32)) OBJS += pipe.o diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c index f867744eee..807f5bd56d 100644 --- a/src/port/getaddrinfo.c +++ b/src/port/getaddrinfo.c @@ -388,16 +388,14 @@ getnameinfo(const struct sockaddr * sa, int salen, if (node) { - int ret = -1; - if (sa->sa_family == AF_INET) { - char *p; - - p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr); - ret = snprintf(node, nodelen, "%s", p); + if (inet_net_ntop(AF_INET, ((struct sockaddr_in *) sa)->sin_addr, + sa->sa_family == AF_INET ? 32 : 128, + node, nodelen) == NULL) + return EAI_MEMORY; } - if (ret == -1 || ret > nodelen) + else return EAI_MEMORY; } diff --git a/src/port/inet_net_ntop.c b/src/port/inet_net_ntop.c new file mode 100644 index 0000000000..02d3a7cea5 --- /dev/null +++ b/src/port/inet_net_ntop.c @@ -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 +#include +#include +#include + +#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); +} +