Kea 3.1.9
client_exchange.cc
Go to the documentation of this file.
1// Copyright (C) 2023-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#include <config.h>
8
10#include <asiolink/io_service.h>
12#include <asiolink/udp_socket.h>
15#include <util/unlock_guard.h>
16#include <client_exchange.h>
17#include <radius.h>
18#include <radius_log.h>
19
20#include <cerrno>
21#include <chrono>
22#include <limits>
23#include <sstream>
24
25using namespace isc;
26using namespace isc::asiolink;
27using namespace isc::data;
28using namespace isc::tcp;
29using namespace isc::util;
30using namespace std;
31using namespace std::chrono;
32namespace ph = std::placeholders;
33
34namespace isc {
35namespace radius {
36
37string
38exchangeRCtoText(const int rc) {
39 ostringstream result;
40 switch (rc) {
41 case BADRESP_RC:
42 return ("bad response");
43 case ERROR_RC:
44 return ("error");
45 case OK_RC:
46 return ("ok");
47 case TIMEOUT_RC:
48 return ("timeout");
49 case REJECT_RC:
50 return ("reject");
51 case READBLOCK_RC:
52 return ("temporarily unavailable");
53 default:
54 result << (rc < 0 ? "error " : "unknown ") << rc;
55 return (result.str());
56 }
57}
58
60 unsigned maxretries,
61 const Servers& servers,
62 Handler handler)
63 : identifier_(""), sync_(false), rc_(ERROR_RC),
64 request_(request), sent_(), received_(),
65 maxretries_(maxretries), servers_(servers), handler_(handler) {
66 if (!request) {
67 isc_throw(BadValue, "null request");
68 }
69 if (servers.empty()) {
70 isc_throw(BadValue, "no server");
71 }
72 if (!handler) {
73 isc_throw(BadValue, "null handler");
74 }
76}
77
79 unsigned maxretries,
80 const Servers& servers)
81 : identifier_(""), sync_(true), rc_(ERROR_RC),
82 request_(request), sent_(), received_(),
83 maxretries_(maxretries), servers_(servers), handler_() {
84 if (!request) {
85 isc_throw(BadValue, "null request");
86 }
87 if (servers.empty()) {
88 isc_throw(BadValue, "no server");
89 }
91}
92
95 const MessagePtr& request,
96 unsigned maxretries,
97 const Servers& servers,
98 Handler handler,
99 RadiusProtocol protocol) {
100 if (protocol == PW_PROTO_UDP) {
101 return (UdpExchangePtr(new UdpExchange(io_service, request, maxretries,
102 servers, handler)));
103 } else {
104 return (TcpExchangePtr(new TcpExchange(request, maxretries,
105 servers, handler)));
106 }
107}
108
111 unsigned maxretries,
112 const Servers& servers) {
113 return (UdpExchangePtr(new UdpExchange(request, maxretries, servers)));
114}
115
117 const MessagePtr& request,
118 unsigned maxretries,
119 const Servers& servers,
120 Handler handler)
121 : Exchange(request, maxretries, servers, handler),
122 io_service_(io_service), started_(false), terminated_(false),
123 start_time_(std::chrono::steady_clock().now()),
124 socket_(), ep_(), timer_(), server_(), idx_(0),
125 buffer_(), size_(0), retries_(0), postponed_(),
126 mutex_(new std::mutex()) {
127 if (!io_service) {
128 isc_throw(BadValue, "null IO service");
129 }
130}
131
133 unsigned maxretries,
134 const Servers& servers)
135 : Exchange(request, maxretries, servers),
136 io_service_(new IOService()),
137 started_(false), terminated_(false),
138 start_time_(std::chrono::steady_clock().now()),
139 socket_(), ep_(), timer_(), server_(), idx_(0),
140 buffer_(), size_(0), retries_(0), postponed_(),
141 mutex_(new std::mutex()) {
142}
143
147 timer_.reset();
148 socket_.reset();
149 if (sync_ && io_service_) {
150 // As a best practice, call any remaining handlers.
151 io_service_->stopAndPoll();
152 io_service_.reset();
153 }
154}
155
156void
158 vector<uint8_t> rv = cryptolink::random(sizeof(uint32_t));
159 if (rv.size() != sizeof(uint32_t)) {
160 isc_throw(Unexpected, "random failed");
161 }
162 uint32_t ri;
163 memmove(&ri, &rv[0], sizeof(uint32_t));
164 ostringstream rs;
165 rs << hex << setfill('0') << setw(8) << ri;
166 identifier_ = rs.str();
167}
168void
170 if (!received_) {
171 return;
172 }
173 const AttributesPtr& attrs = received_->getAttributes();
174 if (!attrs || (attrs->count(PW_REPLY_MESSAGE) == 0)) {
175 return;
176 }
177 for (const ConstAttributePtr& attr : *attrs) {
178 if (!attr || (attr->getType() != PW_REPLY_MESSAGE)) {
179 continue;
180 }
182 .arg(static_cast<int>(received_->getIdentifier()))
183 .arg(identifier_)
184 .arg(attr->toString());
185 }
186}
187
188void
191
192 if (started_) {
193 return;
194 } else {
195 started_ = true;
196 }
198 .arg(identifier_);
199
200 open();
201
202 if (sync_) {
203 // Run() will return when syncHandler will be called.
204 io_service_->run();
205
206 // Done.
207 io_service_.reset();
208
211 .arg(identifier_)
212 .arg(rc_);
213 }
214}
215
216void
218 // Avoid multiple terminations.
221}
222
223void
225 if (terminated_) {
226 return;
227 } else {
228 terminated_ = true;
229 }
230 // Same as terminate but not calling callback.
231 cancelTimer();
232 if (socket_) {
233 socket_->cancel();
234 }
235 handler_ = Handler();
236
237 if (io_service_) {
238 if (sync_) {
239 io_service_->stopWork();
240 } else {
241 io_service_.reset();
242 }
243 }
244}
245
246void
248 std::chrono::steady_clock::time_point start_time) {
249 if (!server) {
250 isc_throw(Unexpected, "no server");
251 }
252
253 // Prepare message to send.
254 sent_.reset(new Message(*request_));
255
256 // Randomize the identifier.
257 sent_->randomIdentifier();
258
259 // Randomize or zero the authenticator.
260 if ((sent_->getCode() == PW_ACCESS_REQUEST) ||
261 (sent_->getCode() == PW_STATUS_SERVER)) {
262 sent_->randomAuth();
263 } else {
264 sent_->zeroAuth();
265 }
266
267 // Set the secret.
268 sent_->setSecret(server->getSecret());
269
270 // Get attributes.
271 AttributesPtr attrs = sent_->getAttributes();
272 if (!attrs) {
273 attrs.reset(new Attributes());
274 sent_->setAttributes(attrs);
275 }
276
277 // Add Acct-Delay-Time to Accounting-Request message.
278 if ((sent_->getCode() == PW_ACCOUNTING_REQUEST) &&
279 (attrs->count(PW_ACCT_DELAY_TIME) == 0)) {
280 auto delta = steady_clock().now() - start_time;
281 seconds secs = duration_cast<seconds>(delta);
283 static_cast<uint32_t>(secs.count())));
284 }
285
286 // Add NAS-IP[v6]-Address with the local address.
287 IOAddress local_addr = server->getLocalAddress();
288 short family = local_addr.getFamily();
289 if (family == AF_INET) {
290 if (attrs->count(PW_NAS_IP_ADDRESS) == 0) {
291 attrs->add(Attribute::fromIpAddr(PW_NAS_IP_ADDRESS, local_addr));
292 }
293 } else if (family == AF_INET6) {
294 if (attrs->count(PW_NAS_IPV6_ADDRESS) == 0) {
296 local_addr));
297 }
298 }
299
300 // Add Message-Authenticator to Status-Server message or when wanted.
301 if ((RadiusImpl::instance().use_message_authenticator_ ||
302 (sent_->getCode() == PW_STATUS_SERVER)) &&
303 (attrs->count(PW_MESSAGE_AUTHENTICATOR) == 0)) {
304 const vector<uint8_t> zero(AUTH_VECTOR_LEN);
305 // The FreeRADIUS server prefers to get it first.
307 false);
308 }
309
310 // Encode the request.
311 sent_->encode();
312}
313
314void
318
319void
323
324void
328 return;
329 }
330
331 if (terminated_) {
332 return;
333 }
334 // In order:
335 // - no current server: open the next one.
336 // - last try.
337 // - next try.
338
339 if (!server_) {
340 // No server: get the next server.
341 if (idx_ < servers_.size()) {
342 // First pass.
344 // Null pointer (should not happen).
345 if (!server_) {
346 isc_throw(Unexpected, "null server at " << idx_);
347 }
348 // Server still in hold-down: postpone it.
349 if ((server_->getDeadtime() > 0) &&
350 (server_->getDeadtimeEnd() > start_time_)) {
351 postponed_.push_back(idx_);
352 ++idx_;
353 io_service_->post(std::bind(&UdpExchange::openNext,
354 shared_from_this()));
355 return;
356 }
357 } else {
358 // Second pass: try postponed servers.
359 if (postponed_.empty()) {
360 io_service_->post(std::bind(&UdpExchange::terminate,
361 shared_from_this()));
362 return;
363 }
364 size_t cur_idx = postponed_.front();
365 // Out-of-range (should not happen).
366 if (cur_idx >= servers_.size()) {
367 isc_throw(Unexpected, "out of range server " << cur_idx
368 << " >= " << servers_.size());
369 }
370 server_ = servers_[cur_idx];
371 // Null pointer (should not happen).
372 if (!server_) {
373 isc_throw(Unexpected, "null server at " << cur_idx);
374 }
375 }
376
377 // Have a new server.
378 try {
379 // Reset error code.
380 rc_ = ERROR_RC;
381
382 // Build to be send request message.
383 buildRequest();
384
385 // Set end-point.
386 ep_.reset(new UDPEndpoint(server_->getPeerAddress(),
387 server_->getPeerPort()));
388
389 // Set socket.
390 if (socket_) {
391 socket_->close();
392 }
393 socket_.reset(new RadiusSocket(io_service_));
394
395 // Launch timer.
396 setTimer();
397
398 // Open socket.
399 socket_->open(ep_.get(), SocketCallback());
400
401 // Should bind the socket but it is not (yet) in the API.
402 // Anyway the kernel should choose the same address...
403
404 // Better to use a connected socket...
405
406 // Send request message.
407 buffer_ = sent_->getBuffer();
408 size_ = buffer_.size();
409
412 .arg(identifier_)
413 .arg(buffer_.size())
414 .arg(idx_)
415 .arg(ep_->getAddress().toText())
416 .arg(ep_->getPort());
417
418 socket_->asyncSend(&buffer_[0], buffer_.size(), ep_.get(),
419 std::bind(&UdpExchange::sentHandler,
420 shared_from_this(),
421 ph::_1, // error_code.
422 ph::_2)); // size.
423 return;
424 } catch (const Exception& exc) {
426 .arg(identifier_)
427 .arg(exc.what());
428 cancelTimer();
429 rc_ = ERROR_RC;
430 if (socket_) {
431 socket_->close();
432 socket_.reset();
433 }
434 io_service_->post(std::bind(&UdpExchange::openNext,
435 shared_from_this()));
436 return;
437 }
438 }
439
440 // No other try?
441 if (retries_++ >= maxretries_) {
442 if ((rc_ == TIMEOUT_RC) && (idx_ < servers_.size())) {
443 // On timeout hold-down the server.
444 unsigned deadtime = server_->getDeadtime();
445 if (deadtime > 0) {
446 server_->setDeadtimeEnd(start_time_ + seconds(deadtime));
447 }
448 }
449 retries_ = 0;
450 server_.reset();
451 ep_.reset();
452 // Try postponed servers?
453 if (idx_ == servers_.size()) {
454 // Postponed servers are exhausted.
455 if (postponed_.size() < 2) {
456 io_service_->post(std::bind(&UdpExchange::terminate,
457 shared_from_this()));
458 return;
459 }
460 // Try next postponed server.
461 postponed_.pop_front();
462 } else {
463 // Try next server.
464 ++idx_;
465 if ((idx_ == servers_.size()) && (postponed_.empty())) {
466 io_service_->post(std::bind(&UdpExchange::terminate,
467 shared_from_this()));
468 return;
469 }
470 }
471 // Call again open to try the next server.
472 io_service_->post(std::bind(&UdpExchange::openNext,
473 shared_from_this()));
474 return;
475 }
476
477 // Next try.
478 try {
479 if (!ep_) {
480 isc_throw(Unexpected, "endpoint is null");
481 }
482
483 // Build to be send request message.
484 buildRequest();
485
486 // Set socket.
487 if (socket_) {
488 socket_->close();
489 }
490 socket_.reset(new RadiusSocket(io_service_));
491
492 // Launch timer.
493 setTimer();
494
495 // Open socket.
496 socket_->open(ep_.get(), SocketCallback());
497
498 // Should bind the socket but it is not (yet) in the API.
499 // Anyway the kernel should choose the same address...
500
501 // Better to use a connected socket...
502
503 // Send request message.
504 buffer_ = sent_->getBuffer();
505 size_ = buffer_.size();
506
509 .arg(identifier_)
510 .arg(buffer_.size())
511 .arg(retries_);
512
513 socket_->asyncSend(&buffer_[0],
514 buffer_.size(),
515 ep_.get(),
516 std::bind(&UdpExchange::sentHandler,
517 shared_from_this(),
518 ph::_1, // error_code.
519 ph::_2)); // size.
520 return;
521 } catch (const Exception& exc) {
523 .arg(identifier_)
524 .arg(exc.what());
525 cancelTimer();
526 rc_ = ERROR_RC;
527 if (socket_) {
528 socket_->close();
529 socket_.reset();
530 }
531 io_service_->post(std::bind(&UdpExchange::openNext,
532 shared_from_this()));
533 return;
534 }
535}
536
537void
539 const boost::system::error_code ec,
540 const size_t size) {
541 if (!ex) {
542 isc_throw(Unexpected, "null exchange in sentHandler");
543 }
544
546 ex->shutdown();
547 return;
548 }
549
550 MultiThreadingLock lock(*ex->mutex_);
551
552 if (ex->terminated_) {
553 return;
554 }
555
556 // Check error code.
557 if (ec) {
559 .arg(ex->identifier_)
560 .arg(ec.message());
561 ex->cancelTimer();
562 if (ex->socket_) {
563 ex->socket_->close();
564 ex->socket_.reset();
565 }
566 ex->io_service_->post(std::bind(&UdpExchange::openNext, ex));
567 return;
568 }
569
570 // No error: receive response.
572 .arg(ex->identifier_)
573 .arg(size);
574 ex->buffer_.clear();
575 ex->buffer_.resize(BUF_LEN);
576 ex->size_ = ex->buffer_.size();
577 ex->socket_->asyncReceive(&(ex->buffer_)[0], ex->size_, 0, ex->ep_.get(),
579 ex,
580 ph::_1, // error_code.
581 ph::_2)); // size.
582}
583
584void
586 // Decode message.
587 rc_ = OK_RC;
588 try {
589 // In order:
590 // - decode message.
591 // - verify that it is signed.
592 // - verify that identifiers match.
593 // - verify that message codes match.
594 received_->decode();
595 if (RadiusImpl::instance().use_message_authenticator_) {
596 auto attrs = received_->getAttributes();
597 if (!attrs || (attrs->count(PW_MESSAGE_AUTHENTICATOR) == 0)) {
598 isc_throw(BadValue, "missing Message-Authenticator");
599 }
600 }
601 unsigned got = received_->getIdentifier();
602 unsigned expected = sent_->getIdentifier();
603 if (got != expected) {
605 .arg(identifier_)
606 .arg(got)
607 .arg(expected);
608 rc_ = BADRESP_RC;
609 } else if (request_->getCode() == PW_ACCESS_REQUEST) {
610 if (received_->getCode() == PW_ACCESS_REJECT) {
613 .arg(identifier_);
614 rc_ = REJECT_RC;
615 } else if (received_->getCode() != PW_ACCESS_ACCEPT) {
617 .arg(identifier_)
618 .arg(msgCodeToText(request_->getCode()))
619 .arg(msgCodeToText(received_->getCode()));
620 rc_ = BADRESP_RC;
621 } else {
624 .arg(identifier_);
625 }
626 } else if (request_->getCode() == PW_ACCOUNTING_REQUEST) {
627 if (received_->getCode() != PW_ACCOUNTING_RESPONSE) {
629 .arg(identifier_)
630 .arg(msgCodeToText(request_->getCode()))
631 .arg(msgCodeToText(received_->getCode()));
632 rc_ = BADRESP_RC;
633 } else {
636 .arg(identifier_);
637 }
638 } else if (request_->getCode() == PW_STATUS_SERVER) {
639 if (received_->getCode() == PW_ACCESS_ACCEPT) {
642 .arg(identifier_);
643 } else if (received_->getCode() == PW_ACCESS_REJECT) {
646 .arg(identifier_);
647 } else if (received_->getCode() == PW_ACCOUNTING_RESPONSE) {
650 .arg(identifier_);
651 } else {
653 .arg(identifier_)
654 .arg(msgCodeToText(request_->getCode()))
655 .arg(msgCodeToText(received_->getCode()));
656 rc_ = BADRESP_RC;
657 }
658 }
659 } catch (const Exception& exc) {
661 .arg(identifier_)
662 .arg(exc.what());
663 rc_ = BADRESP_RC;
664 }
665
668 .arg(identifier_)
669 .arg(exchangeRCtoText(rc_));
670}
671
672void
674 const boost::system::error_code ec,
675 const size_t size) {
676 if (!ex) {
677 isc_throw(Unexpected, "null exchange in receivedHandler");
678 }
679
681 ex->shutdown();
682 return;
683 }
684
685 MultiThreadingLock lock(*ex->mutex_);
686
687 // This was the action on the socket.
688 ex->cancelTimer();
689 if (ex->socket_) {
690 ex->socket_->close();
691 ex->socket_.reset();
692 }
693
694 if (ex->terminated_) {
695 return;
696 }
697
698 // Check error code.
699 if (ec) {
701 .arg(ex->identifier_)
702 .arg(ec.message());
703 ex->io_service_->post(std::bind(&UdpExchange::openNext, ex));
704 return;
705 }
706
707 // Remove the server from hold-down.
708 if (ex->server_ &&
709 (ex->server_->getDeadtime() > 0) &&
710 (ex->server_->getDeadtimeEnd() > ex->start_time_)) {
711 ex->server_->setDeadtimeEnd(ex->start_time_);
712 }
713
714 // Create message.
716 .arg(ex->identifier_)
717 .arg(size);
718 ex->buffer_.resize(size);
719 ex->received_.reset(new Message(ex->buffer_, ex->sent_->getAuth(),
720 ex->server_->getSecret()));
721
722 ex->processResponse();
723
724 // If bad then retry, if not including reject it is done.
725 if ((ex->rc_ != OK_RC) && (ex->rc_ != REJECT_RC)) {
726 ex->io_service_->post(std::bind(&UdpExchange::openNext, ex));
727 } else {
728 ex->logReplyMessages();
729 ex->io_service_->post(std::bind(&UdpExchange::terminate, ex));
730 }
731}
732
733void
735 // Avoid multiple terminations.
737
738 if (terminated_) {
739 return;
740 } else {
741 terminated_ = true;
742 }
743
744 // Should have been done before.
745 cancelTimer();
746 if (socket_) {
747 socket_->close();
748 socket_.reset();
749 }
750
751 if ((rc_ != OK_RC) && (rc_ != REJECT_RC)) {
753 .arg(identifier_)
754 .arg(exchangeRCtoText(rc_));
755 } else {
758 .arg(identifier_)
759 .arg(exchangeRCtoText(rc_));
760 }
761
762 if (io_service_) {
763 if (sync_) {
764 io_service_->stopWork();
765 } else {
766 io_service_.reset();
767 }
768 }
769
770 // Call handler.
771 if (handler_) {
772 auto handler = handler_;
773 // Avoid to keep a circular reference.
774 handler_ = Handler();
775 if (MultiThreadingMgr::instance().getMode()) {
777 handler(shared_from_this());
778 } else {
779 handler(shared_from_this());
780 }
781 }
782}
783
784void
786 cancelTimer();
787 timer_.reset(new IntervalTimer(io_service_));
788 timer_->setup(std::bind(&UdpExchange::timeoutHandler, shared_from_this()),
789 server_->getTimeout() * 1000, IntervalTimer::ONE_SHOT);
790}
791
792void
794 if (timer_) {
795 timer_->cancel();
796 timer_.reset();
797 }
798}
799
800void
802 MultiThreadingLock lock(*ex->mutex_);
804 .arg(ex->identifier_);
805 ex->rc_ = TIMEOUT_RC;
806 ex->cancelTimer();
807 if (ex->socket_) {
808 ex->socket_->cancel();
809 }
810}
811
813 unsigned maxretries,
814 const Servers& servers,
815 Handler handler)
816 : Exchange(request, maxretries, servers, handler),
817 start_time_(std::chrono::steady_clock().now()),
818 server_(), response_() {
819 server_ = servers_[0];
820}
821
822void
825 shutdown();
826 }
827
828 if (!server_) {
829 isc_throw(Unexpected, "no server");
830 }
831
832 if (!RadiusImpl::instance().tcp_client_) {
833 isc_throw(Unexpected, "no TCP client");
834 }
835
837 .arg(identifier_);
838
839 try {
840
841 // Reset error code.
842 rc_ = ERROR_RC;
843
844 // Build to be send request message.
845 buildRequest();
846
847 // Build write data request.
848 WireDataPtr request(new WireData(sent_->getBuffer()));
849
850 // Build write data response.
851 response_.reset(new WireData());
852
854 .arg(identifier_)
855 .arg(request->size())
856 .arg(server_->getPeerAddress().toText())
857 .arg(server_->getPeerPort())
858 .arg(server_->getTlsContext() ? " using TLS" : "");
859
860 RadiusImpl::instance().tcp_client_->asyncSendRequest(
861 server_->getPeerAddress(),
862 server_->getPeerPort(),
863 server_->getTlsContext(),
864 request,
865 response_,
866 true,
869 shared_from_this(),
870 ph::_1, // error_code
871 ph::_2, // response
872 ph::_3), // error_msg
873 TcpClient::RequestTimeout(server_->getTimeout() * 1000));
874 } catch (const Exception& exc) {
876 .arg(identifier_)
877 .arg(exc.what());
878 rc_ = ERROR_RC;
879 // Call handler.
880 if (handler_) {
881 auto handler = handler_;
882 // Avoid to keep a circular reference.
883 handler_ = Handler();
884 handler(shared_from_this());
885 }
886 }
887}
888
889void
893
894void
896 const boost::system::error_code& ec,
897 const WireDataPtr& response,
898 const string& error_msg) {
899 if (!ex) {
900 isc_throw(Unexpected, "null exchange in RequestHandler");
901 }
902
904 return;
905 }
906
907 // Call handler.
908 auto call_handler = [](TcpExchangePtr exchange) {
909 if (exchange->handler_) {
910 auto handler = exchange->handler_;
911 // Avoid to keep a circular reference.
912 exchange->handler_ = Handler();
913 handler(exchange);
914 }
915 };
916
917 // Check error code.
918 if (ec) {
920 .arg(ex->identifier_)
921 .arg(error_msg);
922 if (ec == boost::asio::error::timed_out) {
923 ex->rc_ = TIMEOUT_RC;
924 } else {
925 ex->rc_ = ERROR_RC;
926 }
927 call_handler(ex);
928 return;
929 }
930
931 if (!response) {
932 isc_throw(Unexpected, "null response in RequestHandler");
933 }
934
936 .arg(ex->identifier_)
937 .arg(response->size());
938
939 const WireData& buffer = *response;
940 ex->received_.reset(new Message(buffer, ex->sent_->getAuth(),
941 ex->server_->getSecret()));
942
943 ex->processResponse();
944
945 if ((ex->rc_ == OK_RC) || (ex->rc_ == REJECT_RC)) {
946 ex->logReplyMessages();
948 .arg(ex->identifier_)
949 .arg(exchangeRCtoText(ex->rc_));
950 } else {
952 .arg(ex->identifier_)
953 .arg(exchangeRCtoText(ex->rc_));
954 }
955 call_handler(ex);
956}
957
958int
959TcpExchange::CompleteCheck(const WireDataPtr& response, string& error_msg) {
960 if (!response) {
961 error_msg = "null response";
962 return (-1);
963 }
964 const WireData& buffer = *response;
965 if (buffer.size() < AUTH_HDR_LEN) {
966 return (0);
967 }
968 uint16_t length = static_cast<uint16_t>(buffer[2]) << 8;
969 length |= static_cast<uint16_t>(buffer[3]);
970 if (length > buffer.size()) {
971 return (0);
972 } else if (length == buffer.size()) {
973 return (1);
974 } else {
975 error_msg = "overflow";
976 return (-2);
977 }
978}
979
980} // end of namespace isc::radius
981} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
static AttributePtr fromInt(const uint8_t type, const uint32_t value)
From integer with type.
static AttributePtr fromIpAddr(const uint8_t type, const asiolink::IOAddress &value)
From IPv4 address with type.
static AttributePtr fromBinary(const uint8_t type, const std::vector< uint8_t > &value)
From binary with type.
static AttributePtr fromIpv6Addr(const uint8_t type, const asiolink::IOAddress &value)
From IPv6 address with type.
Collection of attributes.
asiolink::UDPSocket< const SocketCallback > RadiusSocket
Type of RADIUS UDP sockets.
Servers servers_
Servers (a copy which is what we need).
Handler handler_
Termination handler.
MessagePtr request_
Request message.
Exchange(const MessagePtr &request, unsigned maxretries, const Servers &servers, Handler handler)
Constructor.
std::function< void(const ExchangePtr ex)> Handler
Termination handler.
bool sync_
Sync / async flag.
void processResponse()
Process response.
static constexpr size_t BUF_LEN
Receive buffer size.
void createIdentifier()
Create identifier.
MessagePtr received_
Received message.
int rc_
Error/return code.
std::string identifier_
The identifier (random value in hexadecimal).
std::function< void(const boost::system::error_code ec, const size_t size)> SocketCallback
Type of UDP socket callback functions.
MessagePtr sent_
Sent message.
void buildRequest(const ServerPtr &server, std::chrono::steady_clock::time_point start_time)
Build request.
static ExchangePtr create(const asiolink::IOServicePtr io_service, const MessagePtr &request, unsigned maxretries, const Servers &servers, Handler handler, RadiusProtocol protocol=PW_PROTO_UDP)
Factory.
void logReplyMessages() const
Log reply messages.
unsigned maxretries_
Maximum number of retries for a server.
RADIUS Message.
static std::atomic< bool > shutdown_
Flag which indicates that the instance is shutting down.
Definition radius.h:341
isc::tcp::TcpClientPtr tcp_client_
TCP client.
Definition radius.h:275
static RadiusImpl & instance()
RadiusImpl is a singleton class.
Definition radius.cc:163
RADIUS/TCP (or RADIUS/TLS) Exchange.
isc::tcp::WireDataPtr response_
Response wire data.
TcpExchange(const MessagePtr &request, unsigned maxretries, const Servers &servers, Handler handler)
Constructor.
virtual void shutdown()
Shutdown.
void buildRequest()
Build request.
static int CompleteCheck(const isc::tcp::WireDataPtr &response, std::string &error_msg)
Complete check.
std::chrono::steady_clock::time_point start_time_
Start time.
virtual void start()
Start.
ServerPtr server_
Current server.
static void RequestHandler(TcpExchangePtr ex, const boost::system::error_code &ec, const isc::tcp::WireDataPtr &response, const std::string &error_msg)
Request handler.
RADIUS/UDP Exchange.
asiolink::IOServicePtr io_service_
IO service (argument for async or internal for sync).
boost::scoped_ptr< asiolink::UDPEndpoint > ep_
UDP endpoint.
static void receivedHandler(UdpExchangePtr ex, const boost::system::error_code ec, const size_t size)
Received handler.
void cancelTimer()
Cancel timer.
asiolink::IntervalTimerPtr timer_
Interval timer.
size_t size_
Number of transmitted octests;.
void open()
Instance open.
static void timeoutHandler(UdpExchangePtr ex)
Timeout handler.
virtual ~UdpExchange()
Destructor.
bool started_
Started flag.
virtual void shutdown()
Shutdown.
std::chrono::steady_clock::time_point start_time_
Start time.
std::list< size_t > postponed_
List of postponed server indexes.
void buildRequest()
Build request.
virtual void shutdownInternal()
Shutdown.
size_t idx_
Current server index.
ServerPtr server_
Current server.
virtual void start()
Start.
std::vector< uint8_t > buffer_
Buffer.
static void openNext(UdpExchangePtr ex)
Class open / open next.
boost::scoped_ptr< RadiusSocket > socket_
Socket.
bool terminated_
Terminated flag.
UdpExchange(const asiolink::IOServicePtr io_service, const MessagePtr &request, unsigned maxretries, const Servers &servers, Handler handler)
Constructor.
unsigned retries_
Retry counter.
static void sentHandler(UdpExchangePtr ex, const boost::system::error_code ec, const size_t size)
Sent handler.
boost::scoped_ptr< std::mutex > mutex_
State change mutex.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
if(!(yy_init))
Definition d2_lexer.cc:1502
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#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 isc::log::MessageID RADIUS_UDP_EXCHANGE_OPEN_FAILED
@ PW_MESSAGE_AUTHENTICATOR
string.
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_MISMATCH
boost::shared_ptr< Attributes > AttributesPtr
Shared pointers to attribute collection.
const isc::log::MessageID RADIUS_UDP_EXCHANGE_SYNC_RETURN
boost::shared_ptr< const Attribute > ConstAttributePtr
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_ACCESS_REJECT
const isc::log::MessageID RADIUS_UDP_EXCHANGE_FAILED
boost::shared_ptr< TcpExchange > TcpExchangePtr
Type of shared pointers to RADIUS/TCP exchange object.
string exchangeRCtoText(const int rc)
ExchangeRC value -> name function.
const isc::log::MessageID RADIUS_UDP_EXCHANGE_START
const isc::log::MessageID RADIUS_UDP_EXCHANGE_RECEIVED
const isc::log::MessageID RADIUS_UDP_EXCHANGE_RECEIVE_FAILED
const isc::log::MessageID RADIUS_TCP_EXCHANGE_FAILURE
RadiusProtocol
Transport protocols.
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_ACCESS_ACCEPT
std::vector< ServerPtr > Servers
Type of RADIUS server collection.
boost::shared_ptr< Exchange > ExchangePtr
Type of shared pointers to RADIUS exchange object.
const isc::log::MessageID RADIUS_UDP_EXCHANGE_SEND_NEW
boost::shared_ptr< Server > ServerPtr
Type of shared pointers to a RADIUS server object.
string msgCodeToText(const uint8_t code)
MsgCode value -> name function.
const int RADIUS_DBG_TRACE
Radius logging levels.
Definition radius_log.h:26
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_ACCOUNTING_RESPONSE
const isc::log::MessageID RADIUS_TCP_EXCHANGE_START_ERROR
const isc::log::MessageID RADIUS_TCP_EXCHANGE_RECEIVED
const isc::log::MessageID RADIUS_TCP_EXCHANGE_SUCCESS
const isc::log::MessageID RADIUS_REPLY_MESSAGE_ATTRIBUTE
const isc::log::MessageID RADIUS_UDP_EXCHANGE_TERMINATE
boost::shared_ptr< UdpExchange > UdpExchangePtr
Type of shared pointers to RADIUS/UDP exchange object.
const isc::log::MessageID RADIUS_TCP_EXCHANGE_SEND
isc::log::Logger radius_logger("radius-hooks")
Radius Logger.
Definition radius_log.h:35
boost::shared_ptr< Message > MessagePtr
Shared pointers to message.
const isc::log::MessageID RADIUS_TCP_EXCHANGE_RECEIVE_FAILED
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_UNEXPECTED
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_BAD_RESPONSE
const isc::log::MessageID RADIUS_EXCHANGE_RECEIVED_RESPONSE
const isc::log::MessageID RADIUS_TCP_EXCHANGE_START
const isc::log::MessageID RADIUS_UDP_EXCHANGE_TIMEOUT
const isc::log::MessageID RADIUS_UDP_EXCHANGE_SEND_FAILED
const isc::log::MessageID RADIUS_UDP_EXCHANGE_SENT
const isc::log::MessageID RADIUS_UDP_EXCHANGE_SEND_RETRY
std::vector< uint8_t > WireData
Defines a data structure for storing raw bytes of data on the wire.
Definition wire_data.h:17
boost::shared_ptr< WireData > WireDataPtr
Definition wire_data.h:18
Defines the logger used by the top-level component of kea-lfc.
TCP request/response timeout value.
Definition tcp_client.h:83
RAII lock object to protect the code in the same scope with a mutex.