Kea 3.3.1
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) &&
197 (impl.auth_->requests4_.size() >= max_requests)) ||
198 !impl.checkExchangeListRoom()) {
201 .arg(query->getLabel())
202 .arg(text);
203 StatsMgr::instance().addValue("pkt4-queue-full",
204 static_cast<int64_t>(1));
205 StatsMgr::instance().addValue("pkt4-receive-drop",
206 static_cast<int64_t>(1));
208 return (handler);
209 }
210
211 // Ask the Radius server.
212 handler = impl.auth_->buildAuth(*query, subnet_id, id, text);
213 if (!handler) {
214 // Error was logged.
215 StatsMgr::instance().addValue("pkt4-processing-failed",
216 static_cast<int64_t>(1));
217 StatsMgr::instance().addValue("pkt4-receive-drop",
218 static_cast<int64_t>(1));
220 return (handler);
221 }
222
223 // Create a new pending access request.
224 impl.auth_->requests4_.set(id, query);
225
226 return (handler);
227}
228
235RadiusAuthHandlerPtr subnet6Select(CalloutHandle& handle,
236 ConstSubnet6Ptr subnet, Pkt6Ptr query) {
238 MultiThreadingLock lock(impl.auth_->requests6_.mutex_);
239
240 RadiusAuthHandlerPtr handler;
241 uint32_t subnet_id = subnet->getID();
242 uint32_t host_subnet_id =
243 (subnet->getReservationsGlobal() ? SUBNET_ID_GLOBAL : subnet_id);
244 vector<uint8_t> id;
245 string text;
246 if (!impl.auth_->getIdentifier(*query, id, text)) {
247 // What to do?
249 return (handler);
250 }
251
252 // Ask host cache.
253 ConstHostPtr host = HostMgr::instance().get6Any(host_subnet_id,
254 impl.id_type6_,
255 &id[0], id.size());
256 // Check cached subnet reselect.
257 if (host && host->getContext() &&
258 (host->getContext()->getType() == Element::map) &&
259 host->getContext()->contains("subnet-id")) {
260 try {
261 ConstElementPtr reselected = host->getContext()->get("subnet-id");
262 subnet_id = static_cast<uint32_t>(reselected->intValue());
265 .arg(subnet->getID())
266 .arg(subnet_id);
267 // Reselect to null.
268 if (subnet_id == SUBNET_ID_UNUSED) {
269 ConstSubnet6Ptr null_subnet;
270 handle.setArgument("subnet6", null_subnet);
271 return (handler);
272 }
273 // Reselect to an other subnet.
274 uint32_t new_host_subnet_id = host_subnet_id;
275 if (subnet_id != subnet->getID()) {
276 ConstSubnet6Ptr new_subnet =
278 getCfgSubnets6()->getSubnet(subnet_id);
279 if (!new_subnet) {
281 "can't find subnet with id: " << subnet_id);
282 }
283 new_host_subnet_id =
284 (new_subnet->getReservationsGlobal() ?
285 SUBNET_ID_GLOBAL : subnet_id);
286 handle.setArgument("subnet6", new_subnet);
287 }
288 // Get again host cache.
289 if (new_host_subnet_id != host_subnet_id) {
290 host = HostMgr::instance().get6Any(new_host_subnet_id,
291 impl.id_type6_,
292 &id[0], id.size());
293 }
294 } catch (const std::exception&) {
295 // Delete bad entry from cache.
296 HostPtr bad(new Host(*host));
297 static_cast<void>(impl.cache_->remove(bad));
299 return (handler);
300 }
301 }
302
303 // Check cached RADIUS response.
304 if (host && host->getContext() &&
305 (host->getContext()->getType() == Element::map)) {
306 // Yeah! We don't need to ask the Radius server.
307 Attributes attrs =
308 Attributes::fromElement(host->getContext()->get("radius"));
310 .arg(host->toText())
311 .arg(attrs.toText());
312 // 4 cases:
313 // - ip address (is in the host).
314 // - delegated prefix (is in the host).
315 // - framed pool (put in the query).
316 // - class (todo).
317 if (host->hasIPv6Reservation()) {
318 // Done!
319 return (handler);
320 }
321 ConstAttributePtr framed_pool = attrs.get(PW_FRAMED_POOL);
322 if (framed_pool && (framed_pool->getValueType() == PW_TYPE_STRING)) {
323 query->addClass(framed_pool->toString());
324 // Done!
325 return (handler);
326 }
327 // todo: class.
328 ConstAttributePtr class_ = attrs.get(PW_CLASS);
329 if (class_ && (class_->getValueType() == PW_TYPE_STRING)) {
330 // todo
331 return (handler);
332 }
333 return (handler);
334 }
335
336 // Get the pending request.
338 impl.auth_->requests6_.get(id);
339
340 // Conflict?
341 if (pending_request) {
343 .arg(query->getLabel())
344 .arg(text);
345 StatsMgr::instance().addValue("pkt6-duplicate",
346 static_cast<int64_t>(1));
347 StatsMgr::instance().addValue("pkt6-receive-drop",
348 static_cast<int64_t>(1));
350 return (handler);
351 }
352
353 // Too many pending requests.
354 size_t max_requests = impl.auth_->max_pending_requests_;
355 if (((max_requests > 0) &&
356 (impl.auth_->requests6_.size() >= max_requests)) ||
357 !impl.checkExchangeListRoom()) {
360 .arg(query->getLabel())
361 .arg(text);
362 StatsMgr::instance().addValue("pkt6-queue-full",
363 static_cast<int64_t>(1));
364 StatsMgr::instance().addValue("pkt6-receive-drop",
365 static_cast<int64_t>(1));
367 return (handler);
368 }
369
370 // Ask the Radius server.
371 handler = impl.auth_->buildAuth(*query, subnet_id, id, text);
372 if (!handler) {
373 // Error was logged.
374 StatsMgr::instance().addValue("pkt6-processing-failed",
375 static_cast<int64_t>(1));
376 StatsMgr::instance().addValue("pkt6-receive-drop",
377 static_cast<int64_t>(1));
379 return (handler);
380 }
381
382 // Create a new pending access request.
383 impl.auth_->requests6_.set(id, query);
384
385 return (handler);
386}
387
388} // end of anonymous namespace
389
390extern "C" {
391
396int load(LibraryHandle& handle) {
397
398 try {
399 // Make the hook library not loadable by d2.
400 uint16_t family = CfgMgr::instance().getFamily();
401 const std::string& proc_name = Daemon::getProcName();
402 if (family == AF_INET) {
403 if (proc_name != "kea-dhcp4") {
404 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
405 << ", expected kea-dhcp4");
406 }
407 } else {
408 if (proc_name != "kea-dhcp6") {
409 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
410 << ", expected kea-dhcp6");
411 }
412 }
413
414 // Get and decode configuration.
415 ElementPtr config = getConfig(handle);
417 impl.init(config);
418 } catch (const std::exception& ex) {
420 .arg(ex.what());
421 return (CONTROL_RESULT_ERROR);
422 }
423
425 return (CONTROL_RESULT_SUCCESS);
426}
427
437
442 return (1);
443}
444
456
468
479 if (status == CalloutHandle::NEXT_STEP_DROP ||
481 return (0);
482 }
483
484 InHook in_hook;
486 if (!impl.serveAccess() || !impl.checkHostBackends()) {
487 return (CONTROL_RESULT_SUCCESS);
488 }
489 Pkt4Ptr query;
490 handle.getArgument("query4", query);
491 ConstSubnet4Ptr subnet;
492 handle.getArgument("subnet4", subnet);
493 if (!query || !subnet || (subnet->getID() == 0)) {
494 return (CONTROL_RESULT_SUCCESS);
495 }
496 ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
497 parking_lot->reference(query);
498 try {
499 RadiusAuthHandlerPtr handler = subnet4Select(handle, subnet, query);
500 if (!handler) {
501 parking_lot->dereference(query);
502 return (CONTROL_RESULT_SUCCESS);
503 }
504 handler->start();
506 } catch (...) {
507 parking_lot->dereference(query);
508 StatsMgr::instance().addValue("pkt4-processing-failed",
509 static_cast<int64_t>(1));
510 StatsMgr::instance().addValue("pkt4-receive-drop",
511 static_cast<int64_t>(1));
513 }
514
515 return (CONTROL_RESULT_SUCCESS);
516}
517
528 if (status == CalloutHandle::NEXT_STEP_DROP ||
530 return (CONTROL_RESULT_SUCCESS);
531 }
532
533 InHook in_hook;
535 if (!impl.serveAccess() || !impl.checkHostBackends()) {
536 return (CONTROL_RESULT_SUCCESS);
537 }
538 Pkt6Ptr query;
539 handle.getArgument("query6", query);
540 ConstSubnet6Ptr subnet;
541 handle.getArgument("subnet6", subnet);
542 if (!query || !subnet || (subnet->getID() == 0)) {
543 return (CONTROL_RESULT_SUCCESS);
544 }
545 ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
546 parking_lot->reference(query);
547 try {
548 RadiusAuthHandlerPtr handler = subnet6Select(handle, subnet, query);
549 if (!handler) {
550 parking_lot->dereference(query);
551 return (CONTROL_RESULT_SUCCESS);
552 }
553 handler->start();
555 } catch (...) {
556 parking_lot->dereference(query);
557 StatsMgr::instance().addValue("pkt6-processing-failed",
558 static_cast<int64_t>(1));
559 StatsMgr::instance().addValue("pkt6-receive-drop",
560 static_cast<int64_t>(1));
562 }
563
564 return (CONTROL_RESULT_SUCCESS);
565}
566
576 if (status == CalloutHandle::NEXT_STEP_DROP ||
578 return (0);
579 }
580
581 InHook in_hook;
583 if (!impl.serveAccounting() || !impl.getIOContext()) {
584 return (CONTROL_RESULT_SUCCESS);
585 }
586
587 bool fake_allocation = false;
588 handle.getArgument("fake_allocation", fake_allocation);
589 if (fake_allocation) {
590 // If this is a discover, there's nothing to do
591 return (CONTROL_RESULT_SUCCESS);
592 }
593
594 Lease4Ptr lease;
595 handle.getArgument("lease4", lease);
596 try {
597 // Start the Accounting-Request transmission.
598 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_CREATE);
599 if (!handler) {
600 return (CONTROL_RESULT_SUCCESS);
601 }
602 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
603 } catch (const std::exception& ex) {
605 .arg("lease4_select")
606 .arg(ex.what());
607 }
608 return (CONTROL_RESULT_SUCCESS);
609}
610
620 if (status == CalloutHandle::NEXT_STEP_DROP ||
622 return (0);
623 }
624
625 InHook in_hook;
627 if (!impl.serveAccounting() || !impl.getIOContext()) {
628 return (CONTROL_RESULT_SUCCESS);
629 }
630 Lease4Ptr lease;
631 handle.getArgument("lease4", lease);
632 // Do nothing on reuse.
633 if (!lease || (lease->reuseable_valid_lft_ > 0)) {
634 return (CONTROL_RESULT_SUCCESS);
635 }
636 try {
637 // Start the Accounting-Request transmission.
638 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RENEW);
639 if (!handler) {
640 return (CONTROL_RESULT_SUCCESS);
641 }
642 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
643 } catch (const std::exception& ex) {
645 .arg("lease4_renew")
646 .arg(ex.what());
647 }
648 return (CONTROL_RESULT_SUCCESS);
649}
650
660 if (status == CalloutHandle::NEXT_STEP_DROP ||
662 return (0);
663 }
664
665 InHook in_hook;
667 if (!impl.serveAccounting() || !impl.getIOContext()) {
668 return (CONTROL_RESULT_SUCCESS);
669 }
670 Lease4Ptr lease;
671 handle.getArgument("lease4", lease);
672 try {
673 // Start the Accounting-Request transmission.
674 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RELEASE);
675 if (!handler) {
676 return (CONTROL_RESULT_SUCCESS);
677 }
678 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
679 } catch (const std::exception& ex) {
681 .arg("lease4_release")
682 .arg(ex.what());
683 }
684 return (CONTROL_RESULT_SUCCESS);
685}
686
696 if (status == CalloutHandle::NEXT_STEP_DROP ||
698 return (0);
699 }
700
701 InHook in_hook;
703 if (!impl.serveAccounting() || !impl.getIOContext()) {
704 return (CONTROL_RESULT_SUCCESS);
705 }
706 Lease4Ptr lease;
707 handle.getArgument("lease4", lease);
708 try {
709 // Start the Accounting-Request transmission.
710 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_DECLINE);
711 if (!handler) {
712 return (CONTROL_RESULT_SUCCESS);
713 }
714 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
715 } catch (const std::exception& ex) {
717 .arg("lease4_decline")
718 .arg(ex.what());
719 }
720 return (CONTROL_RESULT_SUCCESS);
721}
722
729 if (status == CalloutHandle::NEXT_STEP_DROP ||
731 return (0);
732 }
733
734 InHook in_hook;
736 if (!impl.serveAccounting() || !impl.getIOContext()) {
737 return (CONTROL_RESULT_SUCCESS);
738 }
739 Lease4Ptr lease;
740 handle.getArgument("lease4", lease);
741 try {
742 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_EXPIRE);
743 if (!handler) {
744 return (CONTROL_RESULT_SUCCESS);
745 }
746 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
747 } catch (const std::exception& ex) {
749 .arg("lease4_expire")
750 .arg(ex.what());
751 }
752 return (CONTROL_RESULT_SUCCESS);
753}
754
761 if (status == CalloutHandle::NEXT_STEP_DROP ||
763 return (0);
764 }
765
766 InHook in_hook;
768 if (!impl.serveAccounting() || !impl.getIOContext()) {
769 return (CONTROL_RESULT_SUCCESS);
770 }
771 bool fake_allocation;
772 handle.getArgument("fake_allocation", fake_allocation);
773 if (fake_allocation) {
774 return (CONTROL_RESULT_SUCCESS);
775 }
776 Lease6Ptr lease;
777 handle.getArgument("lease6", lease);
778 try {
779 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_CREATE);
780 if (!handler) {
781 return (CONTROL_RESULT_SUCCESS);
782 }
783 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
784 } catch (const std::exception& ex) {
786 .arg("lease6_select")
787 .arg(ex.what());
788 }
789 return (CONTROL_RESULT_SUCCESS);
790}
791
798 if (status == CalloutHandle::NEXT_STEP_DROP ||
800 return (0);
801 }
802
803 InHook in_hook;
805 if (!impl.serveAccounting() || !impl.getIOContext()) {
806 return (CONTROL_RESULT_SUCCESS);
807 }
808 Lease6Ptr lease;
809 handle.getArgument("lease6", lease);
810 // Do nothing on reuse.
811 if (!lease || (lease->reuseable_valid_lft_ > 0)) {
812 return (CONTROL_RESULT_SUCCESS);
813 }
814 try {
815 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RENEW);
816 if (!handler) {
817 return (CONTROL_RESULT_SUCCESS);
818 }
819 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
820 } catch (const std::exception& ex) {
822 .arg("lease6_renew")
823 .arg(ex.what());
824 }
825 return (CONTROL_RESULT_SUCCESS);
826}
827
834 if (status == CalloutHandle::NEXT_STEP_DROP ||
836 return (0);
837 }
838
839 InHook in_hook;
841 if (!impl.serveAccounting() || !impl.getIOContext()) {
842 return (CONTROL_RESULT_SUCCESS);
843 }
844 Lease6Ptr lease;
845 handle.getArgument("lease6", lease);
846 // Do nothing on reuse.
847 if (!lease || (lease->reuseable_valid_lft_ > 0)) {
848 return (CONTROL_RESULT_SUCCESS);
849 }
850 try {
851 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_REBIND);
852 if (!handler) {
853 return (CONTROL_RESULT_SUCCESS);
854 }
855 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
856 } catch (const std::exception& ex) {
858 .arg("lease6_rebind")
859 .arg(ex.what());
860 }
861 return (CONTROL_RESULT_SUCCESS);
862}
863
870 if (status == CalloutHandle::NEXT_STEP_DROP ||
872 return (0);
873 }
874
875 InHook in_hook;
877 if (!impl.serveAccounting() || !impl.getIOContext()) {
878 return (CONTROL_RESULT_SUCCESS);
879 }
880 Lease6Ptr lease;
881 handle.getArgument("lease6", lease);
882 try {
883 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RELEASE);
884 if (!handler) {
885 return (CONTROL_RESULT_SUCCESS);
886 }
887 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
888 } catch (const std::exception& ex) {
890 .arg("lease6_release")
891 .arg(ex.what());
892 }
893 return (CONTROL_RESULT_SUCCESS);
894}
895
902 if (status == CalloutHandle::NEXT_STEP_DROP ||
904 return (0);
905 }
906
907 InHook in_hook;
909 if (!impl.serveAccounting() || !impl.getIOContext()) {
910 return (CONTROL_RESULT_SUCCESS);
911 }
912 Lease6Ptr lease;
913 handle.getArgument("lease6", lease);
914 try {
915 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_DECLINE);
916 if (!handler) {
917 return (CONTROL_RESULT_SUCCESS);
918 }
919 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
920 } catch (const std::exception& ex) {
922 .arg("lease6_decline")
923 .arg(ex.what());
924 }
925 return (CONTROL_RESULT_SUCCESS);
926}
927
934 if (status == CalloutHandle::NEXT_STEP_DROP ||
936 return (0);
937 }
938
939 InHook in_hook;
941 if (!impl.serveAccounting() || !impl.getIOContext()) {
942 return (CONTROL_RESULT_SUCCESS);
943 }
944 Lease6Ptr lease;
945 handle.getArgument("lease6", lease);
946 try {
947 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_EXPIRE);
948 if (!handler) {
949 return (CONTROL_RESULT_SUCCESS);
950 }
951 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
952 } catch (const std::exception& ex) {
954 .arg("lease6_expire")
955 .arg(ex.what());
956 }
957 return (CONTROL_RESULT_SUCCESS);
958}
959
968 InHook in_hook;
970 if (!impl.serveAccounting() || !impl.getIOContext()) {
971 return (CONTROL_RESULT_SUCCESS);
972 }
973 string name;
974 ConstElementPtr arguments;
975 ConstElementPtr response;
976 try {
977 handle.getArgument("name", name);
978 handle.getArgument("arguments", arguments);
979 handle.getArgument("response", response);
980 if (!arguments || !response) {
981 // "arguments" and "response" are required for all further actions.
982 // Stop here if they are not set.
983 return (CONTROL_RESULT_SUCCESS);
984 }
985
986 int result = SimpleParser::getInteger(response, "result");
987 if (result != 0) {
988 // Command has failed.
989 return (CONTROL_RESULT_SUCCESS);
990 }
991
992 // Handle peer updates?
993 const ConstElementPtr origin(arguments->get("origin"));
994 if (origin) {
995 // "origin" has a dynamic type. There are commands like ha-sync-complete-notify that set
996 // it to an integer. For simplicity, treat those cases like it is not coming from an HA
997 // partner for now and it will get filtered out by name further down below. We only care
998 // about lease updates.
999 const bool is_from_ha_partner(origin->getType() == Element::string &&
1000 origin->stringValue() == "ha-partner");
1001 if (!impl.acct_->peer_updates_ && is_from_ha_partner) {
1002 return (CONTROL_RESULT_SUCCESS);
1003 }
1004 }
1005
1006 RadiusAcctHandlerPtr handler;
1007 if (name == "lease4-add") {
1008 handler = impl.acct_->buildAcct4(arguments, EVENT_ADD);
1009 } else if (name == "lease4-update") {
1010 handler = impl.acct_->buildAcct4(arguments, EVENT_UPDATE);
1011 } else if (name== "lease4-del") {
1012 handler = impl.acct_->buildAcct4(arguments, EVENT_DEL);
1013 } else if (name == "lease6-add") {
1014 handler = impl.acct_->buildAcct6(arguments, EVENT_ADD);
1015 } else if (name == "lease6-update") {
1016 handler = impl.acct_->buildAcct6(arguments, EVENT_UPDATE);
1017 } else if (name== "lease6-del") {
1018 handler = impl.acct_->buildAcct6(arguments, EVENT_DEL);
1019 }
1020 if (handler) {
1021 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync,
1022 handler));
1023 }
1024 } catch (const std::exception& ex) {
1025 ostringstream ss;
1026 ss << "command_processed: " << name;
1028 .arg(ss.str())
1029 .arg(ex.what());
1030 }
1031 return (CONTROL_RESULT_SUCCESS);
1032}
1033
1034} // 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:355
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:156
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:380
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:151
void reset()
Reset the state as it was just created.
Definition radius.cc:299
void startServices()
Start the I/O mechanisms.
Definition radius.cc:331
static RadiusImpl & instance()
RadiusImpl is a singleton class.
Definition radius.cc:192
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:620
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:455
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.
const isc::log::MessageID RADIUS_ACCESS_CONFLICT
const isc::log::MessageID RADIUS_ACCESS_MAX_PENDING_REQUESTS
boost::shared_ptr< const Attribute > ConstAttributePtr
boost::shared_ptr< RadiusAuthPendingRequest< PktPtrType > > RadiusAuthPendingRequestPtr
Pointer to a pending Radius access request.
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.