Skip to content

Commit b7a4243

Browse files
committed
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names (instead of IP address ranges) failed to complain if reverse DNS lookup failed; instead it silently didn't match, so that you might end up getting a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518 from Mike Blackwell. Since we don't want to make this a fatal error in situations where pg_hba.conf contains a mixture of host names and IP addresses (clients matching one of the numeric entries should not have to have rDNS data), remember the lookup failure and mention it as DETAIL if we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS lookup failures, too, rather than treating them as immediate hard errors. Along the way, fix a couple of bugs that prevented us from detecting an rDNS lookup error reliably, and make sure that we make only one rDNS lookup attempt; formerly, if the lookup attempt failed, the code would try again for each host name entry in pg_hba.conf. Since more or less the whole point of this design is to ensure there's only one lookup attempt not one per entry, the latter point represents a performance bug that seems sufficient justification for back-patching. Also, adjust src/port/getaddrinfo.c so that it plays as well as it can with this code. Which is not all that well, since it does not have actual support for rDNS lookup, but at least it should return the expected (and required by spec) error codes so that the main code correctly perceives the lack of functionality as a lookup failure. It's unlikely that PG is still being used in production on any machines that require our getaddrinfo.c, so I'm not excited about working harder than this. To keep the code in the various branches similar, this includes back-patching commits c424d0d and 1997f34 into 9.2 and earlier. Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was introduced.
1 parent 2b52069 commit b7a4243

File tree

7 files changed

+94
-55
lines changed

7 files changed

+94
-55
lines changed

src/backend/libpq/auth.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -444,15 +444,25 @@ ClientAuthentication(Port *port)
444444
NI_NUMERICHOST);
445445

446446
#define HOSTNAME_LOOKUP_DETAIL(port) \
447-
(port->remote_hostname \
448-
? (port->remote_hostname_resolv == +1 \
449-
? errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", port->remote_hostname) \
450-
: (port->remote_hostname_resolv == 0 \
451-
? errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", port->remote_hostname) \
452-
: (port->remote_hostname_resolv == -1 \
453-
? errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", port->remote_hostname) \
454-
: 0))) \
455-
: 0)
447+
(port->remote_hostname ? \
448+
(port->remote_hostname_resolv == +1 ? \
449+
errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", \
450+
port->remote_hostname) : \
451+
port->remote_hostname_resolv == 0 ? \
452+
errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", \
453+
port->remote_hostname) : \
454+
port->remote_hostname_resolv == -1 ? \
455+
errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", \
456+
port->remote_hostname) : \
457+
port->remote_hostname_resolv == -2 ? \
458+
errdetail_log("Could not translate client host name \"%s\" to IP address: %s.", \
459+
port->remote_hostname, \
460+
gai_strerror(port->remote_hostname_errcode)) : \
461+
0) \
462+
: (port->remote_hostname_resolv == -2 ? \
463+
errdetail_log("Could not resolve client IP address to a host name: %s.", \
464+
gai_strerror(port->remote_hostname_errcode)) : \
465+
0))
456466

457467
if (am_walsender)
458468
{

src/backend/libpq/hba.c

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -598,35 +598,47 @@ check_hostname(hbaPort *port, const char *hostname)
598598
int ret;
599599
bool found;
600600

601+
/* Quick out if remote host name already known bad */
602+
if (port->remote_hostname_resolv < 0)
603+
return false;
604+
601605
/* Lookup remote host name if not already done */
602606
if (!port->remote_hostname)
603607
{
604608
char remote_hostname[NI_MAXHOST];
605609

606-
if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
607-
remote_hostname, sizeof(remote_hostname),
608-
NULL, 0,
609-
0))
610+
ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
611+
remote_hostname, sizeof(remote_hostname),
612+
NULL, 0,
613+
NI_NAMEREQD);
614+
if (ret != 0)
615+
{
616+
/* remember failure; don't complain in the postmaster log yet */
617+
port->remote_hostname_resolv = -2;
618+
port->remote_hostname_errcode = ret;
610619
return false;
620+
}
611621

612622
port->remote_hostname = pstrdup(remote_hostname);
613623
}
614624

625+
/* Now see if remote host name matches this pg_hba line */
615626
if (!hostname_match(hostname, port->remote_hostname))
616627
return false;
617628

618-
/* Lookup IP from host name and check against original IP */
619-
629+
/* If we already verified the forward lookup, we're done */
620630
if (port->remote_hostname_resolv == +1)
621631
return true;
622-
if (port->remote_hostname_resolv == -1)
623-
return false;
624632

633+
/* Lookup IP from host name and check against original IP */
625634
ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
626635
if (ret != 0)
627-
ereport(ERROR,
628-
(errmsg("could not translate host name \"%s\" to address: %s",
629-
port->remote_hostname, gai_strerror(ret))));
636+
{
637+
/* remember failure; don't complain in the postmaster log yet */
638+
port->remote_hostname_resolv = -2;
639+
port->remote_hostname_errcode = ret;
640+
return false;
641+
}
630642

631643
found = false;
632644
for (gai = gai_result; gai; gai = gai->ai_next)

src/backend/libpq/ip.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,6 @@ getnameinfo_unix(const struct sockaddr_un * sa, int salen,
247247
(node == NULL && service == NULL))
248248
return EAI_FAIL;
249249

250-
/* We don't support those. */
251-
if ((node && !(flags & NI_NUMERICHOST))
252-
|| (service && !(flags & NI_NUMERICSERV)))
253-
return EAI_FAIL;
254-
255250
if (node)
256251
{
257252
ret = snprintf(node, nodelen, "%s", "[local]");

src/backend/postmaster/postmaster.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3379,6 +3379,7 @@ static void
33793379
BackendInitialize(Port *port)
33803380
{
33813381
int status;
3382+
int ret;
33823383
char remote_host[NI_MAXHOST];
33833384
char remote_port[NI_MAXSERV];
33843385
char remote_ps_data[NI_MAXHOST];
@@ -3440,21 +3441,13 @@ BackendInitialize(Port *port)
34403441
*/
34413442
remote_host[0] = '\0';
34423443
remote_port[0] = '\0';
3443-
if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
3444+
if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
34443445
remote_host, sizeof(remote_host),
34453446
remote_port, sizeof(remote_port),
3446-
(log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV))
3447-
{
3448-
int ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
3449-
remote_host, sizeof(remote_host),
3450-
remote_port, sizeof(remote_port),
3451-
NI_NUMERICHOST | NI_NUMERICSERV);
3452-
3453-
if (ret)
3454-
ereport(WARNING,
3455-
(errmsg_internal("pg_getnameinfo_all() failed: %s",
3456-
gai_strerror(ret))));
3457-
}
3447+
(log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
3448+
ereport(WARNING,
3449+
(errmsg_internal("pg_getnameinfo_all() failed: %s",
3450+
gai_strerror(ret))));
34583451
if (remote_port[0] == '\0')
34593452
snprintf(remote_ps_data, sizeof(remote_ps_data), "%s", remote_host);
34603453
else
@@ -3478,8 +3471,23 @@ BackendInitialize(Port *port)
34783471
*/
34793472
port->remote_host = strdup(remote_host);
34803473
port->remote_port = strdup(remote_port);
3481-
if (log_hostname)
3482-
port->remote_hostname = port->remote_host;
3474+
3475+
/*
3476+
* If we did a reverse lookup to name, we might as well save the results
3477+
* rather than possibly repeating the lookup during authentication.
3478+
*
3479+
* Note that we don't want to specify NI_NAMEREQD above, because then we'd
3480+
* get nothing useful for a client without an rDNS entry. Therefore, we
3481+
* must check whether we got a numeric IPv4 or IPv6 address, and not save
3482+
* it into remote_hostname if so. (This test is conservative and might
3483+
* sometimes classify a hostname as numeric, but an error in that
3484+
* direction is safe; it only results in a possible extra lookup.)
3485+
*/
3486+
if (log_hostname &&
3487+
ret == 0 &&
3488+
strspn(remote_host, "0123456789.") < strlen(remote_host) &&
3489+
strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
3490+
port->remote_hostname = strdup(remote_host);
34833491

34843492
/*
34853493
* Ready to begin client interaction. We will give up and exit(1) after a

src/include/getaddrinfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@
8282
#ifndef NI_NUMERICSERV
8383
#define NI_NUMERICSERV 2
8484
#endif
85+
#ifndef NI_NAMEREQD
86+
#define NI_NAMEREQD 4
87+
#endif
8588

8689
#ifndef NI_MAXHOST
8790
#define NI_MAXHOST 1025

src/include/libpq/libpq-be.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,20 @@ typedef struct
9999
* still available when a backend is running (see MyProcPort). The data
100100
* it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
101101
* so that it survives into PostgresMain execution!
102+
*
103+
* remote_hostname is set if we did a successful reverse lookup of the
104+
* client's IP address during connection setup.
105+
* remote_hostname_resolv tracks the state of hostname verification:
106+
* +1 = remote_hostname is known to resolve to client's IP address
107+
* -1 = remote_hostname is known NOT to resolve to client's IP address
108+
* 0 = we have not done the forward DNS lookup yet
109+
* -2 = there was an error in name resolution
110+
* If reverse lookup of the client IP address fails, remote_hostname will be
111+
* left NULL while remote_hostname_resolv is set to -2. If reverse lookup
112+
* succeeds but forward lookup fails, remote_hostname_resolv is also set to -2
113+
* (the case is distinguishable because remote_hostname isn't NULL). In
114+
* either of the -2 cases, remote_hostname_errcode saves the lookup return
115+
* code for possible later use with gai_strerror.
102116
*/
103117

104118
typedef struct Port
@@ -111,12 +125,7 @@ typedef struct Port
111125
char *remote_host; /* name (or ip addr) of remote host */
112126
char *remote_hostname;/* name (not ip addr) of remote host, if
113127
* available */
114-
int remote_hostname_resolv; /* +1 = remote_hostname is known to
115-
* resolve to client's IP address; -1
116-
* = remote_hostname is known NOT to
117-
* resolve to client's IP address; 0 =
118-
* we have not done the forward DNS
119-
* lookup yet */
128+
int remote_hostname_resolv; /* see above */
120129
char *remote_port; /* text rep of remote port */
121130
CAC_state canAcceptConnections; /* postmaster connection status */
122131

@@ -178,6 +187,9 @@ typedef struct Port
178187
char *peer_cn;
179188
unsigned long count;
180189
#endif
190+
191+
/* This field will be in a saner place in 9.4 and up */
192+
int remote_hostname_errcode; /* see above */
181193
} Port;
182194

183195

src/port/getaddrinfo.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ getaddrinfo(const char *node, const char *service,
182182
else if (hints.ai_flags & AI_NUMERICHOST)
183183
{
184184
if (!inet_aton(node, &sin.sin_addr))
185-
return EAI_FAIL;
185+
return EAI_NONAME;
186186
}
187187
else
188188
{
@@ -351,8 +351,8 @@ gai_strerror(int errcode)
351351
/*
352352
* Convert an ipv4 address to a hostname.
353353
*
354-
* Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV
355-
* It will never resolv a hostname.
354+
* Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior.
355+
* It will never resolve a hostname.
356356
* - No IPv6 support.
357357
*/
358358
int
@@ -375,16 +375,15 @@ getnameinfo(const struct sockaddr * sa, int salen,
375375
if (sa == NULL || (node == NULL && service == NULL))
376376
return EAI_FAIL;
377377

378-
/* We don't support those. */
379-
if ((node && !(flags & NI_NUMERICHOST))
380-
|| (service && !(flags & NI_NUMERICSERV)))
381-
return EAI_FAIL;
382-
383378
#ifdef HAVE_IPV6
384379
if (sa->sa_family == AF_INET6)
385380
return EAI_FAMILY;
386381
#endif
387382

383+
/* Unsupported flags. */
384+
if (flags & NI_NAMEREQD)
385+
return EAI_AGAIN;
386+
388387
if (node)
389388
{
390389
if (sa->sa_family == AF_INET)
@@ -407,7 +406,7 @@ getnameinfo(const struct sockaddr * sa, int salen,
407406
ret = snprintf(service, servicelen, "%d",
408407
ntohs(((struct sockaddr_in *) sa)->sin_port));
409408
}
410-
if (ret == -1 || ret > servicelen)
409+
if (ret == -1 || ret >= servicelen)
411410
return EAI_MEMORY;
412411
}
413412

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy