Commit 313f56ce authored by Alvaro Herrera's avatar Alvaro Herrera

Tweak libpq's PQhost, PQhostaddr, and psql's \connect

Fixes some problems introduced by 6e5f8d48:

* When reusing conninfo data from the previous connection in \connect,
  the host address should only be reused if it was specified as
  hostaddr; if it wasn't, then 'host' is resolved afresh.  We were
  reusing the same IP address, which ignores a possible DNS change
  as well as any other addresses that the name resolves to than the
  one that was used in the original connection.

* PQhost, PQhostaddr: Don't present user-specified hostaddr when we have
  an inet_net_ntop-produced equivalent address.  The latter has been
  put in canonical format, which is cleaner (so it produces "127.0.0.1"
  when given "host=2130706433", for example).

* Document the hostaddr-reusing aspect of \connect.

* Fix some code comments

Author: Fabien Coelho
Reported-by: Noah Misch
Discussion: https://postgr.es/m/20190527203713.GA58392@gust.leadboat.com
parent 3da73d68
...@@ -911,6 +911,9 @@ testdb=> ...@@ -911,6 +911,9 @@ testdb=>
<replaceable class="parameter">host</replaceable> or <replaceable class="parameter">host</replaceable> or
<replaceable class="parameter">port</replaceable> <replaceable class="parameter">port</replaceable>
as <literal>-</literal> is equivalent to omitting that parameter. as <literal>-</literal> is equivalent to omitting that parameter.
If <literal>hostaddr</literal> was specified in the original
connection's <structname>conninfo</structname>, that address is reused
for the new connection (disregarding any other host specification).
</para> </para>
<para> <para>
......
...@@ -2870,6 +2870,26 @@ param_is_newly_set(const char *old_val, const char *new_val) ...@@ -2870,6 +2870,26 @@ param_is_newly_set(const char *old_val, const char *new_val)
return false; return false;
} }
/* return whether the connection has 'hostaddr' in its conninfo */
static bool
has_hostaddr(PGconn *conn)
{
bool used = false;
PQconninfoOption *ciopt = PQconninfo(conn);
for (PQconninfoOption *p = ciopt; p->keyword != NULL; p++)
{
if (strcmp(p->keyword, "hostaddr") == 0 && p->val != NULL)
{
used = true;
break;
}
}
PQconninfoFree(ciopt);
return used;
}
/* /*
* do_connect -- handler for \connect * do_connect -- handler for \connect
* *
...@@ -2929,24 +2949,24 @@ do_connect(enum trivalue reuse_previous_specification, ...@@ -2929,24 +2949,24 @@ do_connect(enum trivalue reuse_previous_specification,
port = NULL; port = NULL;
} }
/* grab missing values from the old connection */ /*
* Grab missing values from the old connection. If we grab host (or host
* is the same as before) and hostaddr was set, grab that too.
*/
if (reuse_previous) if (reuse_previous)
{ {
if (!user) if (!user)
user = PQuser(o_conn); user = PQuser(o_conn);
if (host && strcmp(host, PQhost(o_conn)) == 0) if (host && strcmp(host, PQhost(o_conn)) == 0 &&
has_hostaddr(o_conn))
{ {
/*
* if we are targeting the same host, reuse its hostaddr for
* consistency
*/
hostaddr = PQhostaddr(o_conn); hostaddr = PQhostaddr(o_conn);
} }
if (!host) if (!host)
{ {
host = PQhost(o_conn); host = PQhost(o_conn);
/* also set hostaddr for consistency */ if (has_hostaddr(o_conn))
hostaddr = PQhostaddr(o_conn); hostaddr = PQhostaddr(o_conn);
} }
if (!port) if (!port)
port = PQport(o_conn); port = PQport(o_conn);
...@@ -3129,7 +3149,10 @@ do_connect(enum trivalue reuse_previous_specification, ...@@ -3129,7 +3149,10 @@ do_connect(enum trivalue reuse_previous_specification,
char *host = PQhost(pset.db); char *host = PQhost(pset.db);
char *hostaddr = PQhostaddr(pset.db); char *hostaddr = PQhostaddr(pset.db);
/* If the host is an absolute path, the connection is via socket */ /*
* If the host is an absolute path, the connection is via socket
* unless overridden by hostaddr
*/
if (is_absolute_path(host)) if (is_absolute_path(host))
{ {
if (hostaddr && *hostaddr) if (hostaddr && *hostaddr)
......
...@@ -1536,9 +1536,7 @@ getHostaddr(PGconn *conn, char *host_addr, int host_addr_len) ...@@ -1536,9 +1536,7 @@ getHostaddr(PGconn *conn, char *host_addr, int host_addr_len)
{ {
struct sockaddr_storage *addr = &conn->raddr.addr; struct sockaddr_storage *addr = &conn->raddr.addr;
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) if (addr->ss_family == AF_INET)
strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, host_addr_len);
else if (addr->ss_family == AF_INET)
{ {
if (inet_net_ntop(AF_INET, if (inet_net_ntop(AF_INET,
&((struct sockaddr_in *) addr)->sin_addr.s_addr, &((struct sockaddr_in *) addr)->sin_addr.s_addr,
...@@ -6463,6 +6461,10 @@ PQhost(const PGconn *conn) ...@@ -6463,6 +6461,10 @@ PQhost(const PGconn *conn)
if (conn->connhost != NULL) if (conn->connhost != NULL)
{ {
/*
* Return the verbatim host value provided by user, or hostaddr in its
* lack.
*/
if (conn->connhost[conn->whichhost].host != NULL && if (conn->connhost[conn->whichhost].host != NULL &&
conn->connhost[conn->whichhost].host[0] != '\0') conn->connhost[conn->whichhost].host[0] != '\0')
return conn->connhost[conn->whichhost].host; return conn->connhost[conn->whichhost].host;
...@@ -6480,15 +6482,9 @@ PQhostaddr(const PGconn *conn) ...@@ -6480,15 +6482,9 @@ PQhostaddr(const PGconn *conn)
if (!conn) if (!conn)
return NULL; return NULL;
if (conn->connhost != NULL) /* Return the parsed IP address */
{ if (conn->connhost != NULL && conn->connip != NULL)
if (conn->connhost[conn->whichhost].hostaddr != NULL && return conn->connip;
conn->connhost[conn->whichhost].hostaddr[0] != '\0')
return conn->connhost[conn->whichhost].hostaddr;
if (conn->connip != NULL)
return conn->connip;
}
return ""; return "";
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment