mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Have a go at fixing various outstanding portability issues in code that
was modified for IPv6. Use a robust definition of struct sockaddr_storage, do a proper configure test to see if ss_len exists, don't assume that getnameinfo() will handle AF_UNIX sockets, don't trust getaddrinfo to return the protocol we ask for, etc. This incorporates several outstanding patches from Kurt Roeckx, but I'm to blame for anything that doesn't work ...
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.104 2003/07/22 19:00:10 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.105 2003/07/23 23:30:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -434,11 +434,10 @@ ClientAuthentication(Port *port)
|
||||
{
|
||||
char hostinfo[NI_MAXHOST];
|
||||
|
||||
getnameinfo((struct sockaddr *) &port->raddr.addr,
|
||||
port->raddr.salen,
|
||||
hostinfo, sizeof(hostinfo),
|
||||
NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
getnameinfo_all(&port->raddr.addr, port->raddr.salen,
|
||||
hostinfo, sizeof(hostinfo),
|
||||
NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
|
||||
ereport(FATAL,
|
||||
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.106 2003/07/22 21:19:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.107 2003/07/23 23:30:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -648,31 +648,33 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
|
||||
hints.ai_next = NULL;
|
||||
|
||||
/* Get the IP address either way */
|
||||
ret = getaddrinfo2(token, NULL, &hints, &file_ip_addr);
|
||||
ret = getaddrinfo_all(token, NULL, &hints, &file_ip_addr);
|
||||
if (ret || !file_ip_addr)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("failed to interpret IP address \"%s\" in config file: %s",
|
||||
errmsg("could not interpret IP address \"%s\" in config file: %s",
|
||||
token, gai_strerror(ret))));
|
||||
if (cidr_slash)
|
||||
*cidr_slash = '/';
|
||||
goto hba_syntax;
|
||||
}
|
||||
|
||||
if (cidr_slash)
|
||||
*cidr_slash = '/';
|
||||
|
||||
if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
|
||||
{
|
||||
/* Wrong address family. */
|
||||
freeaddrinfo2(hints.ai_family, file_ip_addr);
|
||||
freeaddrinfo_all(hints.ai_family, file_ip_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the netmask */
|
||||
if (cidr_slash)
|
||||
{
|
||||
*cidr_slash = '/';
|
||||
if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
|
||||
file_ip_addr->ai_family) < 0)
|
||||
file_ip_addr->ai_family) < 0)
|
||||
goto hba_syntax;
|
||||
}
|
||||
else
|
||||
@@ -683,13 +685,13 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
|
||||
goto hba_syntax;
|
||||
token = lfirst(line);
|
||||
|
||||
ret = getaddrinfo2(token, NULL, &hints, &file_ip_mask);
|
||||
ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
|
||||
if (ret || !file_ip_mask)
|
||||
goto hba_syntax;
|
||||
|
||||
mask = (struct sockaddr_storage *)file_ip_mask->ai_addr;
|
||||
|
||||
if(file_ip_addr->ai_family != mask->ss_family)
|
||||
if (file_ip_addr->ai_family != mask->ss_family)
|
||||
goto hba_syntax;
|
||||
}
|
||||
|
||||
@@ -703,12 +705,13 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
|
||||
|
||||
/* Must meet network restrictions */
|
||||
if (!rangeSockAddr(&port->raddr.addr,
|
||||
(struct sockaddr_storage *)file_ip_addr->ai_addr, mask))
|
||||
(struct sockaddr_storage *)file_ip_addr->ai_addr,
|
||||
mask))
|
||||
goto hba_freeaddr;
|
||||
|
||||
freeaddrinfo2(hints.ai_family, file_ip_addr);
|
||||
freeaddrinfo_all(hints.ai_family, file_ip_addr);
|
||||
if (file_ip_mask)
|
||||
freeaddrinfo2(hints.ai_family, file_ip_mask);
|
||||
freeaddrinfo_all(hints.ai_family, file_ip_mask);
|
||||
}
|
||||
else
|
||||
goto hba_syntax;
|
||||
@@ -731,16 +734,16 @@ hba_syntax:
|
||||
else
|
||||
ereport(LOG,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("missing entry in pg_hba.conf file at end of line %d",
|
||||
errmsg("missing field in pg_hba.conf file at end of line %d",
|
||||
line_number)));
|
||||
|
||||
*error_p = true;
|
||||
|
||||
hba_freeaddr:
|
||||
if (file_ip_addr)
|
||||
freeaddrinfo2(hints.ai_family, file_ip_addr);
|
||||
freeaddrinfo_all(hints.ai_family, file_ip_addr);
|
||||
if (file_ip_mask)
|
||||
freeaddrinfo2(hints.ai_family, file_ip_mask);
|
||||
freeaddrinfo_all(hints.ai_family, file_ip_mask);
|
||||
}
|
||||
|
||||
|
||||
@@ -1209,14 +1212,14 @@ ident_inet(const SockAddr remote_addr,
|
||||
* Might look a little weird to first convert it to text and
|
||||
* then back to sockaddr, but it's protocol independent.
|
||||
*/
|
||||
getnameinfo((struct sockaddr *)&remote_addr.addr, remote_addr.salen,
|
||||
remote_addr_s, sizeof(remote_addr_s),
|
||||
remote_port, sizeof(remote_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
getnameinfo((struct sockaddr *)&local_addr.addr, local_addr.salen,
|
||||
local_addr_s, sizeof(local_addr_s),
|
||||
local_port, sizeof(local_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
getnameinfo_all(&remote_addr.addr, remote_addr.salen,
|
||||
remote_addr_s, sizeof(remote_addr_s),
|
||||
remote_port, sizeof(remote_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
getnameinfo_all(&local_addr.addr, local_addr.salen,
|
||||
local_addr_s, sizeof(local_addr_s),
|
||||
local_port, sizeof(local_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT);
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
@@ -1227,7 +1230,7 @@ ident_inet(const SockAddr remote_addr,
|
||||
hints.ai_canonname = NULL;
|
||||
hints.ai_addr = NULL;
|
||||
hints.ai_next = NULL;
|
||||
rc = getaddrinfo2(remote_addr_s, ident_port, &hints, &ident_serv);
|
||||
rc = getaddrinfo_all(remote_addr_s, ident_port, &hints, &ident_serv);
|
||||
if (rc || !ident_serv)
|
||||
return false; /* we don't expect this to happen */
|
||||
|
||||
@@ -1239,7 +1242,7 @@ ident_inet(const SockAddr remote_addr,
|
||||
hints.ai_canonname = NULL;
|
||||
hints.ai_addr = NULL;
|
||||
hints.ai_next = NULL;
|
||||
rc = getaddrinfo2(local_addr_s, NULL, &hints, &la);
|
||||
rc = getaddrinfo_all(local_addr_s, NULL, &hints, &la);
|
||||
if (rc || !la)
|
||||
return false; /* we don't expect this to happen */
|
||||
|
||||
@@ -1323,8 +1326,8 @@ ident_inet(const SockAddr remote_addr,
|
||||
ident_inet_done:
|
||||
if (sock_fd >= 0)
|
||||
closesocket(sock_fd);
|
||||
freeaddrinfo2(remote_addr.addr.ss_family, ident_serv);
|
||||
freeaddrinfo2(local_addr.addr.ss_family, la);
|
||||
freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
|
||||
freeaddrinfo_all(local_addr.addr.ss_family, la);
|
||||
return ident_return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.15 2003/06/12 08:15:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.16 2003/07/23 23:30:40 tgl Exp $
|
||||
*
|
||||
* This file and the IPV6 implementation were initially provided by
|
||||
* Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
|
||||
@@ -53,15 +53,20 @@ static int rangeSockAddrAF_INET6(const struct sockaddr_in6 *addr,
|
||||
static int getaddrinfo_unix(const char *path,
|
||||
const struct addrinfo *hintsp,
|
||||
struct addrinfo **result);
|
||||
|
||||
static int getnameinfo_unix(const struct sockaddr_un *sa, int salen,
|
||||
char *node, int nodelen,
|
||||
char *service, int servicelen,
|
||||
int flags);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* getaddrinfo2 - get address info for Unix, IPv4 and IPv6 sockets
|
||||
* getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
|
||||
*/
|
||||
int
|
||||
getaddrinfo2(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hintp, struct addrinfo **result)
|
||||
getaddrinfo_all(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hintp, struct addrinfo **result)
|
||||
{
|
||||
#ifdef HAVE_UNIX_SOCKETS
|
||||
if (hintp != NULL && hintp->ai_family == AF_UNIX)
|
||||
@@ -75,7 +80,7 @@ getaddrinfo2(const char *hostname, const char *servname,
|
||||
|
||||
|
||||
/*
|
||||
* freeaddrinfo2 - free addrinfo structures for IPv4, IPv6, or Unix
|
||||
* freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
|
||||
*
|
||||
* Note: the ai_family field of the original hint structure must be passed
|
||||
* so that we can tell whether the addrinfo struct was built by the system's
|
||||
@@ -84,12 +89,12 @@ getaddrinfo2(const char *hostname, const char *servname,
|
||||
* not safe to look at ai_family in the addrinfo itself.
|
||||
*/
|
||||
void
|
||||
freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
|
||||
freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
|
||||
{
|
||||
#ifdef HAVE_UNIX_SOCKETS
|
||||
if (hint_ai_family == AF_UNIX)
|
||||
{
|
||||
/* struct was built by getaddrinfo_unix (see getaddrinfo2) */
|
||||
/* struct was built by getaddrinfo_unix (see getaddrinfo_all) */
|
||||
while (ai != NULL)
|
||||
{
|
||||
struct addrinfo *p = ai;
|
||||
@@ -109,11 +114,53 @@ freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
|
||||
*
|
||||
* The API of this routine differs from the standard getnameinfo() definition
|
||||
* in two ways: first, the addr parameter is declared as sockaddr_storage
|
||||
* rather than struct sockaddr, and second, the node and service fields are
|
||||
* guaranteed to be filled with something even on failure return.
|
||||
*/
|
||||
int
|
||||
getnameinfo_all(const struct sockaddr_storage *addr, int salen,
|
||||
char *node, int nodelen,
|
||||
char *service, int servicelen,
|
||||
int flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#ifdef HAVE_UNIX_SOCKETS
|
||||
if (addr && addr->ss_family == AF_UNIX)
|
||||
rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
|
||||
node, nodelen,
|
||||
service, servicelen,
|
||||
flags);
|
||||
else
|
||||
#endif
|
||||
rc = getnameinfo((const struct sockaddr *) addr, salen,
|
||||
node, nodelen,
|
||||
service, servicelen,
|
||||
flags);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
if (node)
|
||||
StrNCpy(node, "???", nodelen);
|
||||
if (service)
|
||||
StrNCpy(service, "???", servicelen);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_UNIX_SOCKETS)
|
||||
|
||||
/* -------
|
||||
* getaddrinfo_unix - get unix socket info using IPv6-compatible API
|
||||
*
|
||||
* Bug: only one addrinfo is set even though hintsp is NULL or
|
||||
* Bugs: only one addrinfo is set even though hintsp is NULL or
|
||||
* ai_socktype is 0
|
||||
* AI_CANONNAME is not supported.
|
||||
* -------
|
||||
@@ -176,12 +223,59 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
|
||||
|
||||
strcpy(unp->sun_path, path);
|
||||
|
||||
#if SALEN
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||
unp->sun_len = sizeof(struct sockaddr_un);
|
||||
#endif /* SALEN */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an address to a hostname.
|
||||
*/
|
||||
static int
|
||||
getnameinfo_unix(const struct sockaddr_un *sa, int salen,
|
||||
char *node, int nodelen,
|
||||
char *service, int servicelen,
|
||||
int flags)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
/* Invalid arguments. */
|
||||
if (sa == NULL || sa->sun_family != AF_UNIX ||
|
||||
(node == NULL && service == NULL))
|
||||
{
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
/* We don't support those. */
|
||||
if ((node && !(flags & NI_NUMERICHOST))
|
||||
|| (service && !(flags & NI_NUMERICSERV)))
|
||||
{
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
if (node)
|
||||
{
|
||||
ret = snprintf(node, nodelen, "%s", "localhost");
|
||||
if (ret == -1 || ret > nodelen)
|
||||
{
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (service)
|
||||
{
|
||||
ret = snprintf(service, servicelen, "%s", sa->sun_path);
|
||||
if (ret == -1 || ret > servicelen)
|
||||
{
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_UNIX_SOCKETS */
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.158 2003/07/22 19:00:10 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.159 2003/07/23 23:30:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -190,16 +190,18 @@ StreamDoUnlink(void)
|
||||
#endif /* HAVE_UNIX_SOCKETS */
|
||||
|
||||
/*
|
||||
* StreamServerPort -- open a sock stream "listening" port.
|
||||
* StreamServerPort -- open a "listening" port to accept connections.
|
||||
*
|
||||
* This initializes the Postmaster's connection-accepting port *fdP.
|
||||
* Successfully opened sockets are added to the ListenSocket[] array,
|
||||
* at the first position that isn't -1.
|
||||
*
|
||||
* RETURNS: STATUS_OK or STATUS_ERROR
|
||||
*/
|
||||
|
||||
int
|
||||
StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
char *unixSocketName, int ListenSocket[], int MaxListen)
|
||||
char *unixSocketName,
|
||||
int ListenSocket[], int MaxListen)
|
||||
{
|
||||
int fd,
|
||||
err;
|
||||
@@ -216,7 +218,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
/* Initialize hint structure */
|
||||
MemSet(&hint, 0, sizeof(hint));
|
||||
hint.ai_family = family;
|
||||
hint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
||||
hint.ai_flags = AI_PASSIVE;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
#ifdef HAVE_UNIX_SOCKETS
|
||||
@@ -234,13 +236,18 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
service = portNumberStr;
|
||||
}
|
||||
|
||||
ret = getaddrinfo2(hostName, service, &hint, &addrs);
|
||||
if (ret || addrs == NULL)
|
||||
ret = getaddrinfo_all(hostName, service, &hint, &addrs);
|
||||
if (ret || !addrs)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("failed to translate hostname to address: %s",
|
||||
gai_strerror(ret))));
|
||||
freeaddrinfo2(hint.ai_family, addrs);
|
||||
if (hostName)
|
||||
ereport(LOG,
|
||||
(errmsg("could not translate hostname \"%s\", service \"%s\" to address: %s",
|
||||
hostName, service, gai_strerror(ret))));
|
||||
else
|
||||
ereport(LOG,
|
||||
(errmsg("could not translate service \"%s\" to address: %s",
|
||||
service, gai_strerror(ret))));
|
||||
freeaddrinfo_all(hint.ai_family, addrs);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
@@ -250,7 +257,8 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
{
|
||||
/* Only set up a unix domain socket when
|
||||
* they really asked for it. The service/port
|
||||
* is different in that case. */
|
||||
* is different in that case.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -258,17 +266,15 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
for (; listen_index < MaxListen; listen_index++)
|
||||
{
|
||||
if (ListenSocket[listen_index] == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (listen_index == MaxListen)
|
||||
if (listen_index >= MaxListen)
|
||||
{
|
||||
/* Nothing found. */
|
||||
break;
|
||||
}
|
||||
if ((fd = socket(addr->ai_family, addr->ai_socktype,
|
||||
addr->ai_protocol)) < 0)
|
||||
|
||||
if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errcode_for_socket_access(),
|
||||
@@ -276,8 +282,6 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!IS_AF_UNIX(addr->ai_family))
|
||||
{
|
||||
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
@@ -363,12 +367,11 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
added++;
|
||||
}
|
||||
|
||||
freeaddrinfo(addrs);
|
||||
freeaddrinfo_all(hint.ai_family, addrs);
|
||||
|
||||
if (!added)
|
||||
{
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user