Kea 3.3.3
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 <radius/radius.h>
17#include <util/unlock_guard.h>
18
19#include <cerrno>
20#include <chrono>
21#include <limits>
22#include <sstream>
23
24#include <radius_log.h>
25
26using namespace isc;
27using namespace isc::asiolink;
28using namespace isc::data;
29using namespace isc::tcp;
30using namespace isc::util;
31using namespace std;
32using namespace std::chrono;
33namespace ph = std::placeholders;
34
35namespace isc {
36namespace radius {
37
38string
39exchangeRCtoText(const int rc) {
40 ostringstream result;
41 switch (rc) {
42 case BADRESP_RC:
43 return ("bad response");
44 case ERROR_RC:
45 return ("error");
46 case OK_RC:
47 return ("ok");
48 case TIMEOUT_RC:
49 return ("timeout");
50 case REJECT_RC:
51 return ("reject");
52 case READBLOCK_RC:
53 return ("temporarily unavailable");
54 default:
55 result << (rc < 0 ? "error " : "unknown ") << rc;
56 return (result.str());
57 }
58}
59
61 unsigned maxretries,
62 const Servers& servers,
63 Handler handler)
64 : identifier_(""), sync_(false), rc_(ERROR_RC),
65 request_(request), sent_(), received_(),
66 maxretries_(maxretries), servers_(servers), handler_(handler) {
67 if (!request) {
68 isc_throw(BadValue, "null request");
69 }
70 if (servers.empty()) {
71 isc_throw(BadValue, "no server");
72 }
73 if (!handler) {
74 isc_throw(BadValue, "null handler");
75 }
77}
78
80 unsigned maxretries,
81 const Servers& servers)
82 : identifier_(""), sync_(true), rc_(ERROR_RC),
83 request_(request), sent_(), received_(),
84 maxretries_(maxretries), servers_(servers), handler_() {
85 if (!request) {
86 isc_throw(BadValue, "null request");
87 }
88 if (servers.empty()) {
89 isc_throw(BadValue, "no server");
90 }
92}
93
96 const MessagePtr& request,
97 unsigned maxretries,
98 const Servers& servers,
99 Handler handler,
100 RadiusProtocol protocol) {
101 if (protocol == PW_PROTO_UDP) {
102 return (UdpExchangePtr(new UdpExchange(io_service, request, maxretries,
103 servers, handler)));
104 } else {
105 return (TcpExchangePtr(new TcpExchange(request, maxretries,
106 servers, handler)));
107 }
108}
109
112 unsigned maxretries,
113 const Servers& servers) {
114 return (UdpExchangePtr(new UdpExchange(request, maxretries, servers)));
115}
116
118 const MessagePtr& request,
119 unsigned maxretries,
120 const Servers& servers,
121 Handler handler)
122 : Exchange(request, maxretries, servers, handler),
123 io_service_(io_service), started_(false), terminated_(false),
124 start_time_(std::chrono::steady_clock().now()),
125 socket_(), ep_(), timer_(), server_(), idx_(0),
126 buffer_(), size_(0), retries_(0), postponed_(),
127 mutex_(new std::mutex()) {
128 if (!io_service) {
129 isc_throw(BadValue, "null IO service");
130 }
131}
132
134 unsigned maxretries,
135 const Servers& servers)
136 : Exchange(request, maxretries, servers),
137 io_service_(new IOService()),
138 started_(false), terminated_(false),
139 start_time_(std::chrono::steady_clock().now()),
140 socket_(), ep_(), timer_(), server_(), idx_(0),
141 buffer_(), size_(0), retries_(0), postponed_(),
142 mutex_(new std::mutex()) {
143}
144
148 timer_.reset();
149 socket_.reset();
150 if (sync_ && io_service_) {
151 // As a best practice, call any remaining handlers.
152 io_service_->stopAndPoll();
153 io_service_.reset();
154 }
155}
156
157void
159 vector<uint8_t> rv = cryptolink::random(sizeof(uint32_t));
160 if (rv.size() != sizeof(uint32_t)) {
161 isc_throw(Unexpected, "random failed");
162 }
163 uint32_t ri;
164 memmove(&ri, &rv[0], sizeof(uint32_t));
165 ostringstream rs;
166 rs << hex << setfill('0') << setw(8) << ri;
167 identifier_ = rs.str();
168}
169void
171 if (!received_) {
172 return;
173 }
174 const AttributesPtr& attrs = received_->getAttributes();
175 if (!attrs || (attrs->count(PW_REPLY_MESSAGE) == 0)) {
176 return;
177 }
178 for (const ConstAttributePtr& attr : *attrs) {
179 if (!attr || (attr->getType() != PW_REPLY_MESSAGE)) {
180 continue;
181 }
183 .arg(static_cast<int>(received_->getIdentifier()))
184 .arg(identifier_)
185 .arg(attr->toString());
186 }
187}
188
189void
192
193 if (started_) {
194 return;
195 } else {
196 started_ = true;
197 }
199 .arg(identifier_);
200
201 open();
202
203 if (sync_) {
204 // Run() will return when syncHandler will be called.
205 io_service_->run();
206
207 // Done.
208 io_service_.reset();
209
212 .arg(identifier_)
213 .arg(rc_);
214 }
215}
216
217void
219 // Avoid multiple terminations.
222}
223
224void
226 if (terminated_) {
227 return;
228 } else {
229 terminated_ = true;
230 }
231 // Same as terminate but not calling callback.
232 cancelTimer();
233 if (socket_) {
234 socket_->cancel();
235 }
236 handler_ = Handler();
237
238 if (io_service_) {
239 if (sync_) {
240 io_service_->stopWork();
241 } else {
242 io_service_.reset();
243 }
244 }
245}
246
247void
249 std::chrono::steady_clock::time_point start_time) {
250 if (!server) {
251 isc_throw(Unexpected, "no server");
252 }
253
254 // Prepare message to send.
255 sent_.reset(new Message(*request_));
256
257 // Randomize the identifier.
258 sent_->randomIdentifier();
259
260 // Randomize or zero the authenticator.
261 if ((sent_->getCode() == PW_ACCESS_REQUEST) ||
262 (sent_->getCode() == PW_STATUS_SERVER)) {
263 sent_->randomAuth();
264 } else {
265 sent_->zeroAuth();
266 }
267
268 // Set the secret.
269 sent_->setSecret(server->getSecret());
270
271 // Get attributes.
272 AttributesPtr attrs = sent_->getAttributes();
273 if (!attrs) {
274 attrs.reset(new Attributes());
275 sent_->setAttributes(attrs);
276 }
277
278 // Add Acct-Delay-Time to Accounting-Request message.
279 if ((sent_->getCode() == PW_ACCOUNTING_REQUEST) &&
280 (attrs->count(PW_ACCT_DELAY_TIME) == 0)) {
281 auto delta = steady_clock().now() - start_time;
282 seconds secs = duration_cast<seconds>(delta);
284 static_cast<uint32_t>(secs.count())));
285 }
286
287 // Add NAS-IP[v6]-Address with the local address.
288 IOAddress local_addr = server->getLocalAddress();
289 short family = local_addr.getFamily();
290 if (family == AF_INET) {
291 if (attrs->count(PW_NAS_IP_ADDRESS) == 0) {
292 attrs->add(Attribute::fromIpAddr(PW_NAS_IP_ADDRESS, local_addr));
293 }
294 } else if (family == AF_INET6) {
295 if (attrs->count(PW_NAS_IPV6_ADDRESS) == 0) {
297 local_addr));
298 }
299 }
300
301 // Add Message-Authenticator to Status-Server message or when wanted.
302 if ((RadiusImpl::instance().use_message_authenticator_ ||
303 (sent_->getCode() == PW_STATUS_SERVER)) &&
304 (attrs->count(PW_MESSAGE_AUTHENTICATOR) == 0)) {
305 const vector<uint8_t> zero(AUTH_VECTOR_LEN);
306 // The FreeRADIUS server prefers to get it first.
308 false);
309 }
310
311 // Encode the request.
312 sent_->encode();
313}
314
315void
319
320void
324
325void
329 return;
330 }
331
332 if (terminated_) {
333 return;
334 }
335 // In order:
336 // - no current server: open the next one.
337 // - last try.
338 // - next try.
339
340 if (!server_) {
341 // No server: get the next server.
342 if (idx_ < servers_.size()) {
343 // First pass.
345 // Null pointer (should not happen).
346 if (!server_) {
347 isc_throw(Unexpected, "null server at " << idx_);
348 }
349 // Server still in hold-down: postpone it.
350 if ((server_->getDeadtime() > 0) &&
351 (server_->getDeadtimeEnd() > start_time_)) {
352 postponed_.push_back(idx_);
353 ++idx_;
354 io_service_->post(std::bind(&UdpExchange::openNext,
355 shared_from_this()));
356 return;
357 }
358 } else {
359 // Second pass: try postponed servers.
360 if (postponed_.empty()) {
361 io_service_->post(std::bind(&UdpExchange::terminate,
362 shared_from_this()));
363 return;
364 }
365 size_t cur_idx = postponed_.front();
366 // Out-of-range (should not happen).
367 if (cur_idx >= servers_.size()) {
368 isc_throw(Unexpected, "out of range server " << cur_idx
369 << " >= " << servers_.size());
370 }
371 server_ = servers_[cur_idx];
372 // Null pointer (should not happen).
373 if (!server_) {
374 isc_throw(Unexpected, "null server at " << cur_idx);
375 }
376 }
377
378 // Have a new server.
379 try {
380 // Reset error code.
381 rc_ = ERROR_RC;
382
383 // Build to be send request message.
384 buildRequest();
385
386 // Set end-point.
387 ep_.reset(new UDPEndpoint(server_->getPeerAddress(),
388 server_->getPeerPort()));
389
390 // Set socket.
391 if (socket_) {
392 socket_->close();
393 }
394 socket_.reset(new RadiusSocket(io_service_));
395
396 // Launch timer.
397 setTimer();
398
399 // Open socket.
400 socket_->open(ep_.get(), SocketCallback());
401
402 // Should bind the socket but it is not (yet) in the API.
403 // Anyway the kernel should choose the same address...
404
405 // Better to use a connected socket...
406
407 // Send request message.
408 buffer_ = sent_->getBuffer();
409 size_ = buffer_.size();
410 // Note from a message the buffer can't be empty.
411
414 .arg(identifier_)
415 .arg(buffer_.size())
416 .arg(idx_)
417 .arg(ep_->getAddress().toText())
418 .arg(ep_->getPort());
419
420 socket_->asyncSend(&buffer_[0], buffer_.size(), ep_.get(),
421 std::bind(&UdpExchange::sentHandler,
422 shared_from_this(),
423 ph::_1, // error_code.
424 ph::_2)); // size.
425 return;
426 } catch (const std::exception& exc) {
428 .arg(identifier_)
429 .arg(exc.what());
430 cancelTimer();
431 rc_ = ERROR_RC;
432 if (socket_) {
433 socket_->close();
434 socket_.reset();
435 }
436 io_service_->post(std::bind(&UdpExchange::openNext,
437 shared_from_this()));
438 return;
439 }
440 }
441
442 // No other try?
443 if (retries_++ >= maxretries_) {
444 if ((rc_ == TIMEOUT_RC) && (idx_ < servers_.size())) {
445 // On timeout hold-down the server.
446 unsigned deadtime = server_->getDeadtime();
447 if (deadtime > 0) {
448 server_->setDeadtimeEnd(start_time_ + seconds(deadtime));
449 }
450 }
451 retries_ = 0;
452 server_.reset();
453 ep_.reset();
454 // Try postponed servers?
455 if (idx_ == servers_.size()) {
456 // Postponed servers are exhausted.
457 if (postponed_.size() < 2) {
458 io_service_->post(std::bind(&UdpExchange::terminate,
459 shared_from_this()));
460 return;
461 }
462 // Try next postponed server.
463 postponed_.pop_front();
464 } else {
465 // Try next server.
466 ++idx_;
467 if ((idx_ == servers_.size()) && (postponed_.empty())) {
468 io_service_->post(std::bind(&UdpExchange::terminate,
469 shared_from_this()));
470 return;
471 }
472 }
473 // Call again open to try the next server.
474 io_service_->post(std::bind(&UdpExchange::openNext,
475 shared_from_this()));
476 return;
477 }
478
479 // Next try.
480 try {
481 if (!ep_) {
482 isc_throw(Unexpected, "endpoint is null");
483 }
484
485 // Build to be send request message.
486 buildRequest();
487
488 // Set socket.
489 if (socket_) {
490 socket_->close();
491 }
492 socket_.reset(new RadiusSocket(io_service_));
493
494 // Launch timer.
495 setTimer();
496
497 // Open socket.
498 socket_->open(ep_.get(), SocketCallback());
499
500 // Should bind the socket but it is not (yet) in the API.
501 // Anyway the kernel should choose the same address...
502
503 // Better to use a connected socket...
504
505 // Send request message.
506 buffer_ = sent_->getBuffer();
507 size_ = buffer_.size();
508 // Note from a message the buffer can't be empty.
509
512 .arg(identifier_)
513 .arg(buffer_.size())
514 .arg(retries_);
515
516 socket_->asyncSend(&buffer_[0], buffer_.size(), ep_.get(),
517 std::bind(&UdpExchange::sentHandler,
518 shared_from_this(),
519 ph::_1, // error_code.
520 ph::_2)); // size.
521 return;
522 } catch (const std::exception& exc) {
524 .arg(identifier_)
525 .arg(exc.what());
526 cancelTimer();
527 rc_ = ERROR_RC;
528 if (socket_) {
529 socket_->close();
530 socket_.reset();
531 }
532 io_service_->post(std::bind(&UdpExchange::openNext,
533 shared_from_this()));
534 return;
535 }
536}
537
538void
540 const boost::system::error_code ec,
541 const size_t size) {
542 if (!ex) {
543 isc_throw(Unexpected, "null exchange in sentHandler");
544 }
545
547 ex->shutdown();
548 return;
549 }
550
551 MultiThreadingLock lock(*ex->mutex_);
552
553 if (ex->terminated_) {
554 return;
555 }
556
557 // Check error code.
558 if (ec) {
560 .arg(ex->identifier_)
561 .arg(ec.message());
562 ex->cancelTimer();
563 if (ex->socket_) {
564 ex->socket_->close();
565 ex->socket_.reset();
566 }
567 ex->io_service_->post(std::bind(&UdpExchange::openNext, ex));
568 return;
569 }
570
571 // No error: receive response.
573 .arg(ex->identifier_)
574 .arg(size);
575 ex->buffer_.clear();
576 ex->buffer_.resize(BUF_LEN);
577 ex->size_ = ex->buffer_.size();
578 ex->socket_->asyncReceive(&(ex->buffer_)[0], ex->size_, 0, ex->ep_.get(),
580 ex,
581 ph::_1, // error_code.
582 ph::_2)); // size.
583}
584
585void
587 // Decode message.
588 rc_ = OK_RC;
589 try {
590 // In order:
591 // - decode message.
592 // - verify that it is signed.
593 // - verify that identifiers match.
594 // - verify that message codes match.
595 received_->decode();
596 if (RadiusImpl::instance().use_message_authenticator_) {
597 auto attrs = received_->getAttributes();
598 if (!attrs || (attrs->count(PW_MESSAGE_AUTHENTICATOR) == 0)) {
599 isc_throw(BadValue, "missing Message-Authenticator");
600 }
601 }
602 unsigned got = received_->getIdentifier();
603 unsigned expected = sent_->getIdentifier();
604 if (got != expected) {
606 .arg(identifier_)
607 .arg(got)
608 .arg(expected);
609 rc_ = BADRESP_RC;
610 } else if (request_->getCode() == PW_ACCESS_REQUEST) {
611 if (received_->getCode() == PW_ACCESS_REJECT) {
614 .arg(identifier_);
615 rc_ = REJECT_RC;
616 } else if (received_->getCode() != PW_ACCESS_ACCEPT) {
618 .arg(identifier_)
619 .arg(msgCodeToText(request_->getCode()))
620 .arg(msgCodeToText(received_->getCode()));
621 rc_ = BADRESP_RC;
622 } else {
625 .arg(identifier_);
626 }
627 } else if (request_->getCode() == PW_ACCOUNTING_REQUEST) {
628 if (received_->getCode() != PW_ACCOUNTING_RESPONSE) {
630 .arg(identifier_)
631 .arg(msgCodeToText(request_->getCode()))
632 .arg(msgCodeToText(received_->getCode()));
633 rc_ = BADRESP_RC;
634 } else {
637 .arg(identifier_);
638 }
639 } else if (request_->getCode() == PW_STATUS_SERVER) {
640 if (received_->getCode() == PW_ACCESS_ACCEPT) {
643 .arg(identifier_);
644 } else if (received_->getCode() == PW_ACCESS_REJECT) {
647 .arg(identifier_);
648 } else if (received_->getCode() == PW_ACCOUNTING_RESPONSE) {
651 .arg(identifier_);
652 } else {
654 .arg(identifier_)
655 .arg(msgCodeToText(request_->getCode()))
656 .arg(msgCodeToText(received_->getCode()));
657 rc_ = BADRESP_RC;
658 }
659 }
660 } catch (const std::exception& exc) {
662 .arg(identifier_)
663 .arg(exc.what());
664 rc_ = BADRESP_RC;
665 }
666
669 .arg(identifier_)
670 .arg(exchangeRCtoText(rc_));
671}
672
673void
675 const boost::system::error_code ec,
676 const size_t size) {
677 if (!ex) {
678 isc_throw(Unexpected, "null exchange in receivedHandler");
679 }
680
682 ex->shutdown();
683 return;
684 }
685
686 MultiThreadingLock lock(*ex->mutex_);
687
688 // This was the action on the socket.
689 ex->cancelTimer();
690 if (ex->socket_) {
691 ex->socket_->close();
692 ex->socket_.reset();
693 }
694
695 if (ex->terminated_) {
696 return;
697 }
698
699 // Check error code.
700 if (ec) {
702 .arg(ex->identifier_)
703 .arg(ec.message());
704 ex->io_service_->post(std::bind(&UdpExchange::openNext, ex));
705 return;
706 }
707
708 // Remove the server from hold-down.
709 if (ex->server_ &&
710 (ex->server_->getDeadtime() > 0) &&
711 (ex->server_->getDeadtimeEnd() > ex->start_time_)) {
712 ex->server_->setDeadtimeEnd(ex->start_time_);
713 }
714
715 // Create message.
717 .arg(ex->identifier_)
718 .arg(size);
719 ex->buffer_.resize(size);
720 ex->received_.reset(new Message(ex->buffer_, ex->sent_->getAuth(),
721 ex->server_->getSecret()));
722
723 ex->processResponse();
724
725 // If bad then retry, if not including reject it is done.
726 if ((ex->rc_ != OK_RC) && (ex->rc_ != REJECT_RC)) {
727 ex->io_service_->post(std::bind(&UdpExchange::openNext, ex));
728 } else {
729 ex->logReplyMessages();
730 ex->io_service_->post(std::bind(&UdpExchange::terminate, ex));
731 }
732}
733
734void
736 // Avoid multiple terminations.
738
739 if (terminated_) {
740 return;
741 } else {
742 terminated_ = true;
743 }
744
745 // Should have been done before.
746 cancelTimer();
747 if (socket_) {
748 socket_->close();
749 socket_.reset();
750 }
751
752 if ((rc_ != OK_RC) && (rc_ != REJECT_RC)) {
754 .arg(identifier_)
755 .arg(exchangeRCtoText(rc_));
756 } else {
759 .arg(identifier_)
760 .arg(exchangeRCtoText(rc_));
761 }
762
763 if (io_service_) {
764 if (sync_) {
765 io_service_->stopWork();
766 } else {
767 io_service_.reset();
768 }
769 }
770
771 // Call handler.
772 if (handler_) {
773 auto handler = handler_;
774 // Avoid to keep a circular reference.
775 handler_ = Handler();
776 if (MultiThreadingMgr::instance().getMode()) {
778 handler(shared_from_this());
779 } else {
780 handler(shared_from_this());
781 }
782 }
783}
784
785void
787 cancelTimer();
788 timer_.reset(new IntervalTimer(io_service_));
789 timer_->setup(std::bind(&UdpExchange::timeoutHandler, shared_from_this()),
790 server_->getTimeout() * 1000, IntervalTimer::ONE_SHOT);
791}
792
793void
795 if (timer_) {
796 timer_->cancel();
797 timer_.reset();
798 }
799}
800
801void
803 MultiThreadingLock lock(*ex->mutex_);
805 .arg(ex->identifier_);
806 ex->rc_ = TIMEOUT_RC;
807 ex->cancelTimer();
808 if (ex->socket_) {
809 ex->socket_->cancel();
810 }
811}
812
814 unsigned maxretries,
815 const Servers& servers,
816 Handler handler)
817 : Exchange(request, maxretries, servers, handler),
818 start_time_(std::chrono::steady_clock().now()),
819 server_(), response_() {
820 server_ = servers_[0];
821}
822
823void
826 shutdown();
827 }
828
829 if (!server_) {
830 isc_throw(Unexpected, "no server");
831 }
832
833 if (!RadiusImpl::instance().tcp_client_) {
834 isc_throw(Unexpected, "no TCP client");
835 }
836
838 .arg(identifier_);
839
840 try {
841
842 // Reset error code.
843 rc_ = ERROR_RC;
844
845 // Build to be send request message.
846 buildRequest();
847
848 // Build write data request.
849 WireDataPtr request(new WireData(sent_->getBuffer()));
850
851 // Build write data response.
852 response_.reset(new WireData());
853
855 .arg(identifier_)
856 .arg(request->size())
857 .arg(server_->getPeerAddress().toText())
858 .arg(server_->getPeerPort())
859 .arg(server_->getTlsContext() ? " using TLS" : "");
860
861 RadiusImpl::instance().tcp_client_->asyncSendRequest(
862 server_->getPeerAddress(),
863 server_->getPeerPort(),
864 server_->getTlsContext(),
865 request,
866 response_,
867 true,
870 shared_from_this(),
871 ph::_1, // error_code
872 ph::_2, // response
873 ph::_3), // error_msg
874 TcpClient::RequestTimeout(server_->getTimeout() * 1000));
875 } catch (const std::exception& exc) {
877 .arg(identifier_)
878 .arg(exc.what());
879 rc_ = ERROR_RC;
880 // Call handler.
881 if (handler_) {
882 auto handler = handler_;
883 // Avoid to keep a circular reference.
884 handler_ = Handler();
885 handler(shared_from_this());
886 }
887 }
888}
889
890void
894
895void
897 const boost::system::error_code& ec,
898 const WireDataPtr& response,
899 const string& error_msg) {
900 if (!ex) {
901 isc_throw(Unexpected, "null exchange in RequestHandler");
902 }
903
905 return;
906 }
907
908 // Call handler.
909 auto call_handler = [](TcpExchangePtr exchange) {
910 if (exchange->handler_) {
911 auto handler = exchange->handler_;
912 // Avoid to keep a circular reference.
913 exchange->handler_ = Handler();
914 handler(exchange);
915 }
916 };
917
918 // Check error code.
919 if (ec) {
921 .arg(ex->identifier_)
922 .arg(error_msg);
923 if (ec == boost::asio::error::timed_out) {
924 ex->rc_ = TIMEOUT_RC;
925 } else {
926 ex->rc_ = ERROR_RC;
927 }
928 call_handler(ex);
929 return;
930 }
931
932 if (!response) {
933 isc_throw(Unexpected, "null response in RequestHandler");
934 }
935
937 .arg(ex->identifier_)
938 .arg(response->size());
939
940 const WireData& buffer = *response;
941 ex->received_.reset(new Message(buffer, ex->sent_->getAuth(),
942 ex->server_->getSecret()));
943
944 ex->processResponse();
945
946 if ((ex->rc_ == OK_RC) || (ex->rc_ == REJECT_RC)) {
947 ex->logReplyMessages();
949 .arg(ex->identifier_)
950 .arg(exchangeRCtoText(ex->rc_));
951 } else {
953 .arg(ex->identifier_)
954 .arg(exchangeRCtoText(ex->rc_));
955 }
956 call_handler(ex);
957}
958
959int
960TcpExchange::CompleteCheck(const WireDataPtr& response, string& error_msg) {
961 if (!response) {
962 error_msg = "null response";
963 return (-1);
964 }
965 const WireData& buffer = *response;
966 if (buffer.size() < AUTH_HDR_LEN) {
967 return (0);
968 }
969 uint16_t length = static_cast<uint16_t>(buffer[2]) << 8;
970 length |= static_cast<uint16_t>(buffer[3]);
971 if (length > buffer.size()) {
972 return (0);
973 } else if (length == buffer.size()) {
974 return (1);
975 } else {
976 error_msg = "overflow";
977 return (-2);
978 }
979}
980
981} // end of namespace isc::radius
982} // end of namespace isc
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 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:356
isc::tcp::TcpClientPtr tcp_client_
TCP client.
Definition radius.h:290
static RadiusImpl & instance()
RadiusImpl is a singleton class.
Definition radius.cc:194
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:1515
#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
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
RadiusProtocol
Transport protocols.
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.