Temporary fix for the problem that pg_stat_activity, inet_client_addr(),

and inet_server_addr() fail if the client connected over a "scoped" IPv6
address.  In this case getnameinfo() will return a string ending with
a poorly-standardized "%something" zone specifier, which these functions
try to feed to network_in(), which won't take it.  So that we don't lose
functionality altogether, suppress the zone specifier before giving the
string to network_in().  Per report from Brian Hirt.

TODO: probably someday the inet type should support scoped IPv6 addresses,
and then this patch should be reverted.

Backpatch to 8.2 ... is it worth going further?
This commit is contained in:
Tom Lane 2007-05-17 23:31:59 +00:00
parent d42e2b7502
commit 2f6d85101b
3 changed files with 39 additions and 3 deletions

View File

@ -1,7 +1,7 @@
/*
* PostgreSQL type definitions for the INET and CIDR types.
*
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.66 2006/10/04 00:29:59 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.66.2.1 2007/05/17 23:31:59 tgl Exp $
*
* Jon Postel RIP 16 Oct 1998
*/
@ -1138,6 +1138,8 @@ inet_client_addr(PG_FUNCTION_ARGS)
if (ret)
PG_RETURN_NULL();
clean_ipv6_addr(port->raddr.addr.ss_family, remote_host);
PG_RETURN_INET_P(network_in(remote_host, false));
}
@ -1212,6 +1214,8 @@ inet_server_addr(PG_FUNCTION_ARGS)
if (ret)
PG_RETURN_NULL();
clean_ipv6_addr(port->laddr.addr.ss_family, local_host);
PG_RETURN_INET_P(network_in(local_host, false));
}
@ -1483,3 +1487,32 @@ inetmi(PG_FUNCTION_ARGS)
PG_RETURN_INT64(res);
}
/*
* clean_ipv6_addr --- remove any '%zone' part from an IPv6 address string
*
* XXX This should go away someday!
*
* This is a kluge needed because we don't yet support zones in stored inet
* values. Since the result of getnameinfo() might include a zone spec,
* call this to remove it anywhere we want to feed getnameinfo's output to
* network_in. Beats failing entirely.
*
* An alternative approach would be to let network_in ignore %-parts for
* itself, but that would mean we'd silently drop zone specs in user input,
* which seems not such a good idea.
*/
void
clean_ipv6_addr(int addr_family, char *addr)
{
#ifdef HAVE_IPV6
if (addr_family == AF_INET6)
{
char *pct = strchr(addr, '%');
if (pct)
*pct = '\0';
}
#endif
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.34 2006/10/04 00:29:59 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.34.2.1 2007/05/17 23:31:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -485,6 +485,8 @@ pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
if (ret)
PG_RETURN_NULL();
clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
CStringGetDatum(remote_host)));
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.282.2.1 2007/01/03 22:39:35 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.282.2.2 2007/05/17 23:31:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -767,6 +767,7 @@ extern Datum inetor(PG_FUNCTION_ARGS);
extern Datum inetpl(PG_FUNCTION_ARGS);
extern Datum inetmi_int8(PG_FUNCTION_ARGS);
extern Datum inetmi(PG_FUNCTION_ARGS);
extern void clean_ipv6_addr(int addr_family, char *addr);
/* mac.c */
extern Datum macaddr_in(PG_FUNCTION_ARGS);