Kea  2.3.5-git
lease_cmds.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2022 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 <config/command_mgr.h>
9 #include <config/cmds_impl.h>
10 #include <cc/command_interpreter.h>
11 #include <cc/data.h>
12 #include <asiolink/io_address.h>
13 #include <database/db_exceptions.h>
14 #include <dhcpsrv/cfgmgr.h>
16 #include <dhcpsrv/lease_mgr.h>
18 #include <dhcpsrv/ncr_generator.h>
20 #include <dhcpsrv/subnet_id.h>
21 #include <dhcpsrv/sanity_checker.h>
22 #include <dhcp/duid.h>
23 #include <hooks/hooks.h>
24 #include <exceptions/exceptions.h>
25 #include <lease_cmds.h>
26 #include <lease_cmds_exceptions.h>
27 #include <lease_parser.h>
28 #include <lease_cmds_log.h>
29 #include <stats/stats_mgr.h>
30 #include <util/encode/hex.h>
32 #include <util/strutil.h>
33 
34 #include <boost/scoped_ptr.hpp>
35 #include <boost/algorithm/string.hpp>
36 #include <string>
37 #include <sstream>
38 
39 using namespace isc::dhcp;
40 using namespace isc::data;
41 using namespace isc::dhcp_ddns;
42 using namespace isc::config;
43 using namespace isc::asiolink;
44 using namespace isc::hooks;
45 using namespace isc::stats;
46 using namespace isc::util;
47 using namespace std;
48 
49 namespace isc {
50 namespace lease_cmds {
51 
53 class LeaseCmdsImpl : private CmdsImpl {
54 public:
55 
57  class Parameters {
58  public:
59 
61  typedef enum {
65  TYPE_CLIENT_ID
66  } Type;
67 
70 
73 
76 
79 
82 
92  static Type txtToType(const std::string& txt) {
93  if (txt == "address") {
94  return (Parameters::TYPE_ADDR);
95  } else if (txt == "hw-address") {
96  return (Parameters::TYPE_HWADDR);
97  } else if (txt == "duid") {
98  return (Parameters::TYPE_DUID);
99  } else if (txt == "client-id") {
100  return (Parameters::TYPE_CLIENT_ID);
101  } else {
102  isc_throw(BadValue, "Incorrect identifier type: "
103  << txt << ", the only supported values are: "
104  "address, hw-address, duid");
105  }
106  }
107 
110 
113 
115  uint32_t iaid;
116 
119 
122  : subnet_id(0), addr("::"), query_type(TYPE_ADDR),
123  lease_type(Lease::TYPE_NA), iaid(0), updateDDNS(false) {
124  }
125  };
126 
127 public:
128 
137  int
138  leaseAddHandler(CalloutHandle& handle);
139 
149  int
150  lease6BulkApplyHandler(CalloutHandle& handle);
151 
160  int
161  leaseGetHandler(CalloutHandle& handle);
162 
174  int
175  leaseGetAllHandler(CalloutHandle& handle);
176 
192  int
193  leaseGetPageHandler(hooks::CalloutHandle& handle);
194 
204  int
205  leaseGetByHwAddressHandler(hooks::CalloutHandle& handle);
206 
216  int
217  leaseGetByClientIdHandler(hooks::CalloutHandle& handle);
218 
228  int
229  leaseGetByDuidHandler(hooks::CalloutHandle& handle);
230 
241  int
242  leaseGetByHostnameHandler(hooks::CalloutHandle& handle);
243 
252  int
253  lease4DelHandler(CalloutHandle& handle);
254 
263  int
264  lease6DelHandler(CalloutHandle& handle);
265 
274  int
275  lease4UpdateHandler(CalloutHandle& handle);
276 
285  int
286  lease6UpdateHandler(CalloutHandle& handle);
287 
296  int
297  lease4WipeHandler(CalloutHandle& handle);
298 
307  int
308  lease6WipeHandler(CalloutHandle& handle);
309 
318  int lease4ResendDdnsHandler(CalloutHandle& handle);
319 
328  int lease6ResendDdnsHandler(CalloutHandle& handle);
329 
338  int
339  leaseWriteHandler(CalloutHandle& handle);
340 
352  Parameters getParameters(bool v6, const ConstElementPtr& args);
353 
371  Lease6Ptr getIPv6LeaseForDelete(const Parameters& parameters) const;
372 
387  ElementPtr createFailedLeaseMap(const Lease::Type& lease_type,
388  const IOAddress& lease_address,
389  const DuidPtr& duid,
390  const int control_result,
391  const std::string& error_message) const;
392 
403  IOAddress getAddressParam(ConstElementPtr params, const std::string name,
404  short family = AF_INET) const;
405 
409  static void updateStatsOnAdd(const Lease4Ptr& lease);
410 
414  static void updateStatsOnAdd(const Lease6Ptr& lease);
415 
420  static void updateStatsOnUpdate(const Lease4Ptr& existing,
421  const Lease4Ptr& lease);
422 
427  static void updateStatsOnUpdate(const Lease6Ptr& existing,
428  const Lease6Ptr& lease);
429 
433  static void updateStatsOnDelete(const Lease4Ptr& lease);
434 
438  static void updateStatsOnDelete(const Lease6Ptr& lease);
439 
448  static bool addOrUpdate4(Lease4Ptr lease, bool force_create);
449 
458  static bool addOrUpdate6(Lease6Ptr lease, bool force_create);
459 
464  inline static ConstElementPtr getExtendedInfo6(const Lease6Ptr& lease) {
465  ConstElementPtr user_context = lease->getContext();
466  if (!user_context || (user_context->getType() != Element::map)) {
467  return (ConstElementPtr());
468  }
469  ConstElementPtr isc = user_context->get("ISC");
470  if (!isc || (isc->getType() != Element::map)) {
471  return (ConstElementPtr());
472  }
473  return (isc->get("relay-info"));
474  }
475 };
476 
477 void
478 LeaseCmdsImpl::updateStatsOnAdd(const Lease4Ptr& lease) {
479  if (!lease->stateExpiredReclaimed()) {
480  StatsMgr::instance().addValue(
481  StatsMgr::generateName("subnet", lease->subnet_id_,
482  "assigned-addresses"),
483  int64_t(1));
484  if (lease->stateDeclined()) {
485  StatsMgr::instance().addValue("declined-addresses", int64_t(1));
486 
487  StatsMgr::instance().addValue(
488  StatsMgr::generateName("subnet", lease->subnet_id_,
489  "declined-addresses"),
490  int64_t(1));
491  }
492  }
493 }
494 
495 void
496 LeaseCmdsImpl::updateStatsOnAdd(const Lease6Ptr& lease) {
497  if (!lease->stateExpiredReclaimed()) {
498  StatsMgr::instance().addValue(
499  StatsMgr::generateName("subnet", lease->subnet_id_,
500  lease->type_ == Lease::TYPE_NA ?
501  "assigned-nas" : "assigned-pds"),
502  int64_t(1));
503  if (lease->stateDeclined()) {
504  StatsMgr::instance().addValue("declined-addresses", int64_t(1));
505 
506  StatsMgr::instance().addValue(
507  StatsMgr::generateName("subnet", lease->subnet_id_,
508  "declined-addresses"),
509  int64_t(1));
510  }
511  }
512 }
513 
514 void
515 LeaseCmdsImpl::updateStatsOnUpdate(const Lease4Ptr& existing,
516  const Lease4Ptr& lease) {
517  if (!existing->stateExpiredReclaimed()) {
518  // old lease is non expired-reclaimed
519  if (existing->subnet_id_ != lease->subnet_id_) {
520  StatsMgr::instance().addValue(
521  StatsMgr::generateName("subnet", existing->subnet_id_,
522  "assigned-addresses"),
523  int64_t(-1));
524  }
525  if (existing->stateDeclined()) {
526  // old lease is declined
527  StatsMgr::instance().addValue("declined-addresses", int64_t(-1));
528 
529  StatsMgr::instance().addValue(
530  StatsMgr::generateName("subnet", existing->subnet_id_,
531  "declined-addresses"),
532  int64_t(-1));
533  }
534  if (!lease->stateExpiredReclaimed()) {
535  // new lease is non expired-reclaimed
536  if (existing->subnet_id_ != lease->subnet_id_) {
537  StatsMgr::instance().addValue(
538  StatsMgr::generateName("subnet", lease->subnet_id_,
539  "assigned-addresses"),
540  int64_t(1));
541  }
542  if (lease->stateDeclined()) {
543  // new lease is declined
544  StatsMgr::instance().addValue("declined-addresses", int64_t(1));
545 
546  StatsMgr::instance().addValue(
547  StatsMgr::generateName("subnet", lease->subnet_id_,
548  "declined-addresses"),
549  int64_t(1));
550  }
551  }
552  } else {
553  // old lease is expired-reclaimed
554  if (!lease->stateExpiredReclaimed()) {
555  // new lease is non expired-reclaimed
556  StatsMgr::instance().addValue(
557  StatsMgr::generateName("subnet", lease->subnet_id_,
558  "assigned-addresses"),
559  int64_t(1));
560  if (lease->stateDeclined()) {
561  // new lease is declined
562  StatsMgr::instance().addValue("declined-addresses", int64_t(1));
563 
564  StatsMgr::instance().addValue(
565  StatsMgr::generateName("subnet", lease->subnet_id_,
566  "declined-addresses"),
567  int64_t(1));
568  }
569  }
570  }
571 }
572 
573 void
574 LeaseCmdsImpl::updateStatsOnUpdate(const Lease6Ptr& existing,
575  const Lease6Ptr& lease) {
576  if (!existing->stateExpiredReclaimed()) {
577  // old lease is non expired-reclaimed
578  if (existing->subnet_id_ != lease->subnet_id_) {
579  StatsMgr::instance().addValue(
580  StatsMgr::generateName("subnet", existing->subnet_id_,
581  lease->type_ == Lease::TYPE_NA ?
582  "assigned-nas" : "assigned-pds"),
583  int64_t(-1));
584  }
585  if (existing->stateDeclined()) {
586  // old lease is declined
587  StatsMgr::instance().addValue("declined-addresses", int64_t(-1));
588 
589  StatsMgr::instance().addValue(
590  StatsMgr::generateName("subnet", existing->subnet_id_,
591  "declined-addresses"),
592  int64_t(-1));
593  }
594  if (!lease->stateExpiredReclaimed()) {
595  // new lease is non expired-reclaimed
596  if (existing->subnet_id_ != lease->subnet_id_) {
597  StatsMgr::instance().addValue(
598  StatsMgr::generateName("subnet", lease->subnet_id_,
599  lease->type_ == Lease::TYPE_NA ?
600  "assigned-nas" : "assigned-pds"),
601  int64_t(1));
602  }
603  if (lease->stateDeclined()) {
604  // new lease is declined
605  StatsMgr::instance().addValue("declined-addresses", int64_t(1));
606 
607  StatsMgr::instance().addValue(
608  StatsMgr::generateName("subnet", lease->subnet_id_,
609  "declined-addresses"),
610  int64_t(1));
611  }
612  }
613  } else {
614  // old lease is expired-reclaimed
615  if (!lease->stateExpiredReclaimed()) {
616  // new lease is non expired-reclaimed
617  StatsMgr::instance().addValue(
618  StatsMgr::generateName("subnet", lease->subnet_id_,
619  lease->type_ == Lease::TYPE_NA ?
620  "assigned-nas" : "assigned-pds"),
621  int64_t(1));
622  if (lease->stateDeclined()) {
623  // new lease is declined
624  StatsMgr::instance().addValue("declined-addresses", int64_t(1));
625 
626  StatsMgr::instance().addValue(
627  StatsMgr::generateName("subnet", lease->subnet_id_,
628  "declined-addresses"),
629  int64_t(1));
630  }
631  }
632  }
633 }
634 
635 void
636 LeaseCmdsImpl::updateStatsOnDelete(const Lease4Ptr& lease) {
637  if (!lease->stateExpiredReclaimed()) {
638  StatsMgr::instance().addValue(
639  StatsMgr::generateName("subnet", lease->subnet_id_,
640  "assigned-addresses"),
641  int64_t(-1));
642  if (lease->stateDeclined()) {
643  StatsMgr::instance().addValue("declined-addresses", int64_t(-1));
644 
645  StatsMgr::instance().addValue(
646  StatsMgr::generateName("subnet", lease->subnet_id_,
647  "declined-addresses"),
648  int64_t(-1));
649  }
650  }
651 }
652 
653 void
654 LeaseCmdsImpl::updateStatsOnDelete(const Lease6Ptr& lease) {
655  if (!lease->stateExpiredReclaimed()) {
656  StatsMgr::instance().addValue(
657  StatsMgr::generateName("subnet", lease->subnet_id_,
658  lease->type_ == Lease::TYPE_NA ?
659  "assigned-nas" : "assigned-pds"),
660  int64_t(-1));
661  if (lease->stateDeclined()) {
662  StatsMgr::instance().addValue("declined-addresses", int64_t(-1));
663 
664  StatsMgr::instance().addValue(
665  StatsMgr::generateName("subnet", lease->subnet_id_,
666  "declined-addresses"),
667  int64_t(-1));
668  }
669  }
670 }
671 
672 bool
673 LeaseCmdsImpl::addOrUpdate4(Lease4Ptr lease, bool force_create) {
674  Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(lease->addr_);
675  if (force_create && !existing) {
676  // lease does not exist
677  if (!LeaseMgrFactory::instance().addLease(lease)) {
679  "lost race between calls to get and add");
680  }
681  LeaseCmdsImpl::updateStatsOnAdd(lease);
682  return (true);
683  }
684  if (existing) {
685  // Update lease current expiration time with value received from the
686  // database. Some database backends reject operations on the lease if
687  // the current expiration time value does not match what is stored.
688  Lease::syncCurrentExpirationTime(*existing, *lease);
689  }
690  try {
692  } catch (const NoSuchLease&) {
693  isc_throw(LeaseCmdsConflict, "failed to update the lease with address "
694  << lease->addr_ << " either because the lease has been "
695  "deleted or it has changed in the database, in both cases a "
696  "retry might succeed");
697  }
698 
699  LeaseCmdsImpl::updateStatsOnUpdate(existing, lease);
700  return (false);
701 }
702 
703 bool
704 LeaseCmdsImpl::addOrUpdate6(Lease6Ptr lease, bool force_create) {
705  Lease6Ptr existing =
706  LeaseMgrFactory::instance().getLease6(lease->type_, lease->addr_);
707  if (force_create && !existing) {
708  // lease does not exist
709  if (!LeaseMgrFactory::instance().addLease(lease)) {
711  "lost race between calls to get and add");
712  }
713  LeaseCmdsImpl::updateStatsOnAdd(lease);
714  return (true);
715  }
716  if (existing) {
717  // Update lease current expiration time with value received from the
718  // database. Some database backends reject operations on the lease if
719  // the current expiration time value does not match what is stored.
720  Lease::syncCurrentExpirationTime(*existing, *lease);
721 
722  // Check what is the action about extended info.
723  ConstElementPtr old_extended_info = getExtendedInfo6(existing);
724  ConstElementPtr extended_info = getExtendedInfo6(lease);
725  if ((!old_extended_info && !extended_info) ||
726  (old_extended_info && extended_info &&
727  (*old_extended_info == *extended_info))) {
728  // Leave the default Lease::ACTION_IGNORE.
729  } else {
730  lease->extended_info_action_ = Lease::ACTION_UPDATE;
731  }
732  }
733  try {
735  } catch (const NoSuchLease&) {
736  isc_throw(LeaseCmdsConflict, "failed to update the lease with address "
737  << lease->addr_ << " either because the lease has been "
738  "deleted or it has changed in the database, in both cases a "
739  "retry might succeed");
740  }
741 
742  LeaseCmdsImpl::updateStatsOnUpdate(existing, lease);
743  return (false);
744 }
745 
746 int
747 LeaseCmdsImpl::leaseAddHandler(CalloutHandle& handle) {
748  // Arbitrary defaulting to DHCPv4 or with other words extractCommand
749  // below is not expected to throw...
750  bool v4 = true;
751  stringstream resp;
752  string lease_address = "unknown";
753  try {
754  extractCommand(handle);
755  v4 = (cmd_name_ == "lease4-add");
756  if (!cmd_args_) {
757  isc_throw(isc::BadValue, "no parameters specified for the command");
758  }
759 
761 
762  // This parameter is ignored for the commands adding the lease.
763  bool force_create = false;
764  Lease4Ptr lease4;
765  Lease6Ptr lease6;
766  if (v4) {
767  Lease4Parser parser;
768  lease4 = parser.parse(config, cmd_args_, force_create);
769  if (lease4) {
770  lease_address = lease4->addr_.toText();
771  bool success;
772  if (!MultiThreadingMgr::instance().getMode()) {
773  // Not multi-threading.
774  success = LeaseMgrFactory::instance().addLease(lease4);
775  } else {
776  // Multi-threading, try to lock first to avoid a race.
777  ResourceHandler4 resource_handler;
778  if (resource_handler.tryLock4(lease4->addr_)) {
779  success = LeaseMgrFactory::instance().addLease(lease4);
780  } else {
782  "ResourceBusy: IP address:" << lease4->addr_
783  << " could not be added.");
784  }
785  }
786 
787  if (!success) {
788  isc_throw(LeaseCmdsConflict, "IPv4 lease already exists.");
789  }
790 
791  LeaseCmdsImpl::updateStatsOnAdd(lease4);
792  resp << "Lease for address " << lease4->addr_.toText()
793  << ", subnet-id " << lease4->subnet_id_ << " added.";
794  }
795  } else {
796  Lease6Parser parser;
797  lease6 = parser.parse(config, cmd_args_, force_create);
798  if (lease6) {
799  lease_address = lease6->addr_.toText();
800  bool success;
801  if (!MultiThreadingMgr::instance().getMode()) {
802  // Not multi-threading.
803  success = LeaseMgrFactory::instance().addLease(lease6);
804  } else {
805  // Multi-threading, try to lock first to avoid a race.
806  ResourceHandler resource_handler;
807  if (resource_handler.tryLock(lease6->type_, lease6->addr_)) {
808  success = LeaseMgrFactory::instance().addLease(lease6);
809  } else {
811  "ResourceBusy: IP address:" << lease6->addr_
812  << " could not be added.");
813  }
814  }
815 
816  if (!success) {
817  isc_throw(LeaseCmdsConflict, "IPv6 lease already exists.");
818  }
819 
820  LeaseCmdsImpl::updateStatsOnAdd(lease6);
821  if (lease6->type_ == Lease::TYPE_NA) {
822  resp << "Lease for address " << lease6->addr_.toText()
823  << ", subnet-id " << lease6->subnet_id_ << " added.";
824  } else {
825  resp << "Lease for prefix " << lease6->addr_.toText()
826  << "/" << static_cast<int>(lease6->prefixlen_)
827  << ", subnet-id " << lease6->subnet_id_ << " added.";
828  }
829  }
830  }
831  } catch (const LeaseCmdsConflict& ex) {
833  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
834  .arg(ex.what());
835  setErrorResponse(handle, ex.what(), CONTROL_RESULT_CONFLICT);
836  return (0);
837 
838  } catch (const std::exception& ex) {
840  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
841  .arg(ex.what());
842  setErrorResponse(handle, ex.what());
843  return (1);
844  }
845 
848  .arg(lease_address);
849  setSuccessResponse(handle, resp.str());
850  return (0);
851 }
852 
854 LeaseCmdsImpl::getParameters(bool v6, const ConstElementPtr& params) {
855  Parameters x;
856 
857  if (!params || params->getType() != Element::map) {
858  isc_throw(BadValue, "Parameters missing or are not a map.");
859  }
860 
861  if (params->contains("update-ddns")) {
862  ConstElementPtr tmp = params->get("update-ddns");
863  if (tmp->getType() != Element::boolean) {
864  isc_throw(BadValue, "'update-ddns' is not a boolean");
865  } else {
866  x.updateDDNS = tmp->boolValue();
867  }
868  }
869 
870  // We support several sets of parameters for leaseX-get/lease-del:
871  // lease-get(type, address)
872  // lease-get(type, subnet-id, identifier-type, identifier)
873 
874  if (params->contains("type")) {
875  string t = params->get("type")->stringValue();
876  if (t == "IA_NA" || t == "0") {
878  } else if (t == "IA_TA" || t == "1") {
880  } else if (t == "IA_PD" || t == "2") {
882  } else if (t == "V4" || t == "3") {
884  } else {
885  isc_throw(BadValue, "Invalid lease type specified: "
886  << t << ", only supported values are: IA_NA, IA_TA,"
887  << " IA_PD and V4");
888  }
889  }
890 
891  ConstElementPtr tmp = params->get("ip-address");
892  if (tmp) {
893  if (tmp->getType() != Element::string) {
894  isc_throw(BadValue, "'ip-address' is not a string.");
895  }
896 
897  x.addr = IOAddress(tmp->stringValue());
898 
899  if ((v6 && !x.addr.isV6()) || (!v6 && !x.addr.isV4())) {
900  stringstream txt;
901  txt << "Invalid " << (v6 ? "IPv6" : "IPv4")
902  << " address specified: " << tmp->stringValue();
903  isc_throw(BadValue, txt.str());
904  }
905 
906  x.query_type = Parameters::TYPE_ADDR;
907  return (x);
908  }
909 
910  tmp = params->get("subnet-id");
911  if (!tmp) {
912  isc_throw(BadValue, "Mandatory 'subnet-id' parameter missing.");
913  }
914  if (tmp->getType() != Element::integer) {
915  isc_throw(BadValue, "'subnet-id' parameter is not integer.");
916  }
917  x.subnet_id = tmp->intValue();
918 
919  if (params->contains("iaid")) {
920  x.iaid = params->get("iaid")->intValue();
921  }
922 
923  // No address specified. Ok, so it must be identifier based query.
924  // "identifier-type": "duid",
925  // "identifier": "aa:bb:cc:dd:ee:..."
926 
927  ConstElementPtr type = params->get("identifier-type");
928  ConstElementPtr ident = params->get("identifier");
929  if (!type || type->getType() != Element::string) {
930  isc_throw(BadValue, "No 'ip-address' provided"
931  " and 'identifier-type' is either missing or not a string.");
932  }
933  if (!ident || ident->getType() != Element::string) {
934  isc_throw(BadValue, "No 'ip-address' provided"
935  " and 'identifier' is either missing or not a string.");
936  }
937 
938  // Got the parameters. Let's see if their values make sense.
939  // Try to convert identifier-type
940  x.query_type = Parameters::txtToType(type->stringValue());
941 
942  switch (x.query_type) {
943  case Parameters::TYPE_HWADDR: {
944  HWAddr hw = HWAddr::fromText(ident->stringValue());
945  x.hwaddr = HWAddrPtr(new HWAddr(hw));
946  break;
947  }
948  case Parameters::TYPE_CLIENT_ID: {
949  x.client_id = ClientId::fromText(ident->stringValue());
950  break;
951  }
952  case Parameters::TYPE_DUID: {
953  DUID duid = DUID::fromText(ident->stringValue());
954  x.duid = DuidPtr(new DUID(duid));
955  break;
956  }
957  case Parameters::TYPE_ADDR: {
958  // We should never get here. The address clause should have been caught
959  // earlier.
960  return (x);
961  }
962  default: {
963  isc_throw(BadValue, "Identifier type " << type->stringValue() <<
964  " is not supported.");
965  }
966  }
967 
968  return (x);
969 }
970 
971 int
972 LeaseCmdsImpl::leaseGetHandler(CalloutHandle& handle) {
973  Parameters p;
974  Lease4Ptr lease4;
975  Lease6Ptr lease6;
976  bool v4 = true;
977  try {
978  extractCommand(handle);
979  v4 = (cmd_name_ == "lease4-get");
980  p = getParameters(!v4, cmd_args_);
981  switch (p.query_type) {
982  case Parameters::TYPE_ADDR: {
983  // Query by address
984  if (v4) {
986  } else {
988  }
989  break;
990  }
991  case Parameters::TYPE_HWADDR:
992  if (v4) {
993  if (!p.hwaddr) {
994  isc_throw(InvalidParameter, "Program error: Query by hw-address "
995  "requires hwaddr to be specified");
996  }
997 
999  } else {
1000  isc_throw(isc::InvalidParameter, "Query by hw-address is not allowed in v6.");
1001  }
1002  break;
1003 
1004  case Parameters::TYPE_DUID:
1005  if (!v4) {
1006  if (!p.duid) {
1007  isc_throw(InvalidParameter, "Program error: Query by duid "
1008  "requires duid to be specified");
1009  }
1010 
1012  p.iaid, p.subnet_id);
1013  } else {
1014  isc_throw(InvalidParameter, "Query by duid is not allowed in v4.");
1015  }
1016  break;
1017 
1018  case Parameters::TYPE_CLIENT_ID:
1019  if (v4) {
1020  if (!p.client_id) {
1021  isc_throw(InvalidParameter, "Program error: Query by client-id "
1022  "requires client-id to be specified");
1023  }
1024 
1026  } else {
1027  isc_throw(isc::InvalidParameter, "Query by client-id is not allowed in v6.");
1028  }
1029  break;
1030 
1031  default: {
1032  isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1033  break;
1034  }
1035  }
1036  } catch (const std::exception& ex) {
1038  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1039  .arg(ex.what());
1040  setErrorResponse(handle, ex.what());
1041  return (1);
1042  }
1043 
1044  ElementPtr lease_json;
1045  if (v4 && lease4) {
1046  lease_json = lease4->toElement();
1048  "IPv4 lease found.", lease_json);
1049  setResponse(handle, response);
1050  } else if (!v4 && lease6) {
1051  lease_json = lease6->toElement();
1053  "IPv6 lease found.", lease_json);
1054  setResponse(handle, response);
1055  } else {
1056  // If we got here, the lease has not been found.
1057  setErrorResponse(handle, "Lease not found.", CONTROL_RESULT_EMPTY);
1058  }
1059 
1060  return (0);
1061 }
1062 
1063 int
1064 LeaseCmdsImpl::leaseGetAllHandler(CalloutHandle& handle) {
1065  bool v4 = true;
1066  try {
1067  extractCommand(handle);
1068  v4 = (cmd_name_ == "lease4-get-all");
1069 
1070  ElementPtr leases_json = Element::createList();
1071 
1072  // The argument may contain a list of subnets for which leases should
1073  // be returned.
1074  if (cmd_args_) {
1075  ConstElementPtr subnets = cmd_args_->get("subnets");
1076  if (!subnets) {
1077  isc_throw(BadValue, "'subnets' parameter not specified");
1078  }
1079  if (subnets->getType() != Element::list) {
1080  isc_throw(BadValue, "'subnets' parameter must be a list");
1081  }
1082 
1083  const std::vector<ElementPtr>& subnet_ids = subnets->listValue();
1084  for (auto subnet_id = subnet_ids.begin();
1085  subnet_id != subnet_ids.end();
1086  ++subnet_id) {
1087  if ((*subnet_id)->getType() != Element::integer) {
1088  isc_throw(BadValue, "listed subnet identifiers must be numbers");
1089  }
1090 
1091  if (v4) {
1092  Lease4Collection leases =
1093  LeaseMgrFactory::instance().getLeases4((*subnet_id)->intValue());
1094  for (auto lease : leases) {
1095  ElementPtr lease_json = lease->toElement();
1096  leases_json->add(lease_json);
1097  }
1098  } else {
1099  Lease6Collection leases =
1100  LeaseMgrFactory::instance().getLeases6((*subnet_id)->intValue());
1101  for (auto lease : leases) {
1102  ElementPtr lease_json = lease->toElement();
1103  leases_json->add(lease_json);
1104  }
1105  }
1106  }
1107 
1108  } else {
1109  // There is no 'subnets' argument so let's return all leases.
1110  if (v4) {
1112  for (auto lease : leases) {
1113  ElementPtr lease_json = lease->toElement();
1114  leases_json->add(lease_json);
1115  }
1116  } else {
1118  for (auto lease : leases) {
1119  ElementPtr lease_json = lease->toElement();
1120  leases_json->add(lease_json);
1121  }
1122  }
1123  }
1124 
1125  std::ostringstream s;
1126  s << leases_json->size()
1127  << " IPv" << (v4 ? "4" : "6")
1128  << " lease(s) found.";
1129  ElementPtr args = Element::createMap();
1130  args->set("leases", leases_json);
1131  ConstElementPtr response =
1132  createAnswer(leases_json->size() > 0 ?
1135  s.str(), args);
1136  setResponse(handle, response);
1137 
1138  } catch (const std::exception& ex) {
1139  setErrorResponse(handle, ex.what());
1140  return (CONTROL_RESULT_ERROR);
1141  }
1142 
1143  return (0);
1144 }
1145 
1146 int
1147 LeaseCmdsImpl::leaseGetPageHandler(CalloutHandle& handle) {
1148  bool v4 = true;
1149  try {
1150  extractCommand(handle);
1151  v4 = (cmd_name_ == "lease4-get-page");
1152 
1153  // arguments must always be present
1154  if (!cmd_args_) {
1155  isc_throw(BadValue, "no parameters specified for the " << cmd_name_
1156  << " command");
1157  }
1158 
1159  // The 'from' argument denotes from which lease we should start the
1160  // results page. The results page excludes this lease.
1161  ConstElementPtr from = cmd_args_->get("from");
1162  if (!from) {
1163  isc_throw(BadValue, "'from' parameter not specified");
1164  }
1165 
1166  // The 'from' argument is a string. It may contain a 'start' keyword or
1167  // an IP address.
1168  if (from->getType() != Element::string) {
1169  isc_throw(BadValue, "'from' parameter must be a string");
1170  }
1171 
1172  boost::scoped_ptr<IOAddress> from_address;
1173  try {
1174  if (from->stringValue() == "start") {
1175  from_address.reset(new IOAddress(v4 ? "0.0.0.0" : "::"));
1176 
1177  } else {
1178  // Conversion of a string to an IP address may throw.
1179  from_address.reset(new IOAddress(from->stringValue()));
1180  }
1181 
1182  } catch (...) {
1183  isc_throw(BadValue, "'from' parameter value is neither 'start' keyword nor "
1184  "a valid IPv" << (v4 ? "4" : "6") << " address");
1185  }
1186 
1187  // It must be either IPv4 address for lease4-get-page or IPv6 address for
1188  // lease6-get-page.
1189  if (v4 && (!from_address->isV4())) {
1190  isc_throw(BadValue, "'from' parameter value " << from_address->toText()
1191  << " is not an IPv4 address");
1192 
1193  } else if (!v4 && from_address->isV4()) {
1194  isc_throw(BadValue, "'from' parameter value " << from_address->toText()
1195  << " is not an IPv6 address");
1196  }
1197 
1198  // The 'limit' is a desired page size. It must always be present.
1199  ConstElementPtr page_limit = cmd_args_->get("limit");
1200  if (!page_limit) {
1201  isc_throw(BadValue, "'limit' parameter not specified");
1202  }
1203 
1204  // The 'limit' must be a number.
1205  if (page_limit->getType() != Element::integer) {
1206  isc_throw(BadValue, "'limit' parameter must be a number");
1207  }
1208 
1209  // Retrieve the desired page size.
1210  size_t page_limit_value = static_cast<size_t>(page_limit->intValue());
1211 
1212  ElementPtr leases_json = Element::createList();
1213 
1214  if (v4) {
1215  // Get page of IPv4 leases.
1216  Lease4Collection leases =
1217  LeaseMgrFactory::instance().getLeases4(*from_address,
1218  LeasePageSize(page_limit_value));
1219 
1220  // Convert leases into JSON list.
1221  for (auto lease : leases) {
1222  ElementPtr lease_json = lease->toElement();
1223  leases_json->add(lease_json);
1224  }
1225 
1226  } else {
1227  // Get page of IPv6 leases.
1228  Lease6Collection leases =
1229  LeaseMgrFactory::instance().getLeases6(*from_address,
1230  LeasePageSize(page_limit_value));
1231  // Convert leases into JSON list.
1232  for (auto lease : leases) {
1233  ElementPtr lease_json = lease->toElement();
1234  leases_json->add(lease_json);
1235  }
1236  }
1237 
1238  // Prepare textual status.
1239  std::ostringstream s;
1240  s << leases_json->size()
1241  << " IPv" << (v4 ? "4" : "6")
1242  << " lease(s) found.";
1243  ElementPtr args = Element::createMap();
1244 
1245  // Put gathered data into arguments map.
1246  args->set("leases", leases_json);
1247  args->set("count", Element::create(static_cast<int64_t>(leases_json->size())));
1248 
1249  // Create the response.
1250  ConstElementPtr response =
1251  createAnswer(leases_json->size() > 0 ?
1254  s.str(), args);
1255  setResponse(handle, response);
1256 
1257  } catch (const std::exception& ex) {
1258  setErrorResponse(handle, ex.what());
1259  return (CONTROL_RESULT_ERROR);
1260  }
1261 
1262  return (CONTROL_RESULT_SUCCESS);
1263 }
1264 
1265 int
1266 LeaseCmdsImpl::leaseGetByHwAddressHandler(CalloutHandle& handle) {
1267  try {
1268  extractCommand(handle);
1269 
1270  // arguments must always be present
1271  if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1272  isc_throw(BadValue, "Command arguments missing or a not a map.");
1273  }
1274 
1275  // the hw-address parameter is mandatory.
1276  ConstElementPtr hw_address = cmd_args_->get("hw-address");
1277  if (!hw_address) {
1278  isc_throw(BadValue, "'hw-address' parameter not specified");
1279  }
1280 
1281  // The 'hw-address' argument is a string.
1282  if (hw_address->getType() != Element::string) {
1283  isc_throw(BadValue, "'hw-address' parameter must be a string");
1284  }
1285 
1286  HWAddr hwaddr = HWAddr::fromText(hw_address->stringValue());
1287 
1288  Lease4Collection leases =
1290  ElementPtr leases_json = Element::createList();
1291  for (auto lease : leases) {
1292  ElementPtr lease_json = lease->toElement();
1293  leases_json->add(lease_json);
1294  }
1295 
1296  std::ostringstream s;
1297  s << leases_json->size() << " IPv4 lease(s) found.";
1298  ElementPtr args = Element::createMap();
1299  args->set("leases", leases_json);
1300  ConstElementPtr response =
1301  createAnswer(leases_json->size() > 0 ?
1304  s.str(), args);
1305  setResponse(handle, response);
1306 
1307  } catch (const std::exception& ex) {
1308  setErrorResponse(handle, ex.what());
1309  return (CONTROL_RESULT_ERROR);
1310  }
1311 
1312  return (0);
1313 }
1314 
1315 int
1316 LeaseCmdsImpl::leaseGetByClientIdHandler(CalloutHandle& handle) {
1317  try {
1318  extractCommand(handle);
1319 
1320  // arguments must always be present
1321  if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1322  isc_throw(BadValue, "Command arguments missing or a not a map.");
1323  }
1324 
1325  // the client-id parameter is mandatory.
1326  ConstElementPtr client_id = cmd_args_->get("client-id");
1327  if (!client_id) {
1328  isc_throw(BadValue, "'client-id' parameter not specified");
1329  }
1330 
1331  // The 'client-id' argument is a string.
1332  if (client_id->getType() != Element::string) {
1333  isc_throw(BadValue, "'client-id' parameter must be a string");
1334  }
1335 
1336  ClientIdPtr clientid = ClientId::fromText(client_id->stringValue());
1337 
1338  Lease4Collection leases =
1339  LeaseMgrFactory::instance().getLease4(*clientid);
1340  ElementPtr leases_json = Element::createList();
1341  for (auto lease : leases) {
1342  ElementPtr lease_json = lease->toElement();
1343  leases_json->add(lease_json);
1344  }
1345 
1346  std::ostringstream s;
1347  s << leases_json->size() << " IPv4 lease(s) found.";
1348  ElementPtr args = Element::createMap();
1349  args->set("leases", leases_json);
1350  ConstElementPtr response =
1351  createAnswer(leases_json->size() > 0 ?
1354  s.str(), args);
1355  setResponse(handle, response);
1356 
1357  } catch (const std::exception& ex) {
1358  setErrorResponse(handle, ex.what());
1359  return (CONTROL_RESULT_ERROR);
1360  }
1361 
1362  return (0);
1363 }
1364 
1365 int
1366 LeaseCmdsImpl::leaseGetByDuidHandler(CalloutHandle& handle) {
1367  try {
1368  extractCommand(handle);
1369 
1370  // arguments must always be present
1371  if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1372  isc_throw(BadValue, "Command arguments missing or a not a map.");
1373  }
1374 
1375  // the duid parameter is mandatory.
1376  ConstElementPtr duid = cmd_args_->get("duid");
1377  if (!duid) {
1378  isc_throw(BadValue, "'duid' parameter not specified");
1379  }
1380 
1381  // The 'duid' argument is a string.
1382  if (duid->getType() != Element::string) {
1383  isc_throw(BadValue, "'duid' parameter must be a string");
1384  }
1385 
1386  DUID duid_ = DUID::fromText(duid->stringValue());
1387 
1388  Lease6Collection leases =
1390  ElementPtr leases_json = Element::createList();
1391  for (auto lease : leases) {
1392  ElementPtr lease_json = lease->toElement();
1393  leases_json->add(lease_json);
1394  }
1395 
1396  std::ostringstream s;
1397  s << leases_json->size() << " IPv6 lease(s) found.";
1398  ElementPtr args = Element::createMap();
1399  args->set("leases", leases_json);
1400  ConstElementPtr response =
1401  createAnswer(leases_json->size() > 0 ?
1404  s.str(), args);
1405  setResponse(handle, response);
1406 
1407  } catch (const std::exception& ex) {
1408  setErrorResponse(handle, ex.what());
1409  return (CONTROL_RESULT_ERROR);
1410  }
1411 
1412  return (0);
1413 }
1414 
1415 int
1416 LeaseCmdsImpl::leaseGetByHostnameHandler(CalloutHandle& handle) {
1417  bool v4 = true;
1418  try {
1419  extractCommand(handle);
1420  v4 = (cmd_name_ == "lease4-get-by-hostname");
1421 
1422  // arguments must always be present
1423  if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1424  isc_throw(BadValue, "Command arguments missing or a not a map.");
1425  }
1426 
1427  // the hostname parameter is mandatory.
1428  ConstElementPtr hostname = cmd_args_->get("hostname");
1429  if (!hostname) {
1430  isc_throw(BadValue, "'hostname' parameter not specified");
1431  }
1432 
1433  // The 'hostname' argument is a string.
1434  if (hostname->getType() != Element::string) {
1435  isc_throw(BadValue, "'hostname' parameter must be a string");
1436  }
1437 
1438  std::string hostname_ = hostname->stringValue();
1440  if (hostname_.empty()) {
1441  isc_throw(BadValue, "'hostname' parameter is empty");
1442  }
1443  boost::algorithm::to_lower(hostname_);
1444 
1445  ElementPtr leases_json = Element::createList();
1446  if (v4) {
1447  Lease4Collection leases =
1449 
1450  for (auto lease : leases) {
1451  ElementPtr lease_json = lease->toElement();
1452  leases_json->add(lease_json);
1453  }
1454  } else {
1455  Lease6Collection leases =
1457 
1458  for (auto lease : leases) {
1459  ElementPtr lease_json = lease->toElement();
1460  leases_json->add(lease_json);
1461  }
1462  }
1463 
1464  std::ostringstream s;
1465  s << leases_json->size()
1466  << " IPv" << (v4 ? "4" : "6")
1467  << " lease(s) found.";
1468  ElementPtr args = Element::createMap();
1469  args->set("leases", leases_json);
1470  ConstElementPtr response =
1471  createAnswer(leases_json->size() > 0 ?
1474  s.str(), args);
1475  setResponse(handle, response);
1476 
1477  } catch (const std::exception& ex) {
1478  setErrorResponse(handle, ex.what());
1479  return (CONTROL_RESULT_ERROR);
1480  }
1481 
1482  return (0);
1483 }
1484 
1485 int
1486 LeaseCmdsImpl::lease4DelHandler(CalloutHandle& handle) {
1487  Parameters p;
1488  Lease4Ptr lease4;
1489  try {
1490  extractCommand(handle);
1491  p = getParameters(false, cmd_args_);
1492  switch (p.query_type) {
1493  case Parameters::TYPE_ADDR: {
1494  // If address was specified explicitly, let's use it as is.
1496  if (!lease4) {
1497  setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1498  return (0);
1499  }
1500  break;
1501  }
1502  case Parameters::TYPE_HWADDR: {
1503  if (!p.hwaddr) {
1504  isc_throw(InvalidParameter, "Program error: Query by hw-address "
1505  "requires hwaddr to be specified");
1506  }
1507 
1508  // Let's see if there's such a lease at all.
1510  if (!lease4) {
1511  setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1512  return (0);
1513  }
1514  break;
1515  }
1516  case Parameters::TYPE_CLIENT_ID: {
1517  if (!p.client_id) {
1518  isc_throw(InvalidParameter, "Program error: Query by client-id "
1519  "requires client-id to be specified");
1520  }
1521 
1522  // Let's see if there's such a lease at all.
1524  if (!lease4) {
1525  setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1526  return (0);
1527  }
1528  break;
1529  }
1530  case Parameters::TYPE_DUID: {
1531  isc_throw(InvalidParameter, "Delete by duid is not allowed in v4.");
1532  break;
1533  }
1534  default: {
1535  isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1536  break;
1537  }
1538  }
1539 
1540  if (LeaseMgrFactory::instance().deleteLease(lease4)) {
1541  setSuccessResponse(handle, "IPv4 lease deleted.");
1542  LeaseCmdsImpl::updateStatsOnDelete(lease4);
1543  } else {
1544  setErrorResponse (handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1545  }
1546 
1547  // Queue an NCR to remove DNS if configured and the lease has it.
1548  if (p.updateDDNS) {
1549  queueNCR(CHG_REMOVE, lease4);
1550  }
1551 
1552  } catch (const std::exception& ex) {
1554  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1555  .arg(ex.what());
1556  setErrorResponse(handle, ex.what());
1557  return (1);
1558  }
1560  .arg(lease4->addr_.toText());
1561  return (0);
1562 }
1563 
1564 int
1565 LeaseCmdsImpl::lease6BulkApplyHandler(CalloutHandle& handle) {
1566  try {
1567  extractCommand(handle);
1568 
1569  // Arguments are mandatory.
1570  if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1571  isc_throw(BadValue, "Command arguments missing or a not a map.");
1572  }
1573 
1574  // At least one of the 'deleted-leases' or 'leases' must be present.
1575  auto deleted_leases = cmd_args_->get("deleted-leases");
1576  auto leases = cmd_args_->get("leases");
1577 
1578  if (!deleted_leases && !leases) {
1579  isc_throw(BadValue, "neither 'deleted-leases' nor 'leases' parameter"
1580  " specified");
1581  }
1582 
1583  // Make sure that 'deleted-leases' is a list, if present.
1584  if (deleted_leases && (deleted_leases->getType() != Element::list)) {
1585  isc_throw(BadValue, "the 'deleted-leases' parameter must be a list");
1586  }
1587 
1588  // Make sure that 'leases' is a list, if present.
1589  if (leases && (leases->getType() != Element::list)) {
1590  isc_throw(BadValue, "the 'leases' parameter must be a list");
1591  }
1592 
1593  // Parse deleted leases without deleting them from the database
1594  // yet. If any of the deleted leases or new leases appears to be
1595  // malformed we can easily rollback.
1596  std::list<std::pair<Parameters, Lease6Ptr> > parsed_deleted_list;
1597  if (deleted_leases) {
1598  auto leases_list = deleted_leases->listValue();
1599 
1600  // Iterate over leases to be deleted.
1601  for (auto lease_params : leases_list) {
1602  // Parsing the lease may throw and it means that the lease
1603  // information is malformed.
1604  Parameters p = getParameters(true, lease_params);
1605  auto lease = getIPv6LeaseForDelete(p);
1606  parsed_deleted_list.push_back(std::make_pair(p, lease));
1607  }
1608  }
1609 
1610  // Parse new/updated leases without affecting the database to detect
1611  // any errors that should cause an error response.
1612  std::list<Lease6Ptr> parsed_leases_list;
1613  if (leases) {
1615 
1616  // Iterate over all leases.
1617  auto leases_list = leases->listValue();
1618  for (auto lease_params : leases_list) {
1619 
1620  Lease6Parser parser;
1621  bool force_update;
1622 
1623  // If parsing the lease fails we throw, as it indicates that the
1624  // command is malformed.
1625  Lease6Ptr lease6 = parser.parse(config, lease_params, force_update);
1626  parsed_leases_list.push_back(lease6);
1627  }
1628  }
1629 
1630  // Count successful deletions and updates.
1631  size_t success_count = 0;
1632 
1633  ElementPtr failed_deleted_list;
1634  if (!parsed_deleted_list.empty()) {
1635 
1636  // Iterate over leases to be deleted.
1637  for (auto lease_params_pair : parsed_deleted_list) {
1638 
1639  // This part is outside of the try-catch because an exception
1640  // indicates that the command is malformed.
1641  Parameters p = lease_params_pair.first;
1642  auto lease = lease_params_pair.second;
1643 
1644  try {
1645  if (lease) {
1646  // This may throw if the lease couldn't be deleted for
1647  // any reason, but we still want to proceed with other
1648  // leases.
1649  if (LeaseMgrFactory::instance().deleteLease(lease)) {
1650  ++success_count;
1651  LeaseCmdsImpl::updateStatsOnDelete(lease);
1652 
1653  } else {
1654  // Lazy creation of the list of leases which failed to delete.
1655  if (!failed_deleted_list) {
1656  failed_deleted_list = Element::createList();
1657  }
1658 
1659  // If the lease doesn't exist we also want to put it
1660  // on the list of leases which failed to delete. That
1661  // corresponds to the lease6-del command which returns
1662  // an error when the lease doesn't exist.
1663  failed_deleted_list->add(createFailedLeaseMap(p.lease_type,
1664  p.addr, p.duid,
1666  "lease not found"));
1667  }
1668  }
1669 
1670  } catch (const std::exception& ex) {
1671  // Lazy creation of the list of leases which failed to delete.
1672  if (!failed_deleted_list) {
1673  failed_deleted_list = Element::createList();
1674  }
1675  failed_deleted_list->add(createFailedLeaseMap(p.lease_type,
1676  p.addr, p.duid,
1678  ex.what()));
1679  }
1680  }
1681  }
1682 
1683  // Process leases to be added or/and updated.
1684  ElementPtr failed_leases_list;
1685  if (!parsed_leases_list.empty()) {
1687 
1688  // Iterate over all leases.
1689  for (auto lease : parsed_leases_list) {
1690 
1691  auto result = CONTROL_RESULT_SUCCESS;
1692  std::ostringstream text;
1693  try {
1694  if (!MultiThreadingMgr::instance().getMode()) {
1695  // Not multi-threading.
1696  addOrUpdate6(lease, true);
1697  } else {
1698  // Multi-threading, try to lock first to avoid a race.
1699  ResourceHandler resource_handler;
1700  if (resource_handler.tryLock(lease->type_, lease->addr_)) {
1701  addOrUpdate6(lease, true);
1702  } else {
1704  "ResourceBusy: IP address:" << lease->addr_
1705  << " could not be updated.");
1706  }
1707  }
1708 
1709  ++success_count;
1710  } catch (const LeaseCmdsConflict& ex) {
1711  result = CONTROL_RESULT_CONFLICT;
1712  text << ex.what();
1713 
1714  } catch (const std::exception& ex) {
1715  result = CONTROL_RESULT_ERROR;
1716  text << ex.what();
1717  }
1718  // Handle an error.
1719  if (result != CONTROL_RESULT_SUCCESS) {
1720  // Lazy creation of the list of leases which failed to add/update.
1721  if (!failed_leases_list) {
1722  failed_leases_list = Element::createList();
1723  }
1724  failed_leases_list->add(createFailedLeaseMap(lease->type_,
1725  lease->addr_,
1726  lease->duid_,
1727  result,
1728  text.str()));
1729  }
1730  }
1731  }
1732 
1733  // Start preparing the response.
1734  ElementPtr args;
1735 
1736  if (failed_deleted_list || failed_leases_list) {
1737  // If there are any failed leases, let's include them in the response.
1738  args = Element::createMap();
1739 
1740  // failed-deleted-leases
1741  if (failed_deleted_list) {
1742  args->set("failed-deleted-leases", failed_deleted_list);
1743  }
1744 
1745  // failed-leases
1746  if (failed_leases_list) {
1747  args->set("failed-leases", failed_leases_list);
1748  }
1749  }
1750 
1751  // Send the success response and include failed leases.
1752  std::ostringstream resp_text;
1753  resp_text << "Bulk apply of " << success_count << " IPv6 leases completed.";
1754  auto answer = createAnswer(success_count > 0 ? CONTROL_RESULT_SUCCESS :
1755  CONTROL_RESULT_EMPTY, resp_text.str(), args);
1756  setResponse(handle, answer);
1757 
1760  .arg(success_count);
1761 
1762  } catch (const std::exception& ex) {
1763  // Unable to parse the command and similar issues.
1765  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1766  .arg(ex.what());
1767  setErrorResponse(handle, ex.what());
1768  return (CONTROL_RESULT_ERROR);
1769  }
1770 
1771  return (0);
1772 }
1773 
1774 int
1775 LeaseCmdsImpl::lease6DelHandler(CalloutHandle& handle) {
1776  Parameters p;
1777  Lease6Ptr lease6;
1779  try {
1780  extractCommand(handle);
1781  p = getParameters(true, cmd_args_);
1782 
1783  switch (p.query_type) {
1784  case Parameters::TYPE_ADDR: {
1785  // If address was specified explicitly, let's use it as is.
1786 
1787  // Let's see if there's such a lease at all.
1789  if (!lease6) {
1790  setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
1791  return (0);
1792  }
1793  break;
1794  }
1795  case Parameters::TYPE_HWADDR: {
1796  isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6.");
1797  break;
1798  }
1799  case Parameters::TYPE_DUID: {
1800  if (!p.duid) {
1801  isc_throw(InvalidParameter, "Program error: Query by duid "
1802  "requires duid to be specified");
1803  }
1804 
1805  // Let's see if there's such a lease at all.
1807  p.iaid, p.subnet_id);
1808  if (!lease6) {
1809  setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
1810  return (0);
1811  }
1812  break;
1813  }
1814  default: {
1815  isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1816  break;
1817  }
1818  }
1819 
1820  if (LeaseMgrFactory::instance().deleteLease(lease6)) {
1821  setSuccessResponse(handle, "IPv6 lease deleted.");
1822  LeaseCmdsImpl::updateStatsOnDelete(lease6);
1823  } else {
1824  setErrorResponse (handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
1825  }
1826 
1827  // Queue an NCR to remove DNS if configured and the lease has it.
1828  if (p.updateDDNS) {
1829  queueNCR(CHG_REMOVE, lease6);
1830  }
1831 
1832  } catch (const std::exception& ex) {
1834  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1835  .arg(ex.what());
1836  setErrorResponse(handle, ex.what());
1837  return (1);
1838  }
1839 
1841  .arg(lease6->addr_.toText());
1842  return (0);
1843 }
1844 
1845 int
1846 LeaseCmdsImpl::lease4UpdateHandler(CalloutHandle& handle) {
1847  try {
1848  extractCommand(handle);
1849 
1850  // We need the lease to be specified.
1851  if (!cmd_args_) {
1852  isc_throw(isc::BadValue, "no parameters specified for lease4-update command");
1853  }
1854 
1855  // Get the parameters specified by the user first.
1857  Lease4Ptr lease4;
1858  Lease4Parser parser;
1859  bool force_create = false;
1860 
1861  // The parser does sanity checks (if the address is in scope, if
1862  // subnet-id is valid, etc)
1863  lease4 = parser.parse(config, cmd_args_, force_create);
1864  bool added = false;
1865  if (!MultiThreadingMgr::instance().getMode()) {
1866  // Not multi-threading.
1867  added = addOrUpdate4(lease4, force_create);
1868  } else {
1869  // Multi-threading, try to lock first to avoid a race.
1870  ResourceHandler4 resource_handler;
1871  if (resource_handler.tryLock4(lease4->addr_)) {
1872  added = addOrUpdate4(lease4, force_create);
1873  } else {
1875  "ResourceBusy: IP address:" << lease4->addr_
1876  << " could not be updated.");
1877  }
1878  }
1879 
1880  if (added) {
1881  setSuccessResponse(handle, "IPv4 lease added.");
1882  } else {
1883  setSuccessResponse(handle, "IPv4 lease updated.");
1884  }
1887  .arg(lease4->addr_.toText());
1888 
1889  } catch (const LeaseCmdsConflict& ex) {
1891  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1892  .arg(ex.what());
1893  setErrorResponse(handle, ex.what(), CONTROL_RESULT_CONFLICT);
1894  return (0);
1895 
1896  } catch (const std::exception& ex) {
1898  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1899  .arg(ex.what());
1900  setErrorResponse(handle, ex.what());
1901  return (1);
1902  }
1903 
1904  return (0);
1905 }
1906 
1907 int
1908 LeaseCmdsImpl::lease6UpdateHandler(CalloutHandle& handle) {
1909  try {
1910  extractCommand(handle);
1911 
1912  // We need the lease to be specified.
1913  if (!cmd_args_) {
1914  isc_throw(isc::BadValue, "no parameters specified for lease6-update command");
1915  }
1916 
1917  // Get the parameters specified by the user first.
1919  Lease6Ptr lease6;
1920  Lease6Parser parser;
1921  bool force_create = false;
1922 
1923  // The parser does sanity checks (if the address is in scope, if
1924  // subnet-id is valid, etc)
1925  lease6 = parser.parse(config, cmd_args_, force_create);
1926  bool added = false;
1927  if (!MultiThreadingMgr::instance().getMode()) {
1928  // Not multi-threading.
1929  added = addOrUpdate6(lease6, force_create);
1930  } else {
1931  // Multi-threading, try to lock first to avoid a race.
1932  ResourceHandler resource_handler;
1933  if (resource_handler.tryLock(lease6->type_, lease6->addr_)) {
1934  added = addOrUpdate6(lease6, force_create);
1935  } else {
1937  "ResourceBusy: IP address:" << lease6->addr_
1938  << " could not be updated.");
1939  }
1940  }
1941 
1942  if (added) {
1943  setSuccessResponse(handle, "IPv6 lease added.");
1944  } else {
1945  setSuccessResponse(handle, "IPv6 lease updated.");
1946  }
1949  .arg(lease6->addr_.toText());
1950 
1951  } catch (const LeaseCmdsConflict& ex) {
1953  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1954  .arg(ex.what());
1955  setErrorResponse(handle, ex.what(), CONTROL_RESULT_CONFLICT);
1956  return (0);
1957 
1958  } catch (const std::exception& ex) {
1960  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1961  .arg(ex.what());
1962  setErrorResponse(handle, ex.what());
1963  return (1);
1964  }
1965 
1966  return (0);
1967 }
1968 
1969 int
1970 LeaseCmdsImpl::lease4WipeHandler(CalloutHandle& handle) {
1971  try {
1972  extractCommand(handle);
1973 
1974  SimpleParser parser;
1975  SubnetID id = 0;
1976 
1977  size_t num = 0; // number of leases deleted
1978  stringstream ids; // a text with subnet-ids being wiped
1979 
1980  // The subnet-id parameter is now optional.
1981  if (cmd_args_ && cmd_args_->contains("subnet-id")) {
1982  id = parser.getUint32(cmd_args_, "subnet-id");
1983  }
1984 
1985  if (id) {
1986  // Wipe a single subnet.
1988  ids << " " << id;
1989 
1990  auto observation = StatsMgr::instance().getObservation(
1991  StatsMgr::generateName("subnet", id, "declined-addresses"));
1992 
1993  int64_t previous_declined = 0;
1994 
1995  if (observation) {
1996  previous_declined = observation->getInteger().first;
1997  }
1998 
1999  StatsMgr::instance().setValue(
2000  StatsMgr::generateName("subnet", id, "assigned-addresses"),
2001  int64_t(0));
2002 
2003  StatsMgr::instance().setValue(
2004  StatsMgr::generateName("subnet", id, "declined-addresses"),
2005  int64_t(0));
2006 
2007  StatsMgr::instance().addValue("declined-addresses", -previous_declined);
2008  } else {
2009  // Wipe them all!
2011  ConstCfgSubnets4Ptr subnets = config->getCfgSubnets4();
2012  const Subnet4Collection * subs = subnets->getAll();
2013 
2014  // Go over all subnets and wipe leases in each of them.
2015  for (auto sub : *subs) {
2016  num += LeaseMgrFactory::instance().wipeLeases4(sub->getID());
2017  ids << " " << sub->getID();
2018  StatsMgr::instance().setValue(
2019  StatsMgr::generateName("subnet", sub->getID(), "assigned-addresses"),
2020  int64_t(0));
2021 
2022  StatsMgr::instance().setValue(
2023  StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
2024  int64_t(0));
2025  }
2026 
2027  StatsMgr::instance().setValue("declined-addresses", int64_t(0));
2028  }
2029 
2030  stringstream tmp;
2031  tmp << "Deleted " << num << " IPv4 lease(s) from subnet(s)" << ids.str();
2033  : CONTROL_RESULT_EMPTY, tmp.str());
2034  setResponse(handle, response);
2035  } catch (const std::exception& ex) {
2037  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2038  .arg(ex.what());
2039  setErrorResponse(handle, ex.what());
2040  return (1);
2041  }
2042 
2044  .arg(cmd_args_ ? cmd_args_->str() : "<no args>");
2045  return (0);
2046 }
2047 
2048 int
2049 LeaseCmdsImpl::lease6WipeHandler(CalloutHandle& handle) {
2050  try {
2051  extractCommand(handle);
2052 
2053  SimpleParser parser;
2054  SubnetID id = 0;
2055 
2056  size_t num = 0; // number of leases deleted
2057  stringstream ids; // a text with subnet-ids being wiped
2058 
2064 
2065  // The subnet-id parameter is now optional.
2066  if (cmd_args_ && cmd_args_->contains("subnet-id")) {
2067  id = parser.getUint32(cmd_args_, "subnet-id");
2068  }
2069 
2070  if (id) {
2071  // Wipe a single subnet.
2073  ids << " " << id;
2074 
2075  auto observation = StatsMgr::instance().getObservation(
2076  StatsMgr::generateName("subnet", id, "declined-addresses"));
2077 
2078  int64_t previous_declined = 0;
2079 
2080  if (observation) {
2081  previous_declined = observation->getInteger().first;
2082  }
2083 
2084  StatsMgr::instance().setValue(
2085  StatsMgr::generateName("subnet", id, "assigned-nas" ),
2086  int64_t(0));
2087 
2088  StatsMgr::instance().setValue(
2089  StatsMgr::generateName("subnet", id, "assigned-pds"),
2090  int64_t(0));
2091 
2092  StatsMgr::instance().setValue(
2093  StatsMgr::generateName("subnet", id, "declined-addresses"),
2094  int64_t(0));
2095 
2096  StatsMgr::instance().addValue("declined-addresses", -previous_declined);
2097  } else {
2098  // Wipe them all!
2100  ConstCfgSubnets6Ptr subnets = config->getCfgSubnets6();
2101  const Subnet6Collection * subs = subnets->getAll();
2102 
2103  // Go over all subnets and wipe leases in each of them.
2104  for (auto sub : *subs) {
2105  num += LeaseMgrFactory::instance().wipeLeases6(sub->getID());
2106  ids << " " << sub->getID();
2107  StatsMgr::instance().setValue(
2108  StatsMgr::generateName("subnet", sub->getID(), "assigned-nas" ),
2109  int64_t(0));
2110 
2111  StatsMgr::instance().setValue(
2112  StatsMgr::generateName("subnet", sub->getID(), "assigned-pds"),
2113  int64_t(0));
2114 
2115  StatsMgr::instance().setValue(
2116  StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
2117  int64_t(0));
2118  }
2119 
2120  StatsMgr::instance().setValue("declined-addresses", int64_t(0));
2121  }
2122 
2123  stringstream tmp;
2124  tmp << "Deleted " << num << " IPv6 lease(s) from subnet(s)" << ids.str();
2126  : CONTROL_RESULT_EMPTY, tmp.str());
2127  setResponse(handle, response);
2128  } catch (const std::exception& ex) {
2130  .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2131  .arg(ex.what());
2132  setErrorResponse(handle, ex.what());
2133  return (1);
2134  }
2135 
2137  .arg(cmd_args_ ? cmd_args_->str() : "<no args>");
2138  return (0);
2139 }
2140 
2141 Lease6Ptr
2142 LeaseCmdsImpl::getIPv6LeaseForDelete(const Parameters& parameters) const {
2143  Lease6Ptr lease6;
2144 
2145  switch (parameters.query_type) {
2146  case Parameters::TYPE_ADDR: {
2147  // If address was specified explicitly, let's use it as is.
2148 
2149  // Let's see if there's such a lease at all.
2150  lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type,
2151  parameters.addr);
2152  if (!lease6) {
2153  lease6.reset(new Lease6());
2154  lease6->addr_ = parameters.addr;
2155  }
2156  break;
2157  }
2158  case Parameters::TYPE_HWADDR: {
2159  isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6.");
2160  break;
2161  }
2162  case Parameters::TYPE_DUID: {
2163  if (!parameters.duid) {
2164  isc_throw(InvalidParameter, "Program error: Query by duid "
2165  "requires duid to be specified");
2166  }
2167 
2168  // Let's see if there's such a lease at all.
2169  lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type,
2170  *parameters.duid,
2171  parameters.iaid,
2172  parameters.subnet_id);
2173  break;
2174  }
2175  default:
2176  isc_throw(InvalidOperation, "Unknown query type: "
2177  << static_cast<int>(parameters.query_type));
2178  }
2179 
2180  return (lease6);
2181 }
2182 
2183 IOAddress
2184 LeaseCmdsImpl::getAddressParam(ConstElementPtr params, const std::string name,
2185  short family) const {
2186  ConstElementPtr param = params->get(name);
2187  if (!param) {
2188  isc_throw(BadValue, "'" << name << "' parameter is missing.");
2189  }
2190 
2191  if (param->getType() != Element::string) {
2192  isc_throw(BadValue, "'" << name << "' is not a string.");
2193  }
2194 
2195  IOAddress addr(0);
2196  try {
2197  addr = IOAddress(param->stringValue());
2198  } catch (const std::exception& ex) {
2199  isc_throw(BadValue, "'" << param->stringValue()
2200  << "' is not a valid IP address.");
2201  }
2202 
2203  if (addr.getFamily() != family) {
2204  isc_throw(BadValue, "Invalid "
2205  << (family == AF_INET6 ? "IPv6" : "IPv4")
2206  << " address specified: " << param->stringValue());
2207  }
2208 
2209  return (addr);
2210 }
2211 
2212 int
2213 LeaseCmdsImpl::lease4ResendDdnsHandler(CalloutHandle& handle) {
2214  std::stringstream ss;
2215  int resp_code = CONTROL_RESULT_ERROR;
2216 
2217  try {
2218  extractCommand(handle);
2219 
2220  // Get the target lease address. Invalid value will throw.
2221  IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET);
2222 
2223  if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
2224  ss << "DDNS updating is not enabled";
2225  resp_code = CONTROL_RESULT_CONFLICT;
2226  } else {
2227  // Find the lease.
2229  if (!lease) {
2230  ss << "No lease found for: " << addr.toText();
2231  resp_code = CONTROL_RESULT_EMPTY;
2232  } else if (lease->hostname_.empty()) {
2233  ss << "Lease for: " << addr.toText()
2234  << ", has no hostname, nothing to update";
2235  resp_code = CONTROL_RESULT_CONFLICT;
2236  } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
2237  ss << "Neither forward nor reverse updates enabled for lease for: "
2238  << addr.toText();
2239  resp_code = CONTROL_RESULT_CONFLICT;
2240  } else {
2241  // We have a lease with a hostname and updates in at least
2242  // one direction enabled. Queue an NCR for it.
2243  queueNCR(CHG_ADD, lease);
2244  ss << "NCR generated for: " << addr.toText()
2245  << ", hostname: " << lease->hostname_;
2246  setSuccessResponse(handle, ss.str());
2248  return (0);
2249  }
2250  }
2251  } catch (const std::exception& ex) {
2252  ss << ex.what();
2253  }
2254 
2256  setErrorResponse(handle, ss.str(), resp_code);
2257  return (resp_code == CONTROL_RESULT_EMPTY || resp_code == CONTROL_RESULT_CONFLICT ? 0 : 1);
2258 }
2259 
2260 int
2261 LeaseCmdsImpl::lease6ResendDdnsHandler(CalloutHandle& handle) {
2262  std::stringstream ss;
2263  int resp_code = CONTROL_RESULT_ERROR;
2264 
2265  try {
2266  extractCommand(handle);
2267 
2268  // Get the target lease address. Invalid value will throw.
2269  IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET6);
2270 
2271  if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
2272  ss << "DDNS updating is not enabled";
2273  resp_code = CONTROL_RESULT_CONFLICT;
2274  } else {
2275  // Find the lease.
2277  if (!lease) {
2278  ss << "No lease found for: " << addr.toText();
2279  resp_code = CONTROL_RESULT_EMPTY;
2280  } else if (lease->hostname_.empty()) {
2281  ss << "Lease for: " << addr.toText()
2282  << ", has no hostname, nothing to update";
2283  resp_code = CONTROL_RESULT_CONFLICT;
2284  } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
2285  ss << "Neither forward nor reverse updates enabled for lease for: "
2286  << addr.toText();
2287  resp_code = CONTROL_RESULT_CONFLICT;
2288  } else {
2289  // We have a lease with a hostname and updates in at least
2290  // one direction enabled. Queue an NCR for it.
2291  queueNCR(CHG_ADD, lease);
2292  ss << "NCR generated for: " << addr.toText()
2293  << ", hostname: " << lease->hostname_;
2294  setSuccessResponse(handle, ss.str());
2296  return (0);
2297  }
2298  }
2299  } catch (const std::exception& ex) {
2300  ss << ex.what();
2301  }
2302 
2304  setErrorResponse(handle, ss.str(), resp_code);
2305  return (resp_code == CONTROL_RESULT_EMPTY ? 0 : 1);
2306 }
2307 
2308 ElementPtr
2309 LeaseCmdsImpl::createFailedLeaseMap(const Lease::Type& lease_type,
2310  const IOAddress& lease_address,
2311  const DuidPtr& duid,
2312  const int control_result,
2313  const std::string& error_message) const {
2314  auto failed_lease_map = Element::createMap();
2315  failed_lease_map->set("type", Element::create(Lease::typeToText(lease_type)));
2316 
2317  if (!lease_address.isV6Zero()) {
2318  failed_lease_map->set("ip-address", Element::create(lease_address.toText()));
2319 
2320  } else if (duid) {
2321  failed_lease_map->set("duid", Element::create(duid->toText()));
2322  }
2323 
2324  // Associate the result with the lease.
2325  failed_lease_map->set("result", Element::create(control_result));
2326  failed_lease_map->set("error-message", Element::create(error_message));
2327 
2328  return (failed_lease_map);
2329 }
2330 
2331 int
2332 LeaseCmdsImpl::leaseWriteHandler(CalloutHandle& handle) {
2333  bool v4 = true;
2334  try {
2335  extractCommand(handle);
2336  v4 = (cmd_name_ == "lease4-write");
2337 
2338  if (!cmd_args_) {
2339  isc_throw(isc::BadValue, "no parameters specified for the command");
2340  }
2341 
2342  ConstElementPtr file = cmd_args_->get("filename");
2343  if (!file) {
2344  isc_throw(BadValue, "'filename' parameter not specified");
2345  }
2346  if (file->getType() != Element::string) {
2347  isc_throw(BadValue, "'filename' parameter must be a string");
2348  }
2349  string filename = file->stringValue();
2350  if (filename.empty()) {
2351  isc_throw(BadValue, "'filename' parameter is empty");
2352  }
2353 
2354  if (v4) {
2356  } else {
2358  }
2359  ostringstream s;
2360  s << (v4 ? "IPv4" : "IPv6")
2361  << " lease database into '"
2362  << filename << "'.";
2364  setResponse(handle, response);
2365  } catch (const std::exception& ex) {
2366  setErrorResponse(handle, ex.what());
2367  return (CONTROL_RESULT_ERROR);
2368  }
2369 
2370  return (0);
2371 }
2372 
2373 int
2374 LeaseCmds::leaseAddHandler(CalloutHandle& handle) {
2375  return (impl_->leaseAddHandler(handle));
2376 }
2377 
2378 int
2379 LeaseCmds::lease6BulkApplyHandler(CalloutHandle& handle) {
2380  return (impl_->lease6BulkApplyHandler(handle));
2381 }
2382 
2383 int
2384 LeaseCmds::leaseGetHandler(CalloutHandle& handle) {
2385  return (impl_->leaseGetHandler(handle));
2386 }
2387 
2388 int
2389 LeaseCmds::leaseGetAllHandler(hooks::CalloutHandle& handle) {
2390  return (impl_->leaseGetAllHandler(handle));
2391 }
2392 
2393 int
2394 LeaseCmds::leaseGetPageHandler(hooks::CalloutHandle& handle) {
2395  return (impl_->leaseGetPageHandler(handle));
2396 }
2397 
2398 int
2399 LeaseCmds::leaseGetByHwAddressHandler(hooks::CalloutHandle& handle) {
2400  return (impl_->leaseGetByHwAddressHandler(handle));
2401 }
2402 
2403 int
2404 LeaseCmds::leaseGetByClientIdHandler(hooks::CalloutHandle& handle) {
2405  return (impl_->leaseGetByClientIdHandler(handle));
2406 }
2407 
2408 int
2409 LeaseCmds::leaseGetByDuidHandler(hooks::CalloutHandle& handle) {
2410  return (impl_->leaseGetByDuidHandler(handle));
2411 }
2412 
2413 int
2414 LeaseCmds::leaseGetByHostnameHandler(hooks::CalloutHandle& handle) {
2415  return (impl_->leaseGetByHostnameHandler(handle));
2416 }
2417 
2418 int
2419 LeaseCmds::lease4DelHandler(CalloutHandle& handle) {
2420  return (impl_->lease4DelHandler(handle));
2421 }
2422 
2423 int
2424 LeaseCmds::lease6DelHandler(CalloutHandle& handle) {
2425  return (impl_->lease6DelHandler(handle));
2426 }
2427 
2428 int
2429 LeaseCmds::lease4UpdateHandler(CalloutHandle& handle) {
2430  return (impl_->lease4UpdateHandler(handle));
2431 }
2432 
2433 int
2434 LeaseCmds::lease6UpdateHandler(CalloutHandle& handle) {
2435  return (impl_->lease6UpdateHandler(handle));
2436 }
2437 
2438 int
2439 LeaseCmds::lease4WipeHandler(CalloutHandle& handle) {
2441  return (impl_->lease4WipeHandler(handle));
2442 }
2443 
2444 int
2445 LeaseCmds::lease6WipeHandler(CalloutHandle& handle) {
2447  return (impl_->lease6WipeHandler(handle));
2448 }
2449 
2450 int
2451 LeaseCmds::lease4ResendDdnsHandler(CalloutHandle& handle) {
2452  return (impl_->lease4ResendDdnsHandler(handle));
2453 }
2454 
2455 int
2456 LeaseCmds::lease6ResendDdnsHandler(CalloutHandle& handle) {
2457  return (impl_->lease6ResendDdnsHandler(handle));
2458 }
2459 
2460 int
2461 LeaseCmds::leaseWriteHandler(CalloutHandle& handle) {
2462  return (impl_->leaseWriteHandler(handle));
2463 }
2464 
2465 LeaseCmds::LeaseCmds()
2466  :impl_(new LeaseCmdsImpl()) {
2467 }
2468 
2469 } // end of namespace lease_cmds
2470 } // end of namespace isc
RAII class creating a critical section.
const int CONTROL_RESULT_CONFLICT
Status code indicating that the command was unsuccessful due to a conflict between the command argume...
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
const isc::log::MessageID LEASE_CMDS_BULK_APPLY6
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
virtual void updateLease4(const Lease4Ptr &lease4)=0
Updates IPv4 lease.
const isc::log::MessageID LEASE_CMDS_ADD6_FAILED
const isc::log::MessageID LEASE_CMDS_ADD4_FAILED
static ClientIdPtr fromText(const std::string &text)
Create client identifier from the textual format.
Definition: duid.cc:132
Parser for Lease4 structure.
Definition: lease_parser.h:35
HWAddrPtr hwaddr
Specifies hardware address (used when query_type is TYPE_HWADDR)
Definition: lease_cmds.cc:75
const isc::log::MessageID LEASE_CMDS_WIPE4_FAILED
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
virtual size_t wipeLeases4(const SubnetID &subnet_id)=0
Virtual method which removes specified leases.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
static std::string typeToText(Type type)
returns text representation of a lease type
Definition: lease.cc:53
virtual isc::dhcp::Lease6Ptr parse(isc::dhcp::ConstSrvConfigPtr &cfg, const isc::data::ConstElementPtr &lease_info, bool &force_create)
Parses Element tree and tries to convert to Lease4.
const isc::log::MessageID LEASE_CMDS_DEL6_FAILED
An abstract API for lease database.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
Attempt to update lease that was not there.
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6_FAILED
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:514
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4
const isc::log::MessageID LEASE_CMDS_DEL4
const isc::log::MessageID LEASE_CMDS_UPDATE6_CONFLICT
const isc::log::MessageID LEASE_CMDS_UPDATE6_FAILED
Resource race avoidance RAII handler for DHCPv4.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:49
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
STL namespace.
static DUID fromText(const std::string &text)
Create DUID from the textual format.
Definition: duid.cc:62
const isc::log::MessageID LEASE_CMDS_GET6_FAILED
Type query_type
specifies parameter types
Definition: lease_cmds.cc:109
SubnetID subnet_id
Specifies subnet-id (always used)
Definition: lease_cmds.cc:69
const isc::log::MessageID LEASE_CMDS_ADD6_CONFLICT
const isc::log::MessageID LEASE_CMDS_BULK_APPLY6_FAILED
const isc::log::MessageID LEASE_CMDS_ADD4
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:291
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition: data.cc:286
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
boost::shared_ptr< const CfgSubnets4 > ConstCfgSubnets4Ptr
Const pointer.
Definition: cfg_subnets4.h:348
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
Resource race avoidance RAII handler.
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
Exception thrown when a command failed due to a conflict.
bool tryLock(Lease::Type type, const asiolink::IOAddress &addr)
Tries to acquires a resource.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
isc::log::Logger lease_cmds_logger("lease-cmds-hooks")
void queueNCR(const NameChangeType &chg_type, const Lease4Ptr &lease)
Creates name change request from the DHCPv4 lease.
boost::shared_ptr< const SrvConfig > ConstSrvConfigPtr
Const pointer to the SrvConfig.
Definition: srv_config.h:1194
Definition: edns.h:19
const isc::log::MessageID LEASE_CMDS_UPDATE4
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4_FAILED
static void syncCurrentExpirationTime(const Lease &from, Lease &to)
Sync lease current expiration time with new value from another lease, so that additional operations c...
Definition: lease.cc:292
boost::multi_index_container< Subnet4Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetServerIdIndexTag >, boost::multi_index::const_mem_fun< Network4, asiolink::IOAddress, &Network4::getServerId > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > >> Subnet4Collection
A collection of Subnet4 objects.
Definition: subnet.h:866
const isc::log::MessageID LEASE_CMDS_DEL4_FAILED
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:294
Per-packet callout handle.
Wrapper class around reservation command handlers.
Definition: lease_cmds.cc:53
const isc::log::MessageID LEASE_CMDS_UPDATE6
boost::shared_ptr< const CfgSubnets6 > ConstCfgSubnets6Ptr
Const pointer.
Definition: cfg_subnets6.h:346
Parser for Lease6 structure.
Definition: lease_parser.h:78
IPv4 lease.
Definition: lease.h:50
const int LEASE_CMDS_DBG_COMMAND_DATA
Logging level used to log successful commands.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:530
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:677
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
virtual Lease4Collection getLeases4(SubnetID subnet_id) const =0
Returns all IPv4 leases for the particular subnet identifier.
static ConstElementPtr getExtendedInfo6(const Lease6Ptr &lease)
Get DHCPv6 extended info.
Definition: lease_cmds.cc:464
IOAddress addr
Specifies IPv4/v6 address (used when query_type is TYPE_ADDR)
Definition: lease_cmds.cc:72
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition: duid.h:103
the lease contains temporary IPv6 address
Definition: lease.h:48
Type
specifies type of query (by IP addr, by hwaddr, by DUID)
Definition: lease_cmds.cc:61
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
the lease contains non-temporary IPv6 address
Definition: lease.h:47
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > >> Subnet6Collection
A collection of Subnet6 objects.
Definition: subnet.h:937
Lease::Type lease_type
Lease type (NA,TA or PD) used for v6 leases.
Definition: lease_cmds.cc:112
query by IP address (either v4 or v6)
Definition: lease_cmds.cc:62
Defines the logger used by the top-level component of kea-lfc.
update extended info tables.
Definition: lease.h:191
const isc::log::MessageID LEASE_CMDS_DEL6
This file contains several functions and constants that are used for handling commands and responses ...
const isc::log::MessageID LEASE_CMDS_GET4_FAILED
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition: data.cc:241
bool updateDDNS
Indicates whether or not DNS should be updated.
Definition: lease_cmds.cc:118
Base class that command handler implementers may use for common tasks.
Definition: cmds_impl.h:21
a common structure for IPv4 and IPv6 leases
Definition: lease.h:31
static HWAddr fromText(const std::string &text, const uint16_t htype=HTYPE_ETHER)
Creates instance of the hardware address from textual format.
Definition: hwaddr.cc:70
Type
Type of lease or pool.
Definition: lease.h:46
A generic exception that is thrown if a function is called in a prohibited way.
const isc::log::MessageID LEASE_CMDS_WIPE4
virtual void writeLeases6(const std::string &filename)=0
Write V6 leases to a file.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
Parameters specified for lease commands.
Definition: lease_cmds.cc:57
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
static Type txtToType(const std::string &txt)
Attempts to covert text to one of specified types.
Definition: lease_cmds.cc:92
virtual bool addLease(const Lease4Ptr &lease)=0
Adds an IPv4 lease.
const isc::log::MessageID LEASE_CMDS_UPDATE4_FAILED
query by hardware address (v4 only)
Definition: lease_cmds.cc:63
virtual size_t wipeLeases6(const SubnetID &subnet_id)=0
Virtual method which removes specified leases.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const =0
Returns an IPv4 lease for specified IPv4 address.
const isc::log::MessageID LEASE_CMDS_ADD6
virtual bool deleteLease(const Lease4Ptr &lease)=0
Deletes an IPv4 lease.
const isc::log::MessageID LEASE_CMDS_WIPE6
isc::dhcp::DuidPtr duid
Specifies identifier value (used when query_type is TYPE_DUID)
Definition: lease_cmds.cc:78
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:46
virtual isc::dhcp::Lease4Ptr parse(isc::dhcp::ConstSrvConfigPtr &cfg, const isc::data::ConstElementPtr &lease_info, bool &force_create)
Parses Element tree and tries to convert to Lease4.
Definition: lease_parser.cc:28
static LeaseMgr & instance()
Return current lease manager.
virtual Lease6Collection getLeases6(Lease::Type type, const DUID &duid, uint32_t iaid) const =0
Returns existing IPv6 leases for a given DUID+IA combination.
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:519
const isc::log::MessageID LEASE_CMDS_ADD4_CONFLICT
virtual void writeLeases4(const std::string &filename)=0
Write V4 leases to a file.
const isc::log::MessageID LEASE_CMDS_UPDATE4_CONFLICT
virtual void updateLease6(const Lease6Ptr &lease6)=0
Updates IPv6 lease.
const isc::log::MessageID LEASE_CMDS_WIPE6_FAILED
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:25
isc::dhcp::ClientIdPtr client_id
Specifies identifier value (used when query_type is TYPE_CLIENT_ID)
Definition: lease_cmds.cc:81
uint32_t iaid
IAID identifier used for v6 leases.
Definition: lease_cmds.cc:115
bool tryLock4(const asiolink::IOAddress &addr)
Tries to acquires a resource.