3 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "radius_client.h"
16 /* Defaults for RADIUS retransmit values (exponential backoff) */
19 * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
21 #define RADIUS_CLIENT_FIRST_WAIT 3
24 * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
26 #define RADIUS_CLIENT_MAX_WAIT 120
29 * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
31 * Maximum number of retransmit attempts before the entry is removed from
34 #define RADIUS_CLIENT_MAX_RETRIES 10
37 * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
39 * Maximum number of entries in retransmit list (oldest entries will be
40 * removed, if this limit is exceeded).
42 #define RADIUS_CLIENT_MAX_ENTRIES 30
45 * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
47 * The number of failed retry attempts after which the RADIUS server will be
48 * changed (if one of more backup servers are configured).
50 #define RADIUS_CLIENT_NUM_FAILOVER 4
54 * struct radius_rx_handler - RADIUS client RX handler
56 * This data structure is used internally inside the RADIUS client module to
57 * store registered RX handlers. These handlers are registered by calls to
58 * radius_client_register() and unregistered when the RADIUS client is
59 * deinitialized with a call to radius_client_deinit().
61 struct radius_rx_handler {
63 * handler - Received RADIUS message handler
65 RadiusRxResult (*handler)(struct radius_msg *msg,
66 struct radius_msg *req,
67 const u8 *shared_secret,
68 size_t shared_secret_len,
72 * data - Context data for the handler
79 * struct radius_msg_list - RADIUS client message retransmit list
81 * This data structure is used internally inside the RADIUS client module to
82 * store pending RADIUS requests that may still need to be retransmitted.
84 struct radius_msg_list {
86 * addr - STA/client address
88 * This is used to find RADIUS messages for the same STA.
93 * msg - RADIUS message
95 struct radius_msg *msg;
98 * msg_type - Message type
103 * first_try - Time of the first transmission attempt
108 * next_try - Time for the next transmission attempt
113 * attempts - Number of transmission attempts
118 * next_wait - Next retransmission wait time in seconds
123 * last_attempt - Time of the last transmission attempt
125 struct os_reltime last_attempt;
128 * shared_secret - Shared secret with the target RADIUS server
130 const u8 *shared_secret;
133 * shared_secret_len - shared_secret length in octets
135 size_t shared_secret_len;
137 /* TODO: server config with failover to backup server(s) */
140 * next - Next message in the list
142 struct radius_msg_list *next;
147 * struct radius_client_data - Internal RADIUS client data
149 * This data structure is used internally inside the RADIUS client module.
150 * External users allocate this by calling radius_client_init() and free it by
151 * calling radius_client_deinit(). The pointer to this opaque data is used in
152 * calls to other functions as an identifier for the RADIUS client instance.
154 struct radius_client_data {
156 * ctx - Context pointer for hostapd_logger() callbacks
161 * conf - RADIUS client configuration (list of RADIUS servers to use)
163 struct hostapd_radius_servers *conf;
166 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
171 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
176 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
181 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
186 * auth_sock - Currently used socket for RADIUS authentication server
191 * acct_sock - Currently used socket for RADIUS accounting server
196 * auth_handlers - Authentication message handlers
198 struct radius_rx_handler *auth_handlers;
201 * num_auth_handlers - Number of handlers in auth_handlers
203 size_t num_auth_handlers;
206 * acct_handlers - Accounting message handlers
208 struct radius_rx_handler *acct_handlers;
211 * num_acct_handlers - Number of handlers in acct_handlers
213 size_t num_acct_handlers;
216 * msgs - Pending outgoing RADIUS messages
218 struct radius_msg_list *msgs;
221 * num_msgs - Number of pending messages in the msgs list
226 * next_radius_identifier - Next RADIUS message identifier to use
228 u8 next_radius_identifier;
231 * interim_error_cb - Interim accounting error callback
233 void (*interim_error_cb)(const u8 *addr, void *ctx);
236 * interim_error_cb_ctx - interim_error_cb() context data
238 void *interim_error_cb_ctx;
243 radius_change_server(struct radius_client_data *radius,
244 struct hostapd_radius_server *nserv,
245 struct hostapd_radius_server *oserv,
246 int sock, int sock6, int auth);
247 static int radius_client_init_acct(struct radius_client_data *radius);
248 static int radius_client_init_auth(struct radius_client_data *radius);
249 static void radius_client_auth_failover(struct radius_client_data *radius);
250 static void radius_client_acct_failover(struct radius_client_data *radius);
253 static void radius_client_msg_free(struct radius_msg_list *req)
255 radius_msg_free(req->msg);
261 * radius_client_register - Register a RADIUS client RX handler
262 * @radius: RADIUS client context from radius_client_init()
263 * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
264 * @handler: Handler for received RADIUS messages
265 * @data: Context pointer for handler callbacks
266 * Returns: 0 on success, -1 on failure
268 * This function is used to register a handler for processing received RADIUS
269 * authentication and accounting messages. The handler() callback function will
270 * be called whenever a RADIUS message is received from the active server.
272 * There can be multiple registered RADIUS message handlers. The handlers will
273 * be called in order until one of them indicates that it has processed or
274 * queued the message.
276 int radius_client_register(struct radius_client_data *radius,
278 RadiusRxResult (*handler)(struct radius_msg *msg,
279 struct radius_msg *req,
280 const u8 *shared_secret,
281 size_t shared_secret_len,
285 struct radius_rx_handler **handlers, *newh;
288 if (msg_type == RADIUS_ACCT) {
289 handlers = &radius->acct_handlers;
290 num = &radius->num_acct_handlers;
292 handlers = &radius->auth_handlers;
293 num = &radius->num_auth_handlers;
296 newh = os_realloc_array(*handlers, *num + 1,
297 sizeof(struct radius_rx_handler));
301 newh[*num].handler = handler;
302 newh[*num].data = data;
311 * radius_client_set_interim_erro_cb - Register an interim acct error callback
312 * @radius: RADIUS client context from radius_client_init()
313 * @addr: Station address from the failed message
314 * @cb: Handler for interim accounting errors
315 * @ctx: Context pointer for handler callbacks
317 * This function is used to register a handler for processing failed
318 * transmission attempts of interim accounting update messages.
320 void radius_client_set_interim_error_cb(struct radius_client_data *radius,
321 void (*cb)(const u8 *addr, void *ctx),
324 radius->interim_error_cb = cb;
325 radius->interim_error_cb_ctx = ctx;
330 * Returns >0 if message queue was flushed (i.e., the message that triggered
331 * the error is not available anymore)
333 static int radius_client_handle_send_error(struct radius_client_data *radius,
334 int s, RadiusType msg_type)
336 #ifndef CONFIG_NATIVE_WINDOWS
338 wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
339 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
340 _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
341 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
343 "Send failed - maybe interface status changed -"
344 " try to connect again");
345 if (msg_type == RADIUS_ACCT ||
346 msg_type == RADIUS_ACCT_INTERIM) {
347 radius_client_init_acct(radius);
350 radius_client_init_auth(radius);
354 #endif /* CONFIG_NATIVE_WINDOWS */
360 static int radius_client_retransmit(struct radius_client_data *radius,
361 struct radius_msg_list *entry,
364 struct hostapd_radius_servers *conf = radius->conf;
367 size_t prev_num_msgs;
369 size_t acct_delay_time_len;
371 if (entry->msg_type == RADIUS_ACCT ||
372 entry->msg_type == RADIUS_ACCT_INTERIM) {
373 if (radius->acct_sock < 0)
374 radius_client_init_acct(radius);
375 if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
376 prev_num_msgs = radius->num_msgs;
377 radius_client_acct_failover(radius);
378 if (prev_num_msgs != radius->num_msgs)
381 s = radius->acct_sock;
382 if (entry->attempts == 0)
383 conf->acct_server->requests++;
385 conf->acct_server->timeouts++;
386 conf->acct_server->retransmissions++;
389 if (radius->auth_sock < 0)
390 radius_client_init_auth(radius);
391 if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
392 prev_num_msgs = radius->num_msgs;
393 radius_client_auth_failover(radius);
394 if (prev_num_msgs != radius->num_msgs)
397 s = radius->auth_sock;
398 if (entry->attempts == 0)
399 conf->auth_server->requests++;
401 conf->auth_server->timeouts++;
402 conf->auth_server->retransmissions++;
406 if (entry->msg_type == RADIUS_ACCT_INTERIM) {
407 wpa_printf(MSG_DEBUG,
408 "RADIUS: Failed to transmit interim accounting update to "
409 MACSTR " - drop message and request a new update",
410 MAC2STR(entry->addr));
411 if (radius->interim_error_cb)
412 radius->interim_error_cb(entry->addr,
413 radius->interim_error_cb_ctx);
419 "RADIUS: No valid socket for retransmission");
423 if (entry->msg_type == RADIUS_ACCT &&
424 radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
425 &acct_delay_time, &acct_delay_time_len,
427 acct_delay_time_len == 4) {
428 struct radius_hdr *hdr;
432 * Need to assign a new identifier since attribute contents
435 hdr = radius_msg_get_hdr(entry->msg);
436 hdr->identifier = radius_client_get_id(radius);
438 /* Update Acct-Delay-Time to show wait time in queue */
439 delay_time = now - entry->first_try;
440 WPA_PUT_BE32(acct_delay_time, delay_time);
442 wpa_printf(MSG_DEBUG,
443 "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
445 radius_msg_finish_acct(entry->msg, entry->shared_secret,
446 entry->shared_secret_len);
447 if (radius->conf->msg_dumps)
448 radius_msg_dump(entry->msg);
451 /* retransmit; remove entry if too many attempts */
453 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
454 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
455 radius_msg_get_hdr(entry->msg)->identifier);
457 os_get_reltime(&entry->last_attempt);
458 buf = radius_msg_get_buf(entry->msg);
459 if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
460 if (radius_client_handle_send_error(radius, s, entry->msg_type)
465 entry->next_try = now + entry->next_wait;
466 entry->next_wait *= 2;
467 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
468 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
469 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
470 wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
478 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
480 struct radius_client_data *radius = eloop_ctx;
481 struct os_reltime now;
483 struct radius_msg_list *entry, *prev, *tmp;
484 int auth_failover = 0, acct_failover = 0;
485 size_t prev_num_msgs;
488 entry = radius->msgs;
492 os_get_reltime(&now);
497 prev_num_msgs = radius->num_msgs;
498 if (now.sec >= entry->next_try &&
499 radius_client_retransmit(radius, entry, now.sec)) {
501 prev->next = entry->next;
503 radius->msgs = entry->next;
507 radius_client_msg_free(tmp);
512 if (prev_num_msgs != radius->num_msgs) {
513 wpa_printf(MSG_DEBUG,
514 "RADIUS: Message removed from queue - restart from beginning");
515 entry = radius->msgs;
520 s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
522 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
523 (s < 0 && entry->attempts > 0)) {
524 if (entry->msg_type == RADIUS_ACCT ||
525 entry->msg_type == RADIUS_ACCT_INTERIM)
531 if (first == 0 || entry->next_try < first)
532 first = entry->next_try;
541 eloop_register_timeout(first - now.sec, 0,
542 radius_client_timer, radius, NULL);
543 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
544 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
545 "retransmit in %ld seconds",
546 (long int) (first - now.sec));
550 radius_client_auth_failover(radius);
553 radius_client_acct_failover(radius);
557 static void radius_client_auth_failover(struct radius_client_data *radius)
559 struct hostapd_radius_servers *conf = radius->conf;
560 struct hostapd_radius_server *next, *old;
561 struct radius_msg_list *entry;
564 old = conf->auth_server;
565 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
566 HOSTAPD_LEVEL_NOTICE,
567 "No response from Authentication server %s:%d - failover",
568 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
571 for (entry = radius->msgs; entry; entry = entry->next) {
572 if (entry->msg_type == RADIUS_AUTH)
577 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
578 next = conf->auth_servers;
579 conf->auth_server = next;
580 radius_change_server(radius, next, old,
581 radius->auth_serv_sock,
582 radius->auth_serv_sock6, 1);
586 static void radius_client_acct_failover(struct radius_client_data *radius)
588 struct hostapd_radius_servers *conf = radius->conf;
589 struct hostapd_radius_server *next, *old;
590 struct radius_msg_list *entry;
593 old = conf->acct_server;
594 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
595 HOSTAPD_LEVEL_NOTICE,
596 "No response from Accounting server %s:%d - failover",
597 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
600 for (entry = radius->msgs; entry; entry = entry->next) {
601 if (entry->msg_type == RADIUS_ACCT ||
602 entry->msg_type == RADIUS_ACCT_INTERIM)
607 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
608 next = conf->acct_servers;
609 conf->acct_server = next;
610 radius_change_server(radius, next, old,
611 radius->acct_serv_sock,
612 radius->acct_serv_sock6, 0);
616 static void radius_client_update_timeout(struct radius_client_data *radius)
618 struct os_reltime now;
620 struct radius_msg_list *entry;
622 eloop_cancel_timeout(radius_client_timer, radius, NULL);
624 if (radius->msgs == NULL) {
629 for (entry = radius->msgs; entry; entry = entry->next) {
630 if (first == 0 || entry->next_try < first)
631 first = entry->next_try;
634 os_get_reltime(&now);
637 eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
639 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
640 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
641 " %ld seconds", (long int) (first - now.sec));
645 static void radius_client_list_add(struct radius_client_data *radius,
646 struct radius_msg *msg,
648 const u8 *shared_secret,
649 size_t shared_secret_len, const u8 *addr)
651 struct radius_msg_list *entry, *prev;
653 if (eloop_terminated()) {
654 /* No point in adding entries to retransmit queue since event
655 * loop has already been terminated. */
656 radius_msg_free(msg);
660 entry = os_zalloc(sizeof(*entry));
662 wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
663 radius_msg_free(msg);
668 os_memcpy(entry->addr, addr, ETH_ALEN);
670 entry->msg_type = msg_type;
671 entry->shared_secret = shared_secret;
672 entry->shared_secret_len = shared_secret_len;
673 os_get_reltime(&entry->last_attempt);
674 entry->first_try = entry->last_attempt.sec;
675 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
677 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
678 entry->next = radius->msgs;
679 radius->msgs = entry;
680 radius_client_update_timeout(radius);
682 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
683 wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
685 while (entry->next) {
691 radius_client_msg_free(entry);
699 * radius_client_send - Send a RADIUS request
700 * @radius: RADIUS client context from radius_client_init()
701 * @msg: RADIUS message to be sent
702 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
703 * @addr: MAC address of the device related to this message or %NULL
704 * Returns: 0 on success, -1 on failure
706 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
707 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
708 * between accounting and interim accounting messages is that the interim
709 * message will not be retransmitted. Instead, a callback is used to indicate
710 * that the transmission failed for the specific station @addr so that a new
711 * interim accounting update message can be generated with up-to-date session
712 * data instead of trying to resend old information.
714 * The message is added on the retransmission queue and will be retransmitted
715 * automatically until a response is received or maximum number of retries
716 * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
717 * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
718 * automatically on transmission failure.
720 * The related device MAC address can be used to identify pending messages that
721 * can be removed with radius_client_flush_auth().
723 int radius_client_send(struct radius_client_data *radius,
724 struct radius_msg *msg, RadiusType msg_type,
727 struct hostapd_radius_servers *conf = radius->conf;
728 const u8 *shared_secret;
729 size_t shared_secret_len;
734 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
735 if (conf->acct_server && radius->acct_sock < 0)
736 radius_client_init_acct(radius);
738 if (conf->acct_server == NULL || radius->acct_sock < 0 ||
739 conf->acct_server->shared_secret == NULL) {
740 hostapd_logger(radius->ctx, NULL,
741 HOSTAPD_MODULE_RADIUS,
743 "No accounting server configured");
746 shared_secret = conf->acct_server->shared_secret;
747 shared_secret_len = conf->acct_server->shared_secret_len;
748 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
750 s = radius->acct_sock;
751 conf->acct_server->requests++;
753 if (conf->auth_server && radius->auth_sock < 0)
754 radius_client_init_auth(radius);
756 if (conf->auth_server == NULL || radius->auth_sock < 0 ||
757 conf->auth_server->shared_secret == NULL) {
758 hostapd_logger(radius->ctx, NULL,
759 HOSTAPD_MODULE_RADIUS,
761 "No authentication server configured");
764 shared_secret = conf->auth_server->shared_secret;
765 shared_secret_len = conf->auth_server->shared_secret_len;
766 radius_msg_finish(msg, shared_secret, shared_secret_len);
767 name = "authentication";
768 s = radius->auth_sock;
769 conf->auth_server->requests++;
772 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
773 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
776 radius_msg_dump(msg);
778 buf = radius_msg_get_buf(msg);
779 res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
781 radius_client_handle_send_error(radius, s, msg_type);
783 radius_client_list_add(radius, msg, msg_type, shared_secret,
784 shared_secret_len, addr);
790 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
792 struct radius_client_data *radius = eloop_ctx;
793 struct hostapd_radius_servers *conf = radius->conf;
794 RadiusType msg_type = (RadiusType) sock_ctx;
796 unsigned char buf[3000];
797 struct radius_msg *msg;
798 struct radius_hdr *hdr;
799 struct radius_rx_handler *handlers;
800 size_t num_handlers, i;
801 struct radius_msg_list *req, *prev_req;
802 struct os_reltime now;
803 struct hostapd_radius_server *rconf;
804 int invalid_authenticator = 0;
806 if (msg_type == RADIUS_ACCT) {
807 handlers = radius->acct_handlers;
808 num_handlers = radius->num_acct_handlers;
809 rconf = conf->acct_server;
811 handlers = radius->auth_handlers;
812 num_handlers = radius->num_auth_handlers;
813 rconf = conf->auth_server;
816 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
818 wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
821 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
822 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
824 if (len == sizeof(buf)) {
825 wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
829 msg = radius_msg_parse(buf, len);
831 wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
832 rconf->malformed_responses++;
835 hdr = radius_msg_get_hdr(msg);
837 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
838 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
840 radius_msg_dump(msg);
843 case RADIUS_CODE_ACCESS_ACCEPT:
844 rconf->access_accepts++;
846 case RADIUS_CODE_ACCESS_REJECT:
847 rconf->access_rejects++;
849 case RADIUS_CODE_ACCESS_CHALLENGE:
850 rconf->access_challenges++;
852 case RADIUS_CODE_ACCOUNTING_RESPONSE:
860 /* TODO: also match by src addr:port of the packet when using
861 * alternative RADIUS servers (?) */
862 if ((req->msg_type == msg_type ||
863 (req->msg_type == RADIUS_ACCT_INTERIM &&
864 msg_type == RADIUS_ACCT)) &&
865 radius_msg_get_hdr(req->msg)->identifier ==
874 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
876 "No matching RADIUS request found (type=%d "
877 "id=%d) - dropping packet",
878 msg_type, hdr->identifier);
882 os_get_reltime(&now);
883 roundtrip = (now.sec - req->last_attempt.sec) * 100 +
884 (now.usec - req->last_attempt.usec) / 10000;
885 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
887 "Received RADIUS packet matched with a pending "
888 "request, round trip time %d.%02d sec",
889 roundtrip / 100, roundtrip % 100);
890 rconf->round_trip_time = roundtrip;
892 /* Remove ACKed RADIUS packet from retransmit list */
894 prev_req->next = req->next;
896 radius->msgs = req->next;
899 for (i = 0; i < num_handlers; i++) {
901 res = handlers[i].handler(msg, req->msg, req->shared_secret,
902 req->shared_secret_len,
905 case RADIUS_RX_PROCESSED:
906 radius_msg_free(msg);
908 case RADIUS_RX_QUEUED:
909 radius_client_msg_free(req);
911 case RADIUS_RX_INVALID_AUTHENTICATOR:
912 invalid_authenticator++;
914 case RADIUS_RX_UNKNOWN:
915 /* continue with next handler */
920 if (invalid_authenticator)
921 rconf->bad_authenticators++;
923 rconf->unknown_types++;
924 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
925 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
926 "(type=%d code=%d id=%d)%s - dropping packet",
927 msg_type, hdr->code, hdr->identifier,
928 invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
930 radius_client_msg_free(req);
933 radius_msg_free(msg);
938 * radius_client_get_id - Get an identifier for a new RADIUS message
939 * @radius: RADIUS client context from radius_client_init()
940 * Returns: Allocated identifier
942 * This function is used to fetch a unique (among pending requests) identifier
943 * for a new RADIUS message.
945 u8 radius_client_get_id(struct radius_client_data *radius)
947 struct radius_msg_list *entry, *prev, *_remove;
948 u8 id = radius->next_radius_identifier++;
950 /* remove entries with matching id from retransmit list to avoid
951 * using new reply from the RADIUS server with an old request */
952 entry = radius->msgs;
955 if (radius_msg_get_hdr(entry->msg)->identifier == id) {
956 hostapd_logger(radius->ctx, entry->addr,
957 HOSTAPD_MODULE_RADIUS,
959 "Removing pending RADIUS message, "
960 "since its id (%d) is reused", id);
962 prev->next = entry->next;
964 radius->msgs = entry->next;
973 radius_client_msg_free(_remove);
981 * radius_client_flush - Flush all pending RADIUS client messages
982 * @radius: RADIUS client context from radius_client_init()
983 * @only_auth: Whether only authentication messages are removed
985 void radius_client_flush(struct radius_client_data *radius, int only_auth)
987 struct radius_msg_list *entry, *prev, *tmp;
993 entry = radius->msgs;
996 if (!only_auth || entry->msg_type == RADIUS_AUTH) {
998 prev->next = entry->next;
1000 radius->msgs = entry->next;
1003 entry = entry->next;
1004 radius_client_msg_free(tmp);
1008 entry = entry->next;
1012 if (radius->msgs == NULL)
1013 eloop_cancel_timeout(radius_client_timer, radius, NULL);
1017 static void radius_client_update_acct_msgs(struct radius_client_data *radius,
1018 const u8 *shared_secret,
1019 size_t shared_secret_len)
1021 struct radius_msg_list *entry;
1026 for (entry = radius->msgs; entry; entry = entry->next) {
1027 if (entry->msg_type == RADIUS_ACCT) {
1028 entry->shared_secret = shared_secret;
1029 entry->shared_secret_len = shared_secret_len;
1030 radius_msg_finish_acct(entry->msg, shared_secret,
1038 radius_change_server(struct radius_client_data *radius,
1039 struct hostapd_radius_server *nserv,
1040 struct hostapd_radius_server *oserv,
1041 int sock, int sock6, int auth)
1043 struct sockaddr_in serv, claddr;
1045 struct sockaddr_in6 serv6, claddr6;
1046 #endif /* CONFIG_IPV6 */
1047 struct sockaddr *addr, *cl_addr;
1048 socklen_t addrlen, claddrlen;
1051 struct radius_msg_list *entry;
1052 struct hostapd_radius_servers *conf = radius->conf;
1053 struct sockaddr_in disconnect_addr = {
1054 .sin_family = AF_UNSPEC,
1057 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
1060 auth ? "Authentication" : "Accounting",
1061 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
1064 if (oserv && oserv == nserv) {
1065 /* Reconnect to same server, flush */
1067 radius_client_flush(radius, 1);
1070 if (oserv && oserv != nserv &&
1071 (nserv->shared_secret_len != oserv->shared_secret_len ||
1072 os_memcmp(nserv->shared_secret, oserv->shared_secret,
1073 nserv->shared_secret_len) != 0)) {
1074 /* Pending RADIUS packets used different shared secret, so
1075 * they need to be modified. Update accounting message
1076 * authenticators here. Authentication messages are removed
1077 * since they would require more changes and the new RADIUS
1078 * server may not be prepared to receive them anyway due to
1079 * missing state information. Client will likely retry
1080 * authentication, so this should not be an issue. */
1082 radius_client_flush(radius, 1);
1084 radius_client_update_acct_msgs(
1085 radius, nserv->shared_secret,
1086 nserv->shared_secret_len);
1090 /* Reset retry counters for the new server */
1091 for (entry = radius->msgs; oserv && oserv != nserv && entry;
1092 entry = entry->next) {
1093 if ((auth && entry->msg_type != RADIUS_AUTH) ||
1094 (!auth && entry->msg_type != RADIUS_ACCT))
1096 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
1097 entry->attempts = 0;
1098 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
1102 eloop_cancel_timeout(radius_client_timer, radius, NULL);
1103 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
1104 radius_client_timer, radius, NULL);
1107 switch (nserv->addr.af) {
1109 os_memset(&serv, 0, sizeof(serv));
1110 serv.sin_family = AF_INET;
1111 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
1112 serv.sin_port = htons(nserv->port);
1113 addr = (struct sockaddr *) &serv;
1114 addrlen = sizeof(serv);
1119 os_memset(&serv6, 0, sizeof(serv6));
1120 serv6.sin6_family = AF_INET6;
1121 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
1122 sizeof(struct in6_addr));
1123 serv6.sin6_port = htons(nserv->port);
1124 addr = (struct sockaddr *) &serv6;
1125 addrlen = sizeof(serv6);
1128 #endif /* CONFIG_IPV6 */
1134 wpa_printf(MSG_INFO,
1135 "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
1136 nserv->addr.af, sock, sock6, auth);
1140 if (conf->force_client_addr) {
1141 switch (conf->client_addr.af) {
1143 os_memset(&claddr, 0, sizeof(claddr));
1144 claddr.sin_family = AF_INET;
1145 claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
1146 claddr.sin_port = htons(0);
1147 cl_addr = (struct sockaddr *) &claddr;
1148 claddrlen = sizeof(claddr);
1152 os_memset(&claddr6, 0, sizeof(claddr6));
1153 claddr6.sin6_family = AF_INET6;
1154 os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
1155 sizeof(struct in6_addr));
1156 claddr6.sin6_port = htons(0);
1157 cl_addr = (struct sockaddr *) &claddr6;
1158 claddrlen = sizeof(claddr6);
1160 #endif /* CONFIG_IPV6 */
1165 if (bind(sel_sock, cl_addr, claddrlen) < 0) {
1166 wpa_printf(MSG_INFO, "bind[radius]: %s",
1172 /* Force a reconnect by disconnecting the socket first */
1173 if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
1174 sizeof(disconnect_addr)) < 0)
1175 wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
1177 if (connect(sel_sock, addr, addrlen) < 0) {
1178 wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
1182 #ifndef CONFIG_NATIVE_WINDOWS
1183 switch (nserv->addr.af) {
1185 claddrlen = sizeof(claddr);
1186 if (getsockname(sel_sock, (struct sockaddr *) &claddr,
1188 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1189 inet_ntoa(claddr.sin_addr),
1190 ntohs(claddr.sin_port));
1195 claddrlen = sizeof(claddr6);
1196 if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
1198 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1199 inet_ntop(AF_INET6, &claddr6.sin6_addr,
1200 abuf, sizeof(abuf)),
1201 ntohs(claddr6.sin6_port));
1205 #endif /* CONFIG_IPV6 */
1207 #endif /* CONFIG_NATIVE_WINDOWS */
1210 radius->auth_sock = sel_sock;
1212 radius->acct_sock = sel_sock;
1218 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1220 struct radius_client_data *radius = eloop_ctx;
1221 struct hostapd_radius_servers *conf = radius->conf;
1222 struct hostapd_radius_server *oserv;
1224 if (radius->auth_sock >= 0 && conf->auth_servers &&
1225 conf->auth_server != conf->auth_servers) {
1226 oserv = conf->auth_server;
1227 conf->auth_server = conf->auth_servers;
1228 if (radius_change_server(radius, conf->auth_server, oserv,
1229 radius->auth_serv_sock,
1230 radius->auth_serv_sock6, 1) < 0) {
1231 conf->auth_server = oserv;
1232 radius_change_server(radius, oserv, conf->auth_server,
1233 radius->auth_serv_sock,
1234 radius->auth_serv_sock6, 1);
1238 if (radius->acct_sock >= 0 && conf->acct_servers &&
1239 conf->acct_server != conf->acct_servers) {
1240 oserv = conf->acct_server;
1241 conf->acct_server = conf->acct_servers;
1242 if (radius_change_server(radius, conf->acct_server, oserv,
1243 radius->acct_serv_sock,
1244 radius->acct_serv_sock6, 0) < 0) {
1245 conf->acct_server = oserv;
1246 radius_change_server(radius, oserv, conf->acct_server,
1247 radius->acct_serv_sock,
1248 radius->acct_serv_sock6, 0);
1252 if (conf->retry_primary_interval)
1253 eloop_register_timeout(conf->retry_primary_interval, 0,
1254 radius_retry_primary_timer, radius,
1259 static int radius_client_disable_pmtu_discovery(int s)
1262 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1263 /* Turn off Path MTU discovery on IPv4/UDP sockets. */
1264 int action = IP_PMTUDISC_DONT;
1265 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1268 wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1275 static void radius_close_auth_sockets(struct radius_client_data *radius)
1277 radius->auth_sock = -1;
1279 if (radius->auth_serv_sock >= 0) {
1280 eloop_unregister_read_sock(radius->auth_serv_sock);
1281 close(radius->auth_serv_sock);
1282 radius->auth_serv_sock = -1;
1285 if (radius->auth_serv_sock6 >= 0) {
1286 eloop_unregister_read_sock(radius->auth_serv_sock6);
1287 close(radius->auth_serv_sock6);
1288 radius->auth_serv_sock6 = -1;
1290 #endif /* CONFIG_IPV6 */
1294 static void radius_close_acct_sockets(struct radius_client_data *radius)
1296 radius->acct_sock = -1;
1298 if (radius->acct_serv_sock >= 0) {
1299 eloop_unregister_read_sock(radius->acct_serv_sock);
1300 close(radius->acct_serv_sock);
1301 radius->acct_serv_sock = -1;
1304 if (radius->acct_serv_sock6 >= 0) {
1305 eloop_unregister_read_sock(radius->acct_serv_sock6);
1306 close(radius->acct_serv_sock6);
1307 radius->acct_serv_sock6 = -1;
1309 #endif /* CONFIG_IPV6 */
1313 static int radius_client_init_auth(struct radius_client_data *radius)
1315 struct hostapd_radius_servers *conf = radius->conf;
1318 radius_close_auth_sockets(radius);
1320 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1321 if (radius->auth_serv_sock < 0)
1322 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1325 radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
1330 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1331 if (radius->auth_serv_sock6 < 0)
1332 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1336 #endif /* CONFIG_IPV6 */
1341 radius_change_server(radius, conf->auth_server, NULL,
1342 radius->auth_serv_sock, radius->auth_serv_sock6,
1345 if (radius->auth_serv_sock >= 0 &&
1346 eloop_register_read_sock(radius->auth_serv_sock,
1347 radius_client_receive, radius,
1348 (void *) RADIUS_AUTH)) {
1349 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1350 radius_close_auth_sockets(radius);
1355 if (radius->auth_serv_sock6 >= 0 &&
1356 eloop_register_read_sock(radius->auth_serv_sock6,
1357 radius_client_receive, radius,
1358 (void *) RADIUS_AUTH)) {
1359 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1360 radius_close_auth_sockets(radius);
1363 #endif /* CONFIG_IPV6 */
1369 static int radius_client_init_acct(struct radius_client_data *radius)
1371 struct hostapd_radius_servers *conf = radius->conf;
1374 radius_close_acct_sockets(radius);
1376 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1377 if (radius->acct_serv_sock < 0)
1378 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1381 radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
1386 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1387 if (radius->acct_serv_sock6 < 0)
1388 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1392 #endif /* CONFIG_IPV6 */
1397 radius_change_server(radius, conf->acct_server, NULL,
1398 radius->acct_serv_sock, radius->acct_serv_sock6,
1401 if (radius->acct_serv_sock >= 0 &&
1402 eloop_register_read_sock(radius->acct_serv_sock,
1403 radius_client_receive, radius,
1404 (void *) RADIUS_ACCT)) {
1405 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1406 radius_close_acct_sockets(radius);
1411 if (radius->acct_serv_sock6 >= 0 &&
1412 eloop_register_read_sock(radius->acct_serv_sock6,
1413 radius_client_receive, radius,
1414 (void *) RADIUS_ACCT)) {
1415 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1416 radius_close_acct_sockets(radius);
1419 #endif /* CONFIG_IPV6 */
1426 * radius_client_init - Initialize RADIUS client
1427 * @ctx: Callback context to be used in hostapd_logger() calls
1428 * @conf: RADIUS client configuration (RADIUS servers)
1429 * Returns: Pointer to private RADIUS client context or %NULL on failure
1431 * The caller is responsible for keeping the configuration data available for
1432 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1433 * called for the returned context pointer.
1435 struct radius_client_data *
1436 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1438 struct radius_client_data *radius;
1440 radius = os_zalloc(sizeof(struct radius_client_data));
1445 radius->conf = conf;
1446 radius->auth_serv_sock = radius->acct_serv_sock =
1447 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1448 radius->auth_sock = radius->acct_sock = -1;
1450 if (conf->auth_server && radius_client_init_auth(radius)) {
1451 radius_client_deinit(radius);
1455 if (conf->acct_server && radius_client_init_acct(radius)) {
1456 radius_client_deinit(radius);
1460 if (conf->retry_primary_interval)
1461 eloop_register_timeout(conf->retry_primary_interval, 0,
1462 radius_retry_primary_timer, radius,
1470 * radius_client_deinit - Deinitialize RADIUS client
1471 * @radius: RADIUS client context from radius_client_init()
1473 void radius_client_deinit(struct radius_client_data *radius)
1478 radius_close_auth_sockets(radius);
1479 radius_close_acct_sockets(radius);
1481 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1483 radius_client_flush(radius, 0);
1484 os_free(radius->auth_handlers);
1485 os_free(radius->acct_handlers);
1491 * radius_client_flush_auth - Flush pending RADIUS messages for an address
1492 * @radius: RADIUS client context from radius_client_init()
1493 * @addr: MAC address of the related device
1495 * This function can be used to remove pending RADIUS authentication messages
1496 * that are related to a specific device. The addr parameter is matched with
1497 * the one used in radius_client_send() call that was used to transmit the
1498 * authentication request.
1500 void radius_client_flush_auth(struct radius_client_data *radius,
1503 struct radius_msg_list *entry, *prev, *tmp;
1506 entry = radius->msgs;
1508 if (entry->msg_type == RADIUS_AUTH &&
1509 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1510 hostapd_logger(radius->ctx, addr,
1511 HOSTAPD_MODULE_RADIUS,
1512 HOSTAPD_LEVEL_DEBUG,
1513 "Removing pending RADIUS authentication"
1514 " message for removed client");
1517 prev->next = entry->next;
1519 radius->msgs = entry->next;
1522 entry = entry->next;
1523 radius_client_msg_free(tmp);
1529 entry = entry->next;
1534 static int radius_client_dump_auth_server(char *buf, size_t buflen,
1535 struct hostapd_radius_server *serv,
1536 struct radius_client_data *cli)
1539 struct radius_msg_list *msg;
1543 for (msg = cli->msgs; msg; msg = msg->next) {
1544 if (msg->msg_type == RADIUS_AUTH)
1549 return os_snprintf(buf, buflen,
1550 "radiusAuthServerIndex=%d\n"
1551 "radiusAuthServerAddress=%s\n"
1552 "radiusAuthClientServerPortNumber=%d\n"
1553 "radiusAuthClientRoundTripTime=%d\n"
1554 "radiusAuthClientAccessRequests=%u\n"
1555 "radiusAuthClientAccessRetransmissions=%u\n"
1556 "radiusAuthClientAccessAccepts=%u\n"
1557 "radiusAuthClientAccessRejects=%u\n"
1558 "radiusAuthClientAccessChallenges=%u\n"
1559 "radiusAuthClientMalformedAccessResponses=%u\n"
1560 "radiusAuthClientBadAuthenticators=%u\n"
1561 "radiusAuthClientPendingRequests=%u\n"
1562 "radiusAuthClientTimeouts=%u\n"
1563 "radiusAuthClientUnknownTypes=%u\n"
1564 "radiusAuthClientPacketsDropped=%u\n",
1566 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1568 serv->round_trip_time,
1570 serv->retransmissions,
1571 serv->access_accepts,
1572 serv->access_rejects,
1573 serv->access_challenges,
1574 serv->malformed_responses,
1575 serv->bad_authenticators,
1578 serv->unknown_types,
1579 serv->packets_dropped);
1583 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1584 struct hostapd_radius_server *serv,
1585 struct radius_client_data *cli)
1588 struct radius_msg_list *msg;
1592 for (msg = cli->msgs; msg; msg = msg->next) {
1593 if (msg->msg_type == RADIUS_ACCT ||
1594 msg->msg_type == RADIUS_ACCT_INTERIM)
1599 return os_snprintf(buf, buflen,
1600 "radiusAccServerIndex=%d\n"
1601 "radiusAccServerAddress=%s\n"
1602 "radiusAccClientServerPortNumber=%d\n"
1603 "radiusAccClientRoundTripTime=%d\n"
1604 "radiusAccClientRequests=%u\n"
1605 "radiusAccClientRetransmissions=%u\n"
1606 "radiusAccClientResponses=%u\n"
1607 "radiusAccClientMalformedResponses=%u\n"
1608 "radiusAccClientBadAuthenticators=%u\n"
1609 "radiusAccClientPendingRequests=%u\n"
1610 "radiusAccClientTimeouts=%u\n"
1611 "radiusAccClientUnknownTypes=%u\n"
1612 "radiusAccClientPacketsDropped=%u\n",
1614 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1616 serv->round_trip_time,
1618 serv->retransmissions,
1620 serv->malformed_responses,
1621 serv->bad_authenticators,
1624 serv->unknown_types,
1625 serv->packets_dropped);
1630 * radius_client_get_mib - Get RADIUS client MIB information
1631 * @radius: RADIUS client context from radius_client_init()
1632 * @buf: Buffer for returning MIB data in text format
1633 * @buflen: Maximum buf length in octets
1634 * Returns: Number of octets written into the buffer
1636 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1639 struct hostapd_radius_servers *conf;
1641 struct hostapd_radius_server *serv;
1647 conf = radius->conf;
1649 if (conf->auth_servers) {
1650 for (i = 0; i < conf->num_auth_servers; i++) {
1651 serv = &conf->auth_servers[i];
1652 count += radius_client_dump_auth_server(
1653 buf + count, buflen - count, serv,
1654 serv == conf->auth_server ?
1659 if (conf->acct_servers) {
1660 for (i = 0; i < conf->num_acct_servers; i++) {
1661 serv = &conf->acct_servers[i];
1662 count += radius_client_dump_acct_server(
1663 buf + count, buflen - count, serv,
1664 serv == conf->acct_server ?
1673 void radius_client_reconfig(struct radius_client_data *radius,
1674 struct hostapd_radius_servers *conf)
1677 radius->conf = conf;