]> granicus.if.org Git - postgresql/commitdiff
Remove code to match IPv4 pg_hba.conf entries to IPv4-in-IPv6 addresses.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Feb 2015 17:49:18 +0000 (12:49 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 17 Feb 2015 17:49:46 +0000 (12:49 -0500)
In investigating yesterday's crash report from Hugo Osvaldo Barrera, I only
looked back as far as commit f3aec2c7f51904e7 where the breakage occurred
(which is why I thought the IPv4-in-IPv6 business was undocumented).  But
actually the logic dates back to commit 3c9bb8886df7d56a and was simply
broken by erroneous refactoring in the later commit.  A bit of archives
excavation shows that we added the whole business in response to a report
that some 2003-era Linux kernels would report IPv4 connections as having
IPv4-in-IPv6 addresses.  The fact that we've had no complaints since 9.0
seems to be sufficient confirmation that no modern kernels do that, so
let's just rip it all out rather than trying to fix it.

Do this in the back branches too, thus essentially deciding that our
effective behavior since 9.0 is correct.  If there are any platforms on
which the kernel reports IPv4-in-IPv6 addresses as such, yesterday's fix
would have made for a subtle and potentially security-sensitive change in
the effective meaning of IPv4 pg_hba.conf entries, which does not seem like
a good thing to do in minor releases.  So let's let the post-9.0 behavior
stand, and change the documentation to match it.

In passing, I failed to resist the temptation to wordsmith the description
of pg_hba.conf IPv4 and IPv6 address entries a bit.  A lot of this text
hasn't been touched since we were IPv4-only.

doc/src/sgml/client-auth.sgml
src/backend/libpq/hba.c
src/backend/libpq/ip.c
src/include/libpq/ip.h

index 33da89c40cd7bd2899ac71c69a91c8355475727f..4f0ede8aa868c11caa35884f57da6df573aff34e 100644 (file)
@@ -222,14 +222,15 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
      <term><replaceable>address</replaceable></term>
      <listitem>
       <para>
-       Specifies the client machine addresses that this record
+       Specifies the client machine address(es) that this record
        matches.  This field can contain either a host name, an IP
        address range, or one of the special key words mentioned below.
       </para>
 
       <para>
-       An IP address is specified in standard dotted decimal
-       notation with a <acronym>CIDR</> mask length.  The mask
+       An IP address range is specified using standard numeric notation
+       for the range's starting address, then a slash (<literal>/</literal>)
+       and a <acronym>CIDR</> mask length.  The mask
        length indicates the number of high-order bits of the client
        IP address that must match.  Bits to the right of this should
        be zero in the given IP address.
@@ -238,25 +239,27 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
       </para>
 
       <para>
-       Typical examples of an IP address range specified this way are
+       Typical examples of an IPv4 address range specified this way are
        <literal>172.20.143.89/32</literal> for a single host, or
        <literal>172.20.143.0/24</literal> for a small network, or
        <literal>10.6.0.0/16</literal> for a larger one.
+       An IPv6 address range might look like <literal>::1/128</literal>
+       for a single host (in this case the IPv6 loopback address) or
+       <literal>fe80::7a31:c1ff:0000:0000/96</literal> for a small
+       network.
        <literal>0.0.0.0/0</literal> represents all
-       IPv4 addresses, and <literal>::/0</literal> represents
+       IPv4 addresses, and <literal>::0/0</literal> represents
        all IPv6 addresses.
-       To specify a single host, use a CIDR mask of 32 for IPv4 or
+       To specify a single host, use a mask length of 32 for IPv4 or
        128 for IPv6.  In a network address, do not omit trailing zeroes.
       </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.
+       An entry given in IPv4 format will match only IPv4 connections,
+       and 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>
@@ -268,7 +271,7 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
 
       <para>
        If a host name is specified (anything that is not an IP address
-       or a special key word is processed as a potential host name),
+       range or a special key word is treated as a host name),
        that name is compared with the result of a reverse name
        resolution of the client's IP address (e.g., reverse DNS
        lookup, if DNS is used).  Host name comparisons are case
@@ -346,8 +349,9 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
      <term><replaceable>IP-mask</replaceable></term>
      <listitem>
       <para>
-       These fields can be used as an alternative to the
-       <replaceable>CIDR-address</replaceable> notation. Instead of
+       These two fields can be used as an alternative to the
+       <replaceable>IP-address</><literal>/</><replaceable>mask-length</>
+       notation.  Instead of
        specifying the mask length, the actual mask is specified in a
        separate column. For example, <literal>255.0.0.0</> represents an IPv4
        CIDR mask length of 8, and <literal>255.255.255.255</> represents a
index ded2837fdf2371f37eb592382074792b6f27d941..688f1282cbf99a55ee9c2e4fad75f153a3f10143 100644 (file)
@@ -686,42 +686,12 @@ check_hostname(hbaPort *port, const char *hostname)
 static bool
 check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
 {
-       if (raddr->addr.ss_family == addr->sa_family)
-       {
-               /* Same address family */
-               if (!pg_range_sockaddr(&raddr->addr,
-                                                          (struct sockaddr_storage *) addr,
-                                                          (struct sockaddr_storage *) mask))
-                       return false;
-       }
-#ifdef HAVE_IPV6
-       else if (addr->sa_family == AF_INET &&
-                        raddr->addr.ss_family == AF_INET6)
-       {
-               /*
-                * If we're connected on IPv6 but the file specifies an IPv4 address
-                * to match against, promote the latter to an IPv6 address before
-                * trying to match the client's address.
-                */
-               struct sockaddr_storage addrcopy,
-                                       maskcopy;
-
-               memcpy(&addrcopy, addr, sizeof(addrcopy));
-               memcpy(&maskcopy, mask, sizeof(maskcopy));
-               pg_promote_v4_to_v6_addr(&addrcopy);
-               pg_promote_v4_to_v6_mask(&maskcopy);
-
-               if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
-                       return false;
-       }
-#endif   /* HAVE_IPV6 */
-       else
-       {
-               /* Wrong address family, no IPV6 */
-               return false;
-       }
-
-       return true;
+       if (raddr->addr.ss_family == addr->sa_family &&
+               pg_range_sockaddr(&raddr->addr,
+                                                 (struct sockaddr_storage *) addr,
+                                                 (struct sockaddr_storage *) mask))
+               return true;
+       return false;
 }
 
 /*
index 6dcaede083aa4d8b3363b99ec66af2eda9af3047..fd80427f38749e4a891192cab7ac2afc36f6ce71 100644 (file)
@@ -407,79 +407,6 @@ pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
 }
 
 
-#ifdef HAVE_IPV6
-
-/*
- * pg_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; be sure it is large enough to
- * hold the result!  Note that we only worry about setting the fields
- * that pg_range_sockaddr will look at.
- */
-void
-pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr)
-{
-       struct sockaddr_in addr4;
-       struct sockaddr_in6 addr6;
-       uint32          ip4addr;
-
-       memcpy(&addr4, addr, sizeof(addr4));
-       ip4addr = 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] = (ip4addr >> 24) & 0xFF;
-       addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
-       addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
-       addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
-
-       memcpy(addr, &addr6, sizeof(addr6));
-}
-
-/*
- * pg_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 pg_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; be sure it is large enough to
- * hold the result!  Note that we only worry about setting the fields
- * that pg_range_sockaddr will look at.
- */
-void
-pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr)
-{
-       struct sockaddr_in addr4;
-       struct sockaddr_in6 addr6;
-       uint32          ip4addr;
-       int                     i;
-
-       memcpy(&addr4, addr, sizeof(addr4));
-       ip4addr = 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] = (ip4addr >> 24) & 0xFF;
-       addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
-       addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
-       addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
-
-       memcpy(addr, &addr6, sizeof(addr6));
-}
-#endif   /* HAVE_IPV6 */
-
-
 /*
  * Run the callback function for the addr/mask, after making sure the
  * mask is sane for the addr.
index 149c1ff9b48423a11a315d026a7506b891f4c3f9..4946b3b7a6715ba276d2a35e30a0ecb6183653d9 100644 (file)
@@ -46,11 +46,6 @@ extern int pg_range_sockaddr(const struct sockaddr_storage * addr,
 extern int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask,
                                          char *numbits, int family);
 
-#ifdef HAVE_IPV6
-extern void pg_promote_v4_to_v6_addr(struct sockaddr_storage * addr);
-extern void pg_promote_v4_to_v6_mask(struct sockaddr_storage * addr);
-#endif
-
 extern int     pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data);
 
 #endif   /* IP_H */