8#include <kea_version.h>
67#include <boost/tokenizer.hpp>
68#include <boost/foreach.hpp>
69#include <boost/algorithm/string/erase.hpp>
70#include <boost/algorithm/string/join.hpp>
71#include <boost/algorithm/string/split.hpp>
94namespace ph = std::placeholders;
100 int hook_index_buffer6_receive_;
101 int hook_index_pkt6_receive_;
102 int hook_index_subnet6_select_;
103 int hook_index_leases6_committed_;
104 int hook_index_lease6_release_;
105 int hook_index_pkt6_send_;
106 int hook_index_buffer6_send_;
107 int hook_index_lease6_decline_;
108 int hook_index_host6_identifier_;
109 int hook_index_ddns6_update_;
144createStatusCode(
const Pkt6& pkt,
const uint16_t status_code,
145 const std::string& status_message) {
150 .arg(option_status->dataToText());
151 return (option_status);
169createStatusCode(
const Pkt6& pkt,
const Option6IA& ia,
const uint16_t status_code,
170 const std::string& status_message) {
176 .arg(option_status->dataToText());
177 return (option_status);
182std::set<std::string> dhcp6_statistics = {
184 "pkt6-solicit-received",
185 "pkt6-advertise-received",
186 "pkt6-request-received",
187 "pkt6-reply-received",
188 "pkt6-renew-received",
189 "pkt6-rebind-received",
190 "pkt6-decline-received",
191 "pkt6-release-received",
192 "pkt6-infrequest-received",
193 "pkt6-dhcpv4-query-received",
194 "pkt6-dhcpv4-response-received",
195 "pkt6-unknown-received",
197 "pkt6-advertise-sent",
199 "pkt6-dhcpv4-response-sent",
202 "v6-allocation-fail",
203 "v6-allocation-fail-shared-network",
204 "v6-allocation-fail-subnet",
205 "v6-allocation-fail-no-pools",
206 "v6-allocation-fail-classes",
207 "v6-ia-na-lease-reuses",
208 "v6-ia-pd-lease-reuses",
219 : io_service_(new
IOService()), server_port_(server_port),
220 client_port_(client_port), serverid_(), shutdown_(true),
221 alloc_engine_(), name_change_reqs_(),
251 }
catch (
const std::exception &e) {
266 for (
auto const& it : dhcp6_statistics) {
268 stats_mgr.setValue(it,
static_cast<int64_t
>(0));
278 }
catch (
const std::exception& ex) {
285 }
catch (
const std::exception& ex) {
299 if (!names.empty()) {
301 for (
size_t i = 1; i < names.size(); ++i) {
302 msg += std::string(
", ") + names[i];
308 io_service_->stopAndPoll();
334 if (
getServerID()->getData() != server_id->getData()){
336 .arg(pkt->getLabel())
348 switch (pkt->getType()) {
353 if (pkt->relay_info_.empty() && !pkt->getLocalAddr().isV6Multicast()) {
355 .arg(pkt->getLabel())
356 .arg(pkt->getName());
371 for (
auto const& id_type : cfg->getIdentifierTypes()) {
392 std::vector<uint8_t> id;
401 callout_handle->setArgument(
"query6", ctx.
query_);
402 callout_handle->setArgument(
"id_type", type);
403 callout_handle->setArgument(
"id_value",
id);
409 callout_handle->getArgument(
"id_type", type);
410 callout_handle->getArgument(
"id_value",
id);
416 .arg(ctx.
query_->getLabel())
436 ctx.
duid_ = query->getClientId();
463 if (global_host && !global_host->getClientClasses6().empty()) {
468 const ClientClasses& classes = global_host->getClientClasses6();
469 for (
auto const& cclass : classes) {
470 query->addClass(cclass);
479 query->addClass(
"KNOWN");
481 .arg(query->getLabel())
488 if (query->inClass(
"DROP")) {
491 .arg(query->makeLabel(query->getClientId(),
nullptr))
492 .arg(query->toText());
494 static_cast<int64_t
>(1));
499 ctx.
hosts_[SUBNET_ID_GLOBAL] = global_host;
533 ctx.
subnet_->getSharedNetwork(sn);
545 global_host && !global_host->getClientClasses6().empty()) ||
546 (!sn && current_host && !current_host->getClientClasses6().empty())) {
567 if (!ctx.
hosts_.empty()) {
568 ctx.
query_->addClass(
"KNOWN");
570 .arg(ctx.
query_->getLabel())
573 ctx.
query_->addClass(
"UNKNOWN");
575 .arg(ctx.
query_->getLabel())
584 .arg(ctx.
query_->getLabel())
585 .arg(classes.toText());
588 if (ctx.
query_->inClass(
"DROP")) {
590 .arg(ctx.
query_->makeLabel(ctx.
query_->getClientId(), 0))
591 .arg(ctx.
query_->toText());
593 static_cast<int64_t
>(1));
606 while (__AFL_LOOP(fuzzer.maxLoopCount())) {
619 }
catch (
const std::exception& e) {
650 uint32_t timeout = 1;
661 .arg(query->getRemoteAddr().toText())
662 .arg(query->getRemotePort())
663 .arg(query->getLocalAddr().toText())
664 .arg(query->getLocalPort())
665 .arg(query->getIface());
687 }
catch (
const std::exception& e) {
701 .arg(query->getLabel());
705 query->addPktEvent(
"mt_queued");
706 typedef function<void()> CallBack;
707 boost::shared_ptr<CallBack> call_back =
723 }
catch (
const std::exception& e) {
725 .arg(query->getLabel())
729 .arg(query->getLabel());
746 query->addPktEvent(
"process_started");
749 query->addClass(
"ALL");
751 bool skip_unpack =
false;
765 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
768 callout_handle->setArgument(
"query6", query);
779 .arg(query->getRemoteAddr().toText())
780 .arg(query->getLocalAddr().toText())
781 .arg(query->getIface());
790 .arg(query->getRemoteAddr().toText())
791 .arg(query->getLocalAddr().toText())
792 .arg(query->getIface());
802 callout_handle->getArgument(
"query6", query);
814 .arg(query->getRemoteAddr().toText())
815 .arg(query->getLocalAddr().toText())
816 .arg(query->getIface());
823 .arg(query->getLabel())
825 }
catch (
const std::exception &e) {
828 .arg(query->getLabel())
829 .arg(query->getRemoteAddr().toText())
830 .arg(query->getLocalAddr().toText())
831 .arg(query->getIface())
833 .arg(query->makeLabel(query->getClientId(),
nullptr));
837 static_cast<int64_t
>(1));
839 static_cast<int64_t
>(1));
846 .arg(query->getLabel());
849 processStatsReceived(query);
874 .arg(query->getLabel())
875 .arg(query->getName())
876 .arg(
static_cast<int>(query->getType()))
877 .arg(query->getRemoteAddr())
878 .arg(query->getLocalAddr())
879 .arg(query->getIface());
881 .arg(query->getLabel())
882 .arg(query->toText());
897 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
900 callout_handle->setArgument(
"query6", query);
911 .arg(query->getLabel());
920 callout_handle->getArgument(
"query6", query);
933 if (query->inClass(
"DROP")) {
935 .arg(query->makeLabel(query->getClientId(),
nullptr))
936 .arg(query->toText());
938 static_cast<int64_t
>(1));
955 }
catch (
const std::exception& e) {
957 .arg(query->getLabel())
961 .arg(query->getLabel());
981 if (!client_handler.tryLock(query, cont)) {
1022 }
catch (
const std::exception& e) {
1024 .arg(query->getLabel())
1028 .arg(query->getLabel());
1041 callout_handle->getContext(
"subnet6", ctx.
subnet_);
1061 switch (query->getType()) {
1098 }
catch (
const std::exception& e) {
1108 .arg(query->getLabel())
1109 .arg(query->getName())
1110 .arg(query->getRemoteAddr().toText())
1133 rsp->setRemoteAddr(query->getRemoteAddr());
1134 rsp->setLocalAddr(query->getLocalAddr());
1139 }
else if (rsp->relay_info_.empty()) {
1141 rsp->setRemotePort(DHCP6_CLIENT_PORT);
1145 rsp->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
1151 rsp->setLocalPort(DHCP6_SERVER_PORT);
1153 rsp->setIndex(query->getIndex());
1154 rsp->setIface(query->getIface());
1183 std::shared_ptr<ScopedCalloutHandleState> callout_handle_state =
1184 std::make_shared<ScopedCalloutHandleState>(callout_handle);
1186 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
1189 callout_handle->setArgument(
"query6", query);
1195 if (new_lease->reuseable_valid_lft_ == 0) {
1196 new_leases->push_back(new_lease);
1200 callout_handle->setArgument(
"leases6", new_leases);
1205 for (
auto const& iac : ctx.
ias_) {
1206 if (!iac.old_leases_.empty()) {
1207 for (
auto const& old_lease : iac.old_leases_) {
1209 deleted_leases->push_back(old_lease);
1212 bool in_new =
false;
1214 if ((new_lease->addr_ == old_lease->addr_) &&
1216 (new_lease->prefixlen_ == old_lease->prefixlen_))) {
1222 deleted_leases->push_back(old_lease);
1227 callout_handle->setArgument(
"deleted_leases6", deleted_leases);
1230 uint32_t parked_packet_limit = 0;
1234 parked_packet_limit = ppl->intValue();
1237 if (parked_packet_limit) {
1239 getParkingLotPtr(
"leases6_committed");
1240 if (parking_lot && (parking_lot->size() >= parked_packet_limit)) {
1244 .arg(parked_packet_limit)
1245 .arg(query->getLabel());
1247 static_cast<int64_t
>(1));
1259 [
this, callout_handle, query, rsp, callout_handle_state, subnet]()
mutable {
1261 typedef function<void()> CallBack;
1262 boost::shared_ptr<CallBack> call_back =
1264 this, callout_handle, query, rsp, subnet));
1265 callout_handle_state->on_completion_ = [call_back]() {
1286 .arg(query->getLabel());
1297 .arg(query->getLabel());
1317 }
catch (
const std::exception& e) {
1319 .arg(query->getLabel())
1323 .arg(query->getLabel());
1330 query->addPktEvent(
"process_completed");
1336 bool skip_pack =
false;
1351 ScopedEnableOptionsCopy<Pkt6> query_resp_options_copy(query, rsp);
1354 callout_handle->setArgument(
"query6", query);
1357 callout_handle->setArgument(
"response6", rsp);
1360 callout_handle->setArgument(
"subnet6", subnet);
1372 .arg(rsp->getLabel());
1379 .arg(rsp->getLabel());
1388 }
catch (
const std::exception& e) {
1390 .arg(query->getLabel())
1419 ScopedEnableOptionsCopy<Pkt6> response6_options_copy(rsp);
1422 callout_handle->setArgument(
"response6", rsp);
1435 .arg(rsp->getLabel());
1439 callout_handle->getArgument(
"response6", rsp);
1443 .arg(rsp->getLabel())
1444 .arg(rsp->getName())
1445 .arg(
static_cast<int>(rsp->getType()))
1446 .arg(rsp->getLocalAddr().isV6Zero() ?
"*" : rsp->getLocalAddr().toText())
1447 .arg(rsp->getLocalPort())
1448 .arg(rsp->getRemoteAddr())
1449 .arg(rsp->getRemotePort())
1450 .arg(rsp->getIface());
1453 .arg(rsp->getLabel())
1454 .arg(rsp->getName())
1455 .arg(
static_cast<int>(rsp->getType()))
1456 .arg(rsp->toText());
1462 }
catch (
const std::exception& e) {
1464 .arg(rsp->getLabel())
1476 for (
auto const& it : data) {
1480 tmp << hex << setw(2) << setfill('0') << static_cast<uint16_t>(it);
1494 answer->addOption(clientid);
1499 if (!question->relay_info_.empty()) {
1500 answer->copyRelayInfo(question);
1518 co_list.push_back(ctx.
currentHost()->getCfgOption6());
1526 ctx.
subnet_->getPool(resource.getPrefixLength() == 128 ?
1528 resource.getAddress(),
1530 if (pool && !pool->getCfgOption()->empty()) {
1531 co_list.push_back(pool->getCfgOption());
1536 if (!ctx.
subnet_->getCfgOption()->empty()) {
1537 co_list.push_back(ctx.
subnet_->getCfgOption());
1542 ctx.
subnet_->getSharedNetwork(network);
1543 if (network && !network->getCfgOption()->empty()) {
1544 co_list.push_back(network->getCfgOption());
1550 for (
auto const& cclass : classes) {
1553 getClientClassDictionary()->findClass(cclass);
1558 .arg(question->getLabel())
1565 if (ccdef->getCfgOption()->empty()) {
1570 co_list.push_back(ccdef->getCfgOption());
1583 if (co_list.empty()) {
1587 set<uint16_t> requested_opts;
1596 for (uint16_t code : option_oro->getValues()) {
1597 static_cast<void>(requested_opts.insert(code));
1601 set<uint16_t> cancelled_opts;
1605 for (
auto const& copts : co_list) {
1613 BOOST_FOREACH(
auto const& desc, prange) {
1616 uint16_t code = desc.option_->getType();
1617 static_cast<void>(requested_opts.insert(code));
1623 BOOST_FOREACH(
auto const& desc, crange) {
1626 uint16_t code = desc.option_->getType();
1627 static_cast<void>(cancelled_opts.insert(code));
1634 for (uint16_t opt : requested_opts) {
1636 if (cancelled_opts.count(opt) > 0) {
1644 if (!answer->getOption(opt)) {
1646 for (
auto const& copts : co_list) {
1650 answer->addOption(desc.option_);
1663 set<uint32_t> vendor_ids;
1667 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
1669 uint32_t vendor_id = vendor_class->getVendorId();
1670 static_cast<void>(vendor_ids.insert(vendor_id));
1674 for (
auto const& copts : co_list) {
1676 if (!desc.option_) {
1680 boost::dynamic_pointer_cast<OptionVendorClass>(desc.option_);
1681 if (!vendor_class) {
1685 uint32_t vendor_id = vendor_class->getVendorId();
1686 if (vendor_ids.count(vendor_id) > 0) {
1690 answer->addOption(desc.option_);
1691 static_cast<void>(vendor_ids.insert(vendor_id));
1700 set<uint32_t> vendor_ids;
1704 vendor_opts = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1706 uint32_t vendor_id = vendor_opts->getVendorId();
1707 static_cast<void>(vendor_ids.insert(vendor_id));
1711 for (
auto const& copts : co_list) {
1713 if (!desc.option_) {
1717 boost::dynamic_pointer_cast<OptionVendor>(desc.option_);
1722 uint32_t vendor_id = vendor_opts->getVendorId();
1723 if (vendor_ids.count(vendor_id) > 0) {
1729 answer->addOption(vendor_opts);
1730 static_cast<void>(vendor_ids.insert(vendor_id));
1749 if (!ctx.
subnet_ || co_list.empty()) {
1753 set<uint32_t> vendor_ids;
1757 map<uint32_t, OptionVendorPtr> vendor_rsps;
1760 vendor_rsp = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1762 uint32_t vendor_id = vendor_rsp->getVendorId();
1763 vendor_rsps[vendor_id] = vendor_rsp;
1764 static_cast<void>(vendor_ids.insert(vendor_id));
1770 map<uint32_t, OptionVendorPtr> vendor_reqs;
1773 vendor_req = boost::dynamic_pointer_cast<OptionVendor>(opt.second);
1775 uint32_t vendor_id = vendor_req->getVendorId();
1776 vendor_reqs[vendor_id] = vendor_req;
1777 static_cast<void>(vendor_ids.insert(vendor_id));
1785 vendor_class = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
1787 uint32_t vendor_id = vendor_class->getVendorId();
1788 static_cast<void>(vendor_ids.insert(vendor_id));
1794 if (vendor_ids.empty()) {
1798 map<uint32_t, set<uint16_t> > requested_opts;
1812 oro = boost::dynamic_pointer_cast<OptionUint16Array>(oro_generic);
1815 set<uint16_t> oro_req_opts;
1816 for (uint16_t code : oro->getValues()) {
1817 static_cast<void>(oro_req_opts.insert(code));
1823 map<uint32_t, set<uint16_t> > cancelled_opts;
1827 for (uint32_t vendor_id : vendor_ids) {
1828 for (
auto const& copts : co_list) {
1836 BOOST_FOREACH(
auto const& desc, prange) {
1837 if (!desc.option_) {
1841 uint16_t code = desc.option_->getType();
1842 static_cast<void>(requested_opts[vendor_id].insert(code));
1847 BOOST_FOREACH(
auto const& desc, crange) {
1848 if (!desc.option_) {
1852 uint16_t code = desc.option_->getType();
1853 static_cast<void>(cancelled_opts[vendor_id].insert(code));
1862 if (requested_opts[vendor_id].empty()) {
1869 if (vendor_rsps.count(vendor_id) > 0) {
1870 vendor_rsp = vendor_rsps[vendor_id];
1878 for (uint16_t opt : requested_opts[vendor_id]) {
1879 if (cancelled_opts[vendor_id].count(opt) > 0) {
1882 if (!vendor_rsp->getOption(opt)) {
1883 for (
auto const& copts : co_list) {
1886 vendor_rsp->addOption(desc.option_);
1896 if (added && (vendor_rsps.count(vendor_id) == 0)) {
1897 answer->addOption(vendor_rsp);
1905 switch (pkt->getType()) {
1927 .arg(pkt->getLabel())
1928 .arg(
static_cast<int>(pkt->getType()))
1929 .arg(pkt->getIface());
1934 .arg(pkt->getLabel())
1935 .arg(pkt->getName())
1936 .arg(pkt->getRemoteAddr().toText())
1951 if (client_ids.size() != 1) {
1953 << pkt->getName() <<
", but " << client_ids.size()
1960 if (client_ids.size() > 1) {
1962 <<
") client-id options received in " << pkt->getName());
1964 if (!client_ids.empty()) {
1977 if (!server_ids.empty()) {
1979 << server_ids.size() <<
" received in " << pkt->getName());
1984 if (server_ids.size() != 1) {
1986 << server_ids.size() <<
"), exactly 1 expected in message "
1993 if (server_ids.size() > 1) {
1995 <<
") server-id options received in " << pkt->getName());
1997 if (!server_ids.empty()) {
2010 uint16_t len = opt->len() - opt->getHeaderLen();
2023 getCfgSubnets6()->selectSubnet(selector);
2033 shared_ptr<ScopedCalloutHandleState> callout_handle_state(
2034 std::make_shared<ScopedCalloutHandleState>(callout_handle));
2037 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(question);
2040 callout_handle->setArgument(
"query6", question);
2041 callout_handle->setArgument(
"subnet6", subnet);
2046 callout_handle->setArgument(
"subnet6collection",
2048 getCfgSubnets6()->getAll());
2050 auto const tpl(parkingLimitExceeded(
"subnet6_select"));
2051 bool const exceeded(get<0>(tpl));
2053 uint32_t
const limit(get<1>(tpl));
2058 .arg(question->getLabel());
2065 HooksManager::park(
"subnet6_select", question, [
this, question, callout_handle_state]() {
2067 boost::shared_ptr<function<void()>> callback(
2068 boost::make_shared<function<
void()>>([
this, question]()
mutable {
2071 callout_handle_state->on_completion_ = [callback]() {
2093 .arg(question->getLabel());
2106 .arg(question->getLabel());
2114 .arg(question->getLabel());
2120 callout_handle->getArgument(
"subnet6", subnet);
2126 .arg(question->getLabel())
2127 .arg(subnet->getID());
2131 .arg(question->getLabel())
2132 .arg(subnet->toText());
2136 .arg(question->getLabel());
2161 for (
auto const& opt : question->options_) {
2162 switch (opt.second->getType()) {
2165 boost::dynamic_pointer_cast<
2168 answer->addOption(answer_opt);
2174 boost::dynamic_pointer_cast<
2177 answer->addOption(answer_opt);
2202 if (ddns_params->getEnableUpdates() &&
2212 .arg(question->getLabel());
2225 .arg(question->getLabel())
2226 .arg(fqdn->toText());
2244 fqdn_resp->setDomainName(d2_mgr.qualifyName(ctx.
currentHost()->getHostname(),
2245 *ddns_params,
true),
2255 ctx.
hostname_ = fqdn_resp->getDomainName();
2262 .arg(question->getLabel())
2263 .arg(fqdn_resp->toText());
2264 answer->addOption(fqdn_resp);
2279 callout_handle->setArgument(
"query6", question);
2280 callout_handle->setArgument(
"response6", answer);
2281 callout_handle->setArgument(
"subnet6", subnet);
2282 callout_handle->setArgument(
"hostname", ctx.
hostname_);
2285 callout_handle->setArgument(
"ddns-params", ddns_params);
2291 string hook_hostname;
2292 bool hook_fwd_dns_update;
2293 bool hook_rev_dns_update;
2294 callout_handle->getArgument(
"hostname", hook_hostname);
2295 callout_handle->getArgument(
"fwd-update", hook_fwd_dns_update);
2296 callout_handle->getArgument(
"rev-update", hook_rev_dns_update);
2307 fqdn_resp = boost::dynamic_pointer_cast<Option6ClientFqdn>(answer->getOption(
D6O_CLIENT_FQDN));
2310 if (!(hook_fwd_dns_update || hook_rev_dns_update)) {
2337 <<
" encapsulating server's message must not be"
2338 <<
" NULL when creating DNS NameChangeRequest");
2351 bool do_fwd =
false;
2352 bool do_rev =
false;
2362 "client identifier is required when creating a new"
2363 " DNS NameChangeRequest");
2370 opt_fqdn->packDomainName(name_buf);
2371 const std::vector<uint8_t>& buf_vec = name_buf.getVector();
2377 for (
auto const& answer_ia : answer->getOptions(
D6O_IA_NA)) {
2392 bool extended_only =
false;
2395 if (l->addr_ == iaaddr->getAddress()) {
2400 (l->hostname_ == opt_fqdn->getDomainName() &&
2401 l->fqdn_fwd_ == do_fwd && l->fqdn_rev_ == do_rev)) {
2402 extended_only =
true;
2414 if (!(do_fwd || do_rev) || (extended_only)) {
2430 opt_fqdn->getDomainName(),
2431 iaaddr->getAddress().toText(),
2437 .arg(answer->getLabel())
2438 .arg(ncr->toText());
2454 getMACSources().get();
2456 for (
auto const& it : mac_sources) {
2457 hwaddr = pkt->getMAC(it);
2473 BOOST_FOREACH(
auto const& resv, resvs) {
2474 if ((resv.second.getPrefix() == lease->addr_) &&
2475 (resv.second.getPrefixLen() == lease->prefixlen_)) {
2476 return (resv.second.getPDExclude());
2483 Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>(
2486 return (pool->getPrefixExcludeOption());
2494 boost::shared_ptr<Option6IA> ia) {
2500 boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(
D6O_IAADDR));
2503 hint = hint_opt->getAddress();
2508 .arg(query->getLabel())
2510 .arg(hint_opt ? hint.toText() :
"(no hint)");
2513 .arg(query->getLabel())
2515 .arg(hint_opt ? hint.toText() :
"(no hint)");
2535 "Server could not select subnet for"
2558 if (!leases.empty()) {
2559 lease = *leases.begin();
2572 .arg(query->getLabel())
2573 .arg(lease->addr_.toText())
2574 .arg(ia->getIAID());
2575 }
else if (lease->reuseable_valid_lft_ == 0) {
2577 .arg(query->getLabel())
2578 .arg(lease->addr_.toText())
2582 lease->valid_lft_ = lease->reuseable_valid_lft_;
2583 lease->preferred_lft_ = lease->reuseable_preferred_lft_;
2585 .arg(query->getLabel())
2586 .arg(lease->addr_.toText())
2593 "v6-ia-na-lease-reuses"),
2597 .arg(query->getLabel())
2599 .arg(lease->toText());
2602 setTeeTimes(lease->preferred_lft_, subnet, ia_rsp);
2605 lease->preferred_lft_,
2606 lease->valid_lft_));
2607 ia_rsp->addOption(addr);
2620 .arg(query->getLabel())
2621 .arg(ia->getIAID());
2623 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2625 "Sorry, no address could be"
2634 boost::shared_ptr<Option6IA> ia) {
2641 boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(
D6O_IAPREFIX));
2644 hint = hint_opt->getAddress();
2649 .arg(query->getLabel())
2651 .arg(hint_opt ? hint.toText() :
"(no hint)");
2654 .arg(query->getLabel())
2656 .arg(hint_opt ? hint.toText() :
"(no hint)");
2674 "Sorry, no subnet available."));
2694 if (!leases.empty()) {
2698 uint32_t min_preferred_lft = (*leases.begin())->preferred_lft_;
2700 const bool pd_exclude_requested = requestedInORO(query,
D6O_PD_EXCLUDE);
2701 for (
auto const& l : leases) {
2707 .arg(query->getLabel())
2708 .arg(l->addr_.toText())
2709 .arg(
static_cast<int>(l->prefixlen_))
2710 .arg(ia->getIAID());
2711 }
else if (l->reuseable_valid_lft_ == 0) {
2713 .arg(query->getLabel())
2714 .arg(l->addr_.toText())
2715 .arg(
static_cast<int>(l->prefixlen_))
2719 l->valid_lft_ = l->reuseable_valid_lft_;
2720 l->preferred_lft_ = l->reuseable_preferred_lft_;
2722 .arg(query->getLabel())
2723 .arg(l->addr_.toText())
2724 .arg(
static_cast<int>(l->prefixlen_))
2731 "v6-ia-pd-lease-reuses"),
2736 if ((l->preferred_lft_ > 0) && (min_preferred_lft > l->preferred_lft_)) {
2737 min_preferred_lft = l->preferred_lft_;
2740 boost::shared_ptr<Option6IAPrefix>
2742 l->prefixlen_, l->preferred_lft_,
2744 ia_rsp->addOption(addr);
2746 if (pd_exclude_requested) {
2748 if (pd_exclude_option) {
2749 addr->addOption(pd_exclude_option);
2768 .arg(query->getLabel())
2769 .arg(ia->getIAID());
2771 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2773 "Sorry, no prefixes could"
2782 boost::shared_ptr<Option6IA> ia) {
2785 .arg(query->getLabel())
2786 .arg(ia->getIAID());
2805 "Sorry, no known leases for this duid/iaid."));
2817 for (
auto const& it : addrs) {
2821 Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>(it.second);
2848 uint32_t min_preferred_lft = std::numeric_limits<uint32_t>::max();
2851 for (
auto const& l : leases) {
2852 if (l->reuseable_valid_lft_ == 0) {
2854 .arg(query->getLabel())
2855 .arg(l->addr_.toText())
2856 .arg(ia->getIAID());
2858 l->valid_lft_ = l->reuseable_valid_lft_;
2859 l->preferred_lft_ = l->reuseable_preferred_lft_;
2861 .arg(query->getLabel())
2862 .arg(l->addr_.toText())
2869 "v6-ia-na-lease-reuses"),
2874 l->addr_, l->preferred_lft_, l->valid_lft_));
2875 ia_rsp->addOption(iaaddr);
2878 if ((l->preferred_lft_ > 0) && (min_preferred_lft > l->preferred_lft_)) {
2879 min_preferred_lft = l->preferred_lft_;
2884 hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
2894 if (
equalValues(query->getClientId(), l->duid_)) {
2897 ia_rsp->addOption(iaaddr);
2902 hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
2910 .arg(query->getLabel())
2922 for (
auto const& hint : hints) {
2924 hint.getAddress(), 0, 0));
2925 ia_rsp->addOption(iaaddr);
2928 if (!leases.empty()) {
2934 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2936 "Sorry, no addresses could be"
2937 " assigned at this time."));
2946 boost::shared_ptr<Option6IA> ia) {
2949 .arg(query->getLabel())
2950 .arg(ia->getIAID());
2967 "Sorry, no known PD leases"
2968 " for this duid/iaid."));
2988 " client sending Rebind to extend lifetime of the"
2989 " prefix (DUID=" << duid->toText() <<
", IAID="
2990 << ia->getIAID() <<
")");
3002 for (
auto const& it : addrs) {
3036 const bool pd_exclude_requested = requestedInORO(query,
D6O_PD_EXCLUDE);
3040 uint32_t min_preferred_lft = std::numeric_limits<uint32_t>::max();
3042 for (
auto const& l : leases) {
3043 if (l->reuseable_valid_lft_ == 0) {
3045 .arg(query->getLabel())
3046 .arg(l->addr_.toText())
3047 .arg(
static_cast<int>(l->prefixlen_))
3048 .arg(ia->getIAID());
3050 l->valid_lft_ = l->reuseable_valid_lft_;
3051 l->preferred_lft_ = l->reuseable_preferred_lft_;
3053 .arg(query->getLabel())
3054 .arg(l->addr_.toText())
3055 .arg(
static_cast<int>(l->prefixlen_))
3062 "v6-ia-pd-lease-reuses"),
3067 l->addr_, l->prefixlen_,
3068 l->preferred_lft_, l->valid_lft_));
3069 ia_rsp->addOption(prf);
3071 if (pd_exclude_requested) {
3073 if (pd_exclude_option) {
3074 prf->addOption(pd_exclude_option);
3079 if ((l->preferred_lft_ > 0) && (l->preferred_lft_ < min_preferred_lft)) {
3080 min_preferred_lft = l->preferred_lft_;
3085 hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
3095 if (
equalValues(query->getClientId(), l->duid_)) {
3097 l->prefixlen_, 0, 0));
3098 ia_rsp->addOption(prefix);
3103 hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
3108 for (
auto const& prefix : hints) {
3113 if (!prefix.getAddress().isV6Zero()) {
3115 prefix.getAddress(),
3116 prefix.getPrefixLength(),
3118 ia_rsp->addOption(prefix_opt);
3122 if (!leases.empty()) {
3129 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
3131 "Sorry, no prefixes could be"
3132 " assigned at this time."));
3153 for (
auto const& opt : query->options_) {
3154 switch (opt.second->getType()) {
3157 boost::dynamic_pointer_cast<
3160 reply->addOption(answer_opt);
3167 boost::dynamic_pointer_cast<
3170 reply->addOption(answer_opt);
3205 for (
auto const& opt : release->options_) {
3207 switch (opt.second->getType()) {
3210 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3213 reply->addOption(answer_opt);
3219 boost::dynamic_pointer_cast<Option6IA>(opt.second),
3222 reply->addOption(answer_opt);
3239 reply->addOption(createStatusCode(*release, general_status,
3240 "Summary status for all processed IA_NAs"));
3245 int& general_status, boost::shared_ptr<Option6IA> ia,
3249 .arg(query->getLabel())
3250 .arg(ia->getIAID());
3266 if (!release_addr) {
3268 "You did not include an address in your RELEASE"));
3274 release_addr->getAddress());
3281 "Sorry, no known leases for this duid/iaid, can't release."));
3287 if (!lease->duid_) {
3293 .arg(query->getLabel())
3294 .arg(release_addr->getAddress().toText());
3298 "Database consistency check failed when trying to RELEASE"));
3302 if (*duid != *(lease->duid_)) {
3306 .arg(query->getLabel())
3307 .arg(release_addr->getAddress().toText())
3308 .arg(lease->duid_->toText());
3312 "This address does not belong to you, you can't release it"));
3316 if (ia->getIAID() != lease->iaid_) {
3319 .arg(query->getLabel())
3320 .arg(release_addr->getAddress().toText())
3322 .arg(ia->getIAID());
3324 "This is your address, but you used wrong IAID"));
3344 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
3347 callout_handle->deleteAllArguments();
3350 callout_handle->setArgument(
"query6", query);
3353 callout_handle->setArgument(
"lease6", lease);
3365 .arg(query->getLabel());
3370 bool success =
false;
3371 bool expired =
false;
3372 auto expiration_cfg =
CfgMgr::instance().getCurrentCfg()->getCfgExpiration();
3378 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3379 expiration_cfg->getHoldReclaimedTime() &&
3382 lease->valid_lft_ = 0;
3383 lease->preferred_lft_ = 0;
3403 "Server failed to release a lease"));
3406 .arg(query->getLabel())
3407 .arg(lease->addr_.toText())
3416 .arg(query->getLabel())
3417 .arg(lease->addr_.toText())
3420 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_Success,
3421 "Lease released. Thank you, please come again."));
3425 .arg(query->getLabel())
3426 .arg(lease->addr_.toText())
3430 .arg(query->getLabel())
3431 .arg(lease->addr_.toText())
3443 static_cast<int64_t
>(-1));
3445 auto const& subnet =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
3447 auto const& pool = subnet->getPool(
Lease::TYPE_NA, lease->addr_,
false);
3452 static_cast<int64_t
>(-1));
3462 int& general_status, boost::shared_ptr<Option6IA> ia,
3477 boost::shared_ptr<Option6IAPrefix> release_prefix =
3478 boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(
D6O_IAPREFIX));
3479 if (!release_prefix) {
3481 "You did not include a prefix in your RELEASE"));
3487 release_prefix->getAddress());
3494 "Sorry, no known leases for this duid/iaid, can't release."));
3500 if (!lease->duid_) {
3505 .arg(query->getLabel())
3506 .arg(release_prefix->getAddress().toText())
3507 .arg(
static_cast<int>(release_prefix->getLength()));
3511 "Database consistency check failed when trying to RELEASE"));
3515 if (*duid != *(lease->duid_)) {
3518 .arg(query->getLabel())
3519 .arg(release_prefix->getAddress().toText())
3520 .arg(
static_cast<int>(release_prefix->getLength()))
3521 .arg(lease->duid_->toText());
3525 "This address does not belong to you, you can't release it"));
3529 if (ia->getIAID() != lease->iaid_) {
3532 .arg(query->getLabel())
3533 .arg(release_prefix->getAddress().toText())
3534 .arg(
static_cast<int>(release_prefix->getLength()))
3536 .arg(ia->getIAID());
3538 "This is your address, but you used wrong IAID"));
3558 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
3561 callout_handle->setArgument(
"query6", query);
3564 callout_handle->setArgument(
"lease6", lease);
3576 .arg(query->getLabel());
3581 bool success =
false;
3582 bool expired =
false;
3583 auto expiration_cfg =
CfgMgr::instance().getCurrentCfg()->getCfgExpiration();
3589 if (expiration_cfg->getFlushReclaimedTimerWaitTime() &&
3590 expiration_cfg->getHoldReclaimedTime() &&
3593 lease->valid_lft_ = 0;
3594 lease->preferred_lft_ = 0;
3614 "Server failed to release a lease"));
3617 .arg(query->getLabel())
3618 .arg(lease->addr_.toText())
3619 .arg(
static_cast<int>(lease->prefixlen_))
3627 .arg(query->getLabel())
3628 .arg(lease->addr_.toText())
3629 .arg(
static_cast<int>(lease->prefixlen_))
3632 ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
STATUS_Success,
3633 "Lease released. Thank you, please come again."));
3637 .arg(query->getLabel())
3638 .arg(lease->addr_.toText())
3639 .arg(
static_cast<int>(lease->prefixlen_))
3643 .arg(query->getLabel())
3644 .arg(lease->addr_.toText())
3645 .arg(
static_cast<int>(lease->prefixlen_))
3652 static_cast<int64_t
>(-1));
3654 auto const& subnet =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
3656 auto const& pool = subnet->getPool(
Lease::TYPE_PD, lease->addr_,
false);
3661 static_cast<int64_t
>(-1));
3678 if (opt_rapid_commit) {
3681 .arg(solicit->getLabel());
3686 response->addOption(opt_rapid_commit);
3718 .arg(solicit->getLabel())
3719 .arg(solicit->getName())
3720 .arg(solicit->getClasses().toText());
3729 updateReservedFqdn(ctx, response);
3761 .arg(request->getLabel())
3762 .arg(request->getName())
3763 .arg(request->getClasses().toText());
3772 updateReservedFqdn(ctx, reply);
3773 generateFqdn(reply, ctx);
3800 .arg(renew->getLabel())
3801 .arg(renew->getName())
3802 .arg(renew->getClasses().toText());
3811 updateReservedFqdn(ctx, reply);
3812 generateFqdn(reply, ctx);
3839 .arg(rebind->getLabel())
3840 .arg(rebind->getName())
3841 .arg(rebind->getClasses().toText());
3850 updateReservedFqdn(ctx, reply);
3851 generateFqdn(reply, ctx);
3865 .arg(confirm->getLabel())
3866 .arg(confirm->getName())
3867 .arg(confirm->getClasses().toText());
3888 bool verified =
false;
3897 for (
auto const& ia : ias) {
3899 for (
auto const& opt : opts) {
3911 if (subnet && !subnet->inRange(iaaddr->getAddress())) {
3912 std::ostringstream status_msg;
3913 status_msg <<
"Address " << iaaddr->
getAddress()
3914 <<
" is not on link.";
3915 reply->addOption(createStatusCode(*confirm,
3923 " to the Option6IAAddrPtr. This is programming"
3924 " error and should be reported");
3941 "All addresses are on-link"));
3944 "No subnet selected"));
3958 .arg(release->getLabel())
3959 .arg(release->getName())
3960 .arg(release->getClasses().toText());
3989 .arg(decline->getLabel())
3990 .arg(decline->getName())
3991 .arg(decline->getClasses().toText());
4030 for (
auto const& opt : decline->options_) {
4031 switch (opt.second->getType()) {
4034 boost::dynamic_pointer_cast<Option6IA>(opt.second),
4039 reply->addOption(answer_opt);
4060 int& general_status, boost::shared_ptr<Option6IA> ia,
4064 .arg(decline->getLabel())
4065 .arg(ia->getIAID());
4080 int total_addrs = 0;
4081 for (
auto const& opt : opts) {
4090 if (!decline_addr) {
4097 decline_addr->getAddress());
4102 .arg(decline->getLabel()).arg(decline_addr->getAddress().toText());
4110 "Server does not know about such an address."));
4118 if (!lease->duid_) {
4124 .arg(decline->getLabel())
4125 .arg(decline_addr->getAddress().toText());
4128 "Database consistency check failed when attempting Decline."));
4134 if (*duid != *(lease->duid_)) {
4138 .arg(decline->getLabel())
4139 .arg(decline_addr->getAddress().toText())
4140 .arg(lease->duid_->toText());
4143 "This address does not belong to you, you can't decline it"));
4149 if (ia->getIAID() != lease->iaid_) {
4152 .arg(decline->getLabel())
4153 .arg(lease->addr_.toText())
4157 "This is your address, but you used wrong IAID"));
4169 new_leases.push_back(lease);
4173 if (total_addrs == 0) {
4175 "No addresses sent in IA_NA"));
4188 container->addOption(status);
4193 boost::shared_ptr<Option6IA> ia_rsp) {
4214 ScopedEnableOptionsCopy<Pkt6> query6_options_copy(decline);
4217 callout_handle->setArgument(
"query6", decline);
4220 callout_handle->setArgument(
"lease6", lease);
4231 .arg(decline->getLabel())
4232 .arg(decline->getIface())
4233 .arg(lease->addr_.toText());
4241 .arg(decline->getLabel())
4242 .arg(decline->getIface())
4243 .arg(lease->addr_.toText());
4248 Lease6Ptr old_values = boost::make_shared<Lease6>(*lease);
4262 .arg(decline->getLabel())
4263 .arg(lease->addr_.toText())
4276 static_cast<int64_t
>(1));
4278 auto const& subnet =
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
4280 auto const& pool = subnet->getPool(
Lease::TYPE_NA, lease->addr_,
false);
4285 static_cast<int64_t
>(1));
4293 .arg(lease->addr_.toText()).arg(lease->valid_lft_);
4295 ia_rsp->addOption(createStatusCode(*decline, *ia_rsp,
STATUS_Success,
4296 "Lease declined. Hopefully the next one will be better."));
4309 .arg(inf_request->getLabel())
4310 .arg(inf_request->getName())
4311 .arg(inf_request->getClasses().toText());
4360void Dhcpv6Srv::classifyByVendor(
const Pkt6Ptr& pkt) {
4363 vclass = boost::dynamic_pointer_cast<OptionVendorClass>(opt.second);
4364 if (!vclass || vclass->getTuplesNum() == 0) {
4382 pkt->addClass(
"ALL");
4385 classifyByVendor(pkt);
4396 for (
auto const& it : *defs_ptr) {
4404 if (it->getRequired()) {
4408 if (it->getDependOnKnown() != depend_on_known) {
4411 it->test(pkt, expr_ptr);
4420 for (
auto const& def : *defs_ptr) {
4424 if (def->getMatchExpr()) {
4425 pkt->classes_.erase(def->getName());
4435 for (
auto const& cclass : classes) {
4436 pkt->addClass(cclass);
4446 ctx.
subnet_->getSharedNetwork(shared_network);
4447 if (shared_network) {
4449 if (host && (host->getIPv6SubnetID() != SUBNET_ID_GLOBAL)) {
4465 subnet->getSharedNetwork(network);
4467 const ClientClasses& to_add = network->getRequiredClasses();
4468 for (
auto const& cclass : to_add) {
4475 for (
auto const& cclass : to_add) {
4482 ctx.
subnet_->getPool(resource.getPrefixLength() == 128 ?
4484 resource.getAddress(),
4487 const ClientClasses& pool_to_add = pool->getRequiredClasses();
4488 for (
auto const& cclass : pool_to_add) {
4501 for (
auto const& cclass : classes) {
4520 .arg(pkt->getLabel())
4522 .arg(status ?
"true" :
"false");
4525 pkt->addClass(cclass);
4529 .arg(pkt->getLabel())
4541 " a message must not be NULL when updating reserved FQDN");
4552 std::string name = fqdn->getDomainName();
4564 if (new_name != name) {
4569 answer->addOption(fqdn);
4575Dhcpv6Srv::generateFqdn(
const Pkt6Ptr& answer,
4579 " a message must not be NULL when generating FQDN");
4590 if (!fqdn || !fqdn->getDomainName().empty()) {
4604 if (!iaaddr || iaaddr->getValid() == 0) {
4610 std::string generated_name =
4614 .arg(answer->getLabel())
4615 .arg(generated_name);
4625 for (
auto const& l : ctx.new_leases_) {
4632 lease->hostname_ = generated_name;
4633 lease->reuseable_valid_lft_ = 0;
4638 " for address " << addr <<
", so as it is impossible"
4639 " to update FQDN data. This is a programmatic error"
4640 " as the given address is now being handed to the"
4648 answer->addOption(fqdn);
4652 .arg(answer->getLabel())
4661 if (d2_mgr.ddnsEnabled()) {
4666 this, ph::_1, ph::_2));
4673 if (d2_mgr.ddnsEnabled()) {
4676 d2_mgr.stopSender();
4685 arg(result).arg((ncr ? ncr->toText() :
" NULL "));
4694 std::stringstream tmp;
4698 tmp <<
" (" << EXTENDED_VERSION <<
")" << endl;
4699 tmp <<
"premium: " << PREMIUM_EXTENDED_VERSION << endl;
4700 tmp <<
"linked with:" << endl;
4703 tmp <<
"backends:" << endl;
4720 if (query->relay_info_.empty()) {
4731 for (
int i = query->relay_info_.size(); i > 0 ; --i) {
4733 if (rsoo_container) {
4738 for (
auto const& opt : rsoo) {
4742 if (cfg_rsoo->enabled(opt.second->getType()) &&
4743 !rsp->getOption(opt.second->getType())) {
4744 rsp->addOption(opt.second);
4753 if (query->relay_info_.empty()) {
4761 return (query->getRemotePort());
4767void Dhcpv6Srv::processStatsReceived(
const Pkt6Ptr& query) {
4771 string stat_name =
"pkt6-unknown-received";
4772 switch (query->getType()) {
4774 stat_name =
"pkt6-solicit-received";
4778 stat_name =
"pkt6-advertise-received";
4781 stat_name =
"pkt6-request-received";
4784 stat_name =
"pkt6-confirm-received";
4787 stat_name =
"pkt6-renew-received";
4790 stat_name =
"pkt6-rebind-received";
4794 stat_name =
"pkt6-reply-received";
4797 stat_name =
"pkt6-release-received";
4800 stat_name =
"pkt6-decline-received";
4803 stat_name =
"pkt6-reconfigure-received";
4806 stat_name =
"pkt6-infrequest-received";
4809 stat_name =
"pkt6-dhcpv4-query-received";
4813 stat_name =
"pkt6-dhcpv4-response-received";
4828 switch (response->getType()) {
4830 stat_name =
"pkt6-advertise-sent";
4833 stat_name =
"pkt6-reply-sent";
4836 stat_name =
"pkt6-dhcpv4-response-sent";
4847 return (
Hooks.hook_index_buffer6_send_);
4851Dhcpv6Srv::requestedInORO(
const Pkt6Ptr& query,
const uint16_t code)
const {
4853 boost::dynamic_pointer_cast<OptionUint16Array>(query->getOption(
D6O_ORO));
4856 const std::vector<uint16_t>& codes = oro->getValues();
4857 return (std::find(codes.begin(), codes.end(), code) != codes.end());
4863tuple<bool, uint32_t>
4864Dhcpv6Srv::parkingLimitExceeded(
string const& hook_label) {
4866 uint32_t parked_packet_limit(0);
4870 parked_packet_limit = ppl->intValue();
4873 if (parked_packet_limit) {
4877 if (parking_lot && parked_packet_limit <= parking_lot->size()) {
4878 return make_tuple(
true, parked_packet_limit);
4881 return make_tuple(
false, parked_packet_limit);
4894 uint32_t t2_time = 0;
4897 if (!subnet->getT2().unspecified()) {
4898 t2_time = subnet->getT2();
4899 }
else if (subnet->getCalculateTeeTimes()) {
4901 t2_time =
static_cast<uint32_t
>(round(subnet->getT2Percent() * preferred_lft));
4905 resp->setT2(t2_time);
4908 uint32_t t1_time = 0;
4911 if (!subnet->getT1().unspecified()) {
4912 t1_time = subnet->getT1();
4913 }
else if (subnet->getCalculateTeeTimes()) {
4915 t1_time =
static_cast<uint32_t
>(round(subnet->getT1Percent() * preferred_lft));
4919 if (t1_time < t2_time) {
4920 resp->setT1(t1_time);
4932 if ((!ctx.
subnet_) || (!orig_subnet) || (orig_subnet->getID() == ctx.
subnet_->getID())) {
4940 orig_subnet->getSharedNetwork(network);
4942 .arg(question->getLabel())
4943 .arg(orig_subnet->toText())
4945 .arg(network ? network->getName() :
"<no network?>");
4951 std::string prev_hostname = ctx.
hostname_;
4972 l->reuseable_valid_lft_ = 0;
4979 static std::list<std::list<std::string>>
const list({
4980 {
"config-control",
"config-databases",
"[]"},
4981 {
"hooks-libraries",
"[]",
"parameters",
"*"},
4983 {
"hosts-databases",
"[]"},
This is a base class for exceptions thrown from the DNS library module.
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic)
std::string toText() const
Convert the address to a string.
static const IOAddress & IPV6_ZERO_ADDRESS()
Returns an IPv6 zero address.
static IOServiceMgr & instance()
Access the IOServiceMgr singleton instance.
The IOService class is a wrapper for the ASIO io_service class.
static HttpCommandMgr & instance()
HttpCommandMgr is a singleton class.
static std::string getVersion()
Get version string.
DHCPv4 and DHCPv6 allocation engine.
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
static CfgMgr & instance()
returns a single instance of Configuration Manager
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.
Client race avoidance RAII handler.
D2ClientMgr isolates Kea from the details of being a D2 client.
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
static Dhcp6to4Ipc & instance()
Returns pointer to the sole instance of Dhcp6to4Ipc.
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.
Pkt6Ptr processPacket(Pkt6Ptr query)
Process a single incoming DHCPv6 packet.
Pkt6Ptr processLocalizedQuery6(AllocEngine::ClientContext6 &ctx)
Process a localized incoming DHCPv6 query.
void processPacketAndSendResponseNoThrow(Pkt6Ptr query)
Process a single incoming DHCPv6 packet and sends the response.
OptionPtr extendIA_PD(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Extends lifetime of the prefix.
void sendResponseNoThrow(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr query, Pkt6Ptr &rsp, Subnet6Ptr &subnet)
Process an unparked DHCPv6 packet and sends the response.
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.
void processLocalizedQuery6AndSendResponse(Pkt6Ptr query, AllocEngine::ClientContext6 &ctx)
Process a localized incoming DHCPv6 query.
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.
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.
void runOne()
Main server processing step.
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 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.
void processPacketAndSendResponse(Pkt6Ptr query)
Process a single incoming DHCPv6 packet and sends the response.
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 initContext0(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx)
Initialize client context (first part).
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.
void initContext(AllocEngine::ClientContext6 &ctx, bool &drop)
Initializes client context for specified packet.
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.
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 processPacketPktSend(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr &query, Pkt6Ptr &rsp, Subnet6Ptr &subnet)
Executes pkt6_send callout.
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.
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.
Pkt6Ptr processDhcp6Query(Pkt6Ptr query)
Process a single incoming DHCPv6 query.
void processDhcp6QueryAndSendResponse(Pkt6Ptr query)
Process a single incoming DHCPv6 query.
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....
OptionPtr getPDExclude(const AllocEngine::ClientContext6 &ctx, const Lease6Ptr &lease)
Return the PD exclude option to include.
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.
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.
static TrackingLeaseMgr & instance()
Return current lease manager.
static void destroy()
Destroy lease manager.
static std::string getDBVersion()
Class method to return extended version info This class method must be redeclared and redefined in de...
static std::string getDBVersion()
Local version of getDBVersion() class method.
Controls the DHCP service enabling status.