Kea 2.7.6
lease_cmds.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2024 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>
9#include <config/cmds_impl.h>
11#include <cc/data.h>
12#include <asiolink/io_address.h>
14#include <dhcpsrv/cfgmgr.h>
16#include <dhcpsrv/lease_mgr.h>
20#include <dhcpsrv/subnet_id.h>
22#include <dhcp/duid.h>
23#include <hooks/hooks.h>
25#include <lease_cmds.h>
27#include <lease_parser.h>
28#include <lease_cmds_log.h>
29#include <stats/stats_mgr.h>
30#include <util/encode/encode.h>
32
33#include <boost/scoped_ptr.hpp>
34#include <boost/algorithm/string.hpp>
35#include <string>
36#include <sstream>
37
38using namespace isc::dhcp;
39using namespace isc::data;
40using namespace isc::dhcp_ddns;
41using namespace isc::config;
42using namespace isc::asiolink;
43using namespace isc::hooks;
44using namespace isc::stats;
45using namespace isc::util;
46using namespace std;
47
48namespace isc {
49namespace lease_cmds {
50
52class LeaseCmdsImpl : private CmdsImpl {
53public:
54
56 class Parameters {
57 public:
58
66
69
72
75
78
81
91 static Type txtToType(const std::string& txt) {
92 if (txt == "address") {
93 return (Parameters::TYPE_ADDR);
94 } else if (txt == "hw-address") {
96 } else if (txt == "duid") {
97 return (Parameters::TYPE_DUID);
98 } else if (txt == "client-id") {
100 } else {
101 isc_throw(BadValue, "Incorrect identifier type: "
102 << txt << ", the only supported values are: "
103 "address, hw-address, duid");
104 }
105 }
106
109
112
114 uint32_t iaid;
115
118
121 : subnet_id(0), addr("::"), query_type(TYPE_ADDR),
122 lease_type(Lease::TYPE_NA), iaid(0), updateDDNS(false) {
123 }
124 };
125
126public:
127
136 int
138
148 int
150
159 int
161
173 int
175
191 int
193
203 int
205
215 int
217
227 int
229
240 int
242
251 int
253
262 int
264
273 int
275
284 int
286
295 int
297
306 int
308
318
328
337 int
339
351 Parameters getParameters(bool v6, const ConstElementPtr& args);
352
370 Lease6Ptr getIPv6LeaseForDelete(const Parameters& parameters) const;
371
387 const IOAddress& lease_address,
388 const DuidPtr& duid,
389 const int control_result,
390 const std::string& error_message) const;
391
402 IOAddress getAddressParam(ConstElementPtr params, const std::string name,
403 short family = AF_INET) const;
404
408 static void updateStatsOnAdd(const Lease4Ptr& lease);
409
413 static void updateStatsOnAdd(const Lease6Ptr& lease);
414
419 static void updateStatsOnUpdate(const Lease4Ptr& existing,
420 const Lease4Ptr& lease);
421
426 static void updateStatsOnUpdate(const Lease6Ptr& existing,
427 const Lease6Ptr& lease);
428
432 static void updateStatsOnDelete(const Lease4Ptr& lease);
433
437 static void updateStatsOnDelete(const Lease6Ptr& lease);
438
447 static bool addOrUpdate4(Lease4Ptr lease, bool force_create);
448
457 static bool addOrUpdate6(Lease6Ptr lease, bool force_create);
458
463 inline static ConstElementPtr getExtendedInfo6(const Lease6Ptr& lease) {
464 ConstElementPtr user_context = lease->getContext();
465 if (!user_context || (user_context->getType() != Element::map)) {
466 return (ConstElementPtr());
467 }
468 ConstElementPtr isc = user_context->get("ISC");
469 if (!isc || (isc->getType() != Element::map)) {
470 return (ConstElementPtr());
471 }
472 return (isc->get("relay-info"));
473 }
474};
475
476void
478 if (!lease->stateExpiredReclaimed()) {
480 StatsMgr::generateName("subnet", lease->subnet_id_,
481 "assigned-addresses"),
482 static_cast<int64_t>(1));
483
484 PoolPtr pool;
485 auto const& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
486 if (subnet) {
487 pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false);
488 if (pool) {
490 StatsMgr::generateName("subnet", subnet->getID(),
491 StatsMgr::generateName("pool", pool->getID(),
492 "assigned-addresses")),
493 static_cast<int64_t>(1));
494 }
495 }
496
497 if (lease->stateDeclined()) {
498 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
499
501 StatsMgr::generateName("subnet", lease->subnet_id_,
502 "declined-addresses"),
503 static_cast<int64_t>(1));
504
505 if (pool) {
507 StatsMgr::generateName("subnet", subnet->getID(),
508 StatsMgr::generateName("pool", pool->getID(),
509 "declined-addresses")),
510 static_cast<int64_t>(1));
511 }
512 }
513 }
514}
515
516void
518 if (!lease->stateExpiredReclaimed()) {
520 StatsMgr::generateName("subnet", lease->subnet_id_,
521 lease->type_ == Lease::TYPE_NA ?
522 "assigned-nas" : "assigned-pds"),
523 static_cast<int64_t>(1));
524
525 PoolPtr pool;
526 auto const& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
527 if (subnet) {
528 pool = subnet->getPool(lease->type_, lease->addr_, false);
529 if (pool) {
531 StatsMgr::generateName("subnet", subnet->getID(),
532 StatsMgr::generateName(lease->type_ == Lease::TYPE_NA ?
533 "pool" : "pd-pool", pool->getID(),
534 lease->type_ == Lease::TYPE_NA ?
535 "assigned-nas" : "assigned-pds")),
536 static_cast<int64_t>(1));
537 }
538 }
539
540 if (lease->stateDeclined()) {
541 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
542
544 StatsMgr::generateName("subnet", lease->subnet_id_,
545 "declined-addresses"),
546 static_cast<int64_t>(1));
547
548 if (pool) {
550 StatsMgr::generateName("subnet", subnet->getID(),
551 StatsMgr::generateName("pool", pool->getID(),
552 "declined-addresses")),
553 static_cast<int64_t>(1));
554 }
555 }
556 }
557}
558
559void
561 const Lease4Ptr& lease) {
562 if (!existing->stateExpiredReclaimed()) {
563 ConstSubnet4Ptr subnet;
564 PoolPtr pool;
565
566 // old lease is non expired-reclaimed
567 if (existing->subnet_id_ != lease->subnet_id_) {
569 StatsMgr::generateName("subnet", existing->subnet_id_,
570 "assigned-addresses"),
571 static_cast<int64_t>(-1));
572
573 subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(existing->subnet_id_);
574 if (subnet) {
575 pool = subnet->getPool(Lease::TYPE_V4, existing->addr_, false);
576 if (pool) {
578 StatsMgr::generateName("subnet", subnet->getID(),
579 StatsMgr::generateName("pool", pool->getID(),
580 "assigned-addresses")),
581 static_cast<int64_t>(-1));
582 }
583 }
584 }
585
586 if (existing->stateDeclined()) {
587 // old lease is declined
588 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(-1));
589
591 StatsMgr::generateName("subnet", existing->subnet_id_,
592 "declined-addresses"),
593 static_cast<int64_t>(-1));
594
595 if (pool) {
597 StatsMgr::generateName("subnet", subnet->getID(),
598 StatsMgr::generateName("pool", pool->getID(),
599 "declined-addresses")),
600 static_cast<int64_t>(-1));
601 }
602 }
603
604 pool.reset();
605
606 if (!lease->stateExpiredReclaimed()) {
607 // new lease is non expired-reclaimed
608 if (existing->subnet_id_ != lease->subnet_id_) {
610 StatsMgr::generateName("subnet", lease->subnet_id_,
611 "assigned-addresses"),
612 static_cast<int64_t>(1));
613
614 subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
615 if (subnet) {
616 pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false);
617 if (pool) {
619 StatsMgr::generateName("subnet", subnet->getID(),
620 StatsMgr::generateName("pool", pool->getID(),
621 "assigned-addresses")),
622 static_cast<int64_t>(1));
623 }
624 }
625 }
626
627 if (lease->stateDeclined()) {
628 // new lease is declined
629 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
630
632 StatsMgr::generateName("subnet", lease->subnet_id_,
633 "declined-addresses"),
634 static_cast<int64_t>(1));
635
636 if (pool) {
638 StatsMgr::generateName("subnet", subnet->getID(),
639 StatsMgr::generateName("pool", pool->getID(),
640 "declined-addresses")),
641 static_cast<int64_t>(1));
642 }
643 }
644 }
645 } else {
646 // old lease is expired-reclaimed
647 if (!lease->stateExpiredReclaimed()) {
648 // new lease is non expired-reclaimed
650 StatsMgr::generateName("subnet", lease->subnet_id_,
651 "assigned-addresses"),
652 static_cast<int64_t>(1));
653
654 PoolPtr pool;
655 auto const& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
656 if (subnet) {
657 pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false);
658 if (pool) {
660 StatsMgr::generateName("subnet", subnet->getID(),
661 StatsMgr::generateName("pool", pool->getID(),
662 "assigned-addresses")),
663 static_cast<int64_t>(1));
664 }
665 }
666
667 if (lease->stateDeclined()) {
668 // new lease is declined
669 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
670
672 StatsMgr::generateName("subnet", lease->subnet_id_,
673 "declined-addresses"),
674 static_cast<int64_t>(1));
675
676 if (pool) {
678 StatsMgr::generateName("subnet", subnet->getID(),
679 StatsMgr::generateName("pool", pool->getID(),
680 "declined-addresses")),
681 static_cast<int64_t>(1));
682 }
683 }
684 }
685 }
686}
687
688void
690 const Lease6Ptr& lease) {
691 if (!existing->stateExpiredReclaimed()) {
692 ConstSubnet6Ptr subnet;
693 PoolPtr pool;
694
695 // old lease is non expired-reclaimed
696 if (existing->subnet_id_ != lease->subnet_id_) {
698 StatsMgr::generateName("subnet", existing->subnet_id_,
699 lease->type_ == Lease::TYPE_NA ?
700 "assigned-nas" : "assigned-pds"),
701 static_cast<int64_t>(-1));
702
703 subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(existing->subnet_id_);
704 if (subnet) {
705 pool = subnet->getPool(existing->type_, existing->addr_, false);
706 if (pool) {
708 StatsMgr::generateName("subnet", subnet->getID(),
709 StatsMgr::generateName(existing->type_ == Lease::TYPE_NA ?
710 "pool" : "pd-pool", pool->getID(),
711 existing->type_ == Lease::TYPE_NA ?
712 "assigned-nas" : "assigned-pds")),
713 static_cast<int64_t>(-1));
714 }
715 }
716 }
717
718 if (existing->stateDeclined()) {
719 // old lease is declined
720 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(-1));
721
723 StatsMgr::generateName("subnet", existing->subnet_id_,
724 "declined-addresses"),
725 static_cast<int64_t>(-1));
726
727 if (pool) {
729 StatsMgr::generateName("subnet", subnet->getID(),
730 StatsMgr::generateName("pool", pool->getID(),
731 "declined-addresses")),
732 static_cast<int64_t>(-1));
733 }
734 }
735
736 pool.reset();
737
738 if (!lease->stateExpiredReclaimed()) {
739 // new lease is non expired-reclaimed
740 if (existing->subnet_id_ != lease->subnet_id_) {
742 StatsMgr::generateName("subnet", lease->subnet_id_,
743 lease->type_ == Lease::TYPE_NA ?
744 "assigned-nas" : "assigned-pds"),
745 static_cast<int64_t>(1));
746
747 subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
748 if (subnet) {
749 pool = subnet->getPool(lease->type_, lease->addr_, false);
750 if (pool) {
752 StatsMgr::generateName("subnet", subnet->getID(),
753 StatsMgr::generateName(lease->type_ == Lease::TYPE_NA ?
754 "pool" : "pd-pool", pool->getID(),
755 lease->type_ == Lease::TYPE_NA ?
756 "assigned-nas" : "assigned-pds")),
757 static_cast<int64_t>(1));
758 }
759 }
760 }
761
762 if (lease->stateDeclined()) {
763 // new lease is declined
764 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
765
767 StatsMgr::generateName("subnet", lease->subnet_id_,
768 "declined-addresses"),
769 static_cast<int64_t>(1));
770
771 if (pool) {
773 StatsMgr::generateName("subnet", subnet->getID(),
774 StatsMgr::generateName("pool", pool->getID(),
775 "declined-addresses")),
776 static_cast<int64_t>(1));
777 }
778 }
779 }
780 } else {
781 // old lease is expired-reclaimed
782 if (!lease->stateExpiredReclaimed()) {
783 // new lease is non expired-reclaimed
785 StatsMgr::generateName("subnet", lease->subnet_id_,
786 lease->type_ == Lease::TYPE_NA ?
787 "assigned-nas" : "assigned-pds"),
788 static_cast<int64_t>(1));
789
790 PoolPtr pool;
791 auto const& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
792 if (subnet) {
793 pool = subnet->getPool(lease->type_, lease->addr_, false);
794 if (pool) {
796 StatsMgr::generateName("subnet", subnet->getID(),
797 StatsMgr::generateName(lease->type_ == Lease::TYPE_NA ?
798 "pool" : "pd-pool", pool->getID(),
799 lease->type_ == Lease::TYPE_NA ?
800 "assigned-nas" : "assigned-pds")),
801 static_cast<int64_t>(1));
802 }
803 }
804
805 if (lease->stateDeclined()) {
806 // new lease is declined
807 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(1));
808
810 StatsMgr::generateName("subnet", lease->subnet_id_,
811 "declined-addresses"),
812 static_cast<int64_t>(1));
813
814 if (pool) {
816 StatsMgr::generateName("subnet", subnet->getID(),
817 StatsMgr::generateName("pool", pool->getID(),
818 "declined-addresses")),
819 static_cast<int64_t>(1));
820 }
821 }
822 }
823 }
824}
825
826void
828 if (!lease->stateExpiredReclaimed()) {
830 StatsMgr::generateName("subnet", lease->subnet_id_,
831 "assigned-addresses"),
832 static_cast<int64_t>(-1));
833
834 PoolPtr pool;
835 auto const& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(lease->subnet_id_);
836 if (subnet) {
837 pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false);
838 if (pool) {
840 StatsMgr::generateName("subnet", subnet->getID(),
841 StatsMgr::generateName("pool", pool->getID(),
842 "assigned-addresses")),
843 static_cast<int64_t>(-1));
844 }
845 }
846
847 if (lease->stateDeclined()) {
848 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(-1));
849
851 StatsMgr::generateName("subnet", lease->subnet_id_,
852 "declined-addresses"),
853 static_cast<int64_t>(-1));
854
855 if (pool) {
857 StatsMgr::generateName("subnet", subnet->getID(),
858 StatsMgr::generateName("pool", pool->getID(),
859 "declined-addresses")),
860 static_cast<int64_t>(-1));
861 }
862 }
863 }
864}
865
866void
868 if (!lease->stateExpiredReclaimed()) {
870 StatsMgr::generateName("subnet", lease->subnet_id_,
871 lease->type_ == Lease::TYPE_NA ?
872 "assigned-nas" : "assigned-pds"),
873 static_cast<int64_t>(-1));
874
875 PoolPtr pool;
876 auto const& subnet = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(lease->subnet_id_);
877 if (subnet) {
878 pool = subnet->getPool(lease->type_, lease->addr_, false);
879 if (pool) {
881 StatsMgr::generateName("subnet", subnet->getID(),
882 StatsMgr::generateName(lease->type_ == Lease::TYPE_NA ?
883 "pool" : "pd-pool", pool->getID(),
884 lease->type_ == Lease::TYPE_NA ?
885 "assigned-nas" : "assigned-pds")),
886 static_cast<int64_t>(-1));
887 }
888 }
889
890 if (lease->stateDeclined()) {
891 StatsMgr::instance().addValue("declined-addresses", static_cast<int64_t>(-1));
892
894 StatsMgr::generateName("subnet", lease->subnet_id_,
895 "declined-addresses"),
896 static_cast<int64_t>(-1));
897
898 if (pool) {
900 StatsMgr::generateName("subnet", subnet->getID(),
901 StatsMgr::generateName("pool", pool->getID(),
902 "declined-addresses")),
903 static_cast<int64_t>(-1));
904 }
905 }
906 }
907}
908
909bool
910LeaseCmdsImpl::addOrUpdate4(Lease4Ptr lease, bool force_create) {
911 Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(lease->addr_);
912 if (force_create && !existing) {
913 // lease does not exist
914 if (!LeaseMgrFactory::instance().addLease(lease)) {
916 "lost race between calls to get and add");
917 }
919 return (true);
920 }
921 if (existing) {
922 // Update lease current expiration time with value received from the
923 // database. Some database backends reject operations on the lease if
924 // the current expiration time value does not match what is stored.
925 Lease::syncCurrentExpirationTime(*existing, *lease);
926 }
927 try {
929 } catch (const NoSuchLease&) {
930 isc_throw(LeaseCmdsConflict, "failed to update the lease with address "
931 << lease->addr_ << " either because the lease has been "
932 "deleted or it has changed in the database, in both cases a "
933 "retry might succeed");
934 }
935
936 LeaseCmdsImpl::updateStatsOnUpdate(existing, lease);
937 return (false);
938}
939
940bool
941LeaseCmdsImpl::addOrUpdate6(Lease6Ptr lease, bool force_create) {
942 Lease6Ptr existing =
943 LeaseMgrFactory::instance().getLease6(lease->type_, lease->addr_);
944 if (force_create && !existing) {
945 // lease does not exist
946 if (!LeaseMgrFactory::instance().addLease(lease)) {
948 "lost race between calls to get and add");
949 }
951 return (true);
952 }
953 if (existing) {
954 // Update lease current expiration time with value received from the
955 // database. Some database backends reject operations on the lease if
956 // the current expiration time value does not match what is stored.
957 Lease::syncCurrentExpirationTime(*existing, *lease);
958
959 // Check what is the action about extended info.
960 ConstElementPtr old_extended_info = getExtendedInfo6(existing);
961 ConstElementPtr extended_info = getExtendedInfo6(lease);
962 if ((!old_extended_info && !extended_info) ||
963 (old_extended_info && extended_info &&
964 (*old_extended_info == *extended_info))) {
965 // Leave the default Lease6::ACTION_IGNORE.
966 } else {
967 lease->extended_info_action_ = Lease6::ACTION_UPDATE;
968 }
969 }
970 try {
972 } catch (const NoSuchLease&) {
973 isc_throw(LeaseCmdsConflict, "failed to update the lease with address "
974 << lease->addr_ << " either because the lease has been "
975 "deleted or it has changed in the database, in both cases a "
976 "retry might succeed");
977 }
978
979 LeaseCmdsImpl::updateStatsOnUpdate(existing, lease);
980 return (false);
981}
982
983int
985 // Arbitrary defaulting to DHCPv4 or with other words extractCommand
986 // below is not expected to throw...
987 bool v4 = true;
988 stringstream resp;
989 string lease_address = "unknown";
990 try {
991 extractCommand(handle);
992 v4 = (cmd_name_ == "lease4-add");
993 if (!cmd_args_) {
994 isc_throw(isc::BadValue, "no parameters specified for the command");
995 }
996
998
999 // This parameter is ignored for the commands adding the lease.
1000 bool force_create = false;
1001 Lease4Ptr lease4;
1002 Lease6Ptr lease6;
1003 if (v4) {
1004 Lease4Parser parser;
1005 lease4 = parser.parse(config, cmd_args_, force_create);
1006 if (lease4) {
1007 lease_address = lease4->addr_.toText();
1008 bool success;
1009 if (!MultiThreadingMgr::instance().getMode()) {
1010 // Not multi-threading.
1011 success = LeaseMgrFactory::instance().addLease(lease4);
1012 } else {
1013 // Multi-threading, try to lock first to avoid a race.
1014 ResourceHandler4 resource_handler;
1015 if (resource_handler.tryLock4(lease4->addr_)) {
1016 success = LeaseMgrFactory::instance().addLease(lease4);
1017 } else {
1019 "ResourceBusy: IP address:" << lease4->addr_
1020 << " could not be added.");
1021 }
1022 }
1023
1024 if (!success) {
1025 isc_throw(LeaseCmdsConflict, "IPv4 lease already exists.");
1026 }
1027
1029 resp << "Lease for address " << lease4->addr_.toText()
1030 << ", subnet-id " << lease4->subnet_id_ << " added.";
1031 }
1032 } else {
1033 Lease6Parser parser;
1034 lease6 = parser.parse(config, cmd_args_, force_create);
1035 if (lease6) {
1036 lease_address = lease6->addr_.toText();
1037 bool success;
1038 if (!MultiThreadingMgr::instance().getMode()) {
1039 // Not multi-threading.
1040 success = LeaseMgrFactory::instance().addLease(lease6);
1041 } else {
1042 // Multi-threading, try to lock first to avoid a race.
1043 ResourceHandler resource_handler;
1044 if (resource_handler.tryLock(lease6->type_, lease6->addr_)) {
1045 success = LeaseMgrFactory::instance().addLease(lease6);
1046 } else {
1048 "ResourceBusy: IP address:" << lease6->addr_
1049 << " could not be added.");
1050 }
1051 }
1052
1053 if (!success) {
1054 isc_throw(LeaseCmdsConflict, "IPv6 lease already exists.");
1055 }
1056
1058 if (lease6->type_ == Lease::TYPE_NA) {
1059 resp << "Lease for address " << lease6->addr_.toText()
1060 << ", subnet-id " << lease6->subnet_id_ << " added.";
1061 } else {
1062 resp << "Lease for prefix " << lease6->addr_.toText()
1063 << "/" << static_cast<int>(lease6->prefixlen_)
1064 << ", subnet-id " << lease6->subnet_id_ << " added.";
1065 }
1066 }
1067 }
1068 } catch (const LeaseCmdsConflict& ex) {
1070 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1071 .arg(ex.what());
1073 return (0);
1074
1075 } catch (const std::exception& ex) {
1077 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1078 .arg(ex.what());
1079 setErrorResponse(handle, ex.what());
1080 return (1);
1081 }
1082
1085 .arg(lease_address);
1086 setSuccessResponse(handle, resp.str());
1087 return (0);
1088}
1089
1092 Parameters x;
1093
1094 if (!params || params->getType() != Element::map) {
1095 isc_throw(BadValue, "Parameters missing or are not a map.");
1096 }
1097
1098 if (params->contains("update-ddns")) {
1099 ConstElementPtr tmp = params->get("update-ddns");
1100 if (tmp->getType() != Element::boolean) {
1101 isc_throw(BadValue, "'update-ddns' is not a boolean");
1102 } else {
1103 x.updateDDNS = tmp->boolValue();
1104 }
1105 }
1106
1107 // We support several sets of parameters for leaseX-get/lease-del:
1108 // lease-get(type, address)
1109 // lease-get(type, subnet-id, identifier-type, identifier)
1110
1111 if (params->contains("type")) {
1112 string t = params->get("type")->stringValue();
1113 if (t == "IA_NA" || t == "0") {
1115 } else if (t == "IA_TA" || t == "1") {
1117 } else if (t == "IA_PD" || t == "2") {
1119 } else if (t == "V4" || t == "3") {
1121 } else {
1122 isc_throw(BadValue, "Invalid lease type specified: "
1123 << t << ", only supported values are: IA_NA, IA_TA,"
1124 << " IA_PD and V4");
1125 }
1126 }
1127
1128 ConstElementPtr tmp = params->get("ip-address");
1129 if (tmp) {
1130 if (tmp->getType() != Element::string) {
1131 isc_throw(BadValue, "'ip-address' is not a string.");
1132 }
1133
1134 x.addr = IOAddress(tmp->stringValue());
1135
1136 if ((v6 && !x.addr.isV6()) || (!v6 && !x.addr.isV4())) {
1137 stringstream txt;
1138 txt << "Invalid " << (v6 ? "IPv6" : "IPv4")
1139 << " address specified: " << tmp->stringValue();
1140 isc_throw(BadValue, txt.str());
1141 }
1142
1144 return (x);
1145 }
1146
1147 tmp = params->get("subnet-id");
1148 if (!tmp) {
1149 isc_throw(BadValue, "Mandatory 'subnet-id' parameter missing.");
1150 }
1151 if (tmp->getType() != Element::integer) {
1152 isc_throw(BadValue, "'subnet-id' parameter is not integer.");
1153 }
1154 x.subnet_id = tmp->intValue();
1155
1156 if (params->contains("iaid")) {
1157 x.iaid = params->get("iaid")->intValue();
1158 }
1159
1160 // No address specified. Ok, so it must be identifier based query.
1161 // "identifier-type": "duid",
1162 // "identifier": "aa:bb:cc:dd:ee:..."
1163
1164 ConstElementPtr type = params->get("identifier-type");
1165 ConstElementPtr ident = params->get("identifier");
1166 if (!type || type->getType() != Element::string) {
1167 isc_throw(BadValue, "No 'ip-address' provided"
1168 " and 'identifier-type' is either missing or not a string.");
1169 }
1170 if (!ident || ident->getType() != Element::string) {
1171 isc_throw(BadValue, "No 'ip-address' provided"
1172 " and 'identifier' is either missing or not a string.");
1173 }
1174
1175 // Got the parameters. Let's see if their values make sense.
1176 // Try to convert identifier-type
1177 x.query_type = Parameters::txtToType(type->stringValue());
1178
1179 switch (x.query_type) {
1181 HWAddr hw = HWAddr::fromText(ident->stringValue());
1182 x.hwaddr = HWAddrPtr(new HWAddr(hw));
1183 break;
1184 }
1186 x.client_id = ClientId::fromText(ident->stringValue());
1187 break;
1188 }
1189 case Parameters::TYPE_DUID: {
1190 DUID duid = DUID::fromText(ident->stringValue());
1191 x.duid = DuidPtr(new DUID(duid));
1192 break;
1193 }
1194 case Parameters::TYPE_ADDR: {
1195 // We should never get here. The address clause should have been caught
1196 // earlier.
1197 return (x);
1198 }
1199 default: {
1200 isc_throw(BadValue, "Identifier type " << type->stringValue() <<
1201 " is not supported.");
1202 }
1203 }
1204
1205 return (x);
1206}
1207
1208int
1210 Parameters p;
1211 Lease4Ptr lease4;
1212 Lease6Ptr lease6;
1213 bool v4 = true;
1214 try {
1215 extractCommand(handle);
1216 v4 = (cmd_name_ == "lease4-get");
1217 p = getParameters(!v4, cmd_args_);
1218 switch (p.query_type) {
1219 case Parameters::TYPE_ADDR: {
1220 // Query by address
1221 if (v4) {
1223 } else {
1225 }
1226 break;
1227 }
1229 if (v4) {
1230 if (!p.hwaddr) {
1231 isc_throw(InvalidParameter, "Program error: Query by hw-address "
1232 "requires hwaddr to be specified");
1233 }
1234
1236 } else {
1237 isc_throw(isc::InvalidParameter, "Query by hw-address is not allowed in v6.");
1238 }
1239 break;
1240
1242 if (!v4) {
1243 if (!p.duid) {
1244 isc_throw(InvalidParameter, "Program error: Query by duid "
1245 "requires duid to be specified");
1246 }
1247
1249 p.iaid, p.subnet_id);
1250 } else {
1251 isc_throw(InvalidParameter, "Query by duid is not allowed in v4.");
1252 }
1253 break;
1254
1256 if (v4) {
1257 if (!p.client_id) {
1258 isc_throw(InvalidParameter, "Program error: Query by client-id "
1259 "requires client-id to be specified");
1260 }
1261
1263 } else {
1264 isc_throw(isc::InvalidParameter, "Query by client-id is not allowed in v6.");
1265 }
1266 break;
1267
1268 default: {
1269 isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1270 break;
1271 }
1272 }
1273 } catch (const std::exception& ex) {
1275 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1276 .arg(ex.what());
1277 setErrorResponse(handle, ex.what());
1278 return (1);
1279 }
1280
1281 ElementPtr lease_json;
1282 if (v4 && lease4) {
1283 lease_json = lease4->toElement();
1285 "IPv4 lease found.", lease_json);
1286 setResponse(handle, response);
1287 } else if (!v4 && lease6) {
1288 lease_json = lease6->toElement();
1290 "IPv6 lease found.", lease_json);
1291 setResponse(handle, response);
1292 } else {
1293 // If we got here, the lease has not been found.
1294 setErrorResponse(handle, "Lease not found.", CONTROL_RESULT_EMPTY);
1295 }
1296
1297 return (0);
1298}
1299
1300int
1302 bool v4 = true;
1303 try {
1304 extractCommand(handle);
1305 v4 = (cmd_name_ == "lease4-get-all");
1306
1307 ElementPtr leases_json = Element::createList();
1308
1309 // The argument may contain a list of subnets for which leases should
1310 // be returned.
1311 if (cmd_args_) {
1312 ConstElementPtr subnets = cmd_args_->get("subnets");
1313 if (!subnets) {
1314 isc_throw(BadValue, "'subnets' parameter not specified");
1315 }
1316 if (subnets->getType() != Element::list) {
1317 isc_throw(BadValue, "'subnets' parameter must be a list");
1318 }
1319
1320 const std::vector<ElementPtr>& subnet_ids = subnets->listValue();
1321 for (auto const& subnet_id : subnet_ids) {
1322 if (subnet_id->getType() != Element::integer) {
1323 isc_throw(BadValue, "listed subnet identifiers must be numbers");
1324 }
1325
1326 if (v4) {
1327 Lease4Collection leases =
1328 LeaseMgrFactory::instance().getLeases4(subnet_id->intValue());
1329 for (auto const& lease : leases) {
1330 ElementPtr lease_json = lease->toElement();
1331 leases_json->add(lease_json);
1332 }
1333 } else {
1334 Lease6Collection leases =
1335 LeaseMgrFactory::instance().getLeases6(subnet_id->intValue());
1336 for (auto const& lease : leases) {
1337 ElementPtr lease_json = lease->toElement();
1338 leases_json->add(lease_json);
1339 }
1340 }
1341 }
1342
1343 } else {
1344 // There is no 'subnets' argument so let's return all leases.
1345 if (v4) {
1347 for (auto const& lease : leases) {
1348 ElementPtr lease_json = lease->toElement();
1349 leases_json->add(lease_json);
1350 }
1351 } else {
1353 for (auto const& lease : leases) {
1354 ElementPtr lease_json = lease->toElement();
1355 leases_json->add(lease_json);
1356 }
1357 }
1358 }
1359
1360 std::ostringstream s;
1361 s << leases_json->size()
1362 << " IPv" << (v4 ? "4" : "6")
1363 << " lease(s) found.";
1365 args->set("leases", leases_json);
1366 ConstElementPtr response =
1367 createAnswer(leases_json->size() > 0 ?
1370 s.str(), args);
1371 setResponse(handle, response);
1372
1373 } catch (const std::exception& ex) {
1374 setErrorResponse(handle, ex.what());
1375 return (CONTROL_RESULT_ERROR);
1376 }
1377
1378 return (0);
1379}
1380
1381int
1383 bool v4 = true;
1384 try {
1385 extractCommand(handle);
1386 v4 = (cmd_name_ == "lease4-get-page");
1387
1388 // arguments must always be present
1389 if (!cmd_args_) {
1390 isc_throw(BadValue, "no parameters specified for the " << cmd_name_
1391 << " command");
1392 }
1393
1394 // The 'from' argument denotes from which lease we should start the
1395 // results page. The results page excludes this lease.
1396 ConstElementPtr from = cmd_args_->get("from");
1397 if (!from) {
1398 isc_throw(BadValue, "'from' parameter not specified");
1399 }
1400
1401 // The 'from' argument is a string. It may contain a 'start' keyword or
1402 // an IP address.
1403 if (from->getType() != Element::string) {
1404 isc_throw(BadValue, "'from' parameter must be a string");
1405 }
1406
1407 boost::scoped_ptr<IOAddress> from_address;
1408 try {
1409 if (from->stringValue() == "start") {
1410 from_address.reset(new IOAddress(v4 ? "0.0.0.0" : "::"));
1411
1412 } else {
1413 // Conversion of a string to an IP address may throw.
1414 from_address.reset(new IOAddress(from->stringValue()));
1415 }
1416
1417 } catch (...) {
1418 isc_throw(BadValue, "'from' parameter value is neither 'start' keyword nor "
1419 "a valid IPv" << (v4 ? "4" : "6") << " address");
1420 }
1421
1422 // It must be either IPv4 address for lease4-get-page or IPv6 address for
1423 // lease6-get-page.
1424 if (v4 && (!from_address->isV4())) {
1425 isc_throw(BadValue, "'from' parameter value " << from_address->toText()
1426 << " is not an IPv4 address");
1427
1428 } else if (!v4 && from_address->isV4()) {
1429 isc_throw(BadValue, "'from' parameter value " << from_address->toText()
1430 << " is not an IPv6 address");
1431 }
1432
1433 // The 'limit' is a desired page size. It must always be present.
1434 ConstElementPtr page_limit = cmd_args_->get("limit");
1435 if (!page_limit) {
1436 isc_throw(BadValue, "'limit' parameter not specified");
1437 }
1438
1439 // The 'limit' must be a number.
1440 if (page_limit->getType() != Element::integer) {
1441 isc_throw(BadValue, "'limit' parameter must be a number");
1442 }
1443
1444 // Retrieve the desired page size.
1445 size_t page_limit_value = static_cast<size_t>(page_limit->intValue());
1446
1447 ElementPtr leases_json = Element::createList();
1448
1449 if (v4) {
1450 // Get page of IPv4 leases.
1451 Lease4Collection leases =
1452 LeaseMgrFactory::instance().getLeases4(*from_address,
1453 LeasePageSize(page_limit_value));
1454
1455 // Convert leases into JSON list.
1456 for (auto const& lease : leases) {
1457 ElementPtr lease_json = lease->toElement();
1458 leases_json->add(lease_json);
1459 }
1460
1461 } else {
1462 // Get page of IPv6 leases.
1463 Lease6Collection leases =
1464 LeaseMgrFactory::instance().getLeases6(*from_address,
1465 LeasePageSize(page_limit_value));
1466 // Convert leases into JSON list.
1467 for (auto const& lease : leases) {
1468 ElementPtr lease_json = lease->toElement();
1469 leases_json->add(lease_json);
1470 }
1471 }
1472
1473 // Prepare textual status.
1474 std::ostringstream s;
1475 s << leases_json->size()
1476 << " IPv" << (v4 ? "4" : "6")
1477 << " lease(s) found.";
1479
1480 // Put gathered data into arguments map.
1481 args->set("leases", leases_json);
1482 args->set("count", Element::create(static_cast<int64_t>(leases_json->size())));
1483
1484 // Create the response.
1485 ConstElementPtr response =
1486 createAnswer(leases_json->size() > 0 ?
1489 s.str(), args);
1490 setResponse(handle, response);
1491
1492 } catch (const std::exception& ex) {
1493 setErrorResponse(handle, ex.what());
1494 return (CONTROL_RESULT_ERROR);
1495 }
1496
1497 return (CONTROL_RESULT_SUCCESS);
1498}
1499
1500int
1502 try {
1503 extractCommand(handle);
1504
1505 // arguments must always be present
1506 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1507 isc_throw(BadValue, "Command arguments missing or a not a map.");
1508 }
1509
1510 // the hw-address parameter is mandatory.
1511 ConstElementPtr hw_address = cmd_args_->get("hw-address");
1512 if (!hw_address) {
1513 isc_throw(BadValue, "'hw-address' parameter not specified");
1514 }
1515
1516 // The 'hw-address' argument is a string.
1517 if (hw_address->getType() != Element::string) {
1518 isc_throw(BadValue, "'hw-address' parameter must be a string");
1519 }
1520
1521 HWAddr hwaddr = HWAddr::fromText(hw_address->stringValue());
1522
1523 Lease4Collection leases =
1525 ElementPtr leases_json = Element::createList();
1526 for (auto const& lease : leases) {
1527 ElementPtr lease_json = lease->toElement();
1528 leases_json->add(lease_json);
1529 }
1530
1531 std::ostringstream s;
1532 s << leases_json->size() << " IPv4 lease(s) found.";
1534 args->set("leases", leases_json);
1535 ConstElementPtr response =
1536 createAnswer(leases_json->size() > 0 ?
1539 s.str(), args);
1540 setResponse(handle, response);
1541
1542 } catch (const std::exception& ex) {
1543 setErrorResponse(handle, ex.what());
1544 return (CONTROL_RESULT_ERROR);
1545 }
1546
1547 return (0);
1548}
1549
1550int
1552 try {
1553 extractCommand(handle);
1554
1555 // arguments must always be present
1556 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1557 isc_throw(BadValue, "Command arguments missing or a not a map.");
1558 }
1559
1560 // the client-id parameter is mandatory.
1561 ConstElementPtr client_id = cmd_args_->get("client-id");
1562 if (!client_id) {
1563 isc_throw(BadValue, "'client-id' parameter not specified");
1564 }
1565
1566 // The 'client-id' argument is a string.
1567 if (client_id->getType() != Element::string) {
1568 isc_throw(BadValue, "'client-id' parameter must be a string");
1569 }
1570
1571 ClientIdPtr clientid = ClientId::fromText(client_id->stringValue());
1572
1573 Lease4Collection leases =
1575 ElementPtr leases_json = Element::createList();
1576 for (auto const& lease : leases) {
1577 ElementPtr lease_json = lease->toElement();
1578 leases_json->add(lease_json);
1579 }
1580
1581 std::ostringstream s;
1582 s << leases_json->size() << " IPv4 lease(s) found.";
1584 args->set("leases", leases_json);
1585 ConstElementPtr response =
1586 createAnswer(leases_json->size() > 0 ?
1589 s.str(), args);
1590 setResponse(handle, response);
1591
1592 } catch (const std::exception& ex) {
1593 setErrorResponse(handle, ex.what());
1594 return (CONTROL_RESULT_ERROR);
1595 }
1596
1597 return (0);
1598}
1599
1600int
1602 try {
1603 extractCommand(handle);
1604
1605 // arguments must always be present
1606 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1607 isc_throw(BadValue, "Command arguments missing or a not a map.");
1608 }
1609
1610 // the duid parameter is mandatory.
1611 ConstElementPtr duid = cmd_args_->get("duid");
1612 if (!duid) {
1613 isc_throw(BadValue, "'duid' parameter not specified");
1614 }
1615
1616 // The 'duid' argument is a string.
1617 if (duid->getType() != Element::string) {
1618 isc_throw(BadValue, "'duid' parameter must be a string");
1619 }
1620
1621 DUID duid_ = DUID::fromText(duid->stringValue());
1622
1623 Lease6Collection leases =
1625 ElementPtr leases_json = Element::createList();
1626 for (auto const& lease : leases) {
1627 ElementPtr lease_json = lease->toElement();
1628 leases_json->add(lease_json);
1629 }
1630
1631 std::ostringstream s;
1632 s << leases_json->size() << " IPv6 lease(s) found.";
1634 args->set("leases", leases_json);
1635 ConstElementPtr response =
1636 createAnswer(leases_json->size() > 0 ?
1639 s.str(), args);
1640 setResponse(handle, response);
1641
1642 } catch (const std::exception& ex) {
1643 setErrorResponse(handle, ex.what());
1644 return (CONTROL_RESULT_ERROR);
1645 }
1646
1647 return (0);
1648}
1649
1650int
1652 bool v4 = true;
1653 try {
1654 extractCommand(handle);
1655 v4 = (cmd_name_ == "lease4-get-by-hostname");
1656
1657 // arguments must always be present
1658 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1659 isc_throw(BadValue, "Command arguments missing or a not a map.");
1660 }
1661
1662 // the hostname parameter is mandatory.
1663 ConstElementPtr hostname = cmd_args_->get("hostname");
1664 if (!hostname) {
1665 isc_throw(BadValue, "'hostname' parameter not specified");
1666 }
1667
1668 // The 'hostname' argument is a string.
1669 if (hostname->getType() != Element::string) {
1670 isc_throw(BadValue, "'hostname' parameter must be a string");
1671 }
1672
1673 std::string hostname_ = hostname->stringValue();
1675 if (hostname_.empty()) {
1676 isc_throw(BadValue, "'hostname' parameter is empty");
1677 }
1678 boost::algorithm::to_lower(hostname_);
1679
1680 ElementPtr leases_json = Element::createList();
1681 if (v4) {
1682 Lease4Collection leases =
1684
1685 for (auto const& lease : leases) {
1686 ElementPtr lease_json = lease->toElement();
1687 leases_json->add(lease_json);
1688 }
1689 } else {
1690 Lease6Collection leases =
1692
1693 for (auto const& lease : leases) {
1694 ElementPtr lease_json = lease->toElement();
1695 leases_json->add(lease_json);
1696 }
1697 }
1698
1699 std::ostringstream s;
1700 s << leases_json->size()
1701 << " IPv" << (v4 ? "4" : "6")
1702 << " lease(s) found.";
1704 args->set("leases", leases_json);
1705 ConstElementPtr response =
1706 createAnswer(leases_json->size() > 0 ?
1709 s.str(), args);
1710 setResponse(handle, response);
1711
1712 } catch (const std::exception& ex) {
1713 setErrorResponse(handle, ex.what());
1714 return (CONTROL_RESULT_ERROR);
1715 }
1716
1717 return (0);
1718}
1719
1720int
1722 Parameters p;
1723 Lease4Ptr lease4;
1724 try {
1725 extractCommand(handle);
1726 p = getParameters(false, cmd_args_);
1727 switch (p.query_type) {
1728 case Parameters::TYPE_ADDR: {
1729 // If address was specified explicitly, let's use it as is.
1731 if (!lease4) {
1732 setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1733 return (0);
1734 }
1735 break;
1736 }
1738 if (!p.hwaddr) {
1739 isc_throw(InvalidParameter, "Program error: Query by hw-address "
1740 "requires hwaddr to be specified");
1741 }
1742
1743 // Let's see if there's such a lease at all.
1745 if (!lease4) {
1746 setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1747 return (0);
1748 }
1749 break;
1750 }
1752 if (!p.client_id) {
1753 isc_throw(InvalidParameter, "Program error: Query by client-id "
1754 "requires client-id to be specified");
1755 }
1756
1757 // Let's see if there's such a lease at all.
1759 if (!lease4) {
1760 setErrorResponse(handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1761 return (0);
1762 }
1763 break;
1764 }
1765 case Parameters::TYPE_DUID: {
1766 isc_throw(InvalidParameter, "Delete by duid is not allowed in v4.");
1767 break;
1768 }
1769 default: {
1770 isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
1771 break;
1772 }
1773 }
1774
1775 if (LeaseMgrFactory::instance().deleteLease(lease4)) {
1776 setSuccessResponse(handle, "IPv4 lease deleted.");
1778 } else {
1779 setErrorResponse (handle, "IPv4 lease not found.", CONTROL_RESULT_EMPTY);
1780 }
1781
1782 // Queue an NCR to remove DNS if configured and the lease has it.
1783 if (p.updateDDNS) {
1784 queueNCR(CHG_REMOVE, lease4);
1785 }
1786
1787 } catch (const std::exception& ex) {
1789 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
1790 .arg(ex.what());
1791 setErrorResponse(handle, ex.what());
1792 return (1);
1793 }
1795 .arg(lease4->addr_.toText());
1796 return (0);
1797}
1798
1799int
1801 try {
1802 extractCommand(handle);
1803
1804 // Arguments are mandatory.
1805 if (!cmd_args_ || (cmd_args_->getType() != Element::map)) {
1806 isc_throw(BadValue, "Command arguments missing or a not a map.");
1807 }
1808
1809 // At least one of the 'deleted-leases' or 'leases' must be present.
1810 auto deleted_leases = cmd_args_->get("deleted-leases");
1811 auto leases = cmd_args_->get("leases");
1812
1813 if (!deleted_leases && !leases) {
1814 isc_throw(BadValue, "neither 'deleted-leases' nor 'leases' parameter"
1815 " specified");
1816 }
1817
1818 // Make sure that 'deleted-leases' is a list, if present.
1819 if (deleted_leases && (deleted_leases->getType() != Element::list)) {
1820 isc_throw(BadValue, "the 'deleted-leases' parameter must be a list");
1821 }
1822
1823 // Make sure that 'leases' is a list, if present.
1824 if (leases && (leases->getType() != Element::list)) {
1825 isc_throw(BadValue, "the 'leases' parameter must be a list");
1826 }
1827
1828 // Parse deleted leases without deleting them from the database
1829 // yet. If any of the deleted leases or new leases appears to be
1830 // malformed we can easily rollback.
1831 std::list<std::pair<Parameters, Lease6Ptr> > parsed_deleted_list;
1832 if (deleted_leases) {
1833 auto leases_list = deleted_leases->listValue();
1834
1835 // Iterate over leases to be deleted.
1836 for (auto const& lease_params : leases_list) {
1837 // Parsing the lease may throw and it means that the lease
1838 // information is malformed.
1839 Parameters p = getParameters(true, lease_params);
1840 auto lease = getIPv6LeaseForDelete(p);
1841 parsed_deleted_list.push_back(std::make_pair(p, lease));
1842 }
1843 }
1844
1845 // Parse new/updated leases without affecting the database to detect
1846 // any errors that should cause an error response.
1847 std::list<Lease6Ptr> parsed_leases_list;
1848 if (leases) {
1850
1851 // Iterate over all leases.
1852 auto leases_list = leases->listValue();
1853 for (auto const& lease_params : leases_list) {
1854
1855 Lease6Parser parser;
1856 bool force_update;
1857
1858 // If parsing the lease fails we throw, as it indicates that the
1859 // command is malformed.
1860 Lease6Ptr lease6 = parser.parse(config, lease_params, force_update);
1861 parsed_leases_list.push_back(lease6);
1862 }
1863 }
1864
1865 // Count successful deletions and updates.
1866 size_t success_count = 0;
1867
1868 ElementPtr failed_deleted_list;
1869 if (!parsed_deleted_list.empty()) {
1870
1871 // Iterate over leases to be deleted.
1872 for (auto const& lease_params_pair : parsed_deleted_list) {
1873
1874 // This part is outside of the try-catch because an exception
1875 // indicates that the command is malformed.
1876 Parameters p = lease_params_pair.first;
1877 auto lease = lease_params_pair.second;
1878
1879 try {
1880 if (lease) {
1881 // This may throw if the lease couldn't be deleted for
1882 // any reason, but we still want to proceed with other
1883 // leases.
1884 if (LeaseMgrFactory::instance().deleteLease(lease)) {
1885 ++success_count;
1887
1888 } else {
1889 // Lazy creation of the list of leases which failed to delete.
1890 if (!failed_deleted_list) {
1891 failed_deleted_list = Element::createList();
1892 }
1893
1894 // If the lease doesn't exist we also want to put it
1895 // on the list of leases which failed to delete. That
1896 // corresponds to the lease6-del command which returns
1897 // an error when the lease doesn't exist.
1898 failed_deleted_list->add(createFailedLeaseMap(p.lease_type,
1899 p.addr, p.duid,
1901 "lease not found"));
1902 }
1903 }
1904
1905 } catch (const std::exception& ex) {
1906 // Lazy creation of the list of leases which failed to delete.
1907 if (!failed_deleted_list) {
1908 failed_deleted_list = Element::createList();
1909 }
1910 failed_deleted_list->add(createFailedLeaseMap(p.lease_type,
1911 p.addr, p.duid,
1913 ex.what()));
1914 }
1915 }
1916 }
1917
1918 // Process leases to be added or/and updated.
1919 ElementPtr failed_leases_list;
1920 if (!parsed_leases_list.empty()) {
1922
1923 // Iterate over all leases.
1924 for (auto const& lease : parsed_leases_list) {
1925
1926 auto result = CONTROL_RESULT_SUCCESS;
1927 std::ostringstream text;
1928 try {
1929 if (!MultiThreadingMgr::instance().getMode()) {
1930 // Not multi-threading.
1931 addOrUpdate6(lease, true);
1932 } else {
1933 // Multi-threading, try to lock first to avoid a race.
1934 ResourceHandler resource_handler;
1935 if (resource_handler.tryLock(lease->type_, lease->addr_)) {
1936 addOrUpdate6(lease, true);
1937 } else {
1939 "ResourceBusy: IP address:" << lease->addr_
1940 << " could not be updated.");
1941 }
1942 }
1943
1944 ++success_count;
1945 } catch (const LeaseCmdsConflict& ex) {
1946 result = CONTROL_RESULT_CONFLICT;
1947 text << ex.what();
1948
1949 } catch (const std::exception& ex) {
1950 result = CONTROL_RESULT_ERROR;
1951 text << ex.what();
1952 }
1953 // Handle an error.
1954 if (result != CONTROL_RESULT_SUCCESS) {
1955 // Lazy creation of the list of leases which failed to add/update.
1956 if (!failed_leases_list) {
1957 failed_leases_list = Element::createList();
1958 }
1959 failed_leases_list->add(createFailedLeaseMap(lease->type_,
1960 lease->addr_,
1961 lease->duid_,
1962 result,
1963 text.str()));
1964 }
1965 }
1966 }
1967
1968 // Start preparing the response.
1969 ElementPtr args;
1970
1971 if (failed_deleted_list || failed_leases_list) {
1972 // If there are any failed leases, let's include them in the response.
1973 args = Element::createMap();
1974
1975 // failed-deleted-leases
1976 if (failed_deleted_list) {
1977 args->set("failed-deleted-leases", failed_deleted_list);
1978 }
1979
1980 // failed-leases
1981 if (failed_leases_list) {
1982 args->set("failed-leases", failed_leases_list);
1983 }
1984 }
1985
1986 // Send the success response and include failed leases.
1987 std::ostringstream resp_text;
1988 resp_text << "Bulk apply of " << success_count << " IPv6 leases completed.";
1989 auto answer = createAnswer(success_count > 0 ? CONTROL_RESULT_SUCCESS :
1990 CONTROL_RESULT_EMPTY, resp_text.str(), args);
1991 setResponse(handle, answer);
1992
1995 .arg(success_count);
1996
1997 } catch (const std::exception& ex) {
1998 // Unable to parse the command and similar issues.
2000 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2001 .arg(ex.what());
2002 setErrorResponse(handle, ex.what());
2003 return (CONTROL_RESULT_ERROR);
2004 }
2005
2006 return (0);
2007}
2008
2009int
2011 Parameters p;
2012 Lease6Ptr lease6;
2014 try {
2015 extractCommand(handle);
2016 p = getParameters(true, cmd_args_);
2017
2018 switch (p.query_type) {
2019 case Parameters::TYPE_ADDR: {
2020 // If address was specified explicitly, let's use it as is.
2021
2022 // Let's see if there's such a lease at all.
2024 if (!lease6) {
2025 setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
2026 return (0);
2027 }
2028 break;
2029 }
2031 isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6.");
2032 break;
2033 }
2034 case Parameters::TYPE_DUID: {
2035 if (!p.duid) {
2036 isc_throw(InvalidParameter, "Program error: Query by duid "
2037 "requires duid to be specified");
2038 }
2039
2040 // Let's see if there's such a lease at all.
2042 p.iaid, p.subnet_id);
2043 if (!lease6) {
2044 setErrorResponse(handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
2045 return (0);
2046 }
2047 break;
2048 }
2049 default: {
2050 isc_throw(InvalidOperation, "Unknown query type: " << static_cast<int>(p.query_type));
2051 break;
2052 }
2053 }
2054
2055 if (LeaseMgrFactory::instance().deleteLease(lease6)) {
2056 setSuccessResponse(handle, "IPv6 lease deleted.");
2058 } else {
2059 setErrorResponse (handle, "IPv6 lease not found.", CONTROL_RESULT_EMPTY);
2060 }
2061
2062 // Queue an NCR to remove DNS if configured and the lease has it.
2063 if (p.updateDDNS) {
2064 queueNCR(CHG_REMOVE, lease6);
2065 }
2066
2067 } catch (const std::exception& ex) {
2069 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2070 .arg(ex.what());
2071 setErrorResponse(handle, ex.what());
2072 return (1);
2073 }
2074
2076 .arg(lease6->addr_.toText());
2077 return (0);
2078}
2079
2080int
2082 try {
2083 extractCommand(handle);
2084
2085 // We need the lease to be specified.
2086 if (!cmd_args_) {
2087 isc_throw(isc::BadValue, "no parameters specified for lease4-update command");
2088 }
2089
2090 // Get the parameters specified by the user first.
2092 Lease4Ptr lease4;
2093 Lease4Parser parser;
2094 bool force_create = false;
2095
2096 // The parser does sanity checks (if the address is in scope, if
2097 // subnet-id is valid, etc)
2098 lease4 = parser.parse(config, cmd_args_, force_create);
2099 bool added = false;
2100 if (!MultiThreadingMgr::instance().getMode()) {
2101 // Not multi-threading.
2102 added = addOrUpdate4(lease4, force_create);
2103 } else {
2104 // Multi-threading, try to lock first to avoid a race.
2105 ResourceHandler4 resource_handler;
2106 if (resource_handler.tryLock4(lease4->addr_)) {
2107 added = addOrUpdate4(lease4, force_create);
2108 } else {
2110 "ResourceBusy: IP address:" << lease4->addr_
2111 << " could not be updated.");
2112 }
2113 }
2114
2115 if (added) {
2116 setSuccessResponse(handle, "IPv4 lease added.");
2117 } else {
2118 setSuccessResponse(handle, "IPv4 lease updated.");
2119 }
2122 .arg(lease4->addr_.toText());
2123
2124 } catch (const LeaseCmdsConflict& ex) {
2126 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2127 .arg(ex.what());
2129 return (0);
2130
2131 } catch (const std::exception& ex) {
2133 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2134 .arg(ex.what());
2135 setErrorResponse(handle, ex.what());
2136 return (1);
2137 }
2138
2139 return (0);
2140}
2141
2142int
2144 try {
2145 extractCommand(handle);
2146
2147 // We need the lease to be specified.
2148 if (!cmd_args_) {
2149 isc_throw(isc::BadValue, "no parameters specified for lease6-update command");
2150 }
2151
2152 // Get the parameters specified by the user first.
2154 Lease6Ptr lease6;
2155 Lease6Parser parser;
2156 bool force_create = false;
2157
2158 // The parser does sanity checks (if the address is in scope, if
2159 // subnet-id is valid, etc)
2160 lease6 = parser.parse(config, cmd_args_, force_create);
2161 bool added = false;
2162 if (!MultiThreadingMgr::instance().getMode()) {
2163 // Not multi-threading.
2164 added = addOrUpdate6(lease6, force_create);
2165 } else {
2166 // Multi-threading, try to lock first to avoid a race.
2167 ResourceHandler resource_handler;
2168 if (resource_handler.tryLock(lease6->type_, lease6->addr_)) {
2169 added = addOrUpdate6(lease6, force_create);
2170 } else {
2172 "ResourceBusy: IP address:" << lease6->addr_
2173 << " could not be updated.");
2174 }
2175 }
2176
2177 if (added) {
2178 setSuccessResponse(handle, "IPv6 lease added.");
2179 } else {
2180 setSuccessResponse(handle, "IPv6 lease updated.");
2181 }
2184 .arg(lease6->addr_.toText());
2185
2186 } catch (const LeaseCmdsConflict& ex) {
2188 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2189 .arg(ex.what());
2191 return (0);
2192
2193 } catch (const std::exception& ex) {
2195 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2196 .arg(ex.what());
2197 setErrorResponse(handle, ex.what());
2198 return (1);
2199 }
2200
2201 return (0);
2202}
2203
2204int
2206 try {
2207 extractCommand(handle);
2208
2209 SimpleParser parser;
2210 SubnetID id = 0;
2211
2212 size_t num = 0; // number of leases deleted
2213 stringstream ids; // a text with subnet-ids being wiped
2214
2215 // The subnet-id parameter is now optional.
2216 if (cmd_args_ && cmd_args_->contains("subnet-id")) {
2217 id = parser.getUint32(cmd_args_, "subnet-id");
2218 }
2219
2220 if (id) {
2221 // Wipe a single subnet.
2223 ids << " " << id;
2224
2225 auto observation = StatsMgr::instance().getObservation(
2226 StatsMgr::generateName("subnet", id, "declined-addresses"));
2227
2228 int64_t previous_declined = 0;
2229
2230 if (observation) {
2231 previous_declined = observation->getInteger().first;
2232 }
2233
2235 StatsMgr::generateName("subnet", id, "assigned-addresses"),
2236 static_cast<int64_t>(0));
2237
2239 StatsMgr::generateName("subnet", id, "declined-addresses"),
2240 static_cast<int64_t>(0));
2241
2242 auto const& sub = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getBySubnetId(id);
2243 if (sub) {
2244 for (auto const& pool : sub->getPools(Lease::TYPE_V4)) {
2245 const std::string& name_aa(StatsMgr::generateName("subnet", sub->getID(),
2246 StatsMgr::generateName("pool", pool->getID(),
2247 "assigned-addresses")));
2248 if (!StatsMgr::instance().getObservation(name_aa)) {
2249 StatsMgr::instance().setValue(name_aa, static_cast<int64_t>(0));
2250 }
2251
2252 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2253 StatsMgr::generateName("pool", pool->getID(),
2254 "declined-addresses")));
2255 if (!StatsMgr::instance().getObservation(name_da)) {
2256 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2257 }
2258 }
2259 }
2260
2261 StatsMgr::instance().addValue("declined-addresses", -previous_declined);
2262 } else {
2263 // Wipe them all!
2265 ConstCfgSubnets4Ptr subnets = config->getCfgSubnets4();
2266 const Subnet4Collection* subs = subnets->getAll();
2267
2268 // Go over all subnets and wipe leases in each of them.
2269 for (auto const& sub : *subs) {
2270 num += LeaseMgrFactory::instance().wipeLeases4(sub->getID());
2271 ids << " " << sub->getID();
2273 StatsMgr::generateName("subnet", sub->getID(), "assigned-addresses"),
2274 static_cast<int64_t>(0));
2275
2277 StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
2278 static_cast<int64_t>(0));
2279
2280 for (auto const& pool : sub->getPools(Lease::TYPE_V4)) {
2281 const std::string& name_aa(StatsMgr::generateName("subnet", sub->getID(),
2282 StatsMgr::generateName("pool", pool->getID(),
2283 "assigned-addresses")));
2284 if (!StatsMgr::instance().getObservation(name_aa)) {
2285 StatsMgr::instance().setValue(name_aa, static_cast<int64_t>(0));
2286 }
2287
2288 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2289 StatsMgr::generateName("pool", pool->getID(),
2290 "declined-addresses")));
2291 if (!StatsMgr::instance().getObservation(name_da)) {
2292 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2293 }
2294 }
2295 }
2296
2297 StatsMgr::instance().setValue("declined-addresses", static_cast<int64_t>(0));
2298 }
2299
2300 stringstream tmp;
2301 tmp << "Deleted " << num << " IPv4 lease(s) from subnet(s)" << ids.str()
2302 << " WARNING: lease4-wipe is deprecated!";
2304 : CONTROL_RESULT_EMPTY, tmp.str());
2305 setResponse(handle, response);
2306 } catch (const std::exception& ex) {
2308 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2309 .arg(ex.what());
2311 setErrorResponse(handle, ex.what());
2312 return (1);
2313 }
2314
2316 .arg(cmd_args_ ? cmd_args_->str() : "<no args>");
2318 return (0);
2319}
2320
2321int
2323 try {
2324 extractCommand(handle);
2325
2326 SimpleParser parser;
2327 SubnetID id = 0;
2328
2329 size_t num = 0; // number of leases deleted
2330 stringstream ids; // a text with subnet-ids being wiped
2331
2336
2337 // The subnet-id parameter is now optional.
2338 if (cmd_args_ && cmd_args_->contains("subnet-id")) {
2339 id = parser.getUint32(cmd_args_, "subnet-id");
2340 }
2341
2342 if (id) {
2343 // Wipe a single subnet.
2345 ids << " " << id;
2346
2347 auto observation = StatsMgr::instance().getObservation(
2348 StatsMgr::generateName("subnet", id, "declined-addresses"));
2349
2350 int64_t previous_declined = 0;
2351
2352 if (observation) {
2353 previous_declined = observation->getInteger().first;
2354 }
2355
2357 StatsMgr::generateName("subnet", id, "assigned-nas" ),
2358 static_cast<int64_t>(0));
2359
2361 StatsMgr::generateName("subnet", id, "assigned-pds"),
2362 static_cast<int64_t>(0));
2363
2365 StatsMgr::generateName("subnet", id, "declined-addresses"),
2366 static_cast<int64_t>(0));
2367
2368 auto const& sub = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getBySubnetId(id);
2369 if (sub) {
2370 for (auto const& pool : sub->getPools(Lease::TYPE_NA)) {
2371 const std::string& name_anas(StatsMgr::generateName("subnet", sub->getID(),
2372 StatsMgr::generateName("pool", pool->getID(),
2373 "assigned-nas")));
2374 if (!StatsMgr::instance().getObservation(name_anas)) {
2375 StatsMgr::instance().setValue(name_anas, static_cast<int64_t>(0));
2376 }
2377
2378 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2379 StatsMgr::generateName("pool", pool->getID(),
2380 "declined-addresses")));
2381 if (!StatsMgr::instance().getObservation(name_da)) {
2382 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2383 }
2384 }
2385
2386 for (auto const& pool : sub->getPools(Lease::TYPE_PD)) {
2387 const std::string& name_apds(StatsMgr::generateName("subnet", sub->getID(),
2388 StatsMgr::generateName("pd-pool", pool->getID(),
2389 "assigned-pds")));
2390 if (!StatsMgr::instance().getObservation(name_apds)) {
2391 StatsMgr::instance().setValue(name_apds, static_cast<int64_t>(0));
2392 }
2393 }
2394 }
2395
2396 StatsMgr::instance().addValue("declined-addresses", -previous_declined);
2397 } else {
2398 // Wipe them all!
2400 ConstCfgSubnets6Ptr subnets = config->getCfgSubnets6();
2401 const Subnet6Collection* subs = subnets->getAll();
2402
2403 // Go over all subnets and wipe leases in each of them.
2404 for (auto const& sub : *subs) {
2405 num += LeaseMgrFactory::instance().wipeLeases6(sub->getID());
2406 ids << " " << sub->getID();
2408 StatsMgr::generateName("subnet", sub->getID(), "assigned-nas" ),
2409 static_cast<int64_t>(0));
2410
2412 StatsMgr::generateName("subnet", sub->getID(), "assigned-pds"),
2413 static_cast<int64_t>(0));
2414
2416 StatsMgr::generateName("subnet", sub->getID(), "declined-addresses"),
2417 static_cast<int64_t>(0));
2418
2419 for (auto const& pool : sub->getPools(Lease::TYPE_NA)) {
2420 const std::string& name_anas(StatsMgr::generateName("subnet", sub->getID(),
2421 StatsMgr::generateName("pool", pool->getID(),
2422 "assigned-nas")));
2423 if (!StatsMgr::instance().getObservation(name_anas)) {
2424 StatsMgr::instance().setValue(name_anas, static_cast<int64_t>(0));
2425 }
2426
2427 const std::string& name_da(StatsMgr::generateName("subnet", sub->getID(),
2428 StatsMgr::generateName("pool", pool->getID(),
2429 "declined-addresses")));
2430 if (!StatsMgr::instance().getObservation(name_da)) {
2431 StatsMgr::instance().setValue(name_da, static_cast<int64_t>(0));
2432 }
2433 }
2434
2435 for (auto const& pool : sub->getPools(Lease::TYPE_PD)) {
2436 const std::string& name_apds(StatsMgr::generateName("subnet", sub->getID(),
2437 StatsMgr::generateName("pd-pool", pool->getID(),
2438 "assigned-pds")));
2439 if (!StatsMgr::instance().getObservation(name_apds)) {
2440 StatsMgr::instance().setValue(name_apds, static_cast<int64_t>(0));
2441 }
2442 }
2443 }
2444
2445 StatsMgr::instance().setValue("declined-addresses", static_cast<int64_t>(0));
2446 }
2447
2448 stringstream tmp;
2449 tmp << "Deleted " << num << " IPv6 lease(s) from subnet(s)" << ids.str()
2450 << " WARNING: lease6-wipe is deprecated!";
2452 : CONTROL_RESULT_EMPTY, tmp.str());
2453 setResponse(handle, response);
2454 } catch (const std::exception& ex) {
2456 .arg(cmd_args_ ? cmd_args_->str() : "<no args>")
2457 .arg(ex.what());
2459 setErrorResponse(handle, ex.what());
2460 return (1);
2461 }
2462
2464 .arg(cmd_args_ ? cmd_args_->str() : "<no args>");
2466 return (0);
2467}
2468
2471 Lease6Ptr lease6;
2472
2473 switch (parameters.query_type) {
2474 case Parameters::TYPE_ADDR: {
2475 // If address was specified explicitly, let's use it as is.
2476
2477 // Let's see if there's such a lease at all.
2478 lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type,
2479 parameters.addr);
2480 if (!lease6) {
2481 lease6.reset(new Lease6());
2482 lease6->addr_ = parameters.addr;
2483 }
2484 break;
2485 }
2487 isc_throw(InvalidParameter, "Delete by hw-address is not allowed in v6.");
2488 break;
2489 }
2490 case Parameters::TYPE_DUID: {
2491 if (!parameters.duid) {
2492 isc_throw(InvalidParameter, "Program error: Query by duid "
2493 "requires duid to be specified");
2494 }
2495
2496 // Let's see if there's such a lease at all.
2497 lease6 = LeaseMgrFactory::instance().getLease6(parameters.lease_type,
2498 *parameters.duid,
2499 parameters.iaid,
2500 parameters.subnet_id);
2501 break;
2502 }
2503 default:
2504 isc_throw(InvalidOperation, "Unknown query type: "
2505 << static_cast<int>(parameters.query_type));
2506 }
2507
2508 return (lease6);
2509}
2510
2513 short family) const {
2514 ConstElementPtr param = params->get(name);
2515 if (!param) {
2516 isc_throw(BadValue, "'" << name << "' parameter is missing.");
2517 }
2518
2519 if (param->getType() != Element::string) {
2520 isc_throw(BadValue, "'" << name << "' is not a string.");
2521 }
2522
2523 IOAddress addr(0);
2524 try {
2525 addr = IOAddress(param->stringValue());
2526 } catch (const std::exception& ex) {
2527 isc_throw(BadValue, "'" << param->stringValue()
2528 << "' is not a valid IP address.");
2529 }
2530
2531 if (addr.getFamily() != family) {
2532 isc_throw(BadValue, "Invalid "
2533 << (family == AF_INET6 ? "IPv6" : "IPv4")
2534 << " address specified: " << param->stringValue());
2535 }
2536
2537 return (addr);
2538}
2539
2540int
2542 std::stringstream ss;
2543 int resp_code = CONTROL_RESULT_ERROR;
2544
2545 try {
2546 extractCommand(handle);
2547
2548 // Get the target lease address. Invalid value will throw.
2549 IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET);
2550
2551 if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
2552 ss << "DDNS updating is not enabled";
2553 resp_code = CONTROL_RESULT_CONFLICT;
2554 } else {
2555 // Find the lease.
2557 if (!lease) {
2558 ss << "No lease found for: " << addr.toText();
2559 resp_code = CONTROL_RESULT_EMPTY;
2560 } else if (lease->hostname_.empty()) {
2561 ss << "Lease for: " << addr.toText()
2562 << ", has no hostname, nothing to update";
2563 resp_code = CONTROL_RESULT_CONFLICT;
2564 } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
2565 ss << "Neither forward nor reverse updates enabled for lease for: "
2566 << addr.toText();
2567 resp_code = CONTROL_RESULT_CONFLICT;
2568 } else {
2569 // We have a lease with a hostname and updates in at least
2570 // one direction enabled. Queue an NCR for it.
2571 queueNCR(CHG_ADD, lease);
2572 ss << "NCR generated for: " << addr.toText()
2573 << ", hostname: " << lease->hostname_;
2574 setSuccessResponse(handle, ss.str());
2576 return (0);
2577 }
2578 }
2579 } catch (const std::exception& ex) {
2580 ss << ex.what();
2581 }
2582
2584 setErrorResponse(handle, ss.str(), resp_code);
2585 return (resp_code == CONTROL_RESULT_EMPTY || resp_code == CONTROL_RESULT_CONFLICT ? 0 : 1);
2586}
2587
2588int
2590 std::stringstream ss;
2591 int resp_code = CONTROL_RESULT_ERROR;
2592
2593 try {
2594 extractCommand(handle);
2595
2596 // Get the target lease address. Invalid value will throw.
2597 IOAddress addr = getAddressParam(cmd_args_, "ip-address", AF_INET6);
2598
2599 if (!CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) {
2600 ss << "DDNS updating is not enabled";
2601 resp_code = CONTROL_RESULT_CONFLICT;
2602 } else {
2603 // Find the lease.
2605 if (!lease) {
2606 ss << "No lease found for: " << addr.toText();
2607 resp_code = CONTROL_RESULT_EMPTY;
2608 } else if (lease->hostname_.empty()) {
2609 ss << "Lease for: " << addr.toText()
2610 << ", has no hostname, nothing to update";
2611 resp_code = CONTROL_RESULT_CONFLICT;
2612 } else if (!lease->fqdn_fwd_ && !lease->fqdn_rev_) {
2613 ss << "Neither forward nor reverse updates enabled for lease for: "
2614 << addr.toText();
2615 resp_code = CONTROL_RESULT_CONFLICT;
2616 } else {
2617 // We have a lease with a hostname and updates in at least
2618 // one direction enabled. Queue an NCR for it.
2619 queueNCR(CHG_ADD, lease);
2620 ss << "NCR generated for: " << addr.toText()
2621 << ", hostname: " << lease->hostname_;
2622 setSuccessResponse(handle, ss.str());
2624 return (0);
2625 }
2626 }
2627 } catch (const std::exception& ex) {
2628 ss << ex.what();
2629 }
2630
2632 setErrorResponse(handle, ss.str(), resp_code);
2633 return (resp_code == CONTROL_RESULT_EMPTY ? 0 : 1);
2634}
2635
2638 const IOAddress& lease_address,
2639 const DuidPtr& duid,
2640 const int control_result,
2641 const std::string& error_message) const {
2642 auto failed_lease_map = Element::createMap();
2643 failed_lease_map->set("type", Element::create(Lease::typeToText(lease_type)));
2644
2645 if (!lease_address.isV6Zero()) {
2646 failed_lease_map->set("ip-address", Element::create(lease_address.toText()));
2647
2648 } else if (duid) {
2649 failed_lease_map->set("duid", Element::create(duid->toText()));
2650 }
2651
2652 // Associate the result with the lease.
2653 failed_lease_map->set("result", Element::create(control_result));
2654 failed_lease_map->set("error-message", Element::create(error_message));
2655
2656 return (failed_lease_map);
2657}
2658
2659int
2661 bool v4 = true;
2662 try {
2663 extractCommand(handle);
2664 v4 = (cmd_name_ == "lease4-write");
2665
2666 if (!cmd_args_) {
2667 isc_throw(isc::BadValue, "no parameters specified for the command");
2668 }
2669
2670 ConstElementPtr file = cmd_args_->get("filename");
2671 if (!file) {
2672 isc_throw(BadValue, "'filename' parameter not specified");
2673 }
2674 if (file->getType() != Element::string) {
2675 isc_throw(BadValue, "'filename' parameter must be a string");
2676 }
2677 string filename = file->stringValue();
2678 if (filename.empty()) {
2679 isc_throw(BadValue, "'filename' parameter is empty");
2680 }
2681
2682 if (v4) {
2684 } else {
2686 }
2687 ostringstream s;
2688 s << (v4 ? "IPv4" : "IPv6")
2689 << " lease database into '"
2690 << filename << "'.";
2692 setResponse(handle, response);
2693 } catch (const std::exception& ex) {
2694 setErrorResponse(handle, ex.what());
2695 return (CONTROL_RESULT_ERROR);
2696 }
2697
2698 return (0);
2699}
2700
2701int
2703 return (impl_->leaseAddHandler(handle));
2704}
2705
2706int
2708 return (impl_->lease6BulkApplyHandler(handle));
2709}
2710
2711int
2713 return (impl_->leaseGetHandler(handle));
2714}
2715
2716int
2718 return (impl_->leaseGetAllHandler(handle));
2719}
2720
2721int
2723 return (impl_->leaseGetPageHandler(handle));
2724}
2725
2726int
2728 return (impl_->leaseGetByHwAddressHandler(handle));
2729}
2730
2731int
2733 return (impl_->leaseGetByClientIdHandler(handle));
2734}
2735
2736int
2738 return (impl_->leaseGetByDuidHandler(handle));
2739}
2740
2741int
2743 return (impl_->leaseGetByHostnameHandler(handle));
2744}
2745
2746int
2748 return (impl_->lease4DelHandler(handle));
2749}
2750
2751int
2753 return (impl_->lease6DelHandler(handle));
2754}
2755
2756int
2758 return (impl_->lease4UpdateHandler(handle));
2759}
2760
2761int
2763 return (impl_->lease6UpdateHandler(handle));
2764}
2765
2766int
2769 return (impl_->lease4WipeHandler(handle));
2770}
2771
2772int
2775 return (impl_->lease6WipeHandler(handle));
2776}
2777
2778int
2780 return (impl_->lease4ResendDdnsHandler(handle));
2781}
2782
2783int
2785 return (impl_->lease6ResendDdnsHandler(handle));
2786}
2787
2788int
2790 return (impl_->leaseWriteHandler(handle));
2791}
2792
2794}
2795
2796} // end of namespace lease_cmds
2797} // end of namespace isc
Exception thrown when a command failed due to a conflict.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
Base class that command handler implementers may use for common tasks.
Definition cmds_impl.h:21
std::string cmd_name_
Stores the command name extracted by a call to extractCommand.
Definition cmds_impl.h:69
void setErrorResponse(hooks::CalloutHandle &handle, const std::string &text, int status=CONTROL_RESULT_ERROR)
Set the callout argument "response" to indicate an error.
Definition cmds_impl.h:54
data::ConstElementPtr cmd_args_
Stores the command arguments extracted by a call to extractCommand.
Definition cmds_impl.h:72
void extractCommand(hooks::CalloutHandle &handle)
Extracts the command name and arguments from a Callout handle.
Definition cmds_impl.h:29
void setSuccessResponse(hooks::CalloutHandle &handle, const std::string &text)
Set the callout argument "response" to indicate success.
Definition cmds_impl.h:43
void setResponse(hooks::CalloutHandle &handle, data::ConstElementPtr &response)
Set the callout argument "response" to the given response.
Definition cmds_impl.h:64
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:304
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:28
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:115
static ClientIdPtr fromText(const std::string &text)
Create client identifier from the textual format.
Definition duid.cc:73
Holds DUID (DHCPv6 Unique Identifier)
Definition duid.h:142
static DUID fromText(const std::string &text)
Create DUID from the textual format.
Definition duid.cc:50
static TrackingLeaseMgr & 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.
virtual size_t wipeLeases6(const SubnetID &subnet_id)=0
Virtual method which removes specified leases.
virtual Lease4Collection getLeases4(SubnetID subnet_id) const =0
Returns all IPv4 leases for the particular subnet identifier.
virtual void writeLeases6(const std::string &filename)=0
Write V6 leases to a file.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const =0
Returns an IPv4 lease for specified IPv4 address.
virtual bool addLease(const Lease4Ptr &lease)=0
Adds an IPv4 lease.
virtual size_t wipeLeases4(const SubnetID &subnet_id)=0
Virtual method which removes specified leases.
virtual void updateLease4(const Lease4Ptr &lease4)=0
Updates IPv4 lease.
virtual void writeLeases4(const std::string &filename)=0
Write V4 leases to a file.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
virtual void updateLease6(const Lease6Ptr &lease6)=0
Updates IPv6 lease.
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
Attempt to update lease that was not there.
Resource race avoidance RAII handler for DHCPv4.
bool tryLock4(const asiolink::IOAddress &addr)
Tries to acquires a resource.
Resource race avoidance RAII handler.
bool tryLock(Lease::Type type, const asiolink::IOAddress &addr)
Tries to acquires a resource.
Per-packet callout handle.
Parser for Lease4 structure.
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.
Parser for Lease6 structure.
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.
Parameters specified for lease commands.
Definition lease_cmds.cc:56
uint32_t iaid
IAID identifier used for v6 leases.
HWAddrPtr hwaddr
Specifies hardware address (used when query_type is TYPE_HWADDR)
Definition lease_cmds.cc:74
Lease::Type lease_type
Lease type (NA,TA or PD) used for v6 leases.
Type query_type
specifies parameter types
Type
specifies type of query (by IP addr, by hwaddr, by DUID)
Definition lease_cmds.cc:60
@ TYPE_CLIENT_ID
query by client identifier (v4 only).
Definition lease_cmds.cc:64
@ TYPE_HWADDR
query by hardware address (v4 only)
Definition lease_cmds.cc:62
@ TYPE_ADDR
query by IP address (either v4 or v6)
Definition lease_cmds.cc:61
isc::dhcp::ClientIdPtr client_id
Specifies identifier value (used when query_type is TYPE_CLIENT_ID)
Definition lease_cmds.cc:80
static Type txtToType(const std::string &txt)
Attempts to covert text to one of specified types.
Definition lease_cmds.cc:91
bool updateDDNS
Indicates whether or not DNS should be updated.
IOAddress addr
Specifies IPv4/v6 address (used when query_type is TYPE_ADDR)
Definition lease_cmds.cc:71
SubnetID subnet_id
Specifies subnet-id (always used)
Definition lease_cmds.cc:68
isc::dhcp::DuidPtr duid
Specifies identifier value (used when query_type is TYPE_DUID)
Definition lease_cmds.cc:77
Wrapper class around reservation command handlers.
Definition lease_cmds.cc:52
int lease4DelHandler(CalloutHandle &handle)
lease4-del command handler
IOAddress getAddressParam(ConstElementPtr params, const std::string name, short family=AF_INET) const
static void updateStatsOnUpdate(const Lease4Ptr &existing, const Lease4Ptr &lease)
Update stats when updating lease.
ElementPtr createFailedLeaseMap(const Lease::Type &lease_type, const IOAddress &lease_address, const DuidPtr &duid, const int control_result, const std::string &error_message) const
Returns a map holding brief information about a lease which failed to be deleted, updated or added.
static bool addOrUpdate6(Lease6Ptr lease, bool force_create)
Add or update lease.
int lease6BulkApplyHandler(CalloutHandle &handle)
lease6-bulk-apply command handler
int leaseGetByDuidHandler(hooks::CalloutHandle &handle)
lease6-get-by-duid command handler
int lease6UpdateHandler(CalloutHandle &handle)
lease6-update handler
int leaseGetPageHandler(hooks::CalloutHandle &handle)
lease4-get-page, lease6-get-page commands handler
Lease6Ptr getIPv6LeaseForDelete(const Parameters &parameters) const
Convenience function fetching IPv6 address to be used to delete a lease.
int leaseGetByHostnameHandler(hooks::CalloutHandle &handle)
lease4-get-by-hostname and lease6-get-by-hostname commands handler
int lease6DelHandler(CalloutHandle &handle)
lease6-del command handler
int leaseGetByHwAddressHandler(hooks::CalloutHandle &handle)
lease4-get-by-hw-address command handler
static ConstElementPtr getExtendedInfo6(const Lease6Ptr &lease)
Get DHCPv6 extended info.
int leaseGetHandler(CalloutHandle &handle)
lease4-get, lease6-get command handler
static bool addOrUpdate4(Lease4Ptr lease, bool force_create)
Add or update lease.
int lease6WipeHandler(CalloutHandle &handle)
lease6-wipe handler
int leaseGetByClientIdHandler(hooks::CalloutHandle &handle)
lease4-get-by-client-id command handler
int lease6ResendDdnsHandler(CalloutHandle &handle)
lease6-resend-ddns handler
int leaseAddHandler(CalloutHandle &handle)
lease4-add, lease6-add command handler
int lease4ResendDdnsHandler(CalloutHandle &handle)
lease4-resend-ddns handler
static void updateStatsOnAdd(const Lease4Ptr &lease)
Update stats when adding lease.
Parameters getParameters(bool v6, const ConstElementPtr &args)
Extracts parameters required for reservation-get and reservation-del.
int lease4UpdateHandler(CalloutHandle &handle)
lease4-update handler
int lease4WipeHandler(CalloutHandle &handle)
lease4-wipe handler
int leaseGetAllHandler(CalloutHandle &handle)
lease4-get-all, lease6-get-all commands handler
int leaseWriteHandler(CalloutHandle &handle)
lease4-write handler, lease6-write handler
static void updateStatsOnDelete(const Lease4Ptr &lease)
Update stats when deleting lease.
int lease4ResendDdnsHandler(hooks::CalloutHandle &handle)
lease4-resend-ddns command handler
int lease6WipeHandler(hooks::CalloutHandle &handle)
lease6-wipe handler
int leaseGetPageHandler(hooks::CalloutHandle &handle)
lease4-get-page, lease6-get-page commands handler
int lease6DelHandler(hooks::CalloutHandle &handle)
lease6-del command handler
int leaseGetAllHandler(hooks::CalloutHandle &handle)
lease4-get-all, lease6-get-all commands handler
int leaseGetByHostnameHandler(hooks::CalloutHandle &handle)
lease4-get-by-hostname and lease6-get-by-hostname commands handler
int lease4DelHandler(hooks::CalloutHandle &handle)
lease4-del command handler
int leaseWriteHandler(hooks::CalloutHandle &handle)
lease4-write handler, lease6-write handler
int leaseAddHandler(hooks::CalloutHandle &handle)
lease4-add, lease6-add command handler
int leaseGetByClientIdHandler(hooks::CalloutHandle &handle)
lease4-get-by-client-id command handler
int lease4UpdateHandler(hooks::CalloutHandle &handle)
lease4-update handler
int leaseGetHandler(hooks::CalloutHandle &handle)
lease4-get, lease6-get command handler
int leaseGetByHwAddressHandler(hooks::CalloutHandle &handle)
lease4-get-by-hw-address command handler
int lease6UpdateHandler(hooks::CalloutHandle &handle)
lease6-update handler
int leaseGetByDuidHandler(hooks::CalloutHandle &handle)
lease6-get-by-duid command handler
int lease6BulkApplyHandler(hooks::CalloutHandle &handle)
lease6-bulk-apply command handler
int lease4WipeHandler(hooks::CalloutHandle &handle)
lease4-wipe handler
int lease6ResendDdnsHandler(hooks::CalloutHandle &handle)
lease6-resend-ddns command handler
ObservationPtr getObservation(const std::string &name) const
Returns an observation.
static StatsMgr & instance()
Statistics Manager accessor method.
static std::string generateName(const std::string &context, Type index, const std::string &stat_name)
Generates statistic name in a given context.
RAII class creating a critical section.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void setValue(const std::string &name, const int64_t value)
Records absolute integer observation.
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
const isc::log::MessageID LEASE_CMDS_WIPE4_DEPRECATED
const isc::log::MessageID LEASE_CMDS_DEL4
const isc::log::MessageID LEASE_CMDS_WIPE4_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE4_FAILED
const isc::log::MessageID LEASE_CMDS_WIPE6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE6_CONFLICT
const isc::log::MessageID LEASE_CMDS_UPDATE4_CONFLICT
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4_FAILED
const isc::log::MessageID LEASE_CMDS_DEL6
const isc::log::MessageID LEASE_CMDS_ADD4_FAILED
const isc::log::MessageID LEASE_CMDS_WIPE6_DEPRECATED
const isc::log::MessageID LEASE_CMDS_ADD6
const isc::log::MessageID LEASE_CMDS_ADD4
const isc::log::MessageID LEASE_CMDS_WIPE6
const isc::log::MessageID LEASE_CMDS_ADD6_CONFLICT
const isc::log::MessageID LEASE_CMDS_BULK_APPLY6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE6
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS4
const isc::log::MessageID LEASE_CMDS_GET6_FAILED
const isc::log::MessageID LEASE_CMDS_WIPE4
const isc::log::MessageID LEASE_CMDS_BULK_APPLY6
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6_FAILED
const isc::log::MessageID LEASE_CMDS_RESEND_DDNS6
const isc::log::MessageID LEASE_CMDS_GET4_FAILED
const isc::log::MessageID LEASE_CMDS_ADD4_CONFLICT
const isc::log::MessageID LEASE_CMDS_DEL4_FAILED
const isc::log::MessageID LEASE_CMDS_ADD6_FAILED
const isc::log::MessageID LEASE_CMDS_UPDATE4
const isc::log::MessageID LEASE_CMDS_DEL6_FAILED
An abstract API for lease database.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_CONFLICT
Status code indicating that the command was unsuccessful due to a conflict between the command argume...
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
boost::shared_ptr< const SrvConfig > ConstSrvConfigPtr
Const pointer to the SrvConfig.
void queueNCR(const NameChangeType &chg_type, const Lease4Ptr &lease)
Creates name change request from the DHCPv4 lease.
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:623
boost::shared_ptr< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition subnet.h:458
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:508
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition lease.h:673
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
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition pool.h:485
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
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition duid.h:216
boost::shared_ptr< const CfgSubnets4 > ConstCfgSubnets4Ptr
Const pointer.
boost::shared_ptr< const CfgSubnets6 > ConstCfgSubnets6Ptr
Const pointer.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition lease.h:500
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:295
const int LEASE_CMDS_DBG_COMMAND_DATA
Logging level used to log successful commands.
isc::log::Logger lease_cmds_logger("lease-cmds-hooks")
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition hwaddr.h:20
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:69
Structure that holds a lease for IPv6 address and/or prefix.
Definition lease.h:516
@ ACTION_UPDATE
update extended info tables.
Definition lease.h:556
a common structure for IPv4 and IPv6 leases
Definition lease.h:31
Type
Type of lease or pool.
Definition lease.h:46
@ TYPE_TA
the lease contains temporary IPv6 address
Definition lease.h:48
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
@ TYPE_V4
IPv4 lease.
Definition lease.h:50
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
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:313
static std::string typeToText(Type type)
returns text representation of a lease type
Definition lease.cc:55