Allow IPv4-format entries in pg_hba.conf to match IPv6 connections
that have IPv4-embedded-in-IPv6 addresses. Per idea of Andreas Pflug.
This commit is contained in:
parent
23d07fa357
commit
3c9bb8886d
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.56 2003/08/31 17:32:18 petere Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.57 2003/09/05 20:31:35 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="client-authentication">
|
||||
@ -199,13 +199,17 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
|
||||
<programlisting>
|
||||
(<replaceable>actual-IP-address</replaceable> xor <replaceable>IP-address-field</replaceable>) and <replaceable>IP-mask-field</replaceable>
|
||||
</programlisting>
|
||||
must be zero for the record to match. (Of course IP addresses
|
||||
can be spoofed but this consideration is beyond the scope of
|
||||
<productname>PostgreSQL</productname>.) If you machine supports
|
||||
IPv6, the default <filename>pg_hba.conf</> file will have an
|
||||
IPv6 entry for <literal>localhost</>. You can add your own IPv6
|
||||
entries to the file. IPv6 entries are used only for IPv6
|
||||
connections.
|
||||
must be zero for the record to match.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An IP address given in IPv4 format will match IPv6 connections that
|
||||
have the corresponding address, for example <literal>127.0.0.1</>
|
||||
will match the IPv6 address <literal>::ffff:127.0.0.1</>. An entry
|
||||
given in IPv6 format will match only IPv6 connections, even if the
|
||||
represented address is in the IPv4-in-IPv6 range. Note that entries
|
||||
in IPv6 format will be rejected if the system's C library does not have
|
||||
support for IPv6 addresses.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -219,9 +223,10 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
|
||||
<term><replaceable>CIDR-mask</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is an integer specifying the number of significant bits
|
||||
to set in the mask, and is an alternative to using the
|
||||
<replaceable>IP-mask</replaceable> notation. The number must
|
||||
This field may be used as an alternative to the
|
||||
<replaceable>IP-mask</replaceable> notation. It is an
|
||||
integer specifying the number of high-order bits
|
||||
to set in the mask. The number must
|
||||
be between 0 and 32 (in the case of an IPv4 address) or 128
|
||||
(in the case of an IPv6 address) inclusive. 0 will match any
|
||||
address, while 32/128 will match only the exact host specified.
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
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)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
int i;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
uint32 s_addr;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* 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;
|
||||
|
||||
memcpy(&addr4, addr, sizeof(addr4));
|
||||
s_addr = ntohl(addr4.sin_addr.s_addr);
|
||||
|
||||
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 /* HAVE_IPV6 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user