Enable IPv6 connections to the server, and add pg_hba.conf IPv6 entries
if the OS supports it. Code will still compile on non-IPv6-aware machines (feature added by Bruce). Nigel Kukard
This commit is contained in:
parent
d99e7b5a0d
commit
c3e9699f21
75
configure
vendored
75
configure
vendored
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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@
|
||||
|
||||
##########################################################################
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
371
src/backend/libpq/ip.c
Normal file
371
src/backend/libpq/ip.c
Normal file
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
* IPv6 address lookups use a hint structure, while IPv4 creates an
|
||||
* address structure directly.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
struct addrinfo *addrs = NULL;
|
||||
struct addrinfo hint;
|
||||
|
||||
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);
|
||||
|
||||
if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
|
||||
/* 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)
|
||||
{
|
||||
elog(LOG, "StreamServerPort: socket() failed: %m");
|
||||
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);
|
||||
#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)
|
||||
{
|
||||
elog(LOG, "server socket failure: socket(): %s",
|
||||
strerror(errno));
|
||||
FREEADDRINFO2(hint.ai_family, addrs);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (isAF_INETx(family))
|
||||
{
|
||||
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
|
||||
sizeof(one))) == -1)
|
||||
{
|
||||
elog(LOG, "StreamServerPort: setsockopt(SO_REUSEADDR) failed: %m");
|
||||
elog(LOG, "server socket failure: setsockopt(SO_REUSEADDR): %s",
|
||||
strerror(errno));
|
||||
FREEADDRINFO2(hint.ai_family, addrs);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
MemSet((char *) &saddr, 0, sizeof(saddr));
|
||||
saddr.sa.sa_family = family;
|
||||
|
||||
#ifdef HAVE_UNIX_SOCKETS
|
||||
if (family == AF_UNIX)
|
||||
{
|
||||
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 /* HAVE_UNIX_SOCKETS */
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
/* TCP/IP socket */
|
||||
if (hostName[0] == '\0')
|
||||
saddr.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, "StreamServerPort: gethostbyname(%s) failed",
|
||||
hostName);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
memmove((char *) &(saddr.in.sin_addr), (char *) hp->h_addr,
|
||||
hp->h_length);
|
||||
}
|
||||
|
||||
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,15 +333,105 @@ 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
|
||||
* server port.
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
29
src/include/libpq/ip.h
Normal file
29
src/include/libpq/ip.h
Normal file
@ -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 */
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pghostaddr and pghost are NULL, so use Unix domain socket */
|
||||
family = AF_UNIX;
|
||||
}
|
||||
|
||||
/* Set family */
|
||||
conn->raddr.sa.sa_family = family;
|
||||
|
||||
/* Set port number */
|
||||
if (conn->pgport != NULL && conn->pgport[0] != '\0')
|
||||
portno = atoi(conn->pgport);
|
||||
else
|
||||
portno = DEF_PGPORT;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
conn->raddr.in.sin_port = htons((unsigned short) (portno));
|
||||
conn->raddr_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_UNIX_SOCKETS
|
||||
else
|
||||
{
|
||||
UNIXSOCK_PATH(conn->raddr.un, portno, conn->pgunixsocket);
|
||||
#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 */
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
conn->raddr.sa.sa_family = family;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (hint.ai_family == AF_UNSPEC)
|
||||
{/* do nothing*/}
|
||||
#else
|
||||
if (family == AF_INET)
|
||||
{
|
||||
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, 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 /* HAVE_UNIX_SOCKETS */
|
||||
|
||||
#if HAVE_IPV6
|
||||
ret = getaddrinfo2(node, portstr, &hint, &addrs);
|
||||
if (ret || addrs == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("failed to getaddrinfo(): %s\n"),
|
||||
gai_strerror(ret));
|
||||
goto connect_errReturn;
|
||||
}
|
||||
addr_cur = addrs;
|
||||
#endif
|
||||
|
||||
/* Open a socket */
|
||||
if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0)
|
||||
do
|
||||
{
|
||||
#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;
|
||||
#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.
|
||||
* ----------
|
||||
*/
|
||||
retry1:
|
||||
#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
|
||||
{
|
||||
/* We're connected already */
|
||||
conn->status = CONNECTION_MADE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
if (!connectNoDelay(conn))
|
||||
goto connect_errReturn;
|
||||
}
|
||||
|
||||
#if !defined(USE_SSL)
|
||||
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.
|
||||
* ----------
|
||||
*/
|
||||
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)
|
||||
{
|
||||
/*
|
||||
* This is fine - we're in non-blocking mode, and the
|
||||
* connection is in progress.
|
||||
*/
|
||||
conn->status = CONNECTION_STARTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something's gone wrong */
|
||||
connectFailureMessage(conn, 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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user