aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-09-05 20:31:36 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-09-05 20:31:36 +0000
commit3c9bb8886df7d56aaeb619abc246462fa809d946 (patch)
tree286f7994cfdd0ba76f5c2d5763272d45f7cae532 /src
parent23d07fa3575c4953def69ccbc6c3f9e4473578b7 (diff)
downloadpostgresql-3c9bb8886df7d56aaeb619abc246462fa809d946.tar.gz
postgresql-3c9bb8886df7d56aaeb619abc246462fa809d946.zip
Allow IPv4-format entries in pg_hba.conf to match IPv6 connections
that have IPv4-embedded-in-IPv6 addresses. Per idea of Andreas Pflug.
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/hba.c31
-rw-r--r--src/backend/libpq/ip.c129
-rw-r--r--src/backend/libpq/pg_hba.conf.sample3
-rw-r--r--src/include/libpq/ip.h7
4 files changed, 135 insertions, 35 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 4a677585625..2e212636211 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.112 2003/09/05 03:57:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.113 2003/09/05 20:31:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -673,13 +673,6 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
if (cidr_slash)
*cidr_slash = '/';
- if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
- {
- /* Wrong address family. */
- freeaddrinfo_all(hints.ai_family, file_ip_addr);
- return;
- }
-
/* Get the netmask */
if (cidr_slash)
{
@@ -705,6 +698,28 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
goto hba_syntax;
}
+ if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
+ {
+ /*
+ * Wrong address family. We allow only one case: if the
+ * file has IPv4 and the port is IPv6, promote the file
+ * address to IPv6 and try to match that way.
+ */
+#ifdef HAVE_IPV6
+ if (file_ip_addr->ai_family == AF_INET &&
+ port->raddr.addr.ss_family == AF_INET6)
+ {
+ promote_v4_to_v6_addr((struct sockaddr_storage *) file_ip_addr->ai_addr);
+ promote_v4_to_v6_mask(mask);
+ }
+ else
+#endif /* HAVE_IPV6 */
+ {
+ freeaddrinfo_all(hints.ai_family, file_ip_addr);
+ return;
+ }
+ }
+
/* Read the rest of the line. */
line = lnext(line);
if (!line)
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
index 8ae6c8f7848..6ab5f57fd78 100644
--- a/src/backend/libpq/ip.c
+++ b/src/backend/libpq/ip.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.19 2003/08/04 02:39:59 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.20 2003/09/05 20:31:36 tgl Exp $
*
* This file and the IPV6 implementation were initially provided by
* Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
@@ -34,7 +34,8 @@
#endif
#include <arpa/inet.h>
#include <sys/file.h>
-#endif
+
+#endif /* !defined(_MSC_VER) && !defined(__BORLANDC__) */
#include "libpq/ip.h"
@@ -265,9 +266,16 @@ getnameinfo_unix(const struct sockaddr_un * sa, int salen,
return 0;
}
+
#endif /* HAVE_UNIX_SOCKETS */
+/*
+ * rangeSockAddr - is addr within the subnet specified by netaddr/netmask ?
+ *
+ * Note: caller must already have verified that all three addresses are
+ * in the same address family; and AF_UNIX addresses are not supported.
+ */
int
rangeSockAddr(const struct sockaddr_storage * addr,
const struct sockaddr_storage * netaddr,
@@ -287,6 +295,39 @@ rangeSockAddr(const struct sockaddr_storage * addr,
return 0;
}
+static int
+rangeSockAddrAF_INET(const struct sockaddr_in * addr,
+ const struct sockaddr_in * netaddr,
+ const struct sockaddr_in * netmask)
+{
+ if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
+ netmask->sin_addr.s_addr) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+#ifdef HAVE_IPV6
+static int
+rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
+ const struct sockaddr_in6 * netaddr,
+ const struct sockaddr_in6 * netmask)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
+ netmask->sin6_addr.s6_addr[i]) != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif
+
/*
* SockAddr_cidr_mask - make a network mask of the appropriate family
* and required number of significant bits
@@ -358,34 +399,74 @@ SockAddr_cidr_mask(struct sockaddr_storage ** mask, char *numbits, int family)
return 0;
}
-static int
-rangeSockAddrAF_INET(const struct sockaddr_in * addr, const struct sockaddr_in * netaddr,
- const struct sockaddr_in * netmask)
+
+#ifdef HAVE_IPV6
+
+/*
+ * promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
+ * the standard convention for IPv4 addresses mapped into IPv6 world
+ *
+ * The passed addr is modified in place. Note that we only worry about
+ * setting the fields that rangeSockAddr will look at.
+ */
+void
+promote_v4_to_v6_addr(struct sockaddr_storage * addr)
{
- if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
- netmask->sin_addr.s_addr) == 0)
- return 1;
- else
- return 0;
-}
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ uint32 s_addr;
+ memcpy(&addr4, addr, sizeof(addr4));
+ s_addr = ntohl(addr4.sin_addr.s_addr);
-#ifdef HAVE_IPV6
-static int
-rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
- const struct sockaddr_in6 * netaddr,
- const struct sockaddr_in6 * netmask)
+ memset(&addr6, 0, sizeof(addr6));
+
+ addr6.sin6_family = AF_INET6;
+
+ addr6.sin6_addr.s6_addr[10] = 0xff;
+ addr6.sin6_addr.s6_addr[11] = 0xff;
+ addr6.sin6_addr.s6_addr[12] = (s_addr >> 24) & 0xFF;
+ addr6.sin6_addr.s6_addr[13] = (s_addr >> 16) & 0xFF;
+ addr6.sin6_addr.s6_addr[14] = (s_addr >> 8) & 0xFF;
+ addr6.sin6_addr.s6_addr[15] = (s_addr) & 0xFF;
+
+ memcpy(addr, &addr6, sizeof(addr6));
+}
+
+/*
+ * promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
+ * the standard convention for IPv4 addresses mapped into IPv6 world
+ *
+ * This must be different from promote_v4_to_v6_addr because we want to
+ * set the high-order bits to 1's not 0's.
+ *
+ * The passed addr is modified in place. Note that we only worry about
+ * setting the fields that rangeSockAddr will look at.
+ */
+void
+promote_v4_to_v6_mask(struct sockaddr_storage * addr)
{
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ uint32 s_addr;
int i;
- for (i = 0; i < 16; i++)
- {
- if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
- netmask->sin6_addr.s6_addr[i]) != 0)
- return 0;
- }
+ memcpy(&addr4, addr, sizeof(addr4));
+ s_addr = ntohl(addr4.sin_addr.s_addr);
- return 1;
+ memset(&addr6, 0, sizeof(addr6));
+
+ addr6.sin6_family = AF_INET6;
+
+ for (i = 0; i < 12; i++)
+ addr6.sin6_addr.s6_addr[i] = 0xff;
+
+ addr6.sin6_addr.s6_addr[12] = (s_addr >> 24) & 0xFF;
+ addr6.sin6_addr.s6_addr[13] = (s_addr >> 16) & 0xFF;
+ addr6.sin6_addr.s6_addr[14] = (s_addr >> 8) & 0xFF;
+ addr6.sin6_addr.s6_addr[15] = (s_addr) & 0xFF;
+
+ memcpy(addr, &addr6, sizeof(addr6));
}
-#endif
+#endif /* HAVE_IPV6 */
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index e5dba788c66..53c65cc81ae 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -53,6 +53,5 @@
local all all trust
host all all 127.0.0.1 255.255.255.255 trust
-# uncomment these to support IPv6 localhost connections
+# uncomment this to support IPv6 loopback connections
# host all all ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff trust
-# host all all ::ffff:127.0.0.1/128 trust
diff --git a/src/include/libpq/ip.h b/src/include/libpq/ip.h
index c60030ccf50..9858faaddc9 100644
--- a/src/include/libpq/ip.h
+++ b/src/include/libpq/ip.h
@@ -5,7 +5,7 @@
*
* Copyright (c) 2003, PostgreSQL Global Development Group
*
- * $Id: ip.h,v 1.10 2003/08/04 00:43:31 momjian Exp $
+ * $Id: ip.h,v 1.11 2003/09/05 20:31:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,6 +33,11 @@ extern int rangeSockAddr(const struct sockaddr_storage * addr,
extern int SockAddr_cidr_mask(struct sockaddr_storage ** mask,
char *numbits, int family);
+#ifdef HAVE_IPV6
+extern void promote_v4_to_v6_addr(struct sockaddr_storage * addr);
+extern void promote_v4_to_v6_mask(struct sockaddr_storage * addr);
+#endif
+
#ifdef HAVE_UNIX_SOCKETS
#define IS_AF_UNIX(fam) ((fam) == AF_UNIX)
#else