diff --git a/RELNOTES b/RELNOTES index 1b234329..55de1144 100644 --- a/RELNOTES +++ b/RELNOTES @@ -54,6 +54,9 @@ suggested fixes to . 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. diff --git a/common/inet.c b/common/inet.c index 36dcf0f1..4f8f1182 100644 --- a/common/inet.c +++ b/common/inet.c @@ -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 * diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 87209547..9735bdf3 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -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); diff --git a/server/confpars.c b/server/confpars.c index c4fb0134..38361920 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -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);