Thread: IPV4 addresses on IPV6 machines in pg_hba.conf

IPV4 addresses on IPV6 machines in pg_hba.conf

From
Andreas Pflug
Date:
This was discussed in [HACKERS] TCP/IP with 7.4 beta2 broken?


I created a patch to hba.c which uses IPV4 entries as IPV6 entries if
running on a IPV6 system (which is detected from a port coming in as
AF_INET6).

192.168.0.0/24             ->  ::ffff:102.168.0/120

192.168.0.0 255.255.255.0  ->  ::ffff:102.168.0 ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.0

This helps people that think they're using IPV4 while actually their
system silently is using IPV6 (such as SuSE 8.1, 8.2).

Regards,
Andreas


? hba.conf.diff
Index: hba.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/hba.c,v
retrieving revision 1.111
diff -c -r1.111 hba.c
*** hba.c    4 Aug 2003 02:39:59 -0000    1.111
--- hba.c    2 Sep 2003 11:07:10 -0000
***************
*** 673,708 ****
          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)
          {
!             if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
!                                    file_ip_addr->ai_family) < 0)
!                 goto hba_syntax;
          }
          else
          {
!             /* Read the mask field. */
!             line = lnext(line);
!             if (!line)
!                 goto hba_syntax;
!             token = lfirst(line);
!
!             ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
!             if (ret || !file_ip_mask)
!                 goto hba_syntax;
!
!             mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!             if (file_ip_addr->ai_family != mask->ss_family)
!                 goto hba_syntax;
          }

          /* Read the rest of the line. */
--- 673,761 ----
          if (cidr_slash)
              *cidr_slash = '/';

!         if (file_ip_addr->ai_family == AF_INET && port->raddr.addr.ss_family == AF_INET6)
          {
!             /* port got a IPV6 address, but the current line is IPV4.
!              * We'll make a IPV6 entry from this line, to check if by chance the connecting port
!              * is a converted IPV4 address. */
!
!             char *v6addr=palloc(strlen(token)+8);
!             char *v6mask;
!
              freeaddrinfo_all(hints.ai_family, file_ip_addr);

!             if (cidr_slash)
!                 *cidr_slash = 0;
!             sprintf(v6addr, "::ffff:%s", token);
!             if (cidr_slash)
!                 *cidr_slash = '/';
!
!             ret = getaddrinfo_all(v6addr, NULL, &hints, &file_ip_addr);
!             if (ret || !file_ip_addr)
!             {
!                 ereport(LOG,
!                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
!                          errmsg("could not interpret converted IP address \"%s\" in config file: %s",
!                                 token, gai_strerror(ret))));
!             }
!             if (cidr_slash)
!             {
!                 v6mask = palloc(20);
!                 sprintf(v6mask, "%d", atoi(cidr_slash+1)+96);
!                 if (SockAddr_cidr_mask(&mask, v6mask, file_ip_addr->ai_family) < 0)
!                     goto hba_syntax;
!             }
!             else
!             {
!                 line = lnext(line);
!                 if (!line)
!                     goto hba_syntax;
!                 token = lfirst(line);
!                 v6mask = palloc(strlen(token)+32);
!                 sprintf(v6mask, "ffff:ffff:ffff:ffff:ffff:ffff:%s", token);
!
!                 ret = getaddrinfo_all(v6mask, NULL, &hints, &file_ip_mask);
!                 if (ret || !file_ip_mask)
!                     goto hba_syntax;
!
!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!                 if (file_ip_addr->ai_family != mask->ss_family)
!                     goto hba_syntax;
!             }
!         }
!         else if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
          {
!             /* Wrong address family. */
!             freeaddrinfo_all(hints.ai_family, file_ip_addr);
!             return;
          }
          else
          {
!             /* Get the netmask */
!             if (cidr_slash)
!             {
!                 if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
!                                        file_ip_addr->ai_family) < 0)
!                     goto hba_syntax;
!             }
!             else
!             {
!                 /* Read the mask field. */
!                 line = lnext(line);
!                 if (!line)
!                     goto hba_syntax;
!                 token = lfirst(line);
!
!                 ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
!                 if (ret || !file_ip_mask)
!                     goto hba_syntax;
!
!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!                 if (file_ip_addr->ai_family != mask->ss_family)
!                     goto hba_syntax;
!             }
          }

          /* Read the rest of the line. */


Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Kurt Roeckx
Date:
On Wed, Sep 03, 2003 at 07:19:16PM +0200, Andreas Pflug wrote:
> This was discussed in [HACKERS] TCP/IP with 7.4 beta2 broken?
>
>
> I created a patch to hba.c which uses IPV4 entries as IPV6 entries if
> running on a IPV6 system (which is detected from a port coming in as
> AF_INET6).
>

You're assuming all systems have an AF_INET6 constant, which is
not the case.  Please make use of HAVE_IPV6.

Can't directly see anything else wrong with it.


Kurt


Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Andreas Pflug
Date:
Kurt Roeckx wrote:

>You're assuming all systems have an AF_INET6 constant, which is
>not the case.  Please make use of HAVE_IPV6.
>
>Can't directly see anything else wrong with it.
>
>
>
Here's the patch with HAVE_IPV6 conditional compiling.

Regards,
Andreas


Index: hba.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/hba.c,v
retrieving revision 1.111
diff -c -r1.111 hba.c
*** hba.c    4 Aug 2003 02:39:59 -0000    1.111
--- hba.c    5 Sep 2003 00:24:47 -0000
***************
*** 673,708 ****
          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)
          {
!             if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
!                                    file_ip_addr->ai_family) < 0)
!                 goto hba_syntax;
          }
          else
          {
!             /* Read the mask field. */
!             line = lnext(line);
!             if (!line)
!                 goto hba_syntax;
!             token = lfirst(line);
!
!             ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
!             if (ret || !file_ip_mask)
!                 goto hba_syntax;
!
!             mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!             if (file_ip_addr->ai_family != mask->ss_family)
!                 goto hba_syntax;
          }

          /* Read the rest of the line. */
--- 673,767 ----
          if (cidr_slash)
              *cidr_slash = '/';

! #ifdef HAVE_IPV6
!
!         if (file_ip_addr->ai_family == AF_INET && port->raddr.addr.ss_family == AF_INET6)
          {
!             /* port got a IPV6 address, but the current line is IPV4.
!              * We'll make a IPV6 entry from this line, to check if by chance the connecting port
!              * is a converted IPV4 address. */
!
!             char *v6addr=palloc(strlen(token)+8);
!             char *v6mask;
!
              freeaddrinfo_all(hints.ai_family, file_ip_addr);
!
!             if (cidr_slash)
!                 *cidr_slash = 0;
!             sprintf(v6addr, "::ffff:%s", token);
!             if (cidr_slash)
!                 *cidr_slash = '/';
!
!             ret = getaddrinfo_all(v6addr, NULL, &hints, &file_ip_addr);
!             if (ret || !file_ip_addr)
!             {
!                 ereport(LOG,
!                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
!                          errmsg("could not interpret converted IP address \"%s\" in config file: %s",
!                                 token, gai_strerror(ret))));
!             }
!             if (cidr_slash)
!             {
!                 v6mask = palloc(20);
!                 sprintf(v6mask, "%d", atoi(cidr_slash+1)+96);
!                 if (SockAddr_cidr_mask(&mask, v6mask, file_ip_addr->ai_family) < 0)
!                     goto hba_syntax;
!             }
!             else
!             {
!                 line = lnext(line);
!                 if (!line)
!                     goto hba_syntax;
!                 token = lfirst(line);
!                 v6mask = palloc(strlen(token)+32);
!                 sprintf(v6mask, "ffff:ffff:ffff:ffff:ffff:ffff:%s", token);
!
!                 ret = getaddrinfo_all(v6mask, NULL, &hints, &file_ip_mask);
!                 if (ret || !file_ip_mask)
!                     goto hba_syntax;
!
!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!                 if (file_ip_addr->ai_family != mask->ss_family)
!                     goto hba_syntax;
!             }
          }
+         else
+
+ #endif // HAVE_IPV6

!         if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
          {
!             /* Wrong address family. */
!             freeaddrinfo_all(hints.ai_family, file_ip_addr);
!             return;
          }
          else
          {
!             /* Get the netmask */
!             if (cidr_slash)
!             {
!                 if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
!                                        file_ip_addr->ai_family) < 0)
!                     goto hba_syntax;
!             }
!             else
!             {
!                 /* Read the mask field. */
!                 line = lnext(line);
!                 if (!line)
!                     goto hba_syntax;
!                 token = lfirst(line);
!
!                 ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
!                 if (ret || !file_ip_mask)
!                     goto hba_syntax;
!
!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!                 if (file_ip_addr->ai_family != mask->ss_family)
!                     goto hba_syntax;
!             }
          }

          /* Read the rest of the line. */

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Andrew Dunstan
Date:
Andreas,

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.

Sorry, I should have checked this carefully earlier.

andrew

Andreas Pflug wrote:

> Kurt Roeckx wrote:
>
>> You're assuming all systems have an AF_INET6 constant, which is
>> not the case.  Please make use of HAVE_IPV6.
>>
>> Can't directly see anything else wrong with it.
>>
>>
>>
> Here's the patch with HAVE_IPV6 conditional compiling.
>
> Regards,
> Andreas
>
>
>------------------------------------------------------------------------
>
>Index: hba.c
>===================================================================
>RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/hba.c,v
>retrieving revision 1.111
>diff -c -r1.111 hba.c
>*** hba.c    4 Aug 2003 02:39:59 -0000    1.111
>--- hba.c    5 Sep 2003 00:24:47 -0000
>***************
>*** 673,708 ****
>          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)
>          {
>!             if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
>!                                    file_ip_addr->ai_family) < 0)
>!                 goto hba_syntax;
>          }
>          else
>          {
>!             /* Read the mask field. */
>!             line = lnext(line);
>!             if (!line)
>!                 goto hba_syntax;
>!             token = lfirst(line);
>!
>!             ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
>!             if (ret || !file_ip_mask)
>!                 goto hba_syntax;
>!
>!             mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
>!
>!             if (file_ip_addr->ai_family != mask->ss_family)
>!                 goto hba_syntax;
>          }
>
>          /* Read the rest of the line. */
>--- 673,767 ----
>          if (cidr_slash)
>              *cidr_slash = '/';
>
>! #ifdef HAVE_IPV6
>!
>!         if (file_ip_addr->ai_family == AF_INET && port->raddr.addr.ss_family == AF_INET6)
>          {
>!             /* port got a IPV6 address, but the current line is IPV4.
>!              * We'll make a IPV6 entry from this line, to check if by chance the connecting port
>!              * is a converted IPV4 address. */
>!
>!             char *v6addr=palloc(strlen(token)+8);
>!             char *v6mask;
>!
>              freeaddrinfo_all(hints.ai_family, file_ip_addr);
>!
>!             if (cidr_slash)
>!                 *cidr_slash = 0;
>!             sprintf(v6addr, "::ffff:%s", token);
>!             if (cidr_slash)
>!                 *cidr_slash = '/';
>!
>!             ret = getaddrinfo_all(v6addr, NULL, &hints, &file_ip_addr);
>!             if (ret || !file_ip_addr)
>!             {
>!                 ereport(LOG,
>!                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
>!                          errmsg("could not interpret converted IP address \"%s\" in config file: %s",
>!                                 token, gai_strerror(ret))));
>!             }
>!             if (cidr_slash)
>!             {
>!                 v6mask = palloc(20);
>!                 sprintf(v6mask, "%d", atoi(cidr_slash+1)+96);
>!                 if (SockAddr_cidr_mask(&mask, v6mask, file_ip_addr->ai_family) < 0)
>!                     goto hba_syntax;
>!             }
>!             else
>!             {
>!                 line = lnext(line);
>!                 if (!line)
>!                     goto hba_syntax;
>!                 token = lfirst(line);
>!                 v6mask = palloc(strlen(token)+32);
>!                 sprintf(v6mask, "ffff:ffff:ffff:ffff:ffff:ffff:%s", token);
>!
>!                 ret = getaddrinfo_all(v6mask, NULL, &hints, &file_ip_mask);
>!                 if (ret || !file_ip_mask)
>!                     goto hba_syntax;
>!
>!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
>!
>!                 if (file_ip_addr->ai_family != mask->ss_family)
>!                     goto hba_syntax;
>!             }
>          }
>+         else
>+
>+ #endif // HAVE_IPV6
>
>!         if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
>          {
>!             /* Wrong address family. */
>!             freeaddrinfo_all(hints.ai_family, file_ip_addr);
>!             return;
>          }
>          else
>          {
>!             /* Get the netmask */
>!             if (cidr_slash)
>!             {
>!                 if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
>!                                        file_ip_addr->ai_family) < 0)
>!                     goto hba_syntax;
>!             }
>!             else
>!             {
>!                 /* Read the mask field. */
>!                 line = lnext(line);
>!                 if (!line)
>!                     goto hba_syntax;
>!                 token = lfirst(line);
>!
>!                 ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
>!                 if (ret || !file_ip_mask)
>!                     goto hba_syntax;
>!
>!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
>!
>!                 if (file_ip_addr->ai_family != mask->ss_family)
>!                     goto hba_syntax;
>!             }
>          }
>
>          /* Read the rest of the line. */
>
>
>------------------------------------------------------------------------
>
>
>---------------------------(end of broadcast)---------------------------
>TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
>
>


Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Andreas Pflug
Date:
Andrew Dunstan wrote:

>
> Andreas,
>
> 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.

Regards,
Andreas

Index: hba.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/hba.c,v
retrieving revision 1.112
diff -c -r1.112 hba.c
*** hba.c    5 Sep 2003 03:57:13 -0000    1.112
--- hba.c    5 Sep 2003 09:04:33 -0000
***************
*** 673,708 ****
          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)
          {
!             if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
!                                    file_ip_addr->ai_family) < 0)
!                 goto hba_syntax;
          }
          else
          {
!             /* Read the mask field. */
!             line = lnext(line);
!             if (!line)
!                 goto hba_syntax;
!             token = lfirst(line);
!
!             ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
!             if (ret || !file_ip_mask)
!                 goto hba_syntax;
!
!             mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!             if (file_ip_addr->ai_family != mask->ss_family)
!                 goto hba_syntax;
          }

          /* Read the rest of the line. */
--- 673,774 ----
          if (cidr_slash)
              *cidr_slash = '/';

! #ifdef HAVE_IPV6
!
!         if (file_ip_addr->ai_family == AF_INET && port->raddr.addr.ss_family == AF_INET6)
          {
!             /* port got a IPV6 address, but the current line is IPV4.
!              * We'll make a IPV6 entry from this line, to check if by chance the connecting port
!              * is a converted IPV4 address. */
!
!             char *v6addr=palloc(strlen(token)+8);
!             char *v6mask;
!
              freeaddrinfo_all(hints.ai_family, file_ip_addr);
!
!             if (cidr_slash)
!                 *cidr_slash = 0;
!             sprintf(v6addr, "::ffff:%s", token);
!             if (cidr_slash)
!                 *cidr_slash = '/';
!
!             ret = getaddrinfo_all(v6addr, NULL, &hints, &file_ip_addr);
!             if (ret || !file_ip_addr)
!             {
!                 ereport(LOG,
!                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
!                          errmsg("could not interpret converted IP address \"%s\" in config file: %s",
!                                 token, gai_strerror(ret))));
!             }
!             if (cidr_slash)
!             {
!                 int v4bits;
!                 char *endptr;
!
!                 v4bits=strtol(cidr_slash+1, &endptr, 10);
!                 if (cidr_slash[1]==0 || *endptr!=0 || v4bits<0 || v4bits>32)
!                     goto hba_syntax;
!
!                 v6mask = palloc(20);
!                 sprintf(v6mask, "%d", v4bits+96);
!                 if (SockAddr_cidr_mask(&mask, v6mask, file_ip_addr->ai_family) < 0)
!                     goto hba_syntax;
!             }
!             else
!             {
!                 line = lnext(line);
!                 if (!line)
!                     goto hba_syntax;
!                 token = lfirst(line);
!                 v6mask = palloc(strlen(token)+32);
!                 sprintf(v6mask, "ffff:ffff:ffff:ffff:ffff:ffff:%s", token);
!
!                 ret = getaddrinfo_all(v6mask, NULL, &hints, &file_ip_mask);
!                 if (ret || !file_ip_mask)
!                     goto hba_syntax;
!
!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!                 if (file_ip_addr->ai_family != mask->ss_family)
!                     goto hba_syntax;
!             }
          }
+         else

! #endif // HAVE_IPV6
!
!         if (file_ip_addr->ai_family != port->raddr.addr.ss_family)
          {
!             /* Wrong address family. */
!             freeaddrinfo_all(hints.ai_family, file_ip_addr);
!             return;
          }
          else
          {
!             /* Get the netmask */
!             if (cidr_slash)
!             {
!                 if (SockAddr_cidr_mask(&mask, cidr_slash + 1,
!                                        file_ip_addr->ai_family) < 0)
!                     goto hba_syntax;
!             }
!             else
!             {
!                 /* Read the mask field. */
!                 line = lnext(line);
!                 if (!line)
!                     goto hba_syntax;
!                 token = lfirst(line);
!
!                 ret = getaddrinfo_all(token, NULL, &hints, &file_ip_mask);
!                 if (ret || !file_ip_mask)
!                     goto hba_syntax;
!
!                 mask = (struct sockaddr_storage *) file_ip_mask->ai_addr;
!
!                 if (file_ip_addr->ai_family != mask->ss_family)
!                     goto hba_syntax;
!             }
          }

          /* Read the rest of the line. */

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Tom Lane
Date:
Andreas Pflug <pgadmin@pse-consulting.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

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Andreas Pflug
Date:
Tom Lane wrote:

>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.
>
It SEGVs. Reason is that the memcpy of the promote_v4_to_v6_XXX
functions assumes that the sockaddr_storage is large enough to hold an
IPV6 address, which appears to be not true. Since the struct isn't
created by a plain malloc() and returned by free(), but assembled by
getaddrinfo() according to the family's requirement, I don't see a way
how to fix this. IMHO the struct needs to be created officially by
getaddrinfo(), which will lead more or less the the same solution I
posted previously.

Regards,
Andreas



Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Tom Lane
Date:
Andreas Pflug <pgadmin@pse-consulting.de> writes:
> Tom Lane wrote:
>> 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.
>>
> It SEGVs. Reason is that the memcpy of the promote_v4_to_v6_XXX
> functions assumes that the sockaddr_storage is large enough to hold an
> IPV6 address, which appears to be not true.

Drat.  That didn't happen when I forced it through that path here, but
I guess it could if getaddrinfo is trying to be conservative about the
amount of memory in its return value.  I'll rework it.

> IMHO the struct needs to be created officially by
> getaddrinfo(), which will lead more or less the the same solution I
> posted previously.

No, we just need to use datastructures that are under our control for
the values that will get passed to rangeSockAddr.  A few more lines...

            regards, tom lane

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Andreas Pflug
Date:
Tom Lane wrote:

>
>
>>IMHO the struct needs to be created officially by
>>getaddrinfo(), which will lead more or less the the same solution I
>>posted previously.
>>
>>
>
>No, we just need to use datastructures that are under our control for
>the values that will get passed to rangeSockAddr.  A few more lines...
>
>
>
Hm,

are you sure it's not just for beauty's sake? While talking about
beauty: that setting of *cidr_slash to '/' and 0 doesn't look too
esthetic...

Regards,
Andreas



Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Tom Lane
Date:
Andreas Pflug <pgadmin@pse-consulting.de> writes:
> are you sure it's not just for beauty's sake?

What I didn't like about your last patch was the close coupling of the
CIDR/netmask processing to the v4-to-v6 conversion; as Andrew pointed
out, you were hacking into hba.c functionality that overlapped with
SockAddr_cidr_mask.  Doing the conversion after we've collected the
netmask seems a lot cleaner to me.  Also, this way keeps a fairly decent
separation of interests between hba.c (parsing the hba.conf syntax) and
ip.c (messing with address representations).

> While talking about beauty: that setting of *cidr_slash to '/' and 0
> doesn't look too esthetic...

It is ugly (and I didn't write it ;-)).  But if we palloc'd a modified
version of the token we'd have to remember to pfree it, so it nets out
to about the same amount of code either way I think.  If you wanna try
to clean it up more, be my guest ...

            regards, tom lane

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Date:
Tom Lane said:
> Andreas Pflug <pgadmin@pse-consulting.de> writes:
>> are you sure it's not just for beauty's sake?
>
> What I didn't like about your last patch was the close coupling of the
CIDR/netmask processing to the v4-to-v6 conversion; as Andrew pointed
out,  you were hacking into hba.c functionality that overlapped with
SockAddr_cidr_mask.  Doing the conversion after we've collected the
netmask seems a lot cleaner to me.  Also, this way keeps a fairly decent
separation of interests between hba.c (parsing the hba.conf syntax) and
ip.c (messing with address representations).
>
>> While talking about beauty: that setting of *cidr_slash to '/' and 0
doesn't look too esthetic...
>
> It is ugly (and I didn't write it ;-)).  But if we palloc'd a modified
version of the token we'd have to remember to pfree it, so it nets out to
about the same amount of code either way I think.  If you wanna try to
clean it up more, be my guest ...
>

I wrote it :-) The reason is that alone of the tokens in this file
address/mask is a composite. I agree it is a bit ugly. In fact, this
whole function is ugly and getting uglier and needs recasting. I intend
to have  a go at that, since I am partly responsible, but not in the
present cycle.

Nobody objected when the original patch from Kurt (including my bit) was
submitted, though, so it's a bit late to complain now about aesthetics.

cheers

andrew




Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Bruce Momjian
Date:
Tom Lane wrote:
> Andreas Pflug <pgadmin@pse-consulting.de> writes:
> > are you sure it's not just for beauty's sake?
>
> What I didn't like about your last patch was the close coupling of the
> CIDR/netmask processing to the v4-to-v6 conversion; as Andrew pointed
> out, you were hacking into hba.c functionality that overlapped with
> SockAddr_cidr_mask.  Doing the conversion after we've collected the
> netmask seems a lot cleaner to me.  Also, this way keeps a fairly decent
> separation of interests between hba.c (parsing the hba.conf syntax) and
> ip.c (messing with address representations).
>
> > While talking about beauty: that setting of *cidr_slash to '/' and 0
> > doesn't look too esthetic...
>
> It is ugly (and I didn't write it ;-)).  But if we palloc'd a modified
> version of the token we'd have to remember to pfree it, so it nets out
> to about the same amount of code either way I think.  If you wanna try
> to clean it up more, be my guest ...

Would you like me to conditionally add the IPv6 line to pg_hba.conf from
initdb now?

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Date:
Bruce Momjian said:
>
> Would you like me to conditionally add the IPv6 line to pg_hba.conf
> from initdb now?
>

As a matter of taste and possibly due to some paranoia I would prefer to
see it added unconditionally to pg_hba.conf and conditionally commented
out in initdb. (The paranoia is what says to me that it is better to have
hidden removal of something useless than hidden addition of something
potentially dangerous).

cheers

andrew



Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Bruce Momjian
Date:
andrew@dunslane.net wrote:
> Bruce Momjian said:
> >
> > Would you like me to conditionally add the IPv6 line to pg_hba.conf
> > from initdb now?
> >
>
> As a matter of taste and possibly due to some paranoia I would prefer to
> see it added unconditionally to pg_hba.conf and conditionally commented
> out in initdb. (The paranoia is what says to me that it is better to have
> hidden removal of something useless than hidden addition of something
> potentially dangerous).

So have initdb coditionally comment it out in data/pg_hba.conf --- I can
do that.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Would you like me to conditionally add the IPv6 line to pg_hba.conf from
> initdb now?

I was going to tackle that tomorrow, but if you wanna do it, go for it.

            regards, tom lane

Re: IPV4 addresses on IPV6 machines in pg_hba.conf

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Would you like me to conditionally add the IPv6 line to pg_hba.conf from
> > initdb now?
>
> I was going to tackle that tomorrow, but if you wanna do it, go for it.

No, go ahead.  I wasn't sure if you were waiting for me so I asked.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073