hba-hostnames.patch
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| doc/src/sgml/client-auth.sgml | 47 | 21 |
| src/backend/libpq/hba.c | 114 | 9 |
| src/backend/libpq/pg_hba.conf.sample | 8 | 9 |
| src/backend/postmaster/postmaster.c | 2 | 0 |
| src/include/libpq/hba.h | 1 | 0 |
| src/include/libpq/libpq-be.h | 1 | 0 |
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index e8995f9..808c468 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -101,9 +101,9 @@
A record can have one of the seven formats
<synopsis>
local <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
-host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
-hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
-hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
+host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>address</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
+hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>address</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
+hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>address</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
@@ -218,12 +218,17 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</varlistentry>
<varlistentry>
- <term><replaceable>CIDR-address</replaceable></term>
+ <term><replaceable>address</replaceable></term>
<listitem>
<para>
Specifies the client machine IP address range that this record
- matches. This field contains an IP address in standard dotted decimal
- notation and a <acronym>CIDR</> mask length. (IP addresses can only be
+ matches. This field can contain either a host name, an IP
+ address range, one of the special key words mentioned below.
+ </para>
+
+ <para>
+ An IP address is specified in standard dotted decimal
+ notation with a <acronym>CIDR</> mask length. (IP addresses can only be
specified numerically, not as domain or host names.) The mask
length indicates the number of high-order bits of the client
IP address that must match. Bits to the right of this must
@@ -233,14 +238,7 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</para>
<para>
- Instead of a <replaceable>CIDR-address</replaceable>, you can write
- <literal>samehost</literal> to match any of the server's own IP
- addresses, or <literal>samenet</literal> to match any address in any
- subnet that the server is directly connected to.
- </para>
-
- <para>
- Typical examples of a <replaceable>CIDR-address</replaceable> are
+ Typical examples of an IP address range specified this way are
<literal>172.20.143.89/32</literal> for a single host, or
<literal>172.20.143.0/24</literal> for a small network, or
<literal>10.6.0.0/16</literal> for a larger one.
@@ -260,6 +258,24 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</para>
<para>
+ You can also write
+ <literal>samehost</literal> to match any of the server's own IP
+ addresses, or <literal>samenet</literal> to match any address in any
+ subnet that the server is directly connected to.
+ </para>
+
+ <para>
+ If a host name is specified (anything that is not an IP address
+ or a special key word is processed as a potential host name), a
+ reverse DNS lookup is performed on the client's IP address,
+ then a forward DNS lookup on the resulting name to check if it
+ matches the original IP address (that is, at least one of the
+ potentially many IP addresses matches the original one), and
+ the name found in the reverse lookup is compared with the
+ specified host name.
+ </para>
+
+ <para>
This field only applies to <literal>host</literal>,
<literal>hostssl</literal>, and <literal>hostnossl</> records.
</para>
@@ -511,12 +527,12 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
# any database user name using Unix-domain sockets (the default for local
# connections).
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
local all all trust
# The same using local loopback TCP/IP connections.
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
host all all 127.0.0.1/32 trust
# The same as the previous line, but using a separate netmask column
@@ -524,17 +540,27 @@ host all all 127.0.0.1/32 trust
# TYPE DATABASE USER IP-ADDRESS IP-MASK METHOD
host all all 127.0.0.1 255.255.255.255 trust
+# The same over IPv6.
+#
+# TYPE DATABASE USER ADDRESS METHOD
+host all all ::1/128 trust
+
+# The same using a host name (would typically cover both IPv4 and IPv6).
+#
+# TYPE DATABASE USER ADDRESS METHOD
+host all all localhost trust
+
# Allow any user from any host with IP address 192.168.93.x to connect
# to database "postgres" as the same user name that ident reports for
# the connection (typically the operating system user name).
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
host postgres all 192.168.93.0/24 ident
# Allow any user from host 192.168.12.10 to connect to database
# "postgres" if the user's password is correctly supplied.
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
host postgres all 192.168.12.10/32 md5
# In the absence of preceding "host" lines, these two lines will
@@ -543,7 +569,7 @@ host postgres all 192.168.12.10/32 md5
# on the Internet. The zero mask causes no bits of the host IP
# address to be considered, so it matches any host.
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
host all all 192.168.54.1/32 reject
host all all 0.0.0.0/0 krb5
@@ -553,7 +579,7 @@ host all all 0.0.0.0/0 krb5
# connection is allowed if there is an entry in pg_ident.conf for map
# "omicron" that says "bryanh" is allowed to connect as "guest1".
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
host all all 192.168.0.0/16 ident map=omicron
# If these are the only three lines for local connections, they will
@@ -563,7 +589,7 @@ host all all 192.168.0.0/16 ident map=omicro
# $PGDATA/admins contains a list of names of administrators. Passwords
# are required in all cases.
#
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
local sameuser all md5
local all @admins md5
local all +support md5
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index aec12b0..b2ff30d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -540,6 +540,99 @@ check_db(const char *dbname, const char *role, Oid roleid, char *param_str)
return false;
}
+static bool
+ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
+{
+ return (a->sin_addr.s_addr == b->sin_addr.s_addr);
+}
+
+static bool
+ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
+ return false;
+
+ return true;
+}
+
+/*
+ * Check to see if a connecting IP matches a given host name.
+ */
+static bool
+check_hostname(hbaPort *port, const char *hostname)
+{
+ struct addrinfo *gai_result, *gai;
+ int ret;
+ bool found;
+
+ /* 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))
+ return false;
+
+ port->remote_hostname = strdup(remote_hostname);
+ }
+
+ if (strcmp(port->remote_hostname, hostname) != 0)
+ 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,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("getaddrinfo failed on \"%s\": %s",
+ port->remote_hostname, gai_strerror(ret))));
+
+ found = false;
+ for (gai = gai_result; gai; gai = gai->ai_next)
+ {
+ char hostinfo[NI_MAXHOST];
+
+ getnameinfo(gai->ai_addr, gai->ai_addrlen,
+ hostinfo, sizeof(hostinfo),
+ NULL, 0,
+ NI_NUMERICHOST);
+
+ if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
+ {
+ if (gai->ai_addr->sa_family == AF_INET)
+ {
+ if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
+ (struct sockaddr_in *) &port->raddr.addr))
+ {
+ found = true;
+ break;
+ }
+ }
+ else if (gai->ai_addr->sa_family == AF_INET6)
+ {
+ if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
+ (struct sockaddr_in6 *) &port->raddr.addr))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (gai_result)
+ freeaddrinfo(gai_result);
+
+ return found;
+}
+
/*
* Check to see if a connecting IP matches the given address and netmask.
*/
@@ -816,7 +909,12 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
hints.ai_next = NULL;
ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
- if (ret || !gai_result)
+ if (ret == 0 && gai_result)
+ memcpy(&parsedline->addr, gai_result->ai_addr,
+ gai_result->ai_addrlen);
+ else if (ret == EAI_NONAME)
+ parsedline->hostname = token;
+ else
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
@@ -830,12 +928,10 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
return false;
}
- memcpy(&parsedline->addr, gai_result->ai_addr,
- gai_result->ai_addrlen);
pg_freeaddrinfo_all(hints.ai_family, gai_result);
/* Get the netmask */
- if (cidr_slash)
+ if (!parsedline->hostname && cidr_slash)
{
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
parsedline->addr.ss_family) < 0)
@@ -852,7 +948,7 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
}
pfree(token);
}
- else
+ else if (!parsedline->hostname)
{
/* Read the mask field. */
pfree(token);
@@ -1369,10 +1465,19 @@ check_hba(hbaPort *port)
switch (hba->ip_cmp_method)
{
case ipCmpMask:
- if (!check_ip(&port->raddr,
- (struct sockaddr *) & hba->addr,
- (struct sockaddr *) & hba->mask))
- continue;
+ if (hba->hostname)
+ {
+ if (!check_hostname(port,
+ hba->hostname))
+ continue;
+ }
+ else
+ {
+ if (!check_ip(&port->raddr,
+ (struct sockaddr *) & hba->addr,
+ (struct sockaddr *) & hba->mask))
+ continue;
+ }
break;
case ipCmpSameHost:
case ipCmpSameNet:
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index e1017cf..65842ea 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -10,9 +10,9 @@
# databases they can access. Records take one of these forms:
#
# local DATABASE USER METHOD [OPTIONS]
-# host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
-# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
-# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
+# host DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostssl DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS]
#
# (The uppercase items must be replaced by actual values.)
#
@@ -29,7 +29,8 @@
# you can also write a file name prefixed with "@" to include names
# from a separate file.
#
-# CIDR-ADDRESS specifies the set of hosts the record matches. It is
+# ADDRESS specifies the set of hosts the record matches. It can be a
+# host name, or it is
# made up of an IP address and a CIDR mask that is an integer (between
# 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies the number
# of significant bits in the mask. Alternatively, you can write an IP
@@ -70,11 +71,9 @@
@authcomment@
-# TYPE DATABASE USER CIDR-ADDRESS METHOD
+# TYPE DATABASE USER ADDRESS METHOD
@remove-line-for-nolocal@# "local" is for Unix domain socket connections only
@remove-line-for-nolocal@local all all @authmethod@
-# IPv4 local connections:
-host all all 127.0.0.1/32 @authmethod@
-# IPv6 local connections:
-host all all ::1/128 @authmethod@
+# IPv4/6 local connections:
+host all all localhost @authmethod@
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index db61569..83182ac 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3407,6 +3407,8 @@ BackendInitialize(Port *port)
*/
port->remote_host = strdup(remote_host);
port->remote_port = strdup(remote_port);
+ if (log_hostname)
+ port->remote_hostname = port->remote_host;
/*
* Ready to begin client interaction. We will give up and exit(1) after a
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index da3a2a3..97686ab 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -56,6 +56,7 @@ typedef struct
struct sockaddr_storage addr;
struct sockaddr_storage mask;
IPCompareMethod ip_cmp_method;
+ char *hostname;
UserAuth auth_method;
char *usermap;
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 0a80f74..e364ff0 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -109,6 +109,7 @@ typedef struct Port
SockAddr laddr; /* local addr (postmaster) */
SockAddr raddr; /* remote addr (client) */
char *remote_host; /* name (or ip addr) of remote host */
+ char *remote_hostname; /* name (not ip addr) of remote host, if available */
char *remote_port; /* text rep of remote port */
CAC_state canAcceptConnections; /* postmaster connection status */