1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-15 03:41:20 +03:00

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:
Bruce Momjian
2003-01-06 03:18:27 +00:00
parent d99e7b5a0d
commit c3e9699f21
18 changed files with 949 additions and 248 deletions

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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,

View File

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