2 * event.c Server event handling
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2007 The FreeRADIUS server project
21 * Copyright 2007 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/event.h>
30 #include <freeradius-devel/detail.h>
32 #include <freeradius-devel/rad_assert.h>
37 #ifdef HAVE_SYS_WAIT_H
38 # include <sys/wait.h>
41 #define USEC (1000000)
43 extern pid_t radius_pid;
45 extern int check_config;
46 extern void force_log_reopen(void);
49 * Ridiculous amounts of local state.
51 static fr_event_list_t *el = NULL;
52 static fr_packet_list_t *pl = NULL;
53 static int request_num_counter = 0;
54 static struct timeval now;
56 static int have_children;
57 static int has_detail_listener = FALSE;
58 static int just_started = FALSE;
61 static int self_pipe[2];
66 static pthread_mutex_t proxy_mutex;
69 #define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock
70 #define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock
73 * This is easier than ifdef's throughout the code.
75 #define PTHREAD_MUTEX_LOCK(_x)
76 #define PTHREAD_MUTEX_UNLOCK(_x)
77 int thread_pool_addrequest(REQUEST *request, RAD_REQUEST_FUNP fun)
79 radius_handle_request(request, fun);
84 #define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
87 static fr_packet_list_t *proxy_list = NULL;
90 * We keep the proxy FD's here. The RADIUS Id's are marked
91 * "allocated" per Id, via a bit per proxy FD.
93 static int proxy_fds[32];
94 static rad_listen_t *proxy_listeners[32];
96 #define remove_from_proxy_hash(foo)
99 static void request_post_handler(REQUEST *request);
100 static void wait_a_bit(void *ctx);
101 static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd, void *ctx);
103 static void NEVER_RETURNS _rad_panic(const char *file, unsigned int line,
106 radlog(L_ERR, "[%s:%d] %s", file, line, msg);
110 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
113 static void tv_add(struct timeval *tv, int usec_delay)
115 if (usec_delay > USEC) {
116 tv->tv_sec += usec_delay / USEC;
119 tv->tv_usec += usec_delay;
121 if (tv->tv_usec > USEC) {
127 static void remove_from_request_hash(REQUEST *request)
129 if (!request->in_request_hash) return;
131 fr_packet_list_yank(pl, request->packet);
132 request->in_request_hash = FALSE;
134 request_stats_final(request);
139 static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply)
141 RADIUS_PACKET **proxy_p;
144 PTHREAD_MUTEX_LOCK(&proxy_mutex);
145 proxy_p = fr_packet_list_find_byreply(proxy_list, reply);
148 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
152 request = fr_packet2myptr(REQUEST, proxy, proxy_p);
155 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
159 request->num_proxied_responses++;
162 * Catch the most common case of everything working
165 if (request->num_proxied_requests == request->num_proxied_responses) {
166 fr_packet_list_yank(proxy_list, request->proxy);
167 fr_packet_list_id_free(proxy_list, request->proxy);
168 request->in_proxy_hash = FALSE;
172 * On the FIRST reply, decrement the count of outstanding
173 * requests. Note that this is NOT the count of sent
174 * packets, but whether or not the home server has
177 if (!request->proxy_reply &&
178 request->home_server->currently_outstanding) {
179 request->home_server->currently_outstanding--;
182 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
188 static void remove_from_proxy_hash(REQUEST *request)
190 if (!request->in_proxy_hash) return;
192 PTHREAD_MUTEX_LOCK(&proxy_mutex);
193 fr_packet_list_yank(proxy_list, request->proxy);
194 fr_packet_list_id_free(proxy_list, request->proxy);
197 * The home server hasn't replied, but we've given up on
198 * this request. Don't count this request against the
201 if (!request->proxy_reply &&
202 request->home_server->currently_outstanding) {
203 request->home_server->currently_outstanding--;
206 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
208 request->in_proxy_hash = FALSE;
212 static int insert_into_proxy_hash(REQUEST *request)
217 rad_assert(request->proxy != NULL);
218 rad_assert(proxy_list != NULL);
220 request->proxy->sockfd = -1;
222 PTHREAD_MUTEX_LOCK(&proxy_mutex);
224 request->home_server->currently_outstanding++;
226 if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {
228 rad_listen_t *proxy_listener;
231 * Allocate a new proxy fd. This function adds
232 * it to the tail of the list of listeners. With
233 * some care, this can be thread-safe.
235 proxy_listener = proxy_new_listener();
236 if (!proxy_listener) {
237 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
238 RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
246 proxy = proxy_listener->fd;
247 for (i = 0; i < 32; i++) {
249 * Found a free entry. Save the socket,
250 * and remember where we saved it.
252 if (proxy_fds[(proxy + i) & 0x1f] == -1) {
253 found = (proxy + i) & 0x1f;
254 proxy_fds[found] = proxy;
255 proxy_listeners[found] = proxy_listener;
259 rad_assert(found >= 0);
261 if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
262 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
263 RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
268 if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {
269 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
270 RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
275 * Signal the main thread to add the new FD to the list
278 radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
280 rad_assert(request->proxy->sockfd >= 0);
283 * FIXME: Hack until we get rid of rad_listen_t, and put
284 * the information into the packet_list.
287 for (i = 0; i < 32; i++) {
288 if (proxy_fds[i] == request->proxy->sockfd) {
295 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
296 RDEBUG2("ERROR: All sockets are full.");
300 rad_assert(proxy_fds[proxy] != -1);
301 rad_assert(proxy_listeners[proxy] != NULL);
302 request->proxy_listener = proxy_listeners[proxy];
304 if (!fr_packet_list_insert(proxy_list, &request->proxy)) {
305 fr_packet_list_id_free(proxy_list, request->proxy);
306 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
307 RDEBUG2("ERROR: Failed to insert entry into proxy list");
311 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
313 RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
314 inet_ntop(request->proxy->dst_ipaddr.af,
315 &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
316 request->proxy->dst_port,
319 request->in_proxy_hash = TRUE;
326 * Called as BOTH an event, and in-line from other functions.
328 static void wait_for_proxy_id_to_expire(void *ctx)
330 REQUEST *request = ctx;
331 home_server *home = request->home_server;
333 rad_assert(request->magic == REQUEST_MAGIC);
334 rad_assert(request->proxy != NULL);
336 if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);
337 request->when = request->proxy_when;
338 request->when.tv_sec += home->response_window;
340 if ((request->num_proxied_requests == request->num_proxied_responses) ||
341 timercmp(&now, &request->when, >)) {
342 if (request->packet) {
343 RDEBUG2("Cleaning up request %d ID %d with timestamp +%d",
344 request->number, request->packet->id,
345 (unsigned int) (request->timestamp - fr_start_time));
347 RDEBUG2("Cleaning up request %d with timestamp +%d",
349 (unsigned int) (request->timestamp - fr_start_time));
351 fr_event_delete(el, &request->ev);
352 remove_from_proxy_hash(request);
353 remove_from_request_hash(request);
354 request_free(&request);
358 INSERT_EVENT(wait_for_proxy_id_to_expire, request);
362 #ifdef HAVE_PTHREAD_H
363 static void wait_for_child_to_die(void *ctx)
365 REQUEST *request = ctx;
367 rad_assert(request->magic == REQUEST_MAGIC);
369 if ((request->child_state == REQUEST_QUEUED) |
370 (request->child_state == REQUEST_RUNNING)) {
371 request->delay += (request->delay >> 1);
372 tv_add(&request->when, request->delay);
374 RDEBUG2("Child is still stuck for request %d", request->number);
376 INSERT_EVENT(wait_for_child_to_die, request);
380 RDEBUG2("Child is finally responsive for request %d", request->number);
381 remove_from_request_hash(request);
384 if (request->proxy) {
385 wait_for_proxy_id_to_expire(request);
390 request_free(&request);
394 static void cleanup_delay(void *ctx)
396 REQUEST *request = ctx;
398 rad_assert(request->magic == REQUEST_MAGIC);
399 rad_assert((request->child_state == REQUEST_CLEANUP_DELAY) ||
400 (request->child_state == REQUEST_DONE));
402 remove_from_request_hash(request);
405 if (request->proxy && request->in_proxy_hash) {
406 wait_for_proxy_id_to_expire(request);
411 RDEBUG2("Cleaning up request %d ID %d with timestamp +%d",
412 request->number, request->packet->id,
413 (unsigned int) (request->timestamp - fr_start_time));
415 fr_event_delete(el, &request->ev);
416 request_free(&request);
420 static void reject_delay(void *ctx)
422 REQUEST *request = ctx;
424 rad_assert(request->magic == REQUEST_MAGIC);
425 rad_assert(request->child_state == REQUEST_REJECT_DELAY);
427 RDEBUG2("Sending delayed reject for request %d", request->number);
429 request->listener->send(request->listener, request);
431 request->when.tv_sec += request->root->cleanup_delay;
432 request->child_state = REQUEST_CLEANUP_DELAY;
434 INSERT_EVENT(cleanup_delay, request);
439 static void revive_home_server(void *ctx)
441 home_server *home = ctx;
444 home->state = HOME_STATE_ALIVE;
445 radlog(L_INFO, "PROXY: Marking home server %s port %d alive again... we have no idea if it really is alive or not.",
446 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
447 buffer, sizeof(buffer)),
449 home->currently_outstanding = 0;
450 home->revive_time = now;
454 static void no_response_to_ping(void *ctx)
456 REQUEST *request = ctx;
457 home_server *home = request->home_server;
460 home->num_received_pings = 0;
462 RDEBUG2("No response to status check %d from home server %s port %d",
464 inet_ntop(request->proxy->dst_ipaddr.af,
465 &request->proxy->dst_ipaddr.ipaddr,
466 buffer, sizeof(buffer)),
467 request->proxy->dst_port);
469 wait_for_proxy_id_to_expire(request);
473 static void received_response_to_ping(REQUEST *request)
475 home_server *home = request->home_server;
478 home->num_received_pings++;
480 RDEBUG2("Received response to status check %d (%d in current sequence)",
481 request->number, home->num_received_pings);
483 if (home->num_received_pings < home->num_pings_to_alive) {
484 wait_for_proxy_id_to_expire(request);
488 radlog(L_INFO, "PROXY: Marking home server %s port %d alive",
489 inet_ntop(request->proxy->dst_ipaddr.af,
490 &request->proxy->dst_ipaddr.ipaddr,
491 buffer, sizeof(buffer)),
492 request->proxy->dst_port);
494 if (!fr_event_delete(el, &home->ev)) {
495 RDEBUG2("Hmm... no event for home server, WTF?");
498 if (!fr_event_delete(el, &request->ev)) {
499 RDEBUG2("Hmm... no event for request, WTF?");
502 wait_for_proxy_id_to_expire(request);
504 home->state = HOME_STATE_ALIVE;
505 home->currently_outstanding = 0;
506 home->revive_time = now;
510 static void ping_home_server(void *ctx)
513 home_server *home = ctx;
517 if (home->state == HOME_STATE_ALIVE) {
518 radlog(L_INFO, "Suspicious proxy state... continuing");
522 request = request_alloc();
523 request->number = request_num_counter++;
525 request->proxy = rad_alloc(1);
526 rad_assert(request->proxy != NULL);
528 fr_event_now(el, &request->when);
529 home->when = request->when;
531 if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
532 request->proxy->code = PW_STATUS_SERVER;
534 radius_pairmake(request, &request->proxy->vps,
535 "Message-Authenticator", "0x00", T_OP_SET);
537 } else if (home->type == HOME_TYPE_AUTH) {
538 request->proxy->code = PW_AUTHENTICATION_REQUEST;
540 radius_pairmake(request, &request->proxy->vps,
541 "User-Name", home->ping_user_name, T_OP_SET);
542 radius_pairmake(request, &request->proxy->vps,
543 "User-Password", home->ping_user_password, T_OP_SET);
544 radius_pairmake(request, &request->proxy->vps,
545 "Service-Type", "Authenticate-Only", T_OP_SET);
546 radius_pairmake(request, &request->proxy->vps,
547 "Message-Authenticator", "0x00", T_OP_SET);
550 #ifdef WITH_ACCOUNTING
551 request->proxy->code = PW_ACCOUNTING_REQUEST;
553 radius_pairmake(request, &request->proxy->vps,
554 "User-Name", home->ping_user_name, T_OP_SET);
555 radius_pairmake(request, &request->proxy->vps,
556 "Acct-Status-Type", "Stop", T_OP_SET);
557 radius_pairmake(request, &request->proxy->vps,
558 "Acct-Session-Id", "00000000", T_OP_SET);
559 vp = radius_pairmake(request, &request->proxy->vps,
560 "Event-Timestamp", "0", T_OP_SET);
561 vp->vp_date = now.tv_sec;
563 rad_assert("Internal sanity check failed");
567 radius_pairmake(request, &request->proxy->vps,
568 "NAS-Identifier", "Status Check. Are you alive?",
571 request->proxy->dst_ipaddr = home->ipaddr;
572 request->proxy->dst_port = home->port;
573 request->home_server = home;
575 rad_assert(request->proxy_listener == NULL);
577 if (!insert_into_proxy_hash(request)) {
578 RDEBUG2("ERROR: Failed inserting status check %d into proxy hash. Discarding it.",
580 request_free(&request);
583 rad_assert(request->proxy_listener != NULL);
584 request->proxy_listener->send(request->proxy_listener,
587 request->next_callback = NULL;
588 request->child_state = REQUEST_PROXIED;
589 request->when.tv_sec += home->ping_timeout;;
591 INSERT_EVENT(no_response_to_ping, request);
594 * Add +/- 2s of jitter, as suggested in RFC 3539
595 * and in the Issues and Fixes draft.
597 home->when.tv_sec += home->ping_interval - 2;
600 jitter ^= (jitter >> 10);
601 jitter &= ((1 << 23) - 1); /* 22 bits of 1 */
603 tv_add(&home->when, jitter);
606 INSERT_EVENT(ping_home_server, home);
610 static void check_for_zombie_home_server(REQUEST *request)
616 home = request->home_server;
618 if (home->state != HOME_STATE_ZOMBIE) return;
620 when = home->zombie_period_start;
621 when.tv_sec += home->zombie_period;
623 fr_event_now(el, &now);
624 if (timercmp(&now, &when, <)) {
629 * It's been a zombie for too long, mark it as
632 radlog(L_INFO, "PROXY: Marking home server %s port %d as dead.",
633 inet_ntop(request->proxy->dst_ipaddr.af,
634 &request->proxy->dst_ipaddr.ipaddr,
635 buffer, sizeof(buffer)),
636 request->proxy->dst_port);
637 home->state = HOME_STATE_IS_DEAD;
638 home->num_received_pings = 0;
639 home->when = request->when;
641 if (home->ping_check != HOME_PING_CHECK_NONE) {
642 rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) ||
643 (home->ping_user_name != NULL));
644 home->when.tv_sec += home->ping_interval;
646 INSERT_EVENT(ping_home_server, home);
648 home->when.tv_sec += home->revive_interval;
650 INSERT_EVENT(revive_home_server, home);
654 static int proxy_to_virtual_server(REQUEST *request);
656 static int virtual_server_handler(UNUSED REQUEST *request)
658 proxy_to_virtual_server(request);
662 static void proxy_fallback_handler(REQUEST *request)
665 * A proper time is required for wait_a_bit.
667 request->delay = USEC / 10;
668 gettimeofday(&now, NULL);
669 request->next_when = now;
670 tv_add(&request->next_when, request->delay);
671 request->next_callback = wait_a_bit;
674 * Re-queue the request.
676 request->child_state = REQUEST_QUEUED;
678 rad_assert(request->proxy != NULL);
679 if (!thread_pool_addrequest(request, virtual_server_handler)) {
680 request->child_state = REQUEST_DONE;
683 #ifdef HAVE_PTHREAD_H
685 * MAY free the request if we're over max_request_time,
686 * AND we're not in threaded mode!
688 * Note that we call this ONLY if we're threaded, as
689 * if we're NOT threaded, request_post_handler() calls
690 * wait_a_bit(), which means that "request" may not
693 if (have_children) wait_a_bit(request);
698 static int setup_post_proxy_fail(REQUEST *request)
700 DICT_VALUE *dval = NULL;
703 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
704 dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication");
706 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
707 dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting");
713 if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail");
716 pairdelete(&request->config_items, PW_POST_PROXY_TYPE);
720 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
721 if (!vp) vp = radius_paircreate(request, &request->config_items,
722 PW_POST_PROXY_TYPE, PW_TYPE_INTEGER);
723 vp->vp_integer = dval->value;
725 rad_assert(request->proxy_reply == NULL);
731 static int null_handler(UNUSED REQUEST *request)
736 static void post_proxy_fail_handler(REQUEST *request)
739 * A proper time is required for wait_a_bit.
741 request->delay = USEC / 10;
742 gettimeofday(&now, NULL);
745 * Not set up to run Post-Proxy-Type = Fail.
747 * Mark the request as still running, and figure out what
750 if (!setup_post_proxy_fail(request)) {
751 request->child_state = REQUEST_RUNNING;
752 request_post_handler(request);
756 * Re-queue the request.
758 request->child_state = REQUEST_QUEUED;
761 * There is a post-proxy-type of fail. We run
762 * the request through the pre/post proxy
763 * handlers, just like it was a real proxied
764 * request. However, we set the per-request
765 * handler to NULL, as we don't want to do
768 * Note that when we're not threaded, this will
769 * process the request even if it's greater than
770 * max_request_time. That's not fatal.
772 request->priority = 0;
773 rad_assert(request->proxy != NULL);
774 thread_pool_addrequest(request, null_handler);
778 * MAY free the request if we're over max_request_time,
779 * AND we're not in threaded mode!
781 * Note that we call this ONLY if we're threaded, as
782 * if we're NOT threaded, request_post_handler() calls
783 * wait_a_bit(), which means that "request" may not
786 if (have_children) wait_a_bit(request);
790 /* maybe check this against wait_for_proxy_id_to_expire? */
791 static void no_response_to_proxied_request(void *ctx)
793 REQUEST *request = ctx;
797 rad_assert(request->magic == REQUEST_MAGIC);
798 rad_assert(request->child_state == REQUEST_PROXIED);
801 * If we've failed over to an internal home server,
802 * replace the callback with the correct one. This
803 * is due to locking issues with child threads...
805 if (request->home_server->server) {
810 radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
812 inet_ntop(request->proxy->dst_ipaddr.af,
813 &request->proxy->dst_ipaddr.ipaddr,
814 buffer, sizeof(buffer)),
815 request->proxy->dst_port);
817 check_for_zombie_home_server(request);
819 home = request->home_server;
821 post_proxy_fail_handler(request);
824 * Don't touch request due to race conditions
826 if (home->state == HOME_STATE_IS_DEAD) {
827 rad_assert(home->ev != NULL); /* or it will never wake up */
832 * Enable the zombie period when we notice that the home
833 * server hasn't responded. We also back-date the start
834 * of the zombie period to when the proxied request was
837 if (home->state == HOME_STATE_ALIVE) {
838 radlog(L_ERR, "PROXY: Marking home server %s port %d as zombie (it looks like it is dead).",
839 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
840 buffer, sizeof(buffer)),
842 home->state = HOME_STATE_ZOMBIE;
843 home->zombie_period_start = now;
844 home->zombie_period_start.tv_sec -= home->response_window;
850 static void wait_a_bit(void *ctx)
853 REQUEST *request = ctx;
854 fr_event_callback_t callback = NULL;
856 rad_assert(request->magic == REQUEST_MAGIC);
858 switch (request->child_state) {
860 case REQUEST_RUNNING:
861 when = request->received;
862 when.tv_sec += request->root->max_request_time;
865 * Normally called from the event loop with the
866 * proper event loop time. Otherwise, called from
867 * post proxy fail handler, which sets "now", and
868 * this call won't re-set it, because we're not
871 fr_event_now(el, &now);
874 * Request still has more time. Continue
877 if (timercmp(&now, &when, <) ||
878 ((request->listener->type == RAD_LISTEN_DETAIL) &&
879 (request->child_state == REQUEST_QUEUED))) {
880 if (request->delay < (USEC / 10)) {
881 request->delay = USEC / 10;
883 request->delay += request->delay >> 1;
887 * Cap wait at some sane value for detail
890 if ((request->listener->type == RAD_LISTEN_DETAIL) &&
891 (request->delay > (request->root->max_request_time * USEC))) {
892 request->delay = request->root->max_request_time * USEC;
897 tv_add(&request->when, request->delay);
898 callback = wait_a_bit;
902 #if defined(HAVE_PTHREAD_H) || defined(WITH_PROXY)
904 * A child thread MAY still be running on the
905 * request. Ask the thread to stop working on
909 /* FIXME: kill unresponsive children? */
912 * Print this error message ONLY if
913 * there's a child currently processing
914 * the request. As we don't have thread
915 * locks here, there may be race
916 * conditions on this check. But it's
917 * just an error message, so that's OK.
919 if (request->child_pid != NO_SUCH_CHILD_PID) {
920 radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s",
921 (unsigned long)request->child_pid, request->number,
922 request->module ? request->module : "<server core>",
923 request->component ? request->component : "<server core>");
926 request->master_state = REQUEST_STOP_PROCESSING;
928 request->delay = USEC / 4;
929 tv_add(&request->when, request->delay);
930 callback = wait_for_child_to_die;
936 * Else there are no child threads. We probably
937 * should have just marked the request as 'done'
938 * elsewhere, like in the post-proxy-fail
939 * handler. But doing that would involve
940 * checking for max_request_time in multiple
941 * places, so this may be simplest.
943 request->child_state = REQUEST_DONE;
947 * Mark the request as no longer running,
951 #ifdef HAVE_PTHREAD_H
952 request->child_pid = NO_SUCH_CHILD_PID;
954 request_stats_final(request);
955 cleanup_delay(request);
958 case REQUEST_REJECT_DELAY:
959 case REQUEST_CLEANUP_DELAY:
960 #ifdef HAVE_PTHREAD_H
961 request->child_pid = NO_SUCH_CHILD_PID;
963 request_stats_final(request);
965 case REQUEST_PROXIED:
966 rad_assert(request->next_callback != NULL);
967 rad_assert(request->next_callback != wait_a_bit);
969 request->when = request->next_when;
970 callback = request->next_callback;
971 request->next_callback = NULL;
975 rad_panic("Internal sanity check failure");
980 * Something major went wrong. Discard the request, and
983 * FIXME: No idea why this happens or how to fix it...
984 * It seems to happen *only* when requests are proxied,
985 * and where the home server doesn't respond. So it looks
986 * like a race condition above, but it happens in debug
987 * mode, with no threads...
990 RDEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number);
991 fr_event_delete(el, &request->ev);
992 remove_from_proxy_hash(request);
993 remove_from_request_hash(request);
994 request_free(&request);
998 INSERT_EVENT(callback, request);
1003 static int process_proxy_reply(REQUEST *request)
1006 int post_proxy_type = 0;
1010 * Delete any reply we had accumulated until now.
1012 pairfree(&request->reply->vps);
1015 * Run the packet through the post-proxy stage,
1016 * BEFORE playing games with the attributes.
1018 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
1020 RDEBUG2(" Found Post-Proxy-Type %s", vp->vp_strvalue);
1021 post_proxy_type = vp->vp_integer;
1024 rad_assert(request->home_pool != NULL);
1026 if (request->home_pool->virtual_server) {
1027 const char *old_server = request->server;
1029 request->server = request->home_pool->virtual_server;
1030 RDEBUG2(" server %s {", request->server);
1031 rcode = module_post_proxy(post_proxy_type, request);
1033 request->server = old_server;
1035 rcode = module_post_proxy(post_proxy_type, request);
1039 * There may NOT be a proxy reply, as we may be
1040 * running Post-Proxy-Type = Fail.
1042 if (request->proxy_reply) {
1044 * Delete the Proxy-State Attributes from
1045 * the reply. These include Proxy-State
1046 * attributes from us and remote server.
1048 pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
1051 * Add the attributes left in the proxy
1052 * reply to the reply list.
1054 pairadd(&request->reply->vps, request->proxy_reply->vps);
1055 request->proxy_reply->vps = NULL;
1058 * Free proxy request pairs.
1060 pairfree(&request->proxy->vps);
1064 default: /* Don't do anything */
1066 case RLM_MODULE_FAIL:
1067 /* FIXME: debug print stuff */
1068 request->child_state = REQUEST_DONE;
1071 case RLM_MODULE_HANDLED:
1072 /* FIXME: debug print stuff */
1073 request->child_state = REQUEST_DONE;
1081 static int request_pre_handler(REQUEST *request)
1085 rad_assert(request->magic == REQUEST_MAGIC);
1086 rad_assert(request->packet != NULL);
1088 request->child_state = REQUEST_RUNNING;
1091 * Don't decode the packet if it's an internal "fake"
1092 * request. Instead, just return so that the caller can
1095 if (request->packet->dst_port == 0) {
1096 request->username = pairfind(request->packet->vps,
1098 request->password = pairfind(request->packet->vps,
1105 * Put the decoded packet into it's proper place.
1107 if (request->proxy_reply != NULL) {
1108 rcode = request->proxy_listener->decode(request->proxy_listener,
1112 if (request->packet->vps == NULL) {
1113 rcode = request->listener->decode(request->listener, request);
1120 radlog(L_ERR, "%s Dropping packet without response.", fr_strerror());
1121 request->child_state = REQUEST_DONE;
1126 if (!request->proxy)
1129 request->username = pairfind(request->packet->vps,
1134 return process_proxy_reply(request);
1144 * Do state handling when we proxy a request.
1146 static int proxy_request(REQUEST *request)
1148 struct timeval when;
1151 if (request->home_server->server) {
1152 RDEBUG("ERROR: Cannot perform real proxying to a virtual server.");
1156 if (!insert_into_proxy_hash(request)) {
1157 RDEBUG("ERROR: Failed inserting request into proxy hash.");
1161 request->proxy_listener->encode(request->proxy_listener, request);
1163 when = request->received;
1164 when.tv_sec += request->root->max_request_time;
1166 gettimeofday(&request->proxy_when, NULL);
1168 request->next_when = request->proxy_when;
1169 request->next_when.tv_sec += request->home_server->response_window;
1171 rad_assert(request->home_server->response_window > 0);
1173 if (timercmp(&when, &request->next_when, <)) {
1174 request->next_when = when;
1176 request->next_callback = no_response_to_proxied_request;
1178 RDEBUG2("Proxying request %d to home server %s port %d",
1180 inet_ntop(request->proxy->dst_ipaddr.af,
1181 &request->proxy->dst_ipaddr.ipaddr,
1182 buffer, sizeof(buffer)),
1183 request->proxy->dst_port);
1186 * Note that we set proxied BEFORE sending the packet.
1188 * Once we send it, the request is tainted, as
1189 * another thread may have picked it up. Don't
1192 request->num_proxied_requests = 1;
1193 request->num_proxied_responses = 0;
1194 #ifdef HAVE_PTHREAD_H
1195 request->child_pid = NO_SUCH_CHILD_PID;
1197 request->child_state = REQUEST_PROXIED;
1198 request->proxy_listener->send(request->proxy_listener,
1205 * "Proxy" the request by sending it to a new virtual server.
1207 static int proxy_to_virtual_server(REQUEST *request)
1210 RAD_REQUEST_FUNP fun;
1212 if (!request->home_server || !request->home_server->server) return 0;
1214 if (request->parent) {
1215 RDEBUG2("WARNING: Cancelling proxy request to virtual server %s as this request was itself proxied.", request->home_server->server);
1219 fake = request_alloc_fake(request);
1221 RDEBUG2("WARNING: Out of memory");
1225 fake->packet->vps = paircopy(request->proxy->vps);
1226 fake->server = request->home_server->server;
1228 if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
1229 fun = rad_authenticate;
1231 #ifdef WITH_ACCOUNTING
1232 } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
1233 fun = rad_accounting;
1237 RDEBUG2("Unknown packet type %d", request->proxy->code);
1241 RDEBUG2(">>> Sending proxied request internally to virtual server.");
1242 radius_handle_request(fake, fun);
1243 RDEBUG2("<<< Received proxied response from internal virtual server.");
1245 request->proxy_reply = fake->reply;
1248 request_free(&fake);
1250 process_proxy_reply(request);
1253 return 2; /* success, but NOT '1' !*/
1258 * Return 1 if we did proxy it, or the proxy attempt failed
1259 * completely. Either way, the caller doesn't touch the request
1260 * any more if we return 1.
1262 static int successfully_proxied_request(REQUEST *request)
1265 int pre_proxy_type = 0;
1266 VALUE_PAIR *realmpair;
1267 VALUE_PAIR *strippedname;
1271 REALM *realm = NULL;
1275 * If it was already proxied, do nothing.
1277 * FIXME: This should really be a serious error.
1279 if (request->in_proxy_hash) {
1283 realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
1284 if (!realmpair || (realmpair->length == 0)) {
1288 realmname = (char *) realmpair->vp_strvalue;
1290 realm = realm_find2(realmname);
1292 RDEBUG2("ERROR: Cannot proxy to unknown realm %s", realmname);
1297 * Figure out which pool to use.
1299 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1300 pool = realm->auth_pool;
1302 #ifdef WITH_ACCOUNTING
1303 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1304 pool = realm->acct_pool;
1308 rad_panic("Internal sanity check failed");
1312 RDEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
1317 home = home_server_ldb(realmname, pool, request);
1319 RDEBUG2("ERROR: Failed to find live home server for realm %s",
1323 request->home_pool = pool;
1326 * Remember that we sent the request to a Realm.
1328 pairadd(&request->packet->vps,
1329 pairmake("Realm", realmname, T_OP_EQ));
1333 * We read the packet from a detail file, AND it came from
1334 * the server we're about to send it to. Don't do that.
1336 if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
1337 (request->listener->type == RAD_LISTEN_DETAIL) &&
1338 (home->ipaddr.af == AF_INET) &&
1339 (request->packet->src_ipaddr.af == AF_INET) &&
1340 (home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) {
1341 RDEBUG2(" rlm_realm: Packet came from realm %s, proxy cancelled", realmname);
1347 * Allocate the proxy packet, only if it wasn't already
1348 * allocated by a module. This check is mainly to support
1349 * the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
1351 * In those cases, the EAP module creates a "fake"
1352 * request, and recursively passes it through the
1353 * authentication stage of the server. The module then
1354 * checks if the request was supposed to be proxied, and
1355 * if so, creates a proxy packet from the TUNNELED request,
1356 * and not from the EAP request outside of the tunnel.
1358 * The proxy then works like normal, except that the response
1359 * packet is "eaten" by the EAP module, and encapsulated into
1362 if (!request->proxy) {
1363 if ((request->proxy = rad_alloc(TRUE)) == NULL) {
1364 radlog(L_ERR|L_CONS, "no memory");
1369 * Copy the request, then look up name and
1370 * plain-text password in the copy.
1372 * Note that the User-Name attribute is the
1373 * *original* as sent over by the client. The
1374 * Stripped-User-Name attribute is the one hacked
1375 * through the 'hints' file.
1377 request->proxy->vps = paircopy(request->packet->vps);
1381 * Strip the name, if told to.
1383 * Doing it here catches the case of proxied tunneled
1386 if (realm->striprealm == TRUE &&
1387 (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
1389 * If there's a Stripped-User-Name attribute in
1390 * the request, then use THAT as the User-Name
1391 * for the proxied request, instead of the
1394 * This is done by making a copy of the
1395 * Stripped-User-Name attribute, turning it into
1396 * a User-Name attribute, deleting the
1397 * Stripped-User-Name and User-Name attributes
1398 * from the vps list, and making the new
1399 * User-Name the head of the vps list.
1401 vp = pairfind(request->proxy->vps, PW_USER_NAME);
1403 vp = radius_paircreate(request, NULL,
1404 PW_USER_NAME, PW_TYPE_STRING);
1405 rad_assert(vp != NULL); /* handled by above function */
1406 /* Insert at the START of the list */
1407 vp->next = request->proxy->vps;
1408 request->proxy->vps = vp;
1410 memcpy(vp->vp_strvalue, strippedname->vp_strvalue,
1411 sizeof(vp->vp_strvalue));
1412 vp->length = strippedname->length;
1415 * Do NOT delete Stripped-User-Name.
1420 * If there is no PW_CHAP_CHALLENGE attribute but
1421 * there is a PW_CHAP_PASSWORD we need to add it
1422 * since we can't use the request authenticator
1423 * anymore - we changed it.
1425 if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
1426 pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
1427 vp = radius_paircreate(request, &request->proxy->vps,
1428 PW_CHAP_CHALLENGE, PW_TYPE_OCTETS);
1429 vp->length = AUTH_VECTOR_LEN;
1430 memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN);
1434 * The RFC's say we have to do this, but FreeRADIUS
1437 vp = radius_paircreate(request, &request->proxy->vps,
1438 PW_PROXY_STATE, PW_TYPE_OCTETS);
1439 snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%d",
1440 request->packet->id);
1441 vp->length = strlen(vp->vp_strvalue);
1444 * Should be done BEFORE inserting into proxy hash, as
1445 * pre-proxy may use this information, or change it.
1447 request->proxy->code = request->packet->code;
1448 request->proxy->dst_ipaddr = home->ipaddr;
1449 request->proxy->dst_port = home->port;
1450 request->home_server = home;
1453 * Call the pre-proxy routines.
1455 vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1457 RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
1458 pre_proxy_type = vp->vp_integer;
1461 rad_assert(request->home_pool != NULL);
1463 if (request->home_pool->virtual_server) {
1464 const char *old_server = request->server;
1466 request->server = request->home_pool->virtual_server;
1467 RDEBUG2(" server %s {", request->server);
1468 rcode = module_pre_proxy(pre_proxy_type, request);
1470 request->server = old_server;
1472 rcode = module_pre_proxy(pre_proxy_type, request);
1475 case RLM_MODULE_FAIL:
1476 case RLM_MODULE_INVALID:
1477 case RLM_MODULE_NOTFOUND:
1478 case RLM_MODULE_USERLOCK:
1480 /* FIXME: debug print failed stuff */
1483 case RLM_MODULE_REJECT:
1484 case RLM_MODULE_HANDLED:
1488 * Only proxy the packet if the pre-proxy code succeeded.
1490 case RLM_MODULE_NOOP:
1492 case RLM_MODULE_UPDATED:
1497 * If it's a fake request, don't send the proxy
1498 * packet. The outer tunnel session will take
1499 * care of doing that.
1501 if (request->packet->dst_port == 0) {
1502 request->home_server = NULL;
1506 if (request->home_server->server) {
1507 return proxy_to_virtual_server(request);
1510 if (!proxy_request(request)) {
1511 RDEBUG("ERROR: Failed to proxy request %d", request->number);
1520 static void request_post_handler(REQUEST *request)
1522 int child_state = -1;
1523 struct timeval when;
1526 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
1528 (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
1529 RDEBUG2("Request %d was cancelled.", request->number);
1530 #ifdef HAVE_PTHREAD_H
1531 request->child_pid = NO_SUCH_CHILD_PID;
1533 request->child_state = REQUEST_DONE;
1537 if (request->child_state != REQUEST_RUNNING) {
1538 rad_panic("Internal sanity check failed");
1541 if ((request->reply->code == 0) &&
1542 ((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) &&
1543 (vp->vp_integer == PW_AUTHTYPE_REJECT)) {
1544 request->reply->code = PW_AUTHENTICATION_REJECT;
1548 if (request->root->proxy_requests &&
1549 !request->in_proxy_hash &&
1550 (request->reply->code == 0) &&
1551 (request->packet->dst_port != 0) &&
1552 (request->packet->code != PW_STATUS_SERVER)) {
1553 int rcode = successfully_proxied_request(request);
1555 if (rcode == 1) return;
1558 * Failed proxying it (dead home servers, etc.)
1559 * Run it through Post-Proxy-Type = Fail, and
1560 * respond to the request.
1562 * Note that we're in a child thread here, so we
1563 * do NOT re-schedule the request. Instead, we
1564 * do what we would have done, which is run the
1565 * pre-handler, a NULL request handler, and then
1568 if ((rcode < 0) && setup_post_proxy_fail(request)) {
1569 request_pre_handler(request);
1573 * Else we weren't supposed to proxy it,
1574 * OR we proxied it internally to a virutal server.
1580 * Fake requests don't get encoded or signed. The caller
1581 * also requires the reply VP's, so we don't free them
1584 if (request->packet->dst_port == 0) {
1585 /* FIXME: RDEBUG going to the next request */
1586 #ifdef HAVE_PTHREAD_H
1587 request->child_pid = NO_SUCH_CHILD_PID;
1589 request->child_state = REQUEST_DONE;
1595 * Copy Proxy-State from the request to the reply.
1597 vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
1598 if (vp) pairadd(&request->reply->vps, vp);
1602 * Access-Requests get delayed or cached.
1604 switch (request->packet->code) {
1605 case PW_AUTHENTICATION_REQUEST:
1606 gettimeofday(&request->next_when, NULL);
1608 if (request->reply->code == 0) {
1610 * Check if the lack of response is intentional.
1612 vp = pairfind(request->config_items,
1613 PW_RESPONSE_PACKET_TYPE);
1615 RDEBUG2("There was no response configured: rejecting request %d",
1617 request->reply->code = PW_AUTHENTICATION_REJECT;
1618 } else if (vp->vp_integer == 256) {
1619 RDEBUG2("Not responding to request %d",
1623 request->reply->code = vp->vp_integer;
1629 * Run rejected packets through
1631 * Post-Auth-Type = Reject
1633 if (request->reply->code == PW_AUTHENTICATION_REJECT) {
1634 pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
1635 vp = radius_pairmake(request, &request->config_items,
1636 "Post-Auth-Type", "Reject",
1638 if (vp) rad_postauth(request);
1641 * If configured, delay Access-Reject packets.
1643 * If request->root->reject_delay = 0, we discover
1644 * that we have to send the packet now.
1646 when = request->received;
1647 when.tv_sec += request->root->reject_delay;
1649 if (timercmp(&when, &request->next_when, >)) {
1650 RDEBUG2("Delaying reject of request %d for %d seconds",
1652 request->root->reject_delay);
1653 request->next_when = when;
1654 request->next_callback = reject_delay;
1655 #ifdef HAVE_PTHREAD_H
1656 request->child_pid = NO_SUCH_CHILD_PID;
1658 request->child_state = REQUEST_REJECT_DELAY;
1663 request->next_when.tv_sec += request->root->cleanup_delay;
1664 request->next_callback = cleanup_delay;
1665 child_state = REQUEST_CLEANUP_DELAY;
1668 case PW_ACCOUNTING_REQUEST:
1669 request->next_callback = NULL; /* just to be safe */
1670 child_state = REQUEST_DONE;
1674 * FIXME: Status-Server should probably not be
1677 case PW_STATUS_SERVER:
1678 request->next_callback = NULL;
1679 child_state = REQUEST_DONE;
1683 if ((request->packet->code > 1024) &&
1684 (request->packet->code < (1024 + 254 + 1))) {
1685 request->next_callback = NULL;
1686 child_state = REQUEST_DONE;
1690 radlog(L_ERR, "Unknown packet type %d", request->packet->code);
1691 rad_panic("Unknown packet type");
1696 * Suppress "no reply" packets here, unless we're reading
1697 * from the "detail" file. In that case, we've got to
1698 * tell the detail file handler that the request is dead,
1699 * and it should re-send it.
1700 * If configured, encode, sign, and send.
1702 if ((request->reply->code != 0) ||
1703 (request->listener->type == RAD_LISTEN_DETAIL)) {
1704 request->listener->send(request->listener, request);
1708 * Clean up. These are no longer needed.
1710 pairfree(&request->config_items);
1712 pairfree(&request->packet->vps);
1713 request->username = NULL;
1714 request->password = NULL;
1716 pairfree(&request->reply->vps);
1719 if (request->proxy) {
1720 pairfree(&request->proxy->vps);
1722 if (request->proxy_reply) {
1723 pairfree(&request->proxy_reply->vps);
1728 * We're not tracking responses from the home
1729 * server, we can therefore free this memory in
1732 if (!request->in_proxy_hash) {
1733 rad_free(&request->proxy);
1734 rad_free(&request->proxy_reply);
1735 request->home_server = NULL;
1741 RDEBUG2("Finished request %d.", request->number);
1743 request->child_state = child_state;
1746 * Single threaded mode: update timers now.
1748 if (!have_children) wait_a_bit(request);
1752 static void received_retransmit(REQUEST *request, const RADCLIENT *client)
1758 RAD_STATS_TYPE_INC(request->listener, total_dup_requests);
1759 RAD_STATS_CLIENT_INC(request->listener, client, total_dup_requests);
1761 switch (request->child_state) {
1762 case REQUEST_QUEUED:
1763 case REQUEST_RUNNING:
1767 radlog(L_ERR, "Discarding duplicate request from "
1768 "client %s port %d - ID: %d due to unfinished request %d",
1770 request->packet->src_port,request->packet->id,
1775 case REQUEST_PROXIED:
1777 * We're not supposed to have duplicate
1778 * accounting packets. The other states handle
1779 * duplicates fine (discard, or send duplicate
1780 * reply). But we do NOT want to retransmit an
1781 * accounting request here, because that would
1782 * involve updating the Acct-Delay-Time, and
1783 * therefore changing the packet Id, etc.
1785 * Instead, we just discard the packet. We may
1786 * eventually respond, or the client will send a
1787 * new accounting packet.
1789 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1793 check_for_zombie_home_server(request);
1796 * If we've just discovered that the home server is
1797 * dead, send the packet to another one.
1799 if ((request->packet->dst_port != 0) &&
1800 (request->home_server->state == HOME_STATE_IS_DEAD)) {
1803 remove_from_proxy_hash(request);
1805 home = home_server_ldb(NULL, request->home_pool, request);
1807 RDEBUG2("Failed to find live home server for request %d", request->number);
1810 * Do post-request processing,
1811 * and any insertion of necessary
1814 post_proxy_fail_handler(request);
1818 request->proxy->code = request->packet->code;
1819 request->proxy->dst_ipaddr = home->ipaddr;
1820 request->proxy->dst_port = home->port;
1821 request->home_server = home;
1824 * Free the old packet, to force re-encoding
1826 free(request->proxy->data);
1827 request->proxy->data = NULL;
1828 request->proxy->data_len = 0;
1831 * This request failed over to a virtual
1832 * server. Push it back onto the queue
1835 if (request->home_server->server) {
1836 proxy_fallback_handler(request);
1841 * Try to proxy the request.
1843 if (!proxy_request(request)) {
1844 RDEBUG("ERROR: Failed to re-proxy request %d", request->number);
1845 goto no_home_servers;
1849 * This code executes in the main server
1850 * thread, so there's no need for locking.
1852 rad_assert(request->next_callback != NULL);
1853 INSERT_EVENT(request->next_callback, request);
1854 request->next_callback = NULL;
1856 } /* else the home server is still alive */
1858 RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
1859 inet_ntop(request->proxy->dst_ipaddr.af,
1860 &request->proxy->dst_ipaddr.ipaddr,
1861 buffer, sizeof(buffer)),
1862 request->proxy->dst_port,
1863 request->proxy->id);
1864 request->num_proxied_requests++;
1865 request->proxy_listener->send(request->proxy_listener,
1870 case REQUEST_REJECT_DELAY:
1871 RDEBUG2("Waiting to send Access-Reject "
1872 "to client %s port %d - ID: %d",
1874 request->packet->src_port, request->packet->id);
1877 case REQUEST_CLEANUP_DELAY:
1879 RDEBUG2("Sending duplicate reply "
1880 "to client %s port %d - ID: %d",
1882 request->packet->src_port, request->packet->id);
1883 request->listener->send(request->listener, request);
1889 static void received_conflicting_request(REQUEST *request,
1890 const RADCLIENT *client)
1892 radlog(L_ERR, "Received conflicting packet from "
1893 "client %s port %d - ID: %d due to unfinished request %d. Giving up on old request.",
1895 request->packet->src_port, request->packet->id,
1899 * Nuke it from the request hash, so we can receive new
1902 remove_from_request_hash(request);
1904 switch (request->child_state) {
1905 #ifdef HAVE_PTHREAD_H
1907 * It's queued or running. Tell it to stop, and
1908 * wait for it to do so.
1910 case REQUEST_QUEUED:
1911 case REQUEST_RUNNING:
1912 request->master_state = REQUEST_STOP_PROCESSING;
1913 request->delay += request->delay >> 1;
1915 tv_add(&request->when, request->delay);
1917 INSERT_EVENT(wait_for_child_to_die, request);
1922 * It's in some other state, and therefore also
1923 * in the event queue. At some point, the
1924 * child will notice, and we can then delete it.
1927 rad_assert(request->ev != NULL);
1933 static int can_handle_new_request(RADIUS_PACKET *packet,
1935 struct main_config_t *root)
1938 * Count the total number of requests, to see if
1939 * there are too many. If so, return with an
1942 if (root->max_requests) {
1943 int request_count = fr_packet_list_num_elements(pl);
1946 * This is a new request. Let's see if
1947 * it makes us go over our configured
1950 if (request_count > root->max_requests) {
1951 radlog(L_ERR, "Dropping request (%d is too many): "
1952 "from client %s port %d - ID: %d", request_count,
1954 packet->src_port, packet->id);
1955 radlog(L_INFO, "WARNING: Please check the configuration file.\n"
1956 "\tThe value for 'max_requests' is probably set too low.\n");
1958 } /* else there were a small number of requests */
1959 } /* else there was no configured limit for requests */
1962 * FIXME: Add per-client checks. If one client is sending
1963 * too many packets, start discarding them.
1965 * We increment the counters here, and decrement them
1966 * when the response is sent... somewhere in this file.
1970 * FUTURE: Add checks for system load. If the system is
1971 * busy, start dropping requests...
1973 * We can probably keep some statistics ourselves... if
1974 * there are more requests coming in than we can handle,
1975 * start dropping some.
1982 int received_request(rad_listen_t *listener,
1983 RADIUS_PACKET *packet, REQUEST **prequest,
1986 RADIUS_PACKET **packet_p;
1987 REQUEST *request = NULL;
1988 struct main_config_t *root = &mainconfig;
1990 packet_p = fr_packet_list_find(pl, packet);
1992 request = fr_packet2myptr(REQUEST, packet, packet_p);
1993 rad_assert(request->in_request_hash);
1995 if ((request->packet->data_len == packet->data_len) &&
1996 (memcmp(request->packet->vector, packet->vector,
1997 sizeof(packet->vector)) == 0)) {
1998 received_retransmit(request, client);
2003 * The new request is different from the old one,
2004 * but maybe the old is finished. If so, delete
2007 switch (request->child_state) {
2008 struct timeval when;
2011 gettimeofday(&when, NULL);
2015 * If the cached request was received
2016 * within the last second, then we
2017 * discard the NEW request instead of the
2018 * old one. This will happen ONLY when
2019 * the client is severely broken, and is
2020 * sending conflicting packets very
2023 if (timercmp(&when, &request->received, <)) {
2024 radlog(L_ERR, "Discarding conflicting packet from "
2025 "client %s port %d - ID: %d due to recent request %d.",
2027 packet->src_port, packet->id,
2032 received_conflicting_request(request, client);
2036 case REQUEST_REJECT_DELAY:
2037 case REQUEST_CLEANUP_DELAY:
2038 request->child_state = REQUEST_DONE;
2040 cleanup_delay(request);
2047 * We may want to quench the new request.
2049 if ((listener->type != RAD_LISTEN_DETAIL) &&
2050 !can_handle_new_request(packet, client, root)) {
2055 * Create and initialize the new request.
2057 request = request_alloc(); /* never fails */
2059 if ((request->reply = rad_alloc(0)) == NULL) {
2060 radlog(L_ERR, "No memory");
2064 request->listener = listener;
2065 request->client = client;
2066 request->packet = packet;
2067 request->packet->timestamp = request->timestamp;
2068 request->number = request_num_counter++;
2069 request->priority = listener->type;
2072 * Status-Server packets go to the head of the queue.
2074 if (request->packet->code == PW_STATUS_SERVER) request->priority = 0;
2077 * Set virtual server identity
2079 if (client->server) {
2080 request->server = client->server;
2081 } else if (listener->server) {
2082 request->server = listener->server;
2084 request->server = NULL;
2088 * Remember the request in the list.
2090 if (!fr_packet_list_insert(pl, &request->packet)) {
2091 radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number);
2092 request_free(&request);
2096 request->in_request_hash = TRUE;
2097 request->root = root;
2101 * The request passes many of our sanity checks.
2102 * From here on in, if anything goes wrong, we
2103 * send a reject message, instead of dropping the
2108 * Build the reply template from the request.
2111 request->reply->sockfd = request->packet->sockfd;
2112 request->reply->dst_ipaddr = request->packet->src_ipaddr;
2113 request->reply->src_ipaddr = request->packet->dst_ipaddr;
2114 request->reply->dst_port = request->packet->src_port;
2115 request->reply->src_port = request->packet->dst_port;
2116 request->reply->id = request->packet->id;
2117 request->reply->code = 0; /* UNKNOWN code */
2118 memcpy(request->reply->vector, request->packet->vector,
2119 sizeof(request->reply->vector));
2120 request->reply->vps = NULL;
2121 request->reply->data = NULL;
2122 request->reply->data_len = 0;
2124 request->master_state = REQUEST_ACTIVE;
2125 request->child_state = REQUEST_QUEUED;
2126 request->next_callback = NULL;
2128 gettimeofday(&request->received, NULL);
2129 request->timestamp = request->received.tv_sec;
2130 request->when = request->received;
2132 request->delay = USEC;
2134 tv_add(&request->when, request->delay);
2136 INSERT_EVENT(wait_a_bit, request);
2138 *prequest = request;
2144 REQUEST *received_proxy_response(RADIUS_PACKET *packet)
2150 if (!home_server_find(&packet->src_ipaddr, packet->src_port)) {
2151 radlog(L_ERR, "Ignoring request from unknown home server %s port %d",
2152 inet_ntop(packet->src_ipaddr.af,
2153 &packet->src_ipaddr.ipaddr,
2154 buffer, sizeof(buffer)),
2161 * Also removes from the proxy hash if responses == requests
2163 request = lookup_in_proxy_hash(packet);
2166 radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d",
2167 inet_ntop(packet->src_ipaddr.af,
2168 &packet->src_ipaddr.ipaddr,
2169 buffer, sizeof(buffer)),
2170 packet->src_port, packet->id);
2175 home = request->home_server;
2177 gettimeofday(&now, NULL);
2179 home->state = HOME_STATE_ALIVE;
2181 if (request->reply && request->reply->code != 0) {
2182 RDEBUG2("We already replied to this request. Discarding response from home server.");
2188 * We had previously received a reply, so we don't need
2189 * to do anything here.
2191 if (request->proxy_reply) {
2192 if (memcmp(request->proxy_reply->vector,
2194 sizeof(request->proxy_reply->vector)) == 0) {
2195 RDEBUG2("Discarding duplicate reply from home server %s port %d - ID: %d for request %d",
2196 inet_ntop(packet->src_ipaddr.af,
2197 &packet->src_ipaddr.ipaddr,
2198 buffer, sizeof(buffer)),
2199 packet->src_port, packet->id,
2203 * ? The home server gave us a new proxy
2204 * reply, which doesn't match the old
2207 RDEBUG2("Ignoring conflicting proxy reply");
2210 /* assert that there's an event queued for request? */
2216 * The average includes our time to receive packets and
2217 * look them up in the hashes, which should be the same
2220 * We update the response time only for the FIRST packet
2223 else if (home->ema.window > 0) {
2224 radius_stats_ema(&home->ema, &now, &request->proxy_when);
2229 switch (request->child_state) {
2230 case REQUEST_QUEUED:
2231 case REQUEST_RUNNING:
2232 rad_panic("Internal sanity check failed for child state");
2235 case REQUEST_REJECT_DELAY:
2236 case REQUEST_CLEANUP_DELAY:
2238 radlog(L_ERR, "Reply from home server %s port %d - ID: %d arrived too late for request %d. Try increasing 'retry_delay' or 'max_request_time'",
2239 inet_ntop(packet->src_ipaddr.af,
2240 &packet->src_ipaddr.ipaddr,
2241 buffer, sizeof(buffer)),
2242 packet->src_port, packet->id,
2244 /* assert that there's an event queued for request? */
2248 case REQUEST_PROXIED:
2252 request->proxy_reply = packet;
2256 * Perform RTT calculations, as per RFC 2988 (for TCP).
2257 * Note that we do so only if we sent one request, and
2258 * received one response. If we sent two requests, we
2259 * have no idea if the response is for the first, or for
2260 * the second request/
2262 if (request->num_proxied_requests == 1) {
2264 home_server *home = request->home_server;
2266 rtt = now.tv_sec - request->proxy_when.tv_sec;
2269 rtt -= request->proxy_when.tv_usec;
2271 if (!home->has_rtt) {
2272 home->has_rtt = TRUE;
2275 home->rttvar = rtt / 2;
2278 home->rttvar -= home->rttvar >> 2;
2279 home->rttvar += (home->srtt - rtt);
2280 home->srtt -= home->srtt >> 3;
2281 home->srtt += rtt >> 3;
2284 home->rto = home->srtt;
2285 if (home->rttvar > (USEC / 4)) {
2286 home->rto += home->rttvar * 4;
2294 * There's no incoming request, so it's a proxied packet
2297 if (!request->packet) {
2298 received_response_to_ping(request);
2302 request->child_state = REQUEST_QUEUED;
2303 request->when = now;
2304 request->delay = USEC;
2305 request->priority = RAD_LISTEN_PROXY;
2306 tv_add(&request->when, request->delay);
2309 * Wait a bit will take care of max_request_time
2311 INSERT_EVENT(wait_a_bit, request);
2317 void event_new_fd(rad_listen_t *this)
2321 this->print(this, buffer, sizeof(buffer));
2323 if (this->status == RAD_LISTEN_STATUS_INIT) {
2324 DEBUG2(" ... adding new socket %s", buffer);
2326 if (!fr_event_fd_insert(el, 0, this->fd,
2327 event_socket_handler, this)) {
2328 radlog(L_ERR, "Failed remembering handle for proxy socket!");
2332 this->status = RAD_LISTEN_STATUS_KNOWN;
2336 if (this->status == RAD_LISTEN_STATUS_CLOSED) {
2337 DEBUG2(" ... closing socket %s", buffer);
2339 fr_event_fd_delete(el, 0, this->fd);
2340 this->status = RAD_LISTEN_STATUS_FINISH;
2343 * Close the fd AFTER fixing up the requests and
2344 * listeners, so that they don't send/recv on the
2345 * wrong socket (if someone manages to open
2354 static void event_detail_timer(void *ctx)
2356 rad_listen_t *listener = ctx;
2357 RAD_REQUEST_FUNP fun;
2360 if (listener->recv(listener, &fun, &request)) {
2361 if (!thread_pool_addrequest(request, fun)) {
2362 request->child_state = REQUEST_DONE;
2368 static void handle_signal_self(int flag)
2370 if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
2371 if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
2372 fr_event_loop_exit(el, 1);
2374 fr_event_loop_exit(el, 2);
2378 } /* else exit/term flags weren't set */
2381 * Tell the even loop to stop processing.
2383 if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
2385 static time_t last_hup = 0;
2387 DEBUG("Received HUP signal.");
2390 if ((int) (when - last_hup) < 5) {
2391 radlog(L_INFO, "Ignoring HUP (less than 5s since last one)");
2396 fr_event_loop_exit(el, 0x80);
2400 if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
2403 for (this = mainconfig.listen;
2405 this = this->next) {
2407 struct timeval when;
2409 if (this->type != RAD_LISTEN_DETAIL) continue;
2411 delay = detail_delay(this);
2412 if (!delay) continue;
2414 fr_event_now(el, &now);
2416 tv_add(&when, delay);
2418 if (delay > 100000) {
2419 DEBUG("Delaying next detail event for %d.%01u seconds.",
2420 delay / USEC, (delay % USEC) / 100000);
2423 if (!fr_event_insert(el, event_detail_timer, this,
2425 radlog(L_ERR, "Failed remembering timer");
2432 if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
2435 for (this = mainconfig.listen;
2437 this = this->next) {
2438 if (this->status == RAD_LISTEN_STATUS_KNOWN) continue;
2446 void radius_signal_self(int flag)
2448 handle_signal_self(flag);
2452 * Inform ourselves that we received a signal.
2454 void radius_signal_self(int flag)
2460 * The read MUST be non-blocking for this to work.
2462 rcode = read(self_pipe[0], buffer, sizeof(buffer));
2466 for (i = 0; i < rcode; i++) {
2467 buffer[0] |= buffer[i];
2475 write(self_pipe[1], buffer, 1);
2479 static void event_signal_handler(UNUSED fr_event_list_t *xel,
2480 UNUSED int fd, UNUSED void *ctx)
2485 rcode = read(self_pipe[0], buffer, sizeof(buffer));
2486 if (rcode <= 0) return;
2489 * Merge pending signals.
2491 for (i = 0; i < rcode; i++) {
2492 buffer[0] |= buffer[i];
2495 handle_signal_self(buffer[0]);
2500 static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd,
2503 rad_listen_t *listener = ctx;
2504 RAD_REQUEST_FUNP fun;
2507 rad_assert(xel == el);
2511 if (listener->fd < 0) rad_panic("Socket was closed on us!");
2513 if (!listener->recv(listener, &fun, &request)) return;
2515 if (!thread_pool_addrequest(request, fun)) {
2516 request->child_state = REQUEST_DONE;
2522 * This function is called periodically to see if any FD's are
2523 * available for reading.
2525 static void event_poll_detail(UNUSED void *ctx)
2528 RAD_REQUEST_FUNP fun;
2531 struct timeval when;
2533 fr_event_now(el, &now);
2537 for (this = mainconfig.listen; this != NULL; this = this->next) {
2538 if (this->type != RAD_LISTEN_DETAIL) continue;
2540 if (this->fd >= 0) continue;
2543 * Try to read something.
2545 * FIXME: This does poll AND receive.
2547 rcode = this->recv(this, &fun, &request);
2548 if (!rcode) continue;
2550 rad_assert(fun != NULL);
2551 rad_assert(request != NULL);
2553 if (!thread_pool_addrequest(request, fun)) {
2554 request->child_state = REQUEST_DONE;
2561 if (!fr_event_insert(el, event_poll_detail, NULL,
2563 radlog(L_ERR, "Failed creating handler");
2569 static void event_status(struct timeval *wake)
2571 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
2575 if (debug_flag == 0) {
2577 radlog(L_INFO, "Ready to process requests.");
2578 just_started = FALSE;
2584 DEBUG("Ready to process requests.");
2586 } else if ((wake->tv_sec != 0) ||
2587 (wake->tv_usec >= 100000)) {
2588 DEBUG("Waking up in %d.%01u seconds.",
2589 (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
2594 * FIXME: Put this somewhere else, where it isn't called
2595 * all of the time...
2598 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
2600 * If there are no child threads, then there may
2601 * be child processes. In that case, wait for
2602 * their exit status, and throw that exit status
2603 * away. This helps get rid of zxombie children.
2605 while (waitpid(-1, &argval, WNOHANG) > 0) {
2614 * Externally-visibly functions.
2616 int radius_event_init(CONF_SECTION *cs, int spawn_flag)
2618 rad_listen_t *this, *head = NULL;
2622 time(&fr_start_time);
2624 el = fr_event_list_create(event_status);
2627 pl = fr_packet_list_create(0);
2630 request_num_counter = 0;
2633 * Move all of the thread calls to this file?
2635 * It may be best for the mutexes to be in this file...
2637 have_children = spawn_flag;
2640 if (mainconfig.proxy_requests) {
2642 * Create the tree for managing proxied requests and
2645 proxy_list = fr_packet_list_create(1);
2646 if (!proxy_list) return 0;
2648 #ifdef HAVE_PTHREAD_H
2649 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
2650 radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
2659 * Just before we spawn the child threads, force the log
2660 * subsystem to re-open the log file for every write.
2662 if (spawn_flag) force_log_reopen();
2664 #ifdef HAVE_PTHREAD_H
2665 if (thread_pool_init(cs, spawn_flag) < 0) {
2671 DEBUG("%s: #### Skipping IP addresses and Ports ####",
2678 * Child threads need a pipe to signal us, as do the
2681 if (pipe(self_pipe) < 0) {
2682 radlog(L_ERR, "radiusd: Error opening internal pipe: %s",
2686 if (fcntl(self_pipe[0], F_SETFL, O_NONBLOCK | FD_CLOEXEC) < 0) {
2687 radlog(L_ERR, "radiusd: Error setting internal flags: %s",
2691 if (fcntl(self_pipe[1], F_SETFL, O_NONBLOCK | FD_CLOEXEC) < 0) {
2692 radlog(L_ERR, "radiusd: Error setting internal flags: %s",
2697 if (!fr_event_fd_insert(el, 0, self_pipe[0],
2698 event_signal_handler, el)) {
2699 radlog(L_ERR, "Failed creating handler for signals");
2706 * Mark the proxy Fd's as unused.
2711 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
2715 DEBUG("%s: #### Opening IP addresses and Ports ####",
2718 if (listen_init(cs, &head) < 0) {
2723 * Add all of the sockets to the event loop.
2727 this = this->next) {
2730 this->print(this, buffer, sizeof(buffer));
2732 switch (this->type) {
2734 case RAD_LISTEN_DETAIL:
2735 DEBUG("Listening on %s", buffer);
2736 has_detail_listener = TRUE;
2741 case RAD_LISTEN_PROXY:
2742 rad_assert(proxy_fds[this->fd & 0x1f] == -1);
2743 rad_assert(proxy_listeners[this->fd & 0x1f] == NULL);
2745 proxy_fds[this->fd & 0x1f] = this->fd;
2746 proxy_listeners[this->fd & 0x1f] = this;
2747 if (!fr_packet_list_socket_add(proxy_list,
2755 DEBUG("Listening on %s", buffer);
2760 * The file descriptor isn't ready. Poll for
2761 * when it will become ready. This is for the
2769 * The socket is open. It MUST be a socket,
2770 * as we don't pre-open the detail files (yet).
2772 * FIXME: if we DO open the detail files automatically,
2773 * then much of this code becomes simpler.
2775 if (!fr_event_fd_insert(el, 0, this->fd,
2776 event_socket_handler, this)) {
2777 this->print(this, buffer, sizeof(buffer));
2778 radlog(L_ERR, "Failed creating handler for socket %s",
2783 this->status = RAD_LISTEN_STATUS_KNOWN;
2786 if (has_detail_listener) {
2787 struct timeval when;
2789 gettimeofday(&when, NULL);
2792 if (!fr_event_insert(el, event_poll_detail, NULL,
2794 radlog(L_ERR, "Failed creating handler");
2799 mainconfig.listen = head;
2805 static int request_hash_cb(UNUSED void *ctx, void *data)
2807 REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
2810 rad_assert(request->in_proxy_hash == FALSE);
2813 fr_event_delete(el, &request->ev);
2814 remove_from_request_hash(request);
2815 request_free(&request);
2822 static int proxy_hash_cb(UNUSED void *ctx, void *data)
2824 REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
2826 fr_packet_list_yank(proxy_list, request->proxy);
2827 request->in_proxy_hash = FALSE;
2829 if (!request->in_request_hash) {
2830 fr_event_delete(el, &request->ev);
2831 request_free(&request);
2838 void radius_event_free(void)
2841 * FIXME: Stop all threads, or at least check that
2842 * they're all waiting on the semaphore, and the queues
2848 * There are requests in the proxy hash that aren't
2849 * referenced from anywhere else. Remove them first.
2852 PTHREAD_MUTEX_LOCK(&proxy_mutex);
2853 fr_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
2854 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
2855 fr_packet_list_free(proxy_list);
2860 fr_packet_list_walk(pl, NULL, request_hash_cb);
2862 fr_packet_list_free(pl);
2865 fr_event_list_free(el);
2868 int radius_event_process(void)
2872 just_started = TRUE;
2874 return fr_event_loop(el);
2877 void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun)
2879 request->options = RAD_REQUEST_OPTION_DEBUG2;
2881 if (request_pre_handler(request)) {
2882 rad_assert(fun != NULL);
2883 rad_assert(request != NULL);
2885 if (request->server) RDEBUG("server %s {",
2889 if (request->server) RDEBUG("} # server %s",
2892 request_post_handler(request);
2895 DEBUG2("Going to the next request");