Kea 3.1.8
radius_callout.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2026 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// Functions accessed by the hooks framework use C linkage to avoid the name
8// mangling that accompanies use of the C++ compiler as well as to avoid
9// issues related to namespaces.
10
11#include <config.h>
12
15#include <cc/simple_parser.h>
16#include <hooks/hooks.h>
17#include <dhcp/pkt4.h>
18#include <dhcp/pkt6.h>
19#include <dhcpsrv/lease.h>
20#include <dhcpsrv/subnet.h>
21#include <radius.h>
22#include <dhcpsrv/cfgmgr.h>
23#include <dhcpsrv/host_mgr.h>
24#include <process/daemon.h>
25#include <stats/stats_mgr.h>
26#include <radius_log.h>
27#include <radius_parsers.h>
28#include <radius_access.h>
29#include <radius_accounting.h>
31
32#include <string>
33#include <sstream>
34#include <vector>
35
36using namespace isc;
37using namespace isc::asiolink;
38using namespace isc::config;
39using namespace isc::data;
40using namespace isc::dhcp;
41using namespace isc::hooks;
42using namespace isc::process;
43using namespace isc::radius;
44using namespace isc::stats;
45using namespace isc::util;
46using namespace std;
47
48namespace {
49
54ElementPtr getConfig(LibraryHandle& handle) {
55 const vector<string> names = handle.getParameterNames();
56 const set<string> keywords = RadiusConfigParser::RADIUS_KEYWORDS;
58
59 for (auto const& name : names) {
60 if (keywords.count(name) == 0) {
61 isc_throw(BadValue, "unknown parameter: " << name);
62 }
63 ConstElementPtr value = handle.getParameter(name);
64 if (value) {
65 config->set(name, value);
66 }
67 }
68 return (config);
69}
70
77RadiusAuthHandlerPtr subnet4Select(CalloutHandle& handle,
78 ConstSubnet4Ptr subnet, Pkt4Ptr query) {
80 MultiThreadingLock lock(impl.auth_->requests4_.mutex_);
81
83 uint32_t subnet_id = subnet->getID();
84 uint32_t host_subnet_id =
85 (subnet->getReservationsGlobal() ? SUBNET_ID_GLOBAL : subnet_id);
86 vector<uint8_t> id;
87 string text;
88 if (!impl.auth_->getIdentifier(*query, id, text)) {
89 // What to do?
91 return (handler);
92 }
93
94 // Ask host cache.
95 ConstHostPtr host = HostMgr::instance().get4Any(host_subnet_id,
96 impl.id_type4_,
97 &id[0], id.size());
98 // Check cached subnet reselect.
99 if (host && host->getContext() &&
100 (host->getContext()->getType() == Element::map) &&
101 host->getContext()->contains("subnet-id")) {
102 try {
103 ConstElementPtr reselected = host->getContext()->get("subnet-id");
104 subnet_id = static_cast<uint32_t>(reselected->intValue());
107 .arg(subnet->getID())
108 .arg(subnet_id);
109 // Reselect to null.
110 if (subnet_id == SUBNET_ID_UNUSED) {
111 ConstSubnet4Ptr null_subnet;
112 handle.setArgument("subnet4", null_subnet);
113 return (handler);
114 }
115 // Reselect to an other subnet.
116 uint32_t new_host_subnet_id = host_subnet_id;
117 if (subnet_id != subnet->getID()) {
118 ConstSubnet4Ptr new_subnet =
120 getCfgSubnets4()->getSubnet(subnet_id);
121 if (!new_subnet) {
123 "can't find subnet with id: " << subnet_id);
124 }
125 new_host_subnet_id =
126 (new_subnet->getReservationsGlobal() ?
127 SUBNET_ID_GLOBAL : subnet_id);
128 handle.setArgument("subnet4", new_subnet);
129 }
130 // Get again host cache.
131 if (new_host_subnet_id != host_subnet_id) {
132 host = HostMgr::instance().get4Any(new_host_subnet_id,
133 impl.id_type4_,
134 &id[0], id.size());
135 }
136 } catch (const std::exception&) {
137 // Delete bad entry from cache.
138 HostPtr bad(new Host(*host));
139 static_cast<void>(impl.cache_->remove(bad));
141 return (handler);
142 }
143 }
144
145 // Check cached RADIUS response.
146 if (host && host->getContext() &&
147 (host->getContext()->getType() == Element::map)) {
148 // Yeah! We don't need to ask the Radius server.
149 Attributes attrs =
150 Attributes::fromElement(host->getContext()->get("radius"));
152 .arg(host->toText())
153 .arg(attrs.toText());
154 // 3 cases:
155 // - ip address (is in the host).
156 // - framed pool (put in the query).
157 // - class (todo).
158 if (!host->getIPv4Reservation().isV4Zero()) {
159 // Done!
160 return (handler);
161 }
162 ConstAttributePtr framed_pool = attrs.get(PW_FRAMED_POOL);
163 if (framed_pool && (framed_pool->getValueType() == PW_TYPE_STRING)) {
164 query->addClass(framed_pool->toString());
165 // Done!
166 return (handler);
167 }
168 // todo: class.
169 ConstAttributePtr class_ = attrs.get(PW_CLASS);
170 if (class_ && (class_->getValueType() == PW_TYPE_STRING)) {
171 // todo
172 return (handler);
173 }
174 return (handler);
175 }
176
177 // Get the pending request.
179 impl.auth_->requests4_.get(id);
180
181 // Conflict?
182 if (pending_request) {
184 .arg(query->getLabel())
185 .arg(text);
186 StatsMgr::instance().addValue("pkt4-duplicate",
187 static_cast<int64_t>(1));
188 StatsMgr::instance().addValue("pkt4-receive-drop",
189 static_cast<int64_t>(1));
191 return (handler);
192 }
193
194 // Too many pending requests.
195 size_t max_requests = impl.auth_->max_pending_requests_;
196 if ((max_requests > 0) && (impl.auth_->requests4_.size() >= max_requests)) {
199 .arg(query->getLabel())
200 .arg(text);
201 StatsMgr::instance().addValue("pkt4-queue-full",
202 static_cast<int64_t>(1));
203 StatsMgr::instance().addValue("pkt4-receive-drop",
204 static_cast<int64_t>(1));
206 return (handler);
207 }
208
209 // Ask the Radius server.
210 handler = impl.auth_->buildAuth(*query, subnet_id, id, text);
211 if (!handler) {
212 // Error was logged.
213 StatsMgr::instance().addValue("pkt4-processing-failed",
214 static_cast<int64_t>(1));
215 StatsMgr::instance().addValue("pkt4-receive-drop",
216 static_cast<int64_t>(1));
218 return (handler);
219 }
220
221 // Create a new pending access request.
222 impl.auth_->requests4_.set(id, query);
223
224 return (handler);
225}
226
233RadiusAuthHandlerPtr subnet6Select(CalloutHandle& handle,
234 ConstSubnet6Ptr subnet, Pkt6Ptr query) {
236 MultiThreadingLock lock(impl.auth_->requests6_.mutex_);
237
238 RadiusAuthHandlerPtr handler;
239 uint32_t subnet_id = subnet->getID();
240 uint32_t host_subnet_id =
241 (subnet->getReservationsGlobal() ? SUBNET_ID_GLOBAL : subnet_id);
242 vector<uint8_t> id;
243 string text;
244 if (!impl.auth_->getIdentifier(*query, id, text)) {
245 // What to do?
247 return (handler);
248 }
249
250 // Ask host cache.
251 ConstHostPtr host = HostMgr::instance().get6Any(host_subnet_id,
252 impl.id_type6_,
253 &id[0], id.size());
254 // Check cached subnet reselect.
255 if (host && host->getContext() &&
256 (host->getContext()->getType() == Element::map) &&
257 host->getContext()->contains("subnet-id")) {
258 try {
259 ConstElementPtr reselected = host->getContext()->get("subnet-id");
260 subnet_id = static_cast<uint32_t>(reselected->intValue());
263 .arg(subnet->getID())
264 .arg(subnet_id);
265 // Reselect to null.
266 if (subnet_id == SUBNET_ID_UNUSED) {
267 ConstSubnet6Ptr null_subnet;
268 handle.setArgument("subnet6", null_subnet);
269 return (handler);
270 }
271 // Reselect to an other subnet.
272 uint32_t new_host_subnet_id = host_subnet_id;
273 if (subnet_id != subnet->getID()) {
274 ConstSubnet6Ptr new_subnet =
276 getCfgSubnets6()->getSubnet(subnet_id);
277 if (!new_subnet) {
279 "can't find subnet with id: " << subnet_id);
280 }
281 new_host_subnet_id =
282 (new_subnet->getReservationsGlobal() ?
283 SUBNET_ID_GLOBAL : subnet_id);
284 handle.setArgument("subnet6", new_subnet);
285 }
286 // Get again host cache.
287 if (new_host_subnet_id != host_subnet_id) {
288 host = HostMgr::instance().get6Any(new_host_subnet_id,
289 impl.id_type6_,
290 &id[0], id.size());
291 }
292 } catch (const std::exception&) {
293 // Delete bad entry from cache.
294 HostPtr bad(new Host(*host));
295 static_cast<void>(impl.cache_->remove(bad));
297 return (handler);
298 }
299 }
300
301 // Check cached RADIUS response.
302 if (host && host->getContext() &&
303 (host->getContext()->getType() == Element::map)) {
304 // Yeah! We don't need to ask the Radius server.
305 Attributes attrs =
306 Attributes::fromElement(host->getContext()->get("radius"));
308 .arg(host->toText())
309 .arg(attrs.toText());
310 // 4 cases:
311 // - ip address (is in the host).
312 // - delegated prefix (is in the host).
313 // - framed pool (put in the query).
314 // - class (todo).
315 if (host->hasIPv6Reservation()) {
316 // Done!
317 return (handler);
318 }
319 ConstAttributePtr framed_pool = attrs.get(PW_FRAMED_POOL);
320 if (framed_pool && (framed_pool->getValueType() == PW_TYPE_STRING)) {
321 query->addClass(framed_pool->toString());
322 // Done!
323 return (handler);
324 }
325 // todo: class.
326 ConstAttributePtr class_ = attrs.get(PW_CLASS);
327 if (class_ && (class_->getValueType() == PW_TYPE_STRING)) {
328 // todo
329 return (handler);
330 }
331 return (handler);
332 }
333
334 // Get the pending request.
336 impl.auth_->requests6_.get(id);
337
338 // Conflict?
339 if (pending_request) {
341 .arg(query->getLabel())
342 .arg(text);
343 StatsMgr::instance().addValue("pkt6-duplicate",
344 static_cast<int64_t>(1));
345 StatsMgr::instance().addValue("pkt6-receive-drop",
346 static_cast<int64_t>(1));
348 return (handler);
349 }
350
351 // Too many pending requests.
352 size_t max_requests = impl.auth_->max_pending_requests_;
353 if ((max_requests > 0) && (impl.auth_->requests6_.size() >= max_requests)) {
356 .arg(query->getLabel())
357 .arg(text);
358 StatsMgr::instance().addValue("pkt6-queue-full",
359 static_cast<int64_t>(1));
360 StatsMgr::instance().addValue("pkt6-receive-drop",
361 static_cast<int64_t>(1));
363 return (handler);
364 }
365
366 // Ask the Radius server.
367 handler = impl.auth_->buildAuth(*query, subnet_id, id, text);
368 if (!handler) {
369 // Error was logged.
370 StatsMgr::instance().addValue("pkt6-processing-failed",
371 static_cast<int64_t>(1));
372 StatsMgr::instance().addValue("pkt6-receive-drop",
373 static_cast<int64_t>(1));
375 return (handler);
376 }
377
378 // Create a new pending access request.
379 impl.auth_->requests6_.set(id, query);
380
381 return (handler);
382}
383
384} // end of anonymous namespace
385
386extern "C" {
387
392int load(LibraryHandle& handle) {
393
394 try {
395 // Make the hook library not loadable by d2 or ca.
396 uint16_t family = CfgMgr::instance().getFamily();
397 const std::string& proc_name = Daemon::getProcName();
398 if (family == AF_INET) {
399 if (proc_name != "kea-dhcp4") {
400 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
401 << ", expected kea-dhcp4");
402 }
403 } else {
404 if (proc_name != "kea-dhcp6") {
405 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
406 << ", expected kea-dhcp6");
407 }
408 }
409
410 // Get and decode configuration.
411 ElementPtr config = getConfig(handle);
413 impl.init(config);
414 } catch (const std::exception& ex) {
416 .arg(ex.what());
417 return (CONTROL_RESULT_ERROR);
418 }
419
421 return (CONTROL_RESULT_SUCCESS);
422}
423
433
438 return (1);
439}
440
452
464
475 if (status == CalloutHandle::NEXT_STEP_DROP ||
477 return (0);
478 }
479
480 InHook in_hook;
482 if (!impl.serveAccess() || !impl.checkHostBackends()) {
483 return (CONTROL_RESULT_SUCCESS);
484 }
485 Pkt4Ptr query;
486 handle.getArgument("query4", query);
487 ConstSubnet4Ptr subnet;
488 handle.getArgument("subnet4", subnet);
489 if (!query || !subnet || (subnet->getID() == 0)) {
490 return (CONTROL_RESULT_SUCCESS);
491 }
492 ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
493 parking_lot->reference(query);
494 try {
495 RadiusAuthHandlerPtr handler = subnet4Select(handle, subnet, query);
496 if (!handler) {
497 parking_lot->dereference(query);
498 return (CONTROL_RESULT_SUCCESS);
499 }
500 handler->start();
502 } catch (...) {
503 parking_lot->dereference(query);
504 StatsMgr::instance().addValue("pkt4-processing-failed",
505 static_cast<int64_t>(1));
506 StatsMgr::instance().addValue("pkt4-receive-drop",
507 static_cast<int64_t>(1));
509 }
510
511 return (CONTROL_RESULT_SUCCESS);
512}
513
524 if (status == CalloutHandle::NEXT_STEP_DROP ||
526 return (CONTROL_RESULT_SUCCESS);
527 }
528
529 InHook in_hook;
531 if (!impl.serveAccess() || !impl.checkHostBackends()) {
532 return (CONTROL_RESULT_SUCCESS);
533 }
534 Pkt6Ptr query;
535 handle.getArgument("query6", query);
536 ConstSubnet6Ptr subnet;
537 handle.getArgument("subnet6", subnet);
538 if (!query || !subnet || (subnet->getID() == 0)) {
539 return (CONTROL_RESULT_SUCCESS);
540 }
541 ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
542 parking_lot->reference(query);
543 try {
544 RadiusAuthHandlerPtr handler = subnet6Select(handle, subnet, query);
545 if (!handler) {
546 parking_lot->dereference(query);
547 return (CONTROL_RESULT_SUCCESS);
548 }
549 handler->start();
551 } catch (...) {
552 parking_lot->dereference(query);
553 StatsMgr::instance().addValue("pkt6-processing-failed",
554 static_cast<int64_t>(1));
555 StatsMgr::instance().addValue("pkt6-receive-drop",
556 static_cast<int64_t>(1));
558 }
559
560 return (CONTROL_RESULT_SUCCESS);
561}
562
572 if (status == CalloutHandle::NEXT_STEP_DROP ||
574 return (0);
575 }
576
577 InHook in_hook;
579 if (!impl.serveAccounting() || !impl.getIOContext()) {
580 return (CONTROL_RESULT_SUCCESS);
581 }
582
583 bool fake_allocation = false;
584 handle.getArgument("fake_allocation", fake_allocation);
585 if (fake_allocation) {
586 // If this is a discover, there's nothing to do
587 return (CONTROL_RESULT_SUCCESS);
588 }
589
590 Lease4Ptr lease;
591 handle.getArgument("lease4", lease);
592 try {
593 // Start the Accounting-Request transmission.
594 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_CREATE);
595 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
596 } catch (const std::exception& ex) {
598 .arg("lease4_select")
599 .arg(ex.what());
600 }
601 return (CONTROL_RESULT_SUCCESS);
602}
603
613 if (status == CalloutHandle::NEXT_STEP_DROP ||
615 return (0);
616 }
617
618 InHook in_hook;
620 if (!impl.serveAccounting() || !impl.getIOContext()) {
621 return (CONTROL_RESULT_SUCCESS);
622 }
623 Lease4Ptr lease;
624 handle.getArgument("lease4", lease);
625 try {
626 // Start the Accounting-Request transmission.
627 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RENEW);
628 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
629 } catch (const std::exception& ex) {
631 .arg("lease4_renew")
632 .arg(ex.what());
633 }
634 return (CONTROL_RESULT_SUCCESS);
635}
636
646 if (status == CalloutHandle::NEXT_STEP_DROP ||
648 return (0);
649 }
650
651 InHook in_hook;
653 if (!impl.serveAccounting() || !impl.getIOContext()) {
654 return (CONTROL_RESULT_SUCCESS);
655 }
656 Lease4Ptr lease;
657 handle.getArgument("lease4", lease);
658 try {
659 // Start the Accounting-Request transmission.
660 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RELEASE);
661 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
662 } catch (const std::exception& ex) {
664 .arg("lease4_release")
665 .arg(ex.what());
666 }
667 return (CONTROL_RESULT_SUCCESS);
668}
669
679 if (status == CalloutHandle::NEXT_STEP_DROP ||
681 return (0);
682 }
683
684 InHook in_hook;
686 if (!impl.serveAccounting() || !impl.getIOContext()) {
687 return (CONTROL_RESULT_SUCCESS);
688 }
689 Lease4Ptr lease;
690 handle.getArgument("lease4", lease);
691 try {
692 // Start the Accounting-Request transmission.
693 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_DECLINE);
694 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
695 } catch (const std::exception& ex) {
697 .arg("lease4_decline")
698 .arg(ex.what());
699 }
700 return (CONTROL_RESULT_SUCCESS);
701}
702
709 if (status == CalloutHandle::NEXT_STEP_DROP ||
711 return (0);
712 }
713
714 InHook in_hook;
716 if (!impl.serveAccounting() || !impl.getIOContext()) {
717 return (CONTROL_RESULT_SUCCESS);
718 }
719 Lease4Ptr lease;
720 handle.getArgument("lease4", lease);
721 try {
722 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_EXPIRE);
723 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
724 } catch (const std::exception& ex) {
726 .arg("lease4_expire")
727 .arg(ex.what());
728 }
729 return (CONTROL_RESULT_SUCCESS);
730}
731
738 if (status == CalloutHandle::NEXT_STEP_DROP ||
740 return (0);
741 }
742
743 InHook in_hook;
745 if (!impl.serveAccounting() || !impl.getIOContext()) {
746 return (CONTROL_RESULT_SUCCESS);
747 }
748 bool fake_allocation;
749 handle.getArgument("fake_allocation", fake_allocation);
750 if (fake_allocation) {
751 return (CONTROL_RESULT_SUCCESS);
752 }
753 Lease6Ptr lease;
754 handle.getArgument("lease6", lease);
755 try {
756 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_CREATE);
757 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
758 } catch (const std::exception& ex) {
760 .arg("lease6_select")
761 .arg(ex.what());
762 }
763 return (CONTROL_RESULT_SUCCESS);
764}
765
772 if (status == CalloutHandle::NEXT_STEP_DROP ||
774 return (0);
775 }
776
777 InHook in_hook;
779 if (!impl.serveAccounting() || !impl.getIOContext()) {
780 return (CONTROL_RESULT_SUCCESS);
781 }
782 Lease6Ptr lease;
783 handle.getArgument("lease6", lease);
784 try {
785 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RENEW);
786 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
787 } catch (const std::exception& ex) {
789 .arg("lease6_renew")
790 .arg(ex.what());
791 }
792 return (CONTROL_RESULT_SUCCESS);
793}
794
801 if (status == CalloutHandle::NEXT_STEP_DROP ||
803 return (0);
804 }
805
806 InHook in_hook;
808 if (!impl.serveAccounting() || !impl.getIOContext()) {
809 return (CONTROL_RESULT_SUCCESS);
810 }
811 Lease6Ptr lease;
812 handle.getArgument("lease6", lease);
813 try {
814 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_REBIND);
815 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
816 } catch (const std::exception& ex) {
818 .arg("lease6_rebind")
819 .arg(ex.what());
820 }
821 return (CONTROL_RESULT_SUCCESS);
822}
823
830 if (status == CalloutHandle::NEXT_STEP_DROP ||
832 return (0);
833 }
834
835 InHook in_hook;
837 if (!impl.serveAccounting() || !impl.getIOContext()) {
838 return (CONTROL_RESULT_SUCCESS);
839 }
840 Lease6Ptr lease;
841 handle.getArgument("lease6", lease);
842 try {
843 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RELEASE);
844 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
845 } catch (const std::exception& ex) {
847 .arg("lease6_release")
848 .arg(ex.what());
849 }
850 return (CONTROL_RESULT_SUCCESS);
851}
852
859 if (status == CalloutHandle::NEXT_STEP_DROP ||
861 return (0);
862 }
863
864 InHook in_hook;
866 if (!impl.serveAccounting() || !impl.getIOContext()) {
867 return (CONTROL_RESULT_SUCCESS);
868 }
869 Lease6Ptr lease;
870 handle.getArgument("lease6", lease);
871 try {
872 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_DECLINE);
873 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
874 } catch (const std::exception& ex) {
876 .arg("lease6_decline")
877 .arg(ex.what());
878 }
879 return (CONTROL_RESULT_SUCCESS);
880}
881
888 if (status == CalloutHandle::NEXT_STEP_DROP ||
890 return (0);
891 }
892
893 InHook in_hook;
895 if (!impl.serveAccounting() || !impl.getIOContext()) {
896 return (CONTROL_RESULT_SUCCESS);
897 }
898 Lease6Ptr lease;
899 handle.getArgument("lease6", lease);
900 try {
901 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_EXPIRE);
902 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
903 } catch (const std::exception& ex) {
905 .arg("lease6_expire")
906 .arg(ex.what());
907 }
908 return (CONTROL_RESULT_SUCCESS);
909}
910
919 InHook in_hook;
921 if (!impl.serveAccounting() || !impl.getIOContext()) {
922 return (CONTROL_RESULT_SUCCESS);
923 }
924 string name;
925 ConstElementPtr arguments;
926 ConstElementPtr response;
927 try {
928 handle.getArgument("name", name);
929 handle.getArgument("arguments", arguments);
930 handle.getArgument("response", response);
931 if (!arguments || !response) {
932 // "arguments" and "response" are required for all further actions.
933 // Stop here if they are not set.
934 return (CONTROL_RESULT_SUCCESS);
935 }
936
937 int result = SimpleParser::getInteger(response, "result");
938 if (result != 0) {
939 // Command has failed.
940 return (CONTROL_RESULT_SUCCESS);
941 }
942
943 // Handle peer updates?
944 const ConstElementPtr origin(arguments->get("origin"));
945 if (origin) {
946 // "origin" has a dynamic type. There are commands like ha-sync-complete-notify that set
947 // it to an integer. For simplicity, treat those cases like it is not coming from an HA
948 // partner for now and it will get filtered out by name further down below. We only care
949 // about lease updates.
950 const bool is_from_ha_partner(origin->getType() == Element::string &&
951 origin->stringValue() == "ha-partner");
952 if (!impl.acct_->peer_updates_ && is_from_ha_partner) {
953 return (CONTROL_RESULT_SUCCESS);
954 }
955 }
956
957 RadiusAcctHandlerPtr handler;
958 if (name == "lease4-add") {
959 handler = impl.acct_->buildAcct4(arguments, EVENT_ADD);
960 } else if (name == "lease4-update") {
961 handler = impl.acct_->buildAcct4(arguments, EVENT_UPDATE);
962 } else if (name== "lease4-del") {
963 handler = impl.acct_->buildAcct4(arguments, EVENT_DEL);
964 } else if (name == "lease6-add") {
965 handler = impl.acct_->buildAcct6(arguments, EVENT_ADD);
966 } else if (name == "lease6-update") {
967 handler = impl.acct_->buildAcct6(arguments, EVENT_UPDATE);
968 } else if (name== "lease6-del") {
969 handler = impl.acct_->buildAcct6(arguments, EVENT_DEL);
970 }
971 if (handler) {
972 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync,
973 handler));
974 }
975 } catch (const std::exception& ex) {
976 ostringstream ss;
977 ss << "command_processed: " << name;
979 .arg(ss.str())
980 .arg(ex.what());
981 }
982 return (CONTROL_RESULT_SUCCESS);
983}
984
985} // end extern "C"
CalloutNextStep
Specifies allowed next steps.
@ NEXT_STEP_PARK
park the packet
@ NEXT_STEP_DROP
drop the packet
@ NEXT_STEP_SKIP
skip the next processing step
@ map
Definition data.h:160
@ string
Definition data.h:157
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition data.cc:354
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
uint16_t getFamily() const
Returns address family.
Definition cfgmgr.h:246
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
ConstHostPtr get6Any(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, const HostMgrOperationTarget target) const
Returns any host connected to the IPv6 subnet.
Definition host_mgr.cc:590
ConstHostPtr get4Any(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, const HostMgrOperationTarget target) const
Returns any host connected to the IPv4 subnet.
Definition host_mgr.cc:401
static HostMgr & instance()
Returns a sole instance of the HostMgr.
Definition host_mgr.cc:114
Represents a device with IPv4 and/or IPv6 reservations.
Definition host.h:327
Per-packet callout handle.
ParkingLotHandlePtr getParkingLotHandlePtr() const
Returns pointer to the parking lot handle for this hook point.
CalloutNextStep getStatus() const
Returns the next processing step.
void setStatus(const CalloutNextStep next)
Sets the next processing step.
void getArgument(const std::string &name, T &value) const
Get argument.
void setArgument(const std::string &name, T value)
Set argument.
isc::data::ConstElementPtr getParameter(const std::string &name)
Returns configuration parameter for the library.
std::vector< std::string > getParameterNames()
Returns names of configuration parameters for the library.
static std::string getProcName()
returns the process name This value is used as when forming the default PID file name
Definition daemon.cc:154
Collection of attributes.
std::string toText(size_t indent=0) const
Returns text representation of the collection.
ConstAttributePtr get(const uint8_t type) const
Get instance of the attribute in the collection.
static Attributes fromElement(const data::ConstElementPtr &attr_list)
Parse collection.
InHook class (RAII style).
Definition radius.h:365
static void runAsync(RadiusAcctHandlerPtr handler)
Run asynchronously.
static const std::set< std::string > RADIUS_KEYWORDS
Keywords (aka global configuration entry names).
Radius hooks library implementation.
Definition radius.h:142
void reset()
Reset the state as it was just created.
Definition radius.cc:263
void startServices()
Start the I/O mechanisms.
Definition radius.cc:295
static RadiusImpl & instance()
RadiusImpl is a singleton class.
Definition radius.cc:163
static StatsMgr & instance()
Statistics Manager accessor method.
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 addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
#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_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
boost::shared_ptr< Element > ElementPtr
Definition data.h:29
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:623
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
Definition host.h:837
boost::shared_ptr< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition subnet.h:458
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:528
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition host.h:840
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:315
GssTsigImplPtr impl
The GSS-TSIG hook implementation object.
boost::shared_ptr< ParkingLotHandle > ParkingLotHandlePtr
Pointer to the parking lot handle.
boost::shared_ptr< RadiusAcctHandler > RadiusAcctHandlerPtr
Type of pointers to Radius accounting communication handler.
boost::shared_ptr< RadiusAuthPendingRequest< PktPtrType > > RadiusAuthPendingRequestPtr
Pointer to a pending Radius access request.
const isc::log::MessageID RADIUS_ACCESS_CONFLICT
const isc::log::MessageID RADIUS_ACCESS_MAX_PENDING_REQUESTS
boost::shared_ptr< const Attribute > ConstAttributePtr
const isc::log::MessageID RADIUS_INIT_OK
const isc::log::MessageID RADIUS_DEINIT_OK
const int RADIUS_DBG_TRACE
Radius logging levels.
Definition radius_log.h:26
const isc::log::MessageID RADIUS_ACCESS_CACHE_GET
boost::shared_ptr< RadiusAuthHandler > RadiusAuthHandlerPtr
Type of pointers to Radius access communication handler.
isc::log::Logger radius_logger("radius-hooks")
Radius Logger.
Definition radius_log.h:35
const isc::log::MessageID RADIUS_ACCESS_SUBNET_RESELECT
const isc::log::MessageID RADIUS_CONFIGURATION_FAILED
const isc::log::MessageID RADIUS_HOOK_FAILED
Defines the logger used by the top-level component of kea-lfc.
int subnet4_select(CalloutHandle &handle)
This callout tries to retrieve host information from cache.
int lease4_release(CalloutHandle &handle)
This callout is called at the "lease4_release" hook.
int lease4_decline(CalloutHandle &handle)
This callout is called at the "lease4_decline" hook.
int dhcp6_srv_configured(CalloutHandle &)
This function is called by the DHCPv6 server when it is configured.
int dhcp4_srv_configured(CalloutHandle &)
This function is called by the DHCPv4 server when it is configured.
int lease6_release(CalloutHandle &handle)
This callout is called at the "lease6_release" hook.
int command_processed(CalloutHandle &handle)
This callout is called at the "command_processed" hook point.
int lease6_rebind(CalloutHandle &handle)
This callout is called at the "lease6_rebind" hook.
int multi_threading_compatible()
This function is called to retrieve the multi-threading compatibility.
int lease4_renew(CalloutHandle &handle)
This callout is called at the "lease4_renew" hook.
int subnet6_select(CalloutHandle &handle)
This callout tries to retrieve host information from cache.
int lease4_select(CalloutHandle &handle)
This callout is called at the "lease4_select" hook.
int unload()
This function is called when the library is unloaded.
int lease6_expire(CalloutHandle &handle)
This callout is called at the "lease6_expire" hook.
int lease4_expire(CalloutHandle &handle)
This callout is called at the "lease4_expire" hook.
int lease6_select(CalloutHandle &handle)
This callout is called at the "lease6_select" hook.
int load(LibraryHandle &handle)
This function is called when the library is loaded.
int lease6_decline(CalloutHandle &handle)
This callout is called at the "lease6_decline" hook.
int lease6_renew(CalloutHandle &handle)
This callout is called at the "lease6_renew" hook.
RAII lock object to protect the code in the same scope with a mutex.