Here is a patch that allows CIDR netmasks in pg_hba.conf. It allows two
authorBruce Momjian
Thu, 12 Jun 2003 02:12:58 +0000 (02:12 +0000)
committerBruce Momjian
Thu, 12 Jun 2003 02:12:58 +0000 (02:12 +0000)
address/mask forms:

. address/maskbits, or
. address netmask (as now)

If the patch is accepted I will submit a documentation patch to cover
it.

This is submitted by agreement with Kurt Roeckx, who has worked on a
patch that covers this and other IPv6 issues.

Andrew Dunstan

src/backend/libpq/hba.c
src/backend/libpq/ip.c
src/include/libpq/ip.h

index f722bb52716199853055a05393916935ca0beb59..6d4da21cfb983423856f36afc6ef1c67ffbefb81 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.100 2003/04/25 01:24:00 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.101 2003/06/12 02:12:58 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -588,6 +588,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
    else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
    {
        SockAddr file_ip_addr, mask;
+       char * cidr_slash;
 
        if (strcmp(token, "hostssl") == 0)
        {
@@ -618,26 +619,48 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
            goto hba_syntax;
        user = lfirst(line);
 
-       /* Read the IP address field. */
+       /* Read the IP address field. (with or without CIDR netmask) */
        line = lnext(line);
        if (!line)
            goto hba_syntax;
        token = lfirst(line);
 
+       /* Check if it has a CIDR suffix and if so isolate it */
+       cidr_slash = strchr(token,'/');
+       if (cidr_slash)
+           *cidr_slash = '\0';
+
+       /* Get the IP address either way */
        if(SockAddr_pton(&file_ip_addr, token) < 0)
+       {
+           if (cidr_slash)
+               *cidr_slash = '/';
            goto hba_syntax;
+       }
 
-       /* Read the mask field. */
-       line = lnext(line);
-       if (!line)
-           goto hba_syntax;
-       token = lfirst(line);
+       /* Get the netmask */
+       if (cidr_slash)
+       {
+           *cidr_slash = '/';
+           if (SockAddr_cidr_mask(&mask, ++cidr_slash, file_ip_addr.sa.sa_family) < 0)
+               goto hba_syntax;
+       }
+       else
+       {
+           /* Read the mask field. */
+           line = lnext(line);
+           if (!line)
+               goto hba_syntax;
+           token = lfirst(line);
+
+           if(SockAddr_pton(&mask, token) < 0)
+               goto hba_syntax;
+
+           if(file_ip_addr.sa.sa_family != mask.sa.sa_family)
+               goto hba_syntax;
+       }
 
-       if(SockAddr_pton(&mask, token) < 0)
-           goto hba_syntax;
 
-       if(file_ip_addr.sa.sa_family != mask.sa.sa_family)
-           goto hba_syntax;
 
        /* Read the rest of the line. */
        line = lnext(line);
index 948fb5761414abd3bcb87ac55ffca1ae00557ccd..2573829fd8873b8896b067c7e1b829e214868003 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.9 2003/06/09 17:59:19 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.10 2003/06/12 02:12:58 momjian Exp $
  *
  * This file and the IPV6 implementation were initially provided by
  * Nigel Kukard , Linux Based Systems Design
@@ -251,6 +251,59 @@ SockAddr_pton(SockAddr *sa, const char *src)
    }
 }
 
+/*
+ *  SockAddr_cidr_mask - make a network mask of the appropriate family
+ *    and required number of significant bits
+ */
+
+int
+SockAddr_cidr_mask(SockAddr *mask, char *numbits, int family)
+{
+   int i;
+   long bits;
+   char * endptr;
+
+   bits = strtol(numbits,&endptr,10);
+
+   if (*numbits == '\0' || *endptr != '\0')
+       return -1;
+
+
+   if ((bits < 0) || (family == AF_INET && bits > 32)
+#ifdef HAVE_IPV6
+       || (family == AF_INET6 && bits > 128)
+#endif
+       )
+       return -1;
+
+   mask->sa.sa_family = family;
+
+   switch (family)
+   {
+       case AF_INET:
+           mask->in.sin_addr.s_addr = htonl((0xffffffffUL << (32 - bits)) & 0xffffffffUL);
+           break;
+#ifdef HAVE_IPV6
+       case AF_INET6:  
+           for (i = 0; i < 16; i++)
+           {
+               if (bits <= 0)
+                   mask->in6.sin6_addr.s6_addr[i]=0;
+               else if (bits >= 8)
+                   mask->in6.sin6_addr.s6_addr[i]=0xff;
+               else
+                   mask->in6.sin6_addr.s6_addr[i]=(0xff << (8 - bits)) & 0xff;
+               bits -= 8;
+
+           }
+           break;
+#endif
+       default:
+           return -1;
+   }
+   return 0;
+
+}
 
 /*
  * isAF_INETx - check to see if sa is AF_INET or AF_INET6
index 7e910d5cbb2796a96762febc597d8d9d55180859..a6128e213ea9a5df9f08b34288bc2375b85b4f1f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2003, PostgreSQL Global Development Group
  *
- * $Id: ip.h,v 1.5 2003/06/09 17:59:19 tgl Exp $
+ * $Id: ip.h,v 1.6 2003/06/12 02:12:58 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,6 +25,8 @@ extern char *SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt,
                           int v4conv);
 extern int   SockAddr_pton(SockAddr *sa, const char *src);
 
+extern int SockAddr_cidr_mask(SockAddr *mask, char *numbits, int family);
+
 extern int   isAF_INETx(const int family);
 extern int   rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr,
                           const SockAddr *netmask);