+1955. [bug] tmark
+ kea-dhcp4 no longer sends DHCPNAKs in response to
+ DHCPREQUESTs for addresses for which it has no knowledge.
+ (Gitlab #1584)
+
1954. [doc] fdupont
Updated the Developer's Guide to explain what to do when
GSS-TSIG hook unit tests fail from a system Kerberos
incompatible configuration.
(Gitlab #2056)
-1953. [build] fdupont
+1953. [build] fdupont
Changed the name of the GSS-TSIG hook library object to
libddns_gss_tsig.so.
(Gitlab #2115)
extern const isc::log::MessageID DHCP4_SUBNET_SELECTED = "DHCP4_SUBNET_SELECTED";
extern const isc::log::MessageID DHCP4_SUBNET_SELECTION_FAILED = "DHCP4_SUBNET_SELECTION_FAILED";
extern const isc::log::MessageID DHCP4_TESTING_MODE_SEND_TO_SOURCE_ENABLED = "DHCP4_TESTING_MODE_SEND_TO_SOURCE_ENABLED";
+extern const isc::log::MessageID DHCP4_UNKNOWN_ADDRESS_REQUESTED = "DHCP4_UNKNOWN_ADDRESS_REQUESTED";
extern const isc::log::MessageID DHCP6_DHCP4O6_PACKET_RECEIVED = "DHCP6_DHCP4O6_PACKET_RECEIVED";
} // namespace dhcp
"DHCP4_SUBNET_SELECTED", "%1: the subnet with ID %2 was selected for client assignments",
"DHCP4_SUBNET_SELECTION_FAILED", "%1: failed to select subnet for the client",
"DHCP4_TESTING_MODE_SEND_TO_SOURCE_ENABLED", "All packets will be send to source address of an incoming packet - use only for testing",
+ "DHCP4_UNKNOWN_ADDRESS_REQUESTED", "%1: client requested an unknown address, client sent ciaddr %2, requested-ip-address %3",
"DHCP6_DHCP4O6_PACKET_RECEIVED", "received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 port %3 on interface %4",
NULL
};
extern const isc::log::MessageID DHCP4_SUBNET_SELECTED;
extern const isc::log::MessageID DHCP4_SUBNET_SELECTION_FAILED;
extern const isc::log::MessageID DHCP4_TESTING_MODE_SEND_TO_SOURCE_ENABLED;
+extern const isc::log::MessageID DHCP4_UNKNOWN_ADDRESS_REQUESTED;
extern const isc::log::MessageID DHCP6_DHCP4O6_PACKET_RECEIVED;
} // namespace dhcp
% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 port %3 on interface %4
This debug message is printed when the server is receiving a DHCPv4o6
from the DHCPv6 server over inter-process communication.
+
+% DHCP4_UNKNOWN_ADDRESS_REQUESTED %1: client requested an unknown address, client sent ciaddr %2, requested-ip-address %3
+This message indicates that the client requested an address that does
+not belong to any dynamic pools managed by this server. The first argument
+contains the client and the transaction identification information.
+The second argument contains the IPv4 address in the ciaddr field. The
+third argument contains the IPv4 address in the requested-ip-address
+option (if present).
// it should include this hint. That will help us during the actual lease
// allocation.
bool fake_allocation = (query->getType() == DHCPDISCOVER);
+ Subnet4Ptr original_subnet = subnet;
// Get client-id. It is not mandatory in DHCPv4.
ClientIdPtr client_id = ex.getContext()->clientid_;
.arg(hint.toText());
Lease4Ptr lease;
- Subnet4Ptr original_subnet = subnet;
+// Subnet4Ptr original_subnet = subnet;
// We used to issue a separate query (two actually: one for client-id
// and another one for hw-addr for) each subnet in the shared network.
} else {
// Allocation engine did not allocate a lease. The engine logged
// cause of that failure.
+ if ((ctx->unknown_requested_addr_) /*&& !original_subnet->getAuthoritative()*/) {
+ Subnet4Ptr s = original_subnet;
+ // Address might have been rejected via class guard (i.e. not allowed for
+ // this client). We need to determine if we truly do not know about the
+ // address or whether this client just isn't allowed to have that address.
+ // We should only NAK For the latter.
+ while (s) {
+ if (s->inPool(Lease::TYPE_V4, hint)) {
+ break;
+ }
+
+ s = s->getNextSubnet(original_subnet);
+ }
+
+ // If we didn't find a subnet, it's not an address we know about
+ // so we we drop the NAK.
+ if (!s) {
+ LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL,
+ DHCP4_UNKNOWN_ADDRESS_REQUESTED)
+ .arg(query->getLabel())
+ .arg(query->getCiaddr().toText())
+ .arg(opt_requested_address ?
+ opt_requested_address->readAddress().toText() : "(no address)");
+ ex.deleteResponse();
+ return;
+ }
+ }
+
LOG_DEBUG(bad_packet4_logger, DBG_DHCP4_DETAIL, fake_allocation ?
DHCP4_PACKET_NAK_0003 : DHCP4_PACKET_NAK_0004)
.arg(query->getLabel())
// Configure DHCP server.
configure(DORA_CONFIGS[15], *client.getServer());
client.includeClientId("11:22");
+
+ // Try to renew an address that is outside the pool.
+ client.setState(Dhcp4Client::RENEWING);
+ client.ciaddr_ = IOAddress("10.0.0.9");
+ ASSERT_NO_THROW_LOG(client.doRequest());
+ // Even though we're authoritative server should not respond
+ // since it does not know this address.
+ ASSERT_FALSE(client.getContext().response_);
+
// Obtain a lease from the server using the 4-way exchange.
+ client.ciaddr_ = IOAddress("0.0.0.0");
+ client.setState(Dhcp4Client::SELECTING);
ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
IOAddress>(new IOAddress("10.0.0.50"))));
// Make sure that the server responded.
// Configure DHCP server.
configure(DORA_CONFIGS[16], *client.getServer());
client.includeClientId("11:22");
+
+ // Try to renew an address that is outside the pool.
+ client.setState(Dhcp4Client::RENEWING);
+ client.ciaddr_ = IOAddress("10.0.0.9");
+ ASSERT_NO_THROW_LOG(client.doRequest());
+ // We are not authoritative sure that the server does
+ // not respond at all.
+ ASSERT_FALSE(client.getContext().response_);
+
// Obtain a lease from the server using the 4-way exchange.
+ client.ciaddr_ = IOAddress("0.0.0.0");
+ client.setState(Dhcp4Client::SELECTING);
ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
IOAddress>(new IOAddress("10.0.0.50"))));
// Make sure that the server responded.
// Try to renew the existing lease again.
ASSERT_NO_THROW(client.doRequest());
- // The reservation has been removed, so the server should respond with
- // a DHCPNAK because the address that the client is using doesn't belong
- // to a dynamic pool.
+
+ // The reservation has been removed. Since address that the client is
+ // using doesn't belong a dynamic pool and the server is not
+ // authoritative it should not send a DHCPNAK.
resp = client.getContext().response_;
- ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
+ ASSERT_FALSE(client.getContext().response_);
// A conforming client would go back to the server discovery.
client.setState(Dhcp4Client::SELECTING);
ASSERT_NO_THROW(client.doRequest());
- // Make sure that we received a response
- ASSERT_TRUE(client.getContext().response_);
-
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("leases4_committed", callback_name_);
+ // Make sure that we did not receive a response. If we're
+ // not authoritative, there should not be a NAK.
+ ASSERT_FALSE(client.getContext().response_);
+ // Check that no callback was not called.
+ EXPECT_EQ("", callback_name_);
EXPECT_FALSE(callback_lease4_);
EXPECT_FALSE(callback_deleted_lease4_);
-
- // Check if the callout handle state was reset after the callout.
- checkCalloutHandleReset(client.getContext().query_);
}
// This test verifies that the callout installed on the leases4_committed hook
/// @brief Enum for specifying expected response to client renewal attempt
enum RenewOutcome {
DOES_RENEW,
- DOES_NOT_RENEW
+ DOES_NOT_RENEW,
+ DOES_NOT_NAK
};
/// @brief Enum for specifying expected response to client release attempt
ASSERT_NO_THROW(client.doRequest());
resp = client.getContext().response_;
- // Verify we got ACK'd or NAK'd as expected
- ASSERT_EQ((renew_outcome == DOES_RENEW ? DHCPACK : DHCPNAK),
- static_cast<int>(resp->getType()));
+ switch(renew_outcome) {
+ case DOES_RENEW:
+ ASSERT_TRUE(resp);
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+ break;
+ case DOES_NOT_RENEW:
+ ASSERT_TRUE(resp);
+ ASSERT_EQ(DHCPNAK, static_cast<int>(resp->getType()));
+ break;
+ case DOES_NOT_NAK:
+ ASSERT_FALSE(resp);
+ break;
+ }
// Verify that the lease still exists in the database as it has not
// been explicitly released.
std::string expected_address = "";
oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address,
- DOES_NOT_RENEW);
+ DOES_NOT_NAK);
}
std::string hwaddress = "dd:dd:dd:dd:dd:01";
std::string expected_address = "";
- oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address, DOES_NOT_RENEW);
+ oorRenewReleaseTest(DIFF_POOL, hwaddress, expected_address, DOES_NOT_NAK);
}
// Test verifies that once-valid dynamic address host reservation,
std::string hwaddress = "ff:ff:ff:ff:ff:01";
std::string expected_address = "10.0.0.7";
- oorRenewReleaseTest(NO_HR, hwaddress, expected_address, DOES_NOT_RENEW);
+ oorRenewReleaseTest(NO_HR, hwaddress, expected_address, DOES_NOT_NAK);
}
// Test verifies that once-valid fixed address host reservation,
fwd_dns_update_(false), rev_dns_update_(false),
hostname_(""), callout_handle_(), fake_allocation_(false),
old_lease_(), new_lease_(), hosts_(), conflicting_lease_(),
- query_(), host_identifiers_(),
+ query_(), host_identifiers_(), unknown_requested_addr_(false),
ddns_params_() {
}
fwd_dns_update_(fwd_dns_update), rev_dns_update_(rev_dns_update),
hostname_(hostname), callout_handle_(),
fake_allocation_(fake_allocation), old_lease_(), new_lease_(),
- hosts_(), host_identifiers_(),
+ hosts_(), host_identifiers_(), unknown_requested_addr_(false),
ddns_params_(new DdnsParams()) {
// Initialize host identifiers.
.arg(ctx.query_->getLabel())
.arg(ctx.requested_address_);
+ ctx.unknown_requested_addr_ = true;
return (Lease4Ptr());
}
}
/// received by the server.
IdentifierList host_identifiers_;
+ /// @brief True when the address DHPCREQUEST'ed by client is not within
+ /// a dynamic pool the server knows about.
+ bool unknown_requested_addr_;
+
/// @brief Returns the set of DDNS behavioral parameters based on
/// the selected subnet.
///
/// @return pointer to a DdnsParams instance
DdnsParamsPtr getDdnsParams();
+
/// @brief Convenience function adding host identifier into
/// @ref host_identifiers_ list.
///