2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * @brief Defines the state machines that control how requests are processed.
23 * @copyright 2012 The FreeRADIUS server project
24 * @copyright 2012 Alan DeKok <aland@deployingradius.com>
27 #include <freeradius-devel/ident.h>
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/process.h>
32 #include <freeradius-devel/event.h>
33 #include <freeradius-devel/packet.h>
34 #include <freeradius-devel/modules.h>
36 #include <freeradius-devel/rad_assert.h>
39 #include <freeradius-devel/detail.h>
45 #ifdef HAVE_SYS_WAIT_H
46 # include <sys/wait.h>
51 extern pid_t radius_pid;
52 extern int check_config;
53 extern char *debug_condition;
55 static int spawn_flag = 0;
56 static int just_started = TRUE;
58 static fr_packet_list_t *pl = NULL;
59 static fr_event_list_t *el = NULL;
61 static const char *action_codes[] = {
73 #ifdef DEBUG_STATE_MACHINE
74 #define TRACE_STATE_MACHINE if (debug_flag) printf("(%u) ********\tSTATE %s action %s live M%u C%u\t********\n", request->number, __FUNCTION__, action_codes[action], request->master_state, request->child_state)
76 #define TRACE_STATE_MACHINE {}
80 * Declare a state in the state machine.
83 #define STATE_MACHINE_DECL(_x) static void _x(REQUEST *request, int action)
85 #define STATE_MACHINE_TIMER(_x) request->timer_action = _x; \
86 fr_event_insert(el, request_timer, request, \
92 * @section request_timeline
94 * Time sequence of a request
97 * RQ-----------------P=============================Y-J-C
98 * ::::::::::::::::::::::::::::::::::::::::::::::::::::::::M
101 * - R: received. Duplicate detection is done, and request is
104 * - Q: Request is placed onto a queue for child threads to pick up.
105 * If there are no child threads, the request goes immediately
108 * - P: Processing the request through the modules.
110 * - Y: Reply is ready. Rejects MAY be delayed here. All other
111 * replies are sent immediately.
113 * - J: Reject is sent "reject_delay" after the reply is ready.
115 * - C: For Access-Requests, After "cleanup_delay", the request is
116 * deleted. Accounting-Request packets go directly from Y to C.
118 * - M: Max request time. If the request hits this timer, it is
121 * Other considerations include duplicate and conflicting
122 * packets. When a dupicate packet is received, it is ignored
123 * until we've reached Y, as no response is ready. If the reply
124 * is a reject, duplicates are ignored until J, when we're ready
125 * to send the reply. In between the reply being sent (Y or J),
126 * and C, the server responds to duplicates by sending the cached
129 * Conflicting packets are sent in 2 situations.
131 * The first is in between R and Y. In that case, we consider
132 * it as a hint that we're taking too long, and the NAS has given
133 * up on the request. We then behave just as if the M timer was
134 * reached, and we discard the current request. This allows us
135 * to process the new one.
137 * The second case is when we're at Y, but we haven't yet
138 * finished processing the request. This is a race condition in
139 * the threading code (avoiding locks is faster). It means that
140 * a thread has actually encoded and sent the reply, and that the
141 * NAS has responded with a new packet. The server can then
142 * safely mark the current request as "OK to delete", and behaves
143 * just as if the M timer was reached. This usually happens only
144 * in high-load situations.
146 * Duplicate packets are sent when the NAS thinks we're taking
147 * too long, and wants a reply. From R-Y, duplicates are
148 * ignored. From Y-J (for Access-Rejects), duplicates are also
149 * ignored. From Y-C, duplicates get a duplicate reply. *And*,
150 * they cause the "cleanup_delay" time to be extended. This
151 * extension means that we're more likely to send a duplicate
152 * reply (if we have one), or to suppress processing the packet
153 * twice if we didn't reply to it.
155 * All functions in this file should be thread-safe, and should
156 * assume thet the REQUEST structure is being accessed
157 * simultaneously by the main thread, and by the child worker
158 * threads. This means that timers, etc. cannot be updated in
161 * Instead, the master thread periodically calls request->process
162 * with action TIMER. It's up to the individual functions to
163 * determine how to handle that. They need to check if they're
164 * being called from a child thread or the master, and then do
165 * different things based on that.
170 static fr_packet_list_t *proxy_list = NULL;
173 #ifdef HAVE_PTHREAD_H
175 static pthread_mutex_t proxy_mutex;
176 static rad_listen_t *proxy_listener_list = NULL;
177 static int proxy_no_new_sockets = FALSE;
180 #define PTHREAD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
181 #define PTHREAD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
183 static pthread_t NO_SUCH_CHILD_PID;
186 * This is easier than ifdef's throughout the code.
188 #define PTHREAD_MUTEX_LOCK(_x)
189 #define PTHREAD_MUTEX_UNLOCK(_x)
193 * We need mutexes around the event FD list *only* in certain
196 #if defined (HAVE_PTHREAD_H) && (defined(WITH_PROXY) || defined(WITH_TCP))
197 static pthread_mutex_t fd_mutex;
198 #define FD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
199 #define FD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
202 * This is easier than ifdef's throughout the code.
204 #define FD_MUTEX_LOCK(_x)
205 #define FD_MUTEX_UNLOCK(_x)
208 static int request_num_counter = 0;
210 static int request_will_proxy(REQUEST *request);
211 static int request_proxy(REQUEST *request, int retransmit);
212 STATE_MACHINE_DECL(proxy_wait_for_reply);
213 STATE_MACHINE_DECL(proxy_running);
214 static int process_proxy_reply(REQUEST *request);
215 static void remove_from_proxy_hash(REQUEST *request);
216 static void remove_from_proxy_hash_nl(REQUEST *request);
217 static int insert_into_proxy_hash(REQUEST *request);
220 STATE_MACHINE_DECL(request_common);
222 #if defined(HAVE_PTHREAD_H) && !defined (NDEBUG)
223 static int we_are_master(void)
226 (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
232 #define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
235 #define we_are_master(_x) (1)
236 #define ASSERT_MASTER
239 STATE_MACHINE_DECL(request_reject_delay);
240 STATE_MACHINE_DECL(request_cleanup_delay);
241 STATE_MACHINE_DECL(request_running);
243 static void request_coa_timer(REQUEST *request);
244 static void request_coa_originate(REQUEST *request);
245 STATE_MACHINE_DECL(request_coa_process);
246 static void request_coa_separate(REQUEST *coa);
250 #define USEC (1000000)
252 #define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
254 static void NEVER_RETURNS _rad_panic(const char *file, unsigned int line,
257 radlog(L_ERR, "[%s:%d] %s", file, line, msg);
261 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
263 static void tv_add(struct timeval *tv, int usec_delay)
265 if (usec_delay >= USEC) {
266 tv->tv_sec += usec_delay / USEC;
269 tv->tv_usec += usec_delay;
271 if (tv->tv_usec >= USEC) {
272 tv->tv_sec += tv->tv_usec / USEC;
278 * In daemon mode, AND this request has debug flags set.
280 #define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
282 static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
286 const char *received, *from;
287 const fr_ipaddr_t *ip;
292 rad_assert(request->radlog != NULL);
294 if (direction == 0) {
295 received = "Received";
296 from = "from"; /* what else? */
297 ip = &packet->src_ipaddr;
298 port = packet->src_port;
301 received = "Sending";
302 from = "to"; /* hah! */
303 ip = &packet->dst_ipaddr;
304 port = packet->dst_port;
308 * Client-specific debugging re-prints the input
309 * packet into the client log.
311 * This really belongs in a utility library
313 if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
314 RDEBUG("%s %s packet %s host %s port %d, id=%d, length=%d",
315 received, fr_packet_codes[packet->code], from,
316 inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
317 port, packet->id, packet->data_len);
319 RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%d",
321 inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
323 packet->code, packet->id, packet->data_len);
326 for (vp = packet->vps; vp != NULL; vp = vp->next) {
327 vp_prints(buffer, sizeof(buffer), vp);
328 request->radlog(L_DBG, 0, request, "\t%s", buffer);
333 /***********************************************************************
335 * Start of RADIUS server state machine.
337 ***********************************************************************/
340 * Callback for ALL timer events related to the request.
342 static void request_timer(void *ctx)
344 REQUEST *request = ctx;
345 int action = request->timer_action;
349 request->process(request, action);
352 #define USEC (1000000)
355 * Only ever called from the master thread.
357 STATE_MACHINE_DECL(request_done)
359 struct timeval now, when;
365 * CoA requests can be cleaned up in the child thread,
366 * but ONLY if they aren't tied into anything.
368 if (request->parent && (request->parent->coa == request)) {
369 rad_assert(!request->in_request_hash);
370 rad_assert(!request->in_proxy_hash);
371 rad_assert(action == FR_ACTION_DONE);
372 rad_assert(request->ev == NULL);
380 * Mark ourselves as handling the request.
382 request->process = request_done;
383 request->master_state = REQUEST_STOP_PROCESSING;
387 * Move the CoA request to its own handler.
389 if (request->coa) request_coa_separate(request->coa);
392 * If we're the CoA request, make the parent forget about
395 if (request->parent && (request->parent->coa == request)) {
396 request->parent->coa = NULL;
402 * It doesn't hurt to send duplicate replies. All other
403 * signals are ignored, as the request will be cleaned up
408 if (request->reply->code != 0) {
409 request->listener->send(request->listener, request);
415 * This is only called from the master thread
416 * when there is a child thread processing the
419 case FR_ACTION_CONFLICTING:
420 if (request->child_state == REQUEST_DONE) break;
423 * If there's a reply packet, then we presume
424 * that the child has sent the reply, and we get
425 * pinged here before the child has a chance to
428 if (request->reply->data) break;
430 radlog_request(L_ERR, 0, request,
431 "Received conflicting packet from "
432 "client %s port %d - ID: %d due to "
433 "unfinished request. Giving up on old request.",
434 request->client->shortname,
435 request->packet->src_port, request->packet->id);
439 * Called only when there's an error remembering
440 * the packet, or when the socket gets closed from
444 #ifdef HAVE_PTHREAD_H
446 * If we have child threads and we're NOT the
447 * thread handling the request, don't do anything.
450 !pthread_equal(pthread_self(), request->child_pid)) {
454 #ifdef DEBUG_STATE_MACHINE
455 if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
457 request->child_state = REQUEST_DONE;
461 * Called when the child is taking too long to
462 * finish. We've already marked it "please
463 * stop", so we don't complain any more.
465 case FR_ACTION_TIMER:
470 * Child is still alive, and we're receiving more
471 * packets from the home server.
473 case FR_ACTION_PROXY_REPLY:
474 request_common(request, action);
479 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
484 * Remove it from the request hash.
486 if (request->in_request_hash) {
487 fr_packet_list_yank(pl, request->packet);
488 request->in_request_hash = FALSE;
490 request_stats_final(request);
493 request->listener->count--;
499 * Wait for the proxy ID to expire. This allows us to
500 * avoid re-use of proxy IDs for a while.
502 if (request->in_proxy_hash) {
503 rad_assert(request->proxy != NULL);
505 fr_event_now(el, &now);
506 when = request->proxy->timestamp;
509 if (((request->proxy->code == PW_COA_REQUEST) ||
510 (request->proxy->code == PW_DISCONNECT_REQUEST)) &&
511 (request->packet->code != request->proxy->code)) {
512 when.tv_sec += request->home_server->coa_mrd;
515 when.tv_sec += request->home_server->response_window;
518 * We haven't received all responses, AND there's still
519 * time to wait. Do so.
521 if ((request->num_proxied_requests > request->num_proxied_responses) &&
523 (request->home_server->proto != IPPROTO_TCP) &&
525 timercmp(&now, &when, <)) {
526 RDEBUG("Waiting for more responses from the home server");
533 remove_from_proxy_hash(request);
537 if (request->child_state != REQUEST_DONE) {
539 #ifdef HAVE_PTHREAD_H
543 rad_assert("Internal sanity check failed");
547 gettimeofday(&now, NULL);
552 #ifdef HAVE_PTHREAD_H
554 (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
555 RDEBUG("Waiting for child thread to stop");
560 tv_add(&when, request->delay);
561 request->delay += request->delay >> 1;
562 if (request->delay > (10 * USEC)) request->delay = 10 * USEC;
564 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
568 #ifdef HAVE_PTHREAD_H
569 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
572 if (request->packet) {
573 RDEBUG2("Cleaning up request packet ID %d with timestamp +%d",
575 (unsigned int) (request->timestamp - fr_start_time));
576 } /* else don't print anything */
578 if (request->ev) fr_event_delete(el, &request->ev);
580 request_free(&request);
584 static void request_cleanup_delay_init(REQUEST *request, const struct timeval *pnow)
586 struct timeval now, when;
588 if (request->packet->code == PW_ACCOUNTING_REQUEST) goto done;
589 if (!request->root->cleanup_delay) goto done;
594 gettimeofday(&now, NULL);
597 if (request->reply->timestamp.tv_sec == 0) {
600 when = request->reply->timestamp;
602 request->delay = request->root->cleanup_delay;
603 when.tv_sec += request->delay;
606 * Set timer for when we need to clean it up.
608 if (timercmp(&when, &now, >)) {
609 #ifdef DEBUG_STATE_MACHINE
610 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
612 request->process = request_cleanup_delay;
613 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
618 * Otherwise just clean it up.
621 request_done(request, FR_ACTION_DONE);
626 * Function to do all time-related events.
628 static void request_process_timer(REQUEST *request)
630 struct timeval now, when;
631 rad_assert(request->magic == REQUEST_MAGIC);
632 #ifdef DEBUG_STATE_MACHINE
633 int action = FR_ACTION_TIMER;
641 * If we originated a CoA request, divorce it from the
642 * parent. Then, set up the timers so that we can clean
643 * it up as appropriate.
645 if (request->coa) request_coa_separate(request->coa);
648 * Check request stuff ONLY if we're running the request.
650 if (!request->proxy || (request->packet->code == request->proxy->code))
653 rad_assert(request->listener != NULL);
656 * The socket was closed. Tell the request that
657 * there is no point in continuing.
659 if (request->listener->status != RAD_LISTEN_STATUS_KNOWN) {
660 DEBUGW("Socket was closed while processing request %u: Stopping it.", request->number);
665 gettimeofday(&now, NULL);
668 * A child thread is still working on the request,
669 * OR it was proxied, and there was no response,
670 * OR it was sitting in the queue for too long.
672 if ((request->child_state != REQUEST_DONE) &&
673 (request->master_state != REQUEST_STOP_PROCESSING)) {
674 when = request->packet->timestamp;
675 when.tv_sec += request->root->max_request_time;
678 * Taking too long: tell it to die.
680 if (timercmp(&now, &when, >=)) {
681 #ifdef HAVE_PTHREAD_H
683 * If there's a child thread processing it,
687 (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
688 radlog(L_ERR, "WARNING: Unresponsive child for request %u, in component %s module %s",
690 request->component ? request->component : "<server core>",
691 request->module ? request->module : "<server core>");
692 exec_trigger(request, NULL, "server.thread.unresponsive", TRUE);
697 * Tell the request to stop it.
700 } /* else we're not at max_request_time */
703 if ((request->master_state != REQUEST_STOP_PROCESSING) &&
705 (request->process == request_running)) {
706 #ifdef DEBUG_STATE_MACHINE
707 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_proxied");
709 request->process = proxy_wait_for_reply;
714 * Wake up again in the future, to check for
718 tv_add(&when, request->delay);
719 request->delay += request->delay >> 1;
721 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
725 #ifdef WITH_ACCOUNTING
726 if (request->reply->code == PW_ACCOUNTING_RESPONSE) {
728 request_done(request, FR_ACTION_DONE);
734 if (!request->proxy || (request->packet->code == request->proxy->code))
737 if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
738 (request->root->reject_delay)) {
739 when = request->reply->timestamp;
740 when.tv_sec += request->root->reject_delay;
743 * Set timer for when we need to send it.
745 if (timercmp(&when, &now, >)) {
746 #ifdef DEBUG_STATE_MACHINE
747 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_reject_delay");
749 request->process = request_reject_delay;
751 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
755 if (request->process == request_reject_delay) {
757 * Assume we're at (or near) the reject
760 request->reply->timestamp = now;
762 RDEBUG2("Sending delayed reject");
763 DEBUG_PACKET(request, request->reply, 1);
764 request->process = request_cleanup_delay;
765 request->listener->send(request->listener, request);
770 * The cleanup_delay is zero for accounting packets, and
771 * enforced for all other packets. We do the
772 * cleanup_delay even if we don't respond to the NAS, so
773 * that any retransmit is *not* processed as a new packet.
775 request_cleanup_delay_init(request, &now);
779 static void request_queue_or_run(UNUSED REQUEST *request,
780 fr_request_process_t process)
783 #ifdef DEBUG_STATE_MACHINE
784 int action = FR_ACTION_TIMER;
791 * (re) set the initial delay.
793 request->delay = USEC / 3;
794 gettimeofday(&when, NULL);
795 tv_add(&when, request->delay);
796 request->delay += request->delay >> 1;
798 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
801 * Do this here so that fewer other functions need to do
804 if (request->master_state == REQUEST_STOP_PROCESSING) {
805 #ifdef DEBUG_STATE_MACHINE
806 if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
808 request_done(request, FR_ACTION_DONE);
812 request->process = process;
814 #ifdef HAVE_PTHREAD_H
816 if (!request_enqueue(request)) {
817 request_done(request, FR_ACTION_DONE);
824 request->process(request, FR_ACTION_RUN);
828 * Requests that care about child process exit
829 * codes have already either called
830 * rad_waitpid(), or they've given up.
837 STATE_MACHINE_DECL(request_common)
848 if ((request->master_state != REQUEST_STOP_PROCESSING) &&
849 request->proxy && !request->proxy_reply) {
851 * TODO: deal with this in a better way?
853 proxy_wait_for_reply(request, action);
857 radlog(L_ERR, "(%u) Discarding duplicate request from "
858 "client %s port %d - ID: %u due to unfinished request",
859 request->number, request->client->shortname,
860 request->packet->src_port,request->packet->id);
863 case FR_ACTION_CONFLICTING:
865 * We're in the master thread, ask the child to
866 * stop processing the request.
868 request_done(request, action);
871 case FR_ACTION_TIMER:
872 request_process_timer(request);
876 case FR_ACTION_PROXY_REPLY:
877 DEBUG2("Reply from home server %s port %d - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'",
878 inet_ntop(request->proxy->src_ipaddr.af,
879 &request->proxy->src_ipaddr.ipaddr,
880 buffer, sizeof(buffer)),
881 request->proxy->dst_port, request->proxy->id,
887 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
892 STATE_MACHINE_DECL(request_cleanup_delay)
901 if (request->reply->code != 0) {
902 request->listener->send(request->listener, request);
904 RDEBUG("No reply. Ignoring retransmit.");
908 * Double the cleanup_delay to catch retransmits.
910 when = request->reply->timestamp;
911 request->delay += request->delay ;
912 when.tv_sec += request->delay;
914 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
918 case FR_ACTION_PROXY_REPLY:
920 case FR_ACTION_CONFLICTING:
921 case FR_ACTION_TIMER:
922 request_common(request, action);
926 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
931 STATE_MACHINE_DECL(request_reject_delay)
938 radlog(L_ERR, "(%u) Discarding duplicate request from "
939 "client %s port %d - ID: %u due to delayed reject",
940 request->number, request->client->shortname,
941 request->packet->src_port,request->packet->id);
945 case FR_ACTION_PROXY_REPLY:
947 case FR_ACTION_CONFLICTING:
948 case FR_ACTION_TIMER:
949 request_common(request, action);
953 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
959 static int request_pre_handler(REQUEST *request, UNUSED int action)
965 if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
968 * Don't decode the packet if it's an internal "fake"
969 * request. Instead, just return so that the caller can
972 if (request->packet->dst_port == 0) {
973 request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
974 request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
980 * Put the decoded packet into it's proper place.
982 if (request->proxy_reply != NULL) {
983 rcode = request->proxy_listener->decode(request->proxy_listener, request);
984 DEBUG_PACKET(request, request->proxy_reply, 0);
987 * Pro-actively remove it from the proxy hash.
988 * This is later than in 2.1.x, but it means that
989 * the replies are authenticated before being
990 * removed from the hash.
993 (request->num_proxied_requests <= request->num_proxied_responses)) {
994 remove_from_proxy_hash(request);
999 if (request->packet->vps == NULL) {
1000 rcode = request->listener->decode(request->listener, request);
1003 if (debug_condition) {
1005 const char *my_debug = debug_condition;
1008 * Ignore parse errors.
1010 (void) radius_evaluate_condition(request, RLM_MODULE_OK,
1014 request->options = 2;
1015 request->radlog = radlog_request;
1020 DEBUG_PACKET(request, request->packet, 0);
1026 RDEBUG("Dropping packet without response because of error %s", fr_strerror());
1027 request->reply->offset = -2; /* bad authenticator */
1031 if (!request->username) {
1032 request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
1036 if (action == FR_ACTION_PROXY_REPLY) {
1037 return process_proxy_reply(request);
1044 STATE_MACHINE_DECL(request_finish)
1048 TRACE_STATE_MACHINE;
1050 action = action; /* -Wunused */
1052 if (request->master_state == REQUEST_STOP_PROCESSING) return;
1055 * Don't send replies if there are none to send.
1057 if (!request->in_request_hash) return;
1060 * Catch Auth-Type := Reject BEFORE proxying the packet.
1062 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1064 * Override the response code if a
1065 * control:Response-Packet-Type attribute is present.
1067 vp = pairfind(request->config_items, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
1069 if (vp->vp_integer == 256) {
1070 RDEBUG2("Not responding to request");
1072 request->reply->code = 0;
1074 request->reply->code = vp->vp_integer;
1076 } else if (request->reply->code == 0) {
1077 vp = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY);
1079 if (!vp || (vp->vp_integer != PW_AUTHENTICATION_REJECT)) {
1080 RDEBUG2("There was no response configured: "
1081 "rejecting request");
1084 request->reply->code = PW_AUTHENTICATION_REJECT;
1089 * Copy Proxy-State from the request to the reply.
1091 vp = paircopy2(request->packet->vps, PW_PROXY_STATE, 0, TAG_ANY);
1092 if (vp) pairadd(&request->reply->vps, vp);
1094 switch (request->reply->code)
1096 case PW_AUTHENTICATION_ACK:
1097 rad_postauth(request);
1099 case PW_ACCESS_CHALLENGE:
1100 pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0,
1102 vp = radius_pairmake(request, &request->config_items,
1103 "Post-Auth-Type", "Challenge",
1106 if (vp) rad_postauth(request);
1113 * Run rejected packets through
1115 * Post-Auth-Type = Reject
1117 * We do this separately so ACK and challenge can change the code
1118 * to reject if a module returns reject.
1120 if (request->reply->code == PW_AUTHENTICATION_REJECT) {
1121 pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
1122 vp = radius_pairmake(request, &request->config_items,
1123 "Post-Auth-Type", "Reject",
1125 if (vp) rad_postauth(request);
1129 * Send the reply here.
1131 if ((request->reply->code != PW_AUTHENTICATION_REJECT) ||
1132 (request->root->reject_delay == 0)) {
1133 DEBUG_PACKET(request, request->reply, 1);
1134 request->listener->send(request->listener,
1138 gettimeofday(&request->reply->timestamp, NULL);
1141 * Clean up. These are no longer needed.
1143 pairfree(&request->config_items);
1145 pairfree(&request->packet->vps);
1146 request->username = NULL;
1147 request->password = NULL;
1149 if (request->reply->code != PW_AUTHENTICATION_REJECT) {
1150 pairfree(&request->reply->vps);
1154 if (request->proxy) {
1155 pairfree(&request->proxy->vps);
1157 if (request->proxy_reply) {
1158 pairfree(&request->proxy_reply->vps);
1163 RDEBUG2("Finished request %u.", request->number);
1166 STATE_MACHINE_DECL(request_running)
1168 TRACE_STATE_MACHINE;
1171 case FR_ACTION_CONFLICTING:
1173 case FR_ACTION_TIMER:
1174 request_common(request, action);
1178 case FR_ACTION_PROXY_REPLY:
1179 #ifdef HAVE_PTHREAD_H
1181 * Catch the case of a proxy reply when called
1182 * from the main worker thread.
1184 if (we_are_master() &&
1185 (request->process != proxy_running)) {
1186 request_queue_or_run(request, proxy_running);
1194 if (!request_pre_handler(request, action)) goto done;
1196 rad_assert(request->handle != NULL);
1197 request->handle(request);
1201 * We may need to send a proxied request.
1203 if ((action == FR_ACTION_RUN) &&
1204 request_will_proxy(request)) {
1205 #ifdef DEBUG_STATE_MACHINE
1206 if (debug_flag) printf("(%u) ********\tWill Proxy\t********\n", request->number);
1210 * takes care of setting
1211 * up the post proxy fail
1214 if (request_proxy(request, 0) < 0) goto finished;
1218 #ifdef DEBUG_STATE_MACHINE
1219 if (debug_flag) printf("(%u) ********\tFinished\t********\n", request->number);
1224 * Maybe originate a CoA request.
1226 if ((action == FR_ACTION_RUN) && request->coa) {
1227 request_coa_originate(request);
1232 request_finish(request, action);
1235 #ifdef DEBUG_STATE_MACHINE
1236 if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
1239 #ifdef HAVE_PTHREAD_H
1240 request->child_pid = NO_SUCH_CHILD_PID;
1242 request->child_state = REQUEST_DONE;
1247 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
1252 int request_receive(rad_listen_t *listener, RADIUS_PACKET *packet,
1253 RADCLIENT *client, RAD_REQUEST_FUNP fun)
1256 RADIUS_PACKET **packet_p;
1257 REQUEST *request = NULL;
1259 listen_socket_t *sock = listener->data;
1262 * Set the last packet received.
1264 gettimeofday(&now, NULL);
1265 sock->last_packet = now.tv_sec;
1267 packet_p = fr_packet_list_find(pl, packet);
1269 request = fr_packet2myptr(REQUEST, packet, packet_p);
1270 rad_assert(request->in_request_hash);
1273 * Same src/dst ip/port, length, and
1274 * authentication vector: must be a duplicate.
1276 if ((request->packet->data_len == packet->data_len) &&
1277 (memcmp(request->packet->vector, packet->vector,
1278 sizeof(packet->vector)) == 0)) {
1281 switch (packet->code) {
1282 case PW_AUTHENTICATION_REQUEST:
1283 FR_STATS_INC(auth, total_dup_requests);
1286 #ifdef WITH_ACCOUNTING
1287 case PW_ACCOUNTING_REQUEST:
1288 FR_STATS_INC(acct, total_dup_requests);
1292 case PW_COA_REQUEST:
1293 FR_STATS_INC(coa, total_dup_requests);
1296 case PW_DISCONNECT_REQUEST:
1297 FR_STATS_INC(dsc, total_dup_requests);
1304 #endif /* WITH_STATS */
1306 request->process(request, FR_ACTION_DUP);
1311 * Say we're ignoring the old one, and continue
1312 * to process the new one.
1314 request->process(request, FR_ACTION_CONFLICTING);
1319 * Quench maximum number of outstanding requests.
1321 if (mainconfig.max_requests &&
1322 ((count = fr_packet_list_num_elements(pl)) > mainconfig.max_requests)) {
1323 radlog(L_ERR, "Dropping request (%d is too many): from client %s port %d - ID: %d", count,
1325 packet->src_port, packet->id);
1326 radlog(L_INFO, "WARNING: Please check the configuration file.\n"
1327 "\tThe value for 'max_requests' is probably set too low.\n");
1329 exec_trigger(NULL, NULL, "server.max_requests", TRUE);
1334 * Rate-limit the incoming packets
1336 if (sock->max_rate) {
1339 pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now,
1340 &sock->rate_time, &now);
1342 if (pps > sock->max_rate) {
1343 DEBUG("Dropping request due to rate limiting");
1346 sock->rate_pps_now++;
1349 return request_insert(listener, packet, client, fun, &now);
1352 int request_insert(rad_listen_t *listener, RADIUS_PACKET *packet,
1353 RADCLIENT *client, RAD_REQUEST_FUNP fun,
1354 struct timeval *pnow)
1359 * Create and initialize the new request.
1361 request = request_alloc(); /* never fails */
1363 if ((request->reply = rad_alloc(0)) == NULL) {
1364 radlog(L_ERR, "No memory");
1365 request_free(&request);
1369 request->listener = listener;
1370 request->client = client;
1371 request->packet = packet;
1372 request->packet->timestamp = *pnow;
1373 request->number = request_num_counter++;
1374 request->priority = listener->type;
1375 request->master_state = REQUEST_ACTIVE;
1376 #ifdef DEBUG_STATE_MACHINE
1377 if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_ACTIVE);
1379 request->child_state = REQUEST_ACTIVE;
1380 request->handle = fun;
1381 #ifdef HAVE_PTHREAD_H
1382 request->child_pid = NO_SUCH_CHILD_PID;
1386 request->listener->stats.last_packet = request->packet->timestamp.tv_sec;
1387 if (packet->code == PW_AUTHENTICATION_REQUEST) {
1388 request->client->auth.last_packet = request->packet->timestamp.tv_sec;
1389 radius_auth_stats.last_packet = request->packet->timestamp.tv_sec;
1390 #ifdef WITH_ACCOUNTING
1391 } else if (packet->code == PW_ACCOUNTING_REQUEST) {
1392 request->client->acct.last_packet = request->packet->timestamp.tv_sec;
1393 radius_acct_stats.last_packet = request->packet->timestamp.tv_sec;
1396 #endif /* WITH_STATS */
1399 * Status-Server packets go to the head of the queue.
1401 if (request->packet->code == PW_STATUS_SERVER) request->priority = 0;
1404 * Set virtual server identity
1406 if (client->server) {
1407 request->server = client->server;
1408 } else if (listener->server) {
1409 request->server = listener->server;
1411 request->server = NULL;
1415 * Remember the request in the list.
1417 if (!fr_packet_list_insert(pl, &request->packet)) {
1418 radlog_request(L_ERR, 0, request, "Failed to insert request in the list of live requests: discarding it");
1419 request_done(request, FR_ACTION_DONE);
1423 request->in_request_hash = TRUE;
1424 request->root = &mainconfig;
1425 mainconfig.refcount++;
1427 request->listener->count++;
1431 * The request passes many of our sanity checks.
1432 * From here on in, if anything goes wrong, we
1433 * send a reject message, instead of dropping the
1438 * Build the reply template from the request.
1441 request->reply->sockfd = request->packet->sockfd;
1442 request->reply->dst_ipaddr = request->packet->src_ipaddr;
1443 request->reply->src_ipaddr = request->packet->dst_ipaddr;
1444 request->reply->dst_port = request->packet->src_port;
1445 request->reply->src_port = request->packet->dst_port;
1446 request->reply->id = request->packet->id;
1447 request->reply->code = 0; /* UNKNOWN code */
1448 memcpy(request->reply->vector, request->packet->vector,
1449 sizeof(request->reply->vector));
1450 request->reply->vps = NULL;
1451 request->reply->data = NULL;
1452 request->reply->data_len = 0;
1454 request_queue_or_run(request, request_running);
1461 /***********************************************************************
1465 ***********************************************************************/
1468 * Timer function for all TCP sockets.
1470 static void tcp_socket_timer(void *ctx)
1472 rad_listen_t *listener = ctx;
1473 listen_socket_t *sock = listener->data;
1474 struct timeval end, now;
1476 fr_socket_limit_t *limit;
1478 fr_event_now(el, &now);
1480 switch (listener->type) {
1481 case RAD_LISTEN_PROXY:
1482 limit = &sock->home->limit;
1485 case RAD_LISTEN_AUTH:
1486 case RAD_LISTEN_ACCT:
1487 limit = &sock->limit;
1495 * If we enforce a lifetime, do it now.
1497 if (limit->lifetime > 0) {
1498 end.tv_sec = sock->opened + limit->lifetime;
1501 if (timercmp(&end, &now, <=)) {
1502 listener->print(listener, buffer, sizeof(buffer));
1503 DEBUG("Reached maximum lifetime on socket %s", buffer);
1507 listener->status = RAD_LISTEN_STATUS_CLOSED;
1508 event_new_fd(listener);
1517 * Enforce an idle timeout.
1519 if (limit->idle_timeout > 0) {
1520 struct timeval idle;
1522 rad_assert(sock->last_packet != 0);
1523 idle.tv_sec = sock->last_packet + limit->idle_timeout;
1526 if (timercmp(&idle, &now, <=)) {
1527 listener->print(listener, buffer, sizeof(buffer));
1528 DEBUG("Reached idle timeout on socket %s", buffer);
1533 * Enforce the minimum of idle timeout or lifetime.
1535 if (timercmp(&idle, &end, <)) {
1541 * Wake up at t + 0.5s. The code above checks if the timers
1542 * are <= t. This addition gives us a bit of leeway.
1544 end.tv_usec = USEC / 2;
1546 if (!fr_event_insert(el, tcp_socket_timer, listener, &end, &sock->ev)) {
1547 rad_panic("Failed to insert event");
1553 * Add +/- 2s of jitter, as suggested in RFC 3539
1556 static void add_jitter(struct timeval *when)
1563 jitter ^= (jitter >> 10);
1564 jitter &= ((1 << 22) - 1); /* 22 bits of 1 */
1567 * Add in ~ (4 * USEC) of jitter.
1569 tv_add(when, jitter);
1573 static int disconnect_all_proxied_requests(void *ctx, void *data)
1575 rad_listen_t *this = ctx;
1576 RADIUS_PACKET **proxy_p = data;
1579 request = fr_packet2myptr(REQUEST, proxy, proxy_p);
1580 if (request->proxy->sockfd != this->fd) return 0;
1583 * The normal "remove_from_proxy_hash" tries to grab the
1584 * proxy mutex. We already have it held, so grabbing it
1585 * again will cause a deadlock. Instead, call the "no
1586 * lock" version of the function.
1588 if (request->in_proxy_hash) {
1589 remove_from_proxy_hash_nl(request);
1591 request->proxy_listener = NULL;
1594 * Don't mark it as DONE. The client can retransmit, and
1595 * the packet SHOULD be re-proxied somewhere else.
1599 #endif /* WITH_PROXY */
1601 static int remove_all_requests(void *ctx, void *data)
1603 rad_listen_t *this = ctx;
1604 RADIUS_PACKET **packet_p = data;
1607 request = fr_packet2myptr(REQUEST, packet, packet_p);
1608 if (request->packet->sockfd != this->fd) return 0;
1610 request_done(request, FR_ACTION_DONE);
1613 #endif /* WITH_TCP */
1616 /***********************************************************************
1618 * Proxy handlers for the state machine.
1620 ***********************************************************************/
1622 static void remove_from_proxy_hash_nl(REQUEST *request)
1624 fr_packet_list_yank(proxy_list, request->proxy);
1625 fr_packet_list_id_free(proxy_list, request->proxy);
1628 * On the FIRST reply, decrement the count of outstanding
1629 * requests. Note that this is NOT the count of sent
1630 * packets, but whether or not the home server has
1633 if (request->home_server &&
1634 request->home_server->currently_outstanding) {
1635 request->home_server->currently_outstanding--;
1638 * If we're NOT sending it packets, then we don't know
1639 * if it's alive or dead.
1641 if ((request->home_server->currently_outstanding == 0) &&
1642 (request->home_server->state == HOME_STATE_ALIVE)) {
1643 request->home_server->state = HOME_STATE_UNKNOWN;
1644 request->home_server->last_packet_sent = 0;
1645 request->home_server->last_packet_recv = 0;
1650 request->proxy_listener->count--;
1652 request->proxy_listener = NULL;
1655 * Got from YES in hash, to NO, not in hash while we hold
1656 * the mutex. This guarantees that when another thread
1657 * grabs the mutex, the "not in hash" flag is correct.
1659 request->in_proxy_hash = FALSE;
1662 static void remove_from_proxy_hash(REQUEST *request)
1665 * Check this without grabbing the mutex because it's a
1666 * lot faster that way.
1668 if (!request->in_proxy_hash) return;
1671 * The "not in hash" flag is definitive. However, if the
1672 * flag says that it IS in the hash, there might still be
1673 * a race condition where it isn't.
1675 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1677 if (!request->in_proxy_hash) {
1678 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1682 remove_from_proxy_hash_nl(request);
1684 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1687 static int insert_into_proxy_hash(REQUEST *request)
1691 void *proxy_listener;
1693 rad_assert(request->proxy != NULL);
1694 rad_assert(request->home_server != NULL);
1695 rad_assert(proxy_list != NULL);
1699 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1700 rcode = fr_packet_list_id_alloc(proxy_list,
1701 request->home_server->proto,
1702 request->proxy, &proxy_listener);
1703 request->num_proxied_requests = 1;
1704 request->num_proxied_responses = 0;
1705 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1708 #ifdef HAVE_PTHREAD_H
1709 if (proxy_no_new_sockets) return 0;
1713 * Also locks the proxy mutex, so we have to call
1714 * it with the mutex unlocked. Some systems
1715 * don't support recursive mutexes.
1717 if (!proxy_new_listener(request->home_server, 0)) {
1718 radlog(L_ERR, "Failed to create a new socket for proxying requests.");
1721 request->proxy->src_port = 0; /* Use any new socket */
1725 RDEBUG2E("Failed allocating Id for new socket when proxying requests.");
1732 request->proxy_listener = proxy_listener;
1734 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1735 if (!fr_packet_list_insert(proxy_list, &request->proxy)) {
1736 fr_packet_list_id_free(proxy_list, request->proxy);
1737 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1738 radlog_request(L_PROXY, 0, request, "Failed to insert entry into proxy list.");
1742 request->in_proxy_hash = TRUE;
1745 * Keep track of maximum outstanding requests to a
1746 * particular home server. 'max_outstanding' is
1747 * enforced in home_server_ldb(), in realms.c.
1749 request->home_server->currently_outstanding++;
1752 request->proxy_listener->count++;
1755 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1757 RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
1758 inet_ntop(request->proxy->dst_ipaddr.af,
1759 &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
1760 request->proxy->dst_port,
1761 request->proxy->id);
1766 static int process_proxy_reply(REQUEST *request)
1769 int post_proxy_type = 0;
1773 * Delete any reply we had accumulated until now.
1775 pairfree(&request->reply->vps);
1778 * Run the packet through the post-proxy stage,
1779 * BEFORE playing games with the attributes.
1781 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
1784 * If we have a proxy_reply, and it was a reject, setup
1785 * post-proxy-type Reject
1787 if (!vp && request->proxy_reply &&
1788 request->proxy_reply->code == PW_AUTHENTICATION_REJECT) {
1791 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Reject");
1793 vp = radius_paircreate(request, &request->config_items,
1794 PW_POST_PROXY_TYPE, 0);
1796 vp->vp_integer = dval->value;
1801 post_proxy_type = vp->vp_integer;
1803 RDEBUG2(" Found Post-Proxy-Type %s",
1804 dict_valnamebyattr(PW_POST_PROXY_TYPE, 0,
1808 if (request->home_pool && request->home_pool->virtual_server) {
1809 const char *old_server = request->server;
1811 request->server = request->home_pool->virtual_server;
1812 RDEBUG2(" server %s {", request->server);
1813 rcode = module_post_proxy(post_proxy_type, request);
1815 request->server = old_server;
1817 rcode = module_post_proxy(post_proxy_type, request);
1821 if (request->packet->code == request->proxy->code)
1823 * Don't run the next bit if we originated a CoA
1824 * packet, after receiving an Access-Request or
1825 * Accounting-Request.
1830 * There may NOT be a proxy reply, as we may be
1831 * running Post-Proxy-Type = Fail.
1833 if (request->proxy_reply) {
1835 * Delete the Proxy-State Attributes from
1836 * the reply. These include Proxy-State
1837 * attributes from us and remote server.
1839 pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
1842 * Add the attributes left in the proxy
1843 * reply to the reply list.
1845 pairadd(&request->reply->vps, request->proxy_reply->vps);
1846 request->proxy_reply->vps = NULL;
1849 * Free proxy request pairs.
1851 pairfree(&request->proxy->vps);
1855 default: /* Don't do anything */
1857 case RLM_MODULE_FAIL:
1860 case RLM_MODULE_HANDLED:
1867 int request_proxy_reply(RADIUS_PACKET *packet)
1869 RADIUS_PACKET **proxy_p;
1874 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1875 proxy_p = fr_packet_list_find_byreply(proxy_list, packet);
1878 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1879 radlog(L_PROXY, "No outstanding request was found for reply from host %s port %d - ID %d",
1880 inet_ntop(packet->src_ipaddr.af,
1881 &packet->src_ipaddr.ipaddr,
1882 buffer, sizeof(buffer)),
1883 packet->src_port, packet->id);
1887 request = fr_packet2myptr(REQUEST, proxy, proxy_p);
1888 request->num_proxied_responses++; /* needs to be protected by lock */
1890 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1893 * No reply, BUT the current packet fails verification:
1894 * ignore it. This does the MD5 calculations in the
1895 * server core, but I guess we can fix that later.
1897 if (!request->proxy_reply &&
1898 (rad_verify(packet, request->proxy,
1899 request->home_server->secret) != 0)) {
1900 DEBUG("Ignoring spoofed proxy reply. Signature is invalid");
1905 * The home server sent us a packet which doesn't match
1906 * something we have: ignore it. This is done only to
1907 * catch the case of broken systems.
1909 if (request->proxy_reply &&
1910 (memcmp(request->proxy_reply->vector,
1912 sizeof(request->proxy_reply->vector)) != 0)) {
1913 RDEBUG2("Ignoring conflicting proxy reply");
1917 gettimeofday(&now, NULL);
1920 * Status-Server packets don't count as real packets.
1922 if (request->proxy->code != PW_STATUS_SERVER) {
1923 listen_socket_t *sock = request->proxy_listener->data;
1925 request->home_server->last_packet_recv = now.tv_sec;
1926 sock->last_packet = now.tv_sec;
1930 * If we have previously seen a reply, ignore the
1933 if (request->proxy_reply) {
1934 RDEBUG2("Discarding duplicate reply from host %s port %d - ID: %d",
1935 inet_ntop(packet->src_ipaddr.af,
1936 &packet->src_ipaddr.ipaddr,
1937 buffer, sizeof(buffer)),
1938 packet->src_port, packet->id);
1943 * Call the state machine to do something useful with the
1946 request->proxy_reply = packet;
1947 packet->timestamp = now;
1948 request->priority = RAD_LISTEN_PROXY;
1951 * We've received a reply. If we hadn't been sending it
1952 * packets for a while, just mark it alive.
1954 if (request->home_server->state == HOME_STATE_UNKNOWN) {
1955 request->home_server->state = HOME_STATE_ALIVE;
1959 request->home_server->stats.last_packet = packet->timestamp.tv_sec;
1960 request->proxy_listener->stats.last_packet = packet->timestamp.tv_sec;
1962 if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
1963 proxy_auth_stats.last_packet = packet->timestamp.tv_sec;
1964 #ifdef WITH_ACCOUNTING
1965 } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
1966 proxy_acct_stats.last_packet = packet->timestamp.tv_sec;
1969 #endif /* WITH_STATS */
1973 * When we originate CoA requests, we patch them in here
1974 * so that they don't affect the rest of the state
1977 if (request->parent) {
1978 rad_assert(request->parent->coa == request);
1979 rad_assert((request->proxy->code == PW_COA_REQUEST) ||
1980 (request->proxy->code == PW_DISCONNECT_REQUEST));
1981 rad_assert(request->process != NULL);
1982 request_coa_separate(request);
1986 request->process(request, FR_ACTION_PROXY_REPLY);
1992 static int setup_post_proxy_fail(REQUEST *request)
1994 const DICT_VALUE *dval = NULL;
1997 if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
1998 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
1999 "Fail-Authentication");
2001 } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
2002 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
2005 } else if (request->proxy->code == PW_COA_REQUEST) {
2006 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-CoA");
2008 } else if (request->proxy->code == PW_DISCONNECT_REQUEST) {
2009 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Disconnect");
2012 DEBUGW("Unknown packet type in Post-Proxy-Type Fail: ignoring");
2013 request_cleanup_delay_init(request, NULL);
2017 if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail");
2020 DEBUG("No Post-Proxy-Type Fail: ignoring");
2021 pairdelete(&request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
2022 request_cleanup_delay_init(request, NULL);
2026 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
2027 if (!vp) vp = radius_paircreate(request, &request->config_items,
2028 PW_POST_PROXY_TYPE, 0);
2029 vp->vp_integer = dval->value;
2034 STATE_MACHINE_DECL(proxy_running)
2036 TRACE_STATE_MACHINE;
2039 case FR_ACTION_CONFLICTING:
2041 case FR_ACTION_TIMER:
2042 case FR_ACTION_PROXY_REPLY:
2043 request_common(request, action);
2047 request_running(request, FR_ACTION_PROXY_REPLY);
2051 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2056 STATE_MACHINE_DECL(request_virtual_server)
2058 TRACE_STATE_MACHINE;
2061 case FR_ACTION_CONFLICTING:
2063 case FR_ACTION_TIMER:
2064 case FR_ACTION_PROXY_REPLY:
2065 request_common(request, action);
2069 request_running(request, action);
2073 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2079 static int request_will_proxy(REQUEST *request)
2081 int rcode, pre_proxy_type = 0;
2082 const char *realmname = NULL;
2083 VALUE_PAIR *vp, *strippedname;
2085 REALM *realm = NULL;
2086 home_pool_t *pool = NULL;
2088 if (!request->root->proxy_requests) return 0;
2089 if (request->packet->dst_port == 0) return 0;
2090 if (request->packet->code == PW_STATUS_SERVER) return 0;
2091 if (request->in_proxy_hash) return 0;
2094 * FIXME: for 3.0, allow this only for rejects?
2096 if (request->reply->code != 0) return 0;
2098 vp = pairfind(request->config_items, PW_PROXY_TO_REALM, 0, TAG_ANY);
2100 realm = realm_find2(vp->vp_strvalue);
2102 RDEBUG2E("Cannot proxy to unknown realm %s",
2107 realmname = vp->vp_strvalue;
2110 * Figure out which pool to use.
2112 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
2113 pool = realm->auth_pool;
2115 #ifdef WITH_ACCOUNTING
2116 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
2117 pool = realm->acct_pool;
2121 } else if ((request->packet->code == PW_COA_REQUEST) ||
2122 (request->packet->code == PW_DISCONNECT_REQUEST)) {
2123 pool = realm->coa_pool;
2133 vp = pairfind(request->config_items, PW_HOME_SERVER_POOL, 0, TAG_ANY);
2136 switch (request->packet->code) {
2137 case PW_AUTHENTICATION_REQUEST:
2138 pool_type = HOME_TYPE_AUTH;
2141 #ifdef WITH_ACCOUNTING
2142 case PW_ACCOUNTING_REQUEST:
2143 pool_type = HOME_TYPE_ACCT;
2148 case PW_COA_REQUEST:
2149 case PW_DISCONNECT_REQUEST:
2150 pool_type = HOME_TYPE_COA;
2158 pool = home_pool_byname(vp->vp_strvalue, pool_type);
2162 RDEBUG2W("Cancelling proxy as no home pool exists");
2166 request->home_pool = pool;
2168 home = home_server_ldb(realmname, pool, request);
2170 RDEBUG2E("Failed to find live home server: Cancelling proxy");
2173 home_server_update_request(home, request);
2177 * Once we've decided to proxy a request, we cannot send
2178 * a CoA packet. So we free up any CoA packet here.
2180 if (request->coa) request_done(request->coa, FR_ACTION_DONE);
2184 * Remember that we sent the request to a Realm.
2186 if (realmname) pairadd(&request->packet->vps,
2187 pairmake("Realm", realmname, T_OP_EQ));
2190 * Strip the name, if told to.
2192 * Doing it here catches the case of proxied tunneled
2195 if (realm && (realm->striprealm == TRUE) &&
2196 (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY)) != NULL) {
2198 * If there's a Stripped-User-Name attribute in
2199 * the request, then use THAT as the User-Name
2200 * for the proxied request, instead of the
2203 * This is done by making a copy of the
2204 * Stripped-User-Name attribute, turning it into
2205 * a User-Name attribute, deleting the
2206 * Stripped-User-Name and User-Name attributes
2207 * from the vps list, and making the new
2208 * User-Name the head of the vps list.
2210 vp = pairfind(request->proxy->vps, PW_USER_NAME, 0, TAG_ANY);
2212 vp = radius_paircreate(request, NULL,
2214 rad_assert(vp != NULL); /* handled by above function */
2215 /* Insert at the START of the list */
2216 vp->next = request->proxy->vps;
2217 request->proxy->vps = vp;
2219 memcpy(vp->vp_strvalue, strippedname->vp_strvalue,
2220 sizeof(vp->vp_strvalue));
2221 vp->length = strippedname->length;
2224 * Do NOT delete Stripped-User-Name.
2229 * If there is no PW_CHAP_CHALLENGE attribute but
2230 * there is a PW_CHAP_PASSWORD we need to add it
2231 * since we can't use the request authenticator
2232 * anymore - we changed it.
2234 if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
2235 pairfind(request->proxy->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
2236 pairfind(request->proxy->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
2237 vp = radius_paircreate(request, &request->proxy->vps,
2238 PW_CHAP_CHALLENGE, 0);
2239 memcpy(vp->vp_strvalue, request->packet->vector,
2240 sizeof(request->packet->vector));
2241 vp->length = sizeof(request->packet->vector);
2245 * The RFC's say we have to do this, but FreeRADIUS
2248 vp = radius_paircreate(request, &request->proxy->vps,
2250 snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%d",
2251 request->packet->id);
2252 vp->length = strlen(vp->vp_strvalue);
2255 * Should be done BEFORE inserting into proxy hash, as
2256 * pre-proxy may use this information, or change it.
2258 request->proxy->code = request->packet->code;
2261 * Call the pre-proxy routines.
2263 vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
2265 RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
2266 pre_proxy_type = vp->vp_integer;
2269 rad_assert(request->home_pool != NULL);
2271 if (request->home_pool->virtual_server) {
2272 const char *old_server = request->server;
2274 request->server = request->home_pool->virtual_server;
2275 RDEBUG2(" server %s {", request->server);
2276 rcode = module_pre_proxy(pre_proxy_type, request);
2278 request->server = old_server;
2280 rcode = module_pre_proxy(pre_proxy_type, request);
2283 case RLM_MODULE_FAIL:
2284 case RLM_MODULE_INVALID:
2285 case RLM_MODULE_NOTFOUND:
2286 case RLM_MODULE_USERLOCK:
2288 /* FIXME: debug print failed stuff */
2291 case RLM_MODULE_REJECT:
2292 case RLM_MODULE_HANDLED:
2296 * Only proxy the packet if the pre-proxy code succeeded.
2298 case RLM_MODULE_NOOP:
2300 case RLM_MODULE_UPDATED:
2307 static int request_proxy(REQUEST *request, int retransmit)
2311 rad_assert(request->parent == NULL);
2312 rad_assert(request->home_server != NULL);
2314 if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
2318 RDEBUGW("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request");
2319 request_done(request->coa, FR_ACTION_DONE);
2324 * The request may be sent to a virtual server. If we're
2325 * in a child thread, just process it here. If we're the
2326 * master, push it back onto the queue for later
2329 if (request->home_server->server) {
2330 DEBUG("Proxying to virtual server %s",
2331 request->home_server->server);
2333 if (!we_are_master()) {
2334 request_virtual_server(request, FR_ACTION_RUN);
2335 #ifdef HAVE_PTHREAD_H
2336 request->child_pid = NO_SUCH_CHILD_PID;
2341 request_queue_or_run(request, request_virtual_server);
2346 * We're actually sending a proxied packet. Do that now.
2348 if (!request->in_proxy_hash && !insert_into_proxy_hash(request)) {
2349 radlog_request(L_PROXY, 0, request, "Failed to insert initial packet into the proxy list.");
2353 RDEBUG2("Proxying request to home server %s port %d",
2354 inet_ntop(request->proxy->dst_ipaddr.af,
2355 &request->proxy->dst_ipaddr.ipaddr,
2356 buffer, sizeof(buffer)),
2357 request->proxy->dst_port);
2359 DEBUG_PACKET(request, request->proxy, 1);
2361 gettimeofday(&request->proxy_retransmit, NULL);
2363 request->proxy->timestamp = request->proxy_retransmit;
2364 request->home_server->last_packet_sent = request->proxy_retransmit.tv_sec;
2367 #ifdef HAVE_PTHREAD_H
2368 request->child_pid = NO_SUCH_CHILD_PID;
2370 FR_STATS_TYPE_INC(request->home_server->stats.total_requests);
2371 request->proxy_listener->send(request->proxy_listener,
2377 * Proxy the packet as if it was new.
2379 static int request_proxy_anew(REQUEST *request)
2382 * Keep a copy of the old Id so that the
2383 * re-transmitted request doesn't re-use the old
2384 * Id. Note that in certain cases (socket crash)
2385 * there is no Id as they have been purged from
2386 * proxy_list, but there should still be a leftover
2387 * packet hung off this request.
2389 RADIUS_PACKET old = *request->proxy;
2390 int old_hash = request->in_proxy_hash;
2392 home_server *old_home = request->home_server;
2394 rad_listen_t *listener = request->proxy_listener;
2397 rad_assert(old_home != NULL);
2400 * Find a live home server for the request.
2402 home = home_server_ldb(NULL, request->home_pool, request);
2404 RDEBUG2E("Failed to find live home server for request");
2406 remove_from_proxy_hash(request);
2408 if (!setup_post_proxy_fail(request)) {
2412 request_queue_or_run(request, proxy_running);
2415 home_server_update_request(home, request);
2418 * Don't free the old Id (if any) on error.
2420 if (!insert_into_proxy_hash(request)) {
2421 radlog_request(L_PROXY, 0, request, "Failed to insert retransmission into the proxy list.");
2422 goto post_proxy_fail;
2426 * Now that we have a new Id, free the old one (if any)
2427 * and update the various statistics.
2429 PTHREAD_MUTEX_LOCK(&proxy_mutex);
2431 fr_packet_list_yank(proxy_list, &old);
2432 fr_packet_list_id_free(proxy_list, &old);
2433 old_home->currently_outstanding--;
2435 if (listener) listener->count--;
2438 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
2441 * Free the old packet, to force re-encoding
2443 free(request->proxy->data);
2444 request->proxy->data = NULL;
2445 request->proxy->data_len = 0;
2447 #ifdef WITH_ACCOUNTING
2449 * Update the Acct-Delay-Time attribute.
2451 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
2454 vp = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
2455 if (!vp) vp = radius_paircreate(request,
2456 &request->proxy->vps,
2457 PW_ACCT_DELAY_TIME, 0);
2461 gettimeofday(&now, NULL);
2462 vp->vp_integer += now.tv_sec - request->proxy_retransmit.tv_sec;
2467 if (request_proxy(request, 1) != 1) goto post_proxy_fail;
2472 STATE_MACHINE_DECL(request_ping)
2474 home_server *home = request->home_server;
2477 TRACE_STATE_MACHINE;
2481 case FR_ACTION_TIMER:
2482 radlog(L_ERR, "No response to status check %d for home server %s port %d",
2484 inet_ntop(request->proxy->dst_ipaddr.af,
2485 &request->proxy->dst_ipaddr.ipaddr,
2486 buffer, sizeof(buffer)),
2487 request->proxy->dst_port);
2490 case FR_ACTION_PROXY_REPLY:
2491 rad_assert(request->in_proxy_hash);
2493 request->home_server->num_received_pings++;
2494 radlog_request(L_PROXY, 0, request, "Received response to status check %d (%d in current sequence)",
2495 request->number, home->num_received_pings);
2498 * Remove the request from any hashes
2500 fr_event_delete(el, &request->ev);
2501 remove_from_proxy_hash(request);
2504 * The control socket may have marked the home server as
2505 * alive. OR, it may have suddenly started responding to
2506 * requests again. If so, don't re-do the "make alive"
2509 if (home->state == HOME_STATE_ALIVE) break;
2512 * We haven't received enough ping responses to mark it
2513 * "alive". Wait a bit.
2515 if (home->num_received_pings < home->num_pings_to_alive) {
2520 * Mark it alive and delete any outstanding
2523 home->state = HOME_STATE_ALIVE;
2524 exec_trigger(request, request->home_server->cs, "home_server.alive", FALSE);
2525 home->currently_outstanding = 0;
2526 home->num_sent_pings = 0;
2527 home->num_received_pings = 0;
2528 gettimeofday(&home->revive_time, NULL);
2530 fr_event_delete(el, &home->ev);
2532 radlog_request(L_PROXY, 0, request, "Marking home server %s port %d alive",
2533 inet_ntop(request->proxy->dst_ipaddr.af,
2534 &request->proxy->dst_ipaddr.ipaddr,
2535 buffer, sizeof(buffer)),
2536 request->proxy->dst_port);
2540 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2544 rad_assert(!request->in_request_hash);
2545 rad_assert(request->ev == NULL);
2546 request_done(request, FR_ACTION_DONE);
2550 * Called from start of zombie period, OR after control socket
2551 * marks the home server dead.
2553 static void ping_home_server(void *ctx)
2555 home_server *home = ctx;
2558 struct timeval when, now;
2560 if ((home->state == HOME_STATE_ALIVE) ||
2561 (home->ping_check == HOME_PING_CHECK_NONE) ||
2563 (home->proto == IPPROTO_TCP) ||
2565 (home->ev != NULL)) {
2569 gettimeofday(&now, NULL);
2571 if (home->state == HOME_STATE_ZOMBIE) {
2572 when = home->zombie_period_start;
2573 when.tv_sec += home->zombie_period;
2575 if (timercmp(&when, &now, <)) {
2576 DEBUG("PING: Zombie period is over for home server %s",
2578 mark_home_server_dead(home, &now);
2582 request = request_alloc();
2583 request->number = request_num_counter++;
2584 #ifdef HAVE_PTHREAD_H
2585 request->child_pid = NO_SUCH_CHILD_PID;
2588 request->proxy = rad_alloc(1);
2589 rad_assert(request->proxy != NULL);
2591 if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
2592 request->proxy->code = PW_STATUS_SERVER;
2594 radius_pairmake(request, &request->proxy->vps,
2595 "Message-Authenticator", "0x00", T_OP_SET);
2597 } else if (home->type == HOME_TYPE_AUTH) {
2598 request->proxy->code = PW_AUTHENTICATION_REQUEST;
2600 radius_pairmake(request, &request->proxy->vps,
2601 "User-Name", home->ping_user_name, T_OP_SET);
2602 radius_pairmake(request, &request->proxy->vps,
2603 "User-Password", home->ping_user_password, T_OP_SET);
2604 radius_pairmake(request, &request->proxy->vps,
2605 "Service-Type", "Authenticate-Only", T_OP_SET);
2606 radius_pairmake(request, &request->proxy->vps,
2607 "Message-Authenticator", "0x00", T_OP_SET);
2610 #ifdef WITH_ACCOUNTING
2611 request->proxy->code = PW_ACCOUNTING_REQUEST;
2613 radius_pairmake(request, &request->proxy->vps,
2614 "User-Name", home->ping_user_name, T_OP_SET);
2615 radius_pairmake(request, &request->proxy->vps,
2616 "Acct-Status-Type", "Stop", T_OP_SET);
2617 radius_pairmake(request, &request->proxy->vps,
2618 "Acct-Session-Id", "00000000", T_OP_SET);
2619 vp = radius_pairmake(request, &request->proxy->vps,
2620 "Event-Timestamp", "0", T_OP_SET);
2621 vp->vp_date = now.tv_sec;
2623 rad_assert("Internal sanity check failed");
2627 vp = radius_pairmake(request, &request->proxy->vps,
2628 "NAS-Identifier", "", T_OP_SET);
2630 snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue),
2631 "Status Check %u. Are you alive?",
2632 home->num_sent_pings);
2633 vp->length = strlen(vp->vp_strvalue);
2636 request->proxy->src_ipaddr = home->src_ipaddr;
2637 request->proxy->dst_ipaddr = home->ipaddr;
2638 request->proxy->dst_port = home->port;
2639 request->home_server = home;
2640 #ifdef DEBUG_STATE_MACHINE
2641 if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
2642 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_ping");
2644 #ifdef HAVE_PTHREAD_H
2645 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
2647 request->child_state = REQUEST_DONE;
2648 request->process = request_ping;
2650 rad_assert(request->proxy_listener == NULL);
2652 if (!insert_into_proxy_hash(request)) {
2653 radlog_request(L_PROXY, 0, request, "Failed to insert status check %d into proxy list. Discarding it.",
2656 rad_assert(!request->in_request_hash);
2657 rad_assert(!request->in_proxy_hash);
2658 rad_assert(request->ev == NULL);
2659 request_free(&request);
2664 * Set up the timer callback.
2667 when.tv_sec += home->ping_timeout;
2669 DEBUG("PING: Waiting %u seconds for response to ping",
2670 home->ping_timeout);
2672 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
2673 home->num_sent_pings++;
2675 rad_assert(request->proxy_listener != NULL);
2676 request->proxy_listener->send(request->proxy_listener,
2680 * Add +/- 2s of jitter, as suggested in RFC 3539
2681 * and in the Issues and Fixes draft.
2684 home->when.tv_sec += home->ping_interval;
2686 add_jitter(&home->when);
2688 DEBUG("PING: Next status packet in %u seconds", home->ping_interval);
2689 INSERT_EVENT(ping_home_server, home);
2692 static void home_trigger(home_server *home, const char *trigger)
2695 RADIUS_PACKET my_packet;
2697 memset(&my_request, 0, sizeof(my_request));
2698 memset(&my_packet, 0, sizeof(my_packet));
2699 my_request.proxy = &my_packet;
2700 my_packet.dst_ipaddr = home->ipaddr;
2701 my_packet.src_ipaddr = home->src_ipaddr;
2703 exec_trigger(&my_request, home->cs, trigger, FALSE);
2706 static void mark_home_server_zombie(home_server *home)
2712 rad_assert((home->state == HOME_STATE_ALIVE) ||
2713 (home->state == HOME_STATE_UNKNOWN));
2716 if (home->proto == IPPROTO_TCP) {
2717 DEBUGW("Not marking TCP server %s zombie", home->name);
2722 home->state = HOME_STATE_ZOMBIE;
2723 home_trigger(home, "home_server.zombie");
2726 * Back-date the zombie period to when we last expected
2727 * to see a response. i.e. when we last sent a request.
2729 if (home->last_packet_sent == 0) {
2730 gettimeofday(&home->zombie_period_start, NULL);
2732 home->zombie_period_start.tv_sec = home->last_packet_sent;
2733 home->zombie_period_start.tv_usec = 0;
2736 fr_event_delete(el, &home->ev);
2737 home->num_sent_pings = 0;
2738 home->num_received_pings = 0;
2740 radlog(L_PROXY, "Marking home server %s port %d as zombie (it has not responded in %d seconds).",
2741 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
2742 buffer, sizeof(buffer)),
2743 home->port, home->response_window);
2745 ping_home_server(home);
2749 void revive_home_server(void *ctx)
2751 home_server *home = ctx;
2755 rad_assert(home->proto != IPPROTO_TCP);
2758 home->state = HOME_STATE_ALIVE;
2759 home_trigger(home, "home_server.alive");
2760 home->currently_outstanding = 0;
2761 gettimeofday(&home->revive_time, NULL);
2764 * Delete any outstanding events.
2766 if (home->ev) fr_event_delete(el, &home->ev);
2768 radlog(L_PROXY, "Marking home server %s port %d alive again... we have no idea if it really is alive or not.",
2769 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
2770 buffer, sizeof(buffer)),
2774 void mark_home_server_dead(home_server *home, struct timeval *when)
2776 int previous_state = home->state;
2780 if (home->proto == IPPROTO_TCP) {
2781 DEBUGW("Not marking TCP server dead");
2786 radlog(L_PROXY, "Marking home server %s port %d as dead.",
2787 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
2788 buffer, sizeof(buffer)),
2791 home->state = HOME_STATE_IS_DEAD;
2792 home_trigger(home, "home_server.dead");
2794 if (home->ping_check != HOME_PING_CHECK_NONE) {
2796 * If the control socket marks us dead, start
2797 * pinging. Otherwise, we already started
2798 * pinging when it was marked "zombie".
2800 if (previous_state == HOME_STATE_ALIVE) {
2801 ping_home_server(home);
2803 DEBUG("PING: Already pinging home server %s",
2809 * Revive it after a fixed period of time. This
2810 * is very, very, bad.
2813 home->when.tv_sec += home->revive_interval;
2815 DEBUG("PING: Reviving home server %s in %u seconds",
2816 home->name, home->revive_interval);
2817 INSERT_EVENT(revive_home_server, home);
2821 STATE_MACHINE_DECL(proxy_wait_for_reply)
2823 struct timeval now, when;
2824 home_server *home = request->home_server;
2827 TRACE_STATE_MACHINE;
2829 rad_assert(request->packet->code != PW_STATUS_SERVER);
2830 rad_assert(request->home_server != NULL);
2832 gettimeofday(&now, NULL);
2834 rad_assert(request->child_state != REQUEST_DONE);
2836 if (request->master_state == REQUEST_STOP_PROCESSING) {
2837 request_done(request, FR_ACTION_DONE);
2843 if (request->proxy_reply) return;
2845 if ((home->state == HOME_STATE_IS_DEAD) ||
2846 !request->proxy_listener ||
2847 (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) {
2848 request_proxy_anew(request);
2853 if (home->proto == IPPROTO_TCP) {
2854 DEBUG2("Suppressing duplicate proxied request to home server %s port %d proto TCP - ID: %d",
2855 inet_ntop(request->proxy->dst_ipaddr.af,
2856 &request->proxy->dst_ipaddr.ipaddr,
2857 buffer, sizeof(buffer)),
2858 request->proxy->dst_port,
2859 request->proxy->id);
2864 #ifdef WITH_ACCOUNTING
2866 * If we update the Acct-Delay-Time, we need to
2869 if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
2870 pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY)) {
2871 request_proxy_anew(request);
2876 RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
2877 inet_ntop(request->proxy->dst_ipaddr.af,
2878 &request->proxy->dst_ipaddr.ipaddr,
2879 buffer, sizeof(buffer)),
2880 request->proxy->dst_port,
2881 request->proxy->id);
2882 request->num_proxied_requests++;
2884 rad_assert(request->proxy_listener != NULL);;
2885 DEBUG_PACKET(request, request->proxy, 1);
2886 FR_STATS_TYPE_INC(home->stats.total_requests);
2887 home->last_packet_sent = now.tv_sec;
2888 request->proxy_listener->send(request->proxy_listener,
2892 case FR_ACTION_TIMER:
2894 * Wake up "response_window" time in the future.
2895 * i.e. when MY packet hasn't received a response.
2897 * Note that we DO NOT mark the home server as
2898 * zombie if it doesn't respond to us. It may be
2899 * responding to other (better looking) packets.
2901 when = request->proxy->timestamp;
2902 when.tv_sec += home->response_window;
2905 * Not at the response window. Set the timer for
2908 if (timercmp(&when, &now, >)) {
2909 RDEBUG("Expecting proxy response no later than %d seconds from now", home->response_window);
2910 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
2914 RDEBUG("No proxy response, giving up on request and marking it done");
2917 * If we haven't received any packets for
2918 * "response_window", then mark the home server
2921 * If the connection is TCP, then another
2922 * "watchdog timer" function takes care of pings,
2923 * etc. So we don't need to do it here.
2925 * This check should really be part of a home
2926 * server state machine.
2928 if (((home->state == HOME_STATE_ALIVE) ||
2929 (home->state == HOME_STATE_UNKNOWN)) &&
2931 (home->proto != IPPROTO_TCP) &&
2933 ((home->last_packet_recv + home->response_window) <= now.tv_sec)) {
2934 mark_home_server_zombie(home);
2937 FR_STATS_TYPE_INC(home->stats.total_timeouts);
2938 if (home->type == HOME_TYPE_AUTH) {
2939 if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
2940 FR_STATS_TYPE_INC(proxy_auth_stats.total_timeouts);
2943 else if (home->type == HOME_TYPE_ACCT) {
2944 if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
2945 FR_STATS_TYPE_INC(proxy_acct_stats.total_timeouts);
2950 * There was no response within the window. Stop
2951 * the request. If the client retransmitted, it
2952 * may have failed over to another home server.
2953 * But that one may be dead, too.
2955 radlog_request(L_ERR, 0, request, "Failing request due to lack of any response from home server %s port %d",
2956 inet_ntop(request->proxy->dst_ipaddr.af,
2957 &request->proxy->dst_ipaddr.ipaddr,
2958 buffer, sizeof(buffer)),
2959 request->proxy->dst_port);
2961 if (!setup_post_proxy_fail(request)) {
2967 * Duplicate proxy replies have been quenched by
2968 * now. This state is only called ONCE, when we
2969 * receive a new reply from the home server.
2971 case FR_ACTION_PROXY_REPLY:
2972 request_queue_or_run(request, proxy_running);
2975 case FR_ACTION_CONFLICTING:
2976 request_done(request, action);
2980 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2984 #endif /* WITH_PROXY */
2986 /***********************************************************************
2990 ***********************************************************************/
2992 static int null_handler(UNUSED REQUEST *request)
2998 * See if we need to originate a CoA request.
3000 static void request_coa_originate(REQUEST *request)
3002 int rcode, pre_proxy_type = 0;
3008 rad_assert(request != NULL);
3009 rad_assert(request->coa != NULL);
3010 rad_assert(request->proxy == NULL);
3011 rad_assert(!request->in_proxy_hash);
3012 rad_assert(request->proxy_reply == NULL);
3015 * Check whether we want to originate one, or cancel one.
3017 vp = pairfind(request->config_items, PW_SEND_COA_REQUEST, 0, TAG_ANY);
3019 vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST, 0, TAG_ANY);
3023 if (vp->vp_integer == 0) {
3025 request_done(request->coa, FR_ACTION_DONE);
3033 * src_ipaddr will be set up in proxy_encode.
3035 memset(&ipaddr, 0, sizeof(ipaddr));
3036 vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY);
3038 ipaddr.af = AF_INET;
3039 ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
3041 } else if ((vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY)) != NULL) {
3042 ipaddr.af = AF_INET6;
3043 ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
3045 } else if ((vp = pairfind(coa->proxy->vps, PW_HOME_SERVER_POOL, 0, TAG_ANY)) != NULL) {
3046 coa->home_pool = home_pool_byname(vp->vp_strvalue,
3048 if (!coa->home_pool) {
3049 RDEBUG2W("No such home_server_pool %s",
3055 * Prefer the pool to one server
3057 } else if (request->client->coa_pool) {
3058 coa->home_pool = request->client->coa_pool;
3060 } else if (request->client->coa_server) {
3061 coa->home_server = request->client->coa_server;
3065 * If all else fails, send it to the client that
3066 * originated this request.
3068 memcpy(&ipaddr, &request->packet->src_ipaddr, sizeof(ipaddr));
3072 * Use the pool, if it exists.
3074 if (coa->home_pool) {
3075 coa->home_server = home_server_ldb(NULL, coa->home_pool, coa);
3076 if (!coa->home_server) {
3077 RDEBUGW("No live home server for home_server_pool %s", vp->vp_strvalue);
3080 home_server_update_request(coa->home_server, coa);
3082 } else if (!coa->home_server) {
3083 int port = PW_COA_UDP_PORT;
3085 vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
3086 if (vp) port = vp->vp_integer;
3088 coa->home_server = home_server_find(&ipaddr, port, IPPROTO_UDP);
3089 if (!coa->home_server) {
3090 RDEBUG2W("Unknown destination %s:%d for CoA request.",
3091 inet_ntop(ipaddr.af, &ipaddr.ipaddr,
3092 buffer, sizeof(buffer)), port);
3097 vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE, 0, TAG_ANY);
3099 switch (vp->vp_integer) {
3100 case PW_COA_REQUEST:
3101 case PW_DISCONNECT_REQUEST:
3102 coa->proxy->code = vp->vp_integer;
3106 DEBUG("Cannot set CoA Packet-Type to code %d",
3112 if (!coa->proxy->code) coa->proxy->code = PW_COA_REQUEST;
3115 * The rest of the server code assumes that
3116 * request->packet && request->reply exist. Copy them
3117 * from the original request.
3119 rad_assert(coa->packet != NULL);
3120 rad_assert(coa->packet->vps == NULL);
3121 memcpy(coa->packet, request->packet, sizeof(*request->packet));
3122 coa->packet->vps = paircopy(request->packet->vps);
3123 coa->packet->data = NULL;
3124 rad_assert(coa->reply != NULL);
3125 rad_assert(coa->reply->vps == NULL);
3126 memcpy(coa->reply, request->reply, sizeof(*request->reply));
3127 coa->reply->vps = paircopy(request->reply->vps);
3128 coa->reply->data = NULL;
3129 coa->config_items = paircopy(request->config_items);
3130 coa->num_coa_requests = 0;
3131 coa->handle = null_handler;
3132 coa->number = request->number ^ (1 << 24);
3135 * Call the pre-proxy routines.
3137 vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
3139 RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
3140 pre_proxy_type = vp->vp_integer;
3143 if (coa->home_pool && coa->home_pool->virtual_server) {
3144 const char *old_server = coa->server;
3146 coa->server = coa->home_pool->virtual_server;
3147 RDEBUG2(" server %s {", coa->server);
3148 rcode = module_pre_proxy(pre_proxy_type, coa);
3150 coa->server = old_server;
3152 rcode = module_pre_proxy(pre_proxy_type, coa);
3159 * Only send the CoA packet if the pre-proxy code succeeded.
3161 case RLM_MODULE_NOOP:
3163 case RLM_MODULE_UPDATED:
3168 * Source IP / port is set when the proxy socket
3171 coa->proxy->dst_ipaddr = coa->home_server->ipaddr;
3172 coa->proxy->dst_port = coa->home_server->port;
3174 if (!insert_into_proxy_hash(coa)) {
3175 radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list.");
3180 * We CANNOT divorce the CoA request from the parent
3181 * request. This function is running in a child thread,
3182 * and we need access to the main event loop in order to
3183 * to add the timers for the CoA packet.
3185 * Instead, we wait for the timer on the parent request
3188 gettimeofday(&coa->proxy->timestamp, NULL);
3189 coa->packet->timestamp = coa->proxy->timestamp; /* for max_request_time */
3190 coa->delay = 0; /* need to calculate a new delay */
3192 DEBUG_PACKET(coa, coa->proxy, 1);
3194 coa->process = request_coa_process;
3195 #ifdef DEBUG_STATE_MACHINE
3196 if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_ACTIVE);
3198 coa->child_state = REQUEST_ACTIVE;
3199 rad_assert(coa->proxy_reply == NULL);
3200 FR_STATS_TYPE_INC(coa->home_server->stats.total_requests);
3201 coa->home_server->last_packet_sent = coa->proxy->timestamp.tv_sec;
3202 coa->proxy_listener->send(coa->proxy_listener, coa);
3206 static void request_coa_separate(REQUEST *request)
3208 #ifdef DEBUG_STATE_MACHINE
3209 int action = FR_ACTION_TIMER;
3211 TRACE_STATE_MACHINE;
3213 rad_assert(request->parent != NULL);
3214 rad_assert(request->parent->coa == request);
3215 rad_assert(request->ev == NULL);
3216 rad_assert(!request->in_request_hash);
3218 request->parent->coa = NULL;
3219 request->parent = NULL;
3222 * Set up timers for the CoA request. These do all kinds
3223 * of different things....
3225 request_coa_timer(request);
3228 static void request_coa_timer(REQUEST *request)
3231 struct timeval now, when, mrd;
3233 rad_assert(request->parent == NULL);
3235 if (request->proxy_reply) return request_process_timer(request);
3237 gettimeofday(&now, NULL);
3239 if (request->delay == 0) {
3241 * Implement re-transmit algorithm as per RFC 5080
3244 * We want IRT + RAND*IRT
3245 * or 0.9 IRT + rand(0,.2) IRT
3247 * 2^20 ~ USEC, and we want 2.
3248 * rand(0,0.2) USEC ~ (rand(0,2^21) / 10)
3250 delay = (fr_rand() & ((1 << 22) - 1)) / 10;
3251 request->delay = delay * request->home_server->coa_irt;
3252 delay = request->home_server->coa_irt * USEC;
3253 delay -= delay / 10;
3254 delay += request->delay;
3255 request->delay = delay;
3257 when = request->proxy->timestamp;
3258 tv_add(&when, delay);
3260 if (timercmp(&when, &now, >)) {
3261 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3267 * Retransmit CoA request.
3271 * Cap count at MRC, if it is non-zero.
3273 if (request->home_server->coa_mrc &&
3274 (request->num_coa_requests >= request->home_server->coa_mrc)) {
3275 if (!setup_post_proxy_fail(request)) {
3279 request_queue_or_run(request, proxy_running);
3284 * RFC 5080 Section 2.2.1
3286 * RT = 2*RTprev + RAND*RTprev
3287 * = 1.9 * RTprev + rand(0,.2) * RTprev
3288 * = 1.9 * RTprev + rand(0,1) * (RTprev / 5)
3291 delay ^= (delay >> 16);
3293 frac = request->delay / 5;
3294 delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
3296 delay += (2 * request->delay) - (request->delay / 10);
3299 * Cap delay at MRT, if MRT is non-zero.
3301 if (request->home_server->coa_mrt &&
3302 (delay > (request->home_server->coa_mrt * USEC))) {
3303 int mrt_usec = request->home_server->coa_mrt * USEC;
3306 * delay = MRT + RAND * MRT
3307 * = 0.9 MRT + rand(0,.2) * MRT
3310 delay ^= (delay >> 15);
3312 delay = ((mrt_usec >> 16) * delay) + (((mrt_usec & 0xffff) * delay) >> 16);
3313 delay += mrt_usec - (mrt_usec / 10);
3316 request->delay = delay;
3318 tv_add(&when, request->delay);
3319 mrd = request->proxy->timestamp;
3320 mrd.tv_sec += request->home_server->coa_mrd;
3323 * Cap duration at MRD.
3325 if (timercmp(&mrd, &when, <)) {
3328 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3330 request->num_coa_requests++; /* is NOT reset by code 3 lines above! */
3332 FR_STATS_TYPE_INC(request->home_server->stats.total_requests);
3335 * Status servers don't count as real packets sent.
3337 request->proxy_listener->send(request->proxy_listener,
3342 #ifdef HAVE_PTHREAD_H
3343 STATE_MACHINE_DECL(coa_running)
3345 TRACE_STATE_MACHINE;
3348 case FR_ACTION_TIMER:
3349 request_coa_timer(request);
3352 case FR_ACTION_PROXY_REPLY:
3353 request_common(request, action);
3357 request_running(request, FR_ACTION_PROXY_REPLY);
3361 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
3365 #endif /* HAVE_PTHREAD_H */
3369 * Process CoA requests that we originated.
3371 STATE_MACHINE_DECL(request_coa_process)
3373 TRACE_STATE_MACHINE;
3376 case FR_ACTION_TIMER:
3377 request_coa_timer(request);
3380 case FR_ACTION_PROXY_REPLY:
3381 rad_assert(request->parent == NULL);
3382 #ifdef HAVE_PTHREAD_H
3384 * Catch the case of a proxy reply when called
3385 * from the main worker thread.
3387 if (we_are_master() &&
3388 (request->process != coa_running)) {
3389 request_queue_or_run(request, coa_running);
3395 request_running(request, action);
3399 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
3404 #endif /* WITH_COA */
3406 /***********************************************************************
3408 * End of the State machine. Start of additional helper code.
3410 ***********************************************************************/
3412 /***********************************************************************
3416 ***********************************************************************/
3417 static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd,
3420 rad_listen_t *listener = ctx;
3422 rad_assert(xel == el);
3428 (listener->type != RAD_LISTEN_DETAIL) &&
3430 (listener->fd < 0)) {
3433 listener->print(listener, buffer, sizeof(buffer));
3434 radlog(L_ERR, "FATAL: Asked to read from closed socket: %s",
3437 rad_panic("Socket was closed on us!");
3441 listener->recv(listener);
3446 * This function is called periodically to see if this detail
3447 * file is available for reading.
3449 static void event_poll_detail(void *ctx)
3452 rad_listen_t *this = ctx;
3453 struct timeval when, now;
3454 listen_detail_t *detail = this->data;
3456 rad_assert(this->type == RAD_LISTEN_DETAIL);
3459 event_socket_handler(el, this->fd, this);
3461 fr_event_now(el, &now);
3465 * Backdoor API to get the delay until the next poll
3468 delay = this->encode(this, NULL);
3469 if (delay == 0) goto redo;
3471 tv_add(&when, delay);
3473 if (!fr_event_insert(el, event_poll_detail, this,
3474 &when, &detail->ev)) {
3475 radlog(L_ERR, "Failed creating handler");
3481 static void event_status(struct timeval *wake)
3483 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
3487 if (debug_flag == 0) {
3489 radlog(L_INFO, "Ready to process requests.");
3490 just_started = FALSE;
3496 radlog(L_INFO, "Ready to process requests.");
3498 } else if ((wake->tv_sec != 0) ||
3499 (wake->tv_usec >= 100000)) {
3500 DEBUG("Waking up in %d.%01u seconds.",
3501 (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
3506 * FIXME: Put this somewhere else, where it isn't called
3507 * all of the time...
3510 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
3512 * If there are no child threads, then there may
3513 * be child processes. In that case, wait for
3514 * their exit status, and throw that exit status
3515 * away. This helps get rid of zxombie children.
3517 while (waitpid(-1, &argval, WNOHANG) > 0) {
3525 int event_new_fd(rad_listen_t *this)
3529 if (this->status == RAD_LISTEN_STATUS_KNOWN) return 1;
3531 this->print(this, buffer, sizeof(buffer));
3533 if (this->status == RAD_LISTEN_STATUS_INIT) {
3534 listen_socket_t *sock = this->data;
3537 DEBUG("Listening on %s", buffer);
3539 radlog(L_INFO, " ... adding new socket %s", buffer);
3544 * Add it to the list of sockets we can use.
3545 * Server sockets (i.e. auth/acct) are never
3546 * added to the packet list.
3548 if (this->type == RAD_LISTEN_PROXY) {
3549 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3550 if (!fr_packet_list_socket_add(proxy_list, this->fd,
3552 &sock->other_ipaddr, sock->other_port,
3555 #ifdef HAVE_PTHREAD_H
3556 proxy_no_new_sockets = TRUE;
3558 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3561 * This is bad. However, the
3562 * packet list now supports 256
3563 * open sockets, which should
3564 * minimize this problem.
3566 radlog(L_ERR, "Failed adding proxy socket: %s",
3572 sock->home->limit.num_connections++;
3574 #ifdef HAVE_PTHREAD_H
3576 * If necessary, add it to the list of
3577 * new proxy listeners.
3579 if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
3580 this->next = proxy_listener_list;
3581 proxy_listener_list = this;
3585 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3588 * Tell the main thread that we've added
3589 * a proxy listener, but only if we need
3590 * to update the event list. Do this
3591 * with the mutex unlocked, to reduce
3595 if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
3596 radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
3604 * Detail files are always known, and aren't
3605 * put into the socket event loop.
3607 if (this->type == RAD_LISTEN_DETAIL) {
3608 this->status = RAD_LISTEN_STATUS_KNOWN;
3611 * Set up the first poll interval.
3613 event_poll_detail(this);
3620 * Add timers to child sockets, if necessary.
3622 if (sock->proto == IPPROTO_TCP && sock->opened &&
3623 (sock->limit.lifetime || sock->limit.idle_timeout)) {
3624 struct timeval when;
3628 when.tv_sec = sock->opened + 1;
3631 if (!fr_event_insert(el, tcp_socket_timer, this, &when,
3633 rad_panic("Failed to insert event");
3638 FD_MUTEX_LOCK(&fd_mutex);
3639 if (!fr_event_fd_insert(el, 0, this->fd,
3640 event_socket_handler, this)) {
3641 radlog(L_ERR, "Failed adding event handler for socket!");
3644 FD_MUTEX_UNLOCK(&fd_mutex);
3646 this->status = RAD_LISTEN_STATUS_KNOWN;
3651 * Something went wrong with the socket: make it harmless.
3653 if (this->status == RAD_LISTEN_STATUS_REMOVE_FD) {
3657 * Remove it from the list of live FD's.
3659 FD_MUTEX_LOCK(&fd_mutex);
3660 fr_event_fd_delete(el, 0, this->fd);
3661 FD_MUTEX_UNLOCK(&fd_mutex);
3665 * We track requests using this socket only for
3666 * TCP. For UDP, we don't currently close
3670 if (this->type != RAD_LISTEN_PROXY)
3673 if (this->count != 0) {
3674 fr_packet_list_walk(pl, this,
3675 remove_all_requests);
3678 if (this->count == 0) {
3679 this->status = RAD_LISTEN_STATUS_FINISH;
3690 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3691 if (!fr_packet_list_socket_freeze(proxy_list,
3693 radlog(L_ERR, "Fatal error freezing socket: %s",
3699 * Doing this with the proxy mutex held
3700 * is a Bad Thing. We should move to
3701 * finer-grained mutexes.
3703 count = this->count;
3705 fr_packet_list_walk(proxy_list, this,
3706 disconnect_all_proxied_requests);
3708 count = this->count; /* protected by mutex */
3709 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3712 this->status = RAD_LISTEN_STATUS_FINISH;
3716 #endif /* WITH_PROXY */
3717 #endif /* WITH_TCP */
3720 * Re-open the socket, pointing it to /dev/null.
3721 * This means that all writes proceed without
3722 * blocking, and all reads return "no data".
3724 * This leaves the socket active, so any child
3725 * threads won't go insane. But it means that
3726 * they cannot send or receive any packets.
3728 * This is EXTRA work in the normal case, when
3729 * sockets are closed without error. But it lets
3730 * us have one simple processing method for all
3733 devnull = open("/dev/null", O_RDWR);
3735 radlog(L_ERR, "FATAL failure opening /dev/null: %s",
3739 if (dup2(devnull, this->fd) < 0) {
3740 radlog(L_ERR, "FATAL failure closing socket: %s",
3746 this->status = RAD_LISTEN_STATUS_CLOSED;
3749 * Fall through to the next section.
3755 * Called ONLY from the main thread. On the following
3761 * (and falling through from "forcibly close FD" above)
3762 * client closed connection on us
3763 * client sent us a bad packet.
3765 if (this->status == RAD_LISTEN_STATUS_CLOSED) {
3766 int count = this->count;
3769 rad_assert(this->type != RAD_LISTEN_DETAIL);
3774 * Remove it from the list of active sockets, so
3775 * that it isn't used when proxying new packets.
3777 if (this->type == RAD_LISTEN_PROXY) {
3778 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3779 if (!fr_packet_list_socket_freeze(proxy_list,
3781 radlog(L_ERR, "Fatal error freezing socket: %s",
3785 count = this->count; /* protected by mutex */
3786 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3791 * Requests are still using the socket. Wait for
3795 struct timeval when;
3796 listen_socket_t *sock = this->data;
3799 * Try again to clean up the socket in 30
3802 gettimeofday(&when, NULL);
3805 if (!fr_event_insert(el,
3806 (fr_event_callback_t) event_new_fd,
3807 this, &when, &sock->ev)) {
3808 rad_panic("Failed to insert event");
3815 * No one is using this socket: we can delete it
3818 this->status = RAD_LISTEN_STATUS_FINISH;
3822 if (this->status == RAD_LISTEN_STATUS_FINISH) {
3823 listen_socket_t *sock = this->data;
3825 rad_assert(this->count == 0);
3826 radlog(L_INFO, " ... closing socket %s", buffer);
3829 * Remove it from the list of live FD's. Note
3830 * that it MAY also have been removed above. We
3831 * do it again here, to catch the case of sockets
3832 * closing on idle timeout, or max
3833 * lifetime... AFTER all requests have finished
3836 FD_MUTEX_LOCK(&fd_mutex);
3837 fr_event_fd_delete(el, 0, this->fd);
3838 FD_MUTEX_UNLOCK(&fd_mutex);
3842 * Remove it from the list of sockets to be used
3845 if (this->type == RAD_LISTEN_PROXY) {
3846 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3847 if (!fr_packet_list_socket_remove(proxy_list,
3849 radlog(L_ERR, "Fatal error removing socket: %s",
3853 if (sock->home) sock->home->limit.num_connections--;
3854 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3859 * Remove any pending cleanups.
3861 if (sock->ev) fr_event_delete(el, &sock->ev);
3864 * And finally, close the socket.
3868 #endif /* WITH_TCP */
3873 /***********************************************************************
3877 ***********************************************************************/
3879 static void handle_signal_self(int flag)
3881 if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
3882 if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
3883 radlog(L_INFO, "Signalled to exit");
3884 fr_event_loop_exit(el, 1);
3886 radlog(L_INFO, "Signalled to terminate");
3887 exec_trigger(NULL, NULL, "server.signal.term", TRUE);
3888 fr_event_loop_exit(el, 2);
3892 } /* else exit/term flags weren't set */
3895 * Tell the even loop to stop processing.
3897 if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
3899 static time_t last_hup = 0;
3902 if ((int) (when - last_hup) < 5) {
3903 radlog(L_INFO, "Ignoring HUP (less than 5s since last one)");
3907 radlog(L_INFO, "Received HUP signal.");
3911 exec_trigger(NULL, NULL, "server.signal.hup", TRUE);
3912 fr_event_loop_exit(el, 0x80);
3916 if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
3920 * FIXME: O(N) loops suck.
3922 for (this = mainconfig.listen;
3924 this = this->next) {
3925 if (this->type != RAD_LISTEN_DETAIL) continue;
3928 * This one didn't send the signal, skip
3931 if (!this->decode(this, NULL)) continue;
3934 * Go service the interrupt.
3936 event_poll_detail(this);
3943 #ifdef HAVE_PTHREAD_H
3945 * Add event handlers for idle timeouts && maximum lifetime.
3947 if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
3948 struct timeval when, now;
3950 fr_event_now(el, &now);
3952 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3954 while (proxy_listener_list) {
3955 rad_listen_t *this = proxy_listener_list;
3956 listen_socket_t *sock = this->data;
3958 rad_assert(sock->proto == IPPROTO_TCP);
3959 proxy_listener_list = this->next;
3962 if (!sock->home) continue; /* skip UDP sockets */
3967 * Sockets should only be added to the
3968 * proxy_listener_list if they have limits.
3971 rad_assert(sock->home->limit.lifetime || sock->home->limit.idle_timeout);
3973 if (!fr_event_insert(el, tcp_socket_timer, this, &when,
3975 rad_panic("Failed to insert event");
3979 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3981 #endif /* HAVE_PTHREAD_H */
3982 #endif /* WITH_PROXY */
3983 #endif /* WITH_TCP */
3986 #ifndef WITH_SELF_PIPE
3987 void radius_signal_self(int flag)
3989 handle_signal_self(flag);
3993 * Inform ourselves that we received a signal.
3995 void radius_signal_self(int flag)
4001 * The read MUST be non-blocking for this to work.
4003 rcode = read(self_pipe[0], buffer, sizeof(buffer));
4007 for (i = 0; i < rcode; i++) {
4008 buffer[0] |= buffer[i];
4016 write(self_pipe[1], buffer, 1);
4020 static void event_signal_handler(UNUSED fr_event_list_t *xel,
4021 UNUSED int fd, UNUSED void *ctx)
4026 rcode = read(self_pipe[0], buffer, sizeof(buffer));
4027 if (rcode <= 0) return;
4030 * Merge pending signals.
4032 for (i = 0; i < rcode; i++) {
4033 buffer[0] |= buffer[i];
4036 handle_signal_self(buffer[0]);
4040 /***********************************************************************
4042 * Bootstrapping code.
4044 ***********************************************************************/
4047 * Externally-visibly functions.
4049 int radius_event_init(CONF_SECTION *cs, int have_children)
4051 rad_listen_t *head = NULL;
4055 time(&fr_start_time);
4057 el = fr_event_list_create(event_status);
4060 pl = fr_packet_list_create(0);
4061 if (!pl) return 0; /* leak el */
4063 request_num_counter = 0;
4066 if (mainconfig.proxy_requests) {
4068 * Create the tree for managing proxied requests and
4071 proxy_list = fr_packet_list_create(1);
4072 if (!proxy_list) return 0;
4074 #ifdef HAVE_PTHREAD_H
4075 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
4076 radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
4084 #ifdef HAVE_PTHREAD_H
4085 NO_SUCH_CHILD_PID = pthread_self(); /* not a child thread */
4088 * Initialize the threads ONLY if we're spawning, AND
4089 * we're running normally.
4091 if (have_children && !check_config &&
4092 (thread_pool_init(cs, &have_children) < 0)) {
4098 * Move all of the thread calls to this file?
4100 * It may be best for the mutexes to be in this file...
4102 spawn_flag = have_children;
4105 DEBUG("%s: #### Skipping IP addresses and Ports ####",
4107 if (listen_init(cs, &head, spawn_flag) < 0) {
4114 #ifdef WITH_SELF_PIPE
4116 * Child threads need a pipe to signal us, as do the
4119 if (pipe(self_pipe) < 0) {
4120 radlog(L_ERR, "radiusd: Error opening internal pipe: %s",
4124 if ((fcntl(self_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
4125 (fcntl(self_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
4126 radlog(L_ERR, "radiusd: Error setting internal flags: %s",
4130 if ((fcntl(self_pipe[1], F_SETFL, O_NONBLOCK) < 0) ||
4131 (fcntl(self_pipe[1], F_SETFD, FD_CLOEXEC) < 0)) {
4132 radlog(L_ERR, "radiusd: Error setting internal flags: %s",
4137 if (!fr_event_fd_insert(el, 0, self_pipe[0],
4138 event_signal_handler, el)) {
4139 radlog(L_ERR, "Failed creating handler for signals");
4142 #endif /* WITH_SELF_PIPE */
4144 DEBUG("%s: #### Opening IP addresses and Ports ####",
4148 * The server temporarily switches to an unprivileged
4149 * user very early in the bootstrapping process.
4150 * However, some sockets MAY require privileged access
4151 * (bind to device, or to port < 1024, or to raw
4152 * sockets). Those sockets need to call suid up/down
4153 * themselves around the functions that need a privileged
4156 if (listen_init(cs, &head, spawn_flag) < 0) {
4160 mainconfig.listen = head;
4163 * At this point, no one has any business *ever* going
4166 fr_suid_down_permanent();
4172 static int request_hash_cb(UNUSED void *ctx, void *data)
4174 REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
4177 rad_assert(request->in_proxy_hash == FALSE);
4180 request_done(request, FR_ACTION_DONE);
4187 static int proxy_hash_cb(UNUSED void *ctx, void *data)
4189 REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
4191 request_done(request, FR_ACTION_DONE);
4197 void radius_event_free(void)
4200 * Stop and join all threads.
4202 #ifdef HAVE_PTHREAD_H
4208 * There are requests in the proxy hash that aren't
4209 * referenced from anywhere else. Remove them first.
4212 fr_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
4213 fr_packet_list_free(proxy_list);
4218 fr_packet_list_walk(pl, NULL, request_hash_cb);
4220 fr_packet_list_free(pl);
4223 fr_event_list_free(el);
4226 int radius_event_process(void)
4230 return fr_event_loop(el);