BIND 10 trac998, updated. ebb6493b8ff763d42fe99438c8befe48c381b4aa [trac998] Minor format changes

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Jun 22 20:11:15 UTC 2011


The branch, trac998 has been updated
       via  ebb6493b8ff763d42fe99438c8befe48c381b4aa (commit)
       via  c786a61641a965545c2e304b1c946afdedc6dc1a (commit)
       via  e5251c4886f626e6ef9f6ba82771c0e949e0071f (commit)
       via  792c8b202cffc8fed726f10b3514523b1fc92469 (commit)
       via  8c624c6644563ed9c4fecec8b0b5f5dd115fe7ef (commit)
       via  d1c7f98e910bd19d21a649386f1a8066e4f41677 (commit)
       via  a90c8a06056300e0f9f5ffdae72b8a2ba26346fc (commit)
       via  30570ab2d917dc6adec02ba272ee50c17124b688 (commit)
       via  59908b70a929baf829202197d6e7ab5a3557da32 (commit)
       via  585d1c63d6d0126607f424571e38a4a60683cf4b (commit)
       via  d335ae50bb855b7b302dab852005385c0227dcfb (commit)
       via  8034dbfe87c45eaa2c0aef0e715b86fa79a7c4e3 (commit)
       via  0ddf0f5fa4d9d18599a1642b9f87caaa1f463c5e (commit)
       via  5a75094dfdd5f2307c4a1669e05db70355b08682 (commit)
       via  df5bad72ac8dac07a038f29823a1938bc9bbe72c (commit)
      from  6c5a9b252b7bc062ed807aff342d0314811b5bde (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ebb6493b8ff763d42fe99438c8befe48c381b4aa
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 20:59:44 2011 +0100

    [trac998] Minor format changes

commit c786a61641a965545c2e304b1c946afdedc6dc1a
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 20:53:21 2011 +0100

    [trac998] Remove prefixlen_; calculate it when getPrefix() is called

commit e5251c4886f626e6ef9f6ba82771c0e949e0071f
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 20:30:26 2011 +0100

    [trac998] Get rid of string address.  Pass address family to compare()

commit 792c8b202cffc8fed726f10b3514523b1fc92469
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 19:55:46 2011 +0100

    [trac998] Get rid of union statement

commit 8c624c6644563ed9c4fecec8b0b5f5dd115fe7ef
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 18:12:49 2011 +0100

    [trac998] Rename getNetmask() to getMask()

commit d1c7f98e910bd19d21a649386f1a8066e4f41677
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 18:11:24 2011 +0100

    [trac998] Remove unneeded copy constructor and assignment operator

commit a90c8a06056300e0f9f5ffdae72b8a2ba26346fc
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 18:01:29 2011 +0100

    [trac998] Catch problem with inet_pton failing with value of -1

commit 30570ab2d917dc6adec02ba272ee50c17124b688
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 17:59:33 2011 +0100

    [trac998] Remove "inverse" argument

commit 59908b70a929baf829202197d6e7ab5a3557da32
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 17:36:47 2011 +0100

    [trac998] Change "addrmask" nasm to ipprefix

commit 585d1c63d6d0126607f424571e38a4a60683cf4b
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 17:32:06 2011 +0100

    [trac998] Move splitIPAddress into .cc file

commit d335ae50bb855b7b302dab852005385c0227dcfb
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 17:22:33 2011 +0100

    [trac998] Fix problems with address strings of "1/" etc.

commit 8034dbfe87c45eaa2c0aef0e715b86fa79a7c4e3
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 16:54:50 2011 +0100

    [trac998] Renamed createNetmask to internal::createMask

commit 0ddf0f5fa4d9d18599a1642b9f87caaa1f463c5e
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 16:49:12 2011 +0100

    [trac998] Add tests for the any4/any6 modifications

commit 5a75094dfdd5f2307c4a1669e05db70355b08682
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 16:39:36 2011 +0100

    [trac998] Add any4 and any6 as valid address prefixes

commit df5bad72ac8dac07a038f29823a1938bc9bbe72c
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Jun 22 16:26:20 2011 +0100

    [trac998] Replaced "netmask" terminology with "prefix"

-----------------------------------------------------------------------

Summary of changes:
 src/lib/acl/Makefile.am                |   25 ++-
 src/lib/acl/ip_check.cc                |   79 ++++++
 src/lib/acl/ip_check.h                 |  456 ++++++++++++++------------------
 src/lib/acl/tests/Makefile.am          |    1 +
 src/lib/acl/tests/ip_check_unittest.cc |  345 ++++++++++++------------
 5 files changed, 469 insertions(+), 437 deletions(-)
 create mode 100644 src/lib/acl/ip_check.cc

-----------------------------------------------------------------------
diff --git a/src/lib/acl/Makefile.am b/src/lib/acl/Makefile.am
index 1fc464a..f7bee9b 100644
--- a/src/lib/acl/Makefile.am
+++ b/src/lib/acl/Makefile.am
@@ -1,6 +1,23 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
-EXTRA_DIST = check.h ip_check.h
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util
 
-# TODO: Once we have some cc file we are able to compile, create the library.
-# For now, we have only header files, not creating empty library.
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libacl.la
+libacl_la_SOURCES  = check.h
+libacl_la_SOURCES += ip_check.h ip_check.cc
+
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+libacl_la_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+libacl_la_CXXFLAGS += -Wno-error
+endif
+libacl_la_CPPFLAGS = $(AM_CPPFLAGS)
+libacl_la_LIBADD = $(top_builddir)/src/lib/util/libutil.la
diff --git a/src/lib/acl/ip_check.cc b/src/lib/acl/ip_check.cc
new file mode 100644
index 0000000..b6d6276
--- /dev/null
+++ b/src/lib/acl/ip_check.cc
@@ -0,0 +1,79 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <acl/ip_check.h>
+#include <util/strutil.h>
+
+using namespace std;
+
+// Split the IP Address prefix
+
+namespace isc {
+namespace acl {
+namespace internal {
+
+pair<string, int>
+splitIPAddress(const string& ipprefix) {
+
+    // Set the default value for the prefix length.  As the type of the address
+    // is not known at the point this function is called, the maximum
+    // allowable value is also not known.  And the value of 0 is reserved for
+    // a "match any address" match.
+    int prefix_size = -1;
+
+    // Only deal with the string after we've removed leading and trailing
+    // spaces.
+    string mod_prefix = isc::util::str::trim(ipprefix);
+
+    // Split string into its components - an address and a prefix length.
+    // We initialize by assuming that there is no slash in the string given.
+    string address = mod_prefix;
+    string prefixlen = "";
+
+    size_t slashpos = mod_prefix.find('/');
+    if ((mod_prefix.size() == 0) || (slashpos == 0) ||
+        (slashpos == (mod_prefix.size() - 1))) {
+        // Nothing in prefix, or it starts with or ends with a slash.
+        isc_throw(isc::InvalidParameter, "address prefix of " << ipprefix <<
+                                         " is not valid");
+
+    } else if (slashpos != string::npos) {
+        // There is a slash somewhere in the string, split the string on it.
+        // Don't worry about multiple slashes - if there are some, they will
+        // appear in the prefixlen segment and will be detected when an attempt
+        // is made to convert it to a number.
+        address = mod_prefix.substr(0, slashpos);
+        prefixlen = mod_prefix.substr(slashpos + 1);
+    }
+
+    // If there is a prefixlength, attempt to convert it.
+    if (!prefixlen.empty()) {
+        try {
+            prefix_size = boost::lexical_cast<int>(prefixlen);
+            if (prefix_size < 0) {
+                isc_throw(isc::InvalidParameter, "address prefix of " <<
+                          ipprefix << " is not valid");
+            }
+        } catch (boost::bad_lexical_cast&) {
+            isc_throw(isc::InvalidParameter, "prefix length of " << prefixlen <<
+                                             " is not valid");
+        }
+    }
+
+    return (make_pair(address, prefix_size));
+}
+
+} // namespace internal
+} // namespace acl
+} // namespace isc
diff --git a/src/lib/acl/ip_check.h b/src/lib/acl/ip_check.h
index 0511832..bdd546a 100644
--- a/src/lib/acl/ip_check.h
+++ b/src/lib/acl/ip_check.h
@@ -15,7 +15,7 @@
 #ifndef __IP_CHECK_H
 #define __IP_CHECK_H
 
-#include <cassert>
+#include <algorithm>
 #include <functional>
 #include <iterator>
 #include <utility>
@@ -30,44 +30,46 @@
 #include <netinet/in.h>
 
 #include <acl/check.h>
-#include <util/strutil.h>
 #include <exceptions/exceptions.h>
 
 namespace isc {
 namespace acl {
 
-// Free functions
+// Free functions.  These are not supposed to be used outside this module,
+// but are declared public for testing.  To try to conceal them, they are
+// put in an "internal" namespace.
 
-/// \brief Convert mask size to mask
+namespace internal {
+
+/// \brief Convert prefix length to mask
 ///
-/// Given a mask size and a data type, return a value of that data type with the
-/// most significant "masksize" bits set.  For example, if the data type is an
-/// uint8_t and the masksize is 3, the function would return a uint8_t holding
-/// the binary value 11100000.
+/// Given a prefix length and a data type, return a value of that data type
+/// with the most significant "prefix length" bits set.  For example, if the
+/// data type is an uint8_t and the p[refix length is 3, the function would
+/// return a uint8_t holding the binary value 11100000.  This value is used as
+/// a mask in the address checks.
 ///
 /// The function is templated on the data type of the mask.
 ///
-/// \param masksize Size of the mask.  This must be between 0 and 8*sizeof(T).
-///        An out of range exception is thrown if this is not the case.
+/// \param prefixlen number of bits to be set in the mask.  This must be
+///        between 0 and 8*sizeof(T).
+///
+/// \return Value with the most significant "prefixlen" bits set.
 ///
-/// \return Value with the most significant "masksize" bits set.
+/// \exception OutOfRange prefixlen is too large for the data type.
 
 template <typename T>
-T createNetmask(size_t masksize) {
+T createMask(size_t prefixlen) {
 
-    if (masksize == 0) {
-
-        // Although a mask size of zero is invalid for the IP ACL check
-        // specification, it simplifies logic elsewhere if this function is
-        // allowed to handle a mask size of 0.
+    if (prefixlen == 0) {
         return (0);
 
-    } else if (masksize <= 8 * sizeof(T)) {
+    } else if (prefixlen <= 8 * sizeof(T)) {
 
         // In the following discussion:
         //
         // w is the width of the data type T in bits.
-        // m is the value of masksize, the number of most signifcant bits we
+        // m is the value of prefixlen, the number of most signifcant bits we
         // want to set.
         // ** is exponentiation (i.e. 2**n is 2 raised to the power of n).
         //
@@ -79,87 +81,50 @@ T createNetmask(size_t masksize) {
         // w-m bits set and the most significant m bits clear.  The 1's
         // complement of this value gives is the result we want.
         //
-        // Final note: at this point in the logic, m is non-zero, so w-m < m.
+        // Final note: at this point in the logic, m is non-zero, so w-m < w.
         // This means 1<<(w-m) will fit into a variable of width w bits.  In
         // other words, in the expression below, no term will cause an integer
         // overflow.
-        return (~((1 << (8 * sizeof(T) - masksize)) - 1));
+        return (~((1 << (8 * sizeof(T) - prefixlen)) - 1));
     }
 
-    // Mask size is too large. (Note that masksize is unsigned, so can't be
+    // Mask size is too large. (Note that prefixlen is unsigned, so can't be
     // negative.)
-    isc_throw(isc::OutOfRange, "masksize argument must be between 0 and " <<
+    isc_throw(isc::OutOfRange, "prefixlen argument must be between 0 and " <<
                                8 * sizeof(T));
 }
 
-/// \brief Split IP Address
+/// \brief Split IP Address Prefix
 ///
-/// Splits an IP address (given in the form of "xxxxxx/n" or "xxxxx" into a
-/// string representing the IP address and a number giving the size of the
-/// network mask in bits. (In the latter case, the size of the network mask is
-/// equal to the width of the data type holding the address.) An exception will
-/// be thrown if the string format is invalid or if the network mask size is not
-/// an integer.
+/// Splits an IP address prefix (given in the form of "xxxxxx/n" or "xxxxx" into
+/// a string representing the IP address and a number giving the length of the
+/// prefix. (In the latter case, the prefix is equal in length to the width in
+/// width in bits of the data type holding the address.) An exception will
+/// be thrown if the string format is invalid or if the prefix length is
+/// invalid.
 ///
 /// N.B. This function does NOT check that the address component is a valid IP
 /// address; this is done elsewhere in the address parsing process.
 ///
-/// \param addrmask Address and/or address/mask.  The string should be passed
+/// \param ipprefix Address or address prefix.  The string should be passed
 ///                 without leading or trailing spaces.
 ///
-/// \return Pair of (string, int) holding the address string and the mask
-///         size value.  The second element is -1 if no mask was given.
+/// \return Pair of (string, int) holding the address string and the prefix
+///         length.  The second element is -1 if no prefix was given.
+// definitions and te/
+/// \exception InvalidParameter Address prefix not of the expected syntax
 
 std::pair<std::string, int>
-splitIPAddress(const std::string& addrmask) {
-
-    // Set the default value for the mask size
-    int masksize = -1;
-
-    // Split string into its components.  As the tokenising code ignores
-    // leading, trailing nd consecutive delimiters, be strict here and ensures
-    // that the string contains at most 0 or 1 slashes.
-    if (std::count(addrmask.begin(), addrmask.end(), '/') > 1) {
-        isc_throw(isc::InvalidParameter, "address/masksize of " <<
-                  addrmask << " is not valid");
-    }
-
-    std::vector<std::string> components = isc::util::str::tokens(addrmask, "/");
-    if (components.size() == 2) {
-
-        // There appears to be a mask, try converting it to a number.
-        try {
-            masksize = boost::lexical_cast<int>(components[1]);
-        } catch (boost::bad_lexical_cast&) {
-            isc_throw(isc::InvalidParameter,
-                      "mask size specified in address/masksize " << addrmask <<
-                      " is not valid");
-        }
-
-        // Ensure that it is positive - a mask size of zero is not a valid
-        // value.
-        if (masksize <= 0) {
-            isc_throw(isc::OutOfRange,
-                      "mask size specified in address/masksize " << addrmask <<
-                      " must be a positive number");
-        }
-
-    } else if (components.size() > 2) {
-        isc_throw(isc::InvalidParameter, "address/masksize of " <<
-                  addrmask << " is not valid");
-    }
+splitIPAddress(const std::string& ipprefix);
 
-    return (std::make_pair(components[0], masksize));
-}
+} // namespace internal
 
 
 
 /// \brief IP Check
 ///
-/// This class performs a match between an IP address specified in an ACL
-/// (IP address, network mask and a flag indicating whether the check should
-/// be for a match or for a non-match) and a given IP address.  The check
-/// works for both IPV4 and IPV6 addresses.
+/// This class performs a match between an IP address prefix specified in an ACL
+/// and a given IP address.  The check works for both IPV4 and IPV6 addresses.
 ///
 /// The class is templated on the type of a context structure passed to the
 /// matches() method, and a template specialisation for that method must be
@@ -168,153 +133,120 @@ splitIPAddress(const std::string& addrmask) {
 template <typename Context>
 class IPCheck : public Check<Context> {
 private:
-    // Size of uint8_t array to hold an IPV6 address, and size of a 32-bit word
-    // equivalent.
-    static const size_t IPV6_SIZE8 = sizeof(struct in6_addr);
-    static const size_t IPV6_SIZE32 = IPV6_SIZE8 / 4;
-
-    // Data type to hold the address, regardless of the address family.  The
-    // union allows an IPV4 address to be treated as a sequence of bytes when
-    // necessary.
-    union AddressData {
-        uint32_t    word[IPV6_SIZE32];      ///< Address in 32-bit words
-        uint8_t     byte[IPV6_SIZE8];       ///< Address in 8-bit bytes
-    };
+    // Size of uint8_t array to holds different address types
+    static const size_t IPV6_SIZE = sizeof(struct in6_addr);
+    static const size_t IPV4_SIZE = sizeof(struct in_addr);
 
 public:
     /// \brief Default Constructor
     ///
     /// Constructs an empty IPCheck object.  The address family returned will
     /// be zero.
-    IPCheck() : address_(), netmask_(), masksize_(0), inverse_(false),
-                family_(0), straddr_()
-    {
-        std::fill(address_.word, address_.word + IPV6_SIZE32, 0);
-        std::fill(netmask_.word, netmask_.word + IPV6_SIZE32, 0);
-    }
+    IPCheck() : address_(), mask_(), family_(0)
+    {}
 
     /// \brief IPV4 Constructor
     ///
     /// Constructs an IPCheck object from a network address given as a
-    /// 32-bit value in network byte order.
+    /// 32-bit value in network byte order and a prefix length.
     ///
-    /// \param address IP address to check for (as an address in network-byte
-    ///        order).
-    /// \param mask The network mask specified as an integer between 1 and
-    ///        32. This determines the number of bits in the mask to check.
-    ///        An exception will be thrown if the number is not within these
-    ///        bounds.
-    /// \param inverse If false (the default), matches() returns true if the
-    ///        condition matches.  If true, matches() returns true if the
-    ///        condition does not match.
-    IPCheck(uint32_t address, int masksize = 8 * sizeof(uint32_t),
-            bool inverse = false):
-            address_(), netmask_(), masksize_(masksize), inverse_(inverse),
-            family_(AF_INET), straddr_()
+    /// \param address IP address to check for (as an address in host-byte
+    ///        order).  N.B.  Unlike the IPV6 constructor, this is in host
+    ///        byte order.
+    /// \param prefixlen The prefix length specified as an integer between 0 and
+    ///        32. This determines the number of bits of the address to check.
+    ///        (A value of zero imples match all IPV4 addresses.)
+    IPCheck(uint32_t address, int prefixlen = 8 * IPV4_SIZE) :
+            address_(IPV4_SIZE), mask_(), family_(AF_INET)
     {
-        address_.word[0] = address;
-        std::fill(address_.word + 1, address_.word + IPV6_SIZE32, 0);
-        std::fill(netmask_.word, netmask_.word + IPV6_SIZE32, 0);
-        setNetmask(masksize_);
+        // The address is stored in network-byte order, so the
+        // the address passed should be stored at the lowest address in
+        // the array.
+        address_[3] = static_cast<uint8_t>((address      ) & 0xff);
+        address_[2] = static_cast<uint8_t>((address >>  8) & 0xff);
+        address_[1] = static_cast<uint8_t>((address >> 16) & 0xff);
+        address_[0] = static_cast<uint8_t>((address >> 24) & 0xff);
+
+        setMask(prefixlen);
     }
 
     /// \brief IPV6 Constructor
     ///
     /// Constructs an IPv6 Check object from a network address given as a
-    /// 16-byte array in network-byte order.
+    /// 16-byte array in network-byte order and a prefix length.
     ///
     /// \param address IP address to check for (as an address in network-byte
     ///        order).
     /// \param mask The network mask specified as an integer between 1 and
     ///        128 This determines the number of bits in the mask to check.
-    ///        An exception will be thrown if the number is not within these
-    ///        bounds.
-    /// \param inverse If false (the default), matches() returns true if the
-    ///        condition matches.  If true, matches() returns true if the
-    ///        condition does not match.
-    IPCheck(const uint8_t* address, int masksize = 8 * IPV6_SIZE8,
-            bool inverse = false):
-            address_(), netmask_(), masksize_(masksize), inverse_(inverse),
-            family_(AF_INET6), straddr_()
+    IPCheck(const uint8_t* address, int prefixlen = 8 * IPV6_SIZE) :
+            address_(address, address + IPV6_SIZE), mask_(), family_(AF_INET6)
     {
-        std::copy(address, address + IPV6_SIZE8, address_.byte);
-        std::fill(netmask_.word, netmask_.word + IPV6_SIZE32, 0);
-        setNetmask(masksize_);
+
+        setMask(prefixlen);
     }
 
     /// \brief String Constructor
     ///
-    /// Constructs an IP Check object from a network address and size of mask
-    /// given as a string of the form <ip-address>/n".
+    /// Constructs an IP Check object from an address or address prefix in the
+    /// form <ip-address>/n".
     ///
-    /// \param address IP address and netmask in the form "<ip-address>/n"
+    /// Also allowed are the special keywords "any4" and "any6", which match
+    /// any IPV4 or IPV6 address.  These must be specified exactly as-is
+    /// (i.e. lowercase, with no leading or trailing spaces).
+    ///
+    /// \param addrprfx IP address prefix in the form "<ip-address>/n"
     ///        (where the "/n" part is optional and should be valid for the
-    ///        address).
-    /// \param inverse If false (the default), matches() returns true if the
-    ///        condition matches.  If true, matches() returns true if the
-    ///        condition does not match.
-    IPCheck(const std::string& address, bool inverse = false) :
-            address_(), netmask_(), masksize_(0), inverse_(inverse),
-            family_(0), straddr_(address)
+    ///        address).  If "n" is specified as zero, the match is for any
+    ///        address in that address family.  The address can also be
+    ///        given as "any4" or "any6".
+    IPCheck(const std::string& addrprfx) : address_(), mask_(), family_(0)
     {
-        // Initialize.
-        std::fill(address_.word, address_.word + IPV6_SIZE32, 0);
-        std::fill(netmask_.word, netmask_.word + IPV6_SIZE32, 0);
+        // Check for special cases first.
+        if (addrprfx == "any4") {
+            family_ = AF_INET;
 
-        // Split the address into address part and mask.
-        std::pair<std::string, int> result = splitIPAddress(address);
+        } else if (addrprfx == "any6") {
+            family_ = AF_INET6;
 
-        // Try to convert the address.  If successful, the result is in
-        // network-byte order (most significant components at lower addresses).
-        family_ = AF_INET6;
-        int status = inet_pton(AF_INET6, result.first.c_str(), address_.byte);
-        if (status == 0) {
+        } else {
 
-            // Not IPV6, try IPv4
-            family_ = AF_INET;
-            int status = inet_pton(AF_INET, result.first.c_str(),
-                                   address_.word);
-            if (status == 0) {
-                isc_throw(isc::InvalidParameter, "address/masksize of " <<
-                          address << " is not valid IP address");
+            // General address prefix.  Split into address part and prefix
+            // length.
+            std::pair<std::string, int> result =
+                internal::splitIPAddress(addrprfx);
+
+            // Try to convert the address.  If successful, the result is in
+            // network-byte order (most significant components at lower
+            // addresses).
+            BOOST_STATIC_ASSERT(IPV6_SIZE > IPV4_SIZE);
+            uint8_t address_bytes[IPV6_SIZE];
+            int status = inet_pton(AF_INET6, result.first.c_str(),
+                                   address_bytes);
+            if (status == 1) {
+                // It was an IPV6 address, copy into the address store
+                std::copy(address_bytes, address_bytes + IPV6_SIZE,
+                          std::back_inserter(address_));
+                family_ = AF_INET6;
+
+            } else {
+                // Not IPV6, try IPv4
+                int status = inet_pton(AF_INET, result.first.c_str(),
+                                       address_bytes);
+                if (status == 1) {
+                    std::copy(address_bytes, address_bytes + IPV4_SIZE,
+                              std::back_inserter(address_));
+                    family_ = AF_INET;
+
+                } else {
+                    isc_throw(isc::InvalidParameter, "address prefix of " <<
+                              result.first << " is a not valid");
+                }
             }
-        }
 
-        // All done, so set the network mask.
-        setNetmask(result.second);
-    }
-
-    /// \brief Copy constructor
-    ///
-    /// \param other Object from which the copy is being constructed.
-    IPCheck(const IPCheck<Context>& other) : address_(), netmask_(),
-            masksize_(other.masksize_), inverse_(other.inverse_),
-            family_(other.family_), straddr_(other.straddr_)
-    {
-        std::copy(other.address_.word, other.address_.word + IPV6_SIZE32,
-                  address_.word);
-        std::copy(other.netmask_.word, other.netmask_.word + IPV6_SIZE32,
-                  netmask_.word);
-    }
-
-    /// \brief Assignment operator
-    ///
-    /// \param other Source of the assignment.
-    ///
-    /// \return Reference to current object.
-    IPCheck& operator=(const IPCheck<Context>& other) {
-        if (this != &other) {
-            Check<Context>::operator=(other);
-            std::copy(other.address_.word, other.address_.word + IPV6_SIZE32,
-                      address_.word);
-            std::copy(other.netmask_.word, other.netmask_.word + IPV6_SIZE32,
-                      netmask_.word);
-            masksize_ = other.masksize_;
-            inverse_ = other.inverse_;
-            family_ = other.family_;
-            straddr_ = other.straddr_;
+            // All done, so set the mask used in checking.
+            setMask(result.second);
         }
-        return (*this);
     }
 
     /// \brief Destructor
@@ -337,7 +269,7 @@ public:
     ///
     /// \return Estimated cost of the comparison
     virtual unsigned cost() const {
-        return ((family_ == AF_INET) ? 1 : IPV6_SIZE32);
+        return ((family_ == AF_INET) ? IPV4_SIZE : IPV6_SIZE);
     }
 
     ///@{
@@ -345,22 +277,37 @@ public:
 
     /// \return Stored IP address
     std::vector<uint8_t> getAddress() const {
-        return (std::vector<uint8_t>(address_.byte, address_.byte + IPV6_SIZE8));
+        return (address_);
     }
 
     /// \return Network mask applied to match
-    std::vector<uint8_t> getNetmask() const {
-        return (std::vector<uint8_t>(netmask_.byte, netmask_.byte + IPV6_SIZE8));
+    std::vector<uint8_t> getMask() const {
+        return (mask_);
     }
 
-    /// \return String passed to constructor
-    std::string getStringAddress() const {
-        return (straddr_);
-    }
+    /// \return Prefix length of the match
+    size_t getPrefixlen() const {
+        // Work this out by shifting bits out of the mask
+        size_t count = 0;
+        int index = 0;
+        for (size_t i = 0; i < mask_.size(); ++i) {
+            if (mask_[i] == 0xff) {
+                // Full byte, 8 bit set
+                count += 8;
+
+            } else if (mask_[i] != 0) {
+                // Partial set, count the bits
+                uint8_t byte = mask_[i];
+                for (int i = 0; i < 8 * sizeof(uint8_t); ++i) {
+                    count += byte & 0x01;   // Add one if the bit is set
+                    byte >>= 1;             // Go for next bit
+                }
 
-    /// \return Mask size given to constructor
-    size_t getMasksize() const {
-        return (masksize_);
+                // There won't be any more bits set after this, so exit
+                break;
+            }
+        }
+        return (count);
     }
 
     /// \return Address family
@@ -373,11 +320,6 @@ public:
 
         return (family_);
     }
-
-    /// \return Setting of inverse flag
-    bool getInverse() const {
-        return (inverse_);
-    }
     ///@}
 
 private:
@@ -389,112 +331,98 @@ private:
     ///
     /// \param testaddr Address (in network byte order) to test against the
     ///                 check condition in the class.  This is expected to
-    ///                 be IPV6_SIZE8 bytes long.
+    ///                 be IPV6_SIZE or IPV4_SIZE bytes long.
+    /// \param family   Address family of testaddr.
     ///
     /// \return true if the address matches, false if it does not.
-    virtual bool compare(const uint8_t* testaddr) const {
+    virtual bool compare(const uint8_t* testaddr, int family) const {
+
+        if (family != family_) {
+            // Can't match if the address is of the wrong family
+            return (false);
 
-        // To check that the address given matches the stored network address
-        // and netmask, we check the simple condition that:
+        }
+
+        // Simple check failed, so have to do a complete match.  To check that
+        // the address given matches the stored network address and mask, we
+        // check the simple condition that:
         //
-        //     address_given & netmask_ == stored_address & netmask_
+        //     address_given & mask_ == stored_address & mask_
         //
         // The result is checked for all bytes for which there are bits set in
-        // the network mask.  We stop at the first non-match (or when we run
-        // out of bits in the network mask). (Note that the network mask
-        // represents a contiguous set of bits.  As such, as soon as we find
-        // a netmask byte of zeroes, we have run past the part of the address
-        // where we need to match.
+        // the mask.  We stop at the first non-match (or when we run out of bits
+        // in the mask). (Note that the mask represents a contiguous set of
+        // bits.  As such, as soon as we find a mask byte of zeroes, we have run
+        // past the part of the address where we need to match.
         //
-        // We can optimise further by casting to a 32-bit array and checking
-        // 32 bits at a time.
+        // Note that if the passed address was any4 or any6, we rely on the
+        // fact that the size of address_ and mask_ are zero - the loop will
+        // terminate before the first iteration.
 
         bool match = true;
-        for (int i = 0; match && (i < IPV6_SIZE8) && (netmask_.byte[i] != 0);
-             ++i) {
-             match = ((testaddr[i] & netmask_.byte[i]) ==
-                      (address_.byte[i] & netmask_.byte[i]));
+        for (int i = 0; match && (i < address_.size()) &&
+                       (mask_[i] != 0); ++i) {
+             match = ((testaddr[i] & mask_[i]) == (address_[i] & mask_[i]));
         }
-
-        // As with the V4 check, return the XOR with the inverse flag.
-        return (match != inverse_);
+        return (match);
     }
 
-    /// \brief Comparison
-    ///
-    /// Convenience comparison for an IPV4 address.
-    ///
-    /// \param testaddr Address (in network byte order) to test against the
-    ///        check condition in the class.
-    ///
-    /// \return true if the address matches, false if it does not.
-    virtual bool compare(const uint32_t testaddr) const {
-        return (((testaddr & netmask_.word[0]) ==
-                 (address_.word[0] & netmask_.word[0])) != inverse_);
-    }
 
-
-    /// \brief Set Network Mask
+    /// \brief Set Mask
     ///
-    /// Sets up the network mask from the mask size.  This involves setting
-    /// an individual mask in each byte of the network mask.
+    /// Sets up the mask from the prefix length.  This involves setting
+    /// an individual mask in each byte of the mask array.
     ///
-    /// The actual allowed value of the mask size depends on the address
+    /// The actual allowed value of the prefix length depends on the address
     /// family.
     ///
-    /// \param requested Requested mask size.  If negative, the maximum for
-    ///        the address family is assumed.  (A negative value will arise
-    ///        if the string constructor was used and no mask size was given.)
-    void setNetmask(int requested) {
+    /// \param requested Requested prefix length size.  If negative, the
+    ///        maximum for the address family is assumed.  (A negative value
+    ///        will arise if the string constructor was used and no mask size
+    ///        was given.)
+    void setMask(int requested) {
+
+        mask_.clear();
+        mask_.resize((family_ == AF_INET) ? IPV4_SIZE : IPV6_SIZE);
 
-        // Set the maximum mask size allowed.
-        int maxmask = 8 * ((family_ == AF_INET) ? sizeof(uint32_t) : IPV6_SIZE8);
+        // Set the maximum number of bits allowed in the mask.
+        int maxmask = 8 * (mask_.size());
         if (requested < 0) {
             requested = maxmask;
         }
 
         // Validate that the mask is valid.
-        if ((requested >= 1) && (requested <= maxmask)) {
-            masksize_ = requested;
-
-            // The netmask array was initialized to zero in the constructor,
-            // but as an addition check, assert that this is so.
-            assert(std::find_if(netmask_.word, netmask_.word + IPV6_SIZE32,
-                   std::bind1st(std::not_equal_to<uint32_t>(), 0)) ==
-                   netmask_.word + IPV6_SIZE32);
+        if (requested <= maxmask) {
 
             // Loop, setting the bits in the set of mask bytes until all the
             // specified bits have been used up.  As both IPV4 and IPV6
             // addresses are stored in network-byte order, this works in
             // both cases.
-            size_t bits_left = masksize_;   // Bits remaining to set
+            size_t bits_left = requested;   // Bits remaining to set
             int i = -1;
             while (bits_left > 0) {
                 if (bits_left >= 8) {
-                    netmask_.byte[++i] = ~0;  // All bits set
+                    mask_[++i] = ~0;  // All bits set
                     bits_left -= 8;
 
                 } else if (bits_left > 0) {
-                    netmask_.byte[++i] = createNetmask<uint8_t>(bits_left);
+                    mask_[++i] = internal::createMask<uint8_t>(bits_left);
                     bits_left = 0;
 
                 }
             }
         } else {
             isc_throw(isc::OutOfRange,
-                      "mask size of " << masksize_ << " is invalid " <<
-                      "for the givem address");
+                      "mask size of " << requested << " is invalid " <<
+                      "for the given address");
         }
     }
 
     // Member variables
 
-    AddressData address_;   ///< Address in binary form
-    AddressData netmask_;   ///< Network mask
-    size_t      masksize_;  ///< Mask size passed to constructor
-    bool        inverse_;   ///< Test for equality or inequality
-    int         family_;    ///< Address family
-    std::string straddr_;   ///< Copy of constructor address string
+    std::vector<uint8_t> address_;  ///< Address in binary form
+    std::vector<uint8_t> mask_;     ///< Address mask
+    int         family_;            ///< Address family
 };
 
 } // namespace acl
diff --git a/src/lib/acl/tests/Makefile.am b/src/lib/acl/tests/Makefile.am
index 6016f90..91cebdd 100644
--- a/src/lib/acl/tests/Makefile.am
+++ b/src/lib/acl/tests/Makefile.am
@@ -10,6 +10,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
 run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/acl/libacl.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/lib/acl/tests/ip_check_unittest.cc b/src/lib/acl/tests/ip_check_unittest.cc
index eb55486..a8cc73f 100644
--- a/src/lib/acl/tests/ip_check_unittest.cc
+++ b/src/lib/acl/tests/ip_check_unittest.cc
@@ -18,60 +18,79 @@
 #include <boost/scoped_ptr.hpp>
 
 using namespace isc::acl;
+using namespace isc::acl::internal;
 using namespace std;
 
+namespace {
+const size_t IPV4_SIZE = 4;
+const size_t IPV6_SIZE = 16;
+}
+
 // Simple struct holding either an IPV4 or IPV6 address.  This is the "Context"
 // used for the tests.
 //
 // The structure is also used for converting an IPV4 address to a four-byte
 // array.
 struct GeneralAddress {
-    bool        isv4;           // true if it holds a v4 address
-    union {
-        uint32_t    v4addr;
-        uint8_t     v6addr[16];
-    };
-
-    // Default constructor.
-    GeneralAddress() : isv4(false) {
-        fill(v6addr, v6addr + sizeof(v6addr), 0);
+    vector<uint8_t> addr;       // Address type.  Size indicates what it holds
+
+    // Convert uint32_t address to a uint8_t vector
+    vector<uint8_t> convertUint32(uint32_t address) {
+        BOOST_STATIC_ASSERT(sizeof(uint32_t) == IPV4_SIZE);
+
+        vector<uint8_t> result(IPV4_SIZE);
+
+        // Address is in network-byte order, so copy to the array.  The
+        // MS byte is at the lowest address.
+        result[3] = address & 0xff;
+        result[2] = (address >> 8) & 0xff;
+        result[1] = (address >> 16) & 0xff;
+        result[0] = (address >> 24) & 0xff;
+
+        return (result);
     }
 
     // Convenience constructor for V4 address.  As it is not marked as explicit,
     // it allows the automatic promotion of a uint32_t to a GeneralAddress data
     // type in calls to matches().
-    GeneralAddress(uint32_t address) : isv4(true), v4addr(address) {
-        fill(v6addr +sizeof(v4addr), v6addr + sizeof(v6addr), 0);
+    GeneralAddress(uint32_t address) : addr()
+    {
+        addr = convertUint32(address);
     }
 
     // Convenience constructor for V6 address.  As it is not marked as explicit,
     // it allows the automatic promotion of a vector<uint8_t> to a
     // GeneralAddress data type in calls to matches().
-    GeneralAddress(const vector<uint8_t>& address) : isv4(false) {
-        if (address.size() != sizeof(v6addr)) {
+    GeneralAddress(const vector<uint8_t>& address) : addr(address)
+    {
+        // Implicit assertion here that an IPV6 address size is 16 bytes
+        if (address.size() != IPV6_SIZE) {
             isc_throw(isc::InvalidParameter, "vector passed to GeneralAddress "
                       "constructor is " << address.size() << " bytes long - it "
-                      "should be " << sizeof(v6addr) << " instead");
+                      "should be " << IPV6_SIZE << " bytes instead");
         }
-        copy(address.begin(), address.end(), v6addr);
     }
 
     // A couple of convenience methods for checking equality with different
     // representations of an address.
 
-    // Check that the IPV4 address is the same as that given, and that the
-    // remainder of the V6 addray is zero.
+    // Check that the IPV4 address is the same as that given.
     bool equals(uint32_t address) {
-        return ((address == v4addr) &&
-                (find_if(v6addr + sizeof(v4addr), v6addr + sizeof(v6addr),
-                         bind1st(not_equal_to<uint8_t>(), 0)) ==
-                         v6addr + sizeof(v6addr)));
+        if (addr.size() == IPV4_SIZE) {
+            vector<uint8_t> byte_address = convertUint32(address);
+            return (equal(byte_address.begin(), byte_address.end(),
+                           addr.begin()));
+        }
+        return (false);
     }
 
-    // Check that the V6 array is equal to that given.
-    bool equals(const vector<uint8_t>& address) {
-        return ((address.size() == sizeof(v6addr)) &&
-                equal(address.begin(), address.end(), v6addr));
+    // Check that the array is equal to that given
+    bool equals(const vector<uint8_t>& byte_address) {
+        if (addr.size() == byte_address.size()) {
+            return (equal(byte_address.begin(), byte_address.end(),
+                           addr.begin()));
+        }
+        return (false);
     }
 };
 
@@ -81,43 +100,39 @@ struct GeneralAddress {
 namespace isc  {
 namespace acl {
 template <>
-bool IPCheck<GeneralAddress>::matches(const GeneralAddress& addr) const {
-    if (addr.isv4 && (getFamily() == AF_INET)) {
-        return (compare(addr.v4addr));
-    } else if (!addr.isv4 && (getFamily() == AF_INET6)) {
-        return (compare(addr.v6addr));
-    }
-    return (false);
+bool IPCheck<GeneralAddress>::matches(const GeneralAddress& address) const {
+    return (compare(&address.addr[0],
+            (address.addr.size() == IPV4_SIZE) ? AF_INET : AF_INET6));
 }
 } // namespace acl
 } // namespace isc
 
 /// *** Free Function Tests ***
 
-// Test the createNetmask() function.
-TEST(IPFunctionCheck, CreateNetmask) {
+// Test the createMask() function.
+TEST(IPFunctionCheck, CreateMask) {
 
     // 8-bit tests: invalid arguments should throw.
-    EXPECT_THROW(createNetmask<uint8_t>(9), isc::OutOfRange);
+    EXPECT_THROW(createMask<uint8_t>(9), isc::OutOfRange);
 
     // Check on all possible 8-bit values.  Use a signed type to generate a
     // variable with the most significant bits set (right-shifting will
     // introduce additional bits).
     int8_t expected8 = 0x80;
     for (size_t i = 1; i <= 8; ++i, expected8 >>= 1) {
-        EXPECT_EQ(static_cast<uint8_t>(expected8), createNetmask<uint8_t>(i));
+        EXPECT_EQ(static_cast<uint8_t>(expected8), createMask<uint8_t>(i));
     }
-    EXPECT_EQ(0, createNetmask<uint8_t>(0));
+    EXPECT_EQ(0, createMask<uint8_t>(0));
 
     // Do the same for 32 bits.
-    EXPECT_THROW(createNetmask<int32_t>(33), isc::OutOfRange);
+    EXPECT_THROW(createMask<int32_t>(33), isc::OutOfRange);
 
     int32_t expected32 = 0x80000000;
     for (size_t i = 1; i <= 32; ++i, expected32 >>= 1) {
         EXPECT_EQ(static_cast<uint32_t>(expected32),
-                  createNetmask<uint32_t>(i));
+                  createMask<uint32_t>(i));
     }
-    EXPECT_EQ(0, createNetmask<uint32_t>(0));
+    EXPECT_EQ(0, createMask<uint32_t>(0));
 }
 
 // Test the splitIPAddress() function.
@@ -136,13 +151,19 @@ TEST(IPFunctionCheck, SplitIPAddress) {
     EXPECT_EQ(string("2001:db8::"), result.first);
     EXPECT_EQ(128, result.second);
 
-    EXPECT_THROW(splitIPAddress("192.0.2.43/-1"), isc::OutOfRange);
+    result = splitIPAddress("192.0.2.1/0");
+    EXPECT_EQ(string("192.0.2.1"), result.first);
+    EXPECT_EQ(0, result.second);
+
+    EXPECT_THROW(splitIPAddress("192.0.2.43/-1"), isc::InvalidParameter);
     EXPECT_THROW(splitIPAddress("192.0.2.43//1"), isc::InvalidParameter);
     EXPECT_THROW(splitIPAddress("192.0.2.43/1/"), isc::InvalidParameter);
     EXPECT_THROW(splitIPAddress("/192.0.2.43/1"), isc::InvalidParameter);
-    EXPECT_THROW(splitIPAddress("2001:db8::/0"), isc::OutOfRange);
     EXPECT_THROW(splitIPAddress("2001:db8::/xxxx"), isc::InvalidParameter);
     EXPECT_THROW(splitIPAddress("2001:db8::/32/s"), isc::InvalidParameter);
+    EXPECT_THROW(splitIPAddress("1/"), isc::InvalidParameter);
+    EXPECT_THROW(splitIPAddress("/1"), isc::InvalidParameter);
+    EXPECT_THROW(splitIPAddress(" 1/ "), isc::InvalidParameter);
 }
 
 // *** General tests ***
@@ -162,7 +183,7 @@ TEST(IPCheck, V4ConstructorAddress) {
 
     // Address is presented in network byte order in constructor, so no
     // conversion is needed for this test.
-    IPCheck<GeneralAddress> acl(address.v4addr);
+    IPCheck<GeneralAddress> acl(0x12345678);
     vector<uint8_t> stored = acl.getAddress();
 
     EXPECT_EQ(AF_INET, acl.getFamily());
@@ -170,61 +191,52 @@ TEST(IPCheck, V4ConstructorAddress) {
 }
 
 TEST(IPCheck, V4ConstructorMask) {
-    // The mask is stored in network byte order, so the pattern expected must
-    // also be converted to network byte order for the comparison to succeed.
-    // use the general address structure to handle conversions between words
-    // and bytes
+    // The mask is stored in network byte order.  The conversion to a byte
+    // array within the IPCheck object should take care of the ordering.
     IPCheck<GeneralAddress> acl1(1, 1);         // Address of 1 is placeholder
-    GeneralAddress netmask1(htonl(0x80000000)); // Expected mask
-    vector<uint8_t> stored1 = acl1.getNetmask();
-    EXPECT_TRUE(netmask1.equals(stored1));
-    EXPECT_EQ(1, acl1.getMasksize());
+    GeneralAddress mask1(0x80000000);           // Expected mask
+    vector<uint8_t> stored1 = acl1.getMask();
+    EXPECT_TRUE(mask1.equals(stored1));
+    EXPECT_EQ(1, acl1.getPrefixlen());
 
     // Different check
     IPCheck<GeneralAddress> acl2(1, 24);
-    GeneralAddress netmask2(htonl(0xffffff00));
-    vector<uint8_t> stored2 = acl2.getNetmask();
-    EXPECT_TRUE(netmask2.equals(stored2));
-    EXPECT_EQ(24, acl2.getMasksize());
+    GeneralAddress mask2(0xffffff00);
+    vector<uint8_t> stored2 = acl2.getMask();
+    EXPECT_TRUE(mask2.equals(stored2));
+    EXPECT_EQ(24, acl2.getPrefixlen());
 
     // ... and some invalid network masks
-    GeneralAddress dummy;
-    EXPECT_THROW(IPCheck<GeneralAddress>(1, 0), isc::OutOfRange);
     EXPECT_THROW(IPCheck<GeneralAddress>(1, 33), isc::OutOfRange);
-    EXPECT_THROW(IPCheck<GeneralAddress>(dummy.v6addr, 129), isc::OutOfRange);
-}
-
-TEST(IPCheck, V4ConstructorInverse) {
-    // Valid values. Address/mask of "1" is used as a placeholder
-    IPCheck<GeneralAddress> acl1(1, 1);
-    EXPECT_FALSE(acl1.getInverse());
-
-    IPCheck<GeneralAddress> acl2(1, 1, true);
-    EXPECT_TRUE(acl2.getInverse());
-
-    IPCheck<GeneralAddress> acl3(1, 1, false);
-    EXPECT_FALSE(acl3.getInverse());
+    vector<uint8_t> dummy(IPV6_SIZE);
+    EXPECT_THROW(IPCheck<GeneralAddress>(&dummy[0], 129), isc::OutOfRange);
 }
 
 TEST(IPCheck, V4StringConstructor) {
     // Constructor with no mask given
     IPCheck<GeneralAddress> acl1("192.0.2.255");
-    EXPECT_EQ(32, acl1.getMasksize());
+    EXPECT_EQ(32, acl1.getPrefixlen());
+    EXPECT_EQ(AF_INET, acl1.getFamily());
 
     vector<uint8_t> stored1 = acl1.getAddress();
-    GeneralAddress expected1(htonl(0xc00002ff));
+    GeneralAddress expected1(0xc00002ff);
     EXPECT_TRUE(expected1.equals(stored1));
 
     // Constructor with valid mask given
     IPCheck<GeneralAddress> acl2("192.0.2.0/24");
-    EXPECT_EQ(24, acl2.getMasksize());
+    EXPECT_EQ(24, acl2.getPrefixlen());
+    EXPECT_EQ(AF_INET, acl2.getFamily());
 
     vector<uint8_t> stored2 = acl2.getAddress();
-    GeneralAddress expected2(htonl(0xc0000200));
+    GeneralAddress expected2(0xc0000200);
     EXPECT_TRUE(expected2.equals(stored2));
 
-    // Invalid masks
-    EXPECT_THROW(IPCheck<GeneralAddress>("192.0.2.0/0"), isc::OutOfRange);
+    // Any match
+    IPCheck<GeneralAddress> acl3("any4");
+    EXPECT_EQ(0, acl3.getPrefixlen());
+    EXPECT_EQ(AF_INET, acl3.getFamily());
+
+    // Invalid prefix lengths
     EXPECT_THROW(IPCheck<GeneralAddress>("192.0.2.0/33"), isc::OutOfRange);
     EXPECT_THROW(IPCheck<GeneralAddress>("192.0.2.0/24/3"),
                  isc::InvalidParameter);
@@ -235,16 +247,14 @@ TEST(IPCheck, V4StringConstructor) {
 }
 
 TEST(IPCheck, V4CopyConstructor) {
-    IPCheck<GeneralAddress> acl1("192.0.2.1/24", true);
+    IPCheck<GeneralAddress> acl1("192.0.2.1/24");
     IPCheck<GeneralAddress> acl2(acl1);
 
-    EXPECT_EQ(acl1.getMasksize(), acl2.getMasksize());
-    EXPECT_EQ(acl1.getInverse(), acl2.getInverse());
+    EXPECT_EQ(acl1.getPrefixlen(), acl2.getPrefixlen());
     EXPECT_EQ(acl1.getFamily(), acl2.getFamily());
-    EXPECT_EQ(acl1.getStringAddress(), acl2.getStringAddress());
 
-    vector<uint8_t> net1 = acl1.getNetmask();
-    vector<uint8_t> net2 = acl2.getNetmask();
+    vector<uint8_t> net1 = acl1.getMask();
+    vector<uint8_t> net2 = acl2.getMask();
     EXPECT_EQ(net1.size(), net2.size());
     EXPECT_TRUE(equal(net1.begin(), net1.end(), net2.begin()));
 
@@ -255,17 +265,15 @@ TEST(IPCheck, V4CopyConstructor) {
 }
 
 TEST(IPCheck, V4AssignmentOperator) {
-    IPCheck<GeneralAddress> acl1("192.0.2.0/24", true);
-    IPCheck<GeneralAddress> acl2("192.0.2.128/25", false);
+    IPCheck<GeneralAddress> acl1("192.0.2.0/24");
+    IPCheck<GeneralAddress> acl2("192.0.2.128/25");
     acl2 = acl1;
 
-    EXPECT_EQ(acl1.getMasksize(), acl2.getMasksize());
-    EXPECT_EQ(acl1.getInverse(), acl2.getInverse());
+    EXPECT_EQ(acl1.getPrefixlen(), acl2.getPrefixlen());
     EXPECT_EQ(acl1.getFamily(), acl2.getFamily());
-    EXPECT_EQ(acl1.getStringAddress(), acl2.getStringAddress());
 
-    vector<uint8_t> net1 = acl1.getNetmask();
-    vector<uint8_t> net2 = acl2.getNetmask();
+    vector<uint8_t> net1 = acl1.getMask();
+    vector<uint8_t> net2 = acl2.getMask();
     EXPECT_EQ(net1.size(), net2.size());
     EXPECT_TRUE(equal(net1.begin(), net1.end(), net2.begin()));
 
@@ -286,32 +294,33 @@ TEST(IPCheck, V4AssignmentOperator) {
 
 TEST(IPCheck, V4Compare) {
     // Exact address - match if given address matches stored address.
-    IPCheck<GeneralAddress> acl1(htonl(0x23457f13), 32);
-    EXPECT_TRUE(acl1.matches(htonl(0x23457f13)));
-    EXPECT_FALSE(acl1.matches(htonl(0x23457f12)));
-    EXPECT_FALSE(acl1.matches(htonl(0x13457f13)));
-
-    // Exact address - match if address does not match stored address
-    IPCheck<GeneralAddress> acl2(htonl(0x23457f13), 32, true);
-    EXPECT_FALSE(acl2.matches(htonl(0x23457f13)));
-    EXPECT_TRUE(acl2.matches(htonl(0x23457f12)));
-    EXPECT_TRUE(acl2.matches(htonl(0x13457f13)));
+    IPCheck<GeneralAddress> acl1(0x23457f13, 32);
+    EXPECT_TRUE(acl1.matches(0x23457f13));
+    EXPECT_FALSE(acl1.matches(0x23457f12));
+    EXPECT_FALSE(acl1.matches(0x13457f13));
 
     // Match if the address matches a mask
-    IPCheck<GeneralAddress> acl3(htonl(0x23450000), 16);
-    EXPECT_TRUE(acl3.matches(htonl(0x23450000)));
-    EXPECT_TRUE(acl3.matches(htonl(0x23450001)));
-    EXPECT_TRUE(acl3.matches(htonl(0x2345ffff)));
-    EXPECT_FALSE(acl3.matches(htonl(0x23460000)));
-    EXPECT_FALSE(acl3.matches(htonl(0x2346ffff)));
-
-    // Match if the address does not match a mask
-    IPCheck<GeneralAddress> acl4(htonl(0x23450000), 16, true);
-    EXPECT_FALSE(acl4.matches(htonl(0x23450000)));
-    EXPECT_FALSE(acl4.matches(htonl(0x23450001)));
-    EXPECT_FALSE(acl4.matches(htonl(0x2345ffff)));
-    EXPECT_TRUE(acl4.matches(htonl(0x23460000)));
-    EXPECT_TRUE(acl4.matches(htonl(0x2346ffff)));
+    IPCheck<GeneralAddress> acl2(0x23450000, 16);
+    EXPECT_TRUE(acl2.matches(0x23450000));
+    EXPECT_TRUE(acl2.matches(0x23450001));
+    EXPECT_TRUE(acl2.matches(0x2345ffff));
+    EXPECT_FALSE(acl2.matches(0x23460000));
+    EXPECT_FALSE(acl2.matches(0x2346ffff));
+
+    // Match if "any4" is specified
+    IPCheck<GeneralAddress> acl3("any4");
+    EXPECT_TRUE(acl3.matches(0x23450000));
+    EXPECT_TRUE(acl3.matches(0x23450001));
+    EXPECT_TRUE(acl3.matches(0x2345ffff));
+    EXPECT_TRUE(acl3.matches(0x23460000));
+    EXPECT_TRUE(acl3.matches(0x2346ffff));
+
+    IPCheck<GeneralAddress> acl4(0x23450000, 0);
+    EXPECT_TRUE(acl4.matches(0x23450000));
+    EXPECT_TRUE(acl4.matches(0x23450001));
+    EXPECT_TRUE(acl4.matches(0x2345ffff));
+    EXPECT_TRUE(acl4.matches(0x23460000));
+    EXPECT_TRUE(acl4.matches(0x2346ffff));
 }
 
 
@@ -392,60 +401,55 @@ TEST(IPCheck, V6ConstructorMask) {
 
     // Valid masks...
     IPCheck<GeneralAddress> acl1(V6ADDR_1, 1);
-    vector<uint8_t> stored = acl1.getNetmask();
+    vector<uint8_t> stored = acl1.getMask();
     EXPECT_EQ(sizeof(MASK_1), stored.size());
     EXPECT_TRUE(equal(stored.begin(), stored.end(), MASK_1));
 
     IPCheck<GeneralAddress> acl2(V6ADDR_1, 8);
-    stored = acl2.getNetmask();
+    stored = acl2.getMask();
     EXPECT_TRUE(equal(stored.begin(), stored.end(), MASK_8));
 
     IPCheck<GeneralAddress> acl3(V6ADDR_1, 48);
-    stored = acl3.getNetmask();
+    stored = acl3.getMask();
     EXPECT_TRUE(equal(stored.begin(), stored.end(), MASK_48));
 
     IPCheck<GeneralAddress> acl4(V6ADDR_1, 51);
-    stored = acl4.getNetmask();
+    stored = acl4.getMask();
     EXPECT_TRUE(equal(stored.begin(), stored.end(), MASK_51));
 
     IPCheck<GeneralAddress> acl5(V6ADDR_1, 128);
-    stored = acl5.getNetmask();
+    stored = acl5.getMask();
     EXPECT_TRUE(equal(stored.begin(), stored.end(), MASK_128));
 
     // ... and some invalid network masks
-    EXPECT_THROW(IPCheck<GeneralAddress>(V6ADDR_1, 0), isc::OutOfRange);
     EXPECT_THROW(IPCheck<GeneralAddress>(V6ADDR_1, 129), isc::OutOfRange);
 }
 
-TEST(IPCheck, V6ConstructorInverse) {
-    // Valid values. Address/mask of "1" is used as a placeholder
-    IPCheck<GeneralAddress> acl1(V6ADDR_1, 1);
-    EXPECT_FALSE(acl1.getInverse());
-
-    IPCheck<GeneralAddress> acl2(V6ADDR_1, 1, true);
-    EXPECT_TRUE(acl2.getInverse());
-
-    IPCheck<GeneralAddress> acl3(V6ADDR_1, 1, false);
-    EXPECT_FALSE(acl3.getInverse());
-}
-
 TEST(IPCheck, V6StringConstructor) {
     IPCheck<GeneralAddress> acl1(V6ADDR_1_STRING);
     vector<uint8_t> address = acl1.getAddress();
-    EXPECT_EQ(128, acl1.getMasksize());
+    EXPECT_EQ(128, acl1.getPrefixlen());
+    EXPECT_EQ(AF_INET6, acl1.getFamily());
     EXPECT_TRUE(equal(address.begin(), address.end(), V6ADDR_1));
 
     IPCheck<GeneralAddress> acl2(string(V6ADDR_2_STRING) + string("/48"));
     address = acl2.getAddress();
-    EXPECT_EQ(48, acl2.getMasksize());
+    EXPECT_EQ(48, acl2.getPrefixlen());
+    EXPECT_EQ(AF_INET6, acl2.getFamily());
     EXPECT_TRUE(equal(address.begin(), address.end(), V6ADDR_2));
 
     IPCheck<GeneralAddress> acl3("::1");
     address = acl3.getAddress();
-    EXPECT_EQ(128, acl3.getMasksize());
+    EXPECT_EQ(128, acl3.getPrefixlen());
+    EXPECT_EQ(AF_INET6, acl3.getFamily());
     EXPECT_TRUE(equal(address.begin(), address.end(), V6ADDR_3));
 
-    EXPECT_THROW(IPCheck<GeneralAddress>("::1/0"), isc::OutOfRange);
+    // Any match
+    IPCheck<GeneralAddress> acl4("any6");
+    EXPECT_EQ(0, acl4.getPrefixlen());
+    EXPECT_EQ(AF_INET6, acl4.getFamily());
+
+    EXPECT_NO_THROW(IPCheck<GeneralAddress>("::1/0"));
     EXPECT_THROW(IPCheck<GeneralAddress>("::1/129"), isc::OutOfRange);
     EXPECT_THROW(IPCheck<GeneralAddress>("::1/24/3"), isc::InvalidParameter);
     EXPECT_THROW(IPCheck<GeneralAddress>("2001:0db8::abcd/ww"),
@@ -465,16 +469,14 @@ TEST(IPCheck, V6CopyConstructor) {
     EXPECT_TRUE(equal(acl1_address.begin(), acl1_address.end(),
                 acl2_address.begin()));
 
-    EXPECT_EQ(acl1.getMasksize(), acl2.getMasksize());
+    EXPECT_EQ(acl1.getPrefixlen(), acl2.getPrefixlen());
 
-    vector<uint8_t> acl1_netmask = acl1.getNetmask();
-    vector<uint8_t> acl2_netmask = acl1.getNetmask();
-    EXPECT_EQ(sizeof(V6ADDR_1), acl1_netmask.size());
-    EXPECT_EQ(acl1_netmask.size(), acl2_netmask.size());
-    EXPECT_TRUE(equal(acl1_netmask.begin(), acl1_netmask.end(),
-                acl2_netmask.begin()));
-
-    EXPECT_EQ(acl1.getInverse(), acl2.getInverse());
+    vector<uint8_t> acl1_mask = acl1.getMask();
+    vector<uint8_t> acl2_mask = acl1.getMask();
+    EXPECT_EQ(sizeof(V6ADDR_1), acl1_mask.size());
+    EXPECT_EQ(acl1_mask.size(), acl2_mask.size());
+    EXPECT_TRUE(equal(acl1_mask.begin(), acl1_mask.end(),
+                acl2_mask.begin()));
 }
 
 TEST(IPCheck, V6AssignmentOperator) {
@@ -490,16 +492,14 @@ TEST(IPCheck, V6AssignmentOperator) {
     EXPECT_TRUE(equal(acl1_address.begin(), acl1_address.end(),
                 acl2_address.begin()));
 
-    EXPECT_EQ(acl1.getMasksize(), acl2.getMasksize());
-
-    vector<uint8_t> acl1_netmask = acl1.getNetmask();
-    vector<uint8_t> acl2_netmask = acl2.getNetmask();
-    EXPECT_EQ(sizeof(V6ADDR_1), acl1_netmask.size());
-    EXPECT_EQ(acl1_netmask.size(), acl2_netmask.size());
-    EXPECT_TRUE(equal(acl1_netmask.begin(), acl1_netmask.end(),
-                acl2_netmask.begin()));
+    EXPECT_EQ(acl1.getPrefixlen(), acl2.getPrefixlen());
 
-    EXPECT_EQ(acl1.getInverse(), acl2.getInverse());
+    vector<uint8_t> acl1_mask = acl1.getMask();
+    vector<uint8_t> acl2_mask = acl2.getMask();
+    EXPECT_EQ(sizeof(V6ADDR_1), acl1_mask.size());
+    EXPECT_EQ(acl1_mask.size(), acl2_mask.size());
+    EXPECT_TRUE(equal(acl1_mask.begin(), acl1_mask.end(),
+                acl2_mask.begin()));
 }
 
 TEST(IPCheck, V6Compare) {
@@ -516,26 +516,23 @@ TEST(IPCheck, V6Compare) {
     EXPECT_FALSE(acl1.matches(v6addr_2_48));
     EXPECT_FALSE(acl1.matches(v6addr_3));
 
-    // Exact address - match if address does not match stored address
-    IPCheck<GeneralAddress> acl2(string(V6ADDR_2_STRING) + string("/128"),
-                                   true);
-    EXPECT_FALSE(acl2.matches(v6addr_2));
+    // Match if the address matches a mask
+    IPCheck<GeneralAddress> acl2(string(V6ADDR_2_STRING) + string("/52"));
+    EXPECT_TRUE(acl2.matches(v6addr_2));
     EXPECT_TRUE(acl2.matches(v6addr_2_52));
-    EXPECT_TRUE(acl2.matches(v6addr_2_48));
-    EXPECT_TRUE(acl2.matches(v6addr_3));
+    EXPECT_FALSE(acl2.matches(v6addr_2_48));
+    EXPECT_FALSE(acl2.matches(v6addr_3));
 
-    // Match if the address matches a mask
-    IPCheck<GeneralAddress> acl3(string(V6ADDR_2_STRING) + string("/52"));
+    // Match on any address
+    IPCheck<GeneralAddress> acl3("any6");
     EXPECT_TRUE(acl3.matches(v6addr_2));
     EXPECT_TRUE(acl3.matches(v6addr_2_52));
-    EXPECT_FALSE(acl3.matches(v6addr_2_48));
-    EXPECT_FALSE(acl3.matches(v6addr_3));
-
-    // Match if the address does not match a mask
-    IPCheck<GeneralAddress> acl4(string(V6ADDR_2_STRING) + string("/52"),
-                              true);
-    EXPECT_FALSE(acl4.matches(v6addr_2));
-    EXPECT_FALSE(acl4.matches(v6addr_2_52));
+    EXPECT_TRUE(acl3.matches(v6addr_2_48));
+    EXPECT_TRUE(acl3.matches(v6addr_3));
+
+    IPCheck<GeneralAddress> acl4(string(V6ADDR_1_STRING) + string("/0"));
+    EXPECT_TRUE(acl4.matches(v6addr_2));
+    EXPECT_TRUE(acl4.matches(v6addr_2_52));
     EXPECT_TRUE(acl4.matches(v6addr_2_48));
     EXPECT_TRUE(acl4.matches(v6addr_3));
 }
@@ -555,4 +552,14 @@ TEST(IPCheck, MixedMode) {
     GeneralAddress test2(0x12345678);
     EXPECT_NO_THROW(acl2.matches(test2));
     EXPECT_FALSE(acl2.matches(test2));
+
+    // Ensure only a V4 address matches "any4".
+    IPCheck<GeneralAddress> acl3("any4");
+    EXPECT_FALSE(acl3.matches(test1));
+    EXPECT_TRUE(acl3.matches(test2));
+
+    // ... and check the reverse
+    IPCheck<GeneralAddress> acl4("any6");
+    EXPECT_TRUE(acl4.matches(test1));
+    EXPECT_FALSE(acl4.matches(test2));
 }




More information about the bind10-changes mailing list