aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/auth.c28
-rw-r--r--src/backend/libpq/hba.c34
-rw-r--r--src/backend/libpq/ip.c5
-rw-r--r--src/backend/postmaster/postmaster.c38
-rw-r--r--src/include/getaddrinfo.h3
-rw-r--r--src/include/libpq/libpq-be.h24
-rw-r--r--src/port/getaddrinfo.c17
7 files changed, 94 insertions, 55 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 9cdee2bb3e7..c65427e53c4 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -440,15 +440,25 @@ ClientAuthentication(Port *port)
NI_NUMERICHOST);
#define HOSTNAME_LOOKUP_DETAIL(port) \
- (port->remote_hostname \
- ? (port->remote_hostname_resolv == +1 \
- ? errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", port->remote_hostname) \
- : (port->remote_hostname_resolv == 0 \
- ? errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", port->remote_hostname) \
- : (port->remote_hostname_resolv == -1 \
- ? errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", port->remote_hostname) \
- : 0))) \
- : 0)
+ (port->remote_hostname ? \
+ (port->remote_hostname_resolv == +1 ? \
+ errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", \
+ port->remote_hostname) : \
+ port->remote_hostname_resolv == 0 ? \
+ errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", \
+ port->remote_hostname) : \
+ port->remote_hostname_resolv == -1 ? \
+ errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", \
+ port->remote_hostname) : \
+ port->remote_hostname_resolv == -2 ? \
+ errdetail_log("Could not translate client host name \"%s\" to IP address: %s.", \
+ port->remote_hostname, \
+ gai_strerror(port->remote_hostname_errcode)) : \
+ 0) \
+ : (port->remote_hostname_resolv == -2 ? \
+ errdetail_log("Could not resolve client IP address to a host name: %s.", \
+ gai_strerror(port->remote_hostname_errcode)) : \
+ 0))
if (am_walsender)
{
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 828f6dcc8e1..09e8715c798 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -565,35 +565,47 @@ check_hostname(hbaPort *port, const char *hostname)
int ret;
bool found;
+ /* Quick out if remote host name already known bad */
+ if (port->remote_hostname_resolv < 0)
+ return false;
+
/* Lookup remote host name if not already done */
if (!port->remote_hostname)
{
char remote_hostname[NI_MAXHOST];
- if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
- remote_hostname, sizeof(remote_hostname),
- NULL, 0,
- 0) != 0)
+ ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
+ remote_hostname, sizeof(remote_hostname),
+ NULL, 0,
+ NI_NAMEREQD);
+ if (ret != 0)
+ {
+ /* remember failure; don't complain in the postmaster log yet */
+ port->remote_hostname_resolv = -2;
+ port->remote_hostname_errcode = ret;
return false;
+ }
port->remote_hostname = pstrdup(remote_hostname);
}
+ /* Now see if remote host name matches this pg_hba line */
if (!hostname_match(hostname, port->remote_hostname))
return false;
- /* Lookup IP from host name and check against original IP */
-
+ /* If we already verified the forward lookup, we're done */
if (port->remote_hostname_resolv == +1)
return true;
- if (port->remote_hostname_resolv == -1)
- return false;
+ /* Lookup IP from host name and check against original IP */
ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
if (ret != 0)
- ereport(ERROR,
- (errmsg("could not translate host name \"%s\" to address: %s",
- port->remote_hostname, gai_strerror(ret))));
+ {
+ /* remember failure; don't complain in the postmaster log yet */
+ port->remote_hostname_resolv = -2;
+ port->remote_hostname_errcode = ret;
+ return false;
+ }
found = false;
for (gai = gai_result; gai; gai = gai->ai_next)
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
index 550e11b68cf..db3a5252efd 100644
--- a/src/backend/libpq/ip.c
+++ b/src/backend/libpq/ip.c
@@ -247,11 +247,6 @@ getnameinfo_unix(const struct sockaddr_un * sa, int salen,
(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", "[local]");
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index b96b505834a..95640622bc1 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3381,6 +3381,7 @@ static void
BackendInitialize(Port *port)
{
int status;
+ int ret;
char remote_host[NI_MAXHOST];
char remote_port[NI_MAXSERV];
char remote_ps_data[NI_MAXHOST];
@@ -3442,21 +3443,13 @@ BackendInitialize(Port *port)
*/
remote_host[0] = '\0';
remote_port[0] = '\0';
- if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
+ if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
remote_host, sizeof(remote_host),
remote_port, sizeof(remote_port),
- (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV) != 0)
- {
- int ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
- remote_host, sizeof(remote_host),
- remote_port, sizeof(remote_port),
- NI_NUMERICHOST | NI_NUMERICSERV);
-
- if (ret != 0)
- ereport(WARNING,
- (errmsg_internal("pg_getnameinfo_all() failed: %s",
- gai_strerror(ret))));
- }
+ (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
+ ereport(WARNING,
+ (errmsg_internal("pg_getnameinfo_all() failed: %s",
+ gai_strerror(ret))));
if (remote_port[0] == '\0')
snprintf(remote_ps_data, sizeof(remote_ps_data), "%s", remote_host);
else
@@ -3480,8 +3473,23 @@ BackendInitialize(Port *port)
*/
port->remote_host = strdup(remote_host);
port->remote_port = strdup(remote_port);
- if (log_hostname)
- port->remote_hostname = port->remote_host;
+
+ /*
+ * If we did a reverse lookup to name, we might as well save the results
+ * rather than possibly repeating the lookup during authentication.
+ *
+ * Note that we don't want to specify NI_NAMEREQD above, because then we'd
+ * get nothing useful for a client without an rDNS entry. Therefore, we
+ * must check whether we got a numeric IPv4 or IPv6 address, and not save
+ * it into remote_hostname if so. (This test is conservative and might
+ * sometimes classify a hostname as numeric, but an error in that
+ * direction is safe; it only results in a possible extra lookup.)
+ */
+ if (log_hostname &&
+ ret == 0 &&
+ strspn(remote_host, "0123456789.") < strlen(remote_host) &&
+ strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
+ port->remote_hostname = strdup(remote_host);
/*
* Ready to begin client interaction. We will give up and exit(1) after a
diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h
index 519a97975ef..9adceb4575f 100644
--- a/src/include/getaddrinfo.h
+++ b/src/include/getaddrinfo.h
@@ -82,6 +82,9 @@
#ifndef NI_NUMERICSERV
#define NI_NUMERICSERV 2
#endif
+#ifndef NI_NAMEREQD
+#define NI_NAMEREQD 4
+#endif
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 4d92c18974b..95b538c64db 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -99,6 +99,20 @@ typedef struct
* still available when a backend is running (see MyProcPort). The data
* it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
* so that it survives into PostgresMain execution!
+ *
+ * remote_hostname is set if we did a successful reverse lookup of the
+ * client's IP address during connection setup.
+ * remote_hostname_resolv tracks the state of hostname verification:
+ * +1 = remote_hostname is known to resolve to client's IP address
+ * -1 = remote_hostname is known NOT to resolve to client's IP address
+ * 0 = we have not done the forward DNS lookup yet
+ * -2 = there was an error in name resolution
+ * If reverse lookup of the client IP address fails, remote_hostname will be
+ * left NULL while remote_hostname_resolv is set to -2. If reverse lookup
+ * succeeds but forward lookup fails, remote_hostname_resolv is also set to -2
+ * (the case is distinguishable because remote_hostname isn't NULL). In
+ * either of the -2 cases, remote_hostname_errcode saves the lookup return
+ * code for possible later use with gai_strerror.
*/
typedef struct Port
@@ -111,12 +125,7 @@ typedef struct Port
char *remote_host; /* name (or ip addr) of remote host */
char *remote_hostname;/* name (not ip addr) of remote host, if
* available */
- int remote_hostname_resolv; /* +1 = remote_hostname is known to
- * resolve to client's IP address; -1
- * = remote_hostname is known NOT to
- * resolve to client's IP address; 0 =
- * we have not done the forward DNS
- * lookup yet */
+ int remote_hostname_resolv; /* see above */
char *remote_port; /* text rep of remote port */
CAC_state canAcceptConnections; /* postmaster connection status */
@@ -178,6 +187,9 @@ typedef struct Port
char *peer_cn;
unsigned long count;
#endif
+
+ /* This field will be in a saner place in 9.4 and up */
+ int remote_hostname_errcode; /* see above */
} Port;
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
index c117012ec7e..3d23ffecaa3 100644
--- a/src/port/getaddrinfo.c
+++ b/src/port/getaddrinfo.c
@@ -182,7 +182,7 @@ getaddrinfo(const char *node, const char *service,
else if (hints.ai_flags & AI_NUMERICHOST)
{
if (!inet_aton(node, &sin.sin_addr))
- return EAI_FAIL;
+ return EAI_NONAME;
}
else
{
@@ -349,8 +349,8 @@ gai_strerror(int errcode)
/*
* Convert an ipv4 address to a hostname.
*
- * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
- * It will never resolv a hostname.
+ * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
+ * It will never resolve a hostname.
* - No IPv6 support.
*/
int
@@ -373,16 +373,15 @@ getnameinfo(const struct sockaddr * sa, int salen,
if (sa == NULL || (node == NULL && service == NULL))
return EAI_FAIL;
- /* We don't support those. */
- if ((node && !(flags & NI_NUMERICHOST))
- || (service && !(flags & NI_NUMERICSERV)))
- return EAI_FAIL;
-
#ifdef HAVE_IPV6
if (sa->sa_family == AF_INET6)
return EAI_FAMILY;
#endif
+ /* Unsupported flags. */
+ if (flags & NI_NAMEREQD)
+ return EAI_AGAIN;
+
if (node)
{
if (sa->sa_family == AF_INET)
@@ -405,7 +404,7 @@ getnameinfo(const struct sockaddr * sa, int salen,
ret = snprintf(service, servicelen, "%d",
ntohs(((struct sockaddr_in *) sa)->sin_port));
}
- if (ret == -1 || ret > servicelen)
+ if (ret == -1 || ret >= servicelen)
return EAI_MEMORY;
}