Kea  1.5.0
dhcp6_srv.cc
Go to the documentation of this file.
1 // Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 #include <kea_version.h>
9 
10 #include <asiolink/io_address.h>
11 #include <dhcp_ddns/ncr_msg.h>
12 #include <dhcp/dhcp6.h>
14 #include <dhcp/duid.h>
15 #include <dhcp/duid_factory.h>
16 #include <dhcp/iface_mgr.h>
17 #include <dhcp/libdhcp++.h>
18 #include <dhcp/option6_addrlst.h>
20 #include <dhcp/option6_ia.h>
21 #include <dhcp/option6_iaaddr.h>
22 #include <dhcp/option6_iaprefix.h>
24 #include <dhcp/option6_pdexclude.h>
25 #include <dhcp/option_custom.h>
26 #include <dhcp/option_vendor.h>
28 #include <dhcp/option_int_array.h>
29 #include <dhcp/pkt6.h>
30 #include <dhcp6/dhcp6to4_ipc.h>
31 #include <dhcp6/dhcp6_log.h>
32 #include <dhcp6/dhcp6_srv.h>
34 #include <dhcpsrv/cfgmgr.h>
35 #include <dhcpsrv/lease_mgr.h>
37 #include <dhcpsrv/ncr_generator.h>
38 #include <dhcpsrv/subnet.h>
40 #include <dhcpsrv/utils.h>
41 #include <eval/evaluate.h>
42 #include <eval/eval_messages.h>
43 #include <exceptions/exceptions.h>
44 #include <hooks/callout_handle.h>
45 #include <hooks/hooks_log.h>
46 #include <hooks/hooks_manager.h>
47 #include <stats/stats_mgr.h>
48 
49 #include <util/encode/hex.h>
50 #include <util/io_utilities.h>
51 #include <util/pointer_util.h>
52 #include <util/range_utilities.h>
53 #include <log/logger.h>
54 #include <cryptolink/cryptolink.h>
55 #include <cfgrpt/config_report.h>
56 
57 #ifdef HAVE_MYSQL
59 #endif
60 #ifdef HAVE_PGSQL
62 #endif
63 #ifdef HAVE_CQL
64 #include <dhcpsrv/cql_lease_mgr.h>
65 #endif
67 
68 #include <boost/bind.hpp>
69 #include <boost/foreach.hpp>
70 #include <boost/tokenizer.hpp>
71 #include <boost/algorithm/string/erase.hpp>
72 #include <boost/algorithm/string/join.hpp>
73 #include <boost/algorithm/string/split.hpp>
74 
75 #include <algorithm>
76 #include <stdlib.h>
77 #include <time.h>
78 #include <iomanip>
79 #include <fstream>
80 #include <sstream>
81 
82 using namespace isc;
83 using namespace isc::asiolink;
84 using namespace isc::cryptolink;
85 using namespace isc::dhcp;
86 using namespace isc::dhcp_ddns;
87 using namespace isc::hooks;
88 using namespace isc::log;
89 using namespace isc::stats;
90 using namespace isc::util;
91 using namespace std;
92 
93 namespace {
94 
96 struct Dhcp6Hooks {
97  int hook_index_buffer6_receive_;
98  int hook_index_pkt6_receive_;
99  int hook_index_subnet6_select_;
100  int hook_index_leases6_committed_;
101  int hook_index_lease6_release_;
102  int hook_index_pkt6_send_;
103  int hook_index_buffer6_send_;
104  int hook_index_lease6_decline_;
105  int hook_index_host6_identifier_;
106 
108  Dhcp6Hooks() {
109  hook_index_buffer6_receive_ = HooksManager::registerHook("buffer6_receive");
110  hook_index_pkt6_receive_ = HooksManager::registerHook("pkt6_receive");
111  hook_index_subnet6_select_ = HooksManager::registerHook("subnet6_select");
112  hook_index_leases6_committed_ = HooksManager::registerHook("leases6_committed");
113  hook_index_lease6_release_ = HooksManager::registerHook("lease6_release");
114  hook_index_pkt6_send_ = HooksManager::registerHook("pkt6_send");
115  hook_index_buffer6_send_ = HooksManager::registerHook("buffer6_send");
116  hook_index_lease6_decline_ = HooksManager::registerHook("lease6_decline");
117  hook_index_host6_identifier_ = HooksManager::registerHook("host6_identifier");
118  }
119 };
120 
121 // Declare a Hooks object. As this is outside any function or method, it
122 // will be instantiated (and the constructor run) when the module is loaded.
123 // As a result, the hook indexes will be defined before any method in this
124 // module is called.
125 Dhcp6Hooks Hooks;
126 
138 OptionPtr
139 createStatusCode(const Pkt6& pkt, const uint16_t status_code,
140  const std::string& status_message) {
141  Option6StatusCodePtr option_status(new Option6StatusCode(status_code,
142  status_message));
143  LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_ADD_GLOBAL_STATUS_CODE)
144  .arg(pkt.getLabel())
145  .arg(option_status->dataToText());
146  return (option_status);
147 }
148 
163 OptionPtr
164 createStatusCode(const Pkt6& pkt, const Option6IA& ia, const uint16_t status_code,
165  const std::string& status_message) {
166  Option6StatusCodePtr option_status(new Option6StatusCode(status_code,
167  status_message));
168  LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_ADD_STATUS_CODE_FOR_IA)
169  .arg(pkt.getLabel())
170  .arg(ia.getIAID())
171  .arg(option_status->dataToText());
172  return (option_status);
173 }
174 
175 }; // anonymous namespace
176 
177 namespace isc {
178 namespace dhcp {
179 
180 const std::string Dhcpv6Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
181 
182 Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
183  : io_service_(new IOService()), port_(port), serverid_(), shutdown_(true),
184  alloc_engine_(), name_change_reqs_(),
185  network_state_(new NetworkState(NetworkState::DHCPv6))
186 {
187 
188  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
189 
190  // Initialize objects required for DHCP server operation.
191  try {
192  // Port 0 is used for testing purposes where in most cases we don't
193  // rely on the physical interfaces. Therefore, it should be possible
194  // to create an object even when there are no usable interfaces.
195  if ((port > 0) && (IfaceMgr::instance().countIfaces() == 0)) {
196  LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
197  return;
198  }
199 
200  // Create a DUID instance but do not store it into a file.
201  DUIDFactory duid_factory;
202  DuidPtr duid = duid_factory.get();
203  serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid()));
204 
205  // Instantiate allocation engine. The number of allocation attempts equal
206  // to zero indicates that the allocation engine will use the number of
207  // attempts depending on the pool size.
209 
211 
212  } catch (const std::exception &e) {
213  LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what());
214  return;
215  }
216 
217  // All done, so can proceed
218  shutdown_ = false;
219 }
220 
222  discardPackets();
223  try {
224  stopD2();
225  } catch(const std::exception& ex) {
226  // Highly unlikely, but lets Report it but go on
227  LOG_ERROR(dhcp6_logger, DHCP6_SRV_D2STOP_ERROR).arg(ex.what());
228  }
229 
230  try {
232  } catch(const std::exception& ex) {
233  // Highly unlikely, but lets Report it but go on
234  // LOG_ERROR(dhcp6_logger, DHCP6_SRV_DHCP4O6_ERROR).arg(ex.what());
235  }
236 
238 
240 
241  // Explicitly unload hooks
242  HooksManager::getHooksManager().unloadLibraries();
243 }
244 
246  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_SHUTDOWN_REQUEST);
247  shutdown_ = true;
248 }
249 
251  return (IfaceMgr::instance().receive6(timeout));
252 }
253 
254 void Dhcpv6Srv::sendPacket(const Pkt6Ptr& packet) {
255  IfaceMgr::instance().send(packet);
256 }
257 
258 bool
264  OptionPtr server_id = pkt->getOption(D6O_SERVERID);
265  if (server_id){
266  // Let us test received ServerID if it is same as ServerID
267  // which is being used by server
268  if (getServerID()->getData() != server_id->getData()){
270  DHCP6_PACKET_DROP_SERVERID_MISMATCH)
271  .arg(pkt->getLabel())
272  .arg(duidToString(server_id))
273  .arg(duidToString(getServerID()));
274  return (false);
275  }
276  }
277  // return True if: no serverid received or ServerIDs matching
278  return (true);
279 }
280 
281 bool
282 Dhcpv6Srv::testUnicast(const Pkt6Ptr& pkt) const {
283  switch (pkt->getType()) {
284  case DHCPV6_SOLICIT:
285  case DHCPV6_CONFIRM:
286  case DHCPV6_REBIND:
288  if (pkt->relay_info_.empty() && !pkt->getLocalAddr().isV6Multicast()) {
289  LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_DETAIL, DHCP6_PACKET_DROP_UNICAST)
290  .arg(pkt->getLabel())
291  .arg(pkt->getName());
292  return (false);
293  }
294  break;
295  default:
296  // do nothing
297  ;
298  }
299  return (true);
300 }
301 
302 void
305  bool& drop) {
306  ctx.subnet_ = selectSubnet(pkt, drop);
307  ctx.duid_ = pkt->getClientId(),
308  ctx.fwd_dns_update_ = false;
309  ctx.rev_dns_update_ = false;
310  ctx.hostname_ = "";
311  ctx.query_ = pkt;
313  ctx.hwaddr_ = getMAC(pkt);
314 
315  if (drop) {
316  // Caller will immediately drop the packet so simply return now.
317  return;
318  }
319 
320  // Collect host identifiers if host reservations enabled. The identifiers
321  // are stored in order of preference. The server will use them in that
322  // order to search for host reservations.
323  if (ctx.subnet_) {
324  const ConstCfgHostOperationsPtr cfg =
325  CfgMgr::instance().getCurrentCfg()->getCfgHostOperations6();
326  BOOST_FOREACH(const Host::IdentifierType& id_type,
327  cfg->getIdentifierTypes()) {
328  switch (id_type) {
329  case Host::IDENT_DUID:
330  if (ctx.duid_) {
331  ctx.addHostIdentifier(id_type, ctx.duid_->getDuid());
332  }
333  break;
334 
335  case Host::IDENT_HWADDR:
336  if (ctx.hwaddr_) {
337  ctx.addHostIdentifier(id_type, ctx.hwaddr_->hwaddr_);
338  }
339  break;
340  case Host::IDENT_FLEX:
341  // At this point the information in the packet has been unpacked into
342  // the various packet fields and option objects has been created.
343  // Execute callouts registered for packet6_receive.
344  if (HooksManager::calloutsPresent(Hooks.hook_index_host6_identifier_)) {
345  CalloutHandlePtr callout_handle = getCalloutHandle(pkt);
346 
348  std::vector<uint8_t> id;
349 
350  // Use the RAII wrapper to make sure that the callout handle state is
351  // reset when this object goes out of scope. All hook points must do
352  // it to prevent possible circular dependency between the callout
353  // handle and its arguments.
354  ScopedCalloutHandleState callout_handle_state(callout_handle);
355 
356  // Pass incoming packet as argument
357  callout_handle->setArgument("query6", pkt);
358  callout_handle->setArgument("id_type", type);
359  callout_handle->setArgument("id_value", id);
360 
361  // Call callouts
362  HooksManager::callCallouts(Hooks.hook_index_host6_identifier_,
363  *callout_handle);
364 
365  callout_handle->getArgument("id_type", type);
366  callout_handle->getArgument("id_value", id);
367 
368  if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_CONTINUE) &&
369  !id.empty()) {
370 
372  .arg(Host::getIdentifierAsText(type, &id[0], id.size()));
373 
374  ctx.addHostIdentifier(type, id);
375  }
376  }
377  break;
378  default:
379  ;
380  }
381  }
382 
383  // Find host reservations using specified identifiers.
384  alloc_engine_->findReservation(ctx);
385  }
386 
387  // Set KNOWN builtin class if something was found, UNKNOWN if not.
388  if (!ctx.hosts_.empty()) {
389  pkt->addClass("KNOWN");
390  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_ASSIGNED)
391  .arg(pkt->getLabel())
392  .arg("KNOWN");
393  } else {
394  pkt->addClass("UNKNOWN");
395  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_ASSIGNED)
396  .arg(pkt->getLabel())
397  .arg("UNKNOWN");
398  }
399 
400  // Perform second pass of classification.
401  evaluateClasses(pkt, true);
402 }
403 
405  while (!shutdown_) {
406  try {
407  run_one();
408  getIOService()->poll();
409  } catch (const std::exception& e) {
410  // General catch-all standard exceptions that are not caught by more
411  // specific catches.
412  LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_STD_EXCEPTION)
413  .arg(e.what());
414  } catch (...) {
415  // General catch-all non-standard exception that are not caught
416  // by more specific catches.
417  LOG_ERROR(packet6_logger, DHCP6_PACKET_PROCESS_EXCEPTION);
418  }
419  }
420 
421  return (true);
422 }
423 
425  // client's message and server's response
426  Pkt6Ptr query;
427  Pkt6Ptr rsp;
428 
429  try {
430  // Set select() timeout to 1s. This value should not be modified
431  // because it is important that the select() returns control
432  // frequently so as the IOService can be polled for ready handlers.
433  uint32_t timeout = 1;
434  query = receivePacket(timeout);
435 
436  // Log if packet has arrived. We can't log the detailed information
437  // about the DHCP message because it hasn't been unpacked/parsed
438  // yet, and it can't be parsed at this point because hooks will
439  // have to process it first. The only information available at this
440  // point are: the interface, source address and destination addresses
441  // and ports.
442  if (query) {
443  LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_BUFFER_RECEIVED)
444  .arg(query->getRemoteAddr().toText())
445  .arg(query->getRemotePort())
446  .arg(query->getLocalAddr().toText())
447  .arg(query->getLocalPort())
448  .arg(query->getIface());
449 
450  // Log reception of the packet. We need to increase it early, as
451  // any failures in unpacking will cause the packet to be dropped.
452  // we will increase type specific packets further down the road.
453  // See processStatsReceived().
454  StatsMgr::instance().addValue("pkt6-received", static_cast<int64_t>(1));
455 
456  }
457  // We used to log that the wait was interrupted, but this is no longer
458  // the case. Our wait time is 1s now, so the lack of query packet more
459  // likely means that nothing new appeared within a second, rather than
460  // we were interrupted. And we don't want to print a message every
461  // second.
462 
463 
464  } catch (const SignalInterruptOnSelect&) {
465  // Packet reception interrupted because a signal has been received.
466  // This is not an error because we might have received a SIGTERM,
467  // SIGINT or SIGHUP which are handled by the server. For signals
468  // that are not handled by the server we rely on the default
469  // behavior of the system.
470  LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_WAIT_SIGNAL)
471  .arg(signal_set_->getNext());
472  } catch (const std::exception& e) {
473  LOG_ERROR(packet6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
474  }
475 
476  // Handle next signal received by the process. It must be called after
477  // an attempt to receive a packet to properly handle server shut down.
478  // The SIGTERM or SIGINT will be received prior to, or during execution
479  // of select() (select is invoked by receivePacket()). When that happens,
480  // select will be interrupted. The signal handler will be invoked
481  // immediately after select(). The handler will set the shutdown flag
482  // and cause the process to terminate before the next select() function
483  // is called. If the function was called before receivePacket the
484  // process could wait up to the duration of timeout of select() to
485  // terminate.
486  try {
487  handleSignal();
488  } catch (const std::exception& e) {
489  // An (a standard or ISC) exception occurred.
490  LOG_ERROR(dhcp6_logger, DHCP6_HANDLE_SIGNAL_EXCEPTION)
491  .arg(e.what());
492  }
493 
494  // Timeout may be reached or signal received, which breaks select()
495  // with no packet received
496  if (!query) {
497  return;
498  }
499 
500  // If the DHCP service has been globally disabled, drop the packet.
501  if (!network_state_->isServiceEnabled()) {
503  DHCP6_PACKET_DROP_DHCP_DISABLED)
504  .arg(query->getLabel());
505  return;
506  } else {
507  processPacket(query, rsp);
508  }
509 
510  if (!rsp) {
511  return;
512  }
513 
514  CalloutHandlePtr callout_handle = getCalloutHandle(query);
515  processPacketBufferSend(callout_handle, rsp);
516 }
517 
518 void
520  bool skip_unpack = false;
521 
522  // The packet has just been received so contains the uninterpreted wire
523  // data; execute callouts registered for buffer6_receive.
524  if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
525  CalloutHandlePtr callout_handle = getCalloutHandle(query);
526 
527  // Use the RAII wrapper to make sure that the callout handle state is
528  // reset when this object goes out of scope. All hook points must do
529  // it to prevent possible circular dependency between the callout
530  // handle and its arguments.
531  ScopedCalloutHandleState callout_handle_state(callout_handle);
532 
533  // Enable copying options from the packet within hook library.
534  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
535 
536  // Pass incoming packet as argument
537  callout_handle->setArgument("query6", query);
538 
539  // Call callouts
540  HooksManager::callCallouts(Hooks.hook_index_buffer6_receive_, *callout_handle);
541 
542  // Callouts decided to skip the next processing step. The next
543  // processing step would to parse the packet, so skip at this
544  // stage means that callouts did the parsing already, so server
545  // should skip parsing.
546  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
547  LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_SKIP)
548  .arg(query->getRemoteAddr().toText())
549  .arg(query->getLocalAddr().toText())
550  .arg(query->getIface());
551  skip_unpack = true;
552  }
553 
554  // Callouts decided to drop the received packet
555  // The response (rsp) is null so the caller (run_one) will
556  // immediately return too.
557  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
558  LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_BUFFER_RCVD_DROP)
559  .arg(query->getRemoteAddr().toText())
560  .arg(query->getLocalAddr().toText())
561  .arg(query->getIface());
562 
563  // Increase the statistic of dropped packets.
564  StatsMgr::instance().addValue("pkt6-receive-drop",
565  static_cast<int64_t>(1));
566  return;
567  }
568 
569  callout_handle->getArgument("query6", query);
570  }
571 
572  // Unpack the packet information unless the buffer6_receive callouts
573  // indicated they did it
574  if (!skip_unpack) {
575  try {
576  LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_BUFFER_UNPACK)
577  .arg(query->getRemoteAddr().toText())
578  .arg(query->getLocalAddr().toText())
579  .arg(query->getIface());
580  query->unpack();
581  } catch (const SkipRemainingOptionsError& e) {
582  // An option failed to unpack but we are to attempt to process it
583  // anyway. Log it and let's hope for the best.
585  DHCP6_PACKET_OPTIONS_SKIPPED)
586  .arg(e.what());
587  } catch (const std::exception &e) {
588  // Failed to parse the packet.
590  DHCP6_PACKET_DROP_PARSE_FAIL)
591  .arg(query->getRemoteAddr().toText())
592  .arg(query->getLocalAddr().toText())
593  .arg(query->getIface())
594  .arg(e.what());
595 
596  // Increase the statistics of parse failures and dropped packets.
597  StatsMgr::instance().addValue("pkt6-parse-failed",
598  static_cast<int64_t>(1));
599  StatsMgr::instance().addValue("pkt6-receive-drop",
600  static_cast<int64_t>(1));
601  return;
602  }
603  }
604 
605  // Update statistics accordingly for received packet.
606  processStatsReceived(query);
607 
608  // Check if received query carries server identifier matching
609  // server identifier being used by the server.
610  if (!testServerID(query)) {
611 
612  // Increase the statistic of dropped packets.
613  StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
614  return;
615  }
616 
617  // Check if the received query has been sent to unicast or multicast.
618  // The Solicit, Confirm, Rebind and Information Request will be
619  // discarded if sent to unicast address.
620  if (!testUnicast(query)) {
621 
622  // Increase the statistic of dropped packets.
623  StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
624  return;
625  }
626 
627  // Assign this packet to a class, if possible
628  classifyPacket(query);
629 
630  LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
631  .arg(query->getLabel())
632  .arg(query->getName())
633  .arg(static_cast<int>(query->getType()))
634  .arg(query->getRemoteAddr())
635  .arg(query->getLocalAddr())
636  .arg(query->getIface());
638  .arg(query->getLabel())
639  .arg(query->toText());
640 
641  // At this point the information in the packet has been unpacked into
642  // the various packet fields and option objects has been created.
643  // Execute callouts registered for packet6_receive.
644  if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_receive_)) {
645  CalloutHandlePtr callout_handle = getCalloutHandle(query);
646 
647  // Use the RAII wrapper to make sure that the callout handle state is
648  // reset when this object goes out of scope. All hook points must do
649  // it to prevent possible circular dependency between the callout
650  // handle and its arguments.
651  ScopedCalloutHandleState callout_handle_state(callout_handle);
652 
653  // Enable copying options from the packet within hook library.
654  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
655 
656  // Pass incoming packet as argument
657  callout_handle->setArgument("query6", query);
658 
659  // Call callouts
660  HooksManager::callCallouts(Hooks.hook_index_pkt6_receive_, *callout_handle);
661 
662  // Callouts decided to skip the next processing step. The next
663  // processing step would to process the packet, so skip at this
664  // stage means drop.
665  if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
666  (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
667  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_RCVD_SKIP)
668  .arg(query->getLabel());
669  // Increase the statistic of dropped packets.
670  StatsMgr::instance().addValue("pkt6-receive-drop",
671  static_cast<int64_t>(1));
672  return;
673  }
674 
675  callout_handle->getArgument("query6", query);
676  }
677 
678  // Reject the message if it doesn't pass the sanity check.
679  if (!sanityCheck(query)) {
680  return;
681  }
682 
683  if (query->getType() == DHCPV6_DHCPV4_QUERY) {
684  // This call never throws. Should this change, this section must be
685  // enclosed in try-catch.
686  processDhcp4Query(query);
687  return;
688  }
689 
690  // Let's create a simplified client context here.
692  bool drop = false;
693  initContext(query, ctx, drop);
694 
695  // Stop here if initContext decided to drop the packet.
696  if (drop) {
697  return;
698  }
699 
700  // Park point here.
701 
702  try {
703  switch (query->getType()) {
704  case DHCPV6_SOLICIT:
705  rsp = processSolicit(ctx);
706  break;
707 
708  case DHCPV6_REQUEST:
709  rsp = processRequest(ctx);
710  break;
711 
712  case DHCPV6_RENEW:
713  rsp = processRenew(ctx);
714  break;
715 
716  case DHCPV6_REBIND:
717  rsp = processRebind(ctx);
718  break;
719 
720  case DHCPV6_CONFIRM:
721  rsp = processConfirm(ctx);
722  break;
723 
724  case DHCPV6_RELEASE:
725  rsp = processRelease(ctx);
726  break;
727 
728  case DHCPV6_DECLINE:
729  rsp = processDecline(ctx);
730  break;
731 
733  rsp = processInfRequest(ctx);
734  break;
735 
736  default:
737  return;
738  }
739 
740  } catch (const std::exception& e) {
741 
742  // Catch-all exception (at least for ones based on the isc Exception
743  // class, which covers more or less all that are explicitly raised
744  // in the Kea code), but also the standard one, which may possibly be
745  // thrown from boost code. Just log the problem and ignore the packet.
746  // (The problem is logged as a debug message because debug is
747  // disabled by default - it prevents a DDOS attack based on the
748  // sending of problem packets.)
749  LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_PACKET_PROCESS_FAIL)
750  .arg(query->getName())
751  .arg(query->getRemoteAddr().toText())
752  .arg(e.what());
753 
754  // Increase the statistic of dropped packets.
755  StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
756  }
757 
758  if (!rsp) {
759  return;
760  }
761 
762  // Process relay-supplied options. It is important to call this very
763  // late in the process, because we now have all the options the
764  // server wanted to send already set. This is important, because
765  // RFC6422, section 6 states:
766  //
767  // The server SHOULD discard any options that appear in the RSOO
768  // for which it already has one or more candidates.
769  //
770  // So we ignore any RSOO options if there's an option with the same
771  // code already present.
772  processRSOO(query, rsp);
773 
774  rsp->setRemoteAddr(query->getRemoteAddr());
775  rsp->setLocalAddr(query->getLocalAddr());
776 
777  if (rsp->relay_info_.empty()) {
778  // Direct traffic, send back to the client directly
779  rsp->setRemotePort(DHCP6_CLIENT_PORT);
780  } else {
781  // Relayed traffic, send back to the relay agent
782  uint16_t relay_port = checkRelaySourcePort(query);
783  rsp->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
784  }
785 
786  rsp->setLocalPort(DHCP6_SERVER_PORT);
787  rsp->setIndex(query->getIndex());
788  rsp->setIface(query->getIface());
789 
790  bool packet_park = false;
791 
792  if (!ctx.fake_allocation_ && (ctx.query_->getType() != DHCPV6_CONFIRM) &&
793  (ctx.query_->getType() != DHCPV6_INFORMATION_REQUEST) &&
794  HooksManager::calloutsPresent(Hooks.hook_index_leases6_committed_)) {
795  CalloutHandlePtr callout_handle = getCalloutHandle(query);
796 
797  // Use the RAII wrapper to make sure that the callout handle state is
798  // reset when this object goes out of scope. All hook points must do
799  // it to prevent possible circular dependency between the callout
800  // handle and its arguments.
801  ScopedCalloutHandleState callout_handle_state(callout_handle);
802 
803  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
804 
805  // Also pass the corresponding query packet as argument
806  callout_handle->setArgument("query6", query);
807 
808  Lease6CollectionPtr new_leases(new Lease6Collection());
809  if (!ctx.new_leases_.empty()) {
810  new_leases->assign(ctx.new_leases_.cbegin(),
811  ctx.new_leases_.cend());
812  }
813  callout_handle->setArgument("leases6", new_leases);
814 
815  Lease6CollectionPtr deleted_leases(new Lease6Collection());
816 
817  // Do per IA lists
818  for (auto const iac : ctx.ias_) {
819  if (!iac.old_leases_.empty()) {
820  for (auto old_lease : iac.old_leases_) {
821  if (ctx.new_leases_.empty()) {
822  deleted_leases->push_back(old_lease);
823  continue;
824  }
825  bool in_new = false;
826  for (auto const new_lease : ctx.new_leases_) {
827  if ((new_lease->addr_ == old_lease->addr_) &&
828  (new_lease->prefixlen_ == old_lease->prefixlen_)) {
829  in_new = true;
830  break;
831  }
832  }
833  if (!in_new) {
834  deleted_leases->push_back(old_lease);
835  }
836  }
837  }
838  }
839  callout_handle->setArgument("deleted_leases6", deleted_leases);
840 
841  // Call all installed callouts
842  HooksManager::callCallouts(Hooks.hook_index_leases6_committed_,
843  *callout_handle);
844 
845  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
847  DHCP6_HOOK_LEASES6_COMMITTED_DROP)
848  .arg(query->getLabel());
849  rsp.reset();
850 
851  } else if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_PARK) {
852  packet_park = true;
853  }
854  }
855 
856  if (!rsp) {
857  return;
858  }
859 
860  // PARKING SPOT after leases6_committed hook point.
861  CalloutHandlePtr callout_handle = getCalloutHandle(query);
862  if (packet_park) {
864  DHCP6_HOOK_LEASES6_COMMITTED_PARK)
865  .arg(query->getLabel());
866 
867  // Park the packet. The function we bind here will be executed when the hook
868  // library unparks the packet.
869  HooksManager::park("leases6_committed", query,
870  [this, callout_handle, query, rsp]() mutable {
871  processPacketPktSend(callout_handle, query, rsp);
872  processPacketBufferSend(callout_handle, rsp);
873  });
874 
875  // If we have parked the packet, let's reset the pointer to the
876  // response to indicate to the caller that it should return, as
877  // the packet processing will continue via the callback.
878  rsp.reset();
879 
880  } else {
881  processPacketPktSend(callout_handle, query, rsp);
882  }
883 }
884 
885 void
887  Pkt6Ptr& query, Pkt6Ptr& rsp) {
888  if (!rsp) {
889  return;
890  }
891 
892  // Specifies if server should do the packing
893  bool skip_pack = false;
894 
895  // Server's reply packet now has all options and fields set.
896  // Options are represented by individual objects, but the
897  // output wire data has not been prepared yet.
898  // Execute all callouts registered for packet6_send
899  if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
900 
901  // Use the RAII wrapper to make sure that the callout handle state is
902  // reset when this object goes out of scope. All hook points must do
903  // it to prevent possible circular dependency between the callout
904  // handle and its arguments.
905  ScopedCalloutHandleState callout_handle_state(callout_handle);
906 
907  // Enable copying options from the packets within hook library.
908  ScopedEnableOptionsCopy<Pkt6> query_resp_options_copy(query, rsp);
909 
910  // Pass incoming packet as argument
911  callout_handle->setArgument("query6", query);
912 
913  // Set our response
914  callout_handle->setArgument("response6", rsp);
915 
916  // Call all installed callouts
917  HooksManager::callCallouts(Hooks.hook_index_pkt6_send_, *callout_handle);
918 
919  // Callouts decided to skip the next processing step. The next
920  // processing step would to pack the packet (create wire data).
921  // That step will be skipped if any callout sets skip flag.
922  // It essentially means that the callout already did packing,
923  // so the server does not have to do it again.
924  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
925  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_SKIP)
926  .arg(rsp->getLabel());
927  skip_pack = true;
928  }
929 
931  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
932  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_PACKET_SEND_DROP)
933  .arg(rsp->getLabel());
934  rsp.reset();
935  return;
936  }
937  }
938 
939  if (!skip_pack) {
940  try {
941  rsp->pack();
942  } catch (const std::exception& e) {
943  LOG_ERROR(options6_logger, DHCP6_PACK_FAIL).arg(e.what());
944  return;
945  }
946 
947  }
948 }
949 
950 void
952  Pkt6Ptr& rsp) {
953  if (!rsp) {
954  return;
955  }
956 
957  try {
958  // Now all fields and options are constructed into output wire buffer.
959  // Option objects modification does not make sense anymore. Hooks
960  // can only manipulate wire buffer at this stage.
961  // Let's execute all callouts registered for buffer6_send
962  if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_send_)) {
963 
964  // Use the RAII wrapper to make sure that the callout handle state is
965  // reset when this object goes out of scope. All hook points must do
966  // it to prevent possible circular dependency between the callout
967  // handle and its arguments.
968  ScopedCalloutHandleState callout_handle_state(callout_handle);
969 
970  // Enable copying options from the packet within hook library.
971  ScopedEnableOptionsCopy<Pkt6> response6_options_copy(rsp);
972 
973  // Pass incoming packet as argument
974  callout_handle->setArgument("response6", rsp);
975 
976  // Call callouts
977  HooksManager::callCallouts(Hooks.hook_index_buffer6_send_,
978  *callout_handle);
979 
980  // Callouts decided to skip the next processing step. The next
981  // processing step would to parse the packet, so skip at this
982  // stage means drop.
983  if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
984  (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
986  DHCP6_HOOK_BUFFER_SEND_SKIP)
987  .arg(rsp->getLabel());
988  return;
989  }
990 
991  callout_handle->getArgument("response6", rsp);
992  }
993 
994  LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_RESPONSE_DATA)
995  .arg(static_cast<int>(rsp->getType())).arg(rsp->toText());
996 
997  sendPacket(rsp);
998 
999  // Update statistics accordingly for sent packet.
1000  processStatsSent(rsp);
1001 
1002  } catch (const std::exception& e) {
1003  LOG_ERROR(packet6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
1004  }
1005 }
1006 
1007 std::string
1009  stringstream tmp;
1010 
1011  OptionBuffer data = opt->getData();
1012 
1013  bool colon = false;
1014  for (OptionBufferConstIter it = data.begin(); it != data.end(); ++it) {
1015  if (colon) {
1016  tmp << ":";
1017  }
1018  tmp << hex << setw(2) << setfill('0') << static_cast<uint16_t>(*it);
1019  if (!colon) {
1020  colon = true;
1021  }
1022  }
1023 
1024  return tmp.str();
1025 }
1026 
1027 void
1028 Dhcpv6Srv::copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
1029  // Add client-id.
1030  OptionPtr clientid = question->getOption(D6O_CLIENTID);
1031  if (clientid) {
1032  answer->addOption(clientid);
1033  }
1035 
1036  // If this is a relayed message, we need to copy relay information
1037  if (!question->relay_info_.empty()) {
1038  answer->copyRelayInfo(question);
1039  }
1040 
1041 }
1042 
1043 void
1045  const CfgOptionList&) {
1046  // add server-id
1047  answer->addOption(getServerID());
1048 }
1049 
1050 void
1053  CfgOptionList& co_list) {
1054  // Firstly, host specific options.
1055  if (ctx.currentHost() && !ctx.currentHost()->getCfgOption6()->empty()) {
1056  co_list.push_back(ctx.currentHost()->getCfgOption6());
1057  }
1058 
1059  // Secondly, pool specific options. Pools are defined within a subnet, so
1060  // if there is no subnet, there is nothing to do.
1061  if (ctx.subnet_) {
1062  BOOST_FOREACH(const AllocEngine::ResourceType& resource,
1063  ctx.allocated_resources_) {
1064  PoolPtr pool = ctx.subnet_->getPool(resource.second == 128 ?
1066  resource.first, false);
1067  if (pool && !pool->getCfgOption()->empty()) {
1068  co_list.push_back(pool->getCfgOption());
1069  }
1070  }
1071  };
1072 
1073  if (ctx.subnet_) {
1074  // Next, subnet configured options.
1075  if (!ctx.subnet_->getCfgOption()->empty()) {
1076  co_list.push_back(ctx.subnet_->getCfgOption());
1077  }
1078 
1079  // Then, shared network specific options.
1080  SharedNetwork6Ptr network;
1081  ctx.subnet_->getSharedNetwork(network);
1082  if (network && !network->getCfgOption()->empty()) {
1083  co_list.push_back(network->getCfgOption());
1084  }
1085  }
1086 
1087  // Each class in the incoming packet
1088  const ClientClasses& classes = question->getClasses();
1089  for (ClientClasses::const_iterator cclass = classes.cbegin();
1090  cclass != classes.cend(); ++cclass) {
1091  // Find the client class definition for this class
1092  const ClientClassDefPtr& ccdef = CfgMgr::instance().getCurrentCfg()->
1093  getClientClassDictionary()->findClass(*cclass);
1094  if (!ccdef) {
1095  // Not found: the class is built-in or not configured
1096  if (!isClientClassBuiltIn(*cclass)) {
1097  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_UNCONFIGURED)
1098  .arg(question->getLabel())
1099  .arg(*cclass);
1100  }
1101  // Skip it
1102  continue;
1103  }
1104 
1105  if (ccdef->getCfgOption()->empty()) {
1106  // Skip classes which don't configure options
1107  continue;
1108  }
1109 
1110  co_list.push_back(ccdef->getCfgOption());
1111  }
1112 
1113  // Last global options
1114  if (!CfgMgr::instance().getCurrentCfg()->getCfgOption()->empty()) {
1115  co_list.push_back(CfgMgr::instance().getCurrentCfg()->getCfgOption());
1116  }
1117 }
1118 
1119 void
1121  const CfgOptionList& co_list) {
1122 
1123  // Unlikely short cut
1124  if (co_list.empty()) {
1125  return;
1126  }
1127 
1128  std::vector<uint16_t> requested_opts;
1129 
1130  // Client requests some options using ORO option. Try to
1131  // get this option from client's message.
1132  boost::shared_ptr<OptionIntArray<uint16_t> > option_oro =
1133  boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >
1134  (question->getOption(D6O_ORO));
1135 
1136  // Get the list of options that client requested.
1137  if (option_oro) {
1138  requested_opts = option_oro->getValues();
1139  }
1140  // Iterate on the configured option list to add persistent options
1141  for (CfgOptionList::const_iterator copts = co_list.begin();
1142  copts != co_list.end(); ++copts) {
1143  const OptionContainerPtr& opts = (*copts)->getAll(DHCP6_OPTION_SPACE);
1144  if (!opts) {
1145  continue;
1146  }
1147  // Get persistent options
1148  const OptionContainerPersistIndex& idx = opts->get<2>();
1149  const OptionContainerPersistRange& range = idx.equal_range(true);
1150  for (OptionContainerPersistIndex::const_iterator desc = range.first;
1151  desc != range.second; ++desc) {
1152  // Add the persistent option code to requested options
1153  requested_opts.push_back(desc->option_->getType());
1154  }
1155  }
1156 
1157  BOOST_FOREACH(uint16_t opt, requested_opts) {
1158  // Iterate on the configured option list
1159  for (CfgOptionList::const_iterator copts = co_list.begin();
1160  copts != co_list.end(); ++copts) {
1161  OptionDescriptor desc = (*copts)->get(DHCP6_OPTION_SPACE, opt);
1162  // Got it: add it and jump to the outer loop
1163  if (desc.option_) {
1164  answer->addOption(desc.option_);
1165  break;
1166  }
1167  }
1168  }
1169 }
1170 
1171 void
1173  Pkt6Ptr& answer,
1175  const CfgOptionList& co_list) {
1176 
1177  // Leave if there is no subnet matching the incoming packet.
1178  // There is no need to log the error message here because
1179  // it will be logged in the assignLease() when it fails to
1180  // pick the suitable subnet. We don't want to duplicate
1181  // error messages in such case.
1182  if (!ctx.subnet_) {
1183  return;
1184  }
1185 
1186  // Try to get the vendor option
1187  boost::shared_ptr<OptionVendor> vendor_req =
1188  boost::dynamic_pointer_cast<OptionVendor>(question->getOption(D6O_VENDOR_OPTS));
1189  if (!vendor_req || co_list.empty()) {
1190  return;
1191  }
1192 
1193  uint32_t vendor_id = vendor_req->getVendorId();
1194  std::vector<uint16_t> requested_opts;
1195 
1196  // Let's try to get ORO within that vendor-option
1199  boost::shared_ptr<OptionUint16Array> oro =
1200  boost::dynamic_pointer_cast<OptionUint16Array>(vendor_req->getOption(DOCSIS3_V6_ORO));
1201  if (oro) {
1202  requested_opts = oro->getValues();
1203  }
1204  // Iterate on the configured option list to add persistent options
1205  for (CfgOptionList::const_iterator copts = co_list.begin();
1206  copts != co_list.end(); ++copts) {
1207  const OptionContainerPtr& opts = (*copts)->getAll(vendor_id);
1208  if (!opts) {
1209  continue;
1210  }
1211  // Get persistent options
1212  const OptionContainerPersistIndex& idx = opts->get<2>();
1213  const OptionContainerPersistRange& range = idx.equal_range(true);
1214  for (OptionContainerPersistIndex::const_iterator desc = range.first;
1215  desc != range.second; ++desc) {
1216  // Add the persistent option code to requested options
1217  requested_opts.push_back(desc->option_->getType());
1218  }
1219  }
1220 
1221  // If there is nothing to add don't do anything then.
1222  if (requested_opts.empty()) {
1223  return;
1224  }
1225 
1226  boost::shared_ptr<OptionVendor> vendor_rsp(new OptionVendor(Option::V6, vendor_id));
1227 
1228  // Get the list of options that client requested.
1229  bool added = false;
1230 
1231  BOOST_FOREACH(uint16_t opt, requested_opts) {
1232  for (CfgOptionList::const_iterator copts = co_list.begin();
1233  copts != co_list.end(); ++copts) {
1234  OptionDescriptor desc = (*copts)->get(vendor_id, opt);
1235  if (desc.option_) {
1236  vendor_rsp->addOption(desc.option_);
1237  added = true;
1238  break;
1239  }
1240  }
1241  }
1242 
1243  if (added) {
1244  answer->addOption(vendor_rsp);
1245  }
1246 }
1247 
1248 bool
1250  try {
1251  switch (pkt->getType()) {
1252  case DHCPV6_SOLICIT:
1253  case DHCPV6_REBIND:
1254  case DHCPV6_CONFIRM:
1256  return (true);
1257 
1258  case DHCPV6_REQUEST:
1259  case DHCPV6_RENEW:
1260  case DHCPV6_RELEASE:
1261  case DHCPV6_DECLINE:
1263  return (true);
1264 
1266  case DHCPV6_DHCPV4_QUERY:
1267  sanityCheck(pkt, OPTIONAL, OPTIONAL);
1268  return (true);
1269 
1270  default:
1272  DHCP6_UNKNOWN_MSG_RECEIVED)
1273  .arg(static_cast<int>(pkt->getType()))
1274  .arg(pkt->getIface());
1275  }
1276 
1277  } catch (const RFCViolation& e) {
1278  LOG_DEBUG(bad_packet6_logger, DBG_DHCP6_BASIC, DHCP6_REQUIRED_OPTIONS_CHECK_FAIL)
1279  .arg(pkt->getName())
1280  .arg(pkt->getRemoteAddr().toText())
1281  .arg(e.what());
1282 
1283  }
1284 
1285  // Increase the statistic of dropped packets.
1286  StatsMgr::instance().addValue("pkt6-receive-drop", static_cast<int64_t>(1));
1287  return (false);
1288 }
1289 
1290 void
1292  RequirementLevel serverid) {
1293  OptionCollection client_ids = pkt->getOptions(D6O_CLIENTID);
1294  switch (clientid) {
1295  case MANDATORY: {
1296  if (client_ids.size() != 1) {
1297  isc_throw(RFCViolation, "Exactly 1 client-id option expected in "
1298  << pkt->getName() << ", but " << client_ids.size()
1299  << " received");
1300  }
1301  sanityCheckDUID(client_ids.begin()->second, "client-id");
1302  break;
1303  }
1304  case OPTIONAL:
1305  if (client_ids.size() > 1) {
1306  isc_throw(RFCViolation, "Too many (" << client_ids.size()
1307  << ") client-id options received in " << pkt->getName());
1308  }
1309  if (!client_ids.empty()) {
1310  sanityCheckDUID(client_ids.begin()->second, "client-id");
1311  }
1312  break;
1313 
1314  case FORBIDDEN:
1315  // doesn't make sense - client-id is always allowed
1316  break;
1317  }
1318 
1319  OptionCollection server_ids = pkt->getOptions(D6O_SERVERID);
1320  switch (serverid) {
1321  case FORBIDDEN:
1322  if (!server_ids.empty()) {
1323  isc_throw(RFCViolation, "Server-id option was not expected, but "
1324  << server_ids.size() << " received in " << pkt->getName());
1325  }
1326  break;
1327 
1328  case MANDATORY:
1329  if (server_ids.size() != 1) {
1330  isc_throw(RFCViolation, "Invalid number of server-id options received ("
1331  << server_ids.size() << "), exactly 1 expected in message "
1332  << pkt->getName());
1333  }
1334  sanityCheckDUID(server_ids.begin()->second, "server-id");
1335  break;
1336 
1337  case OPTIONAL:
1338  if (server_ids.size() > 1) {
1339  isc_throw(RFCViolation, "Too many (" << server_ids.size()
1340  << ") server-id options received in " << pkt->getName());
1341  }
1342  if (!server_ids.empty()) {
1343  sanityCheckDUID(server_ids.begin()->second, "server-id");
1344  }
1345  }
1346 }
1347 
1348 void Dhcpv6Srv::sanityCheckDUID(const OptionPtr& opt, const std::string& opt_name) {
1349  if (!opt) {
1350  isc_throw(RFCViolation, "Unable to find expected option " << opt_name);
1351  }
1352 
1353  // The client-id or server-id has to have at least 3 bytes of useful data:
1354  // two for duid type and one more for actual duid value.
1355  uint16_t len = opt->len() - opt->getHeaderLen();
1356  if (len < 3) {
1357  isc_throw(RFCViolation, "Received empty or truncated " << opt_name << " option: "
1358  << len << " byte(s) only");
1359  }
1360 }
1361 
1362 Subnet6Ptr
1363 Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question, bool& drop) {
1364  const SubnetSelector& selector = CfgSubnets6::initSelector(question);
1365 
1367  getCfgSubnets6()->selectSubnet(selector);
1368 
1369  // Let's execute all callouts registered for subnet6_receive
1370  if (HooksManager::calloutsPresent(Hooks.hook_index_subnet6_select_)) {
1371  CalloutHandlePtr callout_handle = getCalloutHandle(question);
1372 
1373  // Use the RAII wrapper to make sure that the callout handle state is
1374  // reset when this object goes out of scope. All hook points must do
1375  // it to prevent possible circular dependency between the callout
1376  // handle and its arguments.
1377  ScopedCalloutHandleState callout_handle_state(callout_handle);
1378 
1379  // Enable copying options from the packet within hook library.
1380  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(question);
1381 
1382  // Set new arguments
1383  callout_handle->setArgument("query6", question);
1384  callout_handle->setArgument("subnet6", subnet);
1385 
1386  // We pass pointer to const collection for performance reasons.
1387  // Otherwise we would get a non-trivial performance penalty each
1388  // time subnet6_select is called.
1389  callout_handle->setArgument("subnet6collection",
1390  CfgMgr::instance().getCurrentCfg()->
1391  getCfgSubnets6()->getAll());
1392 
1393  // Call user (and server-side) callouts
1394  HooksManager::callCallouts(Hooks.hook_index_subnet6_select_, *callout_handle);
1395 
1396  // Callouts decided to skip this step. This means that no
1397  // subnet will be selected. Packet processing will continue,
1398  // but it will be severely limited (i.e. only global options
1399  // will be assigned)
1400  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
1401  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_SUBNET6_SELECT_SKIP)
1402  .arg(question->getLabel());
1403  return (Subnet6Ptr());
1404  }
1405 
1406  // Callouts decided to drop the packet. It is a superset of the
1407  // skip case so no subnet will be selected.
1408  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
1409  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_SUBNET6_SELECT_DROP)
1410  .arg(question->getLabel());
1411  drop = true;
1412  return (Subnet6Ptr());
1413  }
1414 
1415  // Use whatever subnet was specified by the callout
1416  callout_handle->getArgument("subnet6", subnet);
1417  }
1418 
1419  if (subnet) {
1420  // Log at higher debug level that subnet has been found.
1421  LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_SUBNET_SELECTED)
1422  .arg(question->getLabel())
1423  .arg(subnet->getID());
1424  // Log detailed information about the selected subnet at the
1425  // lower debug level.
1426  LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_SUBNET_DATA)
1427  .arg(question->getLabel())
1428  .arg(subnet->toText());
1429 
1430  } else {
1431  LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_SUBNET_SELECTION_FAILED)
1432  .arg(question->getLabel());
1433  }
1434 
1435  return (subnet);
1436 }
1437 
1438 void
1439 Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
1441 
1442  Subnet6Ptr subnet = ctx.subnet_;
1443 
1444  // We need to allocate addresses for all IA_NA options in the client's
1445  // question (i.e. SOLICIT or REQUEST) message.
1446  // @todo add support for IA_TA
1447 
1448  // For the lease allocation it is critical that the client has sent
1449  // DUID. There is no need to check for the presence of the DUID here
1450  // because we have already checked it in the sanityCheck().
1451 
1452  // Now that we have all information about the client, let's iterate over all
1453  // received options and handle IA_NA options one by one and store our
1454  // responses in answer message (ADVERTISE or REPLY).
1455  //
1456  // @todo: IA_TA once we implement support for temporary addresses.
1457  for (OptionCollection::iterator opt = question->options_.begin();
1458  opt != question->options_.end(); ++opt) {
1459  switch (opt->second->getType()) {
1460  case D6O_IA_NA: {
1461  OptionPtr answer_opt = assignIA_NA(question, answer, ctx,
1462  boost::dynamic_pointer_cast<
1463  Option6IA>(opt->second));
1464  if (answer_opt) {
1465  answer->addOption(answer_opt);
1466  }
1467  break;
1468  }
1469  case D6O_IA_PD: {
1470  OptionPtr answer_opt = assignIA_PD(question, answer, ctx,
1471  boost::dynamic_pointer_cast<
1472  Option6IA>(opt->second));
1473  if (answer_opt) {
1474  answer->addOption(answer_opt);
1475  }
1476  }
1477  default:
1478  break;
1479  }
1480  }
1481 
1482  // Subnet may be modified by the allocation engine, if the initial subnet
1483  // belongs to a shared network.
1484  if (ctx.subnet_ && subnet && (subnet->getID() != ctx.subnet_->getID())) {
1485  SharedNetwork6Ptr network;
1486  subnet->getSharedNetwork(network);
1487  if (network) {
1488  LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC_DATA, DHCP6_SUBNET_DYNAMICALLY_CHANGED)
1489  .arg(question->getLabel())
1490  .arg(subnet->toText())
1491  .arg(ctx.subnet_->toText())
1492  .arg(network->getName());
1493  }
1494  }
1495 }
1496 
1497 
1498 void
1499 Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer,
1502 
1503  // Get Client FQDN Option from the client's message. If this option hasn't
1504  // been included, do nothing.
1505  Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
1506  Option6ClientFqdn>(question->getOption(D6O_CLIENT_FQDN));
1507  if (!fqdn) {
1508  D2ClientConfig::ReplaceClientNameMode replace_name_mode =
1509  d2_mgr.getD2ClientConfig()->getReplaceClientNameMode();
1510  if (d2_mgr.ddnsEnabled() &&
1511  (replace_name_mode == D2ClientConfig::RCM_ALWAYS ||
1512  replace_name_mode == D2ClientConfig::RCM_WHEN_NOT_PRESENT)) {
1513  // Fabricate an empty "client" FQDN with flags requesting
1514  // the server do all the updates. The flags will get modified
1515  // below according the configuration options, the name will
1516  // be supplied later on.
1517  fqdn.reset(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S, "",
1519  LOG_DEBUG(ddns6_logger, DBG_DHCP6_DETAIL, DHCP6_DDNS_GENERATE_FQDN)
1520  .arg(question->getLabel());
1521  } else {
1522  // No FQDN so get the lease hostname from the host reservation if
1523  // there is one.
1524  if (ctx.currentHost()) {
1525  ctx.hostname_ = ctx.currentHost()->getHostname();
1526  }
1527 
1528  return;
1529  }
1530  }
1531 
1532  LOG_DEBUG(ddns6_logger, DBG_DHCP6_DETAIL, DHCP6_DDNS_RECEIVE_FQDN)
1533  .arg(question->getLabel())
1534  .arg(fqdn->toText());
1535 
1536  // Create the DHCPv6 Client FQDN Option to be included in the server's
1537  // response to a client.
1538  Option6ClientFqdnPtr fqdn_resp(new Option6ClientFqdn(*fqdn));
1539 
1540  // Set the server S, N, and O flags based on client's flags and
1541  // current configuration.
1542  d2_mgr.adjustFqdnFlags<Option6ClientFqdn>(*fqdn, *fqdn_resp);
1543 
1544  // If there's a reservation and it has a hostname specified, use it!
1545  if (ctx.currentHost() && !ctx.currentHost()->getHostname().empty()) {
1546  // Add the qualifying suffix.
1547  // After #3765, this will only occur if the suffix is not empty.
1548  fqdn_resp->setDomainName(d2_mgr.qualifyName(ctx.currentHost()->getHostname(),
1549  true),
1551  } else {
1552  // Adjust the domain name based on domain name value and type sent by
1553  // the client and current configuration.
1554  d2_mgr.adjustDomainName<Option6ClientFqdn>(*fqdn, *fqdn_resp);
1555  }
1556 
1557  // Once we have the FQDN setup to use it for the lease hostname. This
1558  // only gets replaced later if the FQDN is to be generated from the address.
1559  ctx.hostname_ = fqdn_resp->getDomainName();
1560 
1561  // The FQDN has been processed successfully. Let's append it to the
1562  // response to be sent to a client. Note that the Client FQDN option is
1563  // always sent back to the client if Client FQDN was included in the
1564  // client's message.
1565  LOG_DEBUG(ddns6_logger, DBG_DHCP6_DETAIL, DHCP6_DDNS_RESPONSE_FQDN_DATA)
1566  .arg(question->getLabel())
1567  .arg(fqdn_resp->toText());
1568  answer->addOption(fqdn_resp);
1569 }
1570 
1571 void
1574  // Don't create NameChangeRequests if DNS updates are disabled.
1575  if (!CfgMgr::instance().ddnsEnabled()) {
1576  return;
1577  }
1578 
1579  // The response message instance is always required. For instance it
1580  // holds the Client Identifier. It is a programming error if supplied
1581  // message is NULL.
1582  if (!answer) {
1583  isc_throw(isc::Unexpected, "an instance of the object"
1584  << " encapsulating server's message must not be"
1585  << " NULL when creating DNS NameChangeRequest");
1586  }
1587 
1588  // It is likely that client haven't included the FQDN option. In such case,
1589  // FQDN option will be NULL. This is valid state, so we simply return.
1590  Option6ClientFqdnPtr opt_fqdn = boost::dynamic_pointer_cast<
1591  Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
1592  if (!opt_fqdn) {
1593  return;
1594  }
1595 
1596  // Get the update directions that should be performed based on our
1597  // response FQDN flags.
1598  bool do_fwd = false;
1599  bool do_rev = false;
1601  do_fwd, do_rev);
1602  if (!do_fwd && !do_rev) {
1603  // Flags indicate there is Nothing to do, get out now.
1604  // The Most likely scenario is that we are honoring the client's
1605  // request that no updates be done.
1606  return;
1607  }
1608 
1609  // Get the Client Id. It is mandatory and a function creating a response
1610  // would have thrown an exception if it was missing. Thus throwing
1611  // Unexpected if it is missing as it is a programming error.
1612  OptionPtr opt_duid = answer->getOption(D6O_CLIENTID);
1613  if (!opt_duid) {
1615  "client identifier is required when creating a new"
1616  " DNS NameChangeRequest");
1617  }
1618  DuidPtr duid = DuidPtr(new DUID(opt_duid->getData()));
1619 
1620  // Get the FQDN in the on-wire format. It will be needed to compute
1621  // DHCID.
1622  OutputBuffer name_buf(1);
1623  opt_fqdn->packDomainName(name_buf);
1624  const uint8_t* name_data = static_cast<const uint8_t*>(name_buf.getData());
1625  // @todo currently D2Dhcid accepts a vector holding FQDN.
1626  // However, it will be faster if we used a pointer name_data.
1627  std::vector<uint8_t> buf_vec(name_data, name_data + name_buf.getLength());
1628  // Compute DHCID from Client Identifier and FQDN.
1629  isc::dhcp_ddns::D2Dhcid dhcid(*duid, buf_vec);
1630 
1631  // Get all IAs from the answer. For each IA, holding an address we will
1632  // create a corresponding NameChangeRequest.
1633  OptionCollection answer_ias = answer->getOptions(D6O_IA_NA);
1634  for (OptionCollection::const_iterator answer_ia =
1635  answer_ias.begin(); answer_ia != answer_ias.end(); ++answer_ia) {
1638  Option6IAAddrPtr iaaddr = boost::static_pointer_cast<
1639  Option6IAAddr>(answer_ia->second->getOption(D6O_IAADDR));
1640  // We need an address to create a name-to-address mapping.
1641  // If address is missing for any reason, go to the next IA.
1642  if (!iaaddr) {
1643  continue;
1644  }
1645 
1646  // If the lease for iaaddr is in the list of changed leases, we need
1647  // to determine if the changes included changes to the FQDN. If there
1648  // were changes to the FQDN then we need to update DNS, otherwise
1649  // we do not.
1650  bool extended_only = false;
1651  for (Lease6Collection::const_iterator l = ctx.currentIA().changed_leases_.begin();
1652  l != ctx.currentIA().changed_leases_.end(); ++l) {
1653  if ((*l)->addr_ == iaaddr->getAddress()) {
1654  if ((*l)->hostname_ == opt_fqdn->getDomainName() &&
1655  (*l)->fqdn_fwd_ == do_fwd && (*l)->fqdn_rev_ == do_rev) {
1656  extended_only = true;
1657  break;
1658  }
1659  }
1660  }
1661 
1662  if (extended_only) {
1663  continue;
1664  }
1665 
1666  // Create new NameChangeRequest. Use the domain name from the FQDN.
1667  // This is an FQDN included in the response to the client, so it
1668  // holds a fully qualified domain-name already (not partial).
1669  // Get the IP address from the lease.
1672  do_fwd, do_rev,
1673  opt_fqdn->getDomainName(),
1674  iaaddr->getAddress().toText(),
1675  dhcid, 0, iaaddr->getValid()));
1676 
1678  DHCP6_DDNS_CREATE_ADD_NAME_CHANGE_REQUEST).arg(ncr->toText());
1679 
1680  // Post the NCR to the D2ClientMgr.
1682 
1687  return;
1688  }
1689 }
1690 
1691 HWAddrPtr
1693  CfgMACSources mac_sources = CfgMgr::instance().getCurrentCfg()->
1694  getMACSources().get();
1695  HWAddrPtr hwaddr;
1696  for (CfgMACSources::const_iterator it = mac_sources.begin();
1697  it != mac_sources.end(); ++it) {
1698  hwaddr = pkt->getMAC(*it);
1699  if (hwaddr) {
1700  return (hwaddr);
1701  }
1702  }
1703  return (hwaddr);
1704 }
1705 
1706 OptionPtr
1707 Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
1709  boost::shared_ptr<Option6IA> ia) {
1710 
1711  // Check if the client sent us a hint in his IA_NA. Clients may send an
1712  // address in their IA_NA options as a suggestion (e.g. the last address
1713  // they used before).
1714  Option6IAAddrPtr hint_opt =
1715  boost::dynamic_pointer_cast<Option6IAAddr>(ia->getOption(D6O_IAADDR));
1717  if (hint_opt) {
1718  hint = hint_opt->getAddress();
1719  }
1720 
1721  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_NA_REQUEST)
1722  .arg(query->getLabel())
1723  .arg(ia->getIAID())
1724  .arg(hint_opt ? hint.toText() : "(no hint)");
1725 
1726  // convenience values
1727  const Subnet6Ptr& subnet = ctx.subnet_;
1728 
1729  // If there is no subnet selected for handling this IA_NA, the only thing left to do is
1730  // to say that we are sorry, but the user won't get an address. As a convenience, we
1731  // use a different status text to indicate that (compare to the same status code,
1732  // but different wording below)
1733  if (!subnet) {
1734  // Create an empty IA_NA option with IAID matching the request.
1735  // Note that we don't use OptionDefinition class to create this option.
1736  // This is because we prefer using a constructor of Option6IA that
1737  // initializes IAID. Otherwise we would have to use setIAID() after
1738  // creation of the option which has some performance implications.
1739  boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
1740 
1741  // Insert status code NoAddrsAvail.
1742  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoAddrsAvail,
1743  "Server could not select subnet for"
1744  " this client"));
1745  return (ia_rsp);
1746  }
1747 
1748  // Get DDNS update direction flags
1749  bool do_fwd = false;
1750  bool do_rev = false;
1751  Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
1752  Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
1753  if (fqdn) {
1755  do_rev);
1756  }
1757 
1758  // Update per-packet context values.
1759  ctx.fwd_dns_update_ = do_fwd;
1760  ctx.rev_dns_update_ = do_rev;
1761 
1762  // Set per-IA context values.
1763  ctx.createIAContext();
1764  ctx.currentIA().iaid_ = ia->getIAID();
1765  ctx.currentIA().addHint(hint);
1766  ctx.currentIA().type_ = Lease::TYPE_NA;
1767 
1768  // Use allocation engine to pick a lease for this client. Allocation engine
1769  // will try to honor the hint, but it is just a hint - some other address
1770  // may be used instead. If fake_allocation is set to false, the lease will
1771  // be inserted into the LeaseMgr as well.
1772  Lease6Collection leases = alloc_engine_->allocateLeases6(ctx);
1773 
1775  Lease6Ptr lease;
1776  if (!leases.empty()) {
1777  lease = *leases.begin();
1778  }
1779 
1780  // Create IA_NA that we will put in the response.
1781  // Do not use OptionDefinition to create option's instance so
1782  // as we can initialize IAID using a constructor.
1783  Option6IAPtr ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
1784 
1785  if (lease) {
1786  // We have a lease! Let's wrap its content into IA_NA option
1787  // with IAADDR suboption.
1788  LOG_INFO(lease6_logger, ctx.fake_allocation_ ? DHCP6_LEASE_ADVERT : DHCP6_LEASE_ALLOC)
1789  .arg(query->getLabel())
1790  .arg(lease->addr_.toText())
1791  .arg(ia->getIAID());
1792  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_LEASE_DATA)
1793  .arg(query->getLabel())
1794  .arg(ia->getIAID())
1795  .arg(lease->toText());
1796 
1797  ia_rsp->setT1(subnet->getT1());
1798  ia_rsp->setT2(subnet->getT2());
1799 
1800  Option6IAAddrPtr addr(new Option6IAAddr(D6O_IAADDR, lease->addr_,
1801  lease->preferred_lft_,
1802  lease->valid_lft_));
1803  ia_rsp->addOption(addr);
1804 
1805  // It would be possible to insert status code=0(success) as well,
1806  // but this is considered waste of bandwidth as absence of status
1807  // code is considered a success.
1808 
1809  } else {
1810  // Allocation engine did not allocate a lease. The engine logged
1811  // cause of that failure. The only thing left is to insert
1812  // status code to pass the sad news to the client.
1813 
1815  DHCP6_LEASE_ADVERT_FAIL : DHCP6_LEASE_ALLOC_FAIL)
1816  .arg(query->getLabel())
1817  .arg(ia->getIAID());
1818 
1819  ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
1821  "Sorry, no address could be"
1822  " allocated."));
1823  }
1824  return (ia_rsp);
1825 }
1826 
1827 OptionPtr
1828 Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query, const Pkt6Ptr& /*answer*/,
1830  boost::shared_ptr<Option6IA> ia) {
1831 
1832  // Check if the client sent us a hint in his IA_PD. Clients may send an
1833  // address in their IA_PD options as a suggestion (e.g. the last address
1834  // they used before). While the hint consists of a full prefix (prefix +
1835  // length), getting just the prefix is sufficient to identify a lease.
1836  Option6IAPrefixPtr hint_opt =
1837  boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(D6O_IAPREFIX));
1839  if (hint_opt) {
1840  hint = hint_opt->getAddress();
1841  }
1842 
1843  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_REQUEST)
1844  .arg(query->getLabel())
1845  .arg(ia->getIAID())
1846  .arg(hint_opt ? hint.toText() : "(no hint)");
1847 
1848 
1849  const Subnet6Ptr& subnet = ctx.subnet_;
1850 
1851  // Create IA_PD that we will put in the response.
1852  // Do not use OptionDefinition to create option's instance so
1853  // as we can initialize IAID using a constructor.
1854  boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
1855 
1856  // If there is no subnet selected for handling this IA_PD, the only thing
1857  // left to do is to say that we are sorry, but the user won't get an address.
1858  // As a convenience, we use a different status text to indicate that
1859  // (compare to the same status code, but different wording below)
1860  if (!subnet) {
1861 
1862  // Insert status code NoAddrsAvail.
1863  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoPrefixAvail,
1864  "Sorry, no subnet available."));
1865  return (ia_rsp);
1866  }
1867 
1868  // Set per-IA context values.
1869  ctx.createIAContext();
1870  ctx.currentIA().iaid_ = ia->getIAID();
1871  ctx.currentIA().addHint(hint);
1872  ctx.currentIA().type_ = Lease::TYPE_PD;
1873 
1874  // Use allocation engine to pick a lease for this client. Allocation engine
1875  // will try to honor the hint, but it is just a hint - some other address
1876  // may be used instead. If fake_allocation is set to false, the lease will
1877  // be inserted into the LeaseMgr as well.
1878  Lease6Collection leases = alloc_engine_->allocateLeases6(ctx);
1879 
1880  if (!leases.empty()) {
1881 
1882  ia_rsp->setT1(subnet->getT1());
1883  ia_rsp->setT2(subnet->getT2());
1884 
1885  const bool pd_exclude_requested = requestedInORO(query, D6O_PD_EXCLUDE);
1886 
1887  for (Lease6Collection::iterator l = leases.begin();
1888  l != leases.end(); ++l) {
1889 
1890  // We have a lease! Let's wrap its content into IA_PD option
1891  // with IAADDR suboption.
1893  DHCP6_PD_LEASE_ADVERT : DHCP6_PD_LEASE_ALLOC)
1894  .arg(query->getLabel())
1895  .arg((*l)->addr_.toText())
1896  .arg(static_cast<int>((*l)->prefixlen_))
1897  .arg(ia->getIAID());
1898 
1899  boost::shared_ptr<Option6IAPrefix>
1900  addr(new Option6IAPrefix(D6O_IAPREFIX, (*l)->addr_,
1901  (*l)->prefixlen_, (*l)->preferred_lft_,
1902  (*l)->valid_lft_));
1903  ia_rsp->addOption(addr);
1904 
1905  if (pd_exclude_requested) {
1906  // PD exclude option has been requested via ORO, thus we need to
1907  // include it if the pool configuration specifies this option.
1908  Pool6Ptr pool = boost::dynamic_pointer_cast<
1909  Pool6>(subnet->getPool(Lease::TYPE_PD, (*l)->addr_));
1910  if (pool) {
1911  Option6PDExcludePtr pd_exclude_option = pool->getPrefixExcludeOption();
1912  if (pd_exclude_option) {
1913  addr->addOption(pd_exclude_option);
1914  }
1915  }
1916  }
1917  }
1918 
1919  // It would be possible to insert status code=0(success) as well,
1920  // but this is considered waste of bandwidth as absence of status
1921  // code is considered a success.
1922 
1923  } else {
1924  // Allocation engine did not allocate a lease. The engine logged
1925  // cause of that failure. The only thing left is to insert
1926  // status code to pass the sad news to the client.
1927 
1929  DHCP6_PD_LEASE_ADVERT_FAIL : DHCP6_PD_LEASE_ALLOC_FAIL)
1930  .arg(query->getLabel())
1931  .arg(ia->getIAID());
1932 
1933  ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
1935  "Sorry, no prefixes could"
1936  " be allocated."));
1937  }
1938  return (ia_rsp);
1939 }
1940 
1941 OptionPtr
1942 Dhcpv6Srv::extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
1944  boost::shared_ptr<Option6IA> ia) {
1945 
1946  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_NA_EXTEND)
1947  .arg(query->getLabel())
1948  .arg(ia->getIAID());
1949 
1950  // convenience values
1951  const Subnet6Ptr& subnet = ctx.subnet_;
1952 
1953  // Create empty IA_NA option with IAID matching the request.
1954  Option6IAPtr ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
1955 
1956  if (!subnet) {
1966  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
1967  "Sorry, no known leases for this duid/iaid."));
1968  return (ia_rsp);
1969  }
1970 
1971  // Set up T1, T2 timers
1972  ia_rsp->setT1(subnet->getT1());
1973  ia_rsp->setT2(subnet->getT2());
1974 
1975  // Get DDNS update directions
1976  bool do_fwd = false;
1977  bool do_rev = false;
1978  Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
1979  Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
1980  if (fqdn) {
1982  do_fwd, do_rev);
1983  }
1984 
1985  // Set per-packet context values.
1986  ctx.fwd_dns_update_ = do_fwd;
1987  ctx.rev_dns_update_ = do_rev;
1988 
1989  // Set per-IA context values.
1990  ctx.createIAContext();
1991  ctx.currentIA().iaid_ = ia->getIAID();
1992  ctx.currentIA().type_ = Lease::TYPE_NA;
1993  ctx.currentIA().ia_rsp_ = ia_rsp;
1994 
1995  // Extract the addresses that the client is trying to obtain.
1996  OptionCollection addrs = ia->getOptions();
1997  for (OptionCollection::const_iterator it = addrs.begin();
1998  it != addrs.end(); ++it) {
1999  if (it->second->getType() != D6O_IAADDR) {
2000  continue;
2001  }
2002  Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>(it->second);
2003  if (!iaaddr) {
2004  // That's weird. Option code was ok, but the object type was not.
2005  // This should never happen. The only case would be with badly
2006  // mis-implemented hook libraries that insert invalid option objects.
2007  // There's no way to protect against this.
2008  continue;
2009  }
2010  ctx.currentIA().addHint(iaaddr->getAddress());
2011  }
2012 
2013  Lease6Collection leases = alloc_engine_->renewLeases6(ctx);
2014 
2015  // Ok, now we have the leases extended. We have:
2016  // - what the client tried to renew in ctx.hints_
2017  // - what we actually assigned in leases
2018  // - old leases that are no longer valid in ctx.old_leases_
2019 
2020  // For each IA inserted by the client we have to determine what to do
2021  // about included addresses and notify the client. We will iterate over
2022  // those prefixes and remove those that we have already processed. We
2023  // don't want to remove them from the context, so we need to copy them
2024  // into temporary container.
2026 
2027  // For all leases we have now, add the IAADDR with non-zero lifetimes.
2028  for (Lease6Collection::const_iterator l = leases.begin(); l != leases.end(); ++l) {
2030  (*l)->addr_, (*l)->preferred_lft_, (*l)->valid_lft_));
2031  ia_rsp->addOption(iaaddr);
2032  LOG_INFO(lease6_logger, DHCP6_LEASE_RENEW)
2033  .arg(query->getLabel())
2034  .arg((*l)->addr_.toText())
2035  .arg(ia_rsp->getIAID());
2036 
2037  // Now remove this address from the hints list.
2038  AllocEngine::ResourceType hint_type((*l)->addr_, 128);
2039  hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
2040  hints.end());
2041  }
2042 
2043  // For the leases that we just retired, send the addresses with 0 lifetimes.
2044  for (Lease6Collection::const_iterator l = ctx.currentIA().old_leases_.begin();
2045  l != ctx.currentIA().old_leases_.end(); ++l) {
2046 
2047  // Send an address with zero lifetimes only when this lease belonged to
2048  // this client. Do not send it when we're reusing an old lease that belonged
2049  // to someone else.
2050  if (equalValues(query->getClientId(), (*l)->duid_)) {
2052  (*l)->addr_, 0, 0));
2053  ia_rsp->addOption(iaaddr);
2054  }
2055 
2056  // Now remove this address from the hints list.
2057  AllocEngine::ResourceType hint_type((*l)->addr_, 128);
2058  hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
2059 
2060  // If the new FQDN settings have changed for the lease, we need to
2061  // delete any existing FQDN records for this lease.
2062  if (((*l)->hostname_ != ctx.hostname_) || ((*l)->fqdn_fwd_ != do_fwd) ||
2063  ((*l)->fqdn_rev_ != do_rev)) {
2065  DHCP6_DDNS_LEASE_RENEW_FQDN_CHANGE)
2066  .arg(query->getLabel())
2067  .arg((*l)->toText())
2068  .arg(ctx.hostname_)
2069  .arg(do_rev ? "true" : "false")
2070  .arg(do_fwd ? "true" : "false");
2071 
2072  queueNCR(CHG_REMOVE, *l);
2073  }
2074  }
2075 
2076  // Finally, if there are any addresses requested that we haven't dealt with
2077  // already, inform the client that he can't have them.
2078  for (AllocEngine::HintContainer::const_iterator hint = hints.begin();
2079  hint != hints.end(); ++hint) {
2081  hint->first, 0, 0));
2082  ia_rsp->addOption(iaaddr);
2083  }
2084 
2085  // All is left is to insert the status code.
2086  if (leases.empty()) {
2087 
2088  // The server wasn't able allocate new lease and renew an existing
2089  // lease. In that case, the server sends NoAddrsAvail per RFC 8415.
2090  ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2092  "Sorry, no addresses could be"
2093  " assigned at this time."));
2094  }
2095 
2096  return (ia_rsp);
2097 }
2098 
2099 OptionPtr
2102  boost::shared_ptr<Option6IA> ia) {
2103 
2104  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_EXTEND)
2105  .arg(query->getLabel())
2106  .arg(ia->getIAID());
2107 
2108  const Subnet6Ptr& subnet = ctx.subnet_;
2109  const DuidPtr& duid = ctx.duid_;
2110 
2111  // Let's create a IA_PD response and fill it in later
2112  Option6IAPtr ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
2113 
2114  // If there is no subnet for the particular client, we can't retrieve
2115  // information about client's leases from lease database. We treat this
2116  // as no binding for the client.
2117  if (!subnet) {
2118  // Per RFC 8415, section 18.3.4, if there is no binding and we are
2119  // processing a Renew, the NoBinding status code should be returned.
2120  if (query->getType() == DHCPV6_RENEW) {
2121  // Insert status code NoBinding
2122  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2123  "Sorry, no known PD leases"
2124  " for this duid/iaid."));
2125  return (ia_rsp);
2126 
2127  // Per RFC 8415, section 18.3.5, if there is no binding and we are
2128  // processing Rebind, the message has to be discarded (assuming that
2129  // the server doesn't know if the prefix in the IA_PD option is
2130  // appropriate for the client's link). The exception being thrown
2131  // here should propagate to the main loop and cause the message to
2132  // be discarded.
2133  } else {
2134 
2143  isc_throw(DHCPv6DiscardMessageError, "no subnet found for the"
2144  " client sending Rebind to extend lifetime of the"
2145  " prefix (DUID=" << duid->toText() << ", IAID="
2146  << ia->getIAID() << ")");
2147  }
2148  }
2149 
2150  // Set up T1, T2 timers
2151  ia_rsp->setT1(subnet->getT1());
2152  ia_rsp->setT2(subnet->getT2());
2153 
2154  // Set per-IA context values.
2155  ctx.createIAContext();
2156  ctx.currentIA().iaid_ = ia->getIAID();
2157  ctx.currentIA().type_ = Lease::TYPE_PD;
2158  ctx.currentIA().ia_rsp_ = ia_rsp;
2159 
2160  // Extract prefixes that the client is trying to renew.
2161  OptionCollection addrs = ia->getOptions();
2162  for (OptionCollection::const_iterator it = addrs.begin();
2163  it != addrs.end(); ++it) {
2164  if (it->second->getType() != D6O_IAPREFIX) {
2165  continue;
2166  }
2167  Option6IAPrefixPtr prf = boost::dynamic_pointer_cast<Option6IAPrefix>(it->second);
2168  if (!prf) {
2169  // That's weird. Option code was ok, but the object type was not.
2170  // This should never happen. The only case would be with badly
2171  // mis-implemented hook libraries that insert invalid option objects.
2172  // There's no way to protect against this.
2173  continue;
2174  }
2175 
2176  // Put the client's prefix into the hints list.
2177  ctx.currentIA().addHint(prf->getAddress(), prf->getLength());
2178  }
2179 
2180  // Call Allocation Engine and attempt to renew leases. Number of things
2181  // may happen. Leases may be extended, revoked (if the lease is no longer
2182  // valid or reserved for someone else), or new leases may be added.
2183  // Important parameters are:
2184  // - returned container - current valid leases
2185  // - old_leases - leases that used to be, but are no longer valid
2186  // - changed_leases - leases that have FQDN changed (not really important
2187  // in PD context)
2188  Lease6Collection leases = alloc_engine_->renewLeases6(ctx);
2189 
2190  // For each IA inserted by the client we have to determine what to do
2191  // about included prefixes and notify the client. We will iterate over
2192  // those prefixes and remove those that we have already processed. We
2193  // don't want to remove them from the context, so we need to copy them
2194  // into temporary container.
2196 
2197  const bool pd_exclude_requested = requestedInORO(query, D6O_PD_EXCLUDE);
2198 
2199  // For all the leases we have now, add the IAPREFIX with non-zero lifetimes
2200  for (Lease6Collection::const_iterator l = leases.begin(); l != leases.end(); ++l) {
2201 
2203  (*l)->addr_, (*l)->prefixlen_,
2204  (*l)->preferred_lft_, (*l)->valid_lft_));
2205  ia_rsp->addOption(prf);
2206 
2207 
2208  if (pd_exclude_requested) {
2209  // PD exclude option has been requested via ORO, thus we need to
2210  // include it if the pool configuration specifies this option.
2211  Pool6Ptr pool = boost::dynamic_pointer_cast<
2212  Pool6>(subnet->getPool(Lease::TYPE_PD, (*l)->addr_));
2213 
2214  if (pool) {
2215  Option6PDExcludePtr pd_exclude_option = pool->getPrefixExcludeOption();
2216  if (pd_exclude_option) {
2217  prf->addOption(pd_exclude_option);
2218  }
2219  }
2220  }
2221 
2222 
2223  LOG_INFO(lease6_logger, DHCP6_PD_LEASE_RENEW)
2224  .arg(query->getLabel())
2225  .arg((*l)->addr_.toText())
2226  .arg(static_cast<int>((*l)->prefixlen_))
2227  .arg(ia->getIAID());
2228 
2229  // Now remove this prefix from the hints list.
2230  AllocEngine::ResourceType hint_type((*l)->addr_, (*l)->prefixlen_);
2231  hints.erase(std::remove(hints.begin(), hints.end(), hint_type),
2232  hints.end());
2233  }
2234 
2236  for (Lease6Collection::const_iterator l = ctx.currentIA().old_leases_.begin();
2237  l != ctx.currentIA().old_leases_.end(); ++l) {
2238 
2239  // Send a prefix with zero lifetimes only when this lease belonged to
2240  // this client. Do not send it when we're reusing an old lease that belonged
2241  // to someone else.
2242  if (equalValues(query->getClientId(), (*l)->duid_)) {
2243  Option6IAPrefixPtr prefix(new Option6IAPrefix(D6O_IAPREFIX, (*l)->addr_,
2244  (*l)->prefixlen_, 0, 0));
2245  ia_rsp->addOption(prefix);
2246  }
2247 
2248  // Now remove this prefix from the hints list.
2249  AllocEngine::ResourceType hint_type((*l)->addr_, (*l)->prefixlen_);
2250  hints.erase(std::remove(hints.begin(), hints.end(), hint_type), hints.end());
2251  }
2252 
2253  // Finally, if there are any prefixes requested that we haven't dealt with
2254  // already, inform the client that he can't have them.
2255  for (AllocEngine::HintContainer::const_iterator prefix = hints.begin();
2256  prefix != hints.end(); ++prefix) {
2257 
2258  // Send the prefix with the zero lifetimes only if the prefix
2259  // contains non-zero value. A zero value indicates that the hint was
2260  // for the prefix length.
2261  if (!prefix->first.isV6Zero()) {
2262  OptionPtr prefix_opt(new Option6IAPrefix(D6O_IAPREFIX, prefix->first,
2263  prefix->second, 0, 0));
2264  ia_rsp->addOption(prefix_opt);
2265  }
2266  }
2267 
2268  // All is left is to insert the status code.
2269  if (leases.empty()) {
2270 
2271  // The server wasn't able allocate new lease and renew an existing
2272  // lease. In that case, the server sends NoPrefixAvail per RFC 8415.
2273  ia_rsp->addOption(createStatusCode(*query, *ia_rsp,
2275  "Sorry, no prefixes could be"
2276  " assigned at this time."));
2277  }
2278 
2279  return (ia_rsp);
2280 }
2281 
2282 void
2285 
2286  // We will try to extend lease lifetime for all IA options in the client's
2287  // Renew or Rebind message.
2289 
2290  // For the lease extension it is critical that the client has sent
2291  // DUID. There is no need to check for the presence of the DUID here
2292  // because we have already checked it in the sanityCheck().
2293 
2294  for (OptionCollection::iterator opt = query->options_.begin();
2295  opt != query->options_.end(); ++opt) {
2296  switch (opt->second->getType()) {
2297  case D6O_IA_NA: {
2298  OptionPtr answer_opt = extendIA_NA(query, reply, ctx,
2299  boost::dynamic_pointer_cast<
2300  Option6IA>(opt->second));
2301  if (answer_opt) {
2302  reply->addOption(answer_opt);
2303  }
2304  break;
2305  }
2306 
2307  case D6O_IA_PD: {
2308  OptionPtr answer_opt = extendIA_PD(query, ctx,
2309  boost::dynamic_pointer_cast<
2310  Option6IA>(opt->second));
2311  if (answer_opt) {
2312  reply->addOption(answer_opt);
2313  }
2314  break;
2315  }
2316 
2317  default:
2318  break;
2319  }
2320  }
2321 }
2322 
2323 void
2326 
2327  // We need to release addresses for all IA options in the client's
2328  // RELEASE message.
2329 
2336 
2337  // Let's set the status to be success by default. We can override it with
2338  // error status if needed. The important thing to understand here is that
2339  // the global status code may be set to success only if all IA options were
2340  // handled properly. Therefore the releaseIA_NA and releaseIA_PD options
2341  // may turn the status code to some error, but can't turn it back to success.
2342  int general_status = STATUS_Success;
2343  for (OptionCollection::iterator opt = release->options_.begin();
2344  opt != release->options_.end(); ++opt) {
2345  Lease6Ptr old_lease;
2346  switch (opt->second->getType()) {
2347  case D6O_IA_NA: {
2348  OptionPtr answer_opt = releaseIA_NA(ctx.duid_, release, general_status,
2349  boost::dynamic_pointer_cast<Option6IA>(opt->second),
2350  old_lease);
2351  if (answer_opt) {
2352  reply->addOption(answer_opt);
2353  }
2354  break;
2355  }
2356  case D6O_IA_PD: {
2357  OptionPtr answer_opt = releaseIA_PD(ctx.duid_, release, general_status,
2358  boost::dynamic_pointer_cast<Option6IA>(opt->second),
2359  old_lease);
2360  if (answer_opt) {
2361  reply->addOption(answer_opt);
2362  }
2363  break;
2364  }
2365  // @todo: add support for IA_TA
2366  default:
2367  // remaining options are stateless and thus ignored in this context
2368  ;
2369  }
2370 
2371  // Store the old lease.
2372  if (old_lease) {
2373  ctx.currentIA().old_leases_.push_back(old_lease);
2374  }
2375  }
2376 
2377  // Include top-level status code as well.
2378  reply->addOption(createStatusCode(*release, general_status,
2379  "Summary status for all processed IA_NAs"));
2380 }
2381 
2382 OptionPtr
2383 Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
2384  int& general_status, boost::shared_ptr<Option6IA> ia,
2385  Lease6Ptr& old_lease) {
2386 
2387  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_NA_RELEASE)
2388  .arg(query->getLabel())
2389  .arg(ia->getIAID());
2390 
2391 
2392  // Release can be done in one of two ways:
2393  // Approach 1: extract address from client's IA_NA and see if it belongs
2394  // to this particular client.
2395  // Approach 2: find a subnet for this client, get a lease for
2396  // this subnet/duid/iaid and check if its content matches to what the
2397  // client is asking us to release.
2398  //
2399  // This method implements approach 1.
2400 
2401  // That's our response
2402  boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
2403 
2404  Option6IAAddrPtr release_addr = boost::dynamic_pointer_cast<Option6IAAddr>
2405  (ia->getOption(D6O_IAADDR));
2406  if (!release_addr) {
2407  ia_rsp->addOption(createStatusCode(*query, STATUS_NoBinding,
2408  "You did not include an address in your RELEASE"));
2409  general_status = STATUS_NoBinding;
2410  return (ia_rsp);
2411  }
2412 
2414  release_addr->getAddress());
2415 
2416  if (!lease) {
2417  // client releasing a lease that we don't know about.
2418 
2419  // Insert status code NoBinding.
2420  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2421  "Sorry, no known leases for this duid/iaid, can't release."));
2422  general_status = STATUS_NoBinding;
2423 
2424  return (ia_rsp);
2425  }
2426 
2427  if (!lease->duid_) {
2428  // Something is gravely wrong here. We do have a lease, but it does not
2429  // have mandatory DUID information attached. Someone was messing with our
2430  // database.
2431 
2432  LOG_ERROR(lease6_logger, DHCP6_LEASE_NA_WITHOUT_DUID)
2433  .arg(query->getLabel())
2434  .arg(release_addr->getAddress().toText());
2435 
2436  general_status = STATUS_UnspecFail;
2437  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_UnspecFail,
2438  "Database consistency check failed when trying to RELEASE"));
2439  return (ia_rsp);
2440  }
2441 
2442  if (*duid != *(lease->duid_)) {
2443 
2444  // Sorry, it's not your address. You can't release it.
2445  LOG_INFO(lease6_logger, DHCP6_RELEASE_NA_FAIL_WRONG_DUID)
2446  .arg(query->getLabel())
2447  .arg(release_addr->getAddress().toText())
2448  .arg(lease->duid_->toText());
2449 
2450  general_status = STATUS_NoBinding;
2451  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2452  "This address does not belong to you, you can't release it"));
2453  return (ia_rsp);
2454  }
2455 
2456  if (ia->getIAID() != lease->iaid_) {
2457  // This address belongs to this client, but to a different IA
2458  LOG_WARN(lease6_logger, DHCP6_RELEASE_NA_FAIL_WRONG_IAID)
2459  .arg(query->getLabel())
2460  .arg(release_addr->getAddress().toText())
2461  .arg(lease->iaid_)
2462  .arg(ia->getIAID());
2463  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2464  "This is your address, but you used wrong IAID"));
2465  general_status = STATUS_NoBinding;
2466  return (ia_rsp);
2467  }
2468 
2469  // It is not necessary to check if the address matches as we used
2470  // getLease6(addr) method that is supposed to return a proper lease.
2471 
2472  bool skip = false;
2473  // Execute all callouts registered for packet6_send
2474  if (HooksManager::calloutsPresent(Hooks.hook_index_lease6_release_)) {
2475  CalloutHandlePtr callout_handle = getCalloutHandle(query);
2476 
2477  // Use the RAII wrapper to make sure that the callout handle state is
2478  // reset when this object goes out of scope. All hook points must do
2479  // it to prevent possible circular dependency between the callout
2480  // handle and its arguments.
2481  ScopedCalloutHandleState callout_handle_state(callout_handle);
2482 
2483  // Enable copying options from the packet within hook library.
2484  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
2485 
2486  // Delete all previous arguments
2487  callout_handle->deleteAllArguments();
2488 
2489  // Pass the original packet
2490  callout_handle->setArgument("query6", query);
2491 
2492  // Pass the lease to be updated
2493  callout_handle->setArgument("lease6", lease);
2494 
2495  // Call all installed callouts
2496  HooksManager::callCallouts(Hooks.hook_index_lease6_release_, *callout_handle);
2497 
2498  // Callouts decided to skip the next processing step. The next
2499  // processing step would to send the packet, so skip at this
2500  // stage means "drop response".
2501  if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
2502  (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
2503  skip = true;
2504  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_NA_SKIP)
2505  .arg(query->getLabel());
2506  }
2507  }
2508 
2509  // Ok, we've passed all checks. Let's release this address.
2510  bool success = false; // was the removal operation successful?
2511 
2512  if (!skip) {
2513  success = LeaseMgrFactory::instance().deleteLease(lease->addr_);
2514  }
2515 
2516  // Here the success should be true if we removed lease successfully
2517  // and false if skip flag was set or the removal failed for whatever reason
2518 
2519  if (!success) {
2520  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_UnspecFail,
2521  "Server failed to release a lease"));
2522 
2523  LOG_ERROR(lease6_logger, DHCP6_RELEASE_NA_FAIL)
2524  .arg(query->getLabel())
2525  .arg(lease->addr_.toText())
2526  .arg(lease->iaid_);
2527  general_status = STATUS_UnspecFail;
2528 
2529  return (ia_rsp);
2530  } else {
2531  old_lease = lease;
2532 
2533  LOG_INFO(lease6_logger, DHCP6_RELEASE_NA)
2534  .arg(query->getLabel())
2535  .arg(lease->addr_.toText())
2536  .arg(lease->iaid_);
2537 
2538  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_Success,
2539  "Lease released. Thank you, please come again."));
2540 
2541  // Need to decrease statistic for assigned addresses.
2542  StatsMgr::instance().addValue(
2543  StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-nas"),
2544  static_cast<int64_t>(-1));
2545 
2546  // Check if a lease has flags indicating that the FQDN update has
2547  // been performed. If so, create NameChangeRequest which removes
2548  // the entries.
2549  queueNCR(CHG_REMOVE, lease);
2550 
2551  return (ia_rsp);
2552  }
2553 }
2554 
2555 OptionPtr
2556 Dhcpv6Srv::releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
2557  int& general_status, boost::shared_ptr<Option6IA> ia,
2558  Lease6Ptr& old_lease) {
2559  // Release can be done in one of two ways:
2560  // Approach 1: extract address from client's IA_NA and see if it belongs
2561  // to this particular client.
2562  // Approach 2: find a subnet for this client, get a lease for
2563  // this subnet/duid/iaid and check if its content matches to what the
2564  // client is asking us to release.
2565  //
2566  // This method implements approach 1.
2567 
2568  // That's our response. We will fill it in as we check the lease to be
2569  // released.
2570  boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
2571 
2572  boost::shared_ptr<Option6IAPrefix> release_prefix =
2573  boost::dynamic_pointer_cast<Option6IAPrefix>(ia->getOption(D6O_IAPREFIX));
2574  if (!release_prefix) {
2575  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2576  "You did not include a prefix in your RELEASE"));
2577  general_status = STATUS_NoBinding;
2578  return (ia_rsp);
2579  }
2580 
2582  release_prefix->getAddress());
2583 
2584  if (!lease) {
2585  // Client releasing a lease that we don't know about.
2586 
2587  // Insert status code NoBinding.
2588  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2589  "Sorry, no known leases for this duid/iaid, can't release."));
2590  general_status = STATUS_NoBinding;
2591 
2592  return (ia_rsp);
2593  }
2594 
2595  if (!lease->duid_) {
2596  // Something is gravely wrong here. We do have a lease, but it does not
2597  // have mandatory DUID information attached. Someone was messing with our
2598  // database.
2599  LOG_ERROR(lease6_logger, DHCP6_LEASE_PD_WITHOUT_DUID)
2600  .arg(query->getLabel())
2601  .arg(release_prefix->getAddress().toText())
2602  .arg(static_cast<int>(release_prefix->getLength()));
2603 
2604  general_status = STATUS_UnspecFail;
2605  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_UnspecFail,
2606  "Database consistency check failed when trying to RELEASE"));
2607  return (ia_rsp);
2608  }
2609 
2610  if (*duid != *(lease->duid_)) {
2611  // Sorry, it's not your address. You can't release it.
2612  LOG_INFO(lease6_logger, DHCP6_RELEASE_PD_FAIL_WRONG_DUID)
2613  .arg(query->getLabel())
2614  .arg(release_prefix->getAddress().toText())
2615  .arg(static_cast<int>(release_prefix->getLength()))
2616  .arg(lease->duid_->toText());
2617 
2618  general_status = STATUS_NoBinding;
2619  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2620  "This address does not belong to you, you can't release it"));
2621  return (ia_rsp);
2622  }
2623 
2624  if (ia->getIAID() != lease->iaid_) {
2625  // This address belongs to this client, but to a different IA
2626  LOG_WARN(lease6_logger, DHCP6_RELEASE_PD_FAIL_WRONG_IAID)
2627  .arg(query->getLabel())
2628  .arg(release_prefix->getAddress().toText())
2629  .arg(static_cast<int>(release_prefix->getLength()))
2630  .arg(lease->iaid_)
2631  .arg(ia->getIAID());
2632  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_NoBinding,
2633  "This is your address, but you used wrong IAID"));
2634  general_status = STATUS_NoBinding;
2635  return (ia_rsp);
2636  }
2637 
2638  // It is not necessary to check if the address matches as we used
2639  // getLease6(addr) method that is supposed to return a proper lease.
2640 
2641  bool skip = false;
2642  // Execute all callouts registered for packet6_send
2643  if (HooksManager::calloutsPresent(Hooks.hook_index_lease6_release_)) {
2644  CalloutHandlePtr callout_handle = getCalloutHandle(query);
2645 
2646  // Use the RAII wrapper to make sure that the callout handle state is
2647  // reset when this object goes out of scope. All hook points must do
2648  // it to prevent possible circular dependency between the callout
2649  // handle and its arguments.
2650  ScopedCalloutHandleState callout_handle_state(callout_handle);
2651 
2652  // Enable copying options from the packet within hook library.
2653  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
2654 
2655  // Pass the original packet
2656  callout_handle->setArgument("query6", query);
2657 
2658  // Pass the lease to be updated
2659  callout_handle->setArgument("lease6", lease);
2660 
2661  // Call all installed callouts
2662  HooksManager::callCallouts(Hooks.hook_index_lease6_release_, *callout_handle);
2663 
2664  skip = callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP;
2665  }
2666 
2667  // Ok, we've passed all checks. Let's release this prefix.
2668  bool success = false; // was the removal operation successful?
2669 
2670  if (!skip) {
2671  success = LeaseMgrFactory::instance().deleteLease(lease->addr_);
2672  } else {
2673  // Callouts decided to skip the next processing step. The next
2674  // processing step would to send the packet, so skip at this
2675  // stage means "drop response".
2676  LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_LEASE6_RELEASE_PD_SKIP)
2677  .arg(query->getLabel());
2678  }
2679 
2680  // Here the success should be true if we removed lease successfully
2681  // and false if skip flag was set or the removal failed for whatever reason
2682 
2683  if (!success) {
2684  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_UnspecFail,
2685  "Server failed to release a lease"));
2686 
2687  LOG_ERROR(lease6_logger, DHCP6_RELEASE_PD_FAIL)
2688  .arg(query->getLabel())
2689  .arg(lease->addr_.toText())
2690  .arg(static_cast<int>(lease->prefixlen_))
2691  .arg(lease->iaid_);
2692  general_status = STATUS_UnspecFail;
2693 
2694  } else {
2695  old_lease = lease;
2696 
2697  LOG_INFO(lease6_logger, DHCP6_RELEASE_PD)
2698  .arg(query->getLabel())
2699  .arg(lease->addr_.toText())
2700  .arg(static_cast<int>(lease->prefixlen_))
2701  .arg(lease->iaid_);
2702 
2703  ia_rsp->addOption(createStatusCode(*query, *ia_rsp, STATUS_Success,
2704  "Lease released. Thank you, please come again."));
2705 
2706  // Need to decrease statistic for assigned prefixes.
2707  StatsMgr::instance().addValue(
2708  StatsMgr::generateName("subnet", lease->subnet_id_, "assigned-pds"),
2709  static_cast<int64_t>(-1));
2710  }
2711 
2712  return (ia_rsp);
2713 }
2714 
2715 
2716 Pkt6Ptr
2718 
2719  Pkt6Ptr solicit = ctx.query_;
2720  Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
2721 
2722  // Handle Rapid Commit option, if present.
2723  if (ctx.subnet_ && ctx.subnet_->getRapidCommit()) {
2724  OptionPtr opt_rapid_commit = solicit->getOption(D6O_RAPID_COMMIT);
2725  if (opt_rapid_commit) {
2726 
2727  LOG_DEBUG(options6_logger, DBG_DHCP6_DETAIL, DHCP6_RAPID_COMMIT)
2728  .arg(solicit->getLabel());
2729 
2730  // If Rapid Commit has been sent by the client, change the
2731  // response type to Reply and include Rapid Commit option.
2732  response->setType(DHCPV6_REPLY);
2733  response->addOption(opt_rapid_commit);
2734  }
2735  }
2736 
2737  // "Fake" allocation is the case when the server is processing the Solicit
2738  // message without the Rapid Commit option and advertises a lease to
2739  // the client, but doesn't commit this lease to the lease database. If
2740  // the Solicit contains the Rapid Commit option and the server is
2741  // configured to honor the Rapid Commit option, or the client has sent
2742  // the Request message, the lease will be committed to the lease
2743  // database. The type of the server's response may be used to determine
2744  // if this is the fake allocation case or not. When the server sends
2745  // Reply message it means that it is committing leases. Other message
2746  // type (Advertise) means that server is not committing leases (fake
2747  // allocation).
2748  ctx.fake_allocation_ = (response->getType() != DHCPV6_REPLY);
2749 
2750  processClientFqdn(solicit, response, ctx);
2751  assignLeases(solicit, response, ctx);
2752 
2753  setReservedClientClasses(solicit, ctx);
2754  requiredClassify(solicit, ctx);
2755 
2756  copyClientOptions(solicit, response);
2757  CfgOptionList co_list;
2758  buildCfgOptionList(solicit, ctx, co_list);
2759  appendDefaultOptions(solicit, response, co_list);
2760  appendRequestedOptions(solicit, response, co_list);
2761  appendRequestedVendorOptions(solicit, response, ctx, co_list);
2762 
2763  updateReservedFqdn(ctx, response);
2764 
2765  // Only generate name change requests if sending a Reply as a result
2766  // of receiving Rapid Commit option.
2767  if (response->getType() == DHCPV6_REPLY) {
2768  createNameChangeRequests(response, ctx);
2769  }
2770 
2771  return (response);
2772 }
2773 
2774 Pkt6Ptr
2776 
2777  Pkt6Ptr request = ctx.query_;
2778  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
2779 
2780  processClientFqdn(request, reply, ctx);
2781  assignLeases(request, reply, ctx);
2782 
2783  setReservedClientClasses(request, ctx);
2784  requiredClassify(request, ctx);
2785 
2786  copyClientOptions(request, reply);
2787  CfgOptionList co_list;
2788  buildCfgOptionList(request, ctx, co_list);
2789  appendDefaultOptions(request, reply, co_list);
2790  appendRequestedOptions(request, reply, co_list);
2791  appendRequestedVendorOptions(request, reply, ctx, co_list);
2792 
2793  updateReservedFqdn(ctx, reply);
2794  generateFqdn(reply);
2795  createNameChangeRequests(reply, ctx);
2796 
2797  return (reply);
2798 }
2799 
2800 Pkt6Ptr
2802 
2803  Pkt6Ptr renew = ctx.query_;
2804  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
2805 
2806  processClientFqdn(renew, reply, ctx);
2807  extendLeases(renew, reply, ctx);
2808 
2809  setReservedClientClasses(renew, ctx);
2810  requiredClassify(renew, ctx);
2811 
2812  copyClientOptions(renew, reply);
2813  CfgOptionList co_list;
2814  buildCfgOptionList(renew, ctx, co_list);
2815  appendDefaultOptions(renew, reply, co_list);
2816  appendRequestedOptions(renew, reply, co_list);
2817  appendRequestedVendorOptions(renew, reply, ctx, co_list);
2818 
2819  updateReservedFqdn(ctx, reply);
2820  generateFqdn(reply);
2821  createNameChangeRequests(reply, ctx);
2822 
2823  return (reply);
2824 }
2825 
2826 Pkt6Ptr
2828 
2829  Pkt6Ptr rebind = ctx.query_;
2830  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
2831 
2832  processClientFqdn(rebind, reply, ctx);
2833  extendLeases(rebind, reply, ctx);
2834 
2835  setReservedClientClasses(rebind, ctx);
2836  requiredClassify(rebind, ctx);
2837 
2838  copyClientOptions(rebind, reply);
2839  CfgOptionList co_list;
2840  buildCfgOptionList(rebind, ctx, co_list);
2841  appendDefaultOptions(rebind, reply, co_list);
2842  appendRequestedOptions(rebind, reply, co_list);
2843  appendRequestedVendorOptions(rebind, reply, ctx, co_list);
2844 
2845  updateReservedFqdn(ctx, reply);
2846  generateFqdn(reply);
2847  createNameChangeRequests(reply, ctx);
2848 
2849  return (reply);
2850 }
2851 
2852 Pkt6Ptr
2854 
2855  Pkt6Ptr confirm = ctx.query_;
2856  setReservedClientClasses(confirm, ctx);
2857  requiredClassify(confirm, ctx);
2858 
2859  // Get IA_NAs from the Confirm. If there are none, the message is
2860  // invalid and must be discarded. There is nothing more to do.
2861  OptionCollection ias = confirm->getOptions(D6O_IA_NA);
2862  if (ias.empty()) {
2863  return (Pkt6Ptr());
2864  }
2865 
2866  // The server sends Reply message in response to Confirm.
2867  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
2868  // Make sure that the necessary options are included.
2869  copyClientOptions(confirm, reply);
2870  CfgOptionList co_list;
2871  buildCfgOptionList(confirm, ctx, co_list);
2872  appendDefaultOptions(confirm, reply, co_list);
2873  appendRequestedOptions(confirm, reply, co_list);
2874  appendRequestedVendorOptions(confirm, reply, ctx, co_list);
2875  // Indicates if at least one address has been verified. If no addresses
2876  // are verified it means that the client has sent no IA_NA options
2877  // or no IAAddr options and that client's message has to be discarded.
2878  bool verified = false;
2879  // Check if subnet was selected for the message. If no subnet
2880  // has been selected, the client is not on link.
2881  SubnetPtr subnet = ctx.subnet_;
2882 
2883  // Regardless if the subnet has been selected or not, we will iterate
2884  // over the IA_NA options to check if they hold any addresses. If there
2885  // are no, the Confirm is discarded.
2886  // Check addresses in IA_NA options and make sure they are appropriate.
2887  for (OptionCollection::const_iterator ia = ias.begin();
2888  ia != ias.end(); ++ia) {
2889  const OptionCollection& opts = ia->second->getOptions();
2890  for (OptionCollection::const_iterator opt = opts.begin();
2891  opt != opts.end(); ++opt) {
2892  // Ignore options other than IAAddr.
2893  if (opt->second->getType() == D6O_IAADDR) {
2894  // Check that the address is in range in the subnet selected.
2895  Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<
2896  Option6IAAddr>(opt->second);
2897  // If there is subnet selected and the address has been included
2898  // in IA_NA, mark it verified and verify that it belongs to the
2899  // subnet.
2900  if (iaaddr) {
2901  // If at least one address is not in range, then return
2902  // the NotOnLink status code.
2903  if (subnet && !subnet->inRange(iaaddr->getAddress())) {
2904  std::ostringstream status_msg;
2905  status_msg << "Address " << iaaddr->getAddress()
2906  << " is not on link.";
2907  reply->addOption(createStatusCode(*confirm,
2909  status_msg.str()));
2910  return (reply);
2911  }
2912  verified = true;
2913  } else {
2914  isc_throw(Unexpected, "failed to cast the IA Address option"
2915  " to the Option6IAAddrPtr. This is programming"
2916  " error and should be reported");
2917  }
2918  }
2919  }
2920  }
2921 
2922  // It seems that the client hasn't included any addresses in which case
2923  // the Confirm must be discarded.
2924  if (!verified) {
2925  return (Pkt6Ptr());
2926  }
2927 
2928  // If there is a subnet, there were addresses in IA_NA options and the
2929  // addresses where consistent with the subnet then the client is on link.
2930  if (subnet) {
2931  // All addresses in range, so return success.
2932  reply->addOption(createStatusCode(*confirm, STATUS_Success,
2933  "All addresses are on-link"));
2934  } else {
2935  reply->addOption(createStatusCode(*confirm, STATUS_NotOnLink,
2936  "No subnet selected"));
2937  }
2938 
2939  return (reply);
2940 }
2941 
2942 Pkt6Ptr
2944 
2945  Pkt6Ptr release = ctx.query_;
2946  setReservedClientClasses(release, ctx);
2947  requiredClassify(release, ctx);
2948 
2949  // Create an empty Reply message.
2950  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
2951 
2952  // Copy client options (client-id, also relay information if present)
2953  copyClientOptions(release, reply);
2954 
2955  // Get the configured option list
2956  CfgOptionList co_list;
2957  // buildCfgOptionList(release, ctx, co_list);
2958  appendDefaultOptions(release, reply, co_list);
2959 
2960  releaseLeases(release, reply, ctx);
2961 
2964 
2965  return (reply);
2966 }
2967 
2968 Pkt6Ptr
2970 
2971  Pkt6Ptr decline = ctx.query_;
2972  setReservedClientClasses(decline, ctx);
2973  requiredClassify(decline, ctx);
2974 
2975  // Create an empty Reply message.
2976  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
2977 
2978  // Copy client options (client-id, also relay information if present)
2979  copyClientOptions(decline, reply);
2980 
2981  // Get the configured option list
2982  CfgOptionList co_list;
2983  buildCfgOptionList(decline, ctx, co_list);
2984 
2985  // Include server-id
2986  appendDefaultOptions(decline, reply, co_list);
2987 
2988  if (declineLeases(decline, reply, ctx)) {
2989  return (reply);
2990  } else {
2991 
2992  // declineLeases returns false only if the hooks set the next step
2993  // status to DROP. We'll just doing as requested.
2994  return (Pkt6Ptr());
2995  }
2996 }
2997 
2998 bool
3001 
3002  // We need to decline addresses for all IA_NA options in the client's
3003  // DECLINE message.
3004 
3005  // Let's set the status to be success by default. We can override it with
3006  // error status if needed. The important thing to understand here is that
3007  // the global status code may be set to success only if all IA options were
3008  // handled properly. Therefore the declineIA options
3009  // may turn the status code to some error, but can't turn it back to success.
3010  int general_status = STATUS_Success;
3011 
3012  for (OptionCollection::iterator opt = decline->options_.begin();
3013  opt != decline->options_.end(); ++opt) {
3014  switch (opt->second->getType()) {
3015  case D6O_IA_NA: {
3016  OptionPtr answer_opt = declineIA(decline, ctx.duid_, general_status,
3017  boost::dynamic_pointer_cast<Option6IA>(opt->second),
3018  ctx.new_leases_);
3019  if (answer_opt) {
3020 
3021  // We have an answer, let's use it.
3022  reply->addOption(answer_opt);
3023  } else {
3024 
3025  // The only case when declineIA could return NULL is if one of the
3026  // hook callouts set next step status to DROP. We just need to drop
3027  // this packet.
3028  return (false);
3029  }
3030  break;
3031  }
3032  default:
3033  // We don't care for the remaining options
3034  ;
3035  }
3036  }
3037 
3038  return (true);
3039 }
3040 
3041 OptionPtr
3042 Dhcpv6Srv::declineIA(const Pkt6Ptr& decline, const DuidPtr& duid,
3043  int& general_status, boost::shared_ptr<Option6IA> ia,
3044  Lease6Collection& new_leases) {
3045 
3046  LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_DECLINE_PROCESS_IA)
3047  .arg(decline->getLabel())
3048  .arg(ia->getIAID());
3049 
3050  // Decline can be done in one of two ways:
3051  // Approach 1: extract address from client's IA_NA and see if it belongs
3052  // to this particular client.
3053  // Approach 2: find a subnet for this client, get a lease for
3054  // this subnet/duid/iaid and check if its content matches to what the
3055  // client is asking us to decline.
3056  //
3057  // This method implements approach 1.
3058 
3059  // That's our response
3060  boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
3061 
3062  const OptionCollection& opts = ia->getOptions();
3063  int total_addrs = 0; // Let's count the total number of addresses.
3064  for (OptionCollection::const_iterator opt = opts.begin(); opt != opts.end();
3065  ++opt) {
3066 
3067  // Let's ignore nested options other than IAADDR (there shouldn't be anything
3068  // else in IA_NA in Decline message, but let's be on the safe side).
3069  if (opt->second->getType() != D6O_IAADDR) {
3070  continue;
3071  }
3072  Option6IAAddrPtr decline_addr = boost::dynamic_pointer_cast<Option6IAAddr>
3073  (opt->second);
3074  if (!decline_addr) {
3075  continue;
3076  }
3077 
3078  total_addrs++;
3079 
3081  decline_addr->getAddress());
3082 
3083  if (!lease) {
3084  // Client trying to decline a lease that we don't know about.
3085  LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_NO_LEASE)
3086  .arg(decline->getLabel()).arg(decline_addr->getAddress().toText());
3087 
3088  // According to RFC 8415, section 18.3.8:
3089  // "For each IA in the Decline message for which the server has no
3090  // binding information, the server adds an IA option using the IAID
3091  // from the Decline message and includes a Status Code option with
3092  // the value NoBinding in the IA option".
3093  setStatusCode(ia_rsp, createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
3094  "Server does not know about such an address."));
3095 
3096  // In the same section of RFC 8415:
3097  // "The server ignores addresses not assigned to the IAs (though it may"
3098  // choose to log an error if it finds such addresses)."
3099  continue; // There may be other addresses.
3100  }
3101 
3102  if (!lease->duid_) {
3103  // Something is gravely wrong here. We do have a lease, but it does not
3104  // have mandatory DUID information attached. Someone was messing with our
3105  // database.
3106 
3107  LOG_ERROR(lease6_logger, DHCP6_DECLINE_FAIL_LEASE_WITHOUT_DUID)
3108  .arg(decline->getLabel())
3109  .arg(decline_addr->getAddress().toText());
3110 
3111  ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_UnspecFail,
3112  "Database consistency check failed when attempting Decline."));
3113 
3114  continue;
3115  }
3116 
3117  // Ok, there's a sane lease with an address. Let's check if DUID matches first.
3118  if (*duid != *(lease->duid_)) {
3119 
3120  // Sorry, it's not your address. You can't release it.
3121  LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_DUID_MISMATCH)
3122  .arg(decline->getLabel())
3123  .arg(decline_addr->getAddress().toText())
3124  .arg(lease->duid_->toText());
3125 
3126  ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
3127  "This address does not belong to you, you can't decline it"));
3128 
3129  continue;
3130  }
3131 
3132  // Let's check if IAID matches.
3133  if (ia->getIAID() != lease->iaid_) {
3134  // This address belongs to this client, but to a different IA
3135  LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_IAID_MISMATCH)
3136  .arg(decline->getLabel())
3137  .arg(lease->addr_.toText())
3138  .arg(ia->getIAID())
3139  .arg(lease->iaid_);
3140  setStatusCode(ia_rsp, createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
3141  "This is your address, but you used wrong IAID"));
3142 
3143  continue;
3144  }
3145 
3146  // Ok, all is good. Decline this lease.
3147  if (!declineLease(decline, lease, ia_rsp)) {
3148  // declineLease returns false only when hook callouts set the next
3149  // step status to drop. We just propagate the bad news here.
3150  return (OptionPtr());
3151 
3152  } else {
3153  new_leases.push_back(lease);
3154  }
3155  }
3156 
3157  if (total_addrs == 0) {
3158  setStatusCode(ia_rsp, createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
3159  "No addresses sent in IA_NA"));
3160  general_status = STATUS_NoBinding;
3161  }
3162 
3163  return (ia_rsp);
3164 }
3165 
3166 void
3167 Dhcpv6Srv::setStatusCode(boost::shared_ptr<isc::dhcp::Option6IA>& container,
3168  const OptionPtr& status) {
3169  // Let's delete any old status code we may have.
3170  container->delOption(D6O_STATUS_CODE);
3171 
3172  container->addOption(status);
3173 }
3174 
3175 bool
3176 Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
3177  boost::shared_ptr<Option6IA> ia_rsp) {
3178  // We do not want to decrease the assigned-nas at this time. While
3179  // technically a declined address is no longer allocated, the primary usage
3180  // of the assigned-addresses statistic is to monitor pool utilization. Most
3181  // people would forget to include declined-addresses in the calculation,
3182  // and simply do assigned-addresses/total-addresses. This would have a bias
3183  // towards under-representing pool utilization, if we decreased allocated
3184  // immediately after receiving DHCPDECLINE, rather than later when we recover
3185  // the address.
3186 
3187  // Let's call lease6_decline hooks if necessary.
3188  if (HooksManager::calloutsPresent(Hooks.hook_index_lease6_decline_)) {
3189  CalloutHandlePtr callout_handle = getCalloutHandle(decline);
3190 
3191  // Use the RAII wrapper to make sure that the callout handle state is
3192  // reset when this object goes out of scope. All hook points must do
3193  // it to prevent possible circular dependency between the callout
3194  // handle and its arguments.
3195  ScopedCalloutHandleState callout_handle_state(callout_handle);
3196 
3197  // Enable copying options from the packet within hook library.
3198  ScopedEnableOptionsCopy<Pkt6> query6_options_copy(decline);
3199 
3200  // Pass incoming packet as argument
3201  callout_handle->setArgument("query6", decline);
3202  callout_handle->setArgument("lease6", lease);
3203 
3204  // Call callouts
3205  HooksManager::callCallouts(Hooks.hook_index_lease6_decline_,
3206  *callout_handle);
3207 
3208  // Callouts decided to SKIP the next processing step. The next
3209  // processing step would to actually decline the lease, so we'll
3210  // keep the lease as is.
3211  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
3212  LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_DECLINE_SKIP)
3213  .arg(decline->getLabel())
3214  .arg(decline->getIface())
3215  .arg(lease->addr_.toText());
3216  return (true);
3217  }
3218 
3219  // Callouts decided to DROP the packet. Let's simply log it and
3220  // return false, so callers will act accordingly.
3221  if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP) {
3222  LOG_DEBUG(hooks_logger, DBG_DHCP6_DETAIL, DHCP6_HOOK_DECLINE_DROP)
3223  .arg(decline->getLabel())
3224  .arg(decline->getIface())
3225  .arg(lease->addr_.toText());
3226  return (false);
3227  }
3228  }
3229 
3230  // Check if a lease has flags indicating that the FQDN update has
3231  // been performed. If so, create NameChangeRequest which removes
3232  // the entries. This method does all necessary checks.
3233  queueNCR(CHG_REMOVE, lease);
3234 
3235  // Bump up the subnet-specific statistic.
3236  StatsMgr::instance().addValue(
3237  StatsMgr::generateName("subnet", lease->subnet_id_, "declined-addresses"),
3238  static_cast<int64_t>(1));
3239 
3240  // Global declined addresses counter.
3241  StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
3242 
3243  // We need to disassociate the lease from the client. Once we move a lease
3244  // to declined state, it is no longer associated with the client in any
3245  // way.
3246  lease->decline(CfgMgr::instance().getCurrentCfg()->getDeclinePeriod());
3248 
3249  LOG_INFO(lease6_logger, DHCP6_DECLINE_LEASE).arg(decline->getLabel())
3250  .arg(lease->addr_.toText()).arg(lease->valid_lft_);
3251 
3252  ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_Success,
3253  "Lease declined. Hopefully the next one will be better."));
3254 
3255  return (true);
3256 }
3257 
3258 Pkt6Ptr
3260 
3261  Pkt6Ptr inf_request = ctx.query_;
3262  setReservedClientClasses(inf_request, ctx);
3263  requiredClassify(inf_request, ctx);
3264 
3265  // Create a Reply packet, with the same trans-id as the client's.
3266  Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, inf_request->getTransid()));
3267 
3268  // Copy client options (client-id, also relay information if present)
3269  copyClientOptions(inf_request, reply);
3270 
3271  // Build the configured option list for append methods
3272  CfgOptionList co_list;
3273  buildCfgOptionList(inf_request, ctx, co_list);
3274 
3275  // Append default options, i.e. options that the server is supposed
3276  // to put in all messages it sends (server-id for now, but possibly other
3277  // options once we start supporting authentication)
3278  appendDefaultOptions(inf_request, reply, co_list);
3279 
3280  // Try to assign options that were requested by the client.
3281  appendRequestedOptions(inf_request, reply, co_list);
3282 
3283  // Try to assign vendor options that were requested by the client.
3284  appendRequestedVendorOptions(inf_request, reply, ctx, co_list);
3285 
3286  return (reply);
3287 }
3288 
3289 void
3291 
3292  // flags are in transid
3293  // uint32_t flags = dhcp4_query->getTransid();
3294  // do nothing with DHCPV4_QUERY_FLAGS_UNICAST
3295 
3296  // Get the DHCPv4 message option
3297  OptionPtr dhcp4_msg = dhcp4_query->getOption(D6O_DHCPV4_MSG);
3298  if (dhcp4_msg) {
3299  try {
3300  // Forward the whole message to the DHCPv4 server via IPC
3301  Dhcp6to4Ipc::instance().send(dhcp4_query);
3302  } catch (...) {
3303  // Assume the error was already logged
3304  return;
3305  }
3306  }
3307 
3308  // This method does not return anything as we always sent back
3309  // the response via Dhcp6To4Ipc.
3310 }
3311 
3312 void Dhcpv6Srv::classifyByVendor(const Pkt6Ptr& pkt, std::string& classes) {
3313  OptionVendorClassPtr vclass = boost::dynamic_pointer_cast<
3314  OptionVendorClass>(pkt->getOption(D6O_VENDOR_CLASS));
3315 
3316  if (!vclass || vclass->getTuplesNum() == 0) {
3317  return;
3318  }
3319 
3320  if (vclass->hasTuple(DOCSIS3_CLASS_MODEM)) {
3321  pkt->addClass(VENDOR_CLASS_PREFIX + DOCSIS3_CLASS_MODEM);
3322  classes += VENDOR_CLASS_PREFIX + DOCSIS3_CLASS_MODEM + " ";
3323 
3324  } else if (vclass->hasTuple(DOCSIS3_CLASS_EROUTER)) {
3325  pkt->addClass(VENDOR_CLASS_PREFIX + DOCSIS3_CLASS_EROUTER);
3326  classes += VENDOR_CLASS_PREFIX + DOCSIS3_CLASS_EROUTER + " ";
3327 
3328  } else {
3329  pkt->addClass(VENDOR_CLASS_PREFIX + vclass->getTuple(0).getText());
3330  classes + VENDOR_CLASS_PREFIX + vclass->getTuple(0).getText() + " ";
3331  }
3332 }
3333 
3335  // All packets belongs to ALL
3336  pkt->addClass("ALL");
3337  string classes = "ALL ";
3338 
3339  // First: built-in vendor class processing
3340  classifyByVendor(pkt, classes);
3341 
3342  // Run match expressions on classes not depending on KNOWN/UNKNOWN.
3343  evaluateClasses(pkt, false);
3344 }
3345 
3346 void Dhcpv6Srv::evaluateClasses(const Pkt6Ptr& pkt, bool depend_on_known) {
3347  // Note getClientClassDictionary() cannot be null
3348  const ClientClassDictionaryPtr& dict =
3349  CfgMgr::instance().getCurrentCfg()->getClientClassDictionary();
3350  const ClientClassDefListPtr& defs_ptr = dict->getClasses();
3351  for (ClientClassDefList::const_iterator it = defs_ptr->cbegin();
3352  it != defs_ptr->cend(); ++it) {
3353  // Note second cannot be null
3354  const ExpressionPtr& expr_ptr = (*it)->getMatchExpr();
3355  // Nothing to do without an expression to evaluate
3356  if (!expr_ptr) {
3357  continue;
3358  }
3359  // Not the right time if only when required
3360  if ((*it)->getRequired()) {
3361  continue;
3362  }
3363  // Not the right pass.
3364  if ((*it)->getDependOnKnown() != depend_on_known) {
3365  continue;
3366  }
3367  // Evaluate the expression which can return false (no match),
3368  // true (match) or raise an exception (error)
3369  try {
3370  bool status = evaluateBool(*expr_ptr, *pkt);
3371  if (status) {
3372  LOG_INFO(dhcp6_logger, EVAL_RESULT)
3373  .arg((*it)->getName())
3374  .arg(status);
3375  // Matching: add the class
3376  pkt->addClass((*it)->getName());
3377  } else {
3378  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, EVAL_RESULT)
3379  .arg((*it)->getName())
3380  .arg(status);
3381  }
3382  } catch (const Exception& ex) {
3383  LOG_ERROR(dhcp6_logger, EVAL_RESULT)
3384  .arg((*it)->getName())
3385  .arg(ex.what());
3386  } catch (...) {
3387  LOG_ERROR(dhcp6_logger, EVAL_RESULT)
3388  .arg((*it)->getName())
3389  .arg("get exception?");
3390  }
3391  }
3392 }
3393 
3394 void
3396  const AllocEngine::ClientContext6& ctx) {
3397  if (ctx.currentHost() && pkt) {
3398  const ClientClasses& classes = ctx.currentHost()->getClientClasses6();
3399  for (ClientClasses::const_iterator cclass = classes.cbegin();
3400  cclass != classes.cend(); ++cclass) {
3401  pkt->addClass(*cclass);
3402  }
3403  }
3404 
3405  const ClientClasses& classes = pkt->getClasses();
3406  if (!classes.empty()) {
3407  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_ASSIGNED)
3408  .arg(pkt->getLabel())
3409  .arg(classes.toText());
3410  }
3411 }
3412 
3413 void
3415  // First collect required classes
3416  ClientClasses classes = pkt->getClasses(true);
3417  Subnet6Ptr subnet = ctx.subnet_;
3418 
3419  if (subnet) {
3420  // Begin by the shared-network
3421  SharedNetwork6Ptr network;
3422  subnet->getSharedNetwork(network);
3423  if (network) {
3424  const ClientClasses& to_add = network->getRequiredClasses();
3425  for (ClientClasses::const_iterator cclass = to_add.cbegin();
3426  cclass != to_add.cend(); ++cclass) {
3427  classes.insert(*cclass);
3428  }
3429  }
3430 
3431  // Followed by the subnet
3432  const ClientClasses& to_add = subnet->getRequiredClasses();
3433  for (ClientClasses::const_iterator cclass = to_add.cbegin();
3434  cclass != to_add.cend(); ++cclass) {
3435  classes.insert(*cclass);
3436  }
3437 
3438  // And finish by pools
3439  BOOST_FOREACH(const AllocEngine::ResourceType& resource,
3440  ctx.allocated_resources_) {
3441  PoolPtr pool = ctx.subnet_->getPool(resource.second == 128 ?
3442  Lease::TYPE_NA :
3444  resource.first,
3445  false);
3446  if (pool) {
3447  const ClientClasses& to_add = pool->getRequiredClasses();
3448  for (ClientClasses::const_iterator cclass = to_add.cbegin();
3449  cclass != to_add.cend(); ++cclass) {
3450  classes.insert(*cclass);
3451  }
3452  }
3453  }
3454 
3455  // host reservation???
3456  }
3457 
3458  // Run match expressions
3459  // Note getClientClassDictionary() cannot be null
3460  const ClientClassDictionaryPtr& dict =
3461  CfgMgr::instance().getCurrentCfg()->getClientClassDictionary();
3462  for (ClientClasses::const_iterator cclass = classes.cbegin();
3463  cclass != classes.cend(); ++cclass) {
3464  const ClientClassDefPtr class_def = dict->findClass(*cclass);
3465  if (!class_def) {
3466  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_UNDEFINED)
3467  .arg(*cclass);
3468  continue;
3469  }
3470  const ExpressionPtr& expr_ptr = class_def->getMatchExpr();
3471  // Nothing to do without an expression to evaluate
3472  if (!expr_ptr) {
3473  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_UNTESTABLE)
3474  .arg(*cclass);
3475  continue;
3476  }
3477  // Evaluate the expression which can return false (no match),
3478  // true (match) or raise an exception (error)
3479  try {
3480  bool status = evaluateBool(*expr_ptr, *pkt);
3481  if (status) {
3482  LOG_INFO(dhcp6_logger, EVAL_RESULT)
3483  .arg(*cclass)
3484  .arg(status);
3485  // Matching: add the class
3486  pkt->addClass(*cclass);
3487  } else {
3488  LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, EVAL_RESULT)
3489  .arg(*cclass)
3490  .arg(status);
3491  }
3492  } catch (const Exception& ex) {
3493  LOG_ERROR(dhcp6_logger, EVAL_RESULT)
3494  .arg(*cclass)
3495  .arg(ex.what());
3496  } catch (...) {
3497  LOG_ERROR(dhcp6_logger, EVAL_RESULT)
3498  .arg(*cclass)
3499  .arg("get exception?");
3500  }
3501  }
3502 }
3503 
3504 void
3505 Dhcpv6Srv::updateReservedFqdn(const AllocEngine::ClientContext6& ctx,
3506  const Pkt6Ptr& answer) {
3507  if (!answer) {
3508  isc_throw(isc::Unexpected, "an instance of the object encapsulating"
3509  " a message must not be NULL when updating reserved FQDN");
3510  }
3511 
3512  Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<Option6ClientFqdn>
3513  (answer->getOption(D6O_CLIENT_FQDN));
3514 
3515  // If Client FQDN option is not included, there is nothing to do.
3516  if (!fqdn) {
3517  return;
3518  }
3519 
3520  std::string name = fqdn->getDomainName();
3521 
3522  // If there is a host reservation for this client we have to check whether
3523  // this reservation has the same hostname as the hostname currently
3524  // present in the FQDN option. If not, it indicates that the allocation
3525  // engine picked a different subnet (from within a shared network) for
3526  // reservations and we have to send this new value to the client.
3527  if (ctx.currentHost() &&
3528  !ctx.currentHost()->getHostname().empty()) {
3529  std::string new_name = CfgMgr::instance().getD2ClientMgr().
3530  qualifyName(ctx.currentHost()->getHostname(), true);
3531 
3532  if (new_name != name) {
3533  fqdn->setDomainName(new_name, Option6ClientFqdn::FULL);
3534 
3535  // Replace previous instance of Client FQDN option.
3536  answer->delOption(D6O_CLIENT_FQDN);
3537  answer->addOption(fqdn);
3538  }
3539  }
3540 }
3541 
3542 void
3543 Dhcpv6Srv::generateFqdn(const Pkt6Ptr& answer) {
3544  if (!answer) {
3545  isc_throw(isc::Unexpected, "an instance of the object encapsulating"
3546  " a message must not be NULL when generating FQDN");
3547  }
3548 
3551 
3552  // It is likely that client hasn't included the FQDN option. In such case,
3553  // FQDN option will be NULL. Also, there is nothing to do if the option
3554  // is present and conveys the non-empty FQDN.
3555  Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
3556  Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
3557  if (!fqdn || !fqdn->getDomainName().empty()) {
3558  return;
3559  }
3560 
3561  // Get the first IA_NA acquired for the client.
3562  OptionPtr ia = answer->getOption(D6O_IA_NA);
3563  if (!ia) {
3564  return;
3565  }
3566 
3567  // If it has any IAAddr, use the first one to generate unique FQDN.
3568  Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<
3569  Option6IAAddr>(ia->getOption(D6O_IAADDR));
3570  if (!iaaddr) {
3571  return;
3572  }
3573  // Get the IPv6 address acquired by the client.
3574  IOAddress addr = iaaddr->getAddress();
3575  std::string generated_name =
3577 
3578  LOG_DEBUG(ddns6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_DDNS_FQDN_GENERATED)
3579  .arg(answer->getLabel())
3580  .arg(generated_name);
3581 
3582  try {
3583  // The lease has been acquired but the FQDN for this lease hasn't
3584  // been updated in the lease database. We now have new FQDN
3585  // generated, so the lease database has to be updated here.
3586  // However, never update lease database for Advertise, just send
3587  // our notion of client's FQDN in the Client FQDN option.
3588  if (answer->getType() != DHCPV6_ADVERTISE) {
3589  Lease6Ptr lease =
3591  if (lease) {
3592  lease->hostname_ = generated_name;
3594 
3595  } else {
3596  isc_throw(isc::Unexpected, "there is no lease in the database "
3597  " for address " << addr << ", so as it is impossible"
3598  " to update FQDN data. This is a programmatic error"
3599  " as the given address is now being handed to the"
3600  " client");
3601  }
3602  }
3603  // Set the generated FQDN in the Client FQDN option.
3604  fqdn->setDomainName(generated_name, Option6ClientFqdn::FULL);
3605 
3606  answer->delOption(D6O_CLIENT_FQDN);
3607  answer->addOption(fqdn);
3608 
3609  } catch (const Exception& ex) {
3610  LOG_ERROR(ddns6_logger, DHCP6_DDNS_GENERATED_FQDN_UPDATE_FAIL)
3611  .arg(answer->getLabel())
3612  .arg(addr.toText())
3613  .arg(ex.what());
3614  }
3615 }
3616 
3617 void
3620  if (d2_mgr.ddnsEnabled()) {
3621  // Updates are enabled, so lets start the sender, passing in
3622  // our error handler.
3623  // This may throw so wherever this is called needs to ready.
3624  d2_mgr.startSender(boost::bind(&Dhcpv6Srv::d2ClientErrorHandler,
3625  this, _1, _2));
3626  }
3627 }
3628 
3629 void
3632  if (d2_mgr.ddnsEnabled()) {
3633  // Updates are enabled, so lets stop the sender
3634  d2_mgr.stopSender();
3635  }
3636 }
3637 
3638 void
3642  LOG_ERROR(ddns6_logger, DHCP6_DDNS_REQUEST_SEND_FAILED).
3643  arg(result).arg((ncr ? ncr->toText() : " NULL "));
3644  // We cannot communicate with kea-dhcp-ddns, suspend further updates.
3648 }
3649 
3650 // Refer to config_report so it will be embedded in the binary
3652 
3653 std::string
3654 Dhcpv6Srv::getVersion(bool extended) {
3655  std::stringstream tmp;
3656 
3657  tmp << VERSION;
3658  if (extended) {
3659  tmp << endl << EXTENDED_VERSION << endl;
3660  tmp << "linked with:" << endl;
3661  tmp << Logger::getVersion() << endl;
3662  tmp << CryptoLink::getVersion() << endl;
3663  tmp << "database:" << endl;
3664 #ifdef HAVE_MYSQL
3665  tmp << MySqlLeaseMgr::getDBVersion() << endl;
3666 #endif
3667 #ifdef HAVE_PGSQL
3668  tmp << PgSqlLeaseMgr::getDBVersion() << endl;
3669 #endif
3670 #ifdef HAVE_CQL
3671  tmp << CqlLeaseMgr::getDBVersion() << endl;
3672 #endif
3674 
3675  // @todo: more details about database runtime
3676  }
3677 
3678  return (tmp.str());
3679 }
3680 
3681 void Dhcpv6Srv::processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp) {
3682 
3683  if (query->relay_info_.empty()) {
3684  // RSOO is inserted by relay agents, nothing to do here if it's
3685  // a direct message.
3686  return;
3687  }
3688 
3689  // Get RSOO configuration.
3690  ConstCfgRSOOPtr cfg_rsoo = CfgMgr::instance().getCurrentCfg()->getCfgRSOO();
3691 
3692  // Let's get over all relays (encapsulation levels). We need to do
3693  // it in the same order as the client packet traversed the relays.
3694  for (int i = query->relay_info_.size(); i > 0 ; --i) {
3695  OptionPtr rsoo_container = query->getRelayOption(D6O_RSOO, i - 1);
3696  if (rsoo_container) {
3697  // There are RSOO options. Let's get through them one by one
3698  // and if it's RSOO-enabled and there's no such option provided yet,
3699  // copy it to the server's response
3700  const OptionCollection& rsoo = rsoo_container->getOptions();
3701  for (OptionCollection::const_iterator opt = rsoo.begin();
3702  opt != rsoo.end(); ++opt) {
3703 
3704  // Echo option if it is RSOO enabled option and there is no such
3705  // option added yet.
3706  if (cfg_rsoo->enabled(opt->second->getType()) &&
3707  !rsp->getOption(opt->second->getType())) {
3708  rsp->addOption(opt->second);
3709  }
3710  }
3711  }
3712  }
3713 }
3714 
3716 
3717  if (query->relay_info_.empty()) {
3718  // No relay agent
3719  return (0);
3720  }
3721 
3722  // Did the last relay agent add a relay-source-port?
3723  if (query->getRelayOption(D6O_RELAY_SOURCE_PORT, 0)) {
3724  // RFC 8357 section 5.2
3725  return (query->getRemotePort());
3726  }
3727 
3728  return (0);
3729 }
3730 
3731 void Dhcpv6Srv::processStatsReceived(const Pkt6Ptr& query) {
3732  // Note that we're not bumping pkt6-received statistic as it was
3733  // increased early in the packet reception code.
3734 
3735  string stat_name = "pkt6-unknown-received";
3736  switch (query->getType()) {
3737  case DHCPV6_SOLICIT:
3738  stat_name = "pkt6-solicit-received";
3739  break;
3740  case DHCPV6_ADVERTISE:
3741  // Should not happen, but let's keep a counter for it
3742  stat_name = "pkt6-advertise-received";
3743  break;
3744  case DHCPV6_REQUEST:
3745  stat_name = "pkt6-request-received";
3746  break;
3747  case DHCPV6_CONFIRM:
3748  stat_name = "pkt6-confirm-received";
3749  break;
3750  case DHCPV6_RENEW:
3751  stat_name = "pkt6-renew-received";
3752  break;
3753  case DHCPV6_REBIND:
3754  stat_name = "pkt6-rebind-received";
3755  break;
3756  case DHCPV6_REPLY:
3757  // Should not happen, but let's keep a counter for it
3758  stat_name = "pkt6-reply-received";
3759  break;
3760  case DHCPV6_RELEASE:
3761  stat_name = "pkt6-release-received";
3762  break;
3763  case DHCPV6_DECLINE:
3764  stat_name = "pkt6-decline-received";
3765  break;
3766  case DHCPV6_RECONFIGURE:
3767  stat_name = "pkt6-reconfigure-received";
3768  break;
3770  stat_name = "pkt6-infrequest-received";
3771  break;
3772  case DHCPV6_DHCPV4_QUERY:
3773  stat_name = "pkt6-dhcpv4-query-received";
3774  break;
3776  // Should not happen, but let's keep a counter for it
3777  stat_name = "pkt6-dhcpv4-response-received";
3778  break;
3779  default:
3780  ; // do nothing
3781  }
3782 
3783  StatsMgr::instance().addValue(stat_name, static_cast<int64_t>(1));
3784 }
3785 
3786 void Dhcpv6Srv::processStatsSent(const Pkt6Ptr& response) {
3787  // Increase generic counter for sent packets.
3788  StatsMgr::instance().addValue("pkt6-sent", static_cast<int64_t>(1));
3789 
3790  // Increase packet type specific counter for packets sent.
3791  string stat_name;
3792  switch (response->getType()) {
3793  case DHCPV6_ADVERTISE:
3794  stat_name = "pkt6-advertise-sent";
3795  break;
3796  case DHCPV6_REPLY:
3797  stat_name = "pkt6-reply-sent";
3798  break;
3800  stat_name = "pkt6-dhcpv4-response-sent";
3801  break;
3802  default:
3803  // That should never happen
3804  return;
3805  }
3806 
3807  StatsMgr::instance().addValue(stat_name, static_cast<int64_t>(1));
3808 }
3809 
3811  return (Hooks.hook_index_buffer6_send_);
3812 }
3813 
3814 bool
3815 Dhcpv6Srv::requestedInORO(const Pkt6Ptr& query, const uint16_t code) const {
3816  OptionUint16ArrayPtr oro =
3817  boost::dynamic_pointer_cast<OptionUint16Array>(query->getOption(D6O_ORO));
3818 
3819  if (oro) {
3820  const std::vector<uint16_t>& codes = oro->getValues();
3821  return (std::find(codes.begin(), codes.end(), code) != codes.end());
3822  }
3823 
3824  return (false);
3825 }
3826 
3828  // Dump all of our current packets, anything that is mid-stream
3829  isc::dhcp::Pkt6Ptr pkt6ptr_empty;
3830  isc::dhcp::getCalloutHandle(pkt6ptr_empty);
3831  HooksManager::clearParkingLots();
3832 }
3833 
3834 };
3835 };
isc::dhcp::D2ClientMgr::qualifyName
std::string qualifyName(const std::string &partial_name, const bool trailing_dot) const
Adds a qualifying suffix to a given domain name.
Definition: d2_client_mgr.cc:181
ncr_msg.h
This file provides the classes needed to embody, compose, and decompose DNS update requests that are ...
isc::dhcp::AllocEngine::ClientContext6::callout_handle_
hooks::CalloutHandlePtr callout_handle_
Callout handle associated with the client's message.
Definition: alloc_engine.h:375
isc::dhcp::Pkt6
Represents a DHCPv6 packet.
Definition: pkt6.h:44
isc::util::equalValues
bool equalValues(const T &ptr1, const T &ptr2)
This function checks if two pointers are non-null and values are equal.
Definition: pointer_util.h:27
isc::dhcp::OptionContainerPtr
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
Definition: cfg_option.h:206
isc::dhcp::AllocEngine::ClientContext6::allocated_resources_
ResourceContainer allocated_resources_
Holds addresses and prefixes allocated for all IAs.
Definition: alloc_engine.h:378
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:25
isc::hooks::ScopedCalloutHandleState
Wrapper class around callout handle which automatically resets handle's state.
Definition: callout_handle.h:456
isc::dhcp::DUIDFactory
Factory for generating DUIDs (DHCP Unique Identifiers).
Definition: duid_factory.h:63
isc::dhcp::OptionContainerPersistRange
std::pair< OptionContainerPersistIndex::const_iterator, OptionContainerPersistIndex::const_iterator > OptionContainerPersistRange
Pair of iterators to represent the range of options having the same persistency flag.
Definition: cfg_option.h:220
isc::dhcp::AllocEngine::ClientContext6::IAContext::changed_leases_
Lease6Collection changed_leases_
A pointer to any leases that have changed FQDN information.
Definition: alloc_engine.h:416
isc::dhcp::D2ClientMgr::startSender
void startSender(D2ClientErrorHandler error_handler, isc::asiolink::IOService &io_service)
Enables sending NameChangeRequests to kea-dhcp-ddns.
Definition: d2_client_mgr.cc:233
isc::dhcp::ClientClassDictionaryPtr
boost::shared_ptr< ClientClassDictionary > ClientClassDictionaryPtr
Defines a pointer to a ClientClassDictionary.
Definition: client_class_def.h:382
isc::dhcp::Dhcpv6Srv::processPacketPktSend
void processPacketPktSend(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr &query, Pkt6Ptr &rsp)
Executes pkt6_send callout.
Definition: dhcp6_srv.cc:886
docsis3_option_defs.h
isc::dhcp::Memfile_LeaseMgr::getDBVersion
static std::string getDBVersion()
Local version of getDBVersion() class method.
Definition: memfile_lease_mgr.cc:687
isc::dhcp::Dhcpv6Srv::discardPackets
void discardPackets()
Discards cached and parked packets Clears the call_handle store and packet parking lots of all packet...
Definition: dhcp6_srv.cc:3827
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
isc::dhcp::IfaceMgr::send
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Definition: iface_mgr.cc:953
isc::log
Definition: buffer_appender_impl.cc:17
dhcp6to4_ipc.h
isc::dhcp::Option6ClientFqdn::FLAG_S
static const uint8_t FLAG_S
S bit.
Definition: option6_client_fqdn.h:93
isc::dhcp::Dhcp6to4Ipc::instance
static Dhcp6to4Ipc & instance()
Returns pointer to the sole instance of Dhcp6to4Ipc.
Definition: dhcp6to4_ipc.cc:32
isc::dhcp::ExpressionPtr
boost::shared_ptr< Expression > ExpressionPtr
Definition: token.h:30
isc::dhcp::AllocEngine::ResourceType
std::pair< isc::asiolink::IOAddress, uint8_t > ResourceType
Defines a single hint (an address + prefix-length).
Definition: alloc_engine.h:280
isc::dhcp::Dhcpv6Srv::~Dhcpv6Srv
virtual ~Dhcpv6Srv()
Destructor. Used during DHCPv6 service shutdown.
Definition: dhcp6_srv.cc:221
hooks_log.h
isc::process::Daemon::handleSignal
virtual void handleSignal()
Invokes handler for the next received signal.
Definition: daemon.cc:60
LOG_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
isc::dhcp::PgSqlLeaseMgr::getDBVersion
static std::string getDBVersion()
Local version of getDBVersion() class method.
Definition: pgsql_lease_mgr.cc:1117
isc::dhcp::SubnetPtr
boost::shared_ptr< Subnet > SubnetPtr
A generic pointer to either Subnet4 or Subnet6 object.
Definition: subnet.h:455
isc::dhcp::CfgMgr::instance
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
isc::dhcp::Host::IdentifierType
IdentifierType
Type of the host identifier.
Definition: host.h:252
DHCPV6_INFORMATION_REQUEST
@ DHCPV6_INFORMATION_REQUEST
Definition: dhcp6.h:223
iface_mgr.h
STATUS_Success
@ STATUS_Success
Definition: dhcp6.h:173
isc::dhcp::Option6StatusCodePtr
boost::shared_ptr< Option6StatusCode > Option6StatusCodePtr
Pointer to the isc::dhcp::Option6StatusCode.
Definition: option6_status_code.h:18
isc::dhcp::isClientClassBuiltIn
bool isClientClassBuiltIn(const ClientClass &client_class)
Check if a client class name is builtin.
Definition: client_class_def.cc:353
isc::dhcp::DBG_DHCP6_HOOKS
const int DBG_DHCP6_HOOKS
Debug level used to trace hook related operations.
Definition: dhcp6_log.h:33
isc::dhcp::Dhcpv6Srv::receivePacket
virtual Pkt6Ptr receivePacket(int timeout)
dummy wrapper around IfaceMgr::receive6
Definition: dhcp6_srv.cc:250
isc::dhcp::Dhcpv6Srv::processRSOO
void processRSOO(const Pkt6Ptr &query, const Pkt6Ptr &rsp)
Processes Relay-supplied options, if present.
Definition: dhcp6_srv.cc:3681
isc::dhcp::AllocEngine::ClientContext6::duid_
DuidPtr duid_
Client identifier.
Definition: alloc_engine.h:342
isc::dhcp::Dhcpv6Srv::OPTIONAL
@ OPTIONAL
Definition: dhcp6_srv.h:70
pgsql_lease_mgr.h
isc::dhcp::Dhcp4o6IpcBase::close
void close()
Close communication socket.
Definition: dhcp4o6_ipc.cc:118
isc::dhcp::Dhcpv6Srv::initContext
void initContext(const Pkt6Ptr &pkt, AllocEngine::ClientContext6 &ctx, bool &drop)
Initializes client context for specified packet.
Definition: dhcp6_srv.cc:303
isc::dhcp::Dhcpv6Srv::sanityCheckDUID
void sanityCheckDUID(const OptionPtr &opt, const std::string &opt_name)
verifies if received DUID option (client-id or server-id) is sane
Definition: dhcp6_srv.cc:1348
isc::dhcp::Dhcpv6Srv::processSolicit
Pkt6Ptr processSolicit(AllocEngine::ClientContext6 &ctx)
Processes incoming Solicit and returns response.
Definition: dhcp6_srv.cc:2717
isc::dhcp::SharedNetwork6Ptr
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
Definition: shared_network.h:322
isc::dhcp::AllocEngine::ClientContext6::IAContext::old_leases_
Lease6Collection old_leases_
A pointer to any old leases that the client had before update but are no longer valid after the updat...
Definition: alloc_engine.h:408
libdhcp++.h
isc::dhcp_ddns::NameChangeSender::Result
Result
Defines the outcome of an asynchronous NCR send.
Definition: ncr_io.h:467
io_address.h
duid.h
isc::dhcp::Dhcpv6Srv::duidToString
static std::string duidToString(const OptionPtr &opt)
converts DUID to text Converts content of DUID option to a text representation, e....
Definition: dhcp6_srv.cc:1008
isc::dhcp::D2ClientMgr::generateFqdn
std::string generateFqdn(const asiolink::IOAddress &address, const bool trailing_dot=true) const
Builds a FQDN based on the configuration and given IP address.
Definition: d2_client_mgr.cc:168
isc::dhcp::DHCPv6DiscardMessageError
This exception is thrown when DHCP server hits the error which should result in discarding the messag...
Definition: dhcp6_srv.h:45
isc::hooks::CalloutHandlePtr
boost::shared_ptr< CalloutHandle > CalloutHandlePtr
A shared pointer to a CalloutHandle object.
Definition: callout_handle.h:416
option6_ia.h
D6O_IA_PD
@ D6O_IA_PD
Definition: dhcp6.h:45
isc::dhcp::DuidPtr
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
isc::dhcp::Dhcpv6Srv::run_one
void run_one()
Main server processing step.
Definition: dhcp6_srv.cc:424
isc::hooks::hooks_logger
isc::log::Logger hooks_logger("hooks")
Hooks Logger.
Definition: hooks_log.h:37
config_report.h
DHCPV6_REBIND
@ DHCPV6_REBIND
Definition: dhcp6.h:218
isc::dhcp::Lease6Ptr
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:460
isc::dhcp::AllocEngine::ClientContext6::createIAContext
void createIAContext()
Creates new IA context.
Definition: alloc_engine.h:478
isc::dhcp::Option6IAAddr::getAddress
isc::asiolink::IOAddress getAddress() const
Returns address contained within this option.
Definition: option6_iaaddr.h:97
isc::dhcp::AllocEngine::ALLOC_ITERATIVE
@ ALLOC_ITERATIVE
Definition: alloc_engine.h:230
isc::dhcp::packet6_logger
isc::log::Logger packet6_logger(DHCP6_PACKET_LOGGER_NAME)
Logger for processed packets.
Definition: dhcp6_log.h:99
isc::dhcp::AllocEngine
DHCPv4 and DHCPv6 allocation engine.
Definition: alloc_engine.h:56
isc::dhcp::Dhcpv6Srv::getHookIndexBuffer6Send
static int getHookIndexBuffer6Send()
Returns the index of the buffer6_send hook.
Definition: dhcp6_srv.cc:3810
isc::dhcp::Option6IAAddrPtr
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
Definition: option6_iaaddr.h:17
isc::dhcp::AllocEngine::ClientContext6::IAContext::iaid_
uint32_t iaid_
iaid IAID field from IA_NA or IA_PD that is being processed
Definition: alloc_engine.h:390
isc::dhcp::dhcp6_logger
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:87
isc::dhcp::Option::getOptions
const OptionCollection & getOptions() const
Returns all encapsulated options.
Definition: option.h:296
hooks_manager.h
isc::dhcp::Dhcpv6Srv::processDhcp4Query
void processDhcp4Query(const Pkt6Ptr &dhcp4_query)
Processes incoming DHCPv4-query message.
Definition: dhcp6_srv.cc:3290
DHCPV6_RENEW
@ DHCPV6_RENEW
Definition: dhcp6.h:217
isc::dhcp::ClientClasses::toText
std::string toText(const std::string &separator=", ") const
Returns all class names as text.
Definition: classify.cc:34
isc::dhcp::options6_logger
isc::log::Logger options6_logger(DHCP6_OPTIONS_LOGGER_NAME)
Logger for options parser.
Definition: dhcp6_log.h:105
isc::dhcp_ddns::NameChangeRequestPtr
boost::shared_ptr< NameChangeRequest > NameChangeRequestPtr
Defines a pointer to a NameChangeRequest.
Definition: ncr_msg.h:212
pkt6.h
isc::dhcp::Option6IAAddr
Definition: option6_iaaddr.h:22
isc::dhcp::Option6IAPrefix
Class that represents IAPREFIX option in DHCPv6.
Definition: option6_iaprefix.h:51
isc::dhcp::AllocEngine::ClientContext6::addHostIdentifier
void addHostIdentifier(const Host::IdentifierType &id_type, const std::vector< uint8_t > &identifier)
Convenience function adding host identifier into host_identifiers_ list.
Definition: alloc_engine.h:457
cfg_host_operations.h
isc::dhcp_ddns::D2Dhcid
Container class for handling the DHCID value within a NameChangeRequest.
Definition: ncr_msg.h:86
isc::dhcp::Dhcpv6Srv::MANDATORY
@ MANDATORY
Definition: dhcp6_srv.h:69
DHCP6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
Definition: option_space.h:17
isc::dhcp::Dhcpv6Srv::extendIA_PD
OptionPtr extendIA_PD(const Pkt6Ptr &query, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Extends lifetime of the prefix.
Definition: dhcp6_srv.cc:2100
isc::dhcp::ScopedEnableOptionsCopy
RAII object enabling copying options retrieved from the packet.
Definition: pkt.h:40
isc::dhcp::AllocEngine::ClientContext6::IAContext::hints_
HintContainer hints_
client's hints
Definition: alloc_engine.h:399
option6_client_fqdn.h
isc::dhcp::Option::getOption
OptionPtr getOption(uint16_t type) const
Returns shared_ptr to suboption of specific type.
Definition: option.cc:201
isc::dhcp::Dhcpv6Srv::getMAC
static HWAddrPtr getMAC(const Pkt6Ptr &pkt)
Attempts to get a MAC/hardware address using configured sources.
Definition: dhcp6_srv.cc:1692
ncr_generator.h
isc::dhcp::CqlLeaseMgr::getDBVersion
static std::string getDBVersion()
Local version of getDBVersion() class method.
Definition: cql_lease_mgr.cc:2022
lease_mgr_factory.h
isc::dhcp::Dhcpv6Srv::evaluateClasses
void evaluateClasses(const Pkt6Ptr &pkt, bool depend_on_known)
Evaluate classes.
Definition: dhcp6_srv.cc:3346
isc::dhcp::SubnetSelector
Subnet selector used to specify parameters used to select a subnet.
Definition: subnet_selector.h:23
isc::dhcp::Dhcpv6Srv::assignLeases
void assignLeases(const Pkt6Ptr &question, Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx)
Assigns leases.
Definition: dhcp6_srv.cc:1439
isc::dhcp::DOCSIS3_CLASS_EROUTER
const char * DOCSIS3_CLASS_EROUTER
The class as specified in vendor-class option by the devices.
Definition: libdhcp++.cc:72
isc::dhcp::Option6ClientFqdn
Represents DHCPv6 Client FQDN Option (code 39).
Definition: option6_client_fqdn.h:87
isc::dhcp::Dhcpv6Srv::releaseIA_PD
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.
Definition: dhcp6_srv.cc:2556
isc::dhcp::D2ClientMgr::suspendUpdates
void suspendUpdates()
Suspends sending requests.
Definition: d2_client_mgr.cc:34
D6O_VENDOR_OPTS
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
STATUS_NoAddrsAvail
@ STATUS_NoAddrsAvail
Definition: dhcp6.h:175
option6_iaprefix.h
isc::dhcp::AllocEngine::ClientContext6::fwd_dns_update_
bool fwd_dns_update_
A boolean value which indicates that server takes responsibility for the forward DNS Update for this ...
Definition: alloc_engine.h:361
STATUS_UnspecFail
@ STATUS_UnspecFail
Definition: dhcp6.h:174
isc::dhcp::Dhcpv6Srv::shutdown
void shutdown()
Instructs the server to shut down.
Definition: dhcp6_srv.cc:245
isc::dhcp::Dhcpv6Srv::buildCfgOptionList
void buildCfgOptionList(const Pkt6Ptr &question, AllocEngine::ClientContext6 &ctx, CfgOptionList &co_list)
Build the configured option list.
Definition: dhcp6_srv.cc:1051
isc::dhcp::Dhcpv6Srv::serverid_
OptionPtr serverid_
Server DUID (to be sent in server-identifier option)
Definition: dhcp6_srv.h:967
DHCPV6_REQUEST
@ DHCPV6_REQUEST
Definition: dhcp6.h:215
isc::dhcp::OptionCollection
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition: option.h:41
isc::dhcp::Dhcpv6Srv::checkRelaySourcePort
static uint16_t checkRelaySourcePort(const Pkt6Ptr &query)
Used for DHCPv4-over-DHCPv6 too.
Definition: dhcp6_srv.cc:3715
isc::dhcp::Dhcpv6Srv::declineLeases
bool declineLeases(const Pkt6Ptr &decline, Pkt6Ptr &reply, AllocEngine::ClientContext6 &ctx)
Attempts to decline all leases in specified Decline message.
Definition: dhcp6_srv.cc:2999
isc::dhcp_ddns::CHG_REMOVE
@ CHG_REMOVE
Definition: ncr_msg.h:48
Hooks
Dhcp4Hooks Hooks
Definition: dhcp4_srv.cc:117
isc::dhcp::AllocEngine::ClientContext6::fake_allocation_
bool fake_allocation_
Indicates if this is a real or fake allocation.
Definition: alloc_engine.h:331
isc::dhcp::D2ClientMgr::ddnsEnabled
bool ddnsEnabled()
Convenience method for checking if DHCP-DDNS is enabled.
Definition: d2_client_mgr.cc:106
lease_mgr.h
An abstract API for lease database.
isc::dhcp::ddns6_logger
isc::log::Logger ddns6_logger(DHCP6_DDNS_LOGGER_NAME)
Logger for Hostname or FQDN processing.
Definition: dhcp6_log.h:111
isc::dhcp::LeaseMgrFactory::instance
static LeaseMgr & instance()
Return current lease manager.
Definition: lease_mgr_factory.cc:111
isc::Exception
This is a base class for exceptions thrown from the DNS library module.
Definition: exceptions/exceptions.h:23
isc::dhcp::Dhcpv6Srv::releaseIA_NA
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.
Definition: dhcp6_srv.cc:2383
isc::dhcp::LeaseMgrFactory::destroy
static void destroy()
Destroy lease manager.
Definition: lease_mgr_factory.cc:95
isc::dhcp::Dhcpv6Srv::alloc_engine_
boost::shared_ptr< AllocEngine > alloc_engine_
Allocation Engine.
Definition: dhcp6_srv.h:985
isc::dhcp::AllocEngine::ClientContext6::subnet_
Subnet6Ptr subnet_
Subnet selected for the client by the server.
Definition: alloc_engine.h:334
logger.h
D6O_RSOO
@ D6O_RSOO
Definition: dhcp6.h:86
isc::dhcp::AllocEngine::ClientContext6::hwaddr_
HWAddrPtr hwaddr_
Hardware/MAC address (if available, may be NULL)
Definition: alloc_engine.h:345
isc::dhcp::Dhcpv6Srv::RequirementLevel
RequirementLevel
defines if certain option may, must or must not appear
Definition: dhcp6_srv.h:67
DHCPV6_DHCPV4_QUERY
@ DHCPV6_DHCPV4_QUERY
Definition: dhcp6.h:236
isc::util
Definition: edns.h:19
isc::dhcp::Option6IA
Definition: option6_ia.h:22
isc::dhcp::Dhcpv6Srv::processPacket
void processPacket(Pkt6Ptr &query, Pkt6Ptr &rsp)
Process a single incoming DHCPv6 packet.
Definition: dhcp6_srv.cc:519
DHCPV6_REPLY
@ DHCPV6_REPLY
Definition: dhcp6.h:219
STATUS_NoPrefixAvail
@ STATUS_NoPrefixAvail
Definition: dhcp6.h:179
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dhcp::Dhcpv6Srv::appendDefaultOptions
void appendDefaultOptions(const Pkt6Ptr &question, Pkt6Ptr &answer, const CfgOptionList &co_list)
Appends default options to server's answer.
Definition: dhcp6_srv.cc:1044
isc::process::Daemon::signal_set_
isc::util::SignalSetPtr signal_set_
A pointer to the object installing custom signal handlers.
Definition: daemon.h:238
isc::dhcp::D2ClientConfig::ReplaceClientNameMode
ReplaceClientNameMode
Defines the client name replacement modes.
Definition: d2_client_cfg.h:72
isc::dhcp::HWAddrPtr
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
DHCPV6_RELEASE
@ DHCPV6_RELEASE
Definition: dhcp6.h:220
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
subnet_selector.h
isc::dhcp::Pool6Ptr
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition: pool.h:402
hex.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
utils.h
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::dhcp::AllocEngine::ClientContext6::hosts_
std::map< SubnetID, ConstHostPtr > hosts_
Holds a map of hosts belonging to the client within different subnets.
Definition: alloc_engine.h:356
isc::dhcp::AllocEngine::ClientContext6::ias_
std::vector< IAContext > ias_
Container holding IA specific contexts.
Definition: alloc_engine.h:436
isc::dhcp::Dhcpv6Srv::assignIA_NA
OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr &query, const isc::dhcp::Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Processes IA_NA option (and assigns addresses if necessary).
Definition: dhcp6_srv.cc:1707
isc::dhcp::ClientClasses::cbegin
const_iterator cbegin() const
Iterator to the first element.
Definition: classify.h:81
isc::dhcp::Option6IA::getIAID
uint32_t getIAID() const
Returns IA identifier.
Definition: option6_ia.h:86
isc::dhcp::Dhcpv6Srv::getServerID
OptionPtr getServerID()
Returns server-identifier option.
Definition: dhcp6_srv.h:106
isc::dhcp::Lease::TYPE_PD
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
isc::dhcp::Lease6CollectionPtr
boost::shared_ptr< Lease6Collection > Lease6CollectionPtr
A shared pointer to the collection of IPv6 leases.
Definition: lease.h:608
isc::dhcp::D2ClientMgr::adjustFqdnFlags
void adjustFqdnFlags(const T &fqdn, T &fqdn_resp)
Set server FQDN flags based on configuration and a given FQDN.
Definition: d2_client_mgr.h:438
evaluate.h
isc::dhcp::D2ClientMgr::adjustDomainName
void adjustDomainName(const T &fqdn, T &fqdn_resp)
Set server FQDN name based on configuration and a given FQDN.
Definition: d2_client_mgr.h:465
isc::dhcp::Dhcpv6Srv::requiredClassify
void requiredClassify(const Pkt6Ptr &pkt, AllocEngine::ClientContext6 &ctx)
Assigns incoming packet to zero or more classes (required pass).
Definition: dhcp6_srv.cc:3414
isc::dhcp::D2ClientMgr::sendRequest
void sendRequest(dhcp_ddns::NameChangeRequestPtr &ncr)
Send the given NameChangeRequests to kea-dhcp-ddns.
Definition: d2_client_mgr.cc:283
isc::dhcp::D2ClientConfig::RCM_ALWAYS
@ RCM_ALWAYS
Definition: d2_client_cfg.h:74
D6O_RAPID_COMMIT
@ D6O_RAPID_COMMIT
Definition: dhcp6.h:34
isc::dhcp::Pkt6::getLabel
virtual std::string getLabel() const
Returns text representation of the primary packet identifiers.
Definition: pkt6.cc:616
isc::dhcp::Dhcpv6Srv::d2ClientErrorHandler
virtual void d2ClientErrorHandler(const dhcp_ddns::NameChangeSender::Result result, dhcp_ddns::NameChangeRequestPtr &ncr)
Implements the error handler for DHCP_DDNS IO errors.
Definition: dhcp6_srv.cc:3639
isc::dhcp::ConstCfgRSOOPtr
boost::shared_ptr< const CfgRSOO > ConstCfgRSOOPtr
Pointer to the const object.
Definition: cfg_rsoo.h:74
isc::dhcp::ClientClassDefPtr
boost::shared_ptr< ClientClassDef > ClientClassDefPtr
a pointer to an ClientClassDef
Definition: client_class_def.h:252
isc::dhcp::IfaceMgr::closeSockets
void closeSockets()
Closes all open sockets.
Definition: iface_mgr.cc:282
isc::dhcp::Dhcpv6Srv::getVersion
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Definition: dhcp6_srv.cc:3654
isc::dhcp::evaluateBool
bool evaluateBool(const Expression &expr, Pkt &pkt)
Evaluate a RPN expression for a v4 or v6 packet and return a true or false decision.
Definition: evaluate.cc:14
pointer_util.h
isc::dhcp::IfaceMgr::instance
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
dhcp6_log.h
isc::util::OutputBuffer::getLength
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
isc::dhcp::Dhcpv6Srv::assignIA_PD
OptionPtr assignIA_PD(const Pkt6Ptr &query, const isc::dhcp::Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx, boost::shared_ptr< Option6IA > ia)
Processes IA_PD option (and assigns prefixes if necessary).
Definition: dhcp6_srv.cc:1828
DHCPV6_CONFIRM
@ DHCPV6_CONFIRM
Definition: dhcp6.h:216
D6O_SERVERID
@ D6O_SERVERID
Definition: dhcp6.h:22
isc::dhcp
Definition: ctrl_dhcp4_srv.cc:75
isc::dhcp::OptionUint16ArrayPtr
boost::shared_ptr< OptionUint16Array > OptionUint16ArrayPtr
Definition: option_int_array.h:33
isc::dhcp::Dhcpv6Srv::sanityCheck
bool sanityCheck(const Pkt6Ptr &pkt)
Verifies if specified packet meets RFC requirements.
Definition: dhcp6_srv.cc:1249
subnet.h
isc::dhcp::Dhcpv6Srv::releaseLeases
void releaseLeases(const Pkt6Ptr &release, Pkt6Ptr &reply, AllocEngine::ClientContext6 &ctx)
Attempts to release received addresses.
Definition: dhcp6_srv.cc:2324
isc::dhcp::Dhcpv6Srv::classifyByVendor
void classifyByVendor(const Pkt6Ptr &pkt, std::string &classes)
Assign class using vendor-class-identifier option.
Definition: dhcp6_srv.cc:3312
isc::dhcp::Dhcpv6Srv::declineLease
bool declineLease(const Pkt6Ptr &decline, const Lease6Ptr lease, boost::shared_ptr< Option6IA > ia_rsp)
Declines specific IPv6 lease.
Definition: dhcp6_srv.cc:3176
DHCPV6_DHCPV4_RESPONSE
@ DHCPV6_DHCPV4_RESPONSE
Definition: dhcp6.h:237
isc::dhcp::Dhcpv6Srv::extendLeases
void extendLeases(const Pkt6Ptr &query, Pkt6Ptr &reply, AllocEngine::ClientContext6 &ctx)
Attempts to extend the lifetime of IAs.
Definition: dhcp6_srv.cc:2283
isc::dhcp_ddns
Definition: dhcp_ddns_log.cc:14
isc::dhcp::NetworkState
Holds information about DHCP service enabling status.
Definition: network_state.h:57
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
memfile_lease_mgr.h
isc::dhcp::AllocEngine::ClientContext6
Context information for the DHCPv6 leases allocation.
Definition: alloc_engine.h:316
isc::dhcp::PoolPtr
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition: pool.h:405
isc::dhcp::ConstCfgHostOperationsPtr
boost::shared_ptr< const CfgHostOperations > ConstCfgHostOperationsPtr
Pointer to the const object.
Definition: cfg_host_operations.h:29
isc::dhcp::SkipRemainingOptionsError
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition: option.h:52
DHCPV6_RECONFIGURE
@ DHCPV6_RECONFIGURE
Definition: dhcp6.h:222
isc::dhcp::Dhcpv6Srv::network_state_
NetworkStatePtr network_state_
Holds information about disabled DHCP service and/or disabled subnet/network scopes.
Definition: dhcp6_srv.h:993
isc::dhcp::Dhcpv6Srv::startD2
void startD2()
Starts DHCP_DDNS client IO if DDNS updates are enabled.
Definition: dhcp6_srv.cc:3618
isc::stats
Definition: context.cc:13
isc::dhcp::OptionVendorClass
This class encapsulates DHCPv6 Vendor Class and DHCPv4 V-I Vendor Class options.
Definition: option_vendor_class.h:41
LOG_WARN
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
isc::dhcp::ClientClasses::empty
bool empty() const
Check if classes is empty.
Definition: classify.h:68
isc::dhcp::Dhcpv6Srv::processStatsSent
static void processStatsSent(const Pkt6Ptr &response)
Updates statistics for transmitted packets.
Definition: dhcp6_srv.cc:3786
D6O_IA_NA
@ D6O_IA_NA
Definition: dhcp6.h:23
stats_mgr.h
isc::dhcp::bad_packet6_logger
isc::log::Logger bad_packet6_logger(DHCP6_BAD_PACKET_LOGGER_NAME)
Logger for rejected packets.
Definition: dhcp6_log.h:93
isc::dhcp::SignalInterruptOnSelect
Exception thrown when a call to select is interrupted by a signal.
Definition: iface_mgr.h:51
isc::dhcp::Dhcpv6Srv::VENDOR_CLASS_PREFIX
static const std::string VENDOR_CLASS_PREFIX
this is a prefix added to the content of vendor-class option
Definition: dhcp6_srv.h:788
isc::dhcp::Dhcpv6Srv::run
bool run()
Main server processing loop.
Definition: dhcp6_srv.cc:404
isc::dhcp::AllocEngine::ClientContext6::hostname_
std::string hostname_
Hostname.
Definition: alloc_engine.h:372
isc::dhcp::AllocEngine::ClientContext6::new_leases_
Lease6Collection new_leases_
A collection of newly allocated leases.
Definition: alloc_engine.h:381
isc::dhcp::Host::IDENT_HWADDR
@ IDENT_HWADDR
Definition: host.h:253
isc::dhcp_ddns::CHG_ADD
@ CHG_ADD
Definition: ncr_msg.h:47
dhcp6.h
isc::dhcp::Dhcpv6Srv::appendRequestedOptions
void appendRequestedOptions(const Pkt6Ptr &question, Pkt6Ptr &answer, const CfgOptionList &co_list)
Appends requested options to server's answer.
Definition: dhcp6_srv.cc:1120
isc::dhcp::Dhcpv6Srv::appendRequestedVendorOptions
void appendRequestedVendorOptions(const Pkt6Ptr &question, Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx, const CfgOptionList &co_list)
Appends requested vendor options to server's answer.
Definition: dhcp6_srv.cc:1172
DHCPV6_ADVERTISE
@ DHCPV6_ADVERTISE
Definition: dhcp6.h:214
isc::dhcp::Dhcpv6Srv::sendPacket
virtual void sendPacket(const Pkt6Ptr &pkt)
dummy wrapper around IfaceMgr::send()
Definition: dhcp6_srv.cc:254
isc::dhcp::Dhcp4o6IpcBase::send
void send(const Pkt6Ptr &pkt)
Send message over IPC.
Definition: dhcp4o6_ipc.cc:226
isc::dhcp_ddns::NameChangeRequest
Represents a DHCP-DDNS client request.
Definition: ncr_msg.h:227
isc::dhcp::OptionDescriptor::option_
OptionPtr option_
Option instance.
Definition: cfg_option.h:38
option_vendor.h
dhcp6_srv.h
D6O_RELAY_SOURCE_PORT
@ D6O_RELAY_SOURCE_PORT
Definition: dhcp6.h:155
D6O_DHCPV4_MSG
@ D6O_DHCPV4_MSG
Definition: dhcp6.h:107
isc::dhcp::CfgSubnets6::initSelector
static SubnetSelector initSelector(const Pkt6Ptr &query)
Build selector from a client's message.
Definition: cfg_subnets6.cc:73
isc::dhcp::LeaseMgr::deleteLease
virtual bool deleteLease(const isc::asiolink::IOAddress &addr)=0
Deletes a lease.
isc::dhcp::Dhcpv6Srv::processRebind
Pkt6Ptr processRebind(AllocEngine::ClientContext6 &ctx)
Processes incoming Rebind message.
Definition: dhcp6_srv.cc:2827
isc::dhcp::Host::getIdentifierAsText
std::string getIdentifierAsText() const
Returns host identifier in a textual form.
Definition: host.cc:239
DHCPV6_DECLINE
@ DHCPV6_DECLINE
Definition: dhcp6.h:221
isc::dhcp::Dhcpv6Srv::processPacketBufferSend
void processPacketBufferSend(hooks::CalloutHandlePtr &callout_handle, Pkt6Ptr &rsp)
Executes buffer6_send callout and sends the response.
Definition: dhcp6_srv.cc:951
STATUS_NoBinding
@ STATUS_NoBinding
Definition: dhcp6.h:176
isc::dhcp::RFCViolation
An exception that is thrown if a DHCPv6 protocol violation occurs while processing a message (e....
Definition: utils.h:17
D6O_VENDOR_CLASS
@ D6O_VENDOR_CLASS
Definition: dhcp6.h:36
isc::dhcp::DUIDFactory::get
DuidPtr get()
Returns current DUID.
Definition: duid_factory.cc:346
option_vendor_class.h
isc::dhcp::Dhcpv6Srv::getIOService
asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service used by the server.
Definition: dhcp6_srv.h:90
isc::dhcp::Dhcpv6Srv::processConfirm
Pkt6Ptr processConfirm(AllocEngine::ClientContext6 &ctx)
Processes incoming Confirm message and returns Reply.
Definition: dhcp6_srv.cc:2853
isc::dhcp::DBG_DHCP6_START
const int DBG_DHCP6_START
Debug level used to log information during server startup.
Definition: dhcp6_log.h:21
D6O_IAADDR
@ D6O_IAADDR
Definition: dhcp6.h:25
isc::log::DBGLVL_TRACE_BASIC
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Definition: log_dbglevels.h:65
isc::dhcp::AllocEngine::HintContainer
std::vector< ResourceType > HintContainer
Container for client's hints.
Definition: alloc_engine.h:283
isc::detail::config_report
const char *const config_report[]
isc::dhcp::D2ClientConfig::RCM_WHEN_NOT_PRESENT
@ RCM_WHEN_NOT_PRESENT
Definition: d2_client_cfg.h:76
isc::dhcp::D2ClientMgr
D2ClientMgr isolates Kea from the details of being a D2 client.
Definition: d2_client_mgr.h:79
range_utilities.h
isc::dhcp::Dhcpv6Srv::setStatusCode
void setStatusCode(boost::shared_ptr< Option6IA > &container, const OptionPtr &status)
A simple utility method that sets the status code.
Definition: dhcp6_srv.cc:3167
DOCSIS3_V6_ORO
#define DOCSIS3_V6_ORO
Definition: docsis3_option_defs.h:31
isc::dhcp::Dhcpv6Srv::shutdown_
volatile bool shutdown_
Indicates if shutdown is in progress.
Definition: dhcp6_srv.h:971
isc::dhcp::Option6ClientFqdnPtr
boost::shared_ptr< Option6ClientFqdn > Option6ClientFqdnPtr
A pointer to the Option6ClientFqdn object.
Definition: option6_client_fqdn.h:265
isc::dhcp::DBG_DHCP6_BASIC_DATA
const int DBG_DHCP6_BASIC_DATA
Debug level used to log the traces with some basic data.
Definition: dhcp6_log.h:42
cfgmgr.h
isc::dhcp::D2ClientMgr::getUpdateDirections
void getUpdateDirections(const T &fqdn_resp, bool &forward, bool &reverse)
Get directional update flags based on server FQDN flags.
Definition: d2_client_mgr.h:457
io_utilities.h
mysql_lease_mgr.h
isc::dhcp::Dhcpv6Srv::processDecline
Pkt6Ptr processDecline(AllocEngine::ClientContext6 &ctx)
Process incoming Decline message.
Definition: dhcp6_srv.cc:2969
isc::dhcp::ClientClasses::const_iterator
std::list< ClientClass >::const_iterator const_iterator
Type of iterators.
Definition: classify.h:47
isc::dhcp::Subnet6Ptr
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:629
isc::dhcp::Option::V6
@ V6
Definition: option.h:67
isc::dhcp::AllocEngine::ClientContext6::IAContext::ia_rsp_
Option6IAPtr ia_rsp_
A pointer to the IA_NA/IA_PD option to be sent in response.
Definition: alloc_engine.h:420
isc::dhcp::CfgMgr::getCurrentCfg
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:154
isc::dhcp::Dhcpv6Srv::setReservedClientClasses
void setReservedClientClasses(const Pkt6Ptr &pkt, const AllocEngine::ClientContext6 &ctx)
Assigns classes retrieved from host reservation database.
Definition: dhcp6_srv.cc:3395
isc::dhcp::OptionVendor
This class represents vendor-specific information option.
Definition: option_vendor.h:30
isc::dhcp::CfgMgr::getD2ClientMgr
D2ClientMgr & getD2ClientMgr()
Fetches the DHCP-DDNS manager.
Definition: cfgmgr.cc:65
isc::dhcp::OptionVendorClassPtr
boost::shared_ptr< OptionVendorClass > OptionVendorClassPtr
Defines a pointer to the OptionVendorClass.
Definition: option_vendor_class.h:205
isc::dhcp::Option6PDExcludePtr
boost::shared_ptr< Option6PDExclude > Option6PDExcludePtr
Pointer to the Option6PDExclude object.
Definition: option6_pdexclude.h:124
D6O_ORO
@ D6O_ORO
Definition: dhcp6.h:26
isc::dhcp::Pool6::getPrefixExcludeOption
Option6PDExcludePtr getPrefixExcludeOption() const
Returns instance of the pool specific Prefix Exclude option.
Definition: pool.h:352
isc::dhcp::DOCSIS3_CLASS_MODEM
const char * DOCSIS3_CLASS_MODEM
DOCSIS3.0 compatible cable modem.
Definition: libdhcp++.cc:69
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition: option.h:37
isc::dhcp::Dhcpv6Srv::processRenew
Pkt6Ptr processRenew(AllocEngine::ClientContext6 &ctx)
Processes incoming Renew message.
Definition: dhcp6_srv.cc:2801
isc::dhcp::Dhcpv6Srv::processInfRequest
Pkt6Ptr processInfRequest(AllocEngine::ClientContext6 &ctx)
Processes incoming Information-request message.
Definition: dhcp6_srv.cc:3259
exceptions.h
isc::dhcp::Dhcpv6Srv::processRelease
Pkt6Ptr processRelease(AllocEngine::ClientContext6 &ctx)
Process incoming Release message.
Definition: dhcp6_srv.cc:2943
isc::dhcp::Pool6
Pool information for IPv6 addresses and prefixes.
Definition: pool.h:272
isc::dhcp::Dhcpv6Srv::declineIA
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.
Definition: dhcp6_srv.cc:3042
isc::dhcp::OptionDescriptor
Option descriptor.
Definition: cfg_option.h:35
isc::dhcp::OptionContainerPersistIndex
OptionContainer::nth_index< 2 >::type OptionContainerPersistIndex
Type of the index #2 - option persistency flag.
Definition: cfg_option.h:215
isc::dhcp::ClientClasses::insert
void insert(const ClientClass &class_name)
Insert an element.
Definition: classify.h:62
isc::dhcp::DBG_DHCP6_DETAIL_DATA
const int DBG_DHCP6_DETAIL_DATA
This level is used to log the contents of packets received and sent.
Definition: dhcp6_log.h:53
isc::dhcp::AllocEngine::ClientContext6::IAContext::type_
Lease::Type type_
Lease type (IA or PD)
Definition: alloc_engine.h:393
isc::hooks
Definition: callout_handle.cc:21
D6O_CLIENTID
@ D6O_CLIENTID
Definition: dhcp6.h:21
callout_handle.h
isc::util::OutputBuffer::getData
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
Definition: buffer.h:401
isc::dhcp::DBG_DHCP6_DETAIL
const int DBG_DHCP6_DETAIL
Debug level used to trace detailed errors.
Definition: dhcp6_log.h:50
isc::dhcp::Dhcpv6Srv::testUnicast
bool testUnicast(const Pkt6Ptr &pkt) const
Check if the message can be sent to unicast.
Definition: dhcp6_srv.cc:282
isc::dhcp::DUID
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
isc::dhcp::MySqlLeaseMgr::getDBVersion
static std::string getDBVersion()
Local version of getDBVersion() class method.
Definition: mysql_lease_mgr.cc:1710
isc::dhcp::Option6ClientFqdn::setDomainName
void setDomainName(const std::string &domain_name, const DomainNameType domain_name_type)
Set new domain-name.
Definition: option6_client_fqdn.cc:390
isc::dhcp::CfgMACSources
std::vector< uint32_t > CfgMACSources
Container for defined MAC/hardware address sources.
Definition: cfg_mac_source.h:19
isc::dhcp::Dhcpv6Srv::FORBIDDEN
@ FORBIDDEN
Definition: dhcp6_srv.h:68
isc::dhcp::Dhcpv6Srv::copyClientOptions
void copyClientOptions(const Pkt6Ptr &question, Pkt6Ptr &answer)
Copies required options from client message to server answer.
Definition: dhcp6_srv.cc:1028
isc::dhcp::Dhcpv6Srv::classifyPacket
void classifyPacket(const Pkt6Ptr &pkt)
Assigns incoming packet to zero or more classes.
Definition: dhcp6_srv.cc:3334
isc::dhcp::D2ClientMgr::stopSender
void stopSender()
Disables sending NameChangeRequests to kea-dhcp-ddns.
Definition: d2_client_mgr.cc:268
cql_lease_mgr.h
D6O_STATUS_CODE
@ D6O_STATUS_CODE
Definition: dhcp6.h:33
option6_iaaddr.h
isc::dhcp::D2ClientMgr::getD2ClientConfig
const D2ClientConfigPtr & getD2ClientConfig() const
Fetches the DHCP-DDNS configuration pointer.
Definition: d2_client_mgr.cc:111
isc::dhcp::Option6ClientFqdn::FULL
@ FULL
Definition: option6_client_fqdn.h:107
isc::dhcp::Lease6Collection
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:604
isc::dhcp::AllocEngine::ClientContext6::currentHost
ConstHostPtr currentHost() const
Returns host from the most preferred subnet.
Definition: alloc_engine.cc:483
isc::dhcp::Option6IAPrefixPtr
boost::shared_ptr< Option6IAPrefix > Option6IAPrefixPtr
Pointer to the Option6IAPrefix object.
Definition: option6_iaprefix.h:142
isc::dhcp::AllocEngine::ClientContext6::rev_dns_update_
bool rev_dns_update_
A boolean value which indicates that server takes responsibility for the reverse DNS Update for this ...
Definition: alloc_engine.h:366
isc::dhcp::lease6_logger
isc::log::Logger lease6_logger(DHCP6_LEASE_LOGGER_NAME)
Logger for lease allocation logic.
Definition: dhcp6_log.h:116
isc::dhcp::Dhcpv6Srv::processRequest
Pkt6Ptr processRequest(AllocEngine::ClientContext6 &ctx)
Processes incoming Request and returns Reply response.
Definition: dhcp6_srv.cc:2775
isc::dhcp::dhcp6_config_report
const char *const * dhcp6_config_report
Definition: dhcp6_srv.cc:3651
isc::dhcp::Option6StatusCode
This class represents Status Code option (13) from RFC 8415.
Definition: option6_status_code.h:24
isc::dhcp::Dhcpv6Srv::processClientFqdn
void processClientFqdn(const Pkt6Ptr &question, const Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx)
Processes Client FQDN Option.
Definition: dhcp6_srv.cc:1499
isc::dhcp::Option
Definition: option.h:58
D6O_IAPREFIX
@ D6O_IAPREFIX
Definition: dhcp6.h:46
option6_pdexclude.h
duid_factory.h
isc::dhcp::AllocEngine::ClientContext6::IAContext::addHint
void addHint(const asiolink::IOAddress &prefix, const uint8_t prefix_len=128)
Convenience method adding new hint.
Definition: alloc_engine.cc:462
option_custom.h
isc::dhcp::Dhcpv6Srv::createNameChangeRequests
void createNameChangeRequests(const Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx)
Creates a number of isc::dhcp_ddns::NameChangeRequest objects based on the DHCPv6 Client FQDN Option.
Definition: dhcp6_srv.cc:1572
isc::dhcp::Host::IDENT_FLEX
@ IDENT_FLEX
Flexible host identifier.
Definition: host.h:257
STATUS_NotOnLink
@ STATUS_NotOnLink
Definition: dhcp6.h:177
isc::dhcp::Dhcpv6Srv::testServerID
bool testServerID(const Pkt6Ptr &pkt)
Compare received server id with our server id.
Definition: dhcp6_srv.cc:259
isc::dhcp::OptionBufferConstIter
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition: option.h:31
isc::dhcp::Dhcpv6Srv::extendIA_NA
OptionPtr extendIA_NA(const Pkt6Ptr &query, const Pkt6Ptr &answer, AllocEngine::ClientContext6 &ctx, Option6IAPtr ia)
Extends lifetime of the specific IA_NA option.
Definition: dhcp6_srv.cc:1942
isc::dhcp::Dhcpv6Srv::selectSubnet
isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr &question, bool &drop)
Selects a subnet for a given client's packet.
Definition: dhcp6_srv.cc:1363
option_int_array.h
D6O_CLIENT_FQDN
@ D6O_CLIENT_FQDN
Definition: dhcp6.h:59
isc::dhcp::Option6IAPtr
boost::shared_ptr< Option6IA > Option6IAPtr
A pointer to the Option6IA object.
Definition: option6_ia.h:17
isc::dhcp::Lease::TYPE_NA
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:39
isc::dhcp::AllocEngine::ClientContext6::currentIA
IAContext & currentIA()
Returns IA specific context for the currently processed IA.
Definition: alloc_engine.h:467
isc::dhcp::LeaseMgr::updateLease6
virtual void updateLease6(const Lease6Ptr &lease6)=0
Updates IPv6 lease.
isc::dhcp::ClientClasses::cend
const_iterator cend() const
Iterator to the past the end element.
Definition: classify.h:86
isc::dhcp::Option6ClientFqdn::PARTIAL
@ PARTIAL
Definition: option6_client_fqdn.h:106
isc::dhcp::queueNCR
void queueNCR(const NameChangeType &chg_type, const Lease4Ptr &lease)
Creates name change request from the DHCPv4 lease.
Definition: ncr_generator.cc:86
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:28
LOG_INFO
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
option6_status_code.h
isc::dhcp::ClientClassDefListPtr
boost::shared_ptr< ClientClassDefList > ClientClassDefListPtr
Defines a pointer to a ClientClassDefList.
Definition: client_class_def.h:264
DHCPV6_SOLICIT
@ DHCPV6_SOLICIT
Definition: dhcp6.h:213
isc::dhcp::Host::IDENT_DUID
@ IDENT_DUID
Definition: host.h:254
isc::dhcp::Dhcpv6Srv::stopD2
void stopD2()
Stops DHCP_DDNS client IO if DDNS updates are enabled.
Definition: dhcp6_srv.cc:3630
isc::dhcp::ClientClasses
Container for storing client class names.
Definition: classify.h:43
D6O_PD_EXCLUDE
@ D6O_PD_EXCLUDE
Definition: dhcp6.h:87
isc::dhcp::DBG_DHCP6_BASIC
const int DBG_DHCP6_BASIC
Debug level used to trace basic operations within the code.
Definition: dhcp6_log.h:30
isc::dhcp::CfgOptionList
std::list< ConstCfgOptionPtr > CfgOptionList
Const pointer list.
Definition: cfg_option.h:503
isc::dhcp::LeaseMgr::getLease6
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
option6_addrlst.h
isc::dhcp::AllocEngine::ClientContext6::query_
Pkt6Ptr query_
A pointer to the client's message.
Definition: alloc_engine.h:324
isc::dhcp::getCalloutHandle
isc::hooks::CalloutHandlePtr getCalloutHandle(const T &pktptr)
CalloutHandle Store.
Definition: callout_handle_store.h:47