Kea 3.3.3
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 <dhcp/pkt4.h>
17#include <dhcp/pkt6.h>
18#include <dhcpsrv/cfgmgr.h>
19#include <dhcpsrv/host_mgr.h>
20#include <dhcpsrv/lease.h>
21#include <dhcpsrv/subnet.h>
22#include <hooks/hooks.h>
23#include <process/daemon.h>
24#include <radius/radius.h>
28#include <stats/stats_mgr.h>
30
31#include <sstream>
32#include <string>
33#include <vector>
34
35#include <radius_log.h>
36
37using namespace isc;
38using namespace isc::asiolink;
39using namespace isc::config;
40using namespace isc::data;
41using namespace isc::dhcp;
42using namespace isc::hooks;
43using namespace isc::process;
44using namespace isc::radius;
45using namespace isc::stats;
46using namespace isc::util;
47using namespace std;
48
49namespace {
50
55ElementPtr getConfig(LibraryHandle& handle) {
56 const vector<string> names = handle.getParameterNames();
57 const set<string> keywords = RadiusConfigParser::RADIUS_KEYWORDS;
59
60 for (auto const& name : names) {
61 if (keywords.count(name) == 0) {
62 isc_throw(BadValue, "unknown parameter: " << name);
63 }
64 ConstElementPtr value = handle.getParameter(name);
65 if (value) {
66 config->set(name, value);
67 }
68 }
69 return (config);
70}
71
78RadiusAuthHandlerPtr subnet4Select(CalloutHandle& handle,
79 ConstSubnet4Ptr subnet, Pkt4Ptr query) {
81 MultiThreadingLock lock(impl.auth_->requests4_.mutex_);
82
84 uint32_t subnet_id = subnet->getID();
85 uint32_t host_subnet_id =
86 (subnet->getReservationsGlobal() ? SUBNET_ID_GLOBAL : subnet_id);
87 vector<uint8_t> id;
88 string text;
89 if (!impl.auth_->getIdentifier(*query, id, text)) {
90 // What to do?
92 return (handler);
93 }
94
95 // Ask host cache.
96 ConstHostPtr host = HostMgr::instance().get4Any(host_subnet_id,
97 impl.id_type4_,
98 &id[0], id.size());
99 // Check cached subnet reselect.
100 if (host && host->getContext() &&
101 (host->getContext()->getType() == Element::map) &&
102 host->getContext()->contains("subnet-id")) {
103 try {
104 ConstElementPtr reselected = host->getContext()->get("subnet-id");
105 subnet_id = static_cast<uint32_t>(reselected->intValue());
108 .arg(subnet->getID())
109 .arg(subnet_id);
110 // Reselect to null.
111 if (subnet_id == SUBNET_ID_UNUSED) {
112 ConstSubnet4Ptr null_subnet;
113 handle.setArgument("subnet4", null_subnet);
114 return (handler);
115 }
116 // Reselect to an other subnet.
117 uint32_t new_host_subnet_id = host_subnet_id;
118 if (subnet_id != subnet->getID()) {
119 ConstSubnet4Ptr new_subnet =
121 getCfgSubnets4()->getSubnet(subnet_id);
122 if (!new_subnet) {
124 "can't find subnet with id: " << subnet_id);
125 }
126 new_host_subnet_id =
127 (new_subnet->getReservationsGlobal() ?
128 SUBNET_ID_GLOBAL : subnet_id);
129 handle.setArgument("subnet4", new_subnet);
130 }
131 // Get again host cache.
132 if (new_host_subnet_id != host_subnet_id) {
133 host = HostMgr::instance().get4Any(new_host_subnet_id,
134 impl.id_type4_,
135 &id[0], id.size());
136 }
137 } catch (const std::exception&) {
138 // Delete bad entry from cache.
139 HostPtr bad(new Host(*host));
140 static_cast<void>(impl.cache_->remove(bad));
142 return (handler);
143 }
144 }
145
146 // Check cached RADIUS response.
147 if (host && host->getContext() &&
148 (host->getContext()->getType() == Element::map)) {
149 // Yeah! We don't need to ask the Radius server.
150 Attributes attrs =
151 Attributes::fromElement(host->getContext()->get("radius"));
153 .arg(host->toText())
154 .arg(attrs.toText());
155 // 3 cases:
156 // - ip address (is in the host).
157 // - framed pool (put in the query).
158 // - class (todo).
159 if (!host->getIPv4Reservation().isV4Zero()) {
160 // Done!
161 return (handler);
162 }
163 ConstAttributePtr framed_pool = attrs.get(PW_FRAMED_POOL);
164 if (framed_pool && (framed_pool->getValueType() == PW_TYPE_STRING)) {
165 query->addClass(framed_pool->toString());
166 // Done!
167 return (handler);
168 }
169 // todo: class.
170 ConstAttributePtr class_ = attrs.get(PW_CLASS);
171 if (class_ && (class_->getValueType() == PW_TYPE_STRING)) {
172 // todo
173 return (handler);
174 }
175 return (handler);
176 }
177
178 // Get the pending request.
180 impl.auth_->requests4_.get(id);
181
182 // Conflict?
183 if (pending_request) {
185 .arg(query->getLabel())
186 .arg(text);
187 StatsMgr::instance().addValue("pkt4-duplicate",
188 static_cast<int64_t>(1));
189 StatsMgr::instance().addValue("pkt4-receive-drop",
190 static_cast<int64_t>(1));
192 return (handler);
193 }
194
195 // Too many pending requests.
196 size_t max_requests = impl.auth_->max_pending_requests_;
197 if (((max_requests > 0) &&
198 (impl.auth_->requests4_.size() >= max_requests)) ||
199 !impl.checkExchangeListRoom()) {
202 .arg(query->getLabel())
203 .arg(text);
204 StatsMgr::instance().addValue("pkt4-queue-full",
205 static_cast<int64_t>(1));
206 StatsMgr::instance().addValue("pkt4-receive-drop",
207 static_cast<int64_t>(1));
209 return (handler);
210 }
211
212 // Ask the Radius server.
213 handler = impl.auth_->buildAuth(*query, subnet_id, id, text);
214 if (!handler) {
215 // Error was logged.
216 StatsMgr::instance().addValue("pkt4-processing-failed",
217 static_cast<int64_t>(1));
218 StatsMgr::instance().addValue("pkt4-receive-drop",
219 static_cast<int64_t>(1));
221 return (handler);
222 }
223
224 // Create a new pending access request.
225 impl.auth_->requests4_.set(id, query);
226
227 return (handler);
228}
229
236RadiusAuthHandlerPtr subnet6Select(CalloutHandle& handle,
237 ConstSubnet6Ptr subnet, Pkt6Ptr query) {
239 MultiThreadingLock lock(impl.auth_->requests6_.mutex_);
240
241 RadiusAuthHandlerPtr handler;
242 uint32_t subnet_id = subnet->getID();
243 uint32_t host_subnet_id =
244 (subnet->getReservationsGlobal() ? SUBNET_ID_GLOBAL : subnet_id);
245 vector<uint8_t> id;
246 string text;
247 if (!impl.auth_->getIdentifier(*query, id, text)) {
248 // What to do?
250 return (handler);
251 }
252
253 // Ask host cache.
254 ConstHostPtr host = HostMgr::instance().get6Any(host_subnet_id,
255 impl.id_type6_,
256 &id[0], id.size());
257 // Check cached subnet reselect.
258 if (host && host->getContext() &&
259 (host->getContext()->getType() == Element::map) &&
260 host->getContext()->contains("subnet-id")) {
261 try {
262 ConstElementPtr reselected = host->getContext()->get("subnet-id");
263 subnet_id = static_cast<uint32_t>(reselected->intValue());
266 .arg(subnet->getID())
267 .arg(subnet_id);
268 // Reselect to null.
269 if (subnet_id == SUBNET_ID_UNUSED) {
270 ConstSubnet6Ptr null_subnet;
271 handle.setArgument("subnet6", null_subnet);
272 return (handler);
273 }
274 // Reselect to an other subnet.
275 uint32_t new_host_subnet_id = host_subnet_id;
276 if (subnet_id != subnet->getID()) {
277 ConstSubnet6Ptr new_subnet =
279 getCfgSubnets6()->getSubnet(subnet_id);
280 if (!new_subnet) {
282 "can't find subnet with id: " << subnet_id);
283 }
284 new_host_subnet_id =
285 (new_subnet->getReservationsGlobal() ?
286 SUBNET_ID_GLOBAL : subnet_id);
287 handle.setArgument("subnet6", new_subnet);
288 }
289 // Get again host cache.
290 if (new_host_subnet_id != host_subnet_id) {
291 host = HostMgr::instance().get6Any(new_host_subnet_id,
292 impl.id_type6_,
293 &id[0], id.size());
294 }
295 } catch (const std::exception&) {
296 // Delete bad entry from cache.
297 HostPtr bad(new Host(*host));
298 static_cast<void>(impl.cache_->remove(bad));
300 return (handler);
301 }
302 }
303
304 // Check cached RADIUS response.
305 if (host && host->getContext() &&
306 (host->getContext()->getType() == Element::map)) {
307 // Yeah! We don't need to ask the Radius server.
308 Attributes attrs =
309 Attributes::fromElement(host->getContext()->get("radius"));
311 .arg(host->toText())
312 .arg(attrs.toText());
313 // 4 cases:
314 // - ip address (is in the host).
315 // - delegated prefix (is in the host).
316 // - framed pool (put in the query).
317 // - class (todo).
318 if (host->hasIPv6Reservation()) {
319 // Done!
320 return (handler);
321 }
322 ConstAttributePtr framed_pool = attrs.get(PW_FRAMED_POOL);
323 if (framed_pool && (framed_pool->getValueType() == PW_TYPE_STRING)) {
324 query->addClass(framed_pool->toString());
325 // Done!
326 return (handler);
327 }
328 // todo: class.
329 ConstAttributePtr class_ = attrs.get(PW_CLASS);
330 if (class_ && (class_->getValueType() == PW_TYPE_STRING)) {
331 // todo
332 return (handler);
333 }
334 return (handler);
335 }
336
337 // Get the pending request.
339 impl.auth_->requests6_.get(id);
340
341 // Conflict?
342 if (pending_request) {
344 .arg(query->getLabel())
345 .arg(text);
346 StatsMgr::instance().addValue("pkt6-duplicate",
347 static_cast<int64_t>(1));
348 StatsMgr::instance().addValue("pkt6-receive-drop",
349 static_cast<int64_t>(1));
351 return (handler);
352 }
353
354 // Too many pending requests.
355 size_t max_requests = impl.auth_->max_pending_requests_;
356 if (((max_requests > 0) &&
357 (impl.auth_->requests6_.size() >= max_requests)) ||
358 !impl.checkExchangeListRoom()) {
361 .arg(query->getLabel())
362 .arg(text);
363 StatsMgr::instance().addValue("pkt6-queue-full",
364 static_cast<int64_t>(1));
365 StatsMgr::instance().addValue("pkt6-receive-drop",
366 static_cast<int64_t>(1));
368 return (handler);
369 }
370
371 // Ask the Radius server.
372 handler = impl.auth_->buildAuth(*query, subnet_id, id, text);
373 if (!handler) {
374 // Error was logged.
375 StatsMgr::instance().addValue("pkt6-processing-failed",
376 static_cast<int64_t>(1));
377 StatsMgr::instance().addValue("pkt6-receive-drop",
378 static_cast<int64_t>(1));
380 return (handler);
381 }
382
383 // Create a new pending access request.
384 impl.auth_->requests6_.set(id, query);
385
386 return (handler);
387}
388
389} // end of anonymous namespace
390
391extern "C" {
392
397int load(LibraryHandle& handle) {
398
399 try {
400 // Make the hook library not loadable by d2.
401 uint16_t family = CfgMgr::instance().getFamily();
402 const std::string& proc_name = Daemon::getProcName();
403 if (family == AF_INET) {
404 if (proc_name != "kea-dhcp4") {
405 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
406 << ", expected kea-dhcp4");
407 }
408 } else {
409 if (proc_name != "kea-dhcp6") {
410 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
411 << ", expected kea-dhcp6");
412 }
413 }
414
415 // Get and decode configuration.
416 ElementPtr config = getConfig(handle);
418 impl.init(config);
419 } catch (const std::exception& ex) {
421 .arg(ex.what());
422 return (CONTROL_RESULT_ERROR);
423 }
424
426 return (CONTROL_RESULT_SUCCESS);
427}
428
438
443 return (1);
444}
445
457
469
480 if (status == CalloutHandle::NEXT_STEP_DROP ||
482 return (0);
483 }
484
485 InHook in_hook;
487 if (!impl.serveAccess() || !impl.checkHostBackends()) {
488 return (CONTROL_RESULT_SUCCESS);
489 }
490 Pkt4Ptr query;
491 handle.getArgument("query4", query);
492 ConstSubnet4Ptr subnet;
493 handle.getArgument("subnet4", subnet);
494 if (!query || !subnet || (subnet->getID() == 0)) {
495 return (CONTROL_RESULT_SUCCESS);
496 }
497 ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
498 parking_lot->reference(query);
499 try {
500 RadiusAuthHandlerPtr handler = subnet4Select(handle, subnet, query);
501 if (!handler) {
502 parking_lot->dereference(query);
503 return (CONTROL_RESULT_SUCCESS);
504 }
505 handler->start();
507 } catch (...) {
508 parking_lot->dereference(query);
509 StatsMgr::instance().addValue("pkt4-processing-failed",
510 static_cast<int64_t>(1));
511 StatsMgr::instance().addValue("pkt4-receive-drop",
512 static_cast<int64_t>(1));
514 }
515
516 return (CONTROL_RESULT_SUCCESS);
517}
518
529 if (status == CalloutHandle::NEXT_STEP_DROP ||
531 return (CONTROL_RESULT_SUCCESS);
532 }
533
534 InHook in_hook;
536 if (!impl.serveAccess() || !impl.checkHostBackends()) {
537 return (CONTROL_RESULT_SUCCESS);
538 }
539 Pkt6Ptr query;
540 handle.getArgument("query6", query);
541 ConstSubnet6Ptr subnet;
542 handle.getArgument("subnet6", subnet);
543 if (!query || !subnet || (subnet->getID() == 0)) {
544 return (CONTROL_RESULT_SUCCESS);
545 }
546 ParkingLotHandlePtr parking_lot = handle.getParkingLotHandlePtr();
547 parking_lot->reference(query);
548 try {
549 RadiusAuthHandlerPtr handler = subnet6Select(handle, subnet, query);
550 if (!handler) {
551 parking_lot->dereference(query);
552 return (CONTROL_RESULT_SUCCESS);
553 }
554 handler->start();
556 } catch (...) {
557 parking_lot->dereference(query);
558 StatsMgr::instance().addValue("pkt6-processing-failed",
559 static_cast<int64_t>(1));
560 StatsMgr::instance().addValue("pkt6-receive-drop",
561 static_cast<int64_t>(1));
563 }
564
565 return (CONTROL_RESULT_SUCCESS);
566}
567
577 if (status == CalloutHandle::NEXT_STEP_DROP ||
579 return (0);
580 }
581
582 InHook in_hook;
584 if (!impl.serveAccounting() || !impl.getIOContext()) {
585 return (CONTROL_RESULT_SUCCESS);
586 }
587
588 bool fake_allocation = false;
589 handle.getArgument("fake_allocation", fake_allocation);
590 if (fake_allocation) {
591 // If this is a discover, there's nothing to do
592 return (CONTROL_RESULT_SUCCESS);
593 }
594
595 Lease4Ptr lease;
596 handle.getArgument("lease4", lease);
597 try {
598 // Start the Accounting-Request transmission.
599 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_CREATE);
600 if (!handler) {
601 return (CONTROL_RESULT_SUCCESS);
602 }
603 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
604 } catch (const std::exception& ex) {
606 .arg("lease4_select")
607 .arg(ex.what());
608 }
609 return (CONTROL_RESULT_SUCCESS);
610}
611
621 if (status == CalloutHandle::NEXT_STEP_DROP ||
623 return (0);
624 }
625
626 InHook in_hook;
628 if (!impl.serveAccounting() || !impl.getIOContext()) {
629 return (CONTROL_RESULT_SUCCESS);
630 }
631 Lease4Ptr lease;
632 handle.getArgument("lease4", lease);
633 // Do nothing on reuse.
634 if (!lease || (lease->reuseable_valid_lft_ > 0)) {
635 return (CONTROL_RESULT_SUCCESS);
636 }
637 try {
638 // Start the Accounting-Request transmission.
639 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RENEW);
640 if (!handler) {
641 return (CONTROL_RESULT_SUCCESS);
642 }
643 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
644 } catch (const std::exception& ex) {
646 .arg("lease4_renew")
647 .arg(ex.what());
648 }
649 return (CONTROL_RESULT_SUCCESS);
650}
651
661 if (status == CalloutHandle::NEXT_STEP_DROP ||
663 return (0);
664 }
665
666 InHook in_hook;
668 if (!impl.serveAccounting() || !impl.getIOContext()) {
669 return (CONTROL_RESULT_SUCCESS);
670 }
671 Lease4Ptr lease;
672 handle.getArgument("lease4", lease);
673 try {
674 // Start the Accounting-Request transmission.
675 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RELEASE);
676 if (!handler) {
677 return (CONTROL_RESULT_SUCCESS);
678 }
679 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
680 } catch (const std::exception& ex) {
682 .arg("lease4_release")
683 .arg(ex.what());
684 }
685 return (CONTROL_RESULT_SUCCESS);
686}
687
697 if (status == CalloutHandle::NEXT_STEP_DROP ||
699 return (0);
700 }
701
702 InHook in_hook;
704 if (!impl.serveAccounting() || !impl.getIOContext()) {
705 return (CONTROL_RESULT_SUCCESS);
706 }
707 Lease4Ptr lease;
708 handle.getArgument("lease4", lease);
709 try {
710 // Start the Accounting-Request transmission.
711 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_DECLINE);
712 if (!handler) {
713 return (CONTROL_RESULT_SUCCESS);
714 }
715 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
716 } catch (const std::exception& ex) {
718 .arg("lease4_decline")
719 .arg(ex.what());
720 }
721 return (CONTROL_RESULT_SUCCESS);
722}
723
730 if (status == CalloutHandle::NEXT_STEP_DROP ||
732 return (0);
733 }
734
735 InHook in_hook;
737 if (!impl.serveAccounting() || !impl.getIOContext()) {
738 return (CONTROL_RESULT_SUCCESS);
739 }
740 Lease4Ptr lease;
741 handle.getArgument("lease4", lease);
742 try {
743 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_EXPIRE);
744 if (!handler) {
745 return (CONTROL_RESULT_SUCCESS);
746 }
747 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
748 } catch (const std::exception& ex) {
750 .arg("lease4_expire")
751 .arg(ex.what());
752 }
753 return (CONTROL_RESULT_SUCCESS);
754}
755
762 if (status == CalloutHandle::NEXT_STEP_DROP ||
764 return (0);
765 }
766
767 InHook in_hook;
769 if (!impl.serveAccounting() || !impl.getIOContext()) {
770 return (CONTROL_RESULT_SUCCESS);
771 }
772 bool fake_allocation;
773 handle.getArgument("fake_allocation", fake_allocation);
774 if (fake_allocation) {
775 return (CONTROL_RESULT_SUCCESS);
776 }
777 Lease6Ptr lease;
778 handle.getArgument("lease6", lease);
779 try {
780 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_CREATE);
781 if (!handler) {
782 return (CONTROL_RESULT_SUCCESS);
783 }
784 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
785 } catch (const std::exception& ex) {
787 .arg("lease6_select")
788 .arg(ex.what());
789 }
790 return (CONTROL_RESULT_SUCCESS);
791}
792
799 if (status == CalloutHandle::NEXT_STEP_DROP ||
801 return (0);
802 }
803
804 InHook in_hook;
806 if (!impl.serveAccounting() || !impl.getIOContext()) {
807 return (CONTROL_RESULT_SUCCESS);
808 }
809 Lease6Ptr lease;
810 handle.getArgument("lease6", lease);
811 // Do nothing on reuse.
812 if (!lease || (lease->reuseable_valid_lft_ > 0)) {
813 return (CONTROL_RESULT_SUCCESS);
814 }
815 try {
816 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RENEW);
817 if (!handler) {
818 return (CONTROL_RESULT_SUCCESS);
819 }
820 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
821 } catch (const std::exception& ex) {
823 .arg("lease6_renew")
824 .arg(ex.what());
825 }
826 return (CONTROL_RESULT_SUCCESS);
827}
828
835 if (status == CalloutHandle::NEXT_STEP_DROP ||
837 return (0);
838 }
839
840 InHook in_hook;
842 if (!impl.serveAccounting() || !impl.getIOContext()) {
843 return (CONTROL_RESULT_SUCCESS);
844 }
845 Lease6Ptr lease;
846 handle.getArgument("lease6", lease);
847 // Do nothing on reuse.
848 if (!lease || (lease->reuseable_valid_lft_ > 0)) {
849 return (CONTROL_RESULT_SUCCESS);
850 }
851 try {
852 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_REBIND);
853 if (!handler) {
854 return (CONTROL_RESULT_SUCCESS);
855 }
856 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
857 } catch (const std::exception& ex) {
859 .arg("lease6_rebind")
860 .arg(ex.what());
861 }
862 return (CONTROL_RESULT_SUCCESS);
863}
864
871 if (status == CalloutHandle::NEXT_STEP_DROP ||
873 return (0);
874 }
875
876 InHook in_hook;
878 if (!impl.serveAccounting() || !impl.getIOContext()) {
879 return (CONTROL_RESULT_SUCCESS);
880 }
881 Lease6Ptr lease;
882 handle.getArgument("lease6", lease);
883 try {
884 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_RELEASE);
885 if (!handler) {
886 return (CONTROL_RESULT_SUCCESS);
887 }
888 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
889 } catch (const std::exception& ex) {
891 .arg("lease6_release")
892 .arg(ex.what());
893 }
894 return (CONTROL_RESULT_SUCCESS);
895}
896
903 if (status == CalloutHandle::NEXT_STEP_DROP ||
905 return (0);
906 }
907
908 InHook in_hook;
910 if (!impl.serveAccounting() || !impl.getIOContext()) {
911 return (CONTROL_RESULT_SUCCESS);
912 }
913 Lease6Ptr lease;
914 handle.getArgument("lease6", lease);
915 try {
916 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_DECLINE);
917 if (!handler) {
918 return (CONTROL_RESULT_SUCCESS);
919 }
920 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
921 } catch (const std::exception& ex) {
923 .arg("lease6_decline")
924 .arg(ex.what());
925 }
926 return (CONTROL_RESULT_SUCCESS);
927}
928
935 if (status == CalloutHandle::NEXT_STEP_DROP ||
937 return (0);
938 }
939
940 InHook in_hook;
942 if (!impl.serveAccounting() || !impl.getIOContext()) {
943 return (CONTROL_RESULT_SUCCESS);
944 }
945 Lease6Ptr lease;
946 handle.getArgument("lease6", lease);
947 try {
948 RadiusAcctHandlerPtr handler = impl.acct_->buildAcct(lease, EVENT_EXPIRE);
949 if (!handler) {
950 return (CONTROL_RESULT_SUCCESS);
951 }
952 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync, handler));
953 } catch (const std::exception& ex) {
955 .arg("lease6_expire")
956 .arg(ex.what());
957 }
958 return (CONTROL_RESULT_SUCCESS);
959}
960
969 InHook in_hook;
971 if (!impl.serveAccounting() || !impl.getIOContext()) {
972 return (CONTROL_RESULT_SUCCESS);
973 }
974 string name;
975 ConstElementPtr arguments;
976 ConstElementPtr response;
977 try {
978 handle.getArgument("name", name);
979 handle.getArgument("arguments", arguments);
980 handle.getArgument("response", response);
981 if (!arguments || !response) {
982 // "arguments" and "response" are required for all further actions.
983 // Stop here if they are not set.
984 return (CONTROL_RESULT_SUCCESS);
985 }
986
987 int result = SimpleParser::getInteger(response, "result");
988 if (result != 0) {
989 // Command has failed.
990 return (CONTROL_RESULT_SUCCESS);
991 }
992
993 // Handle peer updates?
994 const ConstElementPtr origin(arguments->get("origin"));
995 if (origin) {
996 // "origin" has a dynamic type. There are commands like ha-sync-complete-notify that set
997 // it to an integer. For simplicity, treat those cases like it is not coming from an HA
998 // partner for now and it will get filtered out by name further down below. We only care
999 // about lease updates.
1000 const bool is_from_ha_partner(origin->getType() == Element::string &&
1001 origin->stringValue() == "ha-partner");
1002 if (!impl.acct_->peer_updates_ && is_from_ha_partner) {
1003 return (CONTROL_RESULT_SUCCESS);
1004 }
1005 }
1006
1007 RadiusAcctHandlerPtr handler;
1008 if (name == "lease4-add") {
1009 handler = impl.acct_->buildAcct4(arguments, EVENT_ADD);
1010 } else if (name == "lease4-update") {
1011 handler = impl.acct_->buildAcct4(arguments, EVENT_UPDATE);
1012 } else if (name== "lease4-del") {
1013 handler = impl.acct_->buildAcct4(arguments, EVENT_DEL);
1014 } else if (name == "lease6-add") {
1015 handler = impl.acct_->buildAcct6(arguments, EVENT_ADD);
1016 } else if (name == "lease6-update") {
1017 handler = impl.acct_->buildAcct6(arguments, EVENT_UPDATE);
1018 } else if (name== "lease6-del") {
1019 handler = impl.acct_->buildAcct6(arguments, EVENT_DEL);
1020 }
1021 if (handler) {
1022 impl.getIOContext()->post(std::bind(&RadiusAccounting::runAsync,
1023 handler));
1024 }
1025 } catch (const std::exception& ex) {
1026 ostringstream ss;
1027 ss << "command_processed: " << name;
1029 .arg(ss.str())
1030 .arg(ex.what());
1031 }
1032 return (CONTROL_RESULT_SUCCESS);
1033}
1034
1035} // 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:330
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:301
void startServices()
Start the I/O mechanisms.
Definition radius.cc:333
static RadiusImpl & instance()
RadiusImpl is a singleton class.
Definition radius.cc:194
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:840
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:556
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition host.h:843
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:343
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.