8#include <kea_version.h>
61#include <boost/algorithm/string.hpp>
62#include <boost/foreach.hpp>
63#include <boost/range/adaptor/reversed.hpp>
64#include <boost/pointer_cast.hpp>
65#include <boost/shared_ptr.hpp>
83namespace ph = std::placeholders;
89 int hook_index_buffer4_receive_;
90 int hook_index_pkt4_receive_;
91 int hook_index_subnet4_select_;
92 int hook_index_leases4_committed_;
93 int hook_index_lease4_release_;
94 int hook_index_pkt4_send_;
95 int hook_index_buffer4_send_;
96 int hook_index_lease4_decline_;
97 int hook_index_host4_identifier_;
98 int hook_index_ddns4_update_;
99 int hook_index_lease4_offer_;
100 int hook_index_lease4_server_decline_;
121std::set<std::string> dhcp4_statistics = {
123 "pkt4-discover-received",
124 "pkt4-offer-received",
125 "pkt4-request-received",
128 "pkt4-release-received",
129 "pkt4-decline-received",
130 "pkt4-inform-received",
131 "pkt4-unknown-received",
138 "v4-allocation-fail",
139 "v4-allocation-fail-shared-network",
140 "v4-allocation-fail-subnet",
141 "v4-allocation-fail-no-pools",
142 "v4-allocation-fail-classes",
143 "v4-reservation-conflicts",
163 : alloc_engine_(alloc_engine), query_(query), resp_(),
164 context_(context), ipv6_only_preferred_(false) {
166 if (!alloc_engine_) {
168 " when creating an instance of the Dhcpv4Exchange");
173 " creating an instance of the Dhcpv4Exchange");
182 context_->subnet_ = subnet;
188 if (subnet && !context_->early_global_reservations_lookup_) {
189 OptionPtr opt_clientid = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
191 context_->clientid_.reset(
new ClientId(opt_clientid->getData()));
197 if (subnet->getReservationsInSubnet() ||
198 subnet->getReservationsGlobal()) {
201 if (!context_->early_global_reservations_lookup_) {
206 alloc_engine->findReservation(*context_);
209 subnet->getSharedNetwork(sn);
219 auto global_host = context_->globalHost();
220 auto current_host = context_->currentHost();
221 if ((!context_->early_global_reservations_lookup_ &&
222 global_host && !global_host->getClientClasses4().empty()) ||
223 (!sn && current_host && !current_host->getClientClasses4().empty())) {
244 if (!context_->hosts_.empty()) {
245 query->addClass(
"KNOWN");
247 .arg(query->getLabel())
250 query->addClass(
"UNKNOWN");
252 .arg(query->getLabel())
261 .arg(query_->getLabel())
262 .arg(classes.toText());
265 if (query_->inClass(
"DROP")) {
267 .arg(query_->getHWAddrLabel())
268 .arg(query_->toText());
270 static_cast<int64_t
>(1));
277 uint8_t resp_type = 0;
291 resp_.reset(
new Pkt4(resp_type,
getQuery()->getTransid()));
293 copyDefaultOptions();
307 const Pkt6Ptr& query6 = query->getPkt6();
311 if (!query6->relay_info_.empty()) {
312 resp6->copyRelayInfo(query6);
315 resp6->setIface(query6->getIface());
316 resp6->setIndex(query6->getIndex());
317 resp6->setRemoteAddr(query6->getRemoteAddr());
318 resp6->setRemotePort(query6->getRemotePort());
319 resp_.reset(
new Pkt4o6(resp_, resp6));
323Dhcpv4Exchange::copyDefaultFields() {
324 resp_->setIface(query_->getIface());
325 resp_->setIndex(query_->getIndex());
332 resp_->setCiaddr(query_->getCiaddr());
336 resp_->setHops(query_->getHops());
339 resp_->setHWAddr(query_->getHWAddr());
342 resp_->setGiaddr(query_->getGiaddr());
351 HWAddrPtr src_hw_addr = query_->getLocalHWAddr();
353 resp_->setLocalHWAddr(src_hw_addr);
355 HWAddrPtr dst_hw_addr = query_->getRemoteHWAddr();
357 resp_->setRemoteHWAddr(dst_hw_addr);
361 resp_->setFlags(query_->getFlags());
365Dhcpv4Exchange::copyDefaultOptions() {
369 OptionPtr client_id = query_->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
370 if (client_id && echo) {
371 resp_->addOption(client_id);
384 resp_->addOption(subnet_sel);
397 sao->boolValue() && query_->inClass(
"STASH_AGENT_OPTIONS")) {
400 resp_->addOption(rai);
410 for (
auto const& id_type : cfg->getIdentifierTypes()) {
413 if (context->hwaddr_ && !context->hwaddr_->hwaddr_.empty()) {
414 context->addHostIdentifier(id_type, context->hwaddr_->hwaddr_);
419 if (context->clientid_) {
420 const std::vector<uint8_t>& vec = context->clientid_->getClientId();
425 if ((vec[0] == CLIENT_ID_OPTION_TYPE_DUID) && (vec.size() > 5)) {
427 context->addHostIdentifier(id_type,
428 std::vector<uint8_t>(vec.begin() + 5,
440 if (circuit_id_opt) {
441 const OptionBuffer& circuit_id_vec = circuit_id_opt->getData();
442 if (!circuit_id_vec.empty()) {
443 context->addHostIdentifier(id_type, circuit_id_vec);
451 if (context->clientid_) {
452 const std::vector<uint8_t>& vec = context->clientid_->getClientId();
454 context->addHostIdentifier(id_type, vec);
467 std::vector<uint8_t> id;
476 callout_handle->setArgument(
"query4", context->query_);
477 callout_handle->setArgument(
"id_type", type);
478 callout_handle->setArgument(
"id_value",
id);
484 callout_handle->getArgument(
"id_type", type);
485 callout_handle->getArgument(
"id_value",
id);
491 .arg(context->query_->getLabel())
494 context->addHostIdentifier(type,
id);
509 for (
auto const& def : *defs_ptr) {
513 if (def->getMatchExpr()) {
514 query->classes_.erase(def->getName());
521 if (context->currentHost() && context->query_) {
522 const ClientClasses& classes = context->currentHost()->getClientClasses4();
523 for (
auto const& cclass : classes) {
524 context->query_->addClass(cclass);
531 if (context_->subnet_) {
533 context_->subnet_->getSharedNetwork(shared_network);
534 if (shared_network) {
536 if (host && (host->getIPv4SubnetID() != SUBNET_ID_GLOBAL)) {
548 if (!host->getNextServer().isV4Zero()) {
549 resp_->setSiaddr(host->getNextServer());
552 std::string sname = host->getServerHostname();
553 if (!sname.empty()) {
554 resp_->setSname(
reinterpret_cast<const uint8_t*
>(sname.c_str()),
558 std::string bootfile = host->getBootFileName();
559 if (!bootfile.empty()) {
560 resp_->setFile(
reinterpret_cast<const uint8_t*
>(bootfile.c_str()),
568 boost::shared_ptr<OptionString> vendor_class =
580 pkt->addClass(
"ALL");
594 for (
auto const& it : *defs_ptr) {
602 if (it->getRequired()) {
606 if (it->getDependOnKnown() != depend_on_known) {
609 it->test(pkt, expr_ptr);
616 const bool use_bcast,
const bool direct_response_desired)
617 : io_service_(new
IOService()), server_port_(server_port),
618 client_port_(client_port), shutdown_(true),
619 alloc_engine_(), use_bcast_(use_bcast),
622 test_send_responses_to_source_(false) {
624 const char* env = std::getenv(
"KEA_TEST_SEND_RESPONSES_TO_SOURCE");
627 test_send_responses_to_source_ =
true;
655 }
catch (
const std::exception &e) {
670 for (
auto const& it : dhcp4_statistics) {
672 stats_mgr.setValue(it,
static_cast<int64_t
>(0));
682 }
catch (
const std::exception& ex) {
689 }
catch (
const std::exception& ex) {
705 if (!names.empty()) {
707 for (
size_t i = 1; i < names.size(); ++i) {
708 msg += std::string(
", ") + names[i];
714 io_service_->stopAndPoll();
725 bool sanity_only,
bool allow_answer_park) {
728 if (query->isDhcp4o6()) {
737 subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet(selector);
749 shared_ptr<ScopedCalloutHandleState> callout_handle_state(
750 std::make_shared<ScopedCalloutHandleState>(callout_handle));
753 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
756 callout_handle->setArgument(
"query4", query);
757 callout_handle->setArgument(
"subnet4", subnet);
758 callout_handle->setArgument(
"subnet4collection",
759 cfgmgr.getCurrentCfg()->
760 getCfgSubnets4()->getAll());
762 auto const tpl(parkingLimitExceeded(
"subnet4_select"));
763 bool const exceeded(get<0>(tpl));
765 uint32_t
const limit(get<1>(tpl));
770 .arg(query->getLabel());
776 "subnet4_select", query, [
this, query, allow_answer_park, callout_handle_state]() {
778 boost::shared_ptr<function<void()>> callback(
779 boost::make_shared<function<
void()>>(
780 [
this, query, allow_answer_park]()
mutable {
783 callout_handle_state->on_completion_ = [callback]() {
806 .arg(query->getLabel());
819 .arg(query->getLabel());
828 .arg(query->getLabel());
834 callout_handle->getArgument(
"subnet4", subnet);
840 .arg(query->getLabel())
841 .arg(subnet->getID());
845 .arg(query->getLabel())
846 .arg(subnet->toText());
851 .arg(query->getLabel());
859 bool sanity_only,
bool allow_answer_park) {
863 selector.
ciaddr_ = query->getCiaddr();
864 selector.giaddr_ = query->getGiaddr();
865 selector.local_address_ = query->getLocalAddr();
866 selector.client_classes_ = query->classes_;
867 selector.iface_name_ = query->getIface();
869 selector.dhcp4o6_ =
true;
871 selector.remote_address_ = query->getRemoteAddr();
872 selector.first_relay_linkaddr_ =
IOAddress(
"::");
875 Pkt4o6Ptr query4o6 = boost::dynamic_pointer_cast<Pkt4o6>(query);
879 const Pkt6Ptr& query6 = query4o6->getPkt6();
882 if (query6 && !query6->relay_info_.empty()) {
883 for (
auto const& relay : boost::adaptors::reverse(query6->relay_info_)) {
884 if (!relay.linkaddr_.isV6Zero() &&
885 !relay.linkaddr_.isV6LinkLocal()) {
886 selector.first_relay_linkaddr_ = relay.linkaddr_;
890 selector.interface_id_ =
898 OptionCustomPtr oc = boost::dynamic_pointer_cast<OptionCustom>(sbnsel);
900 selector.option_select_ = oc->readAddress();
905 subnet = cfgmgr.getCurrentCfg()->getCfgSubnets4()->selectSubnet4o6(selector);
917 shared_ptr<ScopedCalloutHandleState> callout_handle_state(
918 std::make_shared<ScopedCalloutHandleState>(callout_handle));
921 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
924 callout_handle->setArgument(
"query4", query);
925 callout_handle->setArgument(
"subnet4", subnet);
926 callout_handle->setArgument(
"subnet4collection",
927 cfgmgr.getCurrentCfg()->
928 getCfgSubnets4()->getAll());
930 auto const tpl(parkingLimitExceeded(
"subnet4_select"));
931 bool const exceeded(get<0>(tpl));
933 uint32_t
const limit(get<1>(tpl));
938 .arg(query->getLabel());
944 "subnet4_select", query, [
this, query, allow_answer_park, callout_handle_state]() {
946 boost::shared_ptr<function<void()>> callback(
947 boost::make_shared<function<
void()>>(
948 [
this, query, allow_answer_park]()
mutable {
951 callout_handle_state->on_completion_ = [callback]() {
974 .arg(query->getLabel());
987 .arg(query->getLabel());
996 .arg(query->getLabel());
1002 callout_handle->getArgument(
"subnet4", subnet);
1009 .arg(query->getLabel())
1010 .arg(subnet->getID());
1015 .arg(query->getLabel())
1016 .arg(subnet->toText());
1021 .arg(query->getLabel());
1041 ctx->query_ = query;
1044 ctx->hwaddr_ = query->getHWAddr();
1058 ctx->early_global_reservations_lookup_ = egrl->boolValue();
1062 if (ctx->early_global_reservations_lookup_) {
1064 OptionPtr opt_clientid = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
1066 ctx->clientid_.reset(
new ClientId(opt_clientid->getData()));
1075 if (global_host && !global_host->getClientClasses4().empty()) {
1080 const ClientClasses& classes = global_host->getClientClasses4();
1081 for (
auto const& cclass : classes) {
1082 query->addClass(cclass);
1091 query->addClass(
"KNOWN");
1093 .arg(query->getLabel())
1100 if (query->inClass(
"DROP")) {
1103 .arg(query->getHWAddrLabel())
1104 .arg(query->toText());
1106 static_cast<int64_t
>(1));
1111 ctx->hosts_[SUBNET_ID_GLOBAL] = global_host;
1126 while (__AFL_LOOP(fuzzer.maxLoopCount())) {
1139 }
catch (
const std::exception& e) {
1170 uint32_t timeout = 1;
1181 .arg(query->getRemoteAddr().toText())
1182 .arg(query->getRemotePort())
1183 .arg(query->getLocalAddr().toText())
1184 .arg(query->getLocalPort())
1185 .arg(query->getIface());
1201 }
catch (
const std::exception& e) {
1217 .arg(query->getLabel());
1221 query->addPktEvent(
"mt_queued");
1222 typedef function<void()> CallBack;
1223 boost::shared_ptr<CallBack> call_back =
1239 }
catch (
const std::exception& e) {
1241 .arg(query->getLabel())
1262 query->addPktEvent(
"process_started");
1265 query->addClass(
"ALL");
1272 static_cast<int64_t
>(1));
1274 bool skip_unpack =
false;
1288 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
1291 callout_handle->setArgument(
"query4", query);
1303 .arg(query->getRemoteAddr().toText())
1304 .arg(query->getLocalAddr().toText())
1305 .arg(query->getIface());
1316 .arg(query->getRemoteAddr().toText())
1317 .arg(query->getLocalAddr().toText())
1318 .arg(query->getIface());
1322 callout_handle->getArgument(
"query4", query);
1330 .arg(query->getRemoteAddr().toText())
1331 .arg(query->getLocalAddr().toText())
1332 .arg(query->getIface());
1339 .arg(query->getLabel())
1341 }
catch (
const std::exception& e) {
1344 .arg(query->getLabel())
1345 .arg(query->getRemoteAddr().toText())
1346 .arg(query->getLocalAddr().toText())
1347 .arg(query->getIface())
1349 .arg(query->getHWAddrLabel());
1353 static_cast<int64_t
>(1));
1355 static_cast<int64_t
>(1));
1362 .arg(query->getLabel());
1370 }
catch (
const std::exception&) {
1387 static_cast<int64_t
>(1));
1393 int type = query->getType();
1395 .arg(query->getLabel())
1396 .arg(query->getName())
1398 .arg(query->getRemoteAddr())
1399 .arg(query->getLocalAddr())
1400 .arg(query->getIface());
1402 .arg(query->getLabel())
1403 .arg(query->toText());
1416 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
1419 callout_handle->setArgument(
"query4", query);
1432 .arg(query->getLabel());
1436 callout_handle->getArgument(
"query4", query);
1440 if (query->inClass(
"DROP")) {
1442 .arg(query->getHWAddrLabel())
1443 .arg(query->toText());
1445 static_cast<int64_t
>(1));
1454 bool allow_answer_park) {
1463 }
catch (
const std::exception& e) {
1465 .arg(query->getLabel())
1485 this, query, allow_answer_park));
1486 if (!client_handler.tryLock(query, cont)) {
1502 ctx->subnet_ =
selectSubnet(query, drop,
false, allow_answer_park);
1508 }
catch (
const std::exception& e) {
1518 .arg(query->getLabel())
1523 static_cast<int64_t
>(1));
1532 bool allow_answer_park) {
1542 }
catch (
const std::exception& e) {
1544 .arg(query->getLabel())
1553 bool allow_answer_park) {
1561 callout_handle->getContext(
"subnet4", ctx->subnet_);
1571 bool allow_answer_park) {
1578 switch (query->getType()) {
1608 }
catch (
const std::exception& e) {
1618 .arg(query->getLabel())
1623 static_cast<int64_t
>(1));
1630 int hook_idx =
Hooks.hook_index_leases4_committed_;
1631 std::string hook_label =
"leases4_committed";
1635 if (ctx->fake_allocation_) {
1636 hook_idx =
Hooks.hook_index_lease4_offer_;
1637 hook_label =
"lease4_offer";
1667 std::shared_ptr<ScopedCalloutHandleState> callout_handle_state =
1668 std::make_shared<ScopedCalloutHandleState>(callout_handle);
1670 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
1673 callout_handle->setArgument(
"query4", query);
1677 if (ctx->new_lease_ && (ctx->new_lease_->reuseable_valid_lft_ == 0)) {
1678 new_leases->push_back(ctx->new_lease_);
1680 callout_handle->setArgument(
"leases4", new_leases);
1682 if (ctx->fake_allocation_) {
1684 callout_handle->setArgument(
"offer_lifetime", ctx->offer_lft_);
1685 callout_handle->setArgument(
"old_lease", ctx->old_lease_);
1689 if (ctx->old_lease_) {
1690 if ((!ctx->new_lease_) || (ctx->new_lease_->addr_ != ctx->old_lease_->addr_)) {
1691 deleted_leases->push_back(ctx->old_lease_);
1694 callout_handle->setArgument(
"deleted_leases4", deleted_leases);
1697 if (allow_answer_park) {
1698 auto const tpl(parkingLimitExceeded(hook_label));
1699 bool const exceeded(get<0>(tpl));
1701 uint32_t
const limit(get<1>(tpl));
1705 .arg(query->getLabel());
1707 static_cast<int64_t
>(1));
1717 [
this, callout_handle, query, rsp, callout_handle_state, hook_idx, ctx]()
mutable {
1718 if (hook_idx ==
Hooks.hook_index_lease4_offer_) {
1719 bool offer_address_in_use = false;
1721 callout_handle->getArgument(
"offer_address_in_use", offer_address_in_use);
1724 .arg(query->getLabel())
1728 if (offer_address_in_use) {
1730 bool lease_exists = (ctx->offer_lft_ > 0);
1732 typedef function<void()> CallBack;
1735 boost::shared_ptr<CallBack> call_back = boost::make_shared<CallBack>(
1737 callout_handle, query, lease, lease_exists));
1738 callout_handle_state->on_completion_ = [call_back]() {
1751 typedef function<void()> CallBack;
1752 boost::shared_ptr<CallBack> call_back = boost::make_shared<CallBack>(
1754 query, rsp, ctx->subnet_));
1755 callout_handle_state->on_completion_ = [call_back]() {
1770 if (allow_answer_park) {
1778 allow_answer_park) {
1780 .arg(query->getLabel());
1791 .arg(query->getLabel());
1812 }
catch (
const std::exception& e) {
1814 .arg(query->getLabel())
1824 query->addPktEvent(
"process_completed");
1830 bool skip_pack =
false;
1843 ScopedEnableOptionsCopy<Pkt4> query_resp_options_copy(query, rsp);
1846 callout_handle->setArgument(
"query4", query);
1849 callout_handle->setArgument(
"response4", rsp);
1852 callout_handle->setArgument(
"subnet4", subnet);
1865 .arg(query->getLabel());
1872 .arg(rsp->getLabel());
1881 .arg(rsp->getLabel());
1883 }
catch (
const std::exception& e) {
1885 .arg(rsp->getLabel())
1912 ScopedEnableOptionsCopy<Pkt4> resp4_options_copy(rsp);
1915 callout_handle->setArgument(
"response4", rsp);
1928 .arg(rsp->getLabel());
1932 callout_handle->getArgument(
"response4", rsp);
1936 .arg(rsp->getLabel())
1937 .arg(rsp->getName())
1938 .arg(
static_cast<int>(rsp->getType()))
1939 .arg(rsp->getLocalAddr().isV4Zero() ?
"*" : rsp->getLocalAddr().toText())
1940 .arg(rsp->getLocalPort())
1941 .arg(rsp->getRemoteAddr())
1942 .arg(rsp->getRemotePort())
1943 .arg(rsp->getIface().empty() ?
"to be determined from routing" :
1948 .arg(rsp->getLabel())
1949 .arg(rsp->getName())
1950 .arg(
static_cast<int>(rsp->getType()))
1951 .arg(rsp->toText());
1957 }
catch (
const std::exception& e) {
1959 .arg(rsp->getLabel())
1969 boost::shared_ptr<Option4AddrLst> generated =
1970 boost::dynamic_pointer_cast<Option4AddrLst>(srvid);
1976 if (addrs.size() != 1) {
1978 <<
"Expected to contain a single IPv4 address.");
1981 return (addrs[0].toText());
1996 IOAddress local_addr = ex.getQuery()->getLocalAddr();
1997 Pkt4Ptr query = ex.getQuery();
1999 if (local_addr.isV4Bcast() || query->isDhcp4o6()) {
2005 ex.getResponse()->addOption(opt_srvid);
2013 Subnet4Ptr subnet = ex.getContext()->subnet_;
2021 const ConstHostPtr& host = ex.getContext()->currentHost();
2022 if (host && !host->getCfgOption4()->empty()) {
2023 co_list.push_back(host->getCfgOption4());
2027 Pkt4Ptr resp = ex.getResponse();
2030 addr = resp->getYiaddr();
2034 if (pool && !pool->getCfgOption()->empty()) {
2035 co_list.push_back(pool->getCfgOption());
2040 if (!subnet->getCfgOption()->empty()) {
2041 co_list.push_back(subnet->getCfgOption());
2046 subnet->getSharedNetwork(network);
2047 if (network && !network->getCfgOption()->empty()) {
2048 co_list.push_back(network->getCfgOption());
2053 for (
auto const& cclass : classes) {
2056 getClientClassDictionary()->findClass(cclass);
2061 .arg(ex.getQuery()->getLabel())
2068 if (ccdef->getCfgOption()->empty()) {
2073 co_list.push_back(ccdef->getCfgOption());
2086 Subnet4Ptr subnet = ex.getContext()->subnet_;
2097 if (co_list.empty()) {
2101 Pkt4Ptr query = ex.getQuery();
2102 Pkt4Ptr resp = ex.getResponse();
2103 set<uint8_t> requested_opts;
2112 for (uint16_t code : option_prl->getValues()) {
2113 static_cast<void>(requested_opts.insert(code));
2117 std::set<uint8_t> cancelled_opts;
2121 for (
auto const& copts : co_list) {
2129 BOOST_FOREACH(
auto const& desc, prange) {
2132 uint8_t code =
static_cast<uint8_t
>(desc.option_->getType());
2133 static_cast<void>(requested_opts.insert(code));
2139 BOOST_FOREACH(
auto const& desc, crange) {
2142 uint8_t code =
static_cast<uint8_t
>(desc.option_->getType());
2143 static_cast<void>(cancelled_opts.insert(code));
2150 for (uint8_t opt : requested_opts) {
2151 if (cancelled_opts.count(opt) > 0) {
2159 if (!resp->getOption(opt)) {
2161 for (
auto const& copts : co_list) {
2165 resp->addOption(desc.option_);
2178 set<uint32_t> vendor_ids;
2182 vendor_opts = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
2184 uint32_t vendor_id = vendor_opts->getVendorId();
2185 static_cast<void>(vendor_ids.insert(vendor_id));
2189 for (
auto const& copts : co_list) {
2192 if (!desc.option_) {
2196 boost::dynamic_pointer_cast<OptionVendorClass>(desc.option_);
2201 uint32_t vendor_id = vendor_opts->getVendorId();
2202 if (vendor_ids.count(vendor_id) > 0) {
2206 resp->Pkt::addOption(desc.option_);
2207 static_cast<void>(vendor_ids.insert(vendor_id));
2216 set<uint32_t> vendor_ids;
2220 vendor_opts = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
2222 uint32_t vendor_id = vendor_opts->getVendorId();
2223 static_cast<void>(vendor_ids.insert(vendor_id));
2227 for (
auto const& copts : co_list) {
2230 if (!desc.option_) {
2234 boost::dynamic_pointer_cast<OptionVendor>(desc.option_);
2239 uint32_t vendor_id = vendor_opts->getVendorId();
2240 if (vendor_ids.count(vendor_id) > 0) {
2246 resp->Pkt::addOption(vendor_opts);
2247 static_cast<void>(vendor_ids.insert(vendor_id));
2256 Subnet4Ptr subnet = ex.getContext()->subnet_;
2267 if (!subnet || co_list.empty()) {
2271 Pkt4Ptr query = ex.getQuery();
2272 Pkt4Ptr resp = ex.getResponse();
2273 set<uint32_t> vendor_ids;
2277 map<uint32_t, OptionVendorPtr> vendor_rsps;
2280 vendor_rsp = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
2282 uint32_t vendor_id = vendor_rsp->getVendorId();
2283 vendor_rsps[vendor_id] = vendor_rsp;
2284 static_cast<void>(vendor_ids.insert(vendor_id));
2290 map<uint32_t, OptionVendorPtr> vendor_reqs;
2293 vendor_req = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
2295 uint32_t vendor_id = vendor_req->getVendorId();
2296 vendor_reqs[vendor_id] = vendor_req;
2297 static_cast<void>(vendor_ids.insert(vendor_id));
2305 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
2307 uint32_t vendor_id = vendor_class->getVendorId();
2308 static_cast<void>(vendor_ids.insert(vendor_id));
2314 if (vendor_ids.empty()) {
2318 map<uint32_t, set<uint8_t> > requested_opts;
2332 oro = boost::dynamic_pointer_cast<OptionUint8Array>(oro_generic);
2335 set<uint8_t> oro_req_opts;
2336 for (uint8_t code : oro->getValues()) {
2337 static_cast<void>(oro_req_opts.insert(code));
2343 for (uint32_t vendor_id : vendor_ids) {
2345 std::set<uint8_t> cancelled_opts;
2349 for (
auto const& copts : co_list) {
2358 BOOST_FOREACH(
auto const& desc, prange) {
2361 uint8_t code =
static_cast<uint8_t
>(desc.option_->getType());
2362 static_cast<void>(requested_opts[vendor_id].insert(code));
2369 BOOST_FOREACH(
auto const& desc, crange) {
2372 uint8_t code =
static_cast<uint8_t
>(desc.option_->getType());
2373 static_cast<void>(cancelled_opts.insert(code));
2383 if (requested_opts[vendor_id].empty()) {
2391 if (vendor_rsps.count(vendor_id) > 0) {
2392 vendor_rsp = vendor_rsps[vendor_id];
2400 for (uint8_t opt : requested_opts[vendor_id]) {
2401 if (cancelled_opts.count(opt) > 0) {
2404 if (!vendor_rsp->getOption(opt)) {
2405 for (
auto const& copts : co_list) {
2408 vendor_rsp->addOption(desc.option_);
2418 if (added && (vendor_rsps.count(vendor_id) == 0)) {
2419 resp->Pkt::addOption(vendor_rsp);
2428 static const std::vector<uint16_t> required_options = {
2435 Subnet4Ptr subnet = ex.getContext()->subnet_;
2442 if (co_list.empty()) {
2446 Pkt4Ptr resp = ex.getResponse();
2450 for (
auto const& required : required_options) {
2451 OptionPtr opt = resp->getOption(required);
2454 for (
auto const& copts : co_list) {
2457 resp->addOption(desc.option_);
2471 Pkt4Ptr query = ex.getQuery();
2472 Pkt4Ptr resp = ex.getResponse();
2477 .arg(query->getLabel());
2478 processClientFqdnOption(ex);
2483 .arg(query->getLabel());
2484 processHostnameOption(ex);
2490 std::string hostname;
2491 bool fqdn_fwd =
false;
2492 bool fqdn_rev =
false;
2495 fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(
DHO_FQDN));
2497 hostname = fqdn->getDomainName();
2498 CfgMgr::instance().getD2ClientMgr().getUpdateDirections(*fqdn, fqdn_fwd, fqdn_rev);
2500 opt_hostname = boost::dynamic_pointer_cast<OptionString>
2504 hostname = opt_hostname->getValue();
2509 if (hostname ==
".") {
2515 if (ex.getContext()->getDdnsParams()->getEnableUpdates()) {
2534 Subnet4Ptr subnet = ex.getContext()->subnet_;
2535 callout_handle->setArgument(
"query4", query);
2536 callout_handle->setArgument(
"response4", resp);
2537 callout_handle->setArgument(
"subnet4", subnet);
2538 callout_handle->setArgument(
"hostname", hostname);
2539 callout_handle->setArgument(
"fwd-update", fqdn_fwd);
2540 callout_handle->setArgument(
"rev-update", fqdn_rev);
2541 callout_handle->setArgument(
"ddns-params", ex.getContext()->getDdnsParams());
2547 string hook_hostname;
2548 bool hook_fqdn_fwd =
false;
2549 bool hook_fqdn_rev =
false;
2550 callout_handle->getArgument(
"hostname", hook_hostname);
2551 callout_handle->getArgument(
"fwd-update", hook_fqdn_fwd);
2552 callout_handle->getArgument(
"rev-update", hook_fqdn_rev);
2556 if ((hostname != hook_hostname) || (fqdn_fwd != hook_fqdn_fwd) ||
2557 (fqdn_rev != hook_fqdn_rev)) {
2559 .arg(hostname).arg(hook_hostname).arg(fqdn_fwd).arg(hook_fqdn_fwd)
2560 .arg(fqdn_rev).arg(hook_fqdn_rev);
2561 hostname = hook_hostname;
2562 fqdn_fwd = hook_fqdn_fwd;
2563 fqdn_rev = hook_fqdn_rev;
2567 OptionStringPtr hostname_opt = boost::dynamic_pointer_cast<OptionString>
2570 hostname_opt->setValue(hook_hostname);
2575 fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(
DHO_FQDN));
2586 auto ctx = ex.getContext();
2587 ctx->fwd_dns_update_ = fqdn_fwd;
2588 ctx->rev_dns_update_ = fqdn_rev;
2589 ctx->hostname_ = hostname;
2601 .arg(ex.getQuery()->getLabel())
2613 .arg(ex.getQuery()->getLabel())
2614 .arg(fqdn->toText());
2624 *(ex.getContext()->getDdnsParams()));
2629 if (ex.getContext()->currentHost() &&
2630 !ex.getContext()->currentHost()->getHostname().empty()) {
2631 fqdn_resp->setDomainName(d2_mgr.qualifyName(ex.getContext()->currentHost()->getHostname(),
2632 *(ex.getContext()->getDdnsParams()),
true),
2639 *(ex.getContext()->getDdnsParams()));
2655 .arg(ex.getQuery()->getLabel())
2656 .arg(fqdn_resp->toText());
2657 ex.getResponse()->addOption(fqdn_resp);
2666 OptionStringPtr opt_hostname = boost::dynamic_pointer_cast<OptionString>
2671 .arg(ex.getQuery()->getLabel())
2672 .arg(opt_hostname->getValue());
2680 if (ctx->currentHost() && !ctx->currentHost()->getHostname().empty()) {
2682 std::string hostname = d2_mgr.qualifyName(ctx->currentHost()->getHostname(),
2683 *(ex.getContext()->getDdnsParams()),
false);
2685 boost::algorithm::to_lower(hostname);
2687 .arg(ex.getQuery()->getLabel())
2692 ex.getResponse()->addOption(opt_hostname_resp);
2703 ex.getContext()->getDdnsParams()->getReplaceClientNameMode();
2706 if (!opt_hostname) {
2713 .arg(ex.getQuery()->getLabel());
2717 ex.getResponse()->addOption(opt_hostname_resp);
2725 .arg(ex.getQuery()->getLabel())
2726 .arg(opt_hostname->getValue());
2729 unsigned int label_count;
2735 }
catch (
const std::exception& exc) {
2737 .arg(ex.getQuery()->getLabel())
2746 if (label_count == 0) {
2748 .arg(ex.getQuery()->getLabel());
2764 || label_count < 2) {
2778 ex.getContext()->getDdnsParams()->getHostnameSanitizer();
2781 hostname = sanitizer->scrub(hostname);
2785 boost::algorithm::to_lower(hostname);
2787 if (label_count == 2) {
2795 opt_hostname_resp.reset(
2797 d2_mgr.qualifyName(hostname, *(ex.getContext()->getDdnsParams()),
2805 .arg(ex.getQuery()->getLabel())
2806 .arg(opt_hostname_resp->getValue());
2807 ex.getResponse()->addOption(opt_hostname_resp);
2816 "NULL lease specified when creating NameChangeRequest");
2820 if (!ddns_params.getEnableUpdates()) {
2824 if (!old_lease || ddns_params.getUpdateOnRenew() || !lease->hasIdenticalFqdn(*old_lease)) {
2841 while (current_subnet) {
2847 subnet = current_subnet;
2851 current_subnet = current_subnet->getNextSubnet(subnet, client_classes);
2855 subnet->getSharedNetwork(network);
2872 Pkt4Ptr query = ex.getQuery();
2873 Pkt4Ptr resp = ex.getResponse();
2887 bool fake_allocation = (query->getType() ==
DHCPDISCOVER);
2893 auto const& requested_opts = option_prl->getValues();
2894 if ((std::find(requested_opts.cbegin(), requested_opts.cend(),
2897 ex.setIPv6OnlyPreferred(
true);
2898 ctx->subnet_ = subnet;
2900 if (!fake_allocation) {
2901 resp->setCiaddr(query->getCiaddr());
2917 if (opt_requested_address) {
2918 hint = opt_requested_address->readAddress();
2920 }
else if (!query->getCiaddr().isV4Zero()) {
2921 hint = query->getCiaddr();
2928 auto authoritative =
false;
2934 auto init_reboot = (!fake_allocation && !opt_serverid && opt_requested_address);
2937 .arg(query->getLabel())
2938 .arg(hint.toText());
2942 authoritative = subnet->getAuthoritative();
2948 authoritative = flag->boolValue();
2951 }
else if (fake_allocation) {
2953 .arg(query->getLabel())
2957 .arg(query->getLabel())
2965 if (!subnet && (!init_reboot || authoritative)) {
2972 .arg(query->getLabel())
2973 .arg(query->getRemoteAddr().toText())
2974 .arg(query->getName());
2985 ClientIdPtr client_id = ex.getContext()->clientid_;
2992 auto const& classes = query->getClasses();
3002 if (original_subnet && client_id) {
3006 if (!leases_client_id.empty()) {
3012 for (
auto const& l : leases_client_id) {
3013 if (l->subnet_id_ == s->getID()) {
3023 s = s->getNextSubnet(original_subnet, classes);
3031 if (original_subnet && !lease && hwaddr) {
3035 if (!leases_hwaddr.empty()) {
3040 for (
auto const& l : leases_hwaddr) {
3041 if (l->subnet_id_ == s->getID()) {
3051 s = s->getNextSubnet(original_subnet, classes);
3060 bool known_client = lease && lease->belongsToClient(hwaddr, client_id);
3061 if (!authoritative && !known_client) {
3064 .arg(query->getLabel())
3065 .arg(hint.toText());
3067 ex.deleteResponse();
3073 if ((known_client && (lease->addr_ != hint)) ||
3074 (!known_client && authoritative) ||
3075 (!original_subnet)) {
3078 .arg(query->getLabel())
3079 .arg(hint.toText());
3090 ctx->requested_address_ = hint;
3091 ctx->fake_allocation_ = fake_allocation;
3092 ctx->callout_handle_ = callout_handle;
3108 bool client_name_changed =
false;
3112 if (subnet && ctx->subnet_ && subnet->getID() != ctx->subnet_->getID()) {
3114 subnet->getSharedNetwork(network);
3116 .arg(query->getLabel())
3117 .arg(subnet->toText())
3118 .arg(ctx->subnet_->toText())
3119 .arg(network ? network->getName() :
"<no network?>");
3121 subnet = ctx->subnet_;
3136 ctx->hostname_ =
"";
3137 ctx->fwd_dns_update_ =
false;
3138 ctx->rev_dns_update_ =
false;
3145 if ((lease->hostname_ != ctx->hostname_) ||
3146 (lease->fqdn_fwd_ != ctx->fwd_dns_update_) ||
3147 (lease->fqdn_rev_ != ctx->rev_dns_update_)) {
3148 lease->hostname_ = ctx->hostname_;
3149 lease->fqdn_fwd_ = ctx->fwd_dns_update_;
3150 lease->fqdn_rev_ = ctx->rev_dns_update_;
3151 client_name_changed =
true;
3159 if (fake_allocation) {
3161 .arg(query->getLabel())
3162 .arg(lease->addr_.toText());
3165 .arg(query->getLabel())
3166 .arg(lease->addr_.toText())
3174 if (!ctx->subnet_->getMatchClientId()) {
3176 .arg(ctx->query_->getLabel())
3177 .arg(ctx->subnet_->getID());
3180 resp->setYiaddr(lease->addr_);
3186 if (!fake_allocation) {
3191 resp->setCiaddr(query->getCiaddr());
3200 if (lease->reuseable_valid_lft_ > 0) {
3201 lease->valid_lft_ = lease->reuseable_valid_lft_;
3203 .arg(query->getLabel())
3204 .arg(lease->addr_.toText())
3221 resp->addOption(opt);
3224 resp->addOption(getNetmaskOption(subnet));
3230 if (!fake_allocation) {
3233 *ex.getContext()->getDdnsParams());
3236 .arg(query->getLabel())
3244 if (ctx->unknown_requested_addr_) {
3256 s = s->getNextSubnet(original_subnet);
3264 .arg(query->getLabel())
3265 .arg(query->getCiaddr().toText())
3266 .arg(opt_requested_address ?
3267 opt_requested_address->readAddress().toText() :
"(no address)");
3268 ex.deleteResponse();
3275 .arg(query->getLabel())
3276 .arg(query->getCiaddr().toText())
3277 .arg(opt_requested_address ?
3278 opt_requested_address->readAddress().toText() :
"(no address)");
3290 const Pkt4Ptr& query,
const Pkt4Ptr& resp,
bool client_name_changed) {
3299 opt_hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(
DHO_HOST_NAME));
3300 if (!opt_hostname) {
3307 if (lease->hostname_.empty()) {
3314 .generateFqdn(lease->addr_, *(ctx->getDdnsParams()),
static_cast<bool>(fqdn));
3317 .arg(query->getLabel())
3318 .arg(lease->hostname_);
3320 client_name_changed =
true;
3323 if (client_name_changed) {
3329 if (!ctx->fake_allocation_ || (ctx->offer_lft_ > 0)) {
3331 lease->reuseable_valid_lft_ = 0;
3344 opt_hostname->setValue(lease->hostname_);
3348 .arg(query->getLabel())
3349 .arg(lease->hostname_)
3359 uint32_t t2_time = 0;
3361 if (!subnet->getT2().unspecified()) {
3362 t2_time = subnet->getT2();
3363 }
else if (subnet->getCalculateTeeTimes()) {
3365 t2_time =
static_cast<uint32_t
>(round(subnet->getT2Percent() * (lease->valid_lft_)));
3370 uint32_t timer_ceiling = lease->valid_lft_;
3371 if (t2_time > 0 && t2_time < timer_ceiling) {
3373 resp->addOption(t2);
3375 timer_ceiling = t2_time;
3378 uint32_t t1_time = 0;
3380 if (!subnet->getT1().unspecified()) {
3381 t1_time = subnet->getT1();
3382 }
else if (subnet->getCalculateTeeTimes()) {
3384 t1_time =
static_cast<uint32_t
>(round(subnet->getT1Percent() * (lease->valid_lft_)));
3389 if (t1_time > 0 && t1_time < timer_ceiling) {
3391 resp->addOption(t1);
3399 const Pkt4Ptr& query = ex.getQuery();
3403 return (query->getRemotePort());
3414 Pkt4Ptr query = ex.getQuery();
3415 Pkt4Ptr response = ex.getResponse();
3431 }
else if (((query->getType() ==
DHCPINFORM) &&
3432 ((!query->getCiaddr().isV4Zero()) ||
3433 (!query->isRelayed() && !query->getRemoteAddr().isV4Zero()))) ||
3434 ((query->getType() !=
DHCPINFORM) && !query->isRelayed())) {
3435 response->setRemotePort(DHCP4_CLIENT_PORT);
3440 response->setRemotePort(relay_port ? relay_port : DHCP4_SERVER_PORT);
3444 if (query->isRelayed() &&
3450 response->resetIndex();
3452 response->setIface(query->getIface());
3456 IOAddress local_addr = query->getLocalAddr();
3465 if (local_addr.isV4Bcast() || query->isDhcp4o6()) {
3476 response->setLocalAddr(local_addr);
3485 response->setIndex(query->getIndex());
3486 response->setIface(query->getIface());
3492 response->setLocalPort(DHCP4_SERVER_PORT);
3500 Pkt4Ptr query = ex.getQuery();
3501 Pkt4Ptr response = ex.getResponse();
3504 if (query->isDhcp4o6()) {
3505 response->setRemoteAddr(query->getRemoteAddr());
3517 if (!query->getCiaddr().isV4Zero()) {
3518 response->setRemoteAddr(query->getCiaddr());
3525 }
else if (query->isRelayed()) {
3526 response->setRemoteAddr(query->getGiaddr());
3527 response->setFlags(response->getFlags() | BOOTP_BROADCAST);
3532 response->setRemoteAddr(query->getRemoteAddr());
3539 if (query->isRelayed()) {
3548 query->getCiaddr().isV4Zero()) {
3549 response->setFlags(BOOTP_BROADCAST);
3551 response->setRemoteAddr(query->getGiaddr());
3555 }
else if (!query->getCiaddr().isV4Zero()) {
3556 response->setRemoteAddr(query->getCiaddr());
3561 }
else if (response->getType() ==
DHCPNAK) {
3565 }
else if (!response->getYiaddr().isV4Zero()) {
3580 response->setRemoteAddr(response ->getYiaddr());
3588 response->setRemoteAddr(query->getRemoteAddr());
3593 response->setRemoteAddr(query->getRemoteAddr());
3599 Pkt4Ptr query = ex.getQuery();
3600 Pkt4Ptr response = ex.getResponse();
3603 Subnet4Ptr subnet = ex.getContext()->subnet_;
3605 IOAddress subnet_next_server = subnet->getSiaddr();
3606 if (!subnet_next_server.isV4Zero()) {
3607 response->setSiaddr(subnet_next_server);
3610 const string& sname = subnet->getSname();
3611 if (!sname.empty()) {
3617 response->setSname(
reinterpret_cast<const uint8_t*
>(sname.c_str()),
3621 const string& filename = subnet->getFilename();
3622 if (!filename.empty()) {
3628 response->setFile(
reinterpret_cast<const uint8_t*
>(filename.c_str()),
3636 if (!classes.empty()) {
3649 size_t found_cnt = 0;
3650 for (
auto const& name : classes) {
3652 if (found_cnt >= 3) {
3666 next_server = cl->getNextServer();
3667 if (!next_server.isV4Zero()) {
3668 response->setSiaddr(next_server);
3673 if (sname.empty()) {
3674 sname = cl->getSname();
3675 if (!sname.empty()) {
3681 response->setSname(
reinterpret_cast<const uint8_t*
>(sname.c_str()),
3687 if (filename.empty()) {
3688 filename = cl->getFilename();
3689 if (!filename.empty()) {
3695 response->setFile(
reinterpret_cast<const uint8_t*
>(filename.c_str()),
3705 ex.setReservedMessageFields();
3709Dhcpv4Srv::getNetmaskOption(
const Subnet4Ptr& subnet) {
3718tuple<bool, uint32_t>
3719Dhcpv4Srv::parkingLimitExceeded(
string const& hook_label) {
3721 uint32_t parked_packet_limit(0);
3725 parked_packet_limit = ppl->intValue();
3728 if (parked_packet_limit) {
3732 if (parking_lot && parked_packet_limit <= parking_lot->size()) {
3733 return make_tuple(
true, parked_packet_limit);
3736 return make_tuple(
false, parked_packet_limit);
3758 if (!ex.getResponse()) {
3765 if (!ex.getResponse()->getYiaddr().isV4Zero() || ex.getIPv6OnlyPreferred()) {
3768 ex.conditionallySetReservedClientClasses();
3774 .arg(discover->getLabel())
3775 .arg(discover->getName())
3776 .arg(discover->getClasses().toText());
3781 if (ex.getIPv6OnlyPreferred()) {
3785 .arg(discover->getLabel());
3813 context = ex.getContext();
3815 return (ex.getResponse());
3840 Pkt4Ptr response = ex.getResponse();
3844 }
else if (request->inClass(
"BOOTP")) {
3846 response->addClass(
"BOOTP");
3851 if (!response->getYiaddr().isV4Zero() || ex.getIPv6OnlyPreferred()) {
3854 ex.conditionallySetReservedClientClasses();
3860 .arg(request->getLabel())
3861 .arg(request->getName())
3862 .arg(request->getClasses().toText());
3867 if (ex.getIPv6OnlyPreferred()) {
3871 .arg(request->getLabel());
3894 context = ex.getContext();
3896 return (ex.getResponse());
3912 OptionPtr opt = release->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
3924 .arg(release->getLabel())
3925 .arg(release->getCiaddr().toText());
3929 if (!lease->belongsToClient(release->getHWAddr(), client_id)) {
3931 .arg(release->getLabel())
3932 .arg(release->getCiaddr().toText());
3949 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(release);
3952 callout_handle->setArgument(
"query4", release);
3955 callout_handle->setArgument(
"lease4", lease);
3969 .arg(release->getLabel());
3977 bool success =
false;
3978 bool expired =
false;
3979 auto expiration_cfg =
CfgMgr::instance().getCurrentCfg()->getCfgExpiration();
3982 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3983 expiration_cfg->getHoldReclaimedTime() &&
3986 lease->valid_lft_ = 0;
4002 context->old_lease_ = lease;
4006 .arg(release->getLabel())
4007 .arg(lease->addr_.toText());
4011 .arg(release->getLabel())
4012 .arg(lease->addr_.toText());
4015 .arg(release->getLabel())
4016 .arg(lease->addr_.toText());
4025 static_cast<int64_t
>(-1));
4027 auto const& subnet =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
4029 auto const& pool = subnet->getPool(
Lease::TYPE_V4, lease->addr_,
false);
4034 static_cast<int64_t
>(-1));
4041 .arg(release->getLabel())
4042 .arg(lease->addr_.toText());
4047 .arg(release->getLabel())
4048 .arg(release->getCiaddr())
4061 if (!opt_requested_address) {
4064 " in DHCPDECLINE sent from " << decline->getLabel());
4066 IOAddress addr(opt_requested_address->readAddress());
4084 .arg(addr.
toText()).arg(decline->getLabel());
4089 OptionPtr opt_clientid = decline->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
4092 client_id.reset(
new ClientId(opt_clientid->getData()));
4101 !lease->belongsToClient(decline->getHWAddr(), client_id)) {
4104 string client_hw = decline->getHWAddr() ?
4105 decline->getHWAddr()->toText(
false) :
"(none)";
4106 string lease_hw = lease->hwaddr_ ?
4107 lease->hwaddr_->toText(
false) :
"(none)";
4110 string client_id_txt = client_id ? client_id->toText() :
"(none)";
4111 string lease_id_txt = lease->client_id_ ?
4112 lease->client_id_->toText() :
"(none)";
4116 .arg(addr.
toText()).arg(decline->getLabel())
4117 .arg(client_hw).arg(lease_hw).arg(client_id_txt).arg(lease_id_txt);
4144 ScopedEnableOptionsCopy<Pkt4> query4_options_copy(decline);
4147 callout_handle->setArgument(
"query4", decline);
4150 callout_handle->setArgument(
"lease4", lease);
4161 .arg(decline->getLabel()).arg(lease->addr_.toText());
4166 Lease4Ptr old_values = boost::make_shared<Lease4>(*lease);
4180 .arg(decline->getLabel())
4181 .arg(lease->addr_.toText())
4195 static_cast<int64_t
>(1));
4197 auto const& subnet =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
4199 auto const& pool = subnet->getPool(
Lease::TYPE_V4, lease->addr_,
false);
4204 static_cast<int64_t
>(1));
4221 context->new_lease_ = lease;
4224 .arg(decline->getLabel()).arg(lease->valid_lft_);
4231 .arg(query->getLabel())
4232 .arg(lease->addr_.toText())
4233 .arg(lease->valid_lft_);
4241 .arg(query->getLabel())
4242 .arg(lease->addr_.toText());
4258 lease_exists =
false;
4262 .arg(query->getLabel())
4263 .arg(lease->addr_.toText());
4268 if (!lease_exists) {
4273 .arg(query->getLabel())
4274 .arg(lease->addr_.toText());
4291 static_cast<int64_t
>(1));
4293 if (!lease_exists) {
4296 static_cast<int64_t
>(1));
4299 auto const& subnet =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
4301 auto const& pool = subnet->getPool(
Lease::TYPE_V4, lease->addr_,
false);
4306 static_cast<int64_t
>(1));
4307 if (!lease_exists) {
4311 static_cast<int64_t
>(1));
4318 if (!lease_exists) {
4332 callout_handle->setArgument(
"query4", query);
4335 callout_handle->setArgument(
"lease4", lease);
4363 Pkt4Ptr ack = ex.getResponse();
4367 ex.conditionallySetReservedClientClasses();
4372 .arg(inform->getLabel())
4373 .arg(inform->getName())
4374 .arg(inform->getClasses().toText());
4391 if (ack->getRemoteAddr() != inform->getGiaddr()) {
4393 .arg(inform->getLabel())
4394 .arg(ack->getRemoteAddr())
4395 .arg(ack->getIface());
4404 return (ex.getResponse());
4409 if (query->getCiaddr().isV4Zero() || !query->getGiaddr().isV4Zero()) {
4426 if (query->inClass(
"STASH_AGENT_OPTIONS")) {
4430 if (!lease || lease->expired()) {
4434 if (!user_context || (user_context->getType() !=
Element::map)) {
4442 if (!relay_agent_info) {
4447 relay_agent_info = relay_agent_info->get(
"sub-options");
4448 if (!relay_agent_info) {
4457 OptionPtr opt_clientid = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
4459 client_id.reset(
new ClientId(opt_clientid->getData()));
4461 if (!lease->belongsToClient(query->getHWAddr(), client_id)) {
4465 string rai_hex = relay_agent_info->stringValue();
4466 if (rai_hex.empty()) {
4469 vector<uint8_t> rai_data;
4474 if (!rai || rai->getOptions().empty()) {
4481 query->addOption(rai);
4482 query->addClass(
"STASH_AGENT_OPTIONS");
4485 .arg(query->getLabel())
4486 .arg(query->getCiaddr())
4487 .arg(rai->toText());
4501 .arg(query->getLabel())
4502 .arg(query->getIface());
4510 .arg(query->getLabel())
4511 .arg(query->getIface());
4521 if (pkt->isRelayed()) {
4526 if (pkt->isDhcp4o6()) {
4535 if (pkt->getRemoteAddr().isV4Zero() &&
4536 pkt->getCiaddr().isV4Zero()) {
4547 bool result = (!pkt->getLocalAddr().isV4Bcast() ||
4562 type = query->getType();
4566 .arg(query->getLabel())
4567 .arg(query->getIface());
4591 .arg(query->getLabel());
4598 .arg(query->getLabel())
4603 .arg(query->getLabel())
4630 boost::dynamic_pointer_cast<OptionCustom>(option);
4633 if (!option_custom) {
4641 if (option_custom->getDataFieldsNum() != 1) {
4647 IOAddress server_id = option_custom->readAddress();
4648 if (!server_id.isV4()) {
4657 if (rai_suboption && (server_id.toBytes() == rai_suboption->toBinary())) {
4664 if (cfg->getIgnoreServerIdentifier()) {
4702 if (cfg_subnets->hasSubnetWithServerId(server_id)) {
4709 if (cfg_networks->hasNetworkWithServerId(server_id)) {
4715 for (
auto const& cclass : classes) {
4718 getClientClassDictionary()->findClass(cclass);
4723 if (ccdef->getCfgOption()->empty()) {
4728 OptionCustomPtr context_opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
4730 if (context_opt_server_id && (context_opt_server_id->readAddress() == server_id)) {
4738 OptionCustomPtr opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
4741 return (opt_server_id && (opt_server_id->readAddress() == server_id));
4746 switch (query->getType()) {
4781 <<
" received in message "
4782 << query->getName());
4789 " received in message "
4790 << query->getName());
4800 if (query->getHWAddr() && !query->getHWAddr()->hwaddr_.empty()) {
4806 OptionPtr client_id = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
4809 if (!client_id || client_id->len() == client_id->getHeaderLen()) {
4811 " provided in message "
4812 << query->getName());
4822 Pkt4Ptr query = ex.getQuery();
4824 Subnet4Ptr subnet = ex.getContext()->subnet_;
4830 Pkt4Ptr resp = ex.getResponse();
4833 addr = resp->getYiaddr();
4838 const ClientClasses& pool_to_add = pool->getRequiredClasses();
4839 for (
auto const& cclass : pool_to_add) {
4847 for (
auto const& cclass : to_add) {
4853 subnet->getSharedNetwork(network);
4855 const ClientClasses& net_to_add = network->getRequiredClasses();
4856 for (
auto const& cclass : net_to_add) {
4866 for (
auto const& cclass : classes) {
4885 .arg(query->getLabel())
4887 .arg(status ?
"true" :
"false");
4890 query->addClass(cclass);
4894 .arg(query->getLabel())
4904 for (
auto const& code : query->getDeferredOptions()) {
4908 for (
auto const& cclass : classes) {
4912 getClientClassDictionary()->findClass(cclass);
4918 if (!ccdef->getCfgOptionDef()) {
4948 .arg(query->getLabel())
4957 opt = def->optionFactory(
Option::V4, code, buf);
4958 }
catch (
const std::exception& e) {
4962 .arg(query->getLabel())
4967 while (query->delOption(code)) {
4971 query->addOption(opt);
4978 if (d2_mgr.ddnsEnabled()) {
4983 this, ph::_1, ph::_2));
4990 if (d2_mgr.ddnsEnabled()) {
4993 d2_mgr.stopSender();
5002 arg(result).arg((ncr ? ncr->toText() :
" NULL "));
5011 std::stringstream tmp;
5015 tmp <<
" (" << EXTENDED_VERSION <<
")" << endl;
5016 tmp <<
"premium: " << PREMIUM_EXTENDED_VERSION << endl;
5017 tmp <<
"linked with:" << endl;
5022 tmp << endl <<
"lease backends:";
5024 tmp << endl <<
"- " <<
version;
5029 tmp << endl <<
"host backends:";
5031 tmp << endl <<
"- " <<
version;
5044 string stat_name =
"pkt4-unknown-received";
5046 switch (query->getType()) {
5048 stat_name =
"pkt4-discover-received";
5052 stat_name =
"pkt4-offer-received";
5055 stat_name =
"pkt4-request-received";
5059 stat_name =
"pkt4-ack-received";
5063 stat_name =
"pkt4-nak-received";
5066 stat_name =
"pkt4-release-received";
5069 stat_name =
"pkt4-decline-received";
5072 stat_name =
"pkt4-inform-received";
5086 static_cast<int64_t
>(1));
5092 static_cast<int64_t
>(1));
5096 switch (response->getType()) {
5098 stat_name =
"pkt4-offer-sent";
5101 stat_name =
"pkt4-ack-sent";
5104 stat_name =
"pkt4-nak-sent";
5112 static_cast<int64_t
>(1));
5116 return (
Hooks.hook_index_buffer4_receive_);
5120 return (
Hooks.hook_index_pkt4_receive_);
5124 return (
Hooks.hook_index_subnet4_select_);
5128 return (
Hooks.hook_index_lease4_release_);
5132 return (
Hooks.hook_index_pkt4_send_);
5136 return (
Hooks.hook_index_buffer4_send_);
5140 return (
Hooks.hook_index_lease4_decline_);
5149 static std::list<std::list<std::string>>
const list({
5150 {
"config-control",
"config-databases",
"[]"},
5151 {
"hooks-libraries",
"[]",
"parameters",
"*"},
5153 {
"hosts-databases",
"[]"},
int version()
returns Kea hooks version.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic)
static const IOAddress & IPV4_ZERO_ADDRESS()
Returns an address set to all zeros.
bool isV4Zero() const
Convenience function to check if it is an IPv4 zero address.
std::string toText() const
Convert the address to a string.
static const IOAddress & IPV4_BCAST_ADDRESS()
Returns a "255.255.255.255" broadcast address.
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
static IOServiceMgr & instance()
Access the IOServiceMgr singleton instance.
The IOService class is a wrapper for the ASIO io_service class.
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
static std::string getVersion()
Get version string.
DHCPv4 and DHCPv6 allocation engine.
boost::shared_ptr< ClientContext4 > ClientContext4Ptr
Pointer to the ClientContext4.
static uint32_t getValidLft(const ClientContext4 &ctx)
Returns the valid lifetime based on the v4 context.
Implementation of the mechanisms to control the use of the Configuration Backends by the DHCPv4 serve...
@ EARLY_GLOBAL_RESERVATIONS_LOOKUP
@ USE_ROUTING
Server uses routing to determine the right interface to send response.
@ SOCKET_UDP
Datagram socket, i.e. IP/UDP socket.
static CfgMgr & instance()
returns a single instance of Configuration Manager
static SubnetSelector initSelector(const Pkt4Ptr &query)
Build selector from a client's message.
Container for storing client class names.
void insert(const ClientClass &class_name)
Insert an element.
Client race avoidance RAII handler.
Holds Client identifier or client IPv4 address.
ReplaceClientNameMode
Defines the client name replacement modes.
D2ClientMgr isolates Kea from the details of being a D2 client.
Convenience container for conveying DDNS behavioral parameters It is intended to be created per Packe...
static Dhcp4to6Ipc & instance()
Returns pointer to the sole instance of Dhcp4to6Ipc.
Pkt4Ptr getQuery() const
Returns the pointer to the query from the client.
static void setHostIdentifiers(AllocEngine::ClientContext4Ptr context)
Set host identifiers within a context.
Dhcpv4Exchange(const AllocEnginePtr &alloc_engine, const Pkt4Ptr &query, AllocEngine::ClientContext4Ptr &context, const Subnet4Ptr &subnet, bool &drop)
Constructor.
static void classifyByVendor(const Pkt4Ptr &pkt)
Assign class using vendor-class-identifier option.
void initResponse()
Initializes the instance of the response message.
void setReservedMessageFields()
Sets reserved values of siaddr, sname and file in the server's response.
static void setReservedClientClasses(AllocEngine::ClientContext4Ptr context)
Assigns classes retrieved from host reservation database.
void initResponse4o6()
Initializes the DHCPv6 part of the response message.
static void evaluateClasses(const Pkt4Ptr &pkt, bool depend_on_known)
Evaluate classes.
static void classifyPacket(const Pkt4Ptr &pkt)
Assigns incoming packet to zero or more classes.
static void removeDependentEvaluatedClasses(const Pkt4Ptr &query)
Removed evaluated client classes.
void conditionallySetReservedClientClasses()
Assigns classes retrieved from host reservation database if they haven't been yet set.
void initContext0(const Pkt4Ptr &query, AllocEngine::ClientContext4Ptr ctx)
Initialize client context (first part).
int run()
Main server processing loop.
void declineLease(const Lease4Ptr &lease, const Pkt4Ptr &decline, AllocEngine::ClientContext4Ptr &context)
Marks lease as declined.
void processPacketAndSendResponse(Pkt4Ptr query)
Process a single incoming DHCPv4 packet and sends the response.
void classifyPacket(const Pkt4Ptr &pkt)
Assigns incoming packet to zero or more classes.
void appendRequestedVendorOptions(Dhcpv4Exchange &ex)
Appends requested vendor options as requested by client.
void adjustIfaceData(Dhcpv4Exchange &ex)
Set IP/UDP and interface parameters for the DHCPv4 response.
isc::dhcp::Subnet4Ptr selectSubnet4o6(const Pkt4Ptr &query, bool &drop, bool sanity_only=false, bool allow_answer_park=true)
Selects a subnet for a given client's DHCP4o6 packet.
static uint16_t checkRelayPort(const Dhcpv4Exchange &ex)
Check if the relay port RAI sub-option was set in the query.
virtual ~Dhcpv4Srv()
Destructor. Used during DHCPv4 service shutdown.
virtual Pkt4Ptr receivePacket(int timeout)
dummy wrapper around IfaceMgr::receive4
bool accept(const Pkt4Ptr &query)
Checks whether received message should be processed or discarded.
static void appendServerID(Dhcpv4Exchange &ex)
Adds server identifier option to the server's response.
void postAllocateNameUpdate(const AllocEngine::ClientContext4Ptr &ctx, const Lease4Ptr &lease, const Pkt4Ptr &query, const Pkt4Ptr &resp, bool client_name_changed)
Update client name and DNS flags in the lease and response.
isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr &query, bool &drop, bool sanity_only=false, bool allow_answer_park=true)
Selects a subnet for a given client's packet.
void runOne()
Main server processing step.
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
static int getHookIndexBuffer4Receive()
Returns the index for "buffer4_receive" hook point.
Pkt4Ptr processRequest(Pkt4Ptr &request, AllocEngine::ClientContext4Ptr &context)
Processes incoming REQUEST and returns REPLY response.
static void processStatsReceived(const Pkt4Ptr &query)
Class methods for DHCPv4-over-DHCPv6 handler.
static int getHookIndexPkt4Send()
Returns the index for "pkt4_send" hook point.
void processDecline(Pkt4Ptr &decline, AllocEngine::ClientContext4Ptr &context)
Process incoming DHCPDECLINE messages.
Dhcpv4Srv(uint16_t server_port=DHCP4_SERVER_PORT, uint16_t client_port=0, const bool use_bcast=true, const bool direct_response_desired=true)
Default constructor.
static int getHookIndexSubnet4Select()
Returns the index for "subnet4_select" hook point.
static void processStatsSent(const Pkt4Ptr &response)
Updates statistics for transmitted packets.
void shutdown() override
Instructs the server to shut down.
static int getHookIndexLease4Release()
Returns the index for "lease4_release" hook point.
void adjustRemoteAddr(Dhcpv4Exchange &ex)
Sets remote addresses for outgoing packet.
static int getHookIndexPkt4Receive()
Returns the index for "pkt4_receive" hook point.
void assignLease(Dhcpv4Exchange &ex)
Assigns a lease and appends corresponding options.
Pkt4Ptr processDhcp4Query(Pkt4Ptr query, bool allow_answer_park)
Process a single incoming DHCPv4 query.
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
void setFixedFields(Dhcpv4Exchange &ex)
Sets fixed fields of the outgoing packet.
void appendBasicOptions(Dhcpv4Exchange &ex)
Append basic options if they are not present.
void recoverStashedAgentOption(const Pkt4Ptr &query)
Recover stashed agent options from client address lease.
void processClientName(Dhcpv4Exchange &ex)
Processes Client FQDN and Hostname Options sent by a client.
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
void serverDecline(hooks::CalloutHandlePtr &callout_handle, Pkt4Ptr &query, Lease4Ptr lease, bool lease_exists)
Renders a lease declined after the server has detected, via ping-check or other means,...
void requiredClassify(Dhcpv4Exchange &ex)
Assigns incoming packet to zero or more classes (required pass).
Pkt4Ptr processInform(Pkt4Ptr &inform, AllocEngine::ClientContext4Ptr &context)
Processes incoming DHCPINFORM messages.
uint16_t client_port_
UDP port number to which server sends all responses.
void serverDeclineNoThrow(hooks::CalloutHandlePtr &callout_handle, Pkt4Ptr &query, Lease4Ptr lease, bool lease_exists)
Exception safe wrapper around serverDecline()
void processPacketAndSendResponseNoThrow(Pkt4Ptr query)
Process a single incoming DHCPv4 packet and sends the response.
std::list< std::list< std::string > > jsonPathsToRedact() const final override
Return a list of all paths that contain passwords or secrets for kea-dhcp4.
static std::string srvidToString(const OptionPtr &opt)
converts server-id to text Converts content of server-id option to a text representation,...
bool acceptServerId(const Pkt4Ptr &pkt) const
Verifies if the server id belongs to our server.
static const std::string VENDOR_CLASS_PREFIX
this is a prefix added to the content of vendor-class option
void createNameChangeRequests(const Lease4Ptr &lease, const Lease4Ptr &old_lease, const DdnsParams &ddns_params)
Creates NameChangeRequests which correspond to the lease which has been acquired.
void sendResponseNoThrow(hooks::CalloutHandlePtr &callout_handle, Pkt4Ptr &query, Pkt4Ptr &rsp, Subnet4Ptr &subnet)
Process an unparked DHCPv4 packet and sends the response.
void appendRequestedOptions(Dhcpv4Exchange &ex)
Appends options requested by client.
void setPacketStatisticsDefaults()
This function sets statistics related to DHCPv4 packets processing to their initial values.
void processLocalizedQuery4AndSendResponse(Pkt4Ptr query, AllocEngine::ClientContext4Ptr &ctx, bool allow_answer_park)
Process a localized incoming DHCPv4 query.
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
bool assignZero(Subnet4Ptr &subnet, const ClientClasses &client_classes)
Assign the 0.0.0.0 address to an IPv6-Only client.
void buildCfgOptionList(Dhcpv4Exchange &ex)
Build the configured option list.
volatile bool shutdown_
Indicates if shutdown is in progress.
uint16_t server_port_
UDP port number on which server listens.
bool earlyGHRLookup(const Pkt4Ptr &query, AllocEngine::ClientContext4Ptr ctx)
Initialize client context and perform early global reservations lookup.
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
void setTeeTimes(const Lease4Ptr &lease, const Subnet4Ptr &subnet, Pkt4Ptr resp)
Adds the T1 and T2 timers to the outbound response as appropriate.
void processDhcp4QueryAndSendResponse(Pkt4Ptr query, bool allow_answer_park)
Process a single incoming DHCPv4 query.
bool getSendResponsesToSource() const
Returns value of the test_send_responses_to_source_ flag.
Pkt4Ptr processDiscover(Pkt4Ptr &discover, AllocEngine::ClientContext4Ptr &context)
Processes incoming DISCOVER and returns response.
virtual void d2ClientErrorHandler(const dhcp_ddns::NameChangeSender::Result result, dhcp_ddns::NameChangeRequestPtr &ncr)
Implements the error handler for DHCP_DDNS IO errors.
virtual void sendPacket(const Pkt4Ptr &pkt)
dummy wrapper around IfaceMgr::send()