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/postmaster/postmaster.c19
-rw-r--r--src/include/getaddrinfo.h3
-rw-r--r--src/include/libpq/libpq-be.h22
-rw-r--r--src/port/getaddrinfo.c12
6 files changed, 86 insertions, 32 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 31ade0bdbe4..d062c1d8cef 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -425,15 +425,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 77434f410ae..83dd1474081 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -592,35 +592,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/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e9072b76efc..7a2c45af382 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3952,8 +3952,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 6192d1fe895..7995235d9fa 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 270e8fbb14b..dbf3a20ed91 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -104,6 +104,20 @@ extern int ssl_renegotiation_limit;
* 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
@@ -116,12 +130,8 @@ 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 */
+ int remote_hostname_errcode; /* see above */
char *remote_port; /* text rep of remote port */
CAC_state canAcceptConnections; /* postmaster connection status */
diff --git a/src/port/getaddrinfo.c b/src/port/getaddrinfo.c
index 52a20c5c2cc..7880ad8a16e 100644
--- a/src/port/getaddrinfo.c
+++ b/src/port/getaddrinfo.c
@@ -181,7 +181,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
{
@@ -347,8 +347,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
@@ -375,6 +375,10 @@ getnameinfo(const struct sockaddr * sa, int salen,
return EAI_FAMILY;
#endif
+ /* Unsupported flags. */
+ if (flags & NI_NAMEREQD)
+ return EAI_AGAIN;
+
if (node)
{
if (sa->sa_family == AF_INET)
@@ -397,7 +401,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;
}