Add resident.conf(5) and varsym.conf(5) manual pages.
[dragonfly/vkernel-mp.git] / contrib / hostapd-0.4.9 / radius_client.c
blob690208445ba357a3a84a6796bbda5984f00121d4
1 /*
2 * Host AP (software wireless LAN access point) user space daemon for
3 * Host AP kernel driver / RADIUS client
4 * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
11 * license.
13 * See README and COPYING for more details.
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <time.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <errno.h>
24 #ifndef CONFIG_NATIVE_WINDOWS
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <arpa/inet.h>
28 #endif /* CONFIG_NATIVE_WINDOWS */
30 #include "hostapd.h"
31 #include "radius.h"
32 #include "radius_client.h"
33 #include "eloop.h"
35 /* Defaults for RADIUS retransmit values (exponential backoff) */
36 #define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
37 #define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
38 #define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
39 * before entry is removed from retransmit
40 * list */
41 #define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
42 * list (oldest will be removed, if this
43 * limit is exceeded) */
44 #define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
45 * many failed retry attempts */
48 struct radius_rx_handler {
49 RadiusRxResult (*handler)(struct radius_msg *msg,
50 struct radius_msg *req,
51 u8 *shared_secret, size_t shared_secret_len,
52 void *data);
53 void *data;
57 /* RADIUS message retransmit list */
58 struct radius_msg_list {
59 u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
60 * for the same STA. */
61 struct radius_msg *msg;
62 RadiusType msg_type;
63 time_t first_try;
64 time_t next_try;
65 int attempts;
66 int next_wait;
67 struct timeval last_attempt;
69 u8 *shared_secret;
70 size_t shared_secret_len;
72 /* TODO: server config with failover to backup server(s) */
74 struct radius_msg_list *next;
78 struct radius_client_data {
79 void *ctx;
80 struct hostapd_radius_servers *conf;
82 int auth_serv_sock; /* socket for authentication RADIUS messages */
83 int acct_serv_sock; /* socket for accounting RADIUS messages */
84 int auth_serv_sock6;
85 int acct_serv_sock6;
86 int auth_sock; /* currently used socket */
87 int acct_sock; /* currently used socket */
89 struct radius_rx_handler *auth_handlers;
90 size_t num_auth_handlers;
91 struct radius_rx_handler *acct_handlers;
92 size_t num_acct_handlers;
94 struct radius_msg_list *msgs;
95 size_t num_msgs;
97 u8 next_radius_identifier;
101 static int
102 radius_change_server(struct radius_client_data *radius,
103 struct hostapd_radius_server *nserv,
104 struct hostapd_radius_server *oserv,
105 int sock, int sock6, int auth);
106 static int radius_client_init_acct(struct radius_client_data *radius);
107 static int radius_client_init_auth(struct radius_client_data *radius);
110 static void radius_client_msg_free(struct radius_msg_list *req)
112 radius_msg_free(req->msg);
113 free(req->msg);
114 free(req);
118 int radius_client_register(struct radius_client_data *radius,
119 RadiusType msg_type,
120 RadiusRxResult (*handler)(struct radius_msg *msg,
121 struct radius_msg *req,
122 u8 *shared_secret,
123 size_t shared_secret_len,
124 void *data),
125 void *data)
127 struct radius_rx_handler **handlers, *newh;
128 size_t *num;
130 if (msg_type == RADIUS_ACCT) {
131 handlers = &radius->acct_handlers;
132 num = &radius->num_acct_handlers;
133 } else {
134 handlers = &radius->auth_handlers;
135 num = &radius->num_auth_handlers;
138 newh = (struct radius_rx_handler *)
139 realloc(*handlers,
140 (*num + 1) * sizeof(struct radius_rx_handler));
141 if (newh == NULL)
142 return -1;
144 newh[*num].handler = handler;
145 newh[*num].data = data;
146 (*num)++;
147 *handlers = newh;
149 return 0;
153 static void radius_client_handle_send_error(struct radius_client_data *radius,
154 int s, RadiusType msg_type)
156 #ifndef CONFIG_NATIVE_WINDOWS
157 int _errno = errno;
158 perror("send[RADIUS]");
159 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
160 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
161 HOSTAPD_LEVEL_INFO,
162 "Send failed - maybe interface status changed -"
163 " try to connect again");
164 eloop_unregister_read_sock(s);
165 close(s);
166 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
167 radius_client_init_acct(radius);
168 else
169 radius_client_init_auth(radius);
171 #endif /* CONFIG_NATIVE_WINDOWS */
175 static int radius_client_retransmit(struct radius_client_data *radius,
176 struct radius_msg_list *entry, time_t now)
178 struct hostapd_radius_servers *conf = radius->conf;
179 int s;
181 if (entry->msg_type == RADIUS_ACCT ||
182 entry->msg_type == RADIUS_ACCT_INTERIM) {
183 s = radius->acct_sock;
184 if (entry->attempts == 0)
185 conf->acct_server->requests++;
186 else {
187 conf->acct_server->timeouts++;
188 conf->acct_server->retransmissions++;
190 } else {
191 s = radius->auth_sock;
192 if (entry->attempts == 0)
193 conf->auth_server->requests++;
194 else {
195 conf->auth_server->timeouts++;
196 conf->auth_server->retransmissions++;
200 /* retransmit; remove entry if too many attempts */
201 entry->attempts++;
202 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
203 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
204 entry->msg->hdr->identifier);
206 gettimeofday(&entry->last_attempt, NULL);
207 if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
208 radius_client_handle_send_error(radius, s, entry->msg_type);
210 entry->next_try = now + entry->next_wait;
211 entry->next_wait *= 2;
212 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
213 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
214 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
215 printf("Removing un-ACKed RADIUS message due to too many "
216 "failed retransmit attempts\n");
217 return 1;
220 return 0;
224 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
226 struct radius_client_data *radius = eloop_ctx;
227 struct hostapd_radius_servers *conf = radius->conf;
228 time_t now, first;
229 struct radius_msg_list *entry, *prev, *tmp;
230 int auth_failover = 0, acct_failover = 0;
231 char abuf[50];
233 entry = radius->msgs;
234 if (!entry)
235 return;
237 time(&now);
238 first = 0;
240 prev = NULL;
241 while (entry) {
242 if (now >= entry->next_try &&
243 radius_client_retransmit(radius, entry, now)) {
244 if (prev)
245 prev->next = entry->next;
246 else
247 radius->msgs = entry->next;
249 tmp = entry;
250 entry = entry->next;
251 radius_client_msg_free(tmp);
252 radius->num_msgs--;
253 continue;
256 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
257 if (entry->msg_type == RADIUS_ACCT ||
258 entry->msg_type == RADIUS_ACCT_INTERIM)
259 acct_failover++;
260 else
261 auth_failover++;
264 if (first == 0 || entry->next_try < first)
265 first = entry->next_try;
267 prev = entry;
268 entry = entry->next;
271 if (radius->msgs) {
272 if (first < now)
273 first = now;
274 eloop_register_timeout(first - now, 0,
275 radius_client_timer, radius, NULL);
276 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
277 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
278 "retransmit in %ld seconds",
279 (long int) (first - now));
282 if (auth_failover && conf->num_auth_servers > 1) {
283 struct hostapd_radius_server *next, *old;
284 old = conf->auth_server;
285 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
286 HOSTAPD_LEVEL_NOTICE,
287 "No response from Authentication server "
288 "%s:%d - failover",
289 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
290 old->port);
292 for (entry = radius->msgs; entry; entry = entry->next) {
293 if (entry->msg_type == RADIUS_AUTH)
294 old->timeouts++;
297 next = old + 1;
298 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
299 next = conf->auth_servers;
300 conf->auth_server = next;
301 radius_change_server(radius, next, old,
302 radius->auth_serv_sock,
303 radius->auth_serv_sock6, 1);
306 if (acct_failover && conf->num_acct_servers > 1) {
307 struct hostapd_radius_server *next, *old;
308 old = conf->acct_server;
309 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
310 HOSTAPD_LEVEL_NOTICE,
311 "No response from Accounting server "
312 "%s:%d - failover",
313 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
314 old->port);
316 for (entry = radius->msgs; entry; entry = entry->next) {
317 if (entry->msg_type == RADIUS_ACCT ||
318 entry->msg_type == RADIUS_ACCT_INTERIM)
319 old->timeouts++;
322 next = old + 1;
323 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
324 next = conf->acct_servers;
325 conf->acct_server = next;
326 radius_change_server(radius, next, old,
327 radius->acct_serv_sock,
328 radius->acct_serv_sock6, 0);
333 static void radius_client_update_timeout(struct radius_client_data *radius)
335 time_t now, first;
336 struct radius_msg_list *entry;
338 eloop_cancel_timeout(radius_client_timer, radius, NULL);
340 if (radius->msgs == NULL) {
341 return;
344 first = 0;
345 for (entry = radius->msgs; entry; entry = entry->next) {
346 if (first == 0 || entry->next_try < first)
347 first = entry->next_try;
350 time(&now);
351 if (first < now)
352 first = now;
353 eloop_register_timeout(first - now, 0, radius_client_timer, radius,
354 NULL);
355 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
356 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
357 " %ld seconds\n", (long int) (first - now));
361 static void radius_client_list_add(struct radius_client_data *radius,
362 struct radius_msg *msg,
363 RadiusType msg_type, u8 *shared_secret,
364 size_t shared_secret_len, u8 *addr)
366 struct radius_msg_list *entry, *prev;
368 if (eloop_terminated()) {
369 /* No point in adding entries to retransmit queue since event
370 * loop has already been terminated. */
371 radius_msg_free(msg);
372 free(msg);
373 return;
376 entry = malloc(sizeof(*entry));
377 if (entry == NULL) {
378 printf("Failed to add RADIUS packet into retransmit list\n");
379 radius_msg_free(msg);
380 free(msg);
381 return;
384 memset(entry, 0, sizeof(*entry));
385 if (addr)
386 memcpy(entry->addr, addr, ETH_ALEN);
387 entry->msg = msg;
388 entry->msg_type = msg_type;
389 entry->shared_secret = shared_secret;
390 entry->shared_secret_len = shared_secret_len;
391 time(&entry->first_try);
392 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
393 entry->attempts = 1;
394 gettimeofday(&entry->last_attempt, NULL);
395 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
396 entry->next = radius->msgs;
397 radius->msgs = entry;
398 radius_client_update_timeout(radius);
400 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
401 printf("Removing the oldest un-ACKed RADIUS packet due to "
402 "retransmit list limits.\n");
403 prev = NULL;
404 while (entry->next) {
405 prev = entry;
406 entry = entry->next;
408 if (prev) {
409 prev->next = NULL;
410 radius_client_msg_free(entry);
412 } else
413 radius->num_msgs++;
417 static void radius_client_list_del(struct radius_client_data *radius,
418 RadiusType msg_type, u8 *addr)
420 struct radius_msg_list *entry, *prev, *tmp;
422 if (addr == NULL)
423 return;
425 entry = radius->msgs;
426 prev = NULL;
427 while (entry) {
428 if (entry->msg_type == msg_type &&
429 memcmp(entry->addr, addr, ETH_ALEN) == 0) {
430 if (prev)
431 prev->next = entry->next;
432 else
433 radius->msgs = entry->next;
434 tmp = entry;
435 entry = entry->next;
436 hostapd_logger(radius->ctx, addr,
437 HOSTAPD_MODULE_RADIUS,
438 HOSTAPD_LEVEL_DEBUG,
439 "Removing matching RADIUS message");
440 radius_client_msg_free(tmp);
441 radius->num_msgs--;
442 continue;
444 prev = entry;
445 entry = entry->next;
450 int radius_client_send(struct radius_client_data *radius,
451 struct radius_msg *msg, RadiusType msg_type, u8 *addr)
453 struct hostapd_radius_servers *conf = radius->conf;
454 u8 *shared_secret;
455 size_t shared_secret_len;
456 char *name;
457 int s, res;
459 if (msg_type == RADIUS_ACCT_INTERIM) {
460 /* Remove any pending interim acct update for the same STA. */
461 radius_client_list_del(radius, msg_type, addr);
464 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
465 shared_secret = conf->acct_server->shared_secret;
466 shared_secret_len = conf->acct_server->shared_secret_len;
467 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
468 name = "accounting";
469 s = radius->acct_sock;
470 conf->acct_server->requests++;
471 } else {
472 shared_secret = conf->auth_server->shared_secret;
473 shared_secret_len = conf->auth_server->shared_secret_len;
474 radius_msg_finish(msg, shared_secret, shared_secret_len);
475 name = "authentication";
476 s = radius->auth_sock;
477 conf->auth_server->requests++;
480 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
481 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
482 "server", name);
483 if (conf->msg_dumps)
484 radius_msg_dump(msg);
486 res = send(s, msg->buf, msg->buf_used, 0);
487 if (res < 0)
488 radius_client_handle_send_error(radius, s, msg_type);
490 radius_client_list_add(radius, msg, msg_type, shared_secret,
491 shared_secret_len, addr);
493 return res;
497 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
499 struct radius_client_data *radius = eloop_ctx;
500 struct hostapd_radius_servers *conf = radius->conf;
501 RadiusType msg_type = (RadiusType) sock_ctx;
502 int len, i, roundtrip;
503 unsigned char buf[3000];
504 struct radius_msg *msg;
505 struct radius_rx_handler *handlers;
506 size_t num_handlers;
507 struct radius_msg_list *req, *prev_req;
508 struct timeval tv;
509 struct hostapd_radius_server *rconf;
510 int invalid_authenticator = 0;
512 if (msg_type == RADIUS_ACCT) {
513 handlers = radius->acct_handlers;
514 num_handlers = radius->num_acct_handlers;
515 rconf = conf->acct_server;
516 } else {
517 handlers = radius->auth_handlers;
518 num_handlers = radius->num_auth_handlers;
519 rconf = conf->auth_server;
522 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
523 if (len < 0) {
524 perror("recv[RADIUS]");
525 return;
527 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
528 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
529 "server", len);
530 if (len == sizeof(buf)) {
531 printf("Possibly too long UDP frame for our buffer - "
532 "dropping it\n");
533 return;
536 msg = radius_msg_parse(buf, len);
537 if (msg == NULL) {
538 printf("Parsing incoming RADIUS frame failed\n");
539 rconf->malformed_responses++;
540 return;
543 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
544 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
545 if (conf->msg_dumps)
546 radius_msg_dump(msg);
548 switch (msg->hdr->code) {
549 case RADIUS_CODE_ACCESS_ACCEPT:
550 rconf->access_accepts++;
551 break;
552 case RADIUS_CODE_ACCESS_REJECT:
553 rconf->access_rejects++;
554 break;
555 case RADIUS_CODE_ACCESS_CHALLENGE:
556 rconf->access_challenges++;
557 break;
558 case RADIUS_CODE_ACCOUNTING_RESPONSE:
559 rconf->responses++;
560 break;
563 prev_req = NULL;
564 req = radius->msgs;
565 while (req) {
566 /* TODO: also match by src addr:port of the packet when using
567 * alternative RADIUS servers (?) */
568 if ((req->msg_type == msg_type ||
569 (req->msg_type == RADIUS_ACCT_INTERIM &&
570 msg_type == RADIUS_ACCT)) &&
571 req->msg->hdr->identifier == msg->hdr->identifier)
572 break;
574 prev_req = req;
575 req = req->next;
578 if (req == NULL) {
579 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
580 HOSTAPD_LEVEL_DEBUG,
581 "No matching RADIUS request found (type=%d "
582 "id=%d) - dropping packet",
583 msg_type, msg->hdr->identifier);
584 goto fail;
587 gettimeofday(&tv, NULL);
588 roundtrip = (tv.tv_sec - req->last_attempt.tv_sec) * 100 +
589 (tv.tv_usec - req->last_attempt.tv_usec) / 10000;
590 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
591 HOSTAPD_LEVEL_DEBUG,
592 "Received RADIUS packet matched with a pending "
593 "request, round trip time %d.%02d sec",
594 roundtrip / 100, roundtrip % 100);
595 rconf->round_trip_time = roundtrip;
597 /* Remove ACKed RADIUS packet from retransmit list */
598 if (prev_req)
599 prev_req->next = req->next;
600 else
601 radius->msgs = req->next;
602 radius->num_msgs--;
604 for (i = 0; i < num_handlers; i++) {
605 RadiusRxResult res;
606 res = handlers[i].handler(msg, req->msg, req->shared_secret,
607 req->shared_secret_len,
608 handlers[i].data);
609 switch (res) {
610 case RADIUS_RX_PROCESSED:
611 radius_msg_free(msg);
612 free(msg);
613 /* continue */
614 case RADIUS_RX_QUEUED:
615 radius_client_msg_free(req);
616 return;
617 case RADIUS_RX_INVALID_AUTHENTICATOR:
618 invalid_authenticator++;
619 /* continue */
620 case RADIUS_RX_UNKNOWN:
621 /* continue with next handler */
622 break;
626 if (invalid_authenticator)
627 rconf->bad_authenticators++;
628 else
629 rconf->unknown_types++;
630 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
631 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
632 "(type=%d code=%d id=%d)%s - dropping packet",
633 msg_type, msg->hdr->code, msg->hdr->identifier,
634 invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
635 "");
636 radius_client_msg_free(req);
638 fail:
639 radius_msg_free(msg);
640 free(msg);
644 u8 radius_client_get_id(struct radius_client_data *radius)
646 struct radius_msg_list *entry, *prev, *remove;
647 u8 id = radius->next_radius_identifier++;
649 /* remove entries with matching id from retransmit list to avoid
650 * using new reply from the RADIUS server with an old request */
651 entry = radius->msgs;
652 prev = NULL;
653 while (entry) {
654 if (entry->msg->hdr->identifier == id) {
655 hostapd_logger(radius->ctx, entry->addr,
656 HOSTAPD_MODULE_RADIUS,
657 HOSTAPD_LEVEL_DEBUG,
658 "Removing pending RADIUS message, "
659 "since its id (%d) is reused", id);
660 if (prev)
661 prev->next = entry->next;
662 else
663 radius->msgs = entry->next;
664 remove = entry;
665 } else {
666 remove = NULL;
667 prev = entry;
669 entry = entry->next;
671 if (remove)
672 radius_client_msg_free(remove);
675 return id;
679 void radius_client_flush(struct radius_client_data *radius)
681 struct radius_msg_list *entry, *prev;
683 if (!radius)
684 return;
686 eloop_cancel_timeout(radius_client_timer, radius, NULL);
688 entry = radius->msgs;
689 radius->msgs = NULL;
690 radius->num_msgs = 0;
691 while (entry) {
692 prev = entry;
693 entry = entry->next;
694 radius_client_msg_free(prev);
699 static int
700 radius_change_server(struct radius_client_data *radius,
701 struct hostapd_radius_server *nserv,
702 struct hostapd_radius_server *oserv,
703 int sock, int sock6, int auth)
705 struct sockaddr_in serv;
706 #ifdef CONFIG_IPV6
707 struct sockaddr_in6 serv6;
708 #endif /* CONFIG_IPV6 */
709 struct sockaddr *addr;
710 socklen_t addrlen;
711 char abuf[50];
712 int sel_sock;
714 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
715 HOSTAPD_LEVEL_INFO,
716 "%s server %s:%d",
717 auth ? "Authentication" : "Accounting",
718 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
719 nserv->port);
721 if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
722 memcmp(nserv->shared_secret, oserv->shared_secret,
723 nserv->shared_secret_len) != 0) {
724 /* Pending RADIUS packets used different shared
725 * secret, so they would need to be modified. Could
726 * update all message authenticators and
727 * User-Passwords, etc. and retry with new server. For
728 * now, just drop all pending packets. */
729 radius_client_flush(radius);
730 } else {
731 /* Reset retry counters for the new server */
732 struct radius_msg_list *entry;
733 entry = radius->msgs;
734 while (entry) {
735 entry->next_try = entry->first_try +
736 RADIUS_CLIENT_FIRST_WAIT;
737 entry->attempts = 0;
738 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
739 entry = entry->next;
741 if (radius->msgs) {
742 eloop_cancel_timeout(radius_client_timer, radius,
743 NULL);
744 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
745 radius_client_timer, radius,
746 NULL);
750 switch (nserv->addr.af) {
751 case AF_INET:
752 memset(&serv, 0, sizeof(serv));
753 serv.sin_family = AF_INET;
754 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
755 serv.sin_port = htons(nserv->port);
756 addr = (struct sockaddr *) &serv;
757 addrlen = sizeof(serv);
758 sel_sock = sock;
759 break;
760 #ifdef CONFIG_IPV6
761 case AF_INET6:
762 memset(&serv6, 0, sizeof(serv6));
763 serv6.sin6_family = AF_INET6;
764 memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
765 sizeof(struct in6_addr));
766 serv6.sin6_port = htons(nserv->port);
767 addr = (struct sockaddr *) &serv6;
768 addrlen = sizeof(serv6);
769 sel_sock = sock6;
770 break;
771 #endif /* CONFIG_IPV6 */
772 default:
773 return -1;
776 if (connect(sel_sock, addr, addrlen) < 0) {
777 perror("connect[radius]");
778 return -1;
781 if (auth)
782 radius->auth_sock = sel_sock;
783 else
784 radius->acct_sock = sel_sock;
786 return 0;
790 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
792 struct radius_client_data *radius = eloop_ctx;
793 struct hostapd_radius_servers *conf = radius->conf;
794 struct hostapd_radius_server *oserv;
796 if (radius->auth_sock >= 0 && conf->auth_servers &&
797 conf->auth_server != conf->auth_servers) {
798 oserv = conf->auth_server;
799 conf->auth_server = conf->auth_servers;
800 radius_change_server(radius, conf->auth_server, oserv,
801 radius->auth_serv_sock,
802 radius->auth_serv_sock6, 1);
805 if (radius->acct_sock >= 0 && conf->acct_servers &&
806 conf->acct_server != conf->acct_servers) {
807 oserv = conf->acct_server;
808 conf->acct_server = conf->acct_servers;
809 radius_change_server(radius, conf->acct_server, oserv,
810 radius->acct_serv_sock,
811 radius->acct_serv_sock6, 0);
814 if (conf->retry_primary_interval)
815 eloop_register_timeout(conf->retry_primary_interval, 0,
816 radius_retry_primary_timer, radius,
817 NULL);
821 static int radius_client_init_auth(struct radius_client_data *radius)
823 struct hostapd_radius_servers *conf = radius->conf;
824 int ok = 0;
826 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
827 if (radius->auth_serv_sock < 0)
828 perror("socket[PF_INET,SOCK_DGRAM]");
829 else
830 ok++;
832 #ifdef CONFIG_IPV6
833 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
834 if (radius->auth_serv_sock6 < 0)
835 perror("socket[PF_INET6,SOCK_DGRAM]");
836 else
837 ok++;
838 #endif /* CONFIG_IPV6 */
840 if (ok == 0)
841 return -1;
843 radius_change_server(radius, conf->auth_server, NULL,
844 radius->auth_serv_sock, radius->auth_serv_sock6,
847 if (radius->auth_serv_sock >= 0 &&
848 eloop_register_read_sock(radius->auth_serv_sock,
849 radius_client_receive, radius,
850 (void *) RADIUS_AUTH)) {
851 printf("Could not register read socket for authentication "
852 "server\n");
853 return -1;
856 #ifdef CONFIG_IPV6
857 if (radius->auth_serv_sock6 >= 0 &&
858 eloop_register_read_sock(radius->auth_serv_sock6,
859 radius_client_receive, radius,
860 (void *) RADIUS_AUTH)) {
861 printf("Could not register read socket for authentication "
862 "server\n");
863 return -1;
865 #endif /* CONFIG_IPV6 */
867 return 0;
871 static int radius_client_init_acct(struct radius_client_data *radius)
873 struct hostapd_radius_servers *conf = radius->conf;
874 int ok = 0;
876 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
877 if (radius->acct_serv_sock < 0)
878 perror("socket[PF_INET,SOCK_DGRAM]");
879 else
880 ok++;
882 radius_change_server(radius, conf->acct_server, NULL,
883 radius->acct_serv_sock, radius->acct_serv_sock6,
886 if (radius->acct_serv_sock >= 0 &&
887 eloop_register_read_sock(radius->acct_serv_sock,
888 radius_client_receive, radius,
889 (void *) RADIUS_ACCT)) {
890 printf("Could not register read socket for accounting "
891 "server\n");
892 return -1;
895 #ifdef CONFIG_IPV6
896 if (radius->acct_serv_sock6 >= 0 &&
897 eloop_register_read_sock(radius->acct_serv_sock6,
898 radius_client_receive, radius,
899 (void *) RADIUS_ACCT)) {
900 printf("Could not register read socket for accounting "
901 "server\n");
902 return -1;
904 #endif /* CONFIG_IPV6 */
906 return 0;
910 struct radius_client_data *
911 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
913 struct radius_client_data *radius;
915 radius = malloc(sizeof(struct radius_client_data));
916 if (radius == NULL)
917 return NULL;
919 memset(radius, 0, sizeof(struct radius_client_data));
920 radius->ctx = ctx;
921 radius->conf = conf;
922 radius->auth_serv_sock = radius->acct_serv_sock =
923 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
924 radius->auth_sock = radius->acct_sock = -1;
926 if (conf->auth_server && radius_client_init_auth(radius)) {
927 radius_client_deinit(radius);
928 return NULL;
931 if (conf->acct_server && radius_client_init_acct(radius)) {
932 radius_client_deinit(radius);
933 return NULL;
936 if (conf->retry_primary_interval)
937 eloop_register_timeout(conf->retry_primary_interval, 0,
938 radius_retry_primary_timer, radius,
939 NULL);
941 return radius;
945 void radius_client_deinit(struct radius_client_data *radius)
947 if (!radius)
948 return;
950 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
952 radius_client_flush(radius);
953 free(radius->auth_handlers);
954 free(radius->acct_handlers);
955 free(radius);
959 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
961 struct radius_msg_list *entry, *prev, *tmp;
963 prev = NULL;
964 entry = radius->msgs;
965 while (entry) {
966 if (entry->msg_type == RADIUS_AUTH &&
967 memcmp(entry->addr, addr, ETH_ALEN) == 0) {
968 hostapd_logger(radius->ctx, addr,
969 HOSTAPD_MODULE_RADIUS,
970 HOSTAPD_LEVEL_DEBUG,
971 "Removing pending RADIUS authentication"
972 " message for removed client");
974 if (prev)
975 prev->next = entry->next;
976 else
977 radius->msgs = entry->next;
979 tmp = entry;
980 entry = entry->next;
981 radius_client_msg_free(tmp);
982 radius->num_msgs--;
983 continue;
986 prev = entry;
987 entry = entry->next;
992 static int radius_client_dump_auth_server(char *buf, size_t buflen,
993 struct hostapd_radius_server *serv,
994 struct radius_client_data *cli)
996 int pending = 0;
997 struct radius_msg_list *msg;
998 char abuf[50];
1000 if (cli) {
1001 for (msg = cli->msgs; msg; msg = msg->next) {
1002 if (msg->msg_type == RADIUS_AUTH)
1003 pending++;
1007 return snprintf(buf, buflen,
1008 "radiusAuthServerIndex=%d\n"
1009 "radiusAuthServerAddress=%s\n"
1010 "radiusAuthClientServerPortNumber=%d\n"
1011 "radiusAuthClientRoundTripTime=%d\n"
1012 "radiusAuthClientAccessRequests=%u\n"
1013 "radiusAuthClientAccessRetransmissions=%u\n"
1014 "radiusAuthClientAccessAccepts=%u\n"
1015 "radiusAuthClientAccessRejects=%u\n"
1016 "radiusAuthClientAccessChallenges=%u\n"
1017 "radiusAuthClientMalformedAccessResponses=%u\n"
1018 "radiusAuthClientBadAuthenticators=%u\n"
1019 "radiusAuthClientPendingRequests=%u\n"
1020 "radiusAuthClientTimeouts=%u\n"
1021 "radiusAuthClientUnknownTypes=%u\n"
1022 "radiusAuthClientPacketsDropped=%u\n",
1023 serv->index,
1024 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1025 serv->port,
1026 serv->round_trip_time,
1027 serv->requests,
1028 serv->retransmissions,
1029 serv->access_accepts,
1030 serv->access_rejects,
1031 serv->access_challenges,
1032 serv->malformed_responses,
1033 serv->bad_authenticators,
1034 pending,
1035 serv->timeouts,
1036 serv->unknown_types,
1037 serv->packets_dropped);
1041 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1042 struct hostapd_radius_server *serv,
1043 struct radius_client_data *cli)
1045 int pending = 0;
1046 struct radius_msg_list *msg;
1047 char abuf[50];
1049 if (cli) {
1050 for (msg = cli->msgs; msg; msg = msg->next) {
1051 if (msg->msg_type == RADIUS_ACCT ||
1052 msg->msg_type == RADIUS_ACCT_INTERIM)
1053 pending++;
1057 return snprintf(buf, buflen,
1058 "radiusAccServerIndex=%d\n"
1059 "radiusAccServerAddress=%s\n"
1060 "radiusAccClientServerPortNumber=%d\n"
1061 "radiusAccClientRoundTripTime=%d\n"
1062 "radiusAccClientRequests=%u\n"
1063 "radiusAccClientRetransmissions=%u\n"
1064 "radiusAccClientResponses=%u\n"
1065 "radiusAccClientMalformedResponses=%u\n"
1066 "radiusAccClientBadAuthenticators=%u\n"
1067 "radiusAccClientPendingRequests=%u\n"
1068 "radiusAccClientTimeouts=%u\n"
1069 "radiusAccClientUnknownTypes=%u\n"
1070 "radiusAccClientPacketsDropped=%u\n",
1071 serv->index,
1072 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1073 serv->port,
1074 serv->round_trip_time,
1075 serv->requests,
1076 serv->retransmissions,
1077 serv->responses,
1078 serv->malformed_responses,
1079 serv->bad_authenticators,
1080 pending,
1081 serv->timeouts,
1082 serv->unknown_types,
1083 serv->packets_dropped);
1087 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1088 size_t buflen)
1090 struct hostapd_radius_servers *conf = radius->conf;
1091 int i;
1092 struct hostapd_radius_server *serv;
1093 int count = 0;
1095 if (conf->auth_servers) {
1096 for (i = 0; i < conf->num_auth_servers; i++) {
1097 serv = &conf->auth_servers[i];
1098 count += radius_client_dump_auth_server(
1099 buf + count, buflen - count, serv,
1100 serv == conf->auth_server ?
1101 radius : NULL);
1105 if (conf->acct_servers) {
1106 for (i = 0; i < conf->num_acct_servers; i++) {
1107 serv = &conf->acct_servers[i];
1108 count += radius_client_dump_acct_server(
1109 buf + count, buflen - count, serv,
1110 serv == conf->acct_server ?
1111 radius : NULL);
1115 return count;