8#include <kea_version.h>
66#include <boost/foreach.hpp>
67#include <boost/tokenizer.hpp>
68#include <boost/algorithm/string/erase.hpp>
69#include <boost/algorithm/string/join.hpp>
70#include <boost/algorithm/string/split.hpp>
92namespace ph = std::placeholders;
98 int hook_index_buffer6_receive_;
99 int hook_index_pkt6_receive_;
100 int hook_index_subnet6_select_;
101 int hook_index_leases6_committed_;
102 int hook_index_lease6_release_;
103 int hook_index_pkt6_send_;
104 int hook_index_buffer6_send_;
105 int hook_index_lease6_decline_;
106 int hook_index_host6_identifier_;
107 int hook_index_ddns6_update_;
111 hook_index_buffer6_receive_ = HooksManager::registerHook(
"buffer6_receive");
112 hook_index_pkt6_receive_ = HooksManager::registerHook(
"pkt6_receive");
113 hook_index_subnet6_select_ = HooksManager::registerHook(
"subnet6_select");
114 hook_index_leases6_committed_ = HooksManager::registerHook(
"leases6_committed");
115 hook_index_lease6_release_ = HooksManager::registerHook(
"lease6_release");
116 hook_index_pkt6_send_ = HooksManager::registerHook(
"pkt6_send");
117 hook_index_buffer6_send_ = HooksManager::registerHook(
"buffer6_send");
118 hook_index_lease6_decline_ = HooksManager::registerHook(
"lease6_decline");
119 hook_index_host6_identifier_ = HooksManager::registerHook(
"host6_identifier");
120 hook_index_ddns6_update_ = HooksManager::registerHook(
"ddns6_update");
142createStatusCode(
const Pkt6& pkt,
const uint16_t status_code,
143 const std::string& status_message) {
148 .arg(option_status->dataToText());
149 return (option_status);
167createStatusCode(
const Pkt6& pkt,
const Option6IA& ia,
const uint16_t status_code,
168 const std::string& status_message) {
174 .arg(option_status->dataToText());
175 return (option_status);
180std::set<std::string> dhcp6_statistics = {
182 "pkt6-solicit-received",
183 "pkt6-advertise-received",
184 "pkt6-request-received",
185 "pkt6-reply-received",
186 "pkt6-renew-received",
187 "pkt6-rebind-received",
188 "pkt6-decline-received",
189 "pkt6-release-received",
190 "pkt6-infrequest-received",
191 "pkt6-dhcpv4-query-received",
192 "pkt6-dhcpv4-response-received",
193 "pkt6-unknown-received",
195 "pkt6-advertise-sent",
197 "pkt6-dhcpv4-response-sent",
200 "v6-allocation-fail",
201 "v6-allocation-fail-shared-network",
202 "v6-allocation-fail-subnet",
203 "v6-allocation-fail-no-pools",
204 "v6-allocation-fail-classes",
205 "v6-ia-na-lease-reuses",
206 "v6-ia-pd-lease-reuses",
217 : io_service_(new
IOService()), server_port_(server_port),
218 client_port_(client_port), serverid_(), shutdown_(true),
219 alloc_engine_(), name_change_reqs_(),
249 }
catch (
const std::exception &e) {
264 for (
auto it = dhcp6_statistics.begin(); it != dhcp6_statistics.end(); ++it) {
266 stats_mgr.
setValue((*it),
static_cast<int64_t
>(0));
276 }
catch (
const std::exception& ex) {
283 }
catch (
const std::exception& ex) {
293 HooksManager::prepareUnloadLibraries();
294 if (!HooksManager::unloadLibraries()) {
295 auto names = HooksManager::getLibraryNames();
297 if (!names.empty()) {
299 for (
size_t i = 1; i < names.size(); ++i) {
300 msg += std::string(
", ") + names[i];
330 if (
getServerID()->getData() != server_id->getData()){
332 .arg(pkt->getLabel())
344 switch (pkt->getType()) {
349 if (pkt->relay_info_.empty() && !pkt->getLocalAddr().isV6Multicast()) {
351 .arg(pkt->getLabel())
352 .arg(pkt->getName());
368 cfg->getIdentifierTypes()) {
385 if (HooksManager::calloutsPresent(
Hooks.hook_index_host6_identifier_)) {
389 std::vector<uint8_t> id;
398 callout_handle->setArgument(
"query6", ctx.
query_);
399 callout_handle->setArgument(
"id_type", type);
400 callout_handle->setArgument(
"id_value",
id);
403 HooksManager::callCallouts(
Hooks.hook_index_host6_identifier_,
406 callout_handle->getArgument(
"id_type", type);
407 callout_handle->getArgument(
"id_value",
id);
409 if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_CONTINUE) &&
432 ctx.
duid_ = query->getClientId();
452 if (global_host && !global_host->getClientClasses6().empty()) {
457 const ClientClasses& classes = global_host->getClientClasses6();
459 cclass != classes.
cend(); ++cclass) {
460 query->addClass(*cclass);
469 query->addClass(
"KNOWN");
471 .arg(query->getLabel())
478 if (query->inClass(
"DROP")) {
481 .arg(query->makeLabel(query->getClientId(),
nullptr))
482 .arg(query->toText());
483 StatsMgr::instance().addValue(
"pkt6-receive-drop",
484 static_cast<int64_t
>(1));
489 ctx.
hosts_[SUBNET_ID_GLOBAL] = global_host;
526 ctx.
subnet_->getSharedNetwork(sn);
538 global_host && !global_host->getClientClasses6().empty()) ||
539 (!sn && current_host && !current_host->getClientClasses6().empty())) {
560 if (!ctx.
hosts_.empty()) {
561 pkt->addClass(
"KNOWN");
563 .arg(pkt->getLabel())
566 pkt->addClass(
"UNKNOWN");
568 .arg(pkt->getLabel())
577 .arg(pkt->getLabel())
581 if (pkt->inClass(
"DROP")) {
583 .arg(pkt->makeLabel(pkt->getClientId(),
nullptr))
585 StatsMgr::instance().addValue(
"pkt6-receive-drop",
586 static_cast<int64_t
>(1));
598 while (__AFL_LOOP(fuzzer.maxLoopCount())) {
608 }
catch (
const std::exception& e) {
625 MultiThreadingMgr::instance().apply(
false, 0, 0);
638 uint32_t timeout = 1;
649 .arg(query->getRemoteAddr().toText())
650 .arg(query->getRemotePort())
651 .arg(query->getLocalAddr().toText())
652 .arg(query->getLocalPort())
653 .arg(query->getIface());
659 StatsMgr::instance().addValue(
"pkt6-received",
static_cast<int64_t
>(1));
675 }
catch (
const std::exception& e) {
688 .arg(query->getLabel());
691 if (MultiThreadingMgr::instance().getMode()) {
692 typedef function<void()> CallBack;
693 boost::shared_ptr<CallBack> call_back =
696 if (!MultiThreadingMgr::instance().getThreadPool().add(call_back)) {
709 }
catch (
const std::exception& e) {
732 query->addClass(
"ALL");
734 bool skip_unpack =
false;
738 if (HooksManager::calloutsPresent(
Hooks.hook_index_buffer6_receive_)) {
751 callout_handle->setArgument(
"query6", query);
754 HooksManager::callCallouts(
Hooks.hook_index_buffer6_receive_, *callout_handle);
760 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
762 .arg(query->getRemoteAddr().toText())
763 .arg(query->getLocalAddr().toText())
764 .arg(query->getIface());
771 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
773 .arg(query->getRemoteAddr().toText())
774 .arg(query->getLocalAddr().toText())
775 .arg(query->getIface());
778 StatsMgr::instance().addValue(
"pkt6-receive-drop",
779 static_cast<int64_t
>(1));
783 callout_handle->getArgument(
"query6", query);
791 .arg(query->getRemoteAddr().toText())
792 .arg(query->getLocalAddr().toText())
793 .arg(query->getIface());
801 }
catch (
const std::exception &e) {
804 .arg(query->getRemoteAddr().toText())
805 .arg(query->getLocalAddr().toText())
806 .arg(query->getIface())
808 .arg(query->makeLabel(query->getClientId(),
nullptr));
811 StatsMgr::instance().addValue(
"pkt6-parse-failed",
812 static_cast<int64_t
>(1));
813 StatsMgr::instance().addValue(
"pkt6-receive-drop",
814 static_cast<int64_t
>(1));
821 .arg(query->getLabel());
824 processStatsReceived(query);
831 StatsMgr::instance().addValue(
"pkt6-receive-drop",
static_cast<int64_t
>(1));
841 StatsMgr::instance().addValue(
"pkt6-receive-drop",
static_cast<int64_t
>(1));
849 .arg(query->getLabel())
850 .arg(query->getName())
851 .arg(
static_cast<int>(query->getType()))
852 .arg(query->getRemoteAddr())
853 .arg(query->getLocalAddr())
854 .arg(query->getIface());
856 .arg(query->getLabel())
857 .arg(query->toText());
862 if (HooksManager::calloutsPresent(
Hooks.hook_index_pkt6_receive_)) {
875 callout_handle->setArgument(
"query6", query);
878 HooksManager::callCallouts(
Hooks.hook_index_pkt6_receive_, *callout_handle);
883 if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
884 (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
886 .arg(query->getLabel());
888 StatsMgr::instance().addValue(
"pkt6-receive-drop",
889 static_cast<int64_t
>(1));
893 callout_handle->getArgument(
"query6", query);
902 if (query->inClass(
"DROP")) {
904 .arg(query->makeLabel(query->getClientId(),
nullptr))
905 .arg(query->toText());
906 StatsMgr::instance().addValue(
"pkt6-receive-drop",
907 static_cast<int64_t
>(1));
924 }
catch (
const std::exception& e) {
938 if (MultiThreadingMgr::instance().getMode() &&
948 if (!client_handler.
tryLock(query, cont)) {
978 switch (query->getType()) {
1015 }
catch (
const std::exception& e) {
1025 .arg(query->getName())
1026 .arg(query->getRemoteAddr().toText())
1030 StatsMgr::instance().addValue(
"pkt6-receive-drop",
static_cast<int64_t
>(1));
1049 rsp->setRemoteAddr(query->getRemoteAddr());
1050 rsp->setLocalAddr(query->getLocalAddr());
1055 }
else if (rsp->relay_info_.empty()) {
1057 rsp->setRemotePort(DHCP6_CLIENT_PORT);
1061 rsp->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
1067 rsp->setLocalPort(DHCP6_SERVER_PORT);
1069 rsp->setIndex(query->getIndex());
1070 rsp->setIface(query->getIface());
1075 HooksManager::calloutsPresent(
Hooks.hook_index_leases6_committed_)) {
1099 std::shared_ptr<ScopedCalloutHandleState> callout_handle_state =
1100 std::make_shared<ScopedCalloutHandleState>(callout_handle);
1105 callout_handle->setArgument(
"query6", query);
1111 if (new_lease->reuseable_valid_lft_ == 0) {
1112 new_leases->push_back(new_lease);
1116 callout_handle->setArgument(
"leases6", new_leases);
1121 for (
auto const& iac : ctx.
ias_) {
1122 if (!iac.old_leases_.empty()) {
1123 for (
auto old_lease : iac.old_leases_) {
1125 deleted_leases->push_back(old_lease);
1128 bool in_new =
false;
1130 if ((new_lease->addr_ == old_lease->addr_) &&
1132 (new_lease->prefixlen_ == old_lease->prefixlen_))) {
1138 deleted_leases->push_back(old_lease);
1143 callout_handle->setArgument(
"deleted_leases6", deleted_leases);
1146 uint32_t parked_packet_limit = 0;
1150 parked_packet_limit = ppl->intValue();
1153 if (parked_packet_limit) {
1154 const auto& parking_lot = ServerHooks::getServerHooks().
1155 getParkingLotPtr(
"leases6_committed");
1156 if (parking_lot && (parking_lot->size() >= parked_packet_limit)) {
1160 .arg(parked_packet_limit)
1161 .arg(query->getLabel());
1163 static_cast<int64_t
>(1));
1173 HooksManager::park(
"leases6_committed", query,
1174 [
this, callout_handle, query, rsp, callout_handle_state]()
mutable {
1175 if (MultiThreadingMgr::instance().getMode()) {
1176 typedef function<void()> CallBack;
1177 boost::shared_ptr<CallBack> call_back =
1179 this, callout_handle, query, rsp));
1180 callout_handle_state->on_completion_ = [call_back]() {
1181 MultiThreadingMgr::instance().getThreadPool().add(call_back);
1191 HooksManager::callCallouts(
Hooks.hook_index_leases6_committed_,
1195 HooksManager::drop(
"leases6_committed", query);
1199 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK) {
1201 .arg(query->getLabel());
1209 HooksManager::drop(
"leases6_committed", query);
1210 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1212 .arg(query->getLabel());
1230 }
catch (
const std::exception& e) {
1246 bool skip_pack =
false;
1252 if (HooksManager::calloutsPresent(
Hooks.hook_index_pkt6_send_)) {
1264 callout_handle->setArgument(
"query6", query);
1267 callout_handle->setArgument(
"response6", rsp);
1270 HooksManager::callCallouts(
Hooks.hook_index_pkt6_send_, *callout_handle);
1277 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
1279 .arg(rsp->getLabel());
1284 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1286 .arg(rsp->getLabel());
1295 }
catch (
const std::exception& e) {
1315 if (HooksManager::calloutsPresent(
Hooks.hook_index_buffer6_send_)) {
1327 callout_handle->setArgument(
"response6", rsp);
1330 HooksManager::callCallouts(
Hooks.hook_index_buffer6_send_,
1336 if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
1337 (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
1340 .arg(rsp->getLabel());
1344 callout_handle->getArgument(
"response6", rsp);
1348 .arg(rsp->getLabel())
1349 .arg(rsp->getName())
1350 .arg(
static_cast<int>(rsp->getType()))
1351 .arg(rsp->getLocalAddr().isV6Zero() ?
"*" : rsp->getLocalAddr().toText())
1352 .arg(rsp->getLocalPort())
1353 .arg(rsp->getRemoteAddr())
1354 .arg(rsp->getRemotePort())
1355 .arg(rsp->getIface());
1358 .arg(rsp->getLabel())
1359 .arg(rsp->getName())
1360 .arg(
static_cast<int>(rsp->getType()))
1361 .arg(rsp->toText());
1367 }
catch (
const std::exception& e) {
1383 tmp << hex << setw(2) << setfill('0') << static_cast<uint16_t>(*it);
1397 answer->addOption(clientid);
1402 if (!question->relay_info_.empty()) {
1403 answer->copyRelayInfo(question);
1421 co_list.push_back(ctx.
currentHost()->getCfgOption6());
1429 ctx.
subnet_->getPool(resource.getPrefixLength() == 128 ?
1431 resource.getAddress(),
1433 if (pool && !pool->getCfgOption()->empty()) {
1434 co_list.push_back(pool->getCfgOption());
1439 if (!ctx.
subnet_->getCfgOption()->empty()) {
1440 co_list.push_back(ctx.
subnet_->getCfgOption());
1445 ctx.
subnet_->getSharedNetwork(network);
1446 if (network && !network->getCfgOption()->empty()) {
1447 co_list.push_back(network->getCfgOption());
1454 cclass != classes.
cend(); ++cclass) {
1457 getClientClassDictionary()->findClass(*cclass);
1462 .arg(question->getLabel())
1469 if (ccdef->getCfgOption()->empty()) {
1474 co_list.push_back(ccdef->getCfgOption());
1487 if (co_list.empty()) {
1491 set<uint16_t> requested_opts;
1500 for (uint16_t code : option_oro->getValues()) {
1501 static_cast<void>(requested_opts.insert(code));
1505 set<uint16_t> cancelled_opts;
1509 for (
auto const& copts : co_list) {
1517 for (OptionContainerPersistIndex::const_iterator desc = prange.first;
1518 desc != prange.second; ++desc) {
1520 if (desc->option_) {
1521 uint16_t code = desc->option_->
getType();
1522 static_cast<void>(requested_opts.insert(code));
1528 for (OptionContainerCancelIndex::const_iterator desc = crange.first;
1529 desc != crange.second; ++desc) {
1531 if (desc->option_) {
1532 uint16_t code = desc->option_->getType();
1533 static_cast<void>(cancelled_opts.insert(code));
1540 for (uint16_t opt : requested_opts) {
1542 if (cancelled_opts.count(opt) > 0) {
1550 if (!answer->getOption(opt)) {
1552 for (
auto const& copts : co_list) {
1556 answer->addOption(desc.
option_);
1569 set<uint32_t> vendor_ids;
1573 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
1575 uint32_t vendor_id = vendor_class->getVendorId();
1576 static_cast<void>(vendor_ids.insert(vendor_id));
1580 for (
auto const& copts : co_list) {
1583 if (!desc.option_) {
1587 boost::dynamic_pointer_cast<OptionVendorClass>(desc.option_);
1588 if (!vendor_class) {
1592 uint32_t vendor_id = vendor_class->getVendorId();
1593 if (vendor_ids.count(vendor_id) > 0) {
1597 answer->addOption(desc.option_);
1598 static_cast<void>(vendor_ids.insert(vendor_id));
1607 set<uint32_t> vendor_ids;
1611 vendor_opts = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1613 uint32_t vendor_id = vendor_opts->getVendorId();
1614 static_cast<void>(vendor_ids.insert(vendor_id));
1618 for (
auto const& copts : co_list) {
1621 if (!desc.option_) {
1625 boost::dynamic_pointer_cast<OptionVendor>(desc.option_);
1630 uint32_t vendor_id = vendor_opts->getVendorId();
1631 if (vendor_ids.count(vendor_id) > 0) {
1637 answer->addOption(vendor_opts);
1638 static_cast<void>(vendor_ids.insert(vendor_id));
1657 if (!ctx.
subnet_ || co_list.empty()) {
1661 set<uint32_t> vendor_ids;
1665 map<uint32_t, OptionVendorPtr> vendor_rsps;
1668 vendor_rsp = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1670 uint32_t vendor_id = vendor_rsp->getVendorId();
1671 vendor_rsps[vendor_id] = vendor_rsp;
1672 static_cast<void>(vendor_ids.insert(vendor_id));
1678 map<uint32_t, OptionVendorPtr> vendor_reqs;
1681 vendor_req = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1683 uint32_t vendor_id = vendor_req->getVendorId();
1684 vendor_reqs[vendor_id] = vendor_req;
1685 static_cast<void>(vendor_ids.insert(vendor_id));
1693 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
1695 uint32_t vendor_id = vendor_class->getVendorId();
1696 static_cast<void>(vendor_ids.insert(vendor_id));
1702 if (vendor_ids.empty()) {
1706 map<uint32_t, set<uint16_t> > requested_opts;
1720 oro = boost::dynamic_pointer_cast<OptionUint16Array>(oro_generic);
1723 set<uint16_t> oro_req_opts;
1724 for (uint16_t code : oro->getValues()) {
1725 static_cast<void>(oro_req_opts.insert(code));
1731 map<uint32_t, set<uint16_t> > cancelled_opts;
1735 for (uint32_t vendor_id : vendor_ids) {
1736 for (
auto const& copts : co_list) {
1744 for (OptionContainerPersistIndex::const_iterator desc = prange.first;
1745 desc != prange.second; ++desc) {
1746 if (!desc->option_) {
1750 uint16_t code = desc->option_->getType();
1751 static_cast<void>(requested_opts[vendor_id].insert(code));
1756 for (OptionContainerCancelIndex::const_iterator desc = crange.first;
1757 desc != crange.second; ++desc) {
1758 if (!desc->option_) {
1762 uint16_t code = desc->option_->getType();
1763 static_cast<void>(cancelled_opts[vendor_id].insert(code));
1772 if (requested_opts[vendor_id].empty()) {
1779 if (vendor_rsps.count(vendor_id) > 0) {
1780 vendor_rsp = vendor_rsps[vendor_id];
1788 for (uint16_t opt : requested_opts[vendor_id]) {
1789 if (cancelled_opts[vendor_id].count(opt) > 0) {
1792 if (!vendor_rsp->getOption(opt)) {
1793 for (
auto const& copts : co_list) {
1796 vendor_rsp->addOption(desc.
option_);
1806 if (added && (vendor_rsps.count(vendor_id) == 0)) {
1807 answer->addOption(vendor_rsp);
1815 switch (pkt->getType()) {
1837 .arg(
static_cast<int>(pkt->getType()))
1838 .arg(pkt->getIface());
1843 .arg(pkt->getName())
1844 .arg(pkt->getRemoteAddr().toText())
1850 StatsMgr::instance().addValue(
"pkt6-receive-drop",
static_cast<int64_t
>(1));
1860 if (client_ids.size() != 1) {
1862 << pkt->getName() <<
", but " << client_ids.size()
1869 if (client_ids.size() > 1) {
1871 <<
") client-id options received in " << pkt->getName());
1873 if (!client_ids.empty()) {
1886 if (!server_ids.empty()) {
1888 << server_ids.size() <<
" received in " << pkt->getName());
1893 if (server_ids.size() != 1) {
1895 << server_ids.size() <<
"), exactly 1 expected in message "
1902 if (server_ids.size() > 1) {
1904 <<
") server-id options received in " << pkt->getName());
1906 if (!server_ids.empty()) {
1919 uint16_t len = opt->len() - opt->getHeaderLen();
1932 getCfgSubnets6()->selectSubnet(selector);
1935 if (HooksManager::calloutsPresent(
Hooks.hook_index_subnet6_select_)) {
1948 callout_handle->setArgument(
"query6", question);
1949 callout_handle->setArgument(
"subnet6", subnet);
1954 callout_handle->setArgument(
"subnet6collection",
1956 getCfgSubnets6()->getAll());
1959 HooksManager::callCallouts(
Hooks.hook_index_subnet6_select_, *callout_handle);
1965 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
1967 .arg(question->getLabel());
1973 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1975 .arg(question->getLabel());
1981 callout_handle->getArgument(
"subnet6", subnet);
1987 .arg(question->getLabel())
1988 .arg(subnet->getID());
1992 .arg(question->getLabel())
1993 .arg(subnet->toText());
1997 .arg(question->getLabel());
2022 for (
const auto& opt : question->options_) {
2023 switch (opt.second->getType()) {
2026 boost::dynamic_pointer_cast<
2029 answer->addOption(answer_opt);
2035 boost::dynamic_pointer_cast<
2038 answer->addOption(answer_opt);
2063 if (ddns_params->getEnableUpdates() &&
2073 .arg(question->getLabel());
2086 .arg(question->getLabel())
2087 .arg(fqdn->toText());
2106 *ddns_params,
true),
2116 ctx.
hostname_ = fqdn_resp->getDomainName();
2123 .arg(question->getLabel())
2124 .arg(fqdn_resp->toText());
2125 answer->addOption(fqdn_resp);
2129 if (HooksManager::calloutsPresent(
Hooks.hook_index_ddns6_update_)) {
2140 callout_handle->setArgument(
"query6", question);
2141 callout_handle->setArgument(
"response6", answer);
2142 callout_handle->setArgument(
"subnet6", subnet);
2143 callout_handle->setArgument(
"hostname", ctx.
hostname_);
2146 callout_handle->setArgument(
"ddns-params", ddns_params);
2149 HooksManager::callCallouts(
Hooks.hook_index_ddns6_update_, *callout_handle);
2152 string hook_hostname;
2153 bool hook_fwd_dns_update;
2154 bool hook_rev_dns_update;
2155 callout_handle->getArgument(
"hostname", hook_hostname);
2156 callout_handle->getArgument(
"fwd-update", hook_fwd_dns_update);
2157 callout_handle->getArgument(
"rev-update", hook_rev_dns_update);
2168 fqdn_resp = boost::dynamic_pointer_cast<Option6ClientFqdn>(answer->getOption(
D6O_CLIENT_FQDN));
2171 if (!(hook_fwd_dns_update || hook_rev_dns_update)) {
2198 <<
" encapsulating server's message must not be"
2199 <<
" NULL when creating DNS NameChangeRequest");
2212 bool do_fwd =
false;
2213 bool do_rev =
false;
2223 "client identifier is required when creating a new"
2224 " DNS NameChangeRequest");
2231 opt_fqdn->packDomainName(name_buf);
2232 const uint8_t* name_data =
static_cast<const uint8_t*
>(name_buf.
getData());
2235 std::vector<uint8_t> buf_vec(name_data, name_data + name_buf.
getLength());
2241 for (
auto answer_ia : answer->getOptions(
D6O_IA_NA)) {
2256 bool extended_only =
false;
2260 if ((*l)->addr_ == iaaddr->getAddress()) {
2265 ((*l)->hostname_ == opt_fqdn->getDomainName() &&
2266 (*l)->fqdn_fwd_ == do_fwd && (*l)->fqdn_rev_ == do_rev)) {
2267 extended_only =
true;
2279 if (!(do_fwd || do_rev) || (extended_only)) {
2295 opt_fqdn->getDomainName(),
2296 iaaddr->getAddress().toText(),
2318 getMACSources().get();
2320 for (CfgMACSources::const_iterator it = mac_sources.begin();
2321 it != mac_sources.end(); ++it) {
2322 hwaddr = pkt->getMAC(*it);
2333 boost::shared_ptr<Option6IA> ia) {
2339 boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(
D6O_IAADDR));
2342 hint = hint_opt->getAddress();
2347 .arg(query->getLabel())
2349 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2352 .arg(query->getLabel())
2354 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2374 "Server could not select subnet for"
2397 if (!leases.empty()) {
2398 lease = *leases.begin();
2411 .arg(query->getLabel())
2412 .arg(lease->addr_.toText())
2413 .arg(ia->getIAID());
2414 }
else if (lease->reuseable_valid_lft_ == 0) {
2416 .arg(query->getLabel())
2417 .arg(lease->addr_.toText())
2421 lease->valid_lft_ = lease->reuseable_valid_lft_;
2422 lease->preferred_lft_ = lease->reuseable_preferred_lft_;
2424 .arg(query->getLabel())
2425 .arg(lease->addr_.toText())
2430 StatsMgr::instance().addValue(
"v6-ia-na-lease-reuses", int64_t(1));
2431 StatsMgr::instance().addValue(StatsMgr::generateName(
"subnet", lease->subnet_id_,
2432 "v6-ia-na-lease-reuses"),
2436 .arg(query->getLabel())
2438 .arg(lease->toText());
2441 setTeeTimes(lease->preferred_lft_, subnet, ia_rsp);
2444 lease->preferred_lft_,
2445 lease->valid_lft_));
2446 ia_rsp->addOption(addr);
2459 .arg(query->getLabel())
2460 .arg(ia->getIAID());
2462 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2464 "Sorry, no address could be"
2473 boost::shared_ptr<Option6IA> ia) {
2480 boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(
D6O_IAPREFIX));
2483 hint = hint_opt->getAddress();
2488 .arg(query->getLabel())
2490 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2493 .arg(query->getLabel())
2495 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2513 "Sorry, no subnet available."));
2533 if (!leases.empty()) {
2537 uint32_t min_preferred_lft = (*leases.begin())->preferred_lft_;
2539 const bool pd_exclude_requested = requestedInORO(query,
D6O_PD_EXCLUDE);
2540 for (Lease6Collection::iterator l = leases.begin();
2541 l != leases.end(); ++l) {
2547 .arg(query->getLabel())
2548 .arg((*l)->addr_.toText())
2549 .arg(
static_cast<int>((*l)->prefixlen_))
2550 .arg(ia->getIAID());
2551 }
else if ((*l)->reuseable_valid_lft_ == 0) {
2553 .arg(query->getLabel())
2554 .arg((*l)->addr_.toText())
2555 .arg(
static_cast<int>((*l)->prefixlen_))
2559 (*l)->valid_lft_ = (*l)->reuseable_valid_lft_;
2560 (*l)->preferred_lft_ = (*l)->reuseable_preferred_lft_;
2562 .arg(query->getLabel())
2563 .arg((*l)->addr_.toText())
2564 .arg(
static_cast<int>((*l)->prefixlen_))
2569 StatsMgr::instance().addValue(
"v6-ia-pd-lease-reuses", int64_t(1));
2570 StatsMgr::instance().addValue(StatsMgr::generateName(
"subnet", (*l)->subnet_id_,
2571 "v6-ia-pd-lease-reuses"),
2576 if (((*l)->preferred_lft_ > 0) && (min_preferred_lft > (*l)->preferred_lft_)) {
2577 min_preferred_lft = (*l)->preferred_lft_;
2580 boost::shared_ptr<Option6IAPrefix>
2582 (*l)->prefixlen_, (*l)->preferred_lft_,
2584 ia_rsp->addOption(addr);
2586 if (pd_exclude_requested) {
2589 Pool6Ptr pool = boost::dynamic_pointer_cast<
2593 if (pd_exclude_option) {
2594 addr->addOption(pd_exclude_option);
2614 .arg(query->getLabel())
2615 .arg(ia->getIAID());
2617 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2619 "Sorry, no prefixes could"
2628 boost::shared_ptr<Option6IA> ia) {
2631 .arg(query->getLabel())
2632 .arg(ia->getIAID());
2651 "Sorry, no known leases for this duid/iaid."));
2663 for (OptionCollection::const_iterator it = addrs.begin();
2664 it != addrs.end(); ++it) {
2668 Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>(it->second);
2695 uint32_t min_preferred_lft = std::numeric_limits<uint32_t>::max();
2698 for (Lease6Collection::iterator l = leases.begin(); l != leases.end(); ++l) {
2699 if ((*l)->reuseable_valid_lft_ == 0) {
2701 .arg(query->getLabel())
2702 .arg((*l)->addr_.toText())
2703 .arg(ia->getIAID());
2705 (*l)->valid_lft_ = (*l)->reuseable_valid_lft_;
2706 (*l)->preferred_lft_ = (*l)->reuseable_preferred_lft_;
2708 .arg(query->getLabel())
2709 .arg((*l)->addr_.toText())
2714 StatsMgr::instance().addValue(
"v6-ia-na-lease-reuses", int64_t(1));
2715 StatsMgr::instance().addValue(StatsMgr::generateName(
"subnet", (*l)->subnet_id_,
2716 "v6-ia-na-lease-reuses"),
2721 (*l)->addr_, (*l)->preferred_lft_, (*l)->valid_lft_));
2722 ia_rsp->addOption(iaaddr);
2725 if (((*l)->preferred_lft_ > 0) && (min_preferred_lft > (*l)->preferred_lft_)) {
2726 min_preferred_lft = (*l)->preferred_lft_;
2731 hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
2742 if (
equalValues(query->getClientId(), (*l)->duid_)) {
2744 (*l)->addr_, 0, 0));
2745 ia_rsp->addOption(iaaddr);
2750 hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
2758 .arg(query->getLabel())
2759 .arg((*l)->toText())
2770 for (AllocEngine::HintContainer::const_iterator hint = hints.begin();
2771 hint != hints.end(); ++hint) {
2773 hint->getAddress(), 0, 0));
2774 ia_rsp->addOption(iaaddr);
2777 if (!leases.empty()) {
2783 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2785 "Sorry, no addresses could be"
2786 " assigned at this time."));
2795 boost::shared_ptr<Option6IA> ia) {
2798 .arg(query->getLabel())
2799 .arg(ia->getIAID());
2816 "Sorry, no known PD leases"
2817 " for this duid/iaid."));
2837 " client sending Rebind to extend lifetime of the"
2838 " prefix (DUID=" << duid->toText() <<
", IAID="
2839 << ia->getIAID() <<
")");
2851 for (OptionCollection::const_iterator it = addrs.begin();
2852 it != addrs.end(); ++it) {
2886 const bool pd_exclude_requested = requestedInORO(query,
D6O_PD_EXCLUDE);
2890 uint32_t min_preferred_lft = std::numeric_limits<uint32_t>::max();
2892 for (Lease6Collection::iterator l = leases.begin(); l != leases.end(); ++l) {
2893 if ((*l)->reuseable_valid_lft_ == 0) {
2895 .arg(query->getLabel())
2896 .arg((*l)->addr_.toText())
2897 .arg(
static_cast<int>((*l)->prefixlen_))
2898 .arg(ia->getIAID());
2900 (*l)->valid_lft_ = (*l)->reuseable_valid_lft_;
2901 (*l)->preferred_lft_ = (*l)->reuseable_preferred_lft_;
2903 .arg(query->getLabel())
2904 .arg((*l)->addr_.toText())
2905 .arg(
static_cast<int>((*l)->prefixlen_))
2910 StatsMgr::instance().addValue(
"v6-ia-pd-lease-reuses", int64_t(1));
2911 StatsMgr::instance().addValue(StatsMgr::generateName(
"subnet", (*l)->subnet_id_,
2912 "v6-ia-pd-lease-reuses"),
2917 (*l)->addr_, (*l)->prefixlen_,
2918 (*l)->preferred_lft_, (*l)->valid_lft_));
2919 ia_rsp->addOption(prf);
2921 if (pd_exclude_requested) {
2924 Pool6Ptr pool = boost::dynamic_pointer_cast<
2929 if (pd_exclude_option) {
2930 prf->addOption(pd_exclude_option);
2936 if (((*l)->preferred_lft_ > 0) && ((*l)->preferred_lft_ < min_preferred_lft)) {
2937 min_preferred_lft = (*l)->preferred_lft_;
2942 hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
2953 if (
equalValues(query->getClientId(), (*l)->duid_)) {
2955 (*l)->prefixlen_, 0, 0));
2956 ia_rsp->addOption(prefix);
2961 hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
2966 for (AllocEngine::HintContainer::const_iterator prefix = hints.begin();
2967 prefix != hints.end(); ++prefix) {
2972 if (!prefix->getAddress().isV6Zero()) {
2974 prefix->getAddress(),
2975 prefix->getPrefixLength(),
2977 ia_rsp->addOption(prefix_opt);
2981 if (!leases.empty()) {
2988 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2990 "Sorry, no prefixes could be"
2991 " assigned at this time."));
3012 for (
const auto& opt : query->options_) {
3013 switch (opt.second->getType()) {
3016 boost::dynamic_pointer_cast<
3019 reply->addOption(answer_opt);
3026 boost::dynamic_pointer_cast<
3029 reply->addOption(answer_opt);
3064 for (
const auto& opt : release->options_) {
3066 switch (opt.second->getType()) {
3069 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3072 reply->addOption(answer_opt);
3078 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3081 reply->addOption(answer_opt);
3098 reply->addOption(createStatusCode(*release, general_status,
3099 "Summary status for all processed IA_NAs"));
3104 int& general_status, boost::shared_ptr<Option6IA> ia,
3108 .arg(query->getLabel())
3109 .arg(ia->getIAID());
3125 if (!release_addr) {
3127 "You did not include an address in your RELEASE"));
3133 release_addr->getAddress());
3140 "Sorry, no known leases for this duid/iaid, can't release."));
3146 if (!lease->duid_) {
3152 .arg(query->getLabel())
3153 .arg(release_addr->getAddress().toText());
3157 "Database consistency check failed when trying to RELEASE"));
3161 if (*duid != *(lease->duid_)) {
3165 .arg(query->getLabel())
3166 .arg(release_addr->getAddress().toText())
3167 .arg(lease->duid_->toText());
3171 "This address does not belong to you, you can't release it"));
3175 if (ia->getIAID() != lease->iaid_) {
3178 .arg(query->getLabel())
3179 .arg(release_addr->getAddress().toText())
3181 .arg(ia->getIAID());
3183 "This is your address, but you used wrong IAID"));
3193 if (HooksManager::calloutsPresent(
Hooks.hook_index_lease6_release_)) {
3206 callout_handle->deleteAllArguments();
3209 callout_handle->setArgument(
"query6", query);
3212 callout_handle->setArgument(
"lease6", lease);
3215 HooksManager::callCallouts(
Hooks.hook_index_lease6_release_, *callout_handle);
3220 if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
3221 (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
3224 .arg(query->getLabel());
3229 bool success =
false;
3230 bool expired =
false;
3237 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3238 expiration_cfg->getHoldReclaimedTime() &&
3241 lease->valid_lft_ = 0;
3242 lease->preferred_lft_ = 0;
3256 "Server failed to release a lease"));
3259 .arg(query->getLabel())
3260 .arg(lease->addr_.toText())
3269 .arg(query->getLabel())
3270 .arg(lease->addr_.toText())
3273 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_Success,
3274 "Lease released. Thank you, please come again."));
3278 .arg(query->getLabel())
3279 .arg(lease->addr_.toText())
3283 .arg(query->getLabel())
3284 .arg(lease->addr_.toText())
3288 StatsMgr::instance().addValue(
3289 StatsMgr::generateName(
"subnet", lease->subnet_id_,
"assigned-nas"),
3290 static_cast<int64_t
>(-1));
3294 const auto& pool = subnet->getPool(
Lease::TYPE_NA, lease->addr_,
false);
3296 StatsMgr::instance().addValue(
3297 StatsMgr::generateName(
"subnet", subnet->getID(),
3298 StatsMgr::generateName(
"pool", pool->getID(),
"assigned-nas")),
3299 static_cast<int64_t
>(-1));
3315 int& general_status, boost::shared_ptr<Option6IA> ia,
3330 boost::shared_ptr<Option6IAPrefix> release_prefix =
3331 boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(
D6O_IAPREFIX));
3332 if (!release_prefix) {
3334 "You did not include a prefix in your RELEASE"));
3340 release_prefix->getAddress());
3347 "Sorry, no known leases for this duid/iaid, can't release."));
3353 if (!lease->duid_) {
3358 .arg(query->getLabel())
3359 .arg(release_prefix->getAddress().toText())
3360 .arg(
static_cast<int>(release_prefix->getLength()));
3364 "Database consistency check failed when trying to RELEASE"));
3368 if (*duid != *(lease->duid_)) {
3371 .arg(query->getLabel())
3372 .arg(release_prefix->getAddress().toText())
3373 .arg(
static_cast<int>(release_prefix->getLength()))
3374 .arg(lease->duid_->toText());
3378 "This address does not belong to you, you can't release it"));
3382 if (ia->getIAID() != lease->iaid_) {
3385 .arg(query->getLabel())
3386 .arg(release_prefix->getAddress().toText())
3387 .arg(
static_cast<int>(release_prefix->getLength()))
3389 .arg(ia->getIAID());
3391 "This is your address, but you used wrong IAID"));
3401 if (HooksManager::calloutsPresent(
Hooks.hook_index_lease6_release_)) {
3414 callout_handle->setArgument(
"query6", query);
3417 callout_handle->setArgument(
"lease6", lease);
3420 HooksManager::callCallouts(
Hooks.hook_index_lease6_release_, *callout_handle);
3425 if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
3426 (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
3429 .arg(query->getLabel());
3434 bool success =
false;
3435 bool expired =
false;
3442 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3443 expiration_cfg->getHoldReclaimedTime() &&
3446 lease->valid_lft_ = 0;
3447 lease->preferred_lft_ = 0;
3461 "Server failed to release a lease"));
3464 .arg(query->getLabel())
3465 .arg(lease->addr_.toText())
3466 .arg(
static_cast<int>(lease->prefixlen_))
3474 .arg(query->getLabel())
3475 .arg(lease->addr_.toText())
3476 .arg(
static_cast<int>(lease->prefixlen_))
3479 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_Success,
3480 "Lease released. Thank you, please come again."));
3484 .arg(query->getLabel())
3485 .arg(lease->addr_.toText())
3486 .arg(
static_cast<int>(lease->prefixlen_))
3490 .arg(query->getLabel())
3491 .arg(lease->addr_.toText())
3492 .arg(
static_cast<int>(lease->prefixlen_))
3496 StatsMgr::instance().addValue(
3497 StatsMgr::generateName(
"subnet", lease->subnet_id_,
"assigned-pds"),
3498 static_cast<int64_t
>(-1));
3502 const auto& pool = subnet->getPool(
Lease::TYPE_PD, lease->addr_,
false);
3504 StatsMgr::instance().addValue(
3505 StatsMgr::generateName(
"subnet", subnet->getID(),
3506 StatsMgr::generateName(
"pd-pool", pool->getID(),
"assigned-pds")),
3507 static_cast<int64_t
>(-1));
3525 if (opt_rapid_commit) {
3528 .arg(solicit->getLabel());
3533 response->addOption(opt_rapid_commit);
3552 if (MultiThreadingMgr::instance().getMode()) {
3565 .arg(solicit->getLabel())
3566 .arg(solicit->getName())
3567 .arg(solicit->getClasses().toText());
3576 updateReservedFqdn(ctx, response);
3595 if (MultiThreadingMgr::instance().getMode()) {
3608 .arg(request->getLabel())
3609 .arg(request->getName())
3610 .arg(request->getClasses().toText());
3619 updateReservedFqdn(ctx, reply);
3620 generateFqdn(reply, ctx);
3634 if (MultiThreadingMgr::instance().getMode()) {
3647 .arg(renew->getLabel())
3648 .arg(renew->getName())
3649 .arg(renew->getClasses().toText());
3658 updateReservedFqdn(ctx, reply);
3659 generateFqdn(reply, ctx);
3673 if (MultiThreadingMgr::instance().getMode()) {
3686 .arg(rebind->getLabel())
3687 .arg(rebind->getName())
3688 .arg(rebind->getClasses().toText());
3697 updateReservedFqdn(ctx, reply);
3698 generateFqdn(reply, ctx);
3712 .arg(confirm->getLabel())
3713 .arg(confirm->getName())
3714 .arg(confirm->getClasses().toText());
3735 bool verified =
false;
3744 for (OptionCollection::const_iterator ia = ias.begin();
3745 ia != ias.end(); ++ia) {
3747 for (OptionCollection::const_iterator opt = opts.begin();
3748 opt != opts.end(); ++opt) {
3760 if (subnet && !subnet->inRange(iaaddr->getAddress())) {
3761 std::ostringstream status_msg;
3762 status_msg <<
"Address " << iaaddr->
getAddress()
3763 <<
" is not on link.";
3764 reply->addOption(createStatusCode(*confirm,
3772 " to the Option6IAAddrPtr. This is programming"
3773 " error and should be reported");
3790 "All addresses are on-link"));
3793 "No subnet selected"));
3807 .arg(release->getLabel())
3808 .arg(release->getName())
3809 .arg(release->getClasses().toText());
3838 .arg(decline->getLabel())
3839 .arg(decline->getName())
3840 .arg(decline->getClasses().toText());
3879 for (
const auto& opt : decline->options_) {
3880 switch (opt.second->getType()) {
3883 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3888 reply->addOption(answer_opt);
3909 int& general_status, boost::shared_ptr<Option6IA> ia,
3913 .arg(decline->getLabel())
3914 .arg(ia->getIAID());
3929 int total_addrs = 0;
3930 for (OptionCollection::const_iterator opt = opts.begin(); opt != opts.end();
3940 if (!decline_addr) {
3947 decline_addr->getAddress());
3952 .arg(decline->getLabel()).arg(decline_addr->getAddress().toText());
3960 "Server does not know about such an address."));
3968 if (!lease->duid_) {
3974 .arg(decline->getLabel())
3975 .arg(decline_addr->getAddress().toText());
3978 "Database consistency check failed when attempting Decline."));
3984 if (*duid != *(lease->duid_)) {
3988 .arg(decline->getLabel())
3989 .arg(decline_addr->getAddress().toText())
3990 .arg(lease->duid_->toText());
3993 "This address does not belong to you, you can't decline it"));
3999 if (ia->getIAID() != lease->iaid_) {
4002 .arg(decline->getLabel())
4003 .arg(lease->addr_.toText())
4007 "This is your address, but you used wrong IAID"));
4019 new_leases.push_back(lease);
4023 if (total_addrs == 0) {
4025 "No addresses sent in IA_NA"));
4038 container->addOption(status);
4043 boost::shared_ptr<Option6IA> ia_rsp) {
4054 if (HooksManager::calloutsPresent(
Hooks.hook_index_lease6_decline_)) {
4067 callout_handle->setArgument(
"query6", decline);
4070 callout_handle->setArgument(
"lease6", lease);
4073 HooksManager::callCallouts(
Hooks.hook_index_lease6_decline_,
4079 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
4081 .arg(decline->getLabel())
4082 .arg(decline->getIface())
4083 .arg(lease->addr_.toText());
4089 if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
4091 .arg(decline->getLabel())
4092 .arg(decline->getIface())
4093 .arg(lease->addr_.toText());
4098 Lease6Ptr old_values = boost::make_shared<Lease6>(*lease);
4112 .arg(decline->getLabel())
4113 .arg(lease->addr_.toText())
4124 StatsMgr::instance().addValue(
4125 StatsMgr::generateName(
"subnet", lease->subnet_id_,
"declined-addresses"),
4126 static_cast<int64_t
>(1));
4130 const auto& pool = subnet->getPool(
Lease::TYPE_NA, lease->addr_,
false);
4132 StatsMgr::instance().addValue(
4133 StatsMgr::generateName(
"subnet", subnet->getID(),
4134 StatsMgr::generateName(
"pool", pool->getID(),
"declined-addresses")),
4135 static_cast<int64_t
>(1));
4140 StatsMgr::instance().addValue(
"declined-addresses",
static_cast<int64_t
>(1));
4143 .arg(lease->addr_.toText()).arg(lease->valid_lft_);
4145 ia_rsp->addOption(createStatusCode(*decline, *ia_rsp,
STATUS_Success,
4146 "Lease declined. Hopefully the next one will be better."));
4159 .arg(inf_request->getLabel())
4160 .arg(inf_request->getName())
4161 .arg(inf_request->getClasses().toText());
4210void Dhcpv6Srv::classifyByVendor(
const Pkt6Ptr& pkt) {
4213 vclass = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
4214 if (!vclass || vclass->getTuplesNum() == 0) {
4232 pkt->addClass(
"ALL");
4235 classifyByVendor(pkt);
4246 for (ClientClassDefList::const_iterator it = defs_ptr->cbegin();
4247 it != defs_ptr->cend(); ++it) {
4255 if ((*it)->getRequired()) {
4259 if ((*it)->getDependOnKnown() != depend_on_known) {
4262 (*it)->test(pkt, expr_ptr);
4271 for (
auto def : *defs_ptr) {
4275 if (def->getMatchExpr()) {
4276 pkt->classes_.erase(def->getName());
4287 cclass != classes.
cend(); ++cclass) {
4288 pkt->addClass(*cclass);
4298 ctx.
subnet_->getSharedNetwork(shared_network);
4299 if (shared_network) {
4301 if (host && (host->getIPv6SubnetID() != SUBNET_ID_GLOBAL)) {
4317 subnet->getSharedNetwork(network);
4319 const ClientClasses& to_add = network->getRequiredClasses();
4321 cclass != to_add.
cend(); ++cclass) {
4329 cclass != to_add.
cend(); ++cclass) {
4336 ctx.
subnet_->getPool(resource.getPrefixLength() == 128 ?
4338 resource.getAddress(),
4343 cclass != to_add.
cend(); ++cclass) {
4357 cclass != classes.
cend(); ++cclass) {
4380 pkt->addClass(*cclass);
4393 .arg(
"get exception?");
4403 " a message must not be NULL when updating reserved FQDN");
4414 std::string name = fqdn->getDomainName();
4426 if (new_name != name) {
4431 answer->addOption(fqdn);
4437Dhcpv6Srv::generateFqdn(
const Pkt6Ptr& answer,
4441 " a message must not be NULL when generating FQDN");
4452 if (!fqdn || !fqdn->getDomainName().empty()) {
4470 std::string generated_name =
4474 .arg(answer->getLabel())
4475 .arg(generated_name);
4492 lease->hostname_ = generated_name;
4493 lease->reuseable_valid_lft_ = 0;
4498 " for address " << addr <<
", so as it is impossible"
4499 " to update FQDN data. This is a programmatic error"
4500 " as the given address is now being handed to the"
4508 answer->addOption(fqdn);
4512 .arg(answer->getLabel())
4526 this, ph::_1, ph::_2));
4544 arg(result).arg((ncr ? ncr->toText() :
" NULL "));
4553 std::stringstream tmp;
4557 tmp << endl << EXTENDED_VERSION << endl;
4558 tmp <<
"linked with:" << endl;
4559 tmp << Logger::getVersion() << endl;
4560 tmp << CryptoLink::getVersion() << endl;
4561 tmp <<
"database:" << endl;
4578 if (query->relay_info_.empty()) {
4589 for (
int i = query->relay_info_.size(); i > 0 ; --i) {
4591 if (rsoo_container) {
4596 for (OptionCollection::const_iterator opt = rsoo.begin();
4597 opt != rsoo.end(); ++opt) {
4601 if (cfg_rsoo->enabled(opt->second->getType()) &&
4602 !rsp->getOption(opt->second->getType())) {
4603 rsp->addOption(opt->second);
4612 if (query->relay_info_.empty()) {
4620 return (query->getRemotePort());
4626void Dhcpv6Srv::processStatsReceived(
const Pkt6Ptr& query) {
4630 string stat_name =
"pkt6-unknown-received";
4631 switch (query->getType()) {
4633 stat_name =
"pkt6-solicit-received";
4637 stat_name =
"pkt6-advertise-received";
4640 stat_name =
"pkt6-request-received";
4643 stat_name =
"pkt6-confirm-received";
4646 stat_name =
"pkt6-renew-received";
4649 stat_name =
"pkt6-rebind-received";
4653 stat_name =
"pkt6-reply-received";
4656 stat_name =
"pkt6-release-received";
4659 stat_name =
"pkt6-decline-received";
4662 stat_name =
"pkt6-reconfigure-received";
4665 stat_name =
"pkt6-infrequest-received";
4668 stat_name =
"pkt6-dhcpv4-query-received";
4672 stat_name =
"pkt6-dhcpv4-response-received";
4678 StatsMgr::instance().addValue(stat_name,
static_cast<int64_t
>(1));
4683 StatsMgr::instance().addValue(
"pkt6-sent",
static_cast<int64_t
>(1));
4687 switch (response->getType()) {
4689 stat_name =
"pkt6-advertise-sent";
4692 stat_name =
"pkt6-reply-sent";
4695 stat_name =
"pkt6-dhcpv4-response-sent";
4702 StatsMgr::instance().addValue(stat_name,
static_cast<int64_t
>(1));
4706 return (
Hooks.hook_index_buffer6_send_);
4710Dhcpv6Srv::requestedInORO(
const Pkt6Ptr& query,
const uint16_t code)
const {
4712 boost::dynamic_pointer_cast<OptionUint16Array>(query->getOption(
D6O_ORO));
4715 const std::vector<uint16_t>& codes = oro->getValues();
4716 return (std::find(codes.begin(), codes.end(), code) != codes.end());
4724 HooksManager::clearParkingLots();
4731 uint32_t t2_time = 0;
4734 if (!subnet->getT2().unspecified()) {
4735 t2_time = subnet->getT2();
4736 }
else if (subnet->getCalculateTeeTimes()) {
4738 t2_time =
static_cast<uint32_t
>(round(subnet->getT2Percent() * preferred_lft));
4742 resp->setT2(t2_time);
4745 uint32_t t1_time = 0;
4748 if (!subnet->getT1().unspecified()) {
4749 t1_time = subnet->getT1();
4750 }
else if (subnet->getCalculateTeeTimes()) {
4752 t1_time =
static_cast<uint32_t
>(round(subnet->getT1Percent() * preferred_lft));
4756 if (t1_time < t2_time) {
4757 resp->setT1(t1_time);
4769 if ((!ctx.
subnet_) || (!orig_subnet) || (orig_subnet->getID() == ctx.
subnet_->getID())) {
4777 orig_subnet->getSharedNetwork(network);
4779 .arg(question->getLabel())
4780 .arg(orig_subnet->toText())
4782 .arg(network ? network->getName() :
"<no network?>");
4788 std::string prev_hostname = ctx.
hostname_;
4805 for (Lease6Collection::const_iterator l = ctx.
new_leases_.begin();
4810 (*l)->reuseable_valid_lft_ = 0;
4817 static std::list<std::list<std::string>>
const list({
4818 {
"config-control",
"config-databases",
"[]"},
4819 {
"hooks-libraries",
"[]",
"parameters",
"*"},
4821 {
"hosts-databases",
"[]"},
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic)
std::string toText() const
Convert the address to a string.
static const IOAddress & IPV6_ZERO_ADDRESS()
Returns an IPv6 zero address.
The IOService class is a wrapper for the ASIO io_service class.
DHCPv4 and DHCPv6 allocation engine.
std::vector< Resource > HintContainer
Container for client's hints.
Implementation of the mechanisms to control the use of the Configuration Backends by the DHCPv6 serve...
@ EARLY_GLOBAL_RESERVATIONS_LOOKUP
D2ClientMgr & getD2ClientMgr()
Fetches the DHCP-DDNS manager.
static CfgMgr & instance()
returns a single instance of Configuration Manager
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
static SubnetSelector initSelector(const Pkt6Ptr &query)
Build selector from a client's message.
Container for storing client class names.
ClientClassContainer::const_iterator const_iterator
Type of iterators.
void insert(const ClientClass &class_name)
Insert an element.
std::string toText(const std::string &separator=", ") const
Returns all class names as text.
const_iterator cbegin() const
Iterators to the first element.
const_iterator cend() const
Iterators to the past the end element.
Client race avoidance RAII handler.
bool tryLock(Pkt4Ptr query, ContinuationPtr cont=ContinuationPtr())
Tries to acquires a client.
D2ClientMgr isolates Kea from the details of being a D2 client.
std::string generateFqdn(const asiolink::IOAddress &address, const DdnsParams &ddns_params, const bool trailing_dot=true) const
Builds a FQDN based on the configuration and given IP address.
bool ddnsEnabled()
Convenience method for checking if DHCP-DDNS is enabled.
void startSender(D2ClientErrorHandler error_handler, isc::asiolink::IOService &io_service)
Enables sending NameChangeRequests to kea-dhcp-ddns.
void getUpdateDirections(const T &fqdn_resp, bool &forward, bool &reverse)
Get directional update flags based on server FQDN flags.
void suspendUpdates()
Suspends sending requests.
void adjustDomainName(const T &fqdn, T &fqdn_resp, const DdnsParams &ddns_params)
Set server FQDN name based on configuration and a given FQDN.
void sendRequest(dhcp_ddns::NameChangeRequestPtr &ncr)
Send the given NameChangeRequests to kea-dhcp-ddns.
void stopSender()
Disables sending NameChangeRequests to kea-dhcp-ddns.
void adjustFqdnFlags(const T &fqdn, T &fqdn_resp, const DdnsParams &ddns_params)
Set server FQDN flags based on configuration and a given FQDN.
std::string qualifyName(const std::string &partial_name, const DdnsParams &ddns_params, const bool trailing_dot) const
Adds a qualifying suffix to a given domain name.
This exception is thrown when DHCP server hits the error which should result in discarding the messag...
Factory for generating DUIDs (DHCP Unique Identifiers).
DuidPtr get()
Returns current DUID.
Holds DUID (DHCPv6 Unique Identifier)
static constexpr size_t MIN_DUID_LEN
minimum duid size
static constexpr size_t MAX_DUID_LEN
maximum duid size
void send(const Pkt6Ptr &pkt)
Send message over IPC.
void close()
Close communication socket.
static Dhcp6to4Ipc & instance()
Returns pointer to the sole instance of Dhcp6to4Ipc.
static uint16_t client_port
void run_one()
Main server processing step.
void shutdown() override
Instructs the server to shut down.
RequirementLevel
defines if certain option may, must or must not appear
OptionPtr getServerID()
Returns server-identifier option.
OptionPtr extendIA_PD(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Extends lifetime of the prefix.
void setReservedClientClasses(const Pkt6Ptr &pkt, const AllocEngine::ClientContext6 &ctx)
Assigns classes retrieved from host reservation database.
Pkt6Ptr processDecline(AllocEngine::ClientContext6 &ctx)
Process incoming Decline message.
void evaluateClasses(const Pkt6Ptr &pkt, bool depend_on_known)
Evaluate classes.
Pkt6Ptr processRenew(AllocEngine::ClientContext6 &ctx)
Processes incoming Renew message.
static void processStatsSent(const Pkt6Ptr &response)
Updates statistics for transmitted packets.
int run()
Main server processing loop.
void setPacketStatisticsDefaults()
This function sets statistics related to DHCPv6 packets processing to their initial values.
bool sanityCheck(const Pkt6Ptr &pkt)
Verifies if specified packet meets RFC requirements.
static uint16_t checkRelaySourcePort(const Pkt6Ptr &query)
Used for DHCPv4-over-DHCPv6 too.
void assignLeases(const Pkt6Ptr &question, Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx)
Assigns leases.
void stopD2()
Stops DHCP_DDNS client IO if DDNS updates are enabled.
void copyClientOptions(const Pkt6Ptr &question, Pkt6Ptr &answer)
Copies required options from client message to server answer.
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
virtual void sendPacket(const Pkt6Ptr &pkt)
dummy wrapper around IfaceMgr::send()
bool testServerID(const Pkt6Ptr &pkt)
Compare received server id with our server id.
void processPacketPktSend(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr &query, Pkt6Ptr &rsp)
Executes pkt6_send callout.
virtual void d2ClientErrorHandler(const dhcp_ddns::NameChangeSender::Result result, dhcp_ddns::NameChangeRequestPtr &ncr)
Implements the error handler for DHCP_DDNS IO errors.
OptionPtr declineIA(const Pkt6Ptr &decline, const DuidPtr &duid, int &general_status, boost::shared_ptr< Option6IA > ia, Lease6Collection &new_leases)
Declines leases in a single IA_NA option.
virtual Pkt6Ptr receivePacket(int timeout)
dummy wrapper around IfaceMgr::receive6
void processPacketBufferSend(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr &rsp)
Executes buffer6_send callout and sends the response.
void requiredClassify(const Pkt6Ptr &pkt, AllocEngine::ClientContext6 &ctx)
Assigns incoming packet to zero or more classes (required pass).
OptionPtr releaseIA_NA(const DuidPtr &duid, const Pkt6Ptr &query, int &general_status, boost::shared_ptr< Option6IA > ia, Lease6Ptr &old_lease)
Releases specific IA_NA option.
void buildCfgOptionList(const Pkt6Ptr &question, AllocEngine::ClientContext6 &ctx, CfgOptionList &co_list)
Build the configured option list.
void appendDefaultOptions(const Pkt6Ptr &question, Pkt6Ptr &answer, const CfgOptionList &co_list)
Appends default options to server's answer.
OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Processes IA_NA option (and assigns addresses if necessary).
static const std::string VENDOR_CLASS_PREFIX
this is a prefix added to the content of vendor-class option
OptionPtr serverid_
Server DUID (to be sent in server-identifier option)
void initContext(const Pkt6Ptr &pkt, AllocEngine::ClientContext6 &ctx, bool &drop)
Initializes client context for specified packet.
void checkDynamicSubnetChange(const Pkt6Ptr &question, Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx, const Subnet6Ptr orig_subnet)
Iterates over new leases, update stale DNS entries.
void conditionallySetReservedClientClasses(const Pkt6Ptr &pkt, const AllocEngine::ClientContext6 &ctx)
Assigns classes retrieved from host reservation database if they haven't been yet set.
OptionPtr releaseIA_PD(const DuidPtr &duid, const Pkt6Ptr &query, int &general_status, boost::shared_ptr< Option6IA > ia, Lease6Ptr &old_lease)
Releases specific IA_PD option.
void processDhcp4Query(const Pkt6Ptr &dhcp4_query)
Processes incoming DHCPv4-query message.
Pkt6Ptr processRebind(AllocEngine::ClientContext6 &ctx)
Processes incoming Rebind message.
bool earlyGHRLookup(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx)
Initialize client context and perform early global reservations lookup.
void processPacketAndSendResponseNoThrow(Pkt6Ptr &query)
Process a single incoming DHCPv6 packet and sends the response.
void processDhcp6Query(Pkt6Ptr &query, Pkt6Ptr &rsp)
Process a single incoming DHCPv6 query.
virtual ~Dhcpv6Srv()
Destructor. Used during DHCPv6 service shutdown.
void setTeeTimes(uint32_t preferred_lft, const Subnet6Ptr &subnet, Option6IAPtr &resp)
Sets the T1 and T2 timers in the outbound IA.
Pkt6Ptr processRequest(AllocEngine::ClientContext6 &ctx)
Processes incoming Request and returns Reply response.
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
std::list< std::list< std::string > > jsonPathsToRedact() const final override
Return a list of all paths that contain passwords or secrets for kea-dhcp6.
void processPacket(Pkt6Ptr &query, Pkt6Ptr &rsp)
Process a single incoming DHCPv6 packet.
OptionPtr assignIA_PD(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx, boost::shared_ptr< Option6IA > ia)
Processes IA_PD option (and assigns prefixes if necessary).
bool testUnicast(const Pkt6Ptr &pkt) const
Check if the message can be sent to unicast.
Pkt6Ptr processRelease(AllocEngine::ClientContext6 &ctx)
Process incoming Release message.
void processClientFqdn(const Pkt6Ptr &question, const Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx)
Processes Client FQDN Option.
void setStatusCode(boost::shared_ptr< Option6IA > &container, const OptionPtr &status)
A simple utility method that sets the status code.
static int getHookIndexBuffer6Send()
Returns the index of the buffer6_send hook.
void sendResponseNoThrow(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr &query, Pkt6Ptr &rsp)
Process an unparked DHCPv6 packet and sends the response.
void classifyPacket(const Pkt6Ptr &pkt)
Assigns incoming packet to zero or more classes.
static HWAddrPtr getMAC(const Pkt6Ptr &pkt)
Attempts to get a MAC/hardware address using configured sources.
Dhcpv6Srv(uint16_t server_port=DHCP6_SERVER_PORT, uint16_t client_port=0)
Default constructor.
bool declineLeases(const Pkt6Ptr &decline, Pkt6Ptr &reply, AllocEngine::ClientContext6 &ctx)
Attempts to decline all leases in specified Decline message.
void releaseLeases(const Pkt6Ptr &release, Pkt6Ptr &reply, AllocEngine::ClientContext6 &ctx)
Attempts to release received addresses.
void extendLeases(const Pkt6Ptr &query, Pkt6Ptr &reply, AllocEngine::ClientContext6 &ctx)
Attempts to extend the lifetime of IAs.
void processRSOO(const Pkt6Ptr &query, const Pkt6Ptr &rsp)
Processes Relay-supplied options, if present.
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
void processPacketAndSendResponse(Pkt6Ptr &query)
Process a single incoming DHCPv6 packet and sends the response.
OptionPtr extendIA_NA(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Extends lifetime of the specific IA_NA option.
Pkt6Ptr processConfirm(AllocEngine::ClientContext6 &ctx)
Processes incoming Confirm message and returns Reply.
void sanityCheckDUID(const OptionPtr &opt, const std::string &opt_name)
verifies if received DUID option (client-id or server-id) is sane
static void setHostIdentifiers(AllocEngine::ClientContext6 &ctx)
Set host identifiers within a context.
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
void appendRequestedOptions(const Pkt6Ptr &question, Pkt6Ptr &answer, const CfgOptionList &co_list)
Appends requested options to server's answer.
uint16_t client_port_
UDP port number to which server sends all responses.
volatile bool shutdown_
Indicates if shutdown is in progress.
Pkt6Ptr processSolicit(AllocEngine::ClientContext6 &ctx)
Processes incoming Solicit and returns response.
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
static std::string duidToString(const OptionPtr &opt)
converts DUID to text Converts content of DUID option to a text representation, e....
static void removeDependentEvaluatedClasses(const Pkt6Ptr &pkt)
Removed evaluated client classes.
void createNameChangeRequests(const Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx)
Creates a number of isc::dhcp_ddns::NameChangeRequest objects based on the DHCPv6 Client FQDN Option.
Pkt6Ptr processInfRequest(AllocEngine::ClientContext6 &ctx)
Processes incoming Information-request message.
void processDhcp6QueryAndSendResponse(Pkt6Ptr &query, Pkt6Ptr &rsp)
Process a single incoming DHCPv6 query.
uint16_t server_port_
UDP port number on which server listens.
isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr &question, bool &drop)
Selects a subnet for a given client's packet.
void appendRequestedVendorOptions(const Pkt6Ptr &question, Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx, const CfgOptionList &co_list)
Appends requested vendor options to server's answer.
bool declineLease(const Pkt6Ptr &decline, const Lease6Ptr lease, boost::shared_ptr< Option6IA > ia_rsp)
Declines specific IPv6 lease.
void discardPackets()
Discards parked packets Clears the packet parking lots of all packets.
IdentifierType
Type of the host identifier.
@ IDENT_FLEX
Flexible host identifier.
std::string getIdentifierAsText() const
Returns host identifier in a textual form.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
void closeSockets()
Closes all open sockets.
static TrackingLeaseMgr & instance()
Return current lease manager.
static void destroy()
Destroy lease manager.
virtual bool deleteLease(const Lease4Ptr &lease)=0
Deletes an IPv4 lease.
static std::string getDBVersion()
Class method to return extended version info This class method must be redeclared and redefined in de...
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
virtual void updateLease6(const Lease6Ptr &lease6)=0
Updates IPv6 lease.
static std::string getDBVersion()
Local version of getDBVersion() class method.
Holds information about DHCP service enabling status.
Represents DHCPv6 Client FQDN Option (code 39).
static const uint8_t FLAG_S
S bit.
static const uint8_t FLAG_N
N bit.
isc::asiolink::IOAddress getAddress() const
Returns address contained within this option.
Class that represents IAPREFIX option in DHCPv6.
uint32_t getIAID() const
Returns IA identifier.
This class represents Status Code option (13) from RFC 8415.
OptionPtr option_
Option instance.
Forward declaration to OptionIntArray.
This class represents vendor-specific information option.
const OptionCollection & getOptions() const
Returns all encapsulated options.
OptionPtr getOption(uint16_t type) const
Returns shared_ptr to suboption of specific type.
uint16_t getType() const
Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
static std::string getDBVersion()
Local version of getDBVersion() class method.
Represents a DHCPv6 packet.
virtual std::string getLabel() const
Returns text representation of the primary packet identifiers.
Pool information for IPv6 addresses and prefixes.
Option6PDExcludePtr getPrefixExcludeOption() const
Returns instance of the pool specific Prefix Exclude option.
An exception that is thrown if a DHCPv6 protocol violation occurs while processing a message (e....
RAII object enabling copying options retrieved from the packet.
Exception thrown when a call to select is interrupted by a signal.
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Container class for handling the DHCID value within a NameChangeRequest.
Represents a DHCP-DDNS client request.
Result
Defines the outcome of an asynchronous NCR send.
Wrapper class around callout handle which automatically resets handle's state.
int getExitValue()
Fetches the exit value.
Statistics Manager class.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
size_t getLength() const
Return the length of data written in the buffer.
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
@ DHCPV6_INFORMATION_REQUEST