From: Francis Dupont Date: Tue, 11 Jun 2019 13:45:50 +0000 (+0200) Subject: [606-drop-packets-in-drop-class] Added DROP class (including doc and unit tests) X-Git-Tag: Kea-1.6.0-beta2~46 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=217be4532bb0f5f8e5576178909ce03f0f04ef39;p=thirdparty%2Fkea.git [606-drop-packets-in-drop-class] Added DROP class (including doc and unit tests) --- diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index 4755913c89..4ca827d436 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -90,6 +90,11 @@ resort) definition. + When the incoming packet belongs the special DROP class it is + dropped and an informational message is logged with the packet + information. + + A subnet is chosen, possibly based on the class information when some subnets are reserved. More precisely: when choosing a subnet, the server iterates over all of the subnets that are @@ -111,10 +116,11 @@ request") evaluation - are processed in the order they are defined in the configuration; the boolean expression is evaluated and, if it returns true ("match"), the incoming packet is associated - with the class. After a subnet is selected, the server determines whether there is a reservation - for a given client. Therefore, it + with the class. After a subnet is selected, the server determines + whether there is a reservation for a given client. Therefore, it is not possible to use KNOWN/UNKNOWN classes to select a shared - network or a subnet. + network or a subnet, nor to make the DROP class dependent of + KNOWN/UNKNOWN classes. If needed, addresses and prefixes from pools are assigned, diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml index 1e9b538482..8b932ce243 100644 --- a/doc/guide/dhcp4-srv.xml +++ b/doc/guide/dhcp4-srv.xml @@ -2534,7 +2534,8 @@ It is merely echoed by the server. The first step is to assess an incoming packet and assign it to zero or more classes. The second step is to choose a subnet, possibly based on the - class information. + class information. When the incoming packet is in the "DROP" + special class it is dropped and an information message logged. The next step is to evaluate class expressions depending on the built-in "KNOWN"/"UNKNOWN" classes after host reservation lookup, using them for pool selection and assigning classes from host reservations. diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml index c17bd88591..78784183d1 100644 --- a/doc/guide/dhcp6-srv.xml +++ b/doc/guide/dhcp6-srv.xml @@ -2429,7 +2429,8 @@ should include options from the new option space: The first step is to assess an incoming packet and assign it to zero or more classes. Next, a subnet is chosen, possibly based on the - class information. + class information. When the incoming packet is inthe "DROP" + special class it is dropped and an information message logged. After that, class expressions are evaluated depending on the built-in "KNOWN"/"UNKNOWN" classes after host reservation lookup, using them for pool/pd-pool selection and assigning classes from host diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc index 44c0f7538a..129aaddeb1 100644 --- a/src/bin/dhcp4/dhcp4_messages.cc +++ b/src/bin/dhcp4/dhcp4_messages.cc @@ -93,6 +93,7 @@ extern const isc::log::MessageID DHCP4_PACKET_DROP_0006 = "DHCP4_PACKET_DROP_000 extern const isc::log::MessageID DHCP4_PACKET_DROP_0007 = "DHCP4_PACKET_DROP_0007"; extern const isc::log::MessageID DHCP4_PACKET_DROP_0008 = "DHCP4_PACKET_DROP_0008"; extern const isc::log::MessageID DHCP4_PACKET_DROP_0009 = "DHCP4_PACKET_DROP_0009"; +extern const isc::log::MessageID DHCP4_PACKET_DROP_DROP_CLASS = "DHCP4_PACKET_DROP_DROP_CLASS"; extern const isc::log::MessageID DHCP4_PACKET_NAK_0001 = "DHCP4_PACKET_NAK_0001"; extern const isc::log::MessageID DHCP4_PACKET_NAK_0002 = "DHCP4_PACKET_NAK_0002"; extern const isc::log::MessageID DHCP4_PACKET_NAK_0003 = "DHCP4_PACKET_NAK_0003"; @@ -228,6 +229,7 @@ const char* values[] = { "DHCP4_PACKET_DROP_0007", "%1: failed to process packet: %2", "DHCP4_PACKET_DROP_0008", "%1: DHCP service is globally disabled", "DHCP4_PACKET_DROP_0009", "%1: Option 53 missing (no DHCP message type), is this a BOOTP packet?", + "DHCP4_PACKET_DROP_DROP_CLASS", "dropped as member of the special DROP class: %1", "DHCP4_PACKET_NAK_0001", "%1: failed to select a subnet for incoming packet, src %2, type %3", "DHCP4_PACKET_NAK_0002", "%1: invalid address %2 requested by INIT-REBOOT", "DHCP4_PACKET_NAK_0003", "%1: failed to advertise a lease, client sent ciaddr %2, requested-ip-address %3", diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h index b8c7ff185c..5d4480cc3d 100644 --- a/src/bin/dhcp4/dhcp4_messages.h +++ b/src/bin/dhcp4/dhcp4_messages.h @@ -94,6 +94,7 @@ extern const isc::log::MessageID DHCP4_PACKET_DROP_0006; extern const isc::log::MessageID DHCP4_PACKET_DROP_0007; extern const isc::log::MessageID DHCP4_PACKET_DROP_0008; extern const isc::log::MessageID DHCP4_PACKET_DROP_0009; +extern const isc::log::MessageID DHCP4_PACKET_DROP_DROP_CLASS; extern const isc::log::MessageID DHCP4_PACKET_NAK_0001; extern const isc::log::MessageID DHCP4_PACKET_NAK_0002; extern const isc::log::MessageID DHCP4_PACKET_NAK_0003; diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 40a02f109b..4bf6ea1bf5 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -509,6 +509,10 @@ This debug message is issued when a packet is dropped because it did contain option 53 and thus has no DHCP message type. The most likely explanation is that it was BOOTP packet. +% DHCP4_PACKET_DROP_DROP_CLASS dropped as member of the special DROP class: %1 +This informational message is emitted when an incoming packet was classified +into the special DROP class and dropped. The packet details are displayed. + % DHCP4_PACKET_NAK_0001 %1: failed to select a subnet for incoming packet, src %2, type %3 This error message is output when a packet was received from a subnet for which the DHCPv4 server has not been configured. The most probable diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index d434691c73..27c32ff4b7 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -1006,6 +1006,14 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp, bool allow_packet_park) { callout_handle->getArgument("query4", query); } + // Check the DROP special class. + if (query->inClass("DROP")) { + LOG_INFO(packet4_logger, DHCP4_PACKET_DROP_DROP_CLASS) + .arg(query->toText()); + // increase pkt4-receive-drop stats? + return; + } + AllocEngine::ClientContext4Ptr ctx; try { diff --git a/src/bin/dhcp4/tests/classify_unittest.cc b/src/bin/dhcp4/tests/classify_unittest.cc index 713fd8f4df..5c1f1047c7 100644 --- a/src/bin/dhcp4/tests/classify_unittest.cc +++ b/src/bin/dhcp4/tests/classify_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -75,6 +75,12 @@ namespace { /// option[93].hex == 0x0009 aka telephones /// option[93].hex == 0x0007 aka computers /// +/// - Configuration 5: +/// - Used for the DROP class +/// - 1 subnet: 10.0.0.0/24 +/// - 1 pool: 10.0.0.10-10.0.0.100 +/// - the following class defined: option[93].hex == 0x0009, DROP +/// const char* CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -275,6 +281,22 @@ const char* CONFIGS[] = { " } ]" "}", + // Configuration 5 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"valid-lifetime\": 600," + "\"client-classes\": [" + "{" + " \"name\": \"DROP\"," + " \"test\": \"option[93].hex == 0x0009\"" + "}]," + "\"subnet4\": [ { " + " \"subnet\": \"10.0.0.0/24\", " + " \"id\": 1," + " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]" + " } ]" + "}" }; /// @brief Test fixture class for testing classification. @@ -1107,4 +1129,31 @@ TEST_F(ClassifyTest, precedenceNetwork) { EXPECT_EQ("10.0.0.3", addrs[0].toText()); } +// This test checks the handling for the DROP special class. +TEST_F(ClassifyTest, dropClass) { + Dhcp4Client client(Dhcp4Client::SELECTING); + + // Configure DHCP server. + configure(CONFIGS[5], *client.getServer()); + + // Send the discover. + client.doDiscover(); + + // No option: no drop. + EXPECT_TRUE(client.getContext().response_); + + // Retry with an option matching the DROP class. + Dhcp4Client client2(Dhcp4Client::SELECTING); + + // Add the pxe option. + OptionPtr pxe(new OptionInt(Option::V4, 93, 0x0009)); + client2.addExtraOption(pxe); + + // Send the discover. + client2.doDiscover(); + + // Option, dropped. + EXPECT_FALSE(client2.getContext().response_); +} + } // end of anonymous namespace diff --git a/src/bin/dhcp6/dhcp6_messages.cc b/src/bin/dhcp6/dhcp6_messages.cc index eaab2c015f..712b076481 100644 --- a/src/bin/dhcp6/dhcp6_messages.cc +++ b/src/bin/dhcp6/dhcp6_messages.cc @@ -88,6 +88,7 @@ extern const isc::log::MessageID DHCP6_NO_SOCKETS_OPEN = "DHCP6_NO_SOCKETS_OPEN" extern const isc::log::MessageID DHCP6_OPEN_SOCKET = "DHCP6_OPEN_SOCKET"; extern const isc::log::MessageID DHCP6_OPEN_SOCKET_FAIL = "DHCP6_OPEN_SOCKET_FAIL"; extern const isc::log::MessageID DHCP6_PACKET_DROP_DHCP_DISABLED = "DHCP6_PACKET_DROP_DHCP_DISABLED"; +extern const isc::log::MessageID DHCP6_PACKET_DROP_DROP_CLASS = "DHCP6_PACKET_DROP_DROP_CLASS"; extern const isc::log::MessageID DHCP6_PACKET_DROP_PARSE_FAIL = "DHCP6_PACKET_DROP_PARSE_FAIL"; extern const isc::log::MessageID DHCP6_PACKET_DROP_SERVERID_MISMATCH = "DHCP6_PACKET_DROP_SERVERID_MISMATCH"; extern const isc::log::MessageID DHCP6_PACKET_DROP_UNICAST = "DHCP6_PACKET_DROP_UNICAST"; @@ -230,6 +231,7 @@ const char* values[] = { "DHCP6_OPEN_SOCKET", "opening service sockets on port %1", "DHCP6_OPEN_SOCKET_FAIL", "failed to open socket: %1", "DHCP6_PACKET_DROP_DHCP_DISABLED", "%1: DHCP service is globally disabled", + "DHCP6_PACKET_DROP_DROP_CLASS", "dropped as member of the special DROP class: %1", "DHCP6_PACKET_DROP_PARSE_FAIL", "failed to parse packet from %1 to %2, received over interface %3, reason: %4", "DHCP6_PACKET_DROP_SERVERID_MISMATCH", "%1: dropping packet with server identifier: %2, server is using: %3", "DHCP6_PACKET_DROP_UNICAST", "%1: dropping unicast %2 packet as this packet should be sent to multicast", diff --git a/src/bin/dhcp6/dhcp6_messages.h b/src/bin/dhcp6/dhcp6_messages.h index cc328c9d6a..f5580fd590 100644 --- a/src/bin/dhcp6/dhcp6_messages.h +++ b/src/bin/dhcp6/dhcp6_messages.h @@ -89,6 +89,7 @@ extern const isc::log::MessageID DHCP6_NO_SOCKETS_OPEN; extern const isc::log::MessageID DHCP6_OPEN_SOCKET; extern const isc::log::MessageID DHCP6_OPEN_SOCKET_FAIL; extern const isc::log::MessageID DHCP6_PACKET_DROP_DHCP_DISABLED; +extern const isc::log::MessageID DHCP6_PACKET_DROP_DROP_CLASS; extern const isc::log::MessageID DHCP6_PACKET_DROP_PARSE_FAIL; extern const isc::log::MessageID DHCP6_PACKET_DROP_SERVERID_MISMATCH; extern const isc::log::MessageID DHCP6_PACKET_DROP_UNICAST; diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes index 0ba507f94b..119ef9bfe3 100644 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -505,6 +505,10 @@ has been temporarily disabled. This affects all received DHCP packets. The service may be enabled by the "dhcp-enable" control command or automatically after a specified amount of time since receiving "dhcp-disable" command. +% DHCP6_PACKET_DROP_DROP_CLASS dropped as member of the special DROP class: %1 +This informational message is emitted when an incoming packet was classified +into the special DROP class and dropped. The packet details are displayed. + % DHCP6_PACKET_DROP_PARSE_FAIL failed to parse packet from %1 to %2, received over interface %3, reason: %4 The DHCPv6 server has received a packet that it is unable to interpret. The reason why the packet is invalid is included in the message. diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 64bb286dd0..5006977a05 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -683,6 +683,14 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) { return; } + // Check the DROP special class. + if (query->inClass("DROP")) { + LOG_INFO(packet6_logger, DHCP6_PACKET_DROP_DROP_CLASS) + .arg(query->toText()); + // increase pkt6-receive-drop stats? + return; + } + if (query->getType() == DHCPV6_DHCPV4_QUERY) { // This call never throws. Should this change, this section must be // enclosed in try-catch. diff --git a/src/bin/dhcp6/tests/classify_unittests.cc b/src/bin/dhcp6/tests/classify_unittests.cc index 9620874853..b37ce46ecd 100644 --- a/src/bin/dhcp6/tests/classify_unittests.cc +++ b/src/bin/dhcp6/tests/classify_unittests.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -67,6 +67,12 @@ namespace { /// option 1234 'foo' aka telephones /// option 1234 'bar' aka computers /// +/// - Configuration 3: +/// - Used for the DROP class +/// - 1 subnet: 2001:db8:1::/48 +/// - 2 pool: 2001:db8:1:1::/64 +/// - the following class defined: option 1234 'foo', DROP +/// const char* CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -249,8 +255,38 @@ const char* CONFIGS[] = { " \"prefix-len\": 48, \"delegated-len\": 64," " \"client-class\": \"server2_and_computers\" } ]" " } ]," - "\"valid-lifetime\": 4000 }" + "\"valid-lifetime\": 4000 }", + // Configuration 3 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"option-def\": [ " + "{" + " \"name\": \"host-name\"," + " \"code\": 1234," + " \"type\": \"string\"" + "}," + "{" + " \"name\": \"ipv6-forwarding\"," + " \"code\": 2345," + " \"type\": \"boolean\"" + "} ]," + "\"client-classes\": [" + "{" + " \"name\": \"DROP\"," + " \"test\": \"option[host-name].text == 'foo'\"" + "}" + "]," + "\"subnet6\": [ " + "{ \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], " + " \"subnet\": \"2001:db8:1::/48\", " + " \"interface\": \"eth1\"" + " } ]," + "\"valid-lifetime\": 4000 }" }; /// @brief Test fixture class for testing client classification by the @@ -2042,4 +2078,35 @@ TEST_F(ClassifyTest, pDserver2Computer) { EXPECT_EQ("2001:db8:4::", lease_client.addr_.toText()); } +// This test checks the handling for the DROP special class. +TEST_F(ClassifyTest, dropClass) { + Dhcp6Client client; + client.setDUID("01:02:03:05"); + client.setInterface("eth1"); + client.requestAddress(); + + // Configure DHCP server. + ASSERT_NO_THROW(configure(CONFIGS[3], *client.getServer())); + + // Send a message to the server. + ASSERT_NO_THROW(client.doSolicit(true)); + + // No option: no drop. + EXPECT_TRUE(client.getContext().response_); + + // Retry with an option matching the DROP class. + Dhcp6Client client2; + + // Add the host-name option. + OptionStringPtr hostname(new OptionString(Option::V6, 1234, "foo")); + ASSERT_TRUE(hostname); + client2.addExtraOption(hostname); + + // Send a message to the server. + ASSERT_NO_THROW(client2.doSolicit(true)); + + // Option, dropped. + EXPECT_FALSE(client2.getContext().response_); +} + } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/client_class_def.cc b/src/lib/dhcpsrv/client_class_def.cc index 2a9a52098a..bb18d8c328 100644 --- a/src/lib/dhcpsrv/client_class_def.cc +++ b/src/lib/dhcpsrv/client_class_def.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -341,6 +341,10 @@ ClientClassDictionary::toElement() const { std::list builtinNames = { + // DROP is not in this list because it is special but not built-in. + // In fact DROP is set from an expression as callouts can drop + // directly the incoming packet. The expression must not depend on + // KNOWN/UNKNOWN which are set far after the drop point. "ALL", "KNOWN", "UNKNOWN" }; diff --git a/src/lib/dhcpsrv/client_class_def.h b/src/lib/dhcpsrv/client_class_def.h index 94e03c2c56..88425d0a97 100644 --- a/src/lib/dhcpsrv/client_class_def.h +++ b/src/lib/dhcpsrv/client_class_def.h @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -382,7 +382,7 @@ private: typedef boost::shared_ptr ClientClassDictionaryPtr; /// @brief List of built-in client class names. -/// i.e. ALL, KNOWN and UNKNOWN. +/// i.e. ALL, KNOWN and UNKNOWN but not DROP. extern std::list builtinNames; /// @brief List of built-in client class prefixes diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc index 7177a4b7c6..4be5e85dcf 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc @@ -203,6 +203,32 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, } + // Sanity checks on built-in classes + for (auto bn : builtinNames) { + if (name == bn) { + if (required) { + isc_throw(DhcpConfigError, "built-in class '" << name + << "' only-if-required flag must be false"); + } + if (!test.empty()) { + isc_throw(DhcpConfigError, "built-in class '" << name + << "' test expression must be empty"); + } + } + } + + // Sanity checks on DROP + if (name == "DROP") { + if (required) { + isc_throw(DhcpConfigError, "special class '" << name + << "' only-if-required flag must be false"); + } + if (depend_on_known) { + isc_throw(DhcpConfigError, "special class '" << name + << "' must not depend on 'KNOWN'/'UNKNOWN' classes"); + } + } + // Add the client class definition try { class_dictionary->addClass(name, match_expr, test, required, diff --git a/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc index 0f24931150..813d46d75a 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -1185,4 +1185,110 @@ TEST_F(ClientClassDefListParserTest, dependOnKnown) { EXPECT_TRUE(cclass->getDependOnKnown()); } +// Verifies that a built-in class can't be required or evaluated. +TEST_F(ClientClassDefListParserTest, builtinCheckError) { + std::string cfg_text = + "[ \n" + " { \n" + " \"name\": \"ALL\" \n" + " } \n" + "] \n"; + + EXPECT_NO_THROW(parseClientClassDefList(cfg_text, AF_INET6)); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"ALL\", \n" + " \"only-if-required\": true \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET), DhcpConfigError); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"ALL\", \n" + " \"test\": \"'aa' == 'aa'\" \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"KNOWN\", \n" + " \"only-if-required\": true \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET), DhcpConfigError); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"KNOWN\", \n" + " \"test\": \"'aa' == 'aa'\" \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"UNKNOWN\", \n" + " \"only-if-required\": true \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET), DhcpConfigError); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"UNKNOWN\", \n" + " \"test\": \"'aa' == 'aa'\" \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError); +} + +// Verifies that the special DROP class can't be required or +// dependent on KNOWN/UNKNOWN +TEST_F(ClientClassDefListParserTest, dropCheckError) { + std::string cfg_text = + "[ \n" + " { \n" + " \"name\": \"DROP\", \n" + " \"test\": \"option[123].text == 'abc'\" \n" + " } \n" + "] \n"; + + EXPECT_NO_THROW(parseClientClassDefList(cfg_text, AF_INET6)); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"DROP\", \n" + " \"only-if-required\": true \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET), DhcpConfigError); + + cfg_text = + "[ \n" + " { \n" + " \"name\": \"DROP\", \n" + " \"test\": \"member('KNOWN')\" \n" + " } \n" + "] \n"; + + EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError); +} + } // end of anonymous namespace