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, nor to make DROP class dependent of KNOWN/UNKNOWN classes.
+ a subnet.
-9. If needed, addresses and prefixes from pools are assigned, possibly
+9. When the incoming packet belongs the special class, `DROP`, it is
+ dropped and an informational message is logged with the packet
+ information. Since Kea version 1.9.8 it is allowed to make DROP
+ class dependent of KNOWN/UNKNOWN classes.
+
+10. If needed, addresses and prefixes from pools are assigned, possibly
based on the class information when some pools are reserved for
class members.
-10. Classes marked as "required" are evaluated in the order in which
+11. Classes marked as "required" are evaluated in the order in which
they are listed: first the shared network, then the subnet, and
finally the pools that assigned resources belong to.
-11. Options are assigned, again possibly based on the class information
+12. Options are assigned, again possibly based on the class information
in the order that classes were associated with the incoming packet.
For DHCPv4 private and code 43 options, this includes class local
option definitions.
extern const isc::log::MessageID DHCP4_PACKET_DROP_0010 = "DHCP4_PACKET_DROP_0010";
extern const isc::log::MessageID DHCP4_PACKET_DROP_0011 = "DHCP4_PACKET_DROP_0011";
extern const isc::log::MessageID DHCP4_PACKET_DROP_0012 = "DHCP4_PACKET_DROP_0012";
+extern const isc::log::MessageID DHCP4_PACKET_DROP_0013 = "DHCP4_PACKET_DROP_0013";
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";
"DHCP4_PACKET_DROP_0010", "dropped as member of the special class 'DROP': %1",
"DHCP4_PACKET_DROP_0011", "dropped as sent by the same client than a packet being processed by another thread: dropped %1 by thread %2 as duplicate of %3 processed by %4",
"DHCP4_PACKET_DROP_0012", "dropped as sent by the same client than a packet being processed by another thread: dropped %1 by thread %2 as duplicate of %3 processed by %4",
+ "DHCP4_PACKET_DROP_0013", "dropped as member of the special class 'DROP' after host reservation lookup: %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",
extern const isc::log::MessageID DHCP4_PACKET_DROP_0010;
extern const isc::log::MessageID DHCP4_PACKET_DROP_0011;
extern const isc::log::MessageID DHCP4_PACKET_DROP_0012;
+extern const isc::log::MessageID DHCP4_PACKET_DROP_0013;
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;
Packet details and thread identifiers are included for both packets in
this warning message.
+% DHCP4_PACKET_DROP_0013 dropped as member of the special class 'DROP' after host reservation lookup: %1
+This debug message is emitted when an incoming packet was classified
+after host reservation lookup into the special class 'DROP' 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
Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
const Pkt4Ptr& query,
- const Subnet4Ptr& subnet)
+ const Subnet4Ptr& subnet,
+ bool& drop)
: alloc_engine_(alloc_engine), query_(query), resp_(),
context_(new AllocEngine::ClientContext4()) {
.arg(query_->getLabel())
.arg(classes.toText());
}
+
+ // Check the DROP special class.
+ if (query_->inClass("DROP")) {
+ LOG_DEBUG(packet4_logger, DBGLVL_TRACE_BASIC, DHCP4_PACKET_DROP_0013)
+ .arg(query_->toText());
+ isc::stats::StatsMgr::instance().addValue("pkt4-receive-drop",
+ static_cast<int64_t>(1));
+ drop = true;
+ }
+
+
}
void
sanityCheck(discover, FORBIDDEN);
bool drop = false;
- Dhcpv4Exchange ex(alloc_engine_, discover, selectSubnet(discover, drop));
+ Subnet4Ptr subnet = selectSubnet(discover, drop);
// Stop here if selectSubnet decided to drop the packet
if (drop) {
return (Pkt4Ptr());
}
+ Dhcpv4Exchange ex(alloc_engine_, discover, subnet, drop);
+
+ // Stop here if Dhcpv4Exchange constructir decided to drop the packet
+ if (drop) {
+ return (Pkt4Ptr());
+ }
+
if (MultiThreadingMgr::instance().getMode()) {
// The lease reclamation cannot run at the same time.
ReadLockGuard share(alloc_engine_->getReadWriteMutex());
sanityCheck(request, OPTIONAL);
bool drop = false;
- Dhcpv4Exchange ex(alloc_engine_, request, selectSubnet(request, drop));
+ Subnet4Ptr subnet = selectSubnet(request, drop);
// Stop here if selectSubnet decided to drop the packet
if (drop) {
return (Pkt4Ptr());
}
+ Dhcpv4Exchange ex(alloc_engine_, request, subnet, drop);
+
+ // Stop here if Dhcpv4Exchange constructir decided to drop the packet
+ if (drop) {
+ return (Pkt4Ptr());
+ }
+
// Note that we treat REQUEST message uniformly, regardless if this is a
// first request (requesting for new address), renewing existing address
// or even rebinding.
sanityCheck(inform, OPTIONAL);
bool drop = false;
- Dhcpv4Exchange ex(alloc_engine_, inform, selectSubnet(inform, drop));
+ Subnet4Ptr subnet = selectSubnet(inform, drop);
// Stop here if selectSubnet decided to drop the packet
if (drop) {
return (Pkt4Ptr());
}
+ Dhcpv4Exchange ex(alloc_engine_, inform, subnet, drop);
+
+ // Stop here if Dhcpv4Exchange constructir decided to drop the packet
+ if (drop) {
+ return (Pkt4Ptr());
+ }
+
Pkt4Ptr ack = ex.getResponse();
// If this is global reservation or the subnet doesn't belong to a shared
/// used by the server.
/// @param query Pointer to the client message.
/// @param subnet Pointer to the subnet to which the client belongs.
+ /// @param drop if it is true the packet will be dropped.
Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query,
- const Subnet4Ptr& subnet);
+ const Subnet4Ptr& subnet, bool& drop);
/// @brief Initializes the instance of the response message.
///
-// Copyright (C) 2016-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2021 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
/// - 1 pool: 10.0.0.10-10.0.0.100
/// - the following class defined: option[93].hex == 0x0009, DROP
///
+/// - Configuration 6:
+/// - Used for the DROP class and reservations.
+/// - 1 subnet: 10.0.0.0/24
+/// - 1 pool: 10.0.0.10-10.0.0.100
+/// - 1 reservation for HW address 'aa:bb:cc:dd:ee:ff'
+/// - the following class defined: not member('KNOWN'), DROP
+/// (the not member also verifies that the DROP class is set only
+/// after the host reservation lookup)
+/// @note the reservation includes a hostname because raw reservations are
+/// not yet allowed.
+///
const char* CONFIGS[] = {
// Configuration 0
"{ \"interfaces-config\": {"
" \"id\": 1,"
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]"
" } ]"
+ "}",
+
+ // Configuration 6
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"client-classes\": ["
+ "{"
+ " \"name\": \"DROP\","
+ " \"test\": \"member('UNKNOWN')\""
+ "}],"
+ "\"subnet4\": [ { "
+ " \"subnet\": \"10.0.0.0/24\", "
+ " \"id\": 1,"
+ " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
+ " \"reservations\": [ {"
+ " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+ " \"hostname\": \"allowed\" } ]"
+ " } ]"
"}"
};
EXPECT_EQ(1, drop_stat->getInteger().first);
}
+// This test checks the handling for the DROP special class at the host
+// reservation classification point.
+TEST_F(ClassifyTest, dropClassHR) {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+
+ // Configure DHCP server.
+ configure(CONFIGS[6], *client.getServer());
+
+ // Set the HW address to the reservation.
+ client.setHWAddress("aa:bb:cc:dd:ee:ff");
+
+ // Send the discover.
+ client.doDiscover();
+
+ // Reservation match: no drop.
+ EXPECT_TRUE(client.getContext().response_);
+
+ // Retry with another HW address.
+ Dhcp4Client client2(Dhcp4Client::SELECTING);
+ client2.setHWAddress("aa:bb:cc:dd:ee:fe");
+
+ // Send the discover.
+ client2.doDiscover();
+
+ // No reservation, dropped.
+ EXPECT_FALSE(client2.getContext().response_);
+
+ // There should also be pkt4-receive-drop stat bumped up.
+ stats::StatsMgr& mgr = stats::StatsMgr::instance();
+ stats::ObservationPtr drop_stat = mgr.getObservation("pkt4-receive-drop");
+
+ // This statistic must be present and must be set to 1.
+ ASSERT_TRUE(drop_stat);
+ EXPECT_EQ(1, drop_stat->getInteger().first);
+}
+
} // end of anonymous namespace
Dhcpv4Exchange
Dhcpv4SrvTest::createExchange(const Pkt4Ptr& query) {
bool drop = false;
- Dhcpv4Exchange ex(srv_.alloc_engine_, query,
- srv_.selectSubnet(query, drop));
+ Subnet4Ptr subnet = srv_.selectSubnet(query, drop);
+ EXPECT_FALSE(drop);
+ Dhcpv4Exchange ex(srv_.alloc_engine_, query, subnet, drop);
EXPECT_FALSE(drop);
return (ex);
}
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");
- }
+ // depend_on_known is now allowed
}
// Add the client class definition
EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError);
}
-// Verifies that the special DROP class can't be required or
-// dependent on KNOWN/UNKNOWN
+// Verifies that the special DROP class can't be required.
TEST_F(ClientClassDefListParserTest, dropCheckError) {
std::string cfg_text =
"[ \n"
EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET), DhcpConfigError);
+ // This constraint was relaxed in #1815.
cfg_text =
"[ \n"
" { \n"
" } \n"
"] \n";
- EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError);
+ EXPECT_NO_THROW(parseClientClassDefList(cfg_text, AF_INET6));
}
// Verify the ability to configure lease lifetime triplet.