diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc index f4ed874589..9bdb9df2d0 100644 --- a/src/bin/dhcp4/dhcp4_messages.cc +++ b/src/bin/dhcp4/dhcp4_messages.cc @@ -143,6 +143,7 @@ extern const isc::log::MessageID DHCP4_SUBNET_DATA = "DHCP4_SUBNET_DATA"; extern const isc::log::MessageID DHCP4_SUBNET_DYNAMICALLY_CHANGED = "DHCP4_SUBNET_DYNAMICALLY_CHANGED"; 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 DHCP6_DHCP4O6_PACKET_RECEIVED = "DHCP6_DHCP4O6_PACKET_RECEIVED"; } // namespace dhcp @@ -287,6 +288,7 @@ const char* values[] = { "DHCP4_SUBNET_DYNAMICALLY_CHANGED", "%1: changed selected subnet %2 to subnet %3 from shared network %4 for client assignments", "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", "DHCP6_DHCP4O6_PACKET_RECEIVED", "received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 port %3 on interface %4", NULL }; diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h index fc649fe66f..2061e44d12 100644 --- a/src/bin/dhcp4/dhcp4_messages.h +++ b/src/bin/dhcp4/dhcp4_messages.h @@ -144,6 +144,7 @@ extern const isc::log::MessageID DHCP4_SUBNET_DATA; extern const isc::log::MessageID DHCP4_SUBNET_DYNAMICALLY_CHANGED; 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 DHCP6_DHCP4O6_PACKET_RECEIVED; } // namespace dhcp diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index 7b9cc4774c..7ecbe1e387 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -6,6 +6,12 @@ $NAMESPACE isc::dhcp +% DHCP4_TESTING_MODE_SEND_TO_SOURCE_ENABLED All packets will be send to source address of an incoming packet - use only for testing +This message is printed then KEA_TEST_SEND_RESPONSES_TO_SOURCE environment +variable is set to ENABLED. It's causing Kea to send packets to source address +of incoming packet. Usable just in testing environment to simulate multiple +subnet traffic from single source. + % DHCP4_ACTIVATE_INTERFACE activating interface %1 This message is printed when DHCPv4 server enabled an interface to be used to receive DHCPv4 traffic. IPv4 socket on this interface will be opened once diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 2faee32d7b..1a4f68a5bb 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -588,6 +588,8 @@ void Dhcpv4Exchange::evaluateClasses(const Pkt4Ptr& pkt, bool depend_on_known) { const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_"); +bool Dhcpv4Srv::Dhcpv4Srv::test_send_responses_to_source_(false); + Dhcpv4Srv::Dhcpv4Srv(uint16_t server_port, uint16_t client_port, const bool use_bcast, const bool direct_response_desired) : io_service_(new IOService()), server_port_(server_port), @@ -596,6 +598,14 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t server_port, uint16_t client_port, network_state_(new NetworkState(NetworkState::DHCPv4)), cb_control_(new CBControlDHCPv4()) { + const char* env = std::getenv("KEA_TEST_SEND_RESPONSES_TO_SOURCE"); + if (env) { + if (strncmp(env, "ENABLED", 7) == 0) { + LOG_WARN(dhcp4_logger, DHCP4_TESTING_MODE_SEND_TO_SOURCE_ENABLED); + setSendResponsesToSource(true); + } + } + LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET) .arg(server_port); @@ -2716,6 +2726,11 @@ Dhcpv4Srv::adjustRemoteAddr(Dhcpv4Exchange& ex) { } else { response->setRemoteAddr(query->getRemoteAddr()); } + + if (getSendResponsesToSource()) { + response->setRemoteAddr(query->getRemoteAddr()); + } + // Remote address is now set so return. return; } @@ -2773,6 +2788,10 @@ Dhcpv4Srv::adjustRemoteAddr(Dhcpv4Exchange& ex) { response->setRemoteAddr(query->getRemoteAddr()); } + + if (getSendResponsesToSource()) { + response->setRemoteAddr(query->getRemoteAddr()); + } } void diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h index bc26386a0f..107d6b4906 100644 --- a/src/bin/dhcp4/dhcp4_srv.h +++ b/src/bin/dhcp4/dhcp4_srv.h @@ -741,6 +741,24 @@ public: /// will cause the packet to be assigned to class VENDOR_CLASS_FOO. static const std::string VENDOR_CLASS_PREFIX; + /// @brief This function set test_send_responses_to_source_ value + /// + /// If environment variable KEA_TEST_SEND_RESPONSES_TO_SOURCE will be + /// set to ENABLED this function will set value true to + /// test_send_responses_to_source_. + /// + /// @param bool value of test_send_responses_to_source_ + void setSendResponsesToSource(const bool value) { + test_send_responses_to_source_ = value; + } + + /// @brief returns value of test_send_responses_to_source_ + /// + /// @return bool value of test_send_responses_to_source_ + static bool getSendResponsesToSource() { + return test_send_responses_to_source_; + } + private: /// @brief Process Client FQDN %Option sent by a client. /// @@ -1060,6 +1078,12 @@ protected: /// @brief Controls access to the configuration backends. CBControlDHCPv4Ptr cb_control_; +private: + + /// @brief value that define is send response to source mode is enabled + /// holds ture if it is. + static bool test_send_responses_to_source_; + public: /// Class methods for DHCPv4-over-DHCPv6 handler diff --git a/src/bin/dhcp4/tests/shared_network_unittest.cc b/src/bin/dhcp4/tests/shared_network_unittest.cc index 2a6720b42c..427fa3b80a 100644 --- a/src/bin/dhcp4/tests/shared_network_unittest.cc +++ b/src/bin/dhcp4/tests/shared_network_unittest.cc @@ -22,6 +22,7 @@ #include #include #include +#include using namespace isc; using namespace isc::asiolink; @@ -2198,6 +2199,58 @@ TEST_F(Dhcpv4SharedNetworkTest, poolInSubnetSelectedByClass) { }); } +// Check if Kea starts with send to source mode enabled +TEST_F(Dhcpv4SharedNetworkTest, sharedNetworkCheckIfSendToSourceTestingModeEnabled) { + // Set env variable that put kea into testing mode + setenv("KEA_TEST_SEND_RESPONSES_TO_SOURCE", "ENABLED", 1); + Dhcp4Client client1(Dhcp4Client::SELECTING); + configure(NETWORKS_CONFIG[1], *client1.getServer()); + // Check if send to source testing mode is enabled + EXPECT_TRUE(isc::dhcp::test::NakedDhcpv4Srv::getSendResponsesToSource()); + + unsetenv("KEA_TEST_SEND_RESPONSES_TO_SOURCE"); +} + +// Shared network is selected based on giaddr value (relay specified +// on shared network level, but response is send to source address. +TEST_F(Dhcpv4SharedNetworkTest, sharedNetworkSendToSourceTestingModeEnabled) { + // Create client #1. This is a relayed client which is using relay + // address matching configured shared network. + // Source address is set to unrelated to configuration. + + // Set env variable that put kea into testing mode + //setenv("KEA_TEST_SEND_RESPONSES_TO_SOURCE", "ENABLED", 1); + Dhcp4Client client1(Dhcp4Client::SELECTING); + client1.useRelay(true, IOAddress("192.3.5.6"), IOAddress("1.1.1.2")); + // Configure the server with one shared network and one subnet outside of the + // shared network. + configure(NETWORKS_CONFIG[1], *client1.getServer()); + //EXPECT_TRUE(isc::dhcp::test::NakedDhcpv4Srv::getSendResponsesToSource()); + // Client #1 should be assigned an address from shared network. + testAssigned([this, &client1] { + doDORA(client1, "192.0.2.63", "192.0.2.63"); + }); + + // normally Kea would send packet to 192.3.5.6 but we want it get from + // 1.1.1.2 in send to source testing mode but still with correctly + // assigned address. + Pkt4Ptr resp1 = client1.getContext().response_; + EXPECT_EQ("1.1.1.2", resp1->getLocalAddr().toText()); + + // Create client #2. This is a relayed client which is using relay + // address matching subnet outside of the shared network. + Dhcp4Client client2(client1.getServer(), Dhcp4Client::SELECTING); + client2.useRelay(true, IOAddress("192.1.2.3"), IOAddress("2.2.2.3")); + testAssigned([this, &client2] { + doDORA(client2, "192.0.2.65", "192.0.2.63"); + }); + + Pkt4Ptr resp2 = client2.getContext().response_; + EXPECT_EQ("2.2.2.3", resp2->getLocalAddr().toText()); + // remove variable + unsetenv("KEA_TEST_SEND_RESPONSES_TO_SOURCE"); +} + // Verify option processing precedence // Order is global < class < shared-network < subnet < pool < host reservation TEST_F(Dhcpv4SharedNetworkTest, precedenceGlobal) {