Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6e5f8d4

Browse files
committed
psql: Show IP address in \conninfo
When hostaddr is given, the actual IP address that psql is connected to can be totally unexpected for the given host. The more verbose output we now generate makes things clearer. Since the "host" and "hostaddr" parts of the conninfo could come from different sources (say, one of them is in the service specification or a URI-style conninfo and the other is not), this is not as silly as it may first appear. This is also definitely useful if the hostname resolves to multiple addresses. Author: Fabien Coelho Reviewed-by: Pavel Stehule, Arthur Zakirov Discussion: https://postgr.es/m/alpine.DEB.2.21.1810261532380.27686@lancre https://postgr.es/m/alpine.DEB.2.21.1808201323020.13832@lancre
1 parent 7ee5f88 commit 6e5f8d4

File tree

6 files changed

+172
-41
lines changed

6 files changed

+172
-41
lines changed

doc/src/sgml/libpq.sgml

+30
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,36 @@ char *PQhost(const PGconn *conn);
17351735
</listitem>
17361736
</varlistentry>
17371737

1738+
1739+
<varlistentry id="libpq-pqhostaddr">
1740+
<term>
1741+
<function>PQhostaddr</function>
1742+
<indexterm>
1743+
<primary>PQhostaddr</primary>
1744+
</indexterm>
1745+
</term>
1746+
1747+
<listitem>
1748+
<para>
1749+
Returns the server IP address of the active connection.
1750+
This can be the address that a host name resolved to,
1751+
or an IP address provided through the <literal>hostaddr</literal>
1752+
parameter.
1753+
<synopsis>
1754+
char *PQhostaddr(const PGconn *conn);
1755+
</synopsis>
1756+
</para>
1757+
1758+
<para>
1759+
<function>PQhostaddr</function> returns <symbol>NULL</symbol> if the
1760+
<parameter>conn</parameter> argument is <symbol>NULL</symbol>.
1761+
Otherwise, if there is an error producing the host information
1762+
(perhaps if the connection has not been fully established or
1763+
there was an error), it returns an empty string.
1764+
</para>
1765+
</listitem>
1766+
</varlistentry>
1767+
17381768
<varlistentry id="libpq-pqport">
17391769
<term>
17401770
<function>PQport</function>

src/bin/psql/command.c

+66-16
Original file line numberDiff line numberDiff line change
@@ -596,14 +596,30 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
596596
else
597597
{
598598
char *host = PQhost(pset.db);
599+
char *hostaddr = PQhostaddr(pset.db);
599600

600-
/* If the host is an absolute path, the connection is via socket */
601+
/*
602+
* If the host is an absolute path, the connection is via socket
603+
* unless overriden by hostaddr
604+
*/
601605
if (is_absolute_path(host))
602-
printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
603-
db, PQuser(pset.db), host, PQport(pset.db));
606+
{
607+
if (hostaddr && *hostaddr)
608+
printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
609+
db, PQuser(pset.db), hostaddr, PQport(pset.db));
610+
else
611+
printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
612+
db, PQuser(pset.db), host, PQport(pset.db));
613+
}
604614
else
605-
printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
606-
db, PQuser(pset.db), host, PQport(pset.db));
615+
{
616+
if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
617+
printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
618+
db, PQuser(pset.db), host, hostaddr, PQport(pset.db));
619+
else
620+
printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
621+
db, PQuser(pset.db), host, PQport(pset.db));
622+
}
607623
printSSLInfo();
608624
}
609625
}
@@ -2854,6 +2870,7 @@ do_connect(enum trivalue reuse_previous_specification,
28542870
PGconn *o_conn = pset.db,
28552871
*n_conn;
28562872
char *password = NULL;
2873+
char *hostaddr = NULL;
28572874
bool keep_password;
28582875
bool has_connection_string;
28592876
bool reuse_previous;
@@ -2894,12 +2911,27 @@ do_connect(enum trivalue reuse_previous_specification,
28942911
}
28952912

28962913
/* grab missing values from the old connection */
2897-
if (!user && reuse_previous)
2898-
user = PQuser(o_conn);
2899-
if (!host && reuse_previous)
2900-
host = PQhost(o_conn);
2901-
if (!port && reuse_previous)
2902-
port = PQport(o_conn);
2914+
if (reuse_previous)
2915+
{
2916+
if (!user)
2917+
user = PQuser(o_conn);
2918+
if (host && strcmp(host, PQhost(o_conn)) == 0)
2919+
{
2920+
/*
2921+
* if we are targetting the same host, reuse its hostaddr for
2922+
* consistency
2923+
*/
2924+
hostaddr = PQhostaddr(o_conn);
2925+
}
2926+
if (!host)
2927+
{
2928+
host = PQhost(o_conn);
2929+
/* also set hostaddr for consistency */
2930+
hostaddr = PQhostaddr(o_conn);
2931+
}
2932+
if (!port)
2933+
port = PQport(o_conn);
2934+
}
29032935

29042936
/*
29052937
* Any change in the parameters read above makes us discard the password.
@@ -2961,13 +2993,18 @@ do_connect(enum trivalue reuse_previous_specification,
29612993

29622994
while (true)
29632995
{
2964-
#define PARAMS_ARRAY_SIZE 8
2996+
#define PARAMS_ARRAY_SIZE 9
29652997
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
29662998
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
29672999
int paramnum = -1;
29683000

29693001
keywords[++paramnum] = "host";
29703002
values[paramnum] = host;
3003+
if (hostaddr && *hostaddr)
3004+
{
3005+
keywords[++paramnum] = "hostaddr";
3006+
values[paramnum] = hostaddr;
3007+
}
29713008
keywords[++paramnum] = "port";
29723009
values[paramnum] = port;
29733010
keywords[++paramnum] = "user";
@@ -3071,14 +3108,27 @@ do_connect(enum trivalue reuse_previous_specification,
30713108
param_is_newly_set(PQport(o_conn), PQport(pset.db)))
30723109
{
30733110
char *host = PQhost(pset.db);
3111+
char *hostaddr = PQhostaddr(pset.db);
30743112

30753113
/* If the host is an absolute path, the connection is via socket */
30763114
if (is_absolute_path(host))
3077-
printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
3078-
PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3115+
{
3116+
if (hostaddr && *hostaddr)
3117+
printf(_("You are now connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
3118+
PQdb(pset.db), PQuser(pset.db), hostaddr, PQport(pset.db));
3119+
else
3120+
printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
3121+
PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3122+
}
30793123
else
3080-
printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
3081-
PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3124+
{
3125+
if (hostaddr && *hostaddr && strcmp(host, hostaddr) != 0)
3126+
printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" (address \"%s\") at port \"%s\".\n"),
3127+
PQdb(pset.db), PQuser(pset.db), host, hostaddr, PQport(pset.db));
3128+
else
3129+
printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
3130+
PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
3131+
}
30823132
}
30833133
else
30843134
printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),

src/interfaces/libpq/exports.txt

+1
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,4 @@ PQsetErrorContextVisibility 170
173173
PQresultVerboseErrorMessage 171
174174
PQencryptPasswordConn 172
175175
PQresultMemorySize 173
176+
PQhostaddr 174

src/interfaces/libpq/fe-connect.c

+73-25
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,39 @@ connectNoDelay(PGconn *conn)
14711471
return 1;
14721472
}
14731473

1474+
/* ----------
1475+
* Write currently connected IP address into host_addr (of len host_addr_len).
1476+
* If unable to, set it to the empty string.
1477+
* ----------
1478+
*/
1479+
static void
1480+
getHostaddr(PGconn *conn, char *host_addr, int host_addr_len)
1481+
{
1482+
struct sockaddr_storage *addr = &conn->raddr.addr;
1483+
1484+
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
1485+
strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, host_addr_len);
1486+
else if (addr->ss_family == AF_INET)
1487+
{
1488+
if (inet_net_ntop(AF_INET,
1489+
&((struct sockaddr_in *) addr)->sin_addr.s_addr,
1490+
32,
1491+
host_addr, host_addr_len) == NULL)
1492+
host_addr[0] = '\0';
1493+
}
1494+
#ifdef HAVE_IPV6
1495+
else if (addr->ss_family == AF_INET6)
1496+
{
1497+
if (inet_net_ntop(AF_INET6,
1498+
&((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
1499+
128,
1500+
host_addr, host_addr_len) == NULL)
1501+
host_addr[0] = '\0';
1502+
}
1503+
#endif
1504+
else
1505+
host_addr[0] = '\0';
1506+
}
14741507

14751508
/* ----------
14761509
* connectFailureMessage -
@@ -1504,34 +1537,12 @@ connectFailureMessage(PGconn *conn, int errorno)
15041537
char host_addr[NI_MAXHOST];
15051538
const char *displayed_host;
15061539
const char *displayed_port;
1507-
struct sockaddr_storage *addr = &conn->raddr.addr;
15081540

15091541
/*
15101542
* Optionally display the network address with the hostname. This is
15111543
* useful to distinguish between IPv4 and IPv6 connections.
15121544
*/
1513-
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
1514-
strlcpy(host_addr, conn->connhost[conn->whichhost].hostaddr, NI_MAXHOST);
1515-
else if (addr->ss_family == AF_INET)
1516-
{
1517-
if (inet_net_ntop(AF_INET,
1518-
&((struct sockaddr_in *) addr)->sin_addr.s_addr,
1519-
32,
1520-
host_addr, sizeof(host_addr)) == NULL)
1521-
strcpy(host_addr, "???");
1522-
}
1523-
#ifdef HAVE_IPV6
1524-
else if (addr->ss_family == AF_INET6)
1525-
{
1526-
if (inet_net_ntop(AF_INET6,
1527-
&((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
1528-
128,
1529-
host_addr, sizeof(host_addr)) == NULL)
1530-
strcpy(host_addr, "???");
1531-
}
1532-
#endif
1533-
else
1534-
strcpy(host_addr, "???");
1545+
getHostaddr(conn, host_addr, NI_MAXHOST);
15351546

15361547
/* To which host and port were we actually connecting? */
15371548
if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
@@ -1548,14 +1559,14 @@ connectFailureMessage(PGconn *conn, int errorno)
15481559
* looked-up IP address.
15491560
*/
15501561
if (conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS &&
1562+
strlen(host_addr) > 0 &&
15511563
strcmp(displayed_host, host_addr) != 0)
15521564
appendPQExpBuffer(&conn->errorMessage,
15531565
libpq_gettext("could not connect to server: %s\n"
15541566
"\tIs the server running on host \"%s\" (%s) and accepting\n"
15551567
"\tTCP/IP connections on port %s?\n"),
15561568
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
1557-
displayed_host,
1558-
host_addr,
1569+
displayed_host, host_addr,
15591570
displayed_port);
15601571
else
15611572
appendPQExpBuffer(&conn->errorMessage,
@@ -2286,6 +2297,7 @@ PQconnectPoll(PGconn *conn)
22862297
*/
22872298
{
22882299
struct addrinfo *addr_cur = conn->addr_cur;
2300+
char host_addr[NI_MAXHOST];
22892301

22902302
/*
22912303
* Advance to next possible host, if we've tried all of
@@ -2302,6 +2314,21 @@ PQconnectPoll(PGconn *conn)
23022314
addr_cur->ai_addrlen);
23032315
conn->raddr.salen = addr_cur->ai_addrlen;
23042316

2317+
/* set connip */
2318+
if (conn->connip != NULL)
2319+
{
2320+
free(conn->connip);
2321+
conn->connip = NULL;
2322+
}
2323+
2324+
getHostaddr(conn, host_addr, NI_MAXHOST);
2325+
if (strlen(host_addr) > 0)
2326+
conn->connip = strdup(host_addr);
2327+
/*
2328+
* purposely ignore strdup failure; not a big problem if
2329+
* it fails anyway.
2330+
*/
2331+
23052332
conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
23062333
if (conn->sock == PGINVALID_SOCKET)
23072334
{
@@ -3665,6 +3692,8 @@ freePGconn(PGconn *conn)
36653692
free(conn->sslcompression);
36663693
if (conn->requirepeer)
36673694
free(conn->requirepeer);
3695+
if (conn->connip)
3696+
free(conn->connip);
36683697
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
36693698
if (conn->krbsrvname)
36703699
free(conn->krbsrvname);
@@ -6172,6 +6201,25 @@ PQhost(const PGconn *conn)
61726201
return "";
61736202
}
61746203

6204+
char *
6205+
PQhostaddr(const PGconn *conn)
6206+
{
6207+
if (!conn)
6208+
return NULL;
6209+
6210+
if (conn->connhost != NULL)
6211+
{
6212+
if (conn->connhost[conn->whichhost].hostaddr != NULL &&
6213+
conn->connhost[conn->whichhost].hostaddr[0] != '\0')
6214+
return conn->connhost[conn->whichhost].hostaddr;
6215+
6216+
if (conn->connip != NULL)
6217+
return conn->connip;
6218+
}
6219+
6220+
return "";
6221+
}
6222+
61756223
char *
61766224
PQport(const PGconn *conn)
61776225
{

src/interfaces/libpq/libpq-fe.h

+1
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ extern char *PQdb(const PGconn *conn);
312312
extern char *PQuser(const PGconn *conn);
313313
extern char *PQpass(const PGconn *conn);
314314
extern char *PQhost(const PGconn *conn);
315+
extern char *PQhostaddr(const PGconn *conn);
315316
extern char *PQport(const PGconn *conn);
316317
extern char *PQtty(const PGconn *conn);
317318
extern char *PQoptions(const PGconn *conn);

src/interfaces/libpq/libpq-int.h

+1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ struct pg_conn
397397
int nconnhost; /* # of hosts named in conn string */
398398
int whichhost; /* host we're currently trying/connected to */
399399
pg_conn_host *connhost; /* details about each named host */
400+
char *connip; /* IP address for current network connection */
400401

401402
/* Connection data */
402403
pgsocket sock; /* FD for socket, PGINVALID_SOCKET if

0 commit comments

Comments
 (0)