core: Add IpAddressPredicate for white-/blacklisting IP address subnets

Change-Id: I9f67c4bcbc55e8a8de0bb70812c5562ba083c948
Refs: #4546
diff --git a/tests/core/network-interface-predicate.t.cpp b/tests/core/network-predicate.t.cpp
similarity index 72%
rename from tests/core/network-interface-predicate.t.cpp
rename to tests/core/network-predicate.t.cpp
index 7e6a1bf..d7ef008 100644
--- a/tests/core/network-interface-predicate.t.cpp
+++ b/tests/core/network-predicate.t.cpp
@@ -23,7 +23,7 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "core/network-interface-predicate.hpp"
+#include "core/network-predicate.hpp"
 
 #include "tests/test-common.hpp"
 
@@ -35,7 +35,34 @@
 namespace nfd {
 namespace tests {
 
-class NetworkInterfacePredicateFixture : public BaseFixture
+BOOST_AUTO_TEST_SUITE(TestNetworkPredicate)
+
+template<class T>
+class NetworkPredicateBaseFixture : public BaseFixture
+{
+public:
+  void
+  parseConfig(const std::string& config)
+  {
+    std::istringstream input(config);
+    boost::property_tree::ptree ptree;
+    boost::property_tree::read_info(input, ptree);
+
+    for (const auto& i : ptree) {
+      if (i.first == "whitelist") {
+        predicate.parseWhitelist(i.second);
+      }
+      else if (i.first == "blacklist") {
+        predicate.parseBlacklist(i.second);
+      }
+    }
+  }
+
+protected:
+  T predicate;
+};
+
+class NetworkInterfacePredicateFixture : public NetworkPredicateBaseFixture<NetworkInterfacePredicate>
 {
 protected:
   NetworkInterfacePredicateFixture()
@@ -51,7 +78,7 @@
     netifs.back()->addNetworkAddress(NetworkAddress(AddressFamily::V4,
       address_v4::from_string("129.82.100.1"), address_v4::from_string("129.82.255.255"),
       16, AddressScope::GLOBAL, 0));
-    netifs.back()->addNetworkAddress(NetworkAddress(AddressFamily::V4,
+    netifs.back()->addNetworkAddress(NetworkAddress(AddressFamily::V6,
       address_v6::from_string("2001:db8:1::1"), address_v6::from_string("2001:db8:1::ffff:ffff:ffff:ffff"),
       64, AddressScope::GLOBAL, 0));
     netifs.back()->setFlags(IFF_UP);
@@ -63,7 +90,7 @@
     netifs.back()->addNetworkAddress(NetworkAddress(AddressFamily::V4,
       address_v4::from_string("192.168.2.1"), address_v4::from_string("192.168.2.255"),
       24, AddressScope::GLOBAL, 0));
-    netifs.back()->addNetworkAddress(NetworkAddress(AddressFamily::V4,
+    netifs.back()->addNetworkAddress(NetworkAddress(AddressFamily::V6,
       address_v6::from_string("2001:db8:2::1"), address_v6::from_string("2001:db8:2::ffff:ffff:ffff:ffff"),
       64, AddressScope::GLOBAL, 0));
     netifs.back()->setFlags(IFF_UP);
@@ -90,29 +117,11 @@
     netifs.back()->setFlags(IFF_UP);
   }
 
-  void
-  parseConfig(const std::string& config)
-  {
-    std::istringstream input(config);
-    boost::property_tree::ptree ptree;
-    boost::property_tree::read_info(input, ptree);
-
-    for (const auto& i : ptree) {
-      if (i.first == "whitelist") {
-        predicate.parseWhitelist(i.second);
-      }
-      else if (i.first == "blacklist") {
-        predicate.parseBlacklist(i.second);
-      }
-    }
-  }
-
 protected:
-  NetworkInterfacePredicate predicate;
   std::vector<shared_ptr<ndn::net::NetworkInterface>> netifs;
 };
 
-BOOST_FIXTURE_TEST_SUITE(TestNetworkInterfacePredicate, NetworkInterfacePredicateFixture)
+BOOST_FIXTURE_TEST_SUITE(NetworkInterface, NetworkInterfacePredicateFixture)
 
 BOOST_AUTO_TEST_CASE(Default)
 {
@@ -352,7 +361,151 @@
     ConfigFile::Error);
 }
 
-BOOST_AUTO_TEST_SUITE_END() // TestNetworkInterfacePredicate
+BOOST_AUTO_TEST_CASE(UnrecognizedKey)
+{
+  BOOST_CHECK_THROW(
+    parseConfig("blacklist\n"
+                "{\n"
+                "  key unrecognized\n"
+                "}"),
+    ConfigFile::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // NetworkInterface
+
+class IpAddressPredicateFixture : public NetworkPredicateBaseFixture<IpAddressPredicate>
+{
+protected:
+  IpAddressPredicateFixture()
+  {
+    using namespace boost::asio::ip;
+
+    addrs.push_back(address_v4::from_string("129.82.100.1"));
+    addrs.push_back(address_v6::from_string("2001:db8:1::1"));
+    addrs.push_back(address_v4::from_string("192.168.2.1"));
+    addrs.push_back(address_v6::from_string("2001:db8:2::1"));
+  }
+
+protected:
+  std::vector<boost::asio::ip::address> addrs;
+};
+
+BOOST_FIXTURE_TEST_SUITE(IpAddress, IpAddressPredicateFixture)
+
+BOOST_AUTO_TEST_CASE(Default)
+{
+  parseConfig("");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), true);
+}
+
+BOOST_AUTO_TEST_CASE(EmptyWhitelist)
+{
+  parseConfig("whitelist\n"
+              "{\n"
+              "}");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), false);
+}
+
+BOOST_AUTO_TEST_CASE(WildcardBlacklist)
+{
+  parseConfig("blacklist\n"
+              "{\n"
+              "  *\n"
+              "}");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), false);
+}
+
+BOOST_AUTO_TEST_CASE(Subnet4Whitelist)
+{
+  parseConfig("whitelist\n"
+              "{\n"
+              "  subnet 192.168.0.0/16\n"
+              "}");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), false);
+}
+
+BOOST_AUTO_TEST_CASE(Subnet4Blacklist)
+{
+  parseConfig("blacklist\n"
+              "{\n"
+              "  subnet 192.168.0.0/16\n"
+              "}");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), true);
+}
+
+BOOST_AUTO_TEST_CASE(Subnet6Whitelist)
+{
+  parseConfig("whitelist\n"
+              "{\n"
+              "  subnet 2001:db8:2::1/120\n"
+              "}");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), false);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), true);
+}
+
+BOOST_AUTO_TEST_CASE(Subnet6Blacklist)
+{
+  parseConfig("blacklist\n"
+              "{\n"
+              "  subnet 2001:db8:2::1/120\n"
+              "}");
+
+  BOOST_CHECK_EQUAL(predicate(addrs[0]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[1]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[2]), true);
+  BOOST_CHECK_EQUAL(predicate(addrs[3]), false);
+}
+
+BOOST_AUTO_TEST_CASE(UnrecognizedKey)
+{
+  BOOST_CHECK_THROW(
+    parseConfig("blacklist\n"
+                "{\n"
+                "  ether 3e:15:c2:8b:65:00\n"
+                "}"),
+    ConfigFile::Error);
+
+  BOOST_CHECK_THROW(
+    parseConfig("blacklist\n"
+                "{\n"
+                "  ifname eth**\n"
+                "}"),
+    ConfigFile::Error);
+
+  BOOST_CHECK_THROW(
+    parseConfig("blacklist\n"
+                "{\n"
+                "  key unrecognized\n"
+                "}"),
+    ConfigFile::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // IpAddress
+
+BOOST_AUTO_TEST_SUITE_END() // TestNetworkPredicate
 
 } // namespace tests
 } // namespace nfd