Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Andreas Pflug <pgadmin(at)pse-consulting(dot)de>
Cc: Andrew Dunstan <andrew(at)dunslane(dot)net>, pgsql-patches(at)postgresql(dot)org
Subject: Re: IPV4 addresses on IPV6 machines in pg_hba.conf
Date: 2003-09-05 20:34:42
Message-ID: 14993.1062794082@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches

Andreas Pflug <pgadmin(at)pse-consulting(dot)de> writes:
> Andrew Dunstan wrote:
>> You should check that the CIDR mask is a valid integer. You would need
>> to use strtol() rather than atoi() to do that. Perhaps this should be
>> hoisted out of ip.c:SockAddr_cidr_mask() and put in hba.c.

> Right, I added this.

I thought this was still really messy, so I modified it to use a
separate "promote v4 address to v6" subroutine. I've applied the
attached patch (plus docs). It's not very well tested since I don't
have an IPv6 setup here; please check that it does what you want.

regards, tom lane

*** src/backend/libpq/hba.c.orig Fri Sep 5 10:35:54 2003
--- src/backend/libpq/hba.c Fri Sep 5 16:24:41 2003
***************
*** 673,685 ****
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)
{
--- 673,678 ----
***************
*** 703,708 ****
--- 696,723 ----

if (file_ip_addr->ai_family != mask->ss_family)
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. */
*** src/backend/libpq/ip.c.orig Sun Aug 3 23:00:36 2003
--- src/backend/libpq/ip.c Fri Sep 5 16:24:42 2003
***************
*** 34,40 ****
#endif
#include <arpa/inet.h>
#include <sys/file.h>
! #endif

#include "libpq/ip.h"

--- 34,41 ----
#endif
#include <arpa/inet.h>
#include <sys/file.h>
!
! #endif /* !defined(_MSC_VER) && !defined(__BORLANDC__) */

#include "libpq/ip.h"

***************
*** 265,273 ****
--- 266,281 ----

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,292 ****
--- 295,333 ----
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,391 ****
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
--- 399,472 ----
return 0;
}

!
! #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)
{
! struct sockaddr_in addr4;
! struct sockaddr_in6 addr6;
! uint32 s_addr;

+ memcpy(&addr4, addr, sizeof(addr4));
+ s_addr = ntohl(addr4.sin_addr.s_addr);

! 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;

! 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 */
*** src/include/libpq/ip.h.orig Sun Aug 3 23:01:33 2003
--- src/include/libpq/ip.h Fri Sep 5 16:24:36 2003
***************
*** 33,38 ****
--- 33,43 ----
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

In response to

Responses

Browse pgsql-patches by date

  From Date Subject
Next Message Peter Eisentraut 2003-09-05 20:37:09 Re: [PATCHES] Warning for missing createlang
Previous Message Peter Eisentraut 2003-09-05 20:33:26 Re: Warning for missing createlang