]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Check for valid prefixes in configuration.
authorShane Kerr <shane@isc.org>
Tue, 19 Jun 2007 17:06:03 +0000 (17:06 +0000)
committerShane Kerr <shane@isc.org>
Tue, 19 Jun 2007 17:06:03 +0000 (17:06 +0000)
See RT ticket #16944 for more information.

RELNOTES
common/inet.c
includes/dhcpd.h
server/confpars.c

index 1b23432938ead37e081095c18783293108ef3e47..55de1144238504623d0b180a7ced8de15c98d634 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -54,6 +54,9 @@ suggested fixes to <dhcp-users@isc.org>.
 
                        Changes since 4.0.0a1
 
+- Invalid CIDR representation for IPv6 subnets or ranges now checked
+  for when loading configuration.
+
 - Compilation on HP/UX has been repaired.  The changes should generally
   apply to any architecture that supplies SIOCGLIFCONF but does not
   use 'struct lifconf' structures to pass values.
index 36dcf0f1f81c9728511d0d05d675b19b05cbcdfc..4f8f11829cb21da4fed0fa3abd801df61d380ab5 100644 (file)
@@ -35,7 +35,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: inet.c,v 1.13 2007/05/19 19:16:24 dhankins Exp $ Copyright (c) 2004,2005,2007 Internet Systems Consortium.  All rights reserved.\n";
+"$Id: inet.c,v 1.14 2007/06/19 17:06:03 shane Exp $ Copyright (c) 2004,2005,2007 Internet Systems Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -297,6 +297,66 @@ addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) {
        return !all_zero;
 }
 
+/*
+ * Check if a bitmask of the given length is valid for the address.
+ * This is not the case if any bits longer than the bitmask are 1.
+ *
+ * So, this is valid:
+ *
+ * 127.0.0.0/8
+ *
+ * But this is not:
+ *
+ * 127.0.0.1/8
+ *
+ * Because the final ".1" would get masked out by the /8.
+ */
+isc_boolean_t
+is_cidr_mask_valid(const struct iaddr *addr, int bits) {
+       int zero_bits;
+       int zero_bytes;
+       int i;
+       char byte;
+       int shift_bits;
+
+       /*
+        * Check our bit boundaries.
+        */
+       if (bits < 0) {
+               return ISC_FALSE;
+       }
+       if (bits > (addr->len * 8)) {
+               return ISC_FALSE;
+       }
+
+       /*
+        * Figure out how many low-order bits need to be zero.
+        */
+       zero_bits = (addr->len * 8) - bits;
+       zero_bytes = zero_bits / 8;
+
+       /* 
+        * Check to make sure the low-order bytes are zero.
+        */
+       for (i=1; i<=zero_bytes; i++) {
+               if (addr->iabuf[addr->len-i] != 0) {
+                       return ISC_FALSE;
+               }
+       }
+
+       /* 
+        * Look to see if any bits not in right-hand bytes are 
+        * non-zero, by making a byte that has these bits set to zero 
+        * comparing to the original byte. If these two values are 
+        * equal, then the right-hand bits are zero, and we are 
+        * happy.
+        */
+       shift_bits = zero_bits % 8;
+       if (shift_bits == 0) return ISC_TRUE;
+       byte = addr->iabuf[addr->len-zero_bytes-1];
+       return (((byte >> shift_bits) << shift_bits) == byte);
+}
+
 /*
  * range2cidr
  *
index 87209547b7e87dbb2d287c9d3feb0f3120d1ebe5..9735bdf33c1bdbb771c5037404f3ece89955e827 100644 (file)
@@ -2321,6 +2321,7 @@ int addr_or(struct iaddr *result,
            const struct iaddr *a1, const struct iaddr *a2);
 int addr_and(struct iaddr *result, 
             const struct iaddr *a1, const struct iaddr *a2);
+isc_boolean_t is_cidr_mask_valid(const struct iaddr *addr, int bits);
 isc_result_t range2cidr(struct iaddrcidrnetlist **result,
                        const struct iaddr *lo, const struct iaddr *hi);
 isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result);
index c4fb0134e7d013e876730418f68c69931044780d..383619202bc65f36fa64ea819c24974c93f5866f 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: confpars.c,v 1.167 2007/06/08 14:58:20 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium.  All rights reserved.\n";
+"$Id: confpars.c,v 1.168 2007/06/19 17:06:03 shane Exp $ Copyright (c) 2004-2007 Internet Systems Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -2640,6 +2640,12 @@ parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
                return;
        }
 
+       if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
+               parse_warn(cfile, "New subnet mask too short.");
+               skip_to_semi(cfile);
+               return;
+       }
+
        /* 
         * Create a netmask. 
         */
@@ -3703,6 +3709,11 @@ parse_address_range6(struct parse *cfile, struct group *group) {
                        skip_to_semi(cfile);
                        return;
                }
+               if (!is_cidr_mask_valid(&lo, bits)) {
+                       parse_warn(cfile, "network mask too short");
+                       skip_to_semi(cfile);
+                       return;
+               }
 
                add_ipv6_pool_to_shared_network(share, &lo, bits);