diff --git a/configure b/configure
index 304ed53728653b2eeb6f5996bd25c529beedcf55..425db13d0599614d65781bdcdf55b118bde54632 100755
--- a/configure
+++ b/configure
@@ -7169,6 +7169,80 @@ fi
 done
 
 
+# This exports HAVE_IPV6 to both C files and Makefiles
+echo "$as_me:$LINENO: checking for getaddrinfo" >&5
+echo $ECHO_N "checking for getaddrinfo... $ECHO_C" >&6
+if test "${ac_cv_func_getaddrinfo+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getaddrinfo (); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char getaddrinfo ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getaddrinfo) || defined (__stub___getaddrinfo)
+choke me
+#else
+f = getaddrinfo;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_getaddrinfo=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func_getaddrinfo=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_getaddrinfo" >&5
+echo "${ECHO_T}$ac_cv_func_getaddrinfo" >&6
+if test $ac_cv_func_getaddrinfo = yes; then
+  HAVE_IPV6="yes"; cat >>confdefs.h <<\_ACEOF
+#define HAVE_IPV6 1
+_ACEOF
+
+fi
+
+
+
 if test "$with_readline" = yes; then
 
 for ac_header in readline/readline.h
@@ -16427,6 +16501,7 @@ s,@python_moduledir@,$python_moduledir,;t t
 s,@python_moduleexecdir@,$python_moduleexecdir,;t t
 s,@python_includespec@,$python_includespec,;t t
 s,@python_libspec@,$python_libspec,;t t
+s,@HAVE_IPV6@,$HAVE_IPV6,;t t
 s,@LIBOBJS@,$LIBOBJS,;t t
 s,@HPUXMATHLIB@,$HPUXMATHLIB,;t t
 s,@HAVE_POSIX_SIGNALS@,$HAVE_POSIX_SIGNALS,;t t
diff --git a/configure.in b/configure.in
index f5f0bb747d3fe32765337f2c6d5cf208a71b4826..64cb6844d56def3a66945d48d51d3b44c83aa500 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-dnl $Header: /cvsroot/pgsql/configure.in,v 1.224 2002/12/30 17:19:49 tgl Exp $
+dnl $Header: /cvsroot/pgsql/configure.in,v 1.225 2003/01/06 03:18:25 momjian Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -687,6 +687,11 @@ AC_CHECK_HEADERS(netinet/tcp.h, [], [],
 #endif
 ])
 
+# This exports HAVE_IPV6 to both C files and Makefiles
+AC_CHECK_FUNC(getaddrinfo,
+             [HAVE_IPV6="yes"; AC_DEFINE(HAVE_IPV6, 1, [])], [])
+AC_SUBST(HAVE_IPV6)
+
 if test "$with_readline" = yes; then
   AC_CHECK_HEADERS(readline/readline.h, [],
                    [AC_CHECK_HEADERS(readline.h, [],
@@ -908,7 +913,7 @@ AC_CHECK_FUNCS([strtoull strtouq], [break])
 # Check for one of atexit() or on_exit()
 AC_CHECK_FUNCS(atexit, [],
                [AC_CHECK_FUNCS(on_exit, [],
-                               [AC_MSG_ERROR([neither atexit() nor on_exit() found])])])
+               [AC_MSG_ERROR([neither atexit() nor on_exit() found])])])
 
 AC_FUNC_FSEEKO
 
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index c4d4af125139d6385849978920aae3ce74726aeb..8e28e3e17a31dbc1b550cba39139eddf6153c7e5 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.42 2002/12/03 21:50:44 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.43 2003/01/06 03:18:26 momjian Exp $
 -->
 
 <chapter id="client-authentication">
@@ -190,7 +190,11 @@ hostssl  <replaceable>database</replaceable>  <replaceable>user</replaceable>  <
        </blockquote>
        must be zero for the record to match.  (Of course IP addresses
        can be spoofed but this consideration is beyond the scope of
-       <productname>PostgreSQL</productname>.)
+       <productname>PostgreSQL</productname>.) If you machine supports
+       IPv6, the default <filename>pg_hba.conf</> will have an IPv6
+       entry for <literal>localhost</>. You can add your own IPv6
+       entries to the file. IPv6 entries are used only for IPv6
+       connections.
       </para>
 
       <para>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 0a9b3ff75eb5711d203b539abdda13fc7bfd567c..c0d2d202c250e10f8066876fea3c3e8c1c8dcf23 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -1,5 +1,5 @@
 # -*-makefile-*-
-# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.158 2003/01/05 13:45:47 petere Exp $
+# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.159 2003/01/06 03:18:26 momjian Exp $
 
 #------------------------------------------------------------------------------
 # All PostgreSQL makefiles include this file and use the variables it sets,
@@ -277,6 +277,7 @@ ifeq ($(enable_rpath), yes)
 LDFLAGS += $(rpath)
 endif
 
+HAVE_IPV6 = @HAVE_IPV6@
 
 ##########################################################################
 #
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 2365b21efdfa6ba6c862237477cdafa7da632bb3..9df4b921d10d2c11ba5f832b2fa8b71c04d7e556 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -4,7 +4,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.89 2002/12/14 00:24:23 petere Exp $
+# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.90 2003/01/06 03:18:26 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -132,7 +132,14 @@ ifeq ($(MAKE_DLL), true)
 endif
 endif
 	$(MAKE) -C catalog install-data
+ifdef HAVE_IPV6
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample $(DESTDIR)$(datadir)/pg_hba.conf.sample
+else
+	grep -v '^host.*::1.*ffff:ffff:ffff:ffff:ffff:ffff' \
+		$(srcdir)/libpq/pg_hba.conf.sample \
+		> $(srcdir)/libpq/pg_hba.conf.sample.no_ipv6
+	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample.no_ipv6 $(DESTDIR)$(datadir)/pg_hba.conf.sample
+endif
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample $(DESTDIR)$(datadir)/pg_ident.conf.sample
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample $(DESTDIR)$(datadir)/postgresql.conf.sample
 
@@ -182,6 +189,9 @@ clean:
 	rm -f postgres$(X) $(POSTGRES_IMP) \
 		$(top_srcdir)/src/include/parser/parse.h \
 		$(top_builddir)/src/include/utils/fmgroids.h
+ifndef HAVE_IPV6
+	rm -f $(srcdir)/libpq/pg_hba.conf.sample.no_ipv6
+endif
 ifeq ($(PORTNAME), win)
 	rm -f postgres.dll postgres.def libpostgres.a
 endif
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 31eecf739b9a01a9ec28824f0bcee59fd8d95378..a4aff2c332a3fee37d40b457930601c5e934df88 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for libpq subsystem (backend half of libpq interface)
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.35 2002/12/06 04:37:02 momjian Exp $
+#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.36 2003/01/06 03:18:26 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,8 +14,8 @@ include $(top_builddir)/src/Makefile.global
 
 # be-fsstubs is here for historical reasons, probably belongs elsewhere
 
-OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o md5.o pqcomm.o \
-	pqformat.o pqsignal.o
+OBJS = be-fsstubs.o be-secure.o auth.o crypt.o hba.o ip.o md5.o pqcomm.o \
+       pqformat.o pqsignal.o
 
 
 all: SUBSYS.o
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index a582ce723ec815758daf112b8a3fa960fdf9f835..247b80ba25e3ef7ed9987e9136b05e7ecc2102bb 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.94 2002/12/06 04:37:02 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.95 2003/01/06 03:18:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -410,12 +410,18 @@ ClientAuthentication(Port *port)
 			 */
 			{
 				const char *hostinfo = "localhost";
+#ifdef HAVE_IPV6
+				char	ip_hostinfo[INET6_ADDRSTRLEN];
+#else
+				char	ip_hostinfo[INET_ADDRSTRLEN];
+#endif
+				if (isAF_INETx(port->raddr.sa.sa_family) )
+					hostinfo = SockAddr_ntop(&port->raddr, ip_hostinfo,
+							   sizeof(ip_hostinfo), 1);
 
-				if (port->raddr.sa.sa_family == AF_INET)
-					hostinfo = inet_ntoa(port->raddr.in.sin_addr);
 				elog(FATAL,
-				"No pg_hba.conf entry for host %s, user %s, database %s",
-					 hostinfo, port->user, port->database);
+					"No pg_hba.conf entry for host %s, user %s, database %s",
+					hostinfo, port->user, port->database);
 				break;
 			}
 
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 185093fb63363422e32d2736cffdf639bb945a14..b9f177c7206bbe8ba8fd08cbb1ab66cd18c6bcdb 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.92 2002/12/14 18:49:37 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.93 2003/01/06 03:18:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -586,8 +586,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 	}
 	else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
 	{
-		struct in_addr file_ip_addr,
-					mask;
+		SockAddr file_ip_addr, mask;
 
 		if (strcmp(token, "hostssl") == 0)
 		{
@@ -623,7 +622,8 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 		if (!line)
 			goto hba_syntax;
 		token = lfirst(line);
-		if (!inet_aton(token, &file_ip_addr))
+
+		if(SockAddr_pton(&file_ip_addr, token) < 0)
 			goto hba_syntax;
 
 		/* Read the mask field. */
@@ -631,7 +631,11 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 		if (!line)
 			goto hba_syntax;
 		token = lfirst(line);
-		if (!inet_aton(token, &mask))
+
+		if(SockAddr_pton(&mask, token) < 0)
+			goto hba_syntax;
+
+		if(file_ip_addr.sa.sa_family != mask.sa.sa_family)
 			goto hba_syntax;
 
 		/* Read the rest of the line. */
@@ -643,8 +647,8 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
 			goto hba_syntax;
 
 		/* Must meet network restrictions */
-		if (port->raddr.sa.sa_family != AF_INET ||
-			((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0)
+		if (!isAF_INETx(port->raddr.sa.sa_family) ||
+			!rangeSockAddr(&port->raddr, &file_ip_addr, &mask))
 			return;
 	}
 	else
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
new file mode 100644
index 0000000000000000000000000000000000000000..21f5c2fe1d5139926a94305c406a6c86bdd046f7
--- /dev/null
+++ b/src/backend/libpq/ip.c
@@ -0,0 +1,371 @@
+/*-------------------------------------------------------------------------
+ *
+ * ip.c
+ *	  Handles IPv6
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.1 2003/01/06 03:18:26 momjian Exp $
+ *
+ * This file and the IPV6 implementation were initially provided by
+ * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
+ * http://www.lbsd.net.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#include "libpq/libpq.h"
+#include "miscadmin.h"
+
+#ifdef FRONTEND
+#define elog fprintf
+#define LOG  stderr
+#endif
+
+#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
+static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
+		struct addrinfo **result);
+#endif   /* HAVE_UNIX_SOCKETS */
+
+/*
+ *	getaddrinfo2 - get address info for Unix, IPv4 and IPv6 sockets
+ */
+int
+getaddrinfo2(const char *hostname, const char *servname,
+#ifdef HAVE_IPV6
+			 const struct addrinfo *hintp, struct addrinfo **result)
+#else
+			 int family, SockAddr *result)
+#endif
+{
+#ifdef HAVE_UNIX_SOCKETS
+#ifdef HAVE_IPV6
+	if (hintp != NULL && hintp->ai_family == AF_UNIX)
+		return getaddrinfo_unix(servname, hintp, result);
+#else
+	if (family == AF_UNIX)
+		return 0;
+#endif
+	else
+	{
+#endif   /* HAVE_UNIX_SOCKETS */
+#ifdef HAVE_IPV6
+		/* NULL has special meaning to getaddrinfo */
+		return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
+						   servname, hintp, result);
+#else
+		if (hostname[0] == '\0')
+			result->in.sin_addr.s_addr = htonl(INADDR_ANY);
+		else
+		{
+			struct hostent *hp;
+
+			hp = gethostbyname(hostname);
+			if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+			{
+				elog(LOG, "getaddrinfo2: gethostbyname(%s) failed\n", hostname);
+				return STATUS_ERROR;
+			}
+			memmove((char *) &(result->in.sin_addr), (char *) hp->h_addr,
+					hp->h_length);
+		}
+
+		result->in.sin_port = htons((unsigned short)atoi(servname));
+		return 0;
+#endif	/* HAVE_IPV6 */
+
+#ifdef HAVE_UNIX_SOCKETS
+	}
+#endif   /* HAVE_UNIX_SOCKETS */
+}
+
+
+/*
+ *	freeaddrinfo2 - free IPv6 addrinfo structures
+ */
+#ifdef HAVE_IPV6
+void
+freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
+{
+#ifdef HAVE_UNIX_SOCKETS
+	if (hint_ai_family == AF_UNIX)
+	{
+		struct addrinfo *p;
+
+		while (ai != NULL)
+		{
+			p = ai;
+			ai = ai->ai_next;
+			free(p->ai_addr);
+			free(p);
+		}
+	}
+	else
+#endif   /* HAVE_UNIX_SOCKETS */
+		freeaddrinfo(ai);
+}
+#endif
+
+
+#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
+/* -------
+ *	getaddrinfo_unix - get unix socket info using IPv6
+ *
+ *	Bug:  only one addrinfo is set even though hintsp is NULL or
+ *		  ai_socktype is 0
+ *		  AI_CANNONNAME does not support.
+ * -------
+ */
+static int
+getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
+		struct addrinfo **result)
+{
+	struct addrinfo hints;
+	struct addrinfo *aip;
+	struct sockaddr_un *unp;
+
+	MemSet(&hints, 0, sizeof(hints));
+
+	if (hintsp == NULL)
+	{
+		hints.ai_family = AF_UNIX;
+		hints.ai_socktype = SOCK_STREAM;
+	}
+	else
+		memcpy(&hints, hintsp, sizeof(hints));
+
+	if (hints.ai_socktype == 0)
+		hints.ai_socktype = SOCK_STREAM;
+
+	if (!(hints.ai_family == AF_UNIX))
+	{
+		elog(LOG, "hints.ai_family is invalied getaddrinfo_unix()\n");
+		return EAI_ADDRFAMILY;
+	}
+
+	aip = calloc(1, sizeof(struct addrinfo));
+	if (aip == NULL)
+		return EAI_MEMORY;
+
+	aip->ai_family = AF_UNIX;
+	aip->ai_socktype = hints.ai_socktype;
+	aip->ai_protocol = hints.ai_protocol;
+	aip->ai_next = NULL;
+	aip->ai_canonname = NULL;
+	*result = aip;
+
+	unp = calloc(1, sizeof(struct sockaddr_un));
+	if (aip == NULL)
+		return EAI_MEMORY;
+
+	unp->sun_family = AF_UNIX;
+	aip->ai_addr = (struct sockaddr *) unp;
+	aip->ai_addrlen = sizeof(struct sockaddr_un);
+
+	if (strlen(path) >= sizeof(unp->sun_path))
+		return EAI_SERVICE;
+	strcpy(unp->sun_path, path);
+
+#if SALEN
+	unp->sun_len = sizeof(struct sockaddr_un);
+#endif   /* SALEN */
+
+	if (hints.ai_flags & AI_PASSIVE)
+		unlink(unp->sun_path);
+
+	return 0;
+}
+#endif   /* HAVE_UNIX_SOCKETS && HAVE_IPV6 */
+
+/* ----------
+ * SockAddr_ntop - set IP address string from SockAddr
+ *
+ * parameters...  sa	: SockAddr union
+ *				  dst	: buffer for address string
+ *				  cnt	: sizeof dst
+ *				  v4conv: non-zero: if address is IPv4 mapped IPv6 address then
+ *						  convert to IPv4 address.
+ * returns... pointer to dst
+ * if sa.sa_family is not AF_INET or AF_INET6 dst is set as empy string.
+ * ----------
+ */
+char *
+SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv)
+{
+	switch (sa->sa.sa_family)
+	{
+		case AF_INET:
+#ifdef HAVE_IPV6
+			inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt);
+#else
+			StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt);
+#endif
+			break;
+#ifdef HAVE_IPV6
+		case AF_INET6:
+			inet_ntop(AF_INET6, &sa->in6.sin6_addr, dst, cnt);
+			if (v4conv && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr))
+				strcpy(dst, dst + 7);
+			break;
+#endif
+		default:
+			dst[0] = '\0';
+			break;
+	}
+	return dst;
+}
+
+
+/*
+ *	SockAddr_pton - IPv6 pton
+ */
+int
+SockAddr_pton(SockAddr *sa, const char *src)
+{
+	int			family = AF_INET;
+#ifdef HAVE_IPV6
+	const char		*ch;
+
+	for (ch = src; *ch != '\0'; ch++)
+	{
+		if (*ch == ':')
+		{
+			family = AF_INET6;
+			break;
+		}
+	}
+#endif
+
+	sa->sa.sa_family = family;
+
+	switch (family)
+	{
+		case AF_INET:
+#ifdef HAVE_IPV6
+			return inet_pton(AF_INET, src, &sa->in.sin_addr);
+#else
+			return inet_aton(src, &sa->in.sin_addr);
+#endif
+
+#ifdef HAVE_IPV6
+		case AF_INET6:
+			return inet_pton(AF_INET6, src, &sa->in6.sin6_addr);
+			break;
+#endif
+		default:
+			return -1;
+	}
+}
+
+
+
+
+/*
+ *	isAF_INETx - check to see if sa is AF_INET or AF_INET6
+ */
+int
+isAF_INETx(const int family)
+{
+	if (family == AF_INET
+#ifdef HAVE_IPV6
+		|| family == AF_INET6
+#endif
+		)
+		return 1;
+	else
+		return 0;
+}
+
+
+int
+rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, const SockAddr *netmask)
+{
+	if (addr->sa.sa_family == AF_INET)
+		return rangeSockAddrAF_INET(addr, netaddr, netmask);
+#ifdef HAVE_IPV6
+	else if (addr->sa.sa_family == AF_INET6)
+		return rangeSockAddrAF_INET6(addr, netaddr, netmask);
+#endif
+	else
+		return 0;
+}
+
+int
+rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
+					 const SockAddr *netmask)
+{
+	if (addr->sa.sa_family != AF_INET ||
+		netaddr->sa.sa_family != AF_INET ||
+		netmask->sa.sa_family != AF_INET)
+		return 0;
+	if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) &
+		 netmask->in.sin_addr.s_addr) == 0)
+		return 1;
+	else
+		return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
+					  const SockAddr *netmask)
+{
+	int			i;
+
+	if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr))
+	{
+		SockAddr	addr4;
+
+		convSockAddr6to4(addr, &addr4);
+		if (rangeSockAddrAF_INET(&addr4, netaddr, netmask))
+			return 1;
+	}
+
+	if (netaddr->sa.sa_family != AF_INET6 ||
+		netmask->sa.sa_family != AF_INET6)
+		return 0;
+
+	for (i = 0; i < 16; i++)
+	{
+		if (((addr->in6.sin6_addr.s6_addr[i] ^ netaddr->in6.sin6_addr.s6_addr[i]) &
+			 netmask->in6.sin6_addr.s6_addr[i]) != 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+void
+convSockAddr6to4(const SockAddr *src, SockAddr *dst)
+{
+	char		addr_str[INET6_ADDRSTRLEN];
+
+	dst->in.sin_family = AF_INET;
+	dst->in.sin_port = src->in6.sin6_port;
+
+	dst->in.sin_addr.s_addr = src->in6.sin6_addr.s6_addr32[3];
+	SockAddr_ntop(src, addr_str, INET6_ADDRSTRLEN, 0);
+}
+#endif
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 5338c79104b07782bf007de42d64e054ebe4dd32..1116debbc1acf07c85aae9a6c87401cac1a460ae 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -44,5 +44,6 @@
 
 # TYPE  DATABASE    USER        IP-ADDRESS        IP-MASK           METHOD
 
-local   all         all                                             trust
-host    all         all         127.0.0.1         255.255.255.255   trust
+local   all         all                                                                trust
+host    all         all         127.0.0.1         255.255.255.255                      trust
+host    all         all         ::1               ffff:ffff:ffff:ffff:ffff:ffff        trust
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index c3a95562b1393fe7a9bb0270454cf7004d326f5a..904afb3b8fd645cf07fbeddb3587a5ef4849c044 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -29,7 +29,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: pqcomm.c,v 1.143 2002/12/06 04:37:02 momjian Exp $
+ *	$Id: pqcomm.c,v 1.144 2003/01/06 03:18:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,6 +86,18 @@ extern ssize_t secure_write(Port *, const void *, size_t);
 
 static void pq_close(void);
 
+#ifdef HAVE_UNIX_SOCKETS
+int 	Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
+int		Setup_AF_UNIX(void);
+#endif   /* HAVE_UNIX_SOCKETS */
+
+#ifdef HAVE_IPV6
+#define FREEADDRINFO2(family, addrs)	freeaddrinfo2((family), (addrs))
+#else
+/* do nothing */
+#define FREEADDRINFO2(family, addrs)	do {} while (0)
+#endif
+
 
 /*
  * Configuration options
@@ -182,149 +194,132 @@ int
 StreamServerPort(int family, char *hostName, unsigned short portNumber,
 				 char *unixSocketName, int *fdP)
 {
-	SockAddr	saddr;
 	int			fd,
 				err;
 	int			maxconn;
-	size_t		len = 0;
 	int			one = 1;
+	int			ret;
+	char		portNumberStr[64];
+	char	   *service;
 
-	Assert(family == AF_INET || family == AF_UNIX);
+	/*
+	 *	IPv6 address lookups use a hint structure, while IPv4 creates an
+	 *	address structure directly.
+	 */
 
-	if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
-	{
-		elog(LOG, "StreamServerPort: socket() failed: %m");
-		return STATUS_ERROR;
-	}
+#ifdef HAVE_IPV6
+	struct addrinfo *addrs = NULL;
+	struct addrinfo hint;
 
-	if (family == AF_INET)
-	{
-		if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
-						sizeof(one))) == -1)
-		{
-			elog(LOG, "StreamServerPort: setsockopt(SO_REUSEADDR) failed: %m");
-			return STATUS_ERROR;
-		}
-	}
+	Assert(family == AF_INET6 || family == AF_INET || family == AF_UNIX);
+
+	/* Initialize hint structure */
+	MemSet(&hint, 0, sizeof(hint));
+	hint.ai_family = family;
+	hint.ai_flags = AI_PASSIVE;
+	hint.ai_socktype = SOCK_STREAM;
+#else
+	SockAddr	saddr;
+	size_t		len;
 
+	Assert(family == AF_INET || family == AF_UNIX);
+
+	/* Initialize address structure */
 	MemSet((char *) &saddr, 0, sizeof(saddr));
 	saddr.sa.sa_family = family;
+#endif	/* HAVE_IPV6 */
 
 #ifdef HAVE_UNIX_SOCKETS
 	if (family == AF_UNIX)
 	{
+		if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK)
+			return STATUS_ERROR;
+		service = sock_path;
+#ifndef HAVE_IPV6
 		UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
 		len = UNIXSOCK_LEN(saddr.un);
-		strcpy(sock_path, saddr.un.sun_path);
-
-		/*
-		 * Grab an interlock file associated with the socket file.
-		 */
-		if (!CreateSocketLockFile(sock_path, true))
-			return STATUS_ERROR;
-
-		/*
-		 * Once we have the interlock, we can safely delete any
-		 * pre-existing socket file to avoid failure at bind() time.
-		 */
-		unlink(sock_path);
+#endif
 	}
+	else
 #endif   /* HAVE_UNIX_SOCKETS */
+	{
+		snprintf(portNumberStr, sizeof(portNumberStr), "%d", portNumber);
+		service = portNumberStr;
+#ifndef HAVE_IPV6
+		len = sizeof(saddr.in);
+#endif
+	}
+	
+	/* Look up name using IPv6 or IPv4 routines */
+#ifdef HAVE_IPV6
+	ret = getaddrinfo2(hostName, service, &hint, &addrs);
+	if (ret || addrs == NULL)
+#else
+	ret = getaddrinfo2(hostName, service, family, &saddr);
+	if (ret)
+#endif
+	{
+		elog(LOG, "server socket failure: getaddrinfo2()%s: %s",
+#ifdef HAVE_IPV6
+			 (family == AF_INET6) ? " using IPv6" : "", gai_strerror(ret));
+		if (addrs != NULL)
+			FREEADDRINFO2(hint.ai_family, addrs);
+#else
+			 "", hostName);
+#endif
+		return STATUS_ERROR;
+	}
 
-	if (family == AF_INET)
+	if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
 	{
-		/* TCP/IP socket */
-		if (hostName[0] == '\0')
-			saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
-		else
-		{
-			struct hostent *hp;
+		elog(LOG, "server socket failure: socket(): %s",
+			 strerror(errno));
+		FREEADDRINFO2(hint.ai_family, addrs);
+		return STATUS_ERROR;
+	}
 
-			hp = gethostbyname(hostName);
-			if ((hp == NULL) || (hp->h_addrtype != AF_INET))
-			{
-				elog(LOG, "StreamServerPort: gethostbyname(%s) failed",
-					 hostName);
-				return STATUS_ERROR;
-			}
-			memmove((char *) &(saddr.in.sin_addr), (char *) hp->h_addr,
-					hp->h_length);
+	if (isAF_INETx(family))
+	{
+		if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
+						sizeof(one))) == -1)
+		{
+			elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s",
+				 strerror(errno));
+			FREEADDRINFO2(hint.ai_family, addrs);
+			return STATUS_ERROR;
 		}
-
-		saddr.in.sin_port = htons(portNumber);
-		len = sizeof(struct sockaddr_in);
 	}
 
-	err = bind(fd, (struct sockaddr *) & saddr.sa, len);
+#ifdef HAVE_IPV6
+	Assert(addrs->ai_next == NULL && addrs->ai_family == family);
+	err = bind(fd, addrs->ai_addr, addrs->ai_addrlen);
+#else
+	err = bind(fd, (struct sockaddr *) &saddr.sa, len);
+#endif
 	if (err < 0)
 	{
+		elog(LOG, "server socket failure: bind(): %s\n"
+			 "\tIs another postmaster already running on port %d?",
+			 strerror(errno), (int) portNumber);
 		if (family == AF_UNIX)
-			elog(LOG, "StreamServerPort: bind() failed: %m\n"
-				 "\tIs another postmaster already running on port %d?\n"
-				 "\tIf not, remove socket node (%s) and retry.",
-				 (int) portNumber, sock_path);
+			elog(LOG, "\tIf not, remove socket node (%s) and retry.",
+				 sock_path);
 		else
-			elog(LOG, "StreamServerPort: bind() failed: %m\n"
-				 "\tIs another postmaster already running on port %d?\n"
-				 "\tIf not, wait a few seconds and retry.",
-				 (int) portNumber);
+			elog(LOG, "\tIf not, wait a few seconds and retry.");
+		FREEADDRINFO2(hint.ai_family, addrs);
 		return STATUS_ERROR;
 	}
 
 #ifdef HAVE_UNIX_SOCKETS
 	if (family == AF_UNIX)
 	{
-		/* Arrange to unlink the socket file at exit */
-		on_proc_exit(StreamDoUnlink, 0);
-
-		/*
-		 * Fix socket ownership/permission if requested.  Note we must do
-		 * this before we listen() to avoid a window where unwanted
-		 * connections could get accepted.
-		 */
-		Assert(Unix_socket_group);
-		if (Unix_socket_group[0] != '\0')
+		if (Setup_AF_UNIX() != STATUS_OK)
 		{
-			char	   *endptr;
-			unsigned long int val;
-			gid_t		gid;
-
-			val = strtoul(Unix_socket_group, &endptr, 10);
-			if (*endptr == '\0')
-			{
-				/* numeric group id */
-				gid = val;
-			}
-			else
-			{
-				/* convert group name to id */
-				struct group *gr;
-
-				gr = getgrnam(Unix_socket_group);
-				if (!gr)
-				{
-					elog(LOG, "No such group as '%s'",
-						 Unix_socket_group);
-					return STATUS_ERROR;
-				}
-				gid = gr->gr_gid;
-			}
-			if (chown(sock_path, -1, gid) == -1)
-			{
-				elog(LOG, "Could not set group of %s: %m",
-					 sock_path);
-				return STATUS_ERROR;
-			}
-		}
-
-		if (chmod(sock_path, Unix_socket_permissions) == -1)
-		{
-			elog(LOG, "Could not set permissions on %s: %m",
-				 sock_path);
+			FREEADDRINFO2(hint.ai_family, addrs);
 			return STATUS_ERROR;
 		}
 	}
-#endif   /* HAVE_UNIX_SOCKETS */
+#endif
 
 	/*
 	 * Select appropriate accept-queue length limit.  PG_SOMAXCONN is only
@@ -338,14 +333,104 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
 	err = listen(fd, maxconn);
 	if (err < 0)
 	{
-		elog(LOG, "StreamServerPort: listen() failed: %m");
+		elog(LOG, "server socket failure: listen(): %s",
+			 strerror(errno));
+		FREEADDRINFO2(hint.ai_family, addrs);
 		return STATUS_ERROR;
 	}
 
 	*fdP = fd;
+	FREEADDRINFO2(hint.ai_family, addrs);
+	return STATUS_OK;
+
+}
+
+/*
+ * Lock_AF_UNIX -- configure unix socket file path
+ */
+
+#ifdef HAVE_UNIX_SOCKETS
+int
+Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
+{
+	SockAddr	saddr;	/* just used to get socket path */
+
+	UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
+	strcpy(sock_path, saddr.un.sun_path);
+
+	/*
+	 * Grab an interlock file associated with the socket file.
+	 */
+	if (!CreateSocketLockFile(sock_path, true))
+		return STATUS_ERROR;
+
+	/*
+	 * Once we have the interlock, we can safely delete any pre-existing
+	 * socket file to avoid failure at bind() time.
+	 */
+	unlink(sock_path);
+
+	return STATUS_OK;
+}
+
+
+/*
+ * Setup_AF_UNIX -- configure unix socket permissions
+ */
+int
+Setup_AF_UNIX(void)
+{
+	/* Arrange to unlink the socket file at exit */
+	on_proc_exit(StreamDoUnlink, 0);
 
+	/*
+	 * Fix socket ownership/permission if requested.  Note we must do this
+	 * before we listen() to avoid a window where unwanted connections
+	 * could get accepted.
+	 */
+	Assert(Unix_socket_group);
+	if (Unix_socket_group[0] != '\0')
+	{
+		char	   *endptr;
+		unsigned long int val;
+		gid_t		gid;
+
+		val = strtoul(Unix_socket_group, &endptr, 10);
+		if (*endptr == '\0')
+		{						/* numeric group id */
+			gid = val;
+		}
+		else
+		{						/* convert group name to id */
+			struct group *gr;
+
+			gr = getgrnam(Unix_socket_group);
+			if (!gr)
+			{
+				elog(LOG, "server socket failure: no such group '%s'",
+					 Unix_socket_group);
+				return STATUS_ERROR;
+			}
+			gid = gr->gr_gid;
+		}
+		if (chown(sock_path, -1, gid) == -1)
+		{
+			elog(LOG, "server socket failure: could not set group of %s: %s",
+				 sock_path, strerror(errno));
+			return STATUS_ERROR;
+		}
+	}
+
+	if (chmod(sock_path, Unix_socket_permissions) == -1)
+	{
+		elog(LOG, "server socket failure: could not set permissions on %s: %s",
+			 sock_path, strerror(errno));
+		return STATUS_ERROR;
+	}
 	return STATUS_OK;
 }
+#endif   /* HAVE_UNIX_SOCKETS */
+
 
 /*
  * StreamConnection -- create a new connection with client using
@@ -365,7 +450,7 @@ StreamConnection(int server_fd, Port *port)
 	/* accept connection (and fill in the client (remote) address) */
 	addrlen = sizeof(port->raddr);
 	if ((port->sock = accept(server_fd,
-							 (struct sockaddr *) & port->raddr,
+							 (struct sockaddr *) &port->raddr,
 							 &addrlen)) < 0)
 	{
 		elog(LOG, "StreamConnection: accept() failed: %m");
@@ -373,7 +458,6 @@ StreamConnection(int server_fd, Port *port)
 	}
 
 #ifdef SCO_ACCEPT_BUG
-
 	/*
 	 * UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it
 	 * shouldn't hurt to catch it for all versions of those platforms.
@@ -392,7 +476,7 @@ StreamConnection(int server_fd, Port *port)
 	}
 
 	/* select NODELAY and KEEPALIVE options if it's a TCP connection */
-	if (port->laddr.sa.sa_family == AF_INET)
+	if (isAF_INETx(port->laddr.sa.sa_family))
 	{
 		int			on = 1;
 
@@ -557,10 +641,10 @@ pq_getbytes(char *s, size_t len)
  *
  *		If maxlen is not zero, it is an upper limit on the length of the
  *		string we are willing to accept.  We abort the connection (by
- *		returning EOF) if client tries to send more than that.  Note that
+ *		returning EOF) if client tries to send more than that.	Note that
  *		since we test maxlen in the outer per-bufferload loop, the limit
  *		is fuzzy: we might accept up to PQ_BUFFER_SIZE more bytes than
- *		specified.  This is fine for the intended purpose, which is just
+ *		specified.	This is fine for the intended purpose, which is just
  *		to prevent DoS attacks from not-yet-authenticated clients.
  *
  *		NOTE: this routine does not do any character set conversion,
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index c1a25645a451978a0b5d3d60176fb05364caf853..e237d00ca7f0a1c31ecc59350ab0b201b4828c96 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.301 2002/12/06 04:37:02 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.302 2003/01/06 03:18:27 momjian Exp $
  *
  * NOTES
  *
@@ -669,15 +669,30 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	if (NetServer)
 	{
-		status = StreamServerPort(AF_INET, VirtualHost,
+#ifdef HAVE_IPV6
+		/* Try INET6 first.  May fail if kernel doesn't support IP6 */
+		status = StreamServerPort(AF_INET6, VirtualHost,
 								  (unsigned short) PostPortNumber,
 								  UnixSocketDir,
 								  &ServerSock_INET);
 		if (status != STATUS_OK)
 		{
-			postmaster_error("cannot create INET stream port");
-			ExitPostmaster(1);
+			elog(LOG, "IPv6 support disabled --- perhaps the kernel does not support IPv6");
+#endif
+			status = StreamServerPort(AF_INET, VirtualHost,
+									  (unsigned short) PostPortNumber,
+									  UnixSocketDir,
+									  &ServerSock_INET);
+			if (status != STATUS_OK)
+			{
+				postmaster_error("cannot create INET stream port");
+				ExitPostmaster(1);
+			}
+#ifdef HAVE_IPV6
+			else
+				elog(LOG, "IPv4 socket created");
 		}
+#endif
 	}
 
 #ifdef HAVE_UNIX_SOCKETS
@@ -2091,13 +2106,19 @@ DoBackend(Port *port)
 	/*
 	 * Get the remote host name and port for logging and status display.
 	 */
-	if (port->raddr.sa.sa_family == AF_INET)
+	if (isAF_INETx(port->raddr.sa.sa_family))
 	{
 		unsigned short remote_port;
 		char	   *host_addr;
+#ifdef HAVE_IPV6
+		char	   ip_hostinfo[INET6_ADDRSTRLEN]; 
+#else
+		char	   ip_hostinfo[INET_ADDRSTRLEN];
+#endif
 
 		remote_port = ntohs(port->raddr.in.sin_port);
-		host_addr = inet_ntoa(port->raddr.in.sin_addr);
+		host_addr = SockAddr_ntop(&port->raddr, ip_hostinfo,
+			sizeof(ip_hostinfo), 1);
 
 		remote_host = NULL;
 
diff --git a/src/include/libpq/ip.h b/src/include/libpq/ip.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9d1b0e466734b32825e92c7ae07b37893610d5c
--- /dev/null
+++ b/src/include/libpq/ip.h
@@ -0,0 +1,29 @@
+#ifndef IP_H
+#define IP_H
+#include <sys/socket.h>
+#include <netdb.h>
+#include "libpq/pqcomm.h"
+
+#ifdef HAVE_IPV6
+void  freeaddrinfo2(int hint_ai_family, struct addrinfo *ai);
+int   getaddrinfo2(const char *hostname, const char *servname,
+		   const struct addrinfo *hintp, struct addrinfo **result);
+#else
+int   getaddrinfo2(const char *hostname, const char *servname,
+			 int family, SockAddr *result);
+#endif
+
+char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv);
+int   SockAddr_pton(SockAddr *sa, const char *src);
+int   isAF_INETx(const int family);
+int   rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr,
+			const SockAddr *netmask);
+int   rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr, 
+			   const SockAddr *netmask);
+#ifdef HAVE_IPV6
+int   rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr, 
+			    const SockAddr *netmask);
+void  convSockAddr6to4(const SockAddr *src, SockAddr *dst);
+#endif
+
+#endif /* IP_H */
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index ced71326cea0aa87598631f17467476fbee566c6..0e8ecad246edfb8d23ab983f333bbc47d917baca 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq.h,v 1.54 2002/12/06 04:37:05 momjian Exp $
+ * $Id: libpq.h,v 1.55 2003/01/06 03:18:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 
 #include "lib/stringinfo.h"
 #include "libpq/libpq-be.h"
+#include "libpq/ip.h"
 
 /* ----------------
  * PQArgBlock
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index 1375852a0ca351d664084595c9564b27d5337f43..88f2d08bbc641523532afbf164acec5a129b6aa7 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqcomm.h,v 1.72 2002/12/06 04:37:05 momjian Exp $
+ * $Id: pqcomm.h,v 1.73 2003/01/06 03:18:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,9 @@ typedef union SockAddr
 {
 	struct sockaddr sa;
 	struct sockaddr_in in;
+#ifdef HAVE_IPV6
+	struct sockaddr_in6 in6;
+#endif
 	struct sockaddr_un un;
 } SockAddr;
 
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index e6668999612eaae8bb14d23b0782795b012907da..447a6c7a89a30735fd3010fa7cc6a1f333831e40 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -8,7 +8,7 @@
  * or in pg_config.h afterwards.  Of course, if you edit pg_config.h, then your
  * changes will be overwritten the next time you run configure.
  *
- * $Id: pg_config.h.in,v 1.34 2002/11/10 00:38:21 momjian Exp $
+ * $Id: pg_config.h.in,v 1.35 2003/01/06 03:18:27 momjian Exp $
  */
 
 #ifndef PG_CONFIG_H
@@ -368,6 +368,9 @@
 /* Set to 1 if you have <sys/shm.h> */
 #undef HAVE_SYS_SHM_H
 
+/* Set to 1 if you have <netinet/ip6.h> for IPv6 */
+#undef HAVE_IPV6
+
 /* Set to 1 if you have <kernel/OS.h> */
 #undef HAVE_KERNEL_OS_H
 
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 4a31afb3d8826ae7b740e2a7347b55777c814297..2fbab37e16134bbe8099d682f5a82ae7eb185b80 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -4,7 +4,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.70 2002/12/13 22:17:57 momjian Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.71 2003/01/06 03:18:27 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -21,8 +21,8 @@ SO_MINOR_VERSION= 1
 override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"'
 
 OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
-      pqexpbuffer.o dllist.o md5.o pqsignal.o fe-secure.o \
-      wchar.o encnames.o \
+      pqexpbuffer.o dllist.o pqsignal.o fe-secure.o wchar.o encnames.o ip.o \
+      md5.o \
       $(filter inet_aton.o snprintf.o strerror.o, $(LIBOBJS))
 
 
@@ -45,6 +45,9 @@ dllist.c: $(backend_src)/lib/dllist.c
 md5.c: $(backend_src)/libpq/md5.c
 	rm -f $@ && $(LN_S) $< .
 
+ip.c: $(backend_src)/libpq/ip.c
+	rm -f $@ && $(LN_S) $< .
+
 # We use several backend modules verbatim, but since we need to
 # compile with appropriate options to build a shared lib, we can't
 # necessarily use the same object files as the backend uses. Instead,
@@ -70,5 +73,5 @@ uninstall: uninstall-lib
 	rm -f $(DESTDIR)$(includedir)/libpq-fe.h $(DESTDIR)$(includedir_internal)/libpq-int.h $(includedir_internal)/pqexpbuffer.h
 
 clean distclean maintainer-clean: clean-lib
-	rm -f $(OBJS) dllist.c md5.c wchar.c encnames.c
+	rm -f $(OBJS) dllist.c md5.c v6util.c wchar.c encnames.c
 	rm -f $(OBJS) inet_aton.c snprintf.c strerror.c
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 659114f9995b74308bbad79e17ad4add3dd566ac..8ce8f197807b60f062acbba64bd6215bfcc44463 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.216 2002/12/19 19:30:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.217 2003/01/06 03:18:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,9 @@
 #include <arpa/inet.h>
 #endif
 
+#include "libpq/ip.h"
+
+
 #ifndef HAVE_STRDUP
 #include "strdup.h"
 #endif
@@ -48,6 +51,14 @@
 
 #include "mb/pg_wchar.h"
 
+
+#ifdef HAVE_IPV6
+#define FREEADDRINFO2(family, addrs)	freeaddrinfo2((family), (addrs))
+#else
+/* do nothing */
+#define FREEADDRINFO2(family, addrs)	do {} while (0)
+#endif
+
 #ifdef WIN32
 static int
 inet_aton(const char *cp, struct in_addr * inp)
@@ -784,19 +795,32 @@ connectFailureMessage(PGconn *conn, int errorno)
 static int
 connectDBStart(PGconn *conn)
 {
-	int			portno,
-				family;
-
+	int			portnum;
+	int			sockfd;
+	char		portstr[64];
 #ifdef USE_SSL
 	StartupPacket np;			/* Used to negotiate SSL connection */
 	char		SSLok;
 #endif
+#ifdef HAVE_IPV6
+	struct addrinfo *addrs = NULL;
+	struct addrinfo *addr_cur = NULL;
+	struct addrinfo hint;
+	const char *node = NULL;
+	const char *unix_node = "unix";
+	int			ret;
+
+	/* Initialize hint structure */
+	MemSet(&hint, 0, sizeof(hint));
+	hint.ai_socktype = SOCK_STREAM;
+#else
+	int			family = -1;
+#endif
 
 	if (!conn)
 		return 0;
 
 #ifdef NOT_USED
-
 	/*
 	 * parse dbName to get all additional info in it, if any
 	 */
@@ -815,10 +839,26 @@ connectDBStart(PGconn *conn)
 
 	MemSet((char *) &conn->raddr, 0, sizeof(conn->raddr));
 
+	/*
+	 *	This code is confusing because IPv6 creates a hint structure
+	 *	that is passed to getaddrinfo2(), which returns a list of address
+	 *	structures that are looped through, while IPv4 creates an address
+	 *	structure directly.
+	 */
+
+	if (conn->pgport != NULL && conn->pgport[0] != '\0')
+		portnum = atoi(conn->pgport);
+	else
+		portnum = DEF_PGPORT;
+	snprintf(portstr, sizeof(portstr), "%d", portnum);
+
 	if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
 	{
+#ifdef HAVE_IPV6
+		node = conn->pghostaddr;
+		hint.ai_family = AF_UNSPEC;
+#else
 		/* Using pghostaddr avoids a hostname lookup */
-		/* Note that this supports IPv4 only */
 		struct in_addr addr;
 
 		if (!inet_aton(conn->pghostaddr, &addr))
@@ -833,120 +873,158 @@ connectDBStart(PGconn *conn)
 
 		memmove((char *) &(conn->raddr.in.sin_addr),
 				(char *) &addr, sizeof(addr));
+#endif
 	}
 	else if (conn->pghost != NULL && conn->pghost[0] != '\0')
 	{
+#ifdef HAVE_IPV6
+		node = conn->pghost;
+		hint.ai_family = AF_UNSPEC;
+#else
 		/* Using pghost, so we have to look-up the hostname */
-		struct hostent *hp;
-
-		hp = gethostbyname(conn->pghost);
-		if ((hp == NULL) || (hp->h_addrtype != AF_INET))
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-							  libpq_gettext("unknown host name: %s\n"),
-							  conn->pghost);
+		if (getaddrinfo2(conn->pghost, portstr, family, &conn->raddr) != 0)
 			goto connect_errReturn;
-		}
-		family = AF_INET;
 
-		memmove((char *) &(conn->raddr.in.sin_addr),
-				(char *) hp->h_addr,
-				hp->h_length);
+		family = AF_INET;
+#endif
 	}
+#ifdef HAVE_UNIX_SOCKETS
 	else
 	{
+#ifdef HAVE_IPV6
+		node = unix_node;
+		hint.ai_family = AF_UNIX;
+#else
 		/* pghostaddr and pghost are NULL, so use Unix domain socket */
 		family = AF_UNIX;
+#endif
 	}
+#endif   /* HAVE_UNIX_SOCKETS */
 
-	/* Set family */
+#ifndef HAVE_IPV6
 	conn->raddr.sa.sa_family = family;
+#endif
 
-	/* Set port number */
-	if (conn->pgport != NULL && conn->pgport[0] != '\0')
-		portno = atoi(conn->pgport);
-	else
-		portno = DEF_PGPORT;
-
+#ifdef HAVE_IPV6
+	if (hint.ai_family == AF_UNSPEC)
+	{/* do nothing*/}
+#else
 	if (family == AF_INET)
 	{
-		conn->raddr.in.sin_port = htons((unsigned short) (portno));
+		conn->raddr.in.sin_port = htons((unsigned short) (portnum));
 		conn->raddr_len = sizeof(struct sockaddr_in);
 	}
+#endif
 #ifdef HAVE_UNIX_SOCKETS
 	else
 	{
-		UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
+		UNIXSOCK_PATH(conn->raddr.un, portnum, conn->pgunixsocket);
 		conn->raddr_len = UNIXSOCK_LEN(conn->raddr.un);
+		StrNCpy(portstr, conn->raddr.un.sun_path, sizeof(portstr));
 #ifdef USE_SSL
 		/* Don't bother requesting SSL over a Unix socket */
 		conn->allow_ssl_try = false;
 		conn->require_ssl = false;
 #endif
 	}
-#endif
+#endif   /* HAVE_UNIX_SOCKETS */
 
-	/* Open a socket */
-	if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
+#if HAVE_IPV6
+	ret = getaddrinfo2(node, portstr, &hint, &addrs);
+	if (ret || addrs == NULL)
 	{
 		printfPQExpBuffer(&conn->errorMessage,
-						  libpq_gettext("could not create socket: %s\n"),
-						  SOCK_STRERROR(SOCK_ERRNO));
+						  libpq_gettext("failed to getaddrinfo(): %s\n"),
+						  gai_strerror(ret));
 		goto connect_errReturn;
 	}
+	addr_cur = addrs;
+#endif
 
-	/*
-	 * Set the right options. Normally, we need nonblocking I/O, and we
-	 * don't want delay of outgoing data for AF_INET sockets.  If we are
-	 * using SSL, then we need the blocking I/O (XXX Can this be fixed?).
-	 */
-
-	if (family == AF_INET)
+	do
 	{
-		if (!connectNoDelay(conn))
-			goto connect_errReturn;
-	}
+#ifdef HAVE_IPV6
+		sockfd = socket(addr_cur->ai_family, SOCK_STREAM,
+						addr_cur->ai_protocol);
+#else
+		sockfd = socket(family, SOCK_STREAM, 0);
+#endif
+		if (sockfd < 0)
+			continue;
 
+		conn->sock = sockfd;
+#ifdef HAVE_IPV6
+		if (isAF_INETx(addr_cur->ai_family))
+#else
+		if (isAF_INETx(family))
+#endif
+		{
+			if (!connectNoDelay(conn))
+				goto connect_errReturn;
+		}
 #if !defined(USE_SSL)
-	if (connectMakeNonblocking(conn) == 0)
-		goto connect_errReturn;
+		if (connectMakeNonblocking(conn) == 0)
+			goto connect_errReturn;
 #endif
 
-	/* ----------
-	 * Start / make connection.  We are hopefully in non-blocking mode
-	 * now, but it is possible that:
-	 *	 1. Older systems will still block on connect, despite the
-	 *		non-blocking flag. (Anyone know if this is true?)
-	 *	 2. We are using SSL.
-	 * Thus, we have to make arrangements for all eventualities.
-	 * ----------
-	 */
+		/* ----------
+		 * Start / make connection.  We are hopefully in non-blocking mode
+		 * now, but it is possible that:
+		 *	 1. Older systems will still block on connect, despite the
+		 *		non-blocking flag. (Anyone know if this is true?)
+		 *	 2. We are using SSL.
+		 * Thus, we have to make arrangements for all eventualities.
+		 * ----------
+		 */
 retry1:
-	if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0)
-	{
-		if (SOCK_ERRNO == EINTR)
-			/* Interrupted system call - we'll just try again */
-			goto retry1;
-
-		if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == 0)
+#ifdef HAVE_IPV6
+		if (connect(sockfd, addr_cur->ai_addr, addr_cur->ai_addrlen) == 0)
+#else
+		if (connect(sockfd, &conn->raddr.sa, conn->raddr_len) == 0)
+#endif
 		{
-			/*
-			 * This is fine - we're in non-blocking mode, and the
-			 * connection is in progress.
-			 */
-			conn->status = CONNECTION_STARTED;
+			/* We're connected already */
+			conn->status = CONNECTION_MADE;
+			break;
 		}
 		else
 		{
-			/* Something's gone wrong */
-			connectFailureMessage(conn, SOCK_ERRNO);
-			goto connect_errReturn;
+			if (SOCK_ERRNO == EINTR)
+				/* Interrupted system call - we'll just try again */
+				goto retry1;
+
+			if (SOCK_ERRNO == EINPROGRESS || SOCK_ERRNO == EWOULDBLOCK || SOCK_ERRNO == 0)
+			{
+				/*
+				 * This is fine - we're in non-blocking mode, and the
+				 * connection is in progress.
+				 */
+				conn->status = CONNECTION_STARTED;
+				break;
+			}
 		}
+		close(sockfd);
+#ifdef HAVE_IPV6
+	} while ((addr_cur = addr_cur->ai_next) != NULL);
+	if (addr_cur == NULL)
+#else
+	} while (0);
+	if (sockfd < 0)
+#endif
+	{
+		printfPQExpBuffer(&conn->errorMessage,
+						  libpq_gettext("could not create socket: %s\n"),
+						  SOCK_STRERROR(SOCK_ERRNO));
+		goto connect_errReturn;
 	}
 	else
 	{
-		/* We're connected already */
-		conn->status = CONNECTION_MADE;
+#ifdef HAVE_IPV6
+		memmove(&conn->raddr, addr_cur->ai_addr, addr_cur->ai_addrlen);
+		conn->raddr_len = addr_cur->ai_addrlen;
+		FREEADDRINFO2(hint.ai_family, addrs);
+		addrs = NULL;
+#endif
 	}
 
 #ifdef USE_SSL
@@ -1014,7 +1092,6 @@ retry2:
 	}
 #endif
 
-
 	/*
 	 * This makes the connection non-blocking, for all those cases which
 	 * forced us not to do it above.
@@ -1038,7 +1115,10 @@ connect_errReturn:
 		conn->sock = -1;
 	}
 	conn->status = CONNECTION_BAD;
-
+#ifdef HAVE_IPV6
+	if (addrs != NULL)
+		FREEADDRINFO2(hint.ai_family, addrs);
+#endif
 	return 0;
 }