8#include <kea_version.h>
114#include <boost/algorithm/string/erase.hpp>
115#include <boost/algorithm/string/join.hpp>
116#include <boost/algorithm/string/split.hpp>
117#include <boost/foreach.hpp>
118#include <boost/tokenizer.hpp>
132namespace ph = std::placeholders;
138 int hook_index_buffer6_receive_;
139 int hook_index_pkt6_receive_;
140 int hook_index_subnet6_select_;
141 int hook_index_leases6_committed_;
142 int hook_index_lease6_release_;
143 int hook_index_pkt6_send_;
144 int hook_index_buffer6_send_;
145 int hook_index_lease6_decline_;
146 int hook_index_host6_identifier_;
147 int hook_index_ddns6_update_;
182createStatusCode(
const Pkt6& pkt,
const uint16_t status_code,
183 const std::string& status_message) {
188 .arg(option_status->dataToText());
189 return (option_status);
207createStatusCode(
const Pkt6& pkt,
const Option6IA& ia,
const uint16_t status_code,
208 const std::string& status_message) {
214 .arg(option_status->dataToText());
215 return (option_status);
220std::set<std::string> dhcp6_statistics = {
222 "pkt6-solicit-received",
223 "pkt6-advertise-received",
224 "pkt6-request-received",
225 "pkt6-reply-received",
226 "pkt6-renew-received",
227 "pkt6-rebind-received",
228 "pkt6-decline-received",
229 "pkt6-release-received",
230 "pkt6-infrequest-received",
231 "pkt6-dhcpv4-query-received",
232 "pkt6-dhcpv4-response-received",
233 "pkt6-unknown-received",
235 "pkt6-advertise-sent",
237 "pkt6-dhcpv4-response-sent",
240 "v6-allocation-fail",
241 "v6-allocation-fail-shared-network",
242 "v6-allocation-fail-subnet",
243 "v6-allocation-fail-no-pools",
244 "v6-allocation-fail-classes",
245 "v6-ia-na-lease-reuses",
246 "v6-ia-pd-lease-reuses",
257 : io_service_(new
IOService()), server_port_(server_port),
258 client_port_(client_port), serverid_(), shutdown_(true),
259 alloc_engine_(), name_change_reqs_(),
289 }
catch (
const std::exception &e) {
305 for (
auto const& it : dhcp6_statistics) {
307 stats_mgr.
setValue(it,
static_cast<int64_t
>(0));
317 }
catch (
const std::exception& ex) {
324 }
catch (
const std::exception& ex) {
343 if (!names.empty()) {
345 for (
size_t i = 1; i < names.size(); ++i) {
346 msg += std::string(
", ") + names[i];
352 io_service_->stopAndPoll();
378 if (
getServerID()->getData() != server_id->getData()){
380 .arg(pkt->getLabel())
392 switch (pkt->getType()) {
397 if (pkt->relay_info_.empty() && !pkt->getLocalAddr().isV6Multicast()) {
399 .arg(pkt->getLabel())
400 .arg(pkt->getName());
415 for (
auto const& id_type : cfg->getIdentifierTypes()) {
436 std::vector<uint8_t> id;
445 callout_handle->setArgument(
"query6", ctx.
query_);
446 callout_handle->setArgument(
"id_type", type);
447 callout_handle->setArgument(
"id_value",
id);
453 callout_handle->getArgument(
"id_type", type);
454 callout_handle->getArgument(
"id_value",
id);
460 .arg(ctx.
query_->getLabel())
480 ctx.
duid_ = query->getClientId();
507 if (global_host && !global_host->getClientClasses6().empty()) {
512 const ClientClasses& classes = global_host->getClientClasses6();
513 for (
auto const& cclass : classes) {
514 query->addClass(cclass);
523 query->addClass(
"KNOWN");
525 .arg(query->getLabel())
532 if (query->inClass(
"DROP")) {
535 .arg(query->makeLabel(query->getClientId(),
nullptr))
536 .arg(query->toText());
538 static_cast<int64_t
>(1));
543 ctx.
hosts_[SUBNET_ID_GLOBAL] = global_host;
577 ctx.
subnet_->getSharedNetwork(sn);
589 global_host && !global_host->getClientClasses6().empty()) ||
590 (!sn && current_host && !current_host->getClientClasses6().empty())) {
611 if (!ctx.
hosts_.empty()) {
612 ctx.
query_->addClass(
"KNOWN");
614 .arg(ctx.
query_->getLabel())
617 ctx.
query_->addClass(
"UNKNOWN");
619 .arg(ctx.
query_->getLabel())
628 .arg(ctx.
query_->getLabel())
632 if (ctx.
query_->inClass(
"DROP")) {
634 .arg(ctx.
query_->makeLabel(ctx.
query_->getClientId(), 0))
635 .arg(ctx.
query_->toText());
637 static_cast<int64_t
>(1));
649 const char*
interface = getenv(
"KEA_AFL_INTERFACE");
651 isc_throw(FuzzInitFail,
"no fuzzing interface has been set");
655 const char* address = getenv(
"KEA_AFL_ADDRESS");
657 isc_throw(FuzzInitFail,
"no fuzzing address has been set");
665 while (__AFL_LOOP(fuzzer.maxLoopCount())) {
677 }
catch (
const std::exception& e) {
708 uint32_t timeout = 1;
719 .arg(query->getRemoteAddr().toText())
720 .arg(query->getRemotePort())
721 .arg(query->getLocalAddr().toText())
722 .arg(query->getLocalPort())
723 .arg(query->getIface());
745 }
catch (
const std::exception& e) {
759 .arg(query->getLabel());
763 query->addPktEvent(
"mt_queued");
764 typedef function<void()> CallBack;
765 boost::shared_ptr<CallBack> call_back =
781 }
catch (
const std::exception& e) {
783 .arg(query->getLabel())
787 .arg(query->getLabel());
804 query->addPktEvent(
"process_started");
807 query->addClass(
"ALL");
809 bool skip_unpack =
false;
826 callout_handle->setArgument(
"query6", query);
837 .arg(query->getRemoteAddr().toText())
838 .arg(query->getLocalAddr().toText())
839 .arg(query->getIface());
848 .arg(query->getRemoteAddr().toText())
849 .arg(query->getLocalAddr().toText())
850 .arg(query->getIface());
860 callout_handle->getArgument(
"query6", query);
872 .arg(query->getRemoteAddr().toText())
873 .arg(query->getLocalAddr().toText())
874 .arg(query->getIface());
881 .arg(query->getLabel())
883 }
catch (
const std::exception &e) {
886 .arg(query->getLabel())
887 .arg(query->getRemoteAddr().toText())
888 .arg(query->getLocalAddr().toText())
889 .arg(query->getIface())
891 .arg(query->makeLabel(query->getClientId(),
nullptr));
895 static_cast<int64_t
>(1));
897 static_cast<int64_t
>(1));
904 .arg(query->getLabel());
907 processStatsReceived(query);
932 .arg(query->getLabel())
933 .arg(query->getName())
934 .arg(
static_cast<int>(query->getType()))
935 .arg(query->getRemoteAddr())
936 .arg(query->getLocalAddr())
937 .arg(query->getIface());
939 .arg(query->getLabel())
940 .arg(query->toText());
958 callout_handle->setArgument(
"query6", query);
969 .arg(query->getLabel());
978 callout_handle->getArgument(
"query6", query);
991 if (query->inClass(
"DROP")) {
993 .arg(query->makeLabel(query->getClientId(),
nullptr))
994 .arg(query->toText());
996 static_cast<int64_t
>(1));
1013 }
catch (
const std::exception& e) {
1015 .arg(query->getLabel())
1019 .arg(query->getLabel());
1039 if (!client_handler.
tryLock(query, cont)) {
1080 }
catch (
const std::exception& e) {
1082 .arg(query->getLabel())
1086 .arg(query->getLabel());
1099 callout_handle->getContext(
"subnet6", ctx.
subnet_);
1119 switch (query->getType()) {
1156 }
catch (
const std::exception& e) {
1166 .arg(query->getLabel())
1167 .arg(query->getName())
1168 .arg(query->getRemoteAddr().toText())
1191 rsp->setRemoteAddr(query->getRemoteAddr());
1192 rsp->setLocalAddr(query->getLocalAddr());
1197 }
else if (rsp->relay_info_.empty()) {
1199 rsp->setRemotePort(DHCP6_CLIENT_PORT);
1203 rsp->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
1209 rsp->setLocalPort(DHCP6_SERVER_PORT);
1211 rsp->setIndex(query->getIndex());
1212 rsp->setIface(query->getIface());
1241 std::shared_ptr<ScopedCalloutHandleState> callout_handle_state =
1242 std::make_shared<ScopedCalloutHandleState>(callout_handle);
1247 callout_handle->setArgument(
"query6", query);
1253 if (new_lease->reuseable_valid_lft_ == 0) {
1254 new_leases->push_back(new_lease);
1258 callout_handle->setArgument(
"leases6", new_leases);
1263 for (
auto const& iac : ctx.
ias_) {
1264 if (!iac.old_leases_.empty()) {
1265 for (
auto const& old_lease : iac.old_leases_) {
1267 deleted_leases->push_back(old_lease);
1270 bool in_new =
false;
1272 if ((new_lease->addr_ == old_lease->addr_) &&
1274 (new_lease->prefixlen_ == old_lease->prefixlen_))) {
1280 deleted_leases->push_back(old_lease);
1285 callout_handle->setArgument(
"deleted_leases6", deleted_leases);
1288 uint32_t parked_packet_limit = 0;
1292 parked_packet_limit = ppl->intValue();
1295 if (parked_packet_limit) {
1297 getParkingLotPtr(
"leases6_committed");
1298 if (parking_lot && (parking_lot->size() >= parked_packet_limit)) {
1302 .arg(parked_packet_limit)
1303 .arg(query->getLabel());
1305 static_cast<int64_t
>(1));
1317 [
this, callout_handle, query, rsp, callout_handle_state, subnet]()
mutable {
1319 typedef function<void()> CallBack;
1320 boost::shared_ptr<CallBack> call_back =
1322 this, callout_handle, query, rsp, subnet));
1323 callout_handle_state->on_completion_ = [call_back]() {
1344 .arg(query->getLabel());
1355 .arg(query->getLabel());
1376 }
catch (
const std::exception& e) {
1378 .arg(query->getLabel())
1382 .arg(query->getLabel());
1390 query->addPktEvent(
"process_completed");
1396 bool skip_pack =
false;
1414 callout_handle->setArgument(
"query6", query);
1417 callout_handle->setArgument(
"response6", rsp);
1420 callout_handle->setArgument(
"subnet6", subnet);
1432 .arg(rsp->getLabel());
1439 .arg(rsp->getLabel());
1449 }
catch (
const std::exception& e) {
1451 .arg(query->getLabel())
1483 callout_handle->setArgument(
"response6", rsp);
1496 .arg(rsp->getLabel());
1500 callout_handle->getArgument(
"response6", rsp);
1504 .arg(rsp->getLabel())
1505 .arg(rsp->getName())
1506 .arg(
static_cast<int>(rsp->getType()))
1507 .arg(rsp->getLocalAddr().isV6Zero() ?
"*" : rsp->getLocalAddr().toText())
1508 .arg(rsp->getLocalPort())
1509 .arg(rsp->getRemoteAddr())
1510 .arg(rsp->getRemotePort())
1511 .arg(rsp->getIface());
1514 .arg(rsp->getLabel())
1515 .arg(rsp->getName())
1516 .arg(
static_cast<int>(rsp->getType()))
1517 .arg(rsp->toText());
1523 }
catch (
const std::exception& e) {
1525 .arg(rsp->getLabel())
1537 for (
auto const& it : data) {
1541 tmp << hex << setw(2) << setfill('0') << static_cast<uint16_t>(it);
1555 answer->addOption(clientid);
1560 if (!question->relay_info_.empty()) {
1561 answer->copyRelayInfo(question);
1579 co_list.push_back(ctx.
currentHost()->getCfgOption6());
1587 ctx.
subnet_->getPool(resource.getPrefixLength() == 128 ?
1589 resource.getAddress(),
1591 if (pool && !pool->getCfgOption()->empty()) {
1592 co_list.push_back(pool->getCfgOption());
1597 if (!ctx.
subnet_->getCfgOption()->empty()) {
1598 co_list.push_back(ctx.
subnet_->getCfgOption());
1603 ctx.
subnet_->getSharedNetwork(network);
1604 if (network && !network->getCfgOption()->empty()) {
1605 co_list.push_back(network->getCfgOption());
1611 for (
auto const& cclass : classes) {
1614 getClientClassDictionary()->findClass(cclass);
1619 .arg(question->getLabel())
1626 if (ccdef->getCfgOption()->empty()) {
1631 co_list.push_back(ccdef->getCfgOption());
1644 if (co_list.empty()) {
1648 set<uint16_t> requested_opts;
1657 for (uint16_t code : option_oro->getValues()) {
1658 static_cast<void>(requested_opts.insert(code));
1662 set<uint16_t> cancelled_opts;
1666 for (
auto const& copts : co_list) {
1674 BOOST_FOREACH(
auto const& desc, prange) {
1677 uint16_t code = desc.option_->getType();
1678 static_cast<void>(requested_opts.insert(code));
1684 BOOST_FOREACH(
auto const& desc, crange) {
1687 uint16_t code = desc.option_->getType();
1688 static_cast<void>(cancelled_opts.insert(code));
1693 const auto& cclasses = question->getClasses();
1696 for (uint16_t opt : requested_opts) {
1698 if (cancelled_opts.count(opt) > 0) {
1706 if (!answer->getOption(opt)) {
1708 for (
auto const& copts : co_list) {
1712 answer->addOption(desc.
option_);
1725 set<uint32_t> vendor_ids;
1729 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
1731 uint32_t vendor_id = vendor_class->getVendorId();
1732 static_cast<void>(vendor_ids.insert(vendor_id));
1736 for (
auto const& copts : co_list) {
1739 if (!desc.option_ || !desc.allowedForClientClasses(cclasses)) {
1743 boost::dynamic_pointer_cast<OptionVendorClass>(desc.option_);
1744 if (!vendor_class) {
1748 uint32_t vendor_id = vendor_class->getVendorId();
1749 if (vendor_ids.count(vendor_id) > 0) {
1753 answer->addOption(desc.option_);
1754 static_cast<void>(vendor_ids.insert(vendor_id));
1763 set<uint32_t> vendor_ids;
1767 vendor_opts = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1769 uint32_t vendor_id = vendor_opts->getVendorId();
1770 static_cast<void>(vendor_ids.insert(vendor_id));
1774 for (
auto const& copts : co_list) {
1777 if (!desc.option_ || !desc.allowedForClientClasses(cclasses)) {
1781 boost::dynamic_pointer_cast<OptionVendor>(desc.option_);
1786 uint32_t vendor_id = vendor_opts->getVendorId();
1787 if (vendor_ids.count(vendor_id) > 0) {
1793 answer->addOption(vendor_opts);
1794 static_cast<void>(vendor_ids.insert(vendor_id));
1813 if (!ctx.
subnet_ || co_list.empty()) {
1817 set<uint32_t> vendor_ids;
1821 map<uint32_t, OptionVendorPtr> vendor_rsps;
1824 vendor_rsp = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1826 uint32_t vendor_id = vendor_rsp->getVendorId();
1827 vendor_rsps[vendor_id] = vendor_rsp;
1828 static_cast<void>(vendor_ids.insert(vendor_id));
1834 map<uint32_t, OptionVendorPtr> vendor_reqs;
1837 vendor_req = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1839 uint32_t vendor_id = vendor_req->getVendorId();
1840 vendor_reqs[vendor_id] = vendor_req;
1841 static_cast<void>(vendor_ids.insert(vendor_id));
1849 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
1851 uint32_t vendor_id = vendor_class->getVendorId();
1852 static_cast<void>(vendor_ids.insert(vendor_id));
1858 if (vendor_ids.empty()) {
1862 map<uint32_t, set<uint16_t> > requested_opts;
1876 oro = boost::dynamic_pointer_cast<OptionUint16Array>(oro_generic);
1879 set<uint16_t> oro_req_opts;
1880 for (uint16_t code : oro->getValues()) {
1881 static_cast<void>(oro_req_opts.insert(code));
1887 map<uint32_t, set<uint16_t> > cancelled_opts;
1888 const auto& cclasses = question->getClasses();
1892 for (uint32_t vendor_id : vendor_ids) {
1893 for (
auto const& copts : co_list) {
1901 BOOST_FOREACH(
auto const& desc, prange) {
1902 if (!desc.option_) {
1906 uint16_t code = desc.option_->getType();
1907 static_cast<void>(requested_opts[vendor_id].insert(code));
1912 BOOST_FOREACH(
auto const& desc, crange) {
1913 if (!desc.option_) {
1917 uint16_t code = desc.option_->getType();
1918 static_cast<void>(cancelled_opts[vendor_id].insert(code));
1927 if (requested_opts[vendor_id].empty()) {
1934 if (vendor_rsps.count(vendor_id) > 0) {
1935 vendor_rsp = vendor_rsps[vendor_id];
1943 for (uint16_t opt : requested_opts[vendor_id]) {
1944 if (cancelled_opts[vendor_id].count(opt) > 0) {
1947 if (!vendor_rsp->getOption(opt)) {
1948 for (
auto const& copts : co_list) {
1952 vendor_rsp->addOption(desc.
option_);
1962 if (added && (vendor_rsps.count(vendor_id) == 0)) {
1963 answer->addOption(vendor_rsp);
1971 switch (pkt->getType()) {
1993 .arg(pkt->getLabel())
1994 .arg(
static_cast<int>(pkt->getType()))
1995 .arg(pkt->getIface());
2000 .arg(pkt->getLabel())
2001 .arg(pkt->getName())
2002 .arg(pkt->getRemoteAddr().toText())
2017 if (client_ids.size() != 1) {
2019 << pkt->getName() <<
", but " << client_ids.size()
2026 if (client_ids.size() > 1) {
2028 <<
") client-id options received in " << pkt->getName());
2030 if (!client_ids.empty()) {
2043 if (!server_ids.empty()) {
2045 << server_ids.size() <<
" received in " << pkt->getName());
2050 if (server_ids.size() != 1) {
2052 << server_ids.size() <<
"), exactly 1 expected in message "
2059 if (server_ids.size() > 1) {
2061 <<
") server-id options received in " << pkt->getName());
2063 if (!server_ids.empty()) {
2076 uint16_t len = opt->len() - opt->getHeaderLen();
2089 getCfgSubnets6()->selectSubnet(selector);
2099 shared_ptr<ScopedCalloutHandleState> callout_handle_state(
2100 std::make_shared<ScopedCalloutHandleState>(callout_handle));
2106 callout_handle->setArgument(
"query6", question);
2107 callout_handle->setArgument(
"subnet6", subnet);
2112 callout_handle->setArgument(
"subnet6collection",
2114 getCfgSubnets6()->getAll());
2116 auto const tpl(parkingLimitExceeded(
"subnet6_select"));
2117 bool const exceeded(get<0>(tpl));
2119 uint32_t
const limit(get<1>(tpl));
2124 .arg(question->getLabel());
2131 HooksManager::park(
"subnet6_select", question, [
this, question, callout_handle_state]() {
2133 boost::shared_ptr<function<void()>> callback(
2134 boost::make_shared<function<
void()>>([
this, question]()
mutable {
2137 callout_handle_state->on_completion_ = [callback]() {
2159 .arg(question->getLabel());
2172 .arg(question->getLabel());
2180 .arg(question->getLabel());
2186 callout_handle->getArgument(
"subnet6", subnet);
2192 .arg(question->getLabel())
2193 .arg(subnet->getID());
2197 .arg(question->getLabel())
2198 .arg(subnet->toText());
2202 .arg(question->getLabel());
2227 for (
auto const& opt : question->options_) {
2228 switch (opt.second->getType()) {
2231 boost::dynamic_pointer_cast<
2234 answer->addOption(answer_opt);
2240 boost::dynamic_pointer_cast<
2243 answer->addOption(answer_opt);
2269 if (ddns_params->getEnableUpdates() &&
2279 .arg(question->getLabel());
2292 .arg(question->getLabel())
2293 .arg(fqdn->toText());
2312 *ddns_params,
true),
2322 ctx.
hostname_ = fqdn_resp->getDomainName();
2329 .arg(question->getLabel())
2330 .arg(fqdn_resp->toText());
2331 answer->addOption(fqdn_resp);
2346 callout_handle->setArgument(
"query6", question);
2347 callout_handle->setArgument(
"response6", answer);
2348 callout_handle->setArgument(
"subnet6", subnet);
2349 callout_handle->setArgument(
"hostname", ctx.
hostname_);
2352 callout_handle->setArgument(
"ddns-params", ddns_params);
2358 string hook_hostname;
2359 bool hook_fwd_dns_update;
2360 bool hook_rev_dns_update;
2361 callout_handle->getArgument(
"hostname", hook_hostname);
2362 callout_handle->getArgument(
"fwd-update", hook_fwd_dns_update);
2363 callout_handle->getArgument(
"rev-update", hook_rev_dns_update);
2374 fqdn_resp = boost::dynamic_pointer_cast<Option6ClientFqdn>(answer->getOption(
D6O_CLIENT_FQDN));
2377 if (!(hook_fwd_dns_update || hook_rev_dns_update)) {
2404 <<
" encapsulating server's message must not be"
2405 <<
" NULL when creating DNS NameChangeRequest");
2418 bool do_fwd =
false;
2419 bool do_rev =
false;
2429 "client identifier is required when creating a new"
2430 " DNS NameChangeRequest");
2437 opt_fqdn->packDomainName(name_buf);
2438 const std::vector<uint8_t>& buf_vec = name_buf.
getVector();
2462 bool extended_only =
false;
2464 IOAddress ia_address = iaaddr->getAddress();
2465 for (
auto const& l : ia_ctx.reused_leases_) {
2466 if (l->addr_ == ia_address) {
2467 extended_only =
true;
2472 if (extended_only) {
2479 for (
auto const& l : ia_ctx.changed_leases_) {
2481 if (l->addr_ == ia_address) {
2485 if ((l->reuseable_valid_lft_ > 0) ||
2487 (l->hostname_ == opt_fqdn->getDomainName() &&
2488 l->fqdn_fwd_ == do_fwd && l->fqdn_rev_ == do_rev))) {
2489 extended_only =
true;
2501 if (!(do_fwd || do_rev) || (extended_only)) {
2517 opt_fqdn->getDomainName(),
2518 iaaddr->getAddress().toText(),
2527 .arg(answer->getLabel())
2528 .arg(ncr->toText());
2544 getMACSources().get();
2546 for (
auto const& it : mac_sources) {
2547 hwaddr = pkt->getMAC(it);
2563 BOOST_FOREACH(
auto const& resv, resvs) {
2564 if ((resv.second.getPrefix() == lease->addr_) &&
2565 (resv.second.getPrefixLen() == lease->prefixlen_)) {
2566 return (resv.second.getPDExclude());
2573 Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>(
2576 return (pool->getPrefixExcludeOption());
2584 boost::shared_ptr<Option6IA> ia) {
2590 boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(
D6O_IAADDR));
2593 hint = hint_opt->getAddress();
2598 .arg(query->getLabel())
2600 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2603 .arg(query->getLabel())
2605 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2625 "Server could not select subnet for"
2648 if (!leases.empty()) {
2649 lease = *leases.begin();
2663 .arg(query->getLabel())
2664 .arg(lease->addr_.toText())
2665 .arg(ia->getIAID());
2666 }
else if (lease->reuseable_valid_lft_ == 0) {
2668 .arg(query->getLabel())
2669 .arg(lease->addr_.toText())
2673 lease->valid_lft_ = lease->reuseable_valid_lft_;
2674 lease->preferred_lft_ = lease->reuseable_preferred_lft_;
2677 .arg(query->getLabel())
2678 .arg(lease->addr_.toText())
2685 "v6-ia-na-lease-reuses"),
2689 .arg(query->getLabel())
2691 .arg(lease->toText());
2694 setTeeTimes(lease->preferred_lft_, subnet, ia_rsp);
2697 lease->preferred_lft_,
2698 lease->valid_lft_));
2699 ia_rsp->addOption(addr);
2712 .arg(query->getLabel())
2713 .arg(ia->getIAID());
2715 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2717 "Sorry, no address could be"
2726 boost::shared_ptr<Option6IA> ia) {
2733 boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(
D6O_IAPREFIX));
2736 hint = hint_opt->getAddress();
2741 .arg(query->getLabel())
2743 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2746 .arg(query->getLabel())
2748 .arg(hint_opt ? hint.
toText() :
"(no hint)");
2766 "Sorry, no subnet available."));
2787 if (!leases.empty()) {
2791 uint32_t min_preferred_lft = (*leases.begin())->preferred_lft_;
2793 const bool pd_exclude_requested = requestedInORO(query,
D6O_PD_EXCLUDE);
2794 for (
auto const& l : leases) {
2800 .arg(query->getLabel())
2801 .arg(l->addr_.toText())
2802 .arg(
static_cast<int>(l->prefixlen_))
2803 .arg(ia->getIAID());
2804 }
else if (l->reuseable_valid_lft_ == 0) {
2806 .arg(query->getLabel())
2807 .arg(l->addr_.toText())
2808 .arg(
static_cast<int>(l->prefixlen_))
2812 l->valid_lft_ = l->reuseable_valid_lft_;
2813 l->preferred_lft_ = l->reuseable_preferred_lft_;
2815 .arg(query->getLabel())
2816 .arg(l->addr_.toText())
2817 .arg(
static_cast<int>(l->prefixlen_))
2824 "v6-ia-pd-lease-reuses"),
2829 if ((l->preferred_lft_ > 0) && (min_preferred_lft > l->preferred_lft_)) {
2830 min_preferred_lft = l->preferred_lft_;
2833 boost::shared_ptr<Option6IAPrefix>
2835 l->prefixlen_, l->preferred_lft_,
2837 ia_rsp->addOption(addr);
2839 if (pd_exclude_requested) {
2841 if (pd_exclude_option) {
2842 addr->addOption(pd_exclude_option);
2861 .arg(query->getLabel())
2862 .arg(ia->getIAID());
2864 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2866 "Sorry, no prefixes could"
2875 boost::shared_ptr<Option6IA> ia) {
2878 .arg(query->getLabel())
2879 .arg(ia->getIAID());
2898 "Sorry, no known leases for this duid/iaid."));
2910 for (
auto const& it : addrs) {
2914 Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>(it.second);
2941 uint32_t min_preferred_lft = std::numeric_limits<uint32_t>::max();
2944 for (
auto const& l : leases) {
2945 if (l->reuseable_valid_lft_ == 0) {
2947 .arg(query->getLabel())
2948 .arg(l->addr_.toText())
2949 .arg(ia->getIAID());
2951 l->valid_lft_ = l->reuseable_valid_lft_;
2952 l->preferred_lft_ = l->reuseable_preferred_lft_;
2954 .arg(query->getLabel())
2955 .arg(l->addr_.toText())
2962 "v6-ia-na-lease-reuses"),
2967 l->addr_, l->preferred_lft_, l->valid_lft_));
2968 ia_rsp->addOption(iaaddr);
2971 if ((l->preferred_lft_ > 0) && (min_preferred_lft > l->preferred_lft_)) {
2972 min_preferred_lft = l->preferred_lft_;
2977 hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
2987 if (
equalValues(query->getClientId(), l->duid_)) {
2990 ia_rsp->addOption(iaaddr);
2995 hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
3003 .arg(query->getLabel())
3015 for (
auto const& hint : hints) {
3017 hint.getAddress(), 0, 0));
3018 ia_rsp->addOption(iaaddr);
3021 if (!leases.empty()) {
3027 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
3029 "Sorry, no addresses could be"
3030 " assigned at this time."));
3039 boost::shared_ptr<Option6IA> ia) {
3042 .arg(query->getLabel())
3043 .arg(ia->getIAID());
3060 "Sorry, no known PD leases"
3061 " for this duid/iaid."));
3081 " client sending Rebind to extend lifetime of the"
3082 " prefix (DUID=" << duid->toText() <<
", IAID="
3083 << ia->getIAID() <<
")");
3095 for (
auto const& it : addrs) {
3129 const bool pd_exclude_requested = requestedInORO(query,
D6O_PD_EXCLUDE);
3133 uint32_t min_preferred_lft = std::numeric_limits<uint32_t>::max();
3135 for (
auto const& l : leases) {
3136 if (l->reuseable_valid_lft_ == 0) {
3138 .arg(query->getLabel())
3139 .arg(l->addr_.toText())
3140 .arg(
static_cast<int>(l->prefixlen_))
3141 .arg(ia->getIAID());
3143 l->valid_lft_ = l->reuseable_valid_lft_;
3144 l->preferred_lft_ = l->reuseable_preferred_lft_;
3146 .arg(query->getLabel())
3147 .arg(l->addr_.toText())
3148 .arg(
static_cast<int>(l->prefixlen_))
3155 "v6-ia-pd-lease-reuses"),
3160 l->addr_, l->prefixlen_,
3161 l->preferred_lft_, l->valid_lft_));
3162 ia_rsp->addOption(prf);
3164 if (pd_exclude_requested) {
3166 if (pd_exclude_option) {
3167 prf->addOption(pd_exclude_option);
3172 if ((l->preferred_lft_ > 0) && (l->preferred_lft_ < min_preferred_lft)) {
3173 min_preferred_lft = l->preferred_lft_;
3178 hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
3188 if (
equalValues(query->getClientId(), l->duid_)) {
3190 l->prefixlen_, 0, 0));
3191 ia_rsp->addOption(prefix);
3196 hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
3201 for (
auto const& prefix : hints) {
3206 if (!prefix.getAddress().isV6Zero()) {
3208 prefix.getAddress(),
3209 prefix.getPrefixLength(),
3211 ia_rsp->addOption(prefix_opt);
3215 if (!leases.empty()) {
3222 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
3224 "Sorry, no prefixes could be"
3225 " assigned at this time."));
3246 for (
auto const& opt : query->options_) {
3247 switch (opt.second->getType()) {
3250 boost::dynamic_pointer_cast<
3253 reply->addOption(answer_opt);
3260 boost::dynamic_pointer_cast<
3263 reply->addOption(answer_opt);
3299 for (
auto const& opt : release->options_) {
3301 switch (opt.second->getType()) {
3304 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3307 reply->addOption(answer_opt);
3313 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3316 reply->addOption(answer_opt);
3333 reply->addOption(createStatusCode(*release, general_status,
3334 "Summary status for all processed IA_NAs"));
3339 int& general_status, boost::shared_ptr<Option6IA> ia,
3343 .arg(query->getLabel())
3344 .arg(ia->getIAID());
3360 if (!release_addr) {
3362 "You did not include an address in your RELEASE"));
3368 release_addr->getAddress());
3375 "Sorry, no known leases for this duid/iaid, can't release."));
3381 if (!lease->duid_) {
3387 .arg(query->getLabel())
3388 .arg(release_addr->getAddress().toText());
3392 "Database consistency check failed when trying to RELEASE"));
3396 if (*duid != *(lease->duid_)) {
3400 .arg(query->getLabel())
3401 .arg(release_addr->getAddress().toText())
3402 .arg(lease->duid_->toText());
3406 "This address does not belong to you, you can't release it"));
3410 if (ia->getIAID() != lease->iaid_) {
3413 .arg(query->getLabel())
3414 .arg(release_addr->getAddress().toText())
3416 .arg(ia->getIAID());
3418 "This is your address, but you used wrong IAID"));
3441 callout_handle->deleteAllArguments();
3444 callout_handle->setArgument(
"query6", query);
3447 callout_handle->setArgument(
"lease6", lease);
3459 .arg(query->getLabel());
3464 bool success =
false;
3465 bool expired =
false;
3472 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3473 expiration_cfg->getHoldReclaimedTime() &&
3476 lease->valid_lft_ = 0;
3477 lease->preferred_lft_ = 0;
3497 "Server failed to release a lease"));
3500 .arg(query->getLabel())
3501 .arg(lease->addr_.toText())
3510 .arg(query->getLabel())
3511 .arg(lease->addr_.toText())
3514 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_Success,
3515 "Lease released. Thank you, please come again."));
3519 .arg(query->getLabel())
3520 .arg(lease->addr_.toText())
3524 .arg(query->getLabel())
3525 .arg(lease->addr_.toText())
3537 static_cast<int64_t
>(-1));
3541 auto const& pool = subnet->getPool(
Lease::TYPE_NA, lease->addr_,
false);
3546 static_cast<int64_t
>(-1));
3556 int& general_status, boost::shared_ptr<Option6IA> ia,
3571 boost::shared_ptr<Option6IAPrefix> release_prefix =
3572 boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(
D6O_IAPREFIX));
3573 if (!release_prefix) {
3575 "You did not include a prefix in your RELEASE"));
3581 release_prefix->getAddress());
3588 "Sorry, no known leases for this duid/iaid, can't release."));
3594 if (!lease->duid_) {
3599 .arg(query->getLabel())
3600 .arg(release_prefix->getAddress().toText())
3601 .arg(
static_cast<int>(release_prefix->getLength()));
3605 "Database consistency check failed when trying to RELEASE"));
3609 if (*duid != *(lease->duid_)) {
3612 .arg(query->getLabel())
3613 .arg(release_prefix->getAddress().toText())
3614 .arg(
static_cast<int>(release_prefix->getLength()))
3615 .arg(lease->duid_->toText());
3619 "This address does not belong to you, you can't release it"));
3623 if (ia->getIAID() != lease->iaid_) {
3626 .arg(query->getLabel())
3627 .arg(release_prefix->getAddress().toText())
3628 .arg(
static_cast<int>(release_prefix->getLength()))
3630 .arg(ia->getIAID());
3632 "This is your address, but you used wrong IAID"));
3655 callout_handle->setArgument(
"query6", query);
3658 callout_handle->setArgument(
"lease6", lease);
3670 .arg(query->getLabel());
3675 bool success =
false;
3676 bool expired =
false;
3683 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3684 expiration_cfg->getHoldReclaimedTime() &&
3687 lease->valid_lft_ = 0;
3688 lease->preferred_lft_ = 0;
3708 "Server failed to release a lease"));
3711 .arg(query->getLabel())
3712 .arg(lease->addr_.toText())
3713 .arg(
static_cast<int>(lease->prefixlen_))
3721 .arg(query->getLabel())
3722 .arg(lease->addr_.toText())
3723 .arg(
static_cast<int>(lease->prefixlen_))
3726 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_Success,
3727 "Lease released. Thank you, please come again."));
3731 .arg(query->getLabel())
3732 .arg(lease->addr_.toText())
3733 .arg(
static_cast<int>(lease->prefixlen_))
3737 .arg(query->getLabel())
3738 .arg(lease->addr_.toText())
3739 .arg(
static_cast<int>(lease->prefixlen_))
3746 static_cast<int64_t
>(-1));
3750 auto const& pool = subnet->getPool(
Lease::TYPE_PD, lease->addr_,
false);
3755 static_cast<int64_t
>(-1));
3772 if (opt_rapid_commit) {
3775 .arg(solicit->getLabel());
3780 response->addOption(opt_rapid_commit);
3813 .arg(solicit->getLabel())
3814 .arg(solicit->getName())
3815 .arg(solicit->getClasses().toText());
3824 updateReservedFqdn(ctx, response);
3857 .arg(request->getLabel())
3858 .arg(request->getName())
3859 .arg(request->getClasses().toText());
3868 updateReservedFqdn(ctx, reply);
3869 generateFqdn(reply, ctx);
3897 .arg(renew->getLabel())
3898 .arg(renew->getName())
3899 .arg(renew->getClasses().toText());
3908 updateReservedFqdn(ctx, reply);
3909 generateFqdn(reply, ctx);
3937 .arg(rebind->getLabel())
3938 .arg(rebind->getName())
3939 .arg(rebind->getClasses().toText());
3948 updateReservedFqdn(ctx, reply);
3949 generateFqdn(reply, ctx);
3964 .arg(confirm->getLabel())
3965 .arg(confirm->getName())
3966 .arg(confirm->getClasses().toText());
3987 bool verified =
false;
3996 for (
auto const& ia : ias) {
3998 for (
auto const& opt : opts) {
4010 if (subnet && !subnet->inRange(iaaddr->getAddress())) {
4011 std::ostringstream status_msg;
4012 status_msg <<
"Address " << iaaddr->getAddress()
4013 <<
" is not on link.";
4014 reply->addOption(createStatusCode(*confirm,
4022 " to the Option6IAAddrPtr. This is programming"
4023 " error and should be reported");
4040 "All addresses are on-link"));
4043 "No subnet selected"));
4058 .arg(release->getLabel())
4059 .arg(release->getName())
4060 .arg(release->getClasses().toText());
4090 .arg(decline->getLabel())
4091 .arg(decline->getName())
4092 .arg(decline->getClasses().toText());
4131 for (
auto const& opt : decline->options_) {
4132 switch (opt.second->getType()) {
4135 boost::dynamic_pointer_cast<Option6IA>(opt.second),
4140 reply->addOption(answer_opt);
4161 int& general_status, boost::shared_ptr<Option6IA> ia,
4165 .arg(decline->getLabel())
4166 .arg(ia->getIAID());
4181 int total_addrs = 0;
4182 for (
auto const& opt : opts) {
4191 if (!decline_addr) {
4198 decline_addr->getAddress());
4203 .arg(decline->getLabel()).arg(decline_addr->getAddress().toText());
4211 "Server does not know about such an address."));
4219 if (!lease->duid_) {
4225 .arg(decline->getLabel())
4226 .arg(decline_addr->getAddress().toText());
4229 "Database consistency check failed when attempting Decline."));
4235 if (*duid != *(lease->duid_)) {
4239 .arg(decline->getLabel())
4240 .arg(decline_addr->getAddress().toText())
4241 .arg(lease->duid_->toText());
4244 "This address does not belong to you, you can't decline it"));
4250 if (ia->getIAID() != lease->iaid_) {
4253 .arg(decline->getLabel())
4254 .arg(lease->addr_.toText())
4258 "This is your address, but you used wrong IAID"));
4270 new_leases.push_back(lease);
4274 if (total_addrs == 0) {
4276 "No addresses sent in IA_NA"));
4289 container->addOption(status);
4294 boost::shared_ptr<Option6IA> ia_rsp) {
4318 callout_handle->setArgument(
"query6", decline);
4321 callout_handle->setArgument(
"lease6", lease);
4332 .arg(decline->getLabel())
4333 .arg(decline->getIface())
4334 .arg(lease->addr_.toText());
4342 .arg(decline->getLabel())
4343 .arg(decline->getIface())
4344 .arg(lease->addr_.toText());
4349 Lease6Ptr old_values = boost::make_shared<Lease6>(*lease);
4363 .arg(decline->getLabel())
4364 .arg(lease->addr_.toText())
4377 static_cast<int64_t
>(1));
4381 auto const& pool = subnet->getPool(
Lease::TYPE_NA, lease->addr_,
false);
4386 static_cast<int64_t
>(1));
4394 .arg(lease->addr_.toText()).arg(lease->valid_lft_);
4396 ia_rsp->addOption(createStatusCode(*decline, *ia_rsp,
STATUS_Success,
4397 "Lease declined. Hopefully the next one will be better."));
4411 .arg(inf_request->getLabel())
4412 .arg(inf_request->getName())
4413 .arg(inf_request->getClasses().toText());
4462void Dhcpv6Srv::classifyByVendor(
const Pkt6Ptr& pkt) {
4465 vclass = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
4466 if (!vclass || vclass->getTuplesNum() == 0) {
4484 pkt->addClass(
"ALL");
4487 classifyByVendor(pkt);
4498 for (
auto const& it : *defs_ptr) {
4506 if (it->getAdditional()) {
4510 if (it->getDependOnKnown() != depend_on_known) {
4513 it->test(pkt, expr_ptr);
4522 for (
auto const& def : *defs_ptr) {
4526 if (def->getMatchExpr()) {
4527 pkt->classes_.erase(def->getName());
4537 for (
auto const& cclass : classes) {
4538 pkt->addClass(cclass);
4548 ctx.
subnet_->getSharedNetwork(shared_network);
4549 if (shared_network) {
4551 if (host && (host->getIPv6SubnetID() != SUBNET_ID_GLOBAL)) {
4570 ctx.
subnet_->getPool(resource.getPrefixLength() == 128 ?
4572 resource.getAddress(),
4575 const ClientClasses& pool_to_add = pool->getAdditionalClasses();
4576 for (
auto const& cclass : pool_to_add) {
4583 const ClientClasses& to_add = subnet->getAdditionalClasses();
4584 for (
auto const& cclass : to_add) {
4590 subnet->getSharedNetwork(network);
4592 const ClientClasses& net_to_add = network->getAdditionalClasses();
4593 for (
auto const& cclass : net_to_add) {
4603 for (
auto const& cclass : classes) {
4618 pkt->addClass(cclass);
4626 .arg(pkt->getLabel())
4628 .arg(status ?
"true" :
"false");
4631 pkt->addClass(cclass);
4635 .arg(pkt->getLabel())
4647 " a message must not be NULL when updating reserved FQDN");
4658 std::string name = fqdn->getDomainName();
4670 if (new_name != name) {
4675 answer->addOption(fqdn);
4681Dhcpv6Srv::generateFqdn(
const Pkt6Ptr& answer,
4685 " a message must not be NULL when generating FQDN");
4696 if (!fqdn || !fqdn->getDomainName().empty()) {
4710 if (!iaaddr || iaaddr->getValid() == 0) {
4716 std::string generated_name =
4720 .arg(answer->getLabel())
4721 .arg(generated_name);
4738 lease->hostname_ = generated_name;
4739 lease->reuseable_valid_lft_ = 0;
4744 " for address " << addr <<
", so as it is impossible"
4745 " to update FQDN data. This is a programmatic error"
4746 " as the given address is now being handed to the"
4754 answer->addOption(fqdn);
4758 .arg(answer->getLabel())
4772 this, ph::_1, ph::_2));
4791 arg(result).arg((ncr ? ncr->toText() :
" NULL "));
4800 std::stringstream tmp;
4804 tmp <<
" (" << EXTENDED_VERSION <<
")" << endl;
4805 tmp <<
"premium: " << PREMIUM_EXTENDED_VERSION << endl;
4806 tmp <<
"linked with:" << endl;
4811 tmp << endl <<
"lease backends:";
4813 tmp << endl <<
"- " <<
version;
4818 tmp << endl <<
"host backends:";
4820 tmp << endl <<
"- " <<
version;
4831 if (query->relay_info_.empty()) {
4842 for (
int i = query->relay_info_.size(); i > 0 ; --i) {
4844 if (rsoo_container) {
4849 for (
auto const& opt : rsoo) {
4853 if (cfg_rsoo->enabled(opt.second->getType()) &&
4854 !rsp->getOption(opt.second->getType())) {
4855 rsp->addOption(opt.second);
4864 if (query->relay_info_.empty()) {
4872 return (query->getRemotePort());
4878void Dhcpv6Srv::processStatsReceived(
const Pkt6Ptr& query) {
4882 string stat_name =
"pkt6-unknown-received";
4883 switch (query->getType()) {
4885 stat_name =
"pkt6-solicit-received";
4889 stat_name =
"pkt6-advertise-received";
4892 stat_name =
"pkt6-request-received";
4895 stat_name =
"pkt6-confirm-received";
4898 stat_name =
"pkt6-renew-received";
4901 stat_name =
"pkt6-rebind-received";
4905 stat_name =
"pkt6-reply-received";
4908 stat_name =
"pkt6-release-received";
4911 stat_name =
"pkt6-decline-received";
4914 stat_name =
"pkt6-reconfigure-received";
4917 stat_name =
"pkt6-infrequest-received";
4920 stat_name =
"pkt6-dhcpv4-query-received";
4924 stat_name =
"pkt6-dhcpv4-response-received";
4939 switch (response->getType()) {
4941 stat_name =
"pkt6-advertise-sent";
4944 stat_name =
"pkt6-reply-sent";
4947 stat_name =
"pkt6-dhcpv4-response-sent";
4958 return (
Hooks.hook_index_buffer6_send_);
4962Dhcpv6Srv::requestedInORO(
const Pkt6Ptr& query,
const uint16_t code)
const {
4964 boost::dynamic_pointer_cast<OptionUint16Array>(query->getOption(
D6O_ORO));
4967 const std::vector<uint16_t>& codes = oro->getValues();
4968 return (std::find(codes.begin(), codes.end(), code) != codes.end());
4974tuple<bool, uint32_t>
4975Dhcpv6Srv::parkingLimitExceeded(
string const& hook_label) {
4977 uint32_t parked_packet_limit(0);
4981 parked_packet_limit = ppl->intValue();
4984 if (parked_packet_limit) {
4988 if (parking_lot && parked_packet_limit <= parking_lot->size()) {
4989 return make_tuple(
true, parked_packet_limit);
4992 return make_tuple(
false, parked_packet_limit);
5003 char const*
const rotate(getenv(
"KEA_DHCP6_FUZZING_ROTATE_PORT"));
5007 while (!locker.
lock()) {
5008 this_thread::sleep_for(1s);
5011 port_file.open(
"/tmp/port6.txt", ios::in);
5014 getline(port_file, line);
5026 port_file.open(
"/tmp/port6.txt", ios::out | ios::trunc);
5027 port_file << to_string(port) << endl;
5042 uint32_t t2_time = 0;
5045 if (!subnet->getT2().unspecified()) {
5046 t2_time = subnet->getT2();
5047 }
else if (subnet->getCalculateTeeTimes()) {
5049 t2_time =
static_cast<uint32_t
>(round(subnet->getT2Percent() * preferred_lft));
5053 resp->setT2(t2_time);
5056 uint32_t t1_time = 0;
5059 if (!subnet->getT1().unspecified()) {
5060 t1_time = subnet->getT1();
5061 }
else if (subnet->getCalculateTeeTimes()) {
5063 t1_time =
static_cast<uint32_t
>(round(subnet->getT1Percent() * preferred_lft));
5067 if (t1_time < t2_time) {
5068 resp->setT1(t1_time);
5079 bool reprocess_client_name =
false;
5086 if (iaaddr && (iaaddr->getValid() > 0)) {
5088 auto pool = ddns_params->setPoolFromAddress(iaaddr->getAddress());
5091 reprocess_client_name = pool->hasDdnsParameters();
5097 if (ctx.
subnet_ && orig_subnet && (orig_subnet->getID() != ctx.
subnet_->getID())) {
5102 orig_subnet->getSharedNetwork(network);
5104 .arg(question->getLabel())
5105 .arg(orig_subnet->toText())
5107 .arg(network ? network->getName() :
"<no network?>");
5110 reprocess_client_name =
true;
5115 if (reprocess_client_name) {
5117 std::string prev_hostname = ctx.
hostname_;
5138 l->reuseable_valid_lft_ = 0;
5146 static std::list<std::list<std::string>>
const list({
5147 {
"config-control",
"config-databases",
"[]"},
5148 {
"hooks-libraries",
"[]",
"parameters",
"*"},
5150 {
"hosts-databases",
"[]"},
int version()
returns Kea hooks version.
Defines elements for storing the names of client classes.
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.
void clearIOServices()
Clear the list of IOService objects.
static IOServiceMgr & instance()
Access the IOServiceMgr singleton instance.
void pollIOServices()
Poll IOService objects.
The IOService class is a wrapper for the ASIO io_context class.
static std::string getVersion()
Get version string.
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.
void insert(const ClientClass &class_name)
Insert an element.
std::string toText(const std::string &separator=", ") const
Returns all class names as text.
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 getUpdateDirections(const T &fqdn_resp, bool &forward, bool &reverse)
Get directional update flags based on server FQDN flags.
void stop()
Stop the sender.
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.