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>
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/process.h>
31 #include <freeradius-devel/modules.h>
33 #include <freeradius-devel/rad_assert.h>
36 #include <freeradius-devel/detail.h>
42 #ifdef HAVE_SYS_WAIT_H
43 # include <sys/wait.h>
46 extern pid_t radius_pid;
47 extern bool check_config;
48 extern fr_cond_t *debug_condition;
50 static bool spawn_flag = false;
51 static bool just_started = true;
53 static fr_packet_list_t *pl = NULL;
54 static fr_event_list_t *el = NULL;
56 static char const *action_codes[] = {
68 #ifdef DEBUG_STATE_MACHINE
69 #define TRACE_STATE_MACHINE if (debug_flag) printf("(%u) ********\tSTATE %s action %s live M-%s C-%s\t********\n", request->number, __FUNCTION__, action_codes[action], master_state_names[request->master_state], child_state_names[request->child_state])
71 static char const *master_state_names[REQUEST_MASTER_NUM_STATES] = {
78 static char const *child_state_names[REQUEST_CHILD_NUM_STATES] = {
89 #define TRACE_STATE_MACHINE {}
93 * Declare a state in the state machine.
96 #define STATE_MACHINE_DECL(_x) static void _x(REQUEST *request, int action)
98 #define STATE_MACHINE_TIMER(_x) request->timer_action = _x; \
99 fr_event_insert(el, request_timer, request, \
100 &when, &request->ev);
105 * @section request_timeline
107 * Time sequence of a request
110 * RQ-----------------P=============================Y-J-C
111 * ::::::::::::::::::::::::::::::::::::::::::::::::::::::::M
114 * - R: received. Duplicate detection is done, and request is
117 * - Q: Request is placed onto a queue for child threads to pick up.
118 * If there are no child threads, the request goes immediately
121 * - P: Processing the request through the modules.
123 * - Y: Reply is ready. Rejects MAY be delayed here. All other
124 * replies are sent immediately.
126 * - J: Reject is sent "reject_delay" after the reply is ready.
128 * - C: For Access-Requests, After "cleanup_delay", the request is
129 * deleted. Accounting-Request packets go directly from Y to C.
131 * - M: Max request time. If the request hits this timer, it is
134 * Other considerations include duplicate and conflicting
135 * packets. When a dupicate packet is received, it is ignored
136 * until we've reached Y, as no response is ready. If the reply
137 * is a reject, duplicates are ignored until J, when we're ready
138 * to send the reply. In between the reply being sent (Y or J),
139 * and C, the server responds to duplicates by sending the cached
142 * Conflicting packets are sent in 2 situations.
144 * The first is in between R and Y. In that case, we consider
145 * it as a hint that we're taking too long, and the NAS has given
146 * up on the request. We then behave just as if the M timer was
147 * reached, and we discard the current request. This allows us
148 * to process the new one.
150 * The second case is when we're at Y, but we haven't yet
151 * finished processing the request. This is a race condition in
152 * the threading code (avoiding locks is faster). It means that
153 * a thread has actually encoded and sent the reply, and that the
154 * NAS has responded with a new packet. The server can then
155 * safely mark the current request as "OK to delete", and behaves
156 * just as if the M timer was reached. This usually happens only
157 * in high-load situations.
159 * Duplicate packets are sent when the NAS thinks we're taking
160 * too long, and wants a reply. From R-Y, duplicates are
161 * ignored. From Y-J (for Access-Rejects), duplicates are also
162 * ignored. From Y-C, duplicates get a duplicate reply. *And*,
163 * they cause the "cleanup_delay" time to be extended. This
164 * extension means that we're more likely to send a duplicate
165 * reply (if we have one), or to suppress processing the packet
166 * twice if we didn't reply to it.
168 * All functions in this file should be thread-safe, and should
169 * assume thet the REQUEST structure is being accessed
170 * simultaneously by the main thread, and by the child worker
171 * threads. This means that timers, etc. cannot be updated in
174 * Instead, the master thread periodically calls request->process
175 * with action TIMER. It's up to the individual functions to
176 * determine how to handle that. They need to check if they're
177 * being called from a child thread or the master, and then do
178 * different things based on that.
183 static fr_packet_list_t *proxy_list = NULL;
186 #ifdef HAVE_PTHREAD_H
188 static pthread_mutex_t proxy_mutex;
189 static rad_listen_t *proxy_listener_list = NULL;
190 static bool proxy_no_new_sockets = false;
193 #define PTHREAD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
194 #define PTHREAD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
196 static pthread_t NO_SUCH_CHILD_PID;
197 #define NO_CHILD_THREAD request->child_pid = NO_SUCH_CHILD_PID
201 * This is easier than ifdef's throughout the code.
203 #define PTHREAD_MUTEX_LOCK(_x)
204 #define PTHREAD_MUTEX_UNLOCK(_x)
205 #define NO_CHILD_THREAD
209 * We need mutexes around the event FD list *only* in certain
212 #if defined (HAVE_PTHREAD_H) && (defined(WITH_PROXY) || defined(WITH_TCP))
213 static pthread_mutex_t fd_mutex;
214 #define FD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
215 #define FD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
218 * This is easier than ifdef's throughout the code.
220 #define FD_MUTEX_LOCK(_x)
221 #define FD_MUTEX_UNLOCK(_x)
224 static int request_num_counter = 0;
226 static int request_will_proxy(REQUEST *request);
227 static int request_proxy(REQUEST *request, int retransmit);
228 STATE_MACHINE_DECL(proxy_wait_for_reply);
229 STATE_MACHINE_DECL(proxy_running);
230 static int process_proxy_reply(REQUEST *request);
231 static void remove_from_proxy_hash(REQUEST *request);
232 static void remove_from_proxy_hash_nl(REQUEST *request, bool yank);
233 static int insert_into_proxy_hash(REQUEST *request);
236 static REQUEST *request_setup(rad_listen_t *listener, RADIUS_PACKET *packet,
237 RADCLIENT *client, RAD_REQUEST_FUNP fun);
239 STATE_MACHINE_DECL(request_common);
241 #if defined(HAVE_PTHREAD_H) && !defined (NDEBUG)
242 static bool we_are_master(void)
245 (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
251 #define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
254 #define we_are_master(_x) (1)
255 #define ASSERT_MASTER
258 STATE_MACHINE_DECL(request_reject_delay);
259 STATE_MACHINE_DECL(request_cleanup_delay);
260 STATE_MACHINE_DECL(request_running);
262 static void request_coa_originate(REQUEST *request);
263 STATE_MACHINE_DECL(coa_running);
264 STATE_MACHINE_DECL(coa_wait_for_reply);
265 static void request_coa_separate(REQUEST *coa);
269 #define USEC (1000000)
271 #define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
273 static void _rad_panic(char const *file, unsigned int line, char const *msg)
275 ERROR("[%s:%d] %s", file, line, msg);
282 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
284 static void tv_add(struct timeval *tv, int usec_delay)
286 if (usec_delay >= USEC) {
287 tv->tv_sec += usec_delay / USEC;
290 tv->tv_usec += usec_delay;
292 if (tv->tv_usec >= USEC) {
293 tv->tv_sec += tv->tv_usec / USEC;
299 * In daemon mode, AND this request has debug flags set.
301 #define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
303 static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
308 char const *received, *from;
309 fr_ipaddr_t const *ip;
314 rad_assert(request->radlog != NULL);
316 if (direction == 0) {
317 received = "Received";
318 from = "from"; /* what else? */
319 ip = &packet->src_ipaddr;
320 port = packet->src_port;
323 received = "Sending";
324 from = "to"; /* hah! */
325 ip = &packet->dst_ipaddr;
326 port = packet->dst_port;
330 * Client-specific debugging re-prints the input
331 * packet into the client log.
333 * This really belongs in a utility library
335 if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
336 RDEBUG("%s %s packet %s host %s port %i, id=%i, length=%zu",
337 received, fr_packet_codes[packet->code], from,
338 inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
339 port, packet->id, packet->data_len);
341 RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%zu",
343 inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
345 packet->code, packet->id, packet->data_len);
348 for (vp = paircursor(&cursor, &packet->vps);
350 vp = pairnext(&cursor)) {
351 vp_prints(buffer, sizeof(buffer), vp);
352 RDEBUG("\t%s", buffer);
357 /***********************************************************************
359 * Start of RADIUS server state machine.
361 ***********************************************************************/
364 * Callback for ALL timer events related to the request.
366 static void request_timer(void *ctx)
368 REQUEST *request = ctx;
369 int action = request->timer_action;
373 request->process(request, action);
376 #define USEC (1000000)
379 * Only ever called from the master thread.
381 STATE_MACHINE_DECL(request_done)
383 struct timeval now, when;
389 * CoA requests can be cleaned up in the child thread,
390 * but ONLY if they aren't tied into anything.
392 if (request->parent && (request->parent->coa == request)) {
393 rad_assert(!request->in_request_hash);
394 rad_assert(!request->in_proxy_hash);
395 rad_assert(action == FR_ACTION_DONE);
396 rad_assert(request->ev == NULL);
400 #ifdef HAVE_PTHREAD_H
402 * If called from a child thread, mark ourselves as done,
403 * and wait for the master thread timer to clean us up.
405 if (!we_are_master()) {
406 request->child_state = REQUEST_DONE;
414 * Move the CoA request to its own handler.
416 if (request->coa) request_coa_separate(request->coa);
419 * If we're the CoA request, make the parent forget about
422 if (request->parent && (request->parent->coa == request)) {
423 request->parent->coa = NULL;
429 * It doesn't hurt to send duplicate replies. All other
430 * signals are ignored, as the request will be cleaned up
435 if (request->reply->code != 0) {
436 request->listener->send(request->listener, request);
442 * This is only called from the master thread
443 * when there is a child thread processing the
446 case FR_ACTION_CONFLICTING:
447 if (request->child_state == REQUEST_DONE) break;
450 * If there's a reply packet, then we presume
451 * that the child has sent the reply, and we get
452 * pinged here before the child has a chance to
455 if (request->reply->data) break;
457 RERROR("Received conflicting packet from "
458 "client %s port %d - ID: %u due to "
459 "unfinished request. Giving up on old request.",
460 request->client->shortname,
461 request->packet->src_port, request->packet->id);
465 * Called only when there's an error remembering
466 * the packet, or when the socket gets closed from
470 #ifdef HAVE_PTHREAD_H
472 * Do NOT set child_state to DONE if it's still in the queue.
474 if (we_are_master() && (request->child_state == REQUEST_QUEUED)) {
479 * If we have child threads and we're NOT the
480 * thread handling the request, don't do anything.
483 !pthread_equal(pthread_self(), request->child_pid)) {
487 #ifdef DEBUG_STATE_MACHINE
488 if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n",
489 request->number, __FUNCTION__,
490 child_state_names[request->child_state],
491 child_state_names[REQUEST_DONE]);
493 request->child_state = REQUEST_DONE;
497 * Called when the child is taking too long to
498 * finish. We've already marked it "please
499 * stop", so we don't complain any more.
501 case FR_ACTION_TIMER:
506 * Child is still alive, and we're receiving more
507 * packets from the home server.
509 case FR_ACTION_PROXY_REPLY:
510 request_common(request, action);
515 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
520 * Remove it from the request hash.
522 if (request->in_request_hash) {
524 if (!fr_packet_list_yank(pl, request->packet)) {
527 request->in_request_hash = false;
532 * Wait for the proxy ID to expire. This allows us to
533 * avoid re-use of proxy IDs for a while.
535 if (request->in_proxy_hash) {
536 rad_assert(request->proxy != NULL);
538 fr_event_now(el, &now);
539 when = request->proxy->timestamp;
542 if (((request->proxy->code == PW_COA_REQUEST) ||
543 (request->proxy->code == PW_DISCONNECT_REQUEST)) &&
544 (request->packet->code != request->proxy->code)) {
545 when.tv_sec += request->home_server->coa_mrd;
548 when.tv_sec += request->home_server->response_window;
551 * We haven't received all responses, AND there's still
552 * time to wait. Do so.
554 if ((request->num_proxied_requests > request->num_proxied_responses) &&
556 (request->home_server->proto != IPPROTO_TCP) &&
558 timercmp(&now, &when, <)) {
559 RDEBUG("Waiting for more responses from the home server");
566 remove_from_proxy_hash(request);
570 #ifdef HAVE_PTHREAD_H
572 * If there's no children, we can mark the request as done.
575 request->child_state = REQUEST_DONE;
579 if (request->child_state != REQUEST_DONE) {
580 gettimeofday(&now, NULL);
585 #ifdef HAVE_PTHREAD_H
587 (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
588 RDEBUG("Waiting for child thread to stop");
593 if (request->delay < (USEC / 3)) request->delay = USEC / 3;
594 tv_add(&when, request->delay);
595 request->delay += request->delay >> 1;
596 if (request->delay > (10 * USEC)) request->delay = 10 * USEC;
598 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
602 #ifdef HAVE_PTHREAD_H
603 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
607 * @todo: do final states for TCP sockets, too?
609 request_stats_final(request);
611 if (request->listener) request->listener->count--;
614 if (request->packet) {
615 RDEBUG2("Cleaning up request packet ID %u with timestamp +%d",
617 (unsigned int) (request->timestamp - fr_start_time));
618 } /* else don't print anything */
620 if (request->ev) fr_event_delete(el, &request->ev);
622 request_free(&request);
626 static void request_cleanup_delay_init(REQUEST *request, struct timeval const *pnow)
628 struct timeval now, when;
630 if (request->packet->code == PW_ACCOUNTING_REQUEST) goto done;
632 if (!request->root->cleanup_delay) goto done;
637 gettimeofday(&now, NULL);
640 rad_assert(request->reply->timestamp.tv_sec != 0);
641 when = request->reply->timestamp;
643 request->delay = request->root->cleanup_delay;
644 when.tv_sec += request->delay;
647 * Set timer for when we need to clean it up.
649 if (timercmp(&when, &now, >)) {
650 #ifdef DEBUG_STATE_MACHINE
651 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
653 request->process = request_cleanup_delay;
654 request->child_state = REQUEST_DONE;
655 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
660 * Otherwise just clean it up.
663 request_done(request, FR_ACTION_DONE);
668 * Function to do all time-related events.
670 static void request_process_timer(REQUEST *request)
672 struct timeval now, when;
673 rad_assert(request->magic == REQUEST_MAGIC);
674 #ifdef DEBUG_STATE_MACHINE
675 int action = FR_ACTION_TIMER;
683 * If we originated a CoA request, divorce it from the
684 * parent. Then, set up the timers so that we can clean
685 * it up as appropriate.
687 if (request->coa) request_coa_separate(request->coa);
690 * If we're the request, OR it isn't originating a CoA
691 * request, check more things.
693 if (!request->proxy || (request->packet->code == request->proxy->code))
696 rad_assert(request->listener != NULL);
699 * The socket was closed. Tell the request that
700 * there is no point in continuing.
702 if (request->listener->status != RAD_LISTEN_STATUS_KNOWN) {
703 if ((request->master_state == REQUEST_ACTIVE) &&
704 (request->child_state < REQUEST_REJECT_DELAY)) {
705 WDEBUG("Socket was closed while processing request %u: Stopping it.", request->number);
706 request->master_state = REQUEST_STOP_PROCESSING;
711 gettimeofday(&now, NULL);
714 * The request was forcibly stopped.
716 if (request->master_state == REQUEST_STOP_PROCESSING) {
717 switch (request->child_state) {
719 case REQUEST_RUNNING:
720 #ifdef HAVE_PTHREAD_H
721 rad_assert(spawn_flag == true);
726 * Sleep for some more. We HOPE that the
727 * child will become responsive at some
728 * point in the future.
731 tv_add(&when, request->delay);
732 request->delay += request->delay >> 1;
733 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
737 * These should all be managed by the master thread
740 case REQUEST_PROXIED:
742 case REQUEST_REJECT_DELAY:
743 case REQUEST_CLEANUP_DELAY:
746 request_done(request, FR_ACTION_DONE);
751 rad_assert(request->master_state == REQUEST_ACTIVE);
754 * It's still supposed to be running.
756 switch (request->child_state) {
758 case REQUEST_RUNNING:
760 case REQUEST_PROXIED:
762 when = request->packet->timestamp;
763 when.tv_sec += request->root->max_request_time;
766 * Taking too long: tell it to die.
768 if (timercmp(&now, &when, >=)) {
769 #ifdef HAVE_PTHREAD_H
771 * If there's a child thread processing it,
775 (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
776 ERROR("Unresponsive child for request %u, in component %s module %s",
778 request->component ? request->component : "<core>",
779 request->module ? request->module : "<core>");
780 exec_trigger(request, NULL, "server.thread.unresponsive", true);
783 request->master_state = REQUEST_STOP_PROCESSING;
788 * We should wait for the proxy reply.
790 if (request->child_state == REQUEST_PROXIED) {
791 if (request->proxy_reply) {
792 request->process = proxy_running;
794 request->process = proxy_wait_for_reply;
800 * If the request has been told to die, we wait.
801 * Otherwise, we wait for the child thread to
806 case REQUEST_REJECT_DELAY:
807 rad_assert(request->root->reject_delay > 0);
809 rad_assert(!request->proxy || (request->packet->code == request->proxy->code));
812 request->process = request_reject_delay;
814 when = request->reply->timestamp;
815 when.tv_sec += request->root->reject_delay;
817 if (timercmp(&when, &now, >)) {
818 #ifdef DEBUG_STATE_MACHINE
819 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_reject_delay");
821 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
823 } /* else it's time to send the reject */
825 RDEBUG2("Sending delayed reject");
826 DEBUG_PACKET(request, request->reply, 1);
827 request->listener->send(request->listener, request);
828 request->child_state = REQUEST_CLEANUP_DELAY;
831 case REQUEST_CLEANUP_DELAY:
832 rad_assert(request->root->cleanup_delay > 0);
835 rad_assert(!request->proxy || (request->packet->code == request->proxy->code));
838 request->process = request_cleanup_delay;
840 when = request->reply->timestamp;
841 when.tv_sec += request->root->cleanup_delay;
843 if (timercmp(&when, &now, >)) {
844 #ifdef DEBUG_STATE_MACHINE
845 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
847 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
849 } /* else it's time to clean up */
858 static void request_queue_or_run(UNUSED REQUEST *request,
859 fr_request_process_t process)
861 #ifdef DEBUG_STATE_MACHINE
862 int action = FR_ACTION_TIMER;
868 * Do this here so that fewer other functions need to do
871 if (request->master_state == REQUEST_STOP_PROCESSING) {
872 #ifdef DEBUG_STATE_MACHINE
873 if (debug_flag) printf("(%u) ********\tSTATE %s M-%s causes C-%s-> C-%s\t********\n",
874 request->number, __FUNCTION__,
875 master_state_names[request->master_state],
876 child_state_names[request->child_state],
877 child_state_names[REQUEST_DONE]);
879 request_done(request, FR_ACTION_DONE);
883 request->process = process;
885 if (we_are_master()) {
889 * (re) set the initial delay.
891 request->delay = USEC / 3;
892 gettimeofday(&when, NULL);
893 tv_add(&when, request->delay);
894 request->delay += request->delay >> 1;
896 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
898 #ifdef HAVE_PTHREAD_H
901 * A child thread will eventually pick it up.
903 if (request_enqueue(request)) return;
906 * Otherwise we're not going to do anything with
909 request_done(request, FR_ACTION_DONE);
915 request->child_state = REQUEST_RUNNING;
916 request->process(request, FR_ACTION_RUN);
920 * Requests that care about child process exit
921 * codes have already either called
922 * rad_waitpid(), or they've given up.
924 while (waitpid(-1, NULL, WNOHANG) > 0);
928 STATE_MACHINE_DECL(request_common)
938 * Bail out as early as possible.
940 if (request->master_state == REQUEST_STOP_PROCESSING) {
941 request_done(request, REQUEST_DONE);
949 * We're still waiting for a proxy reply.
951 if (request->child_state == REQUEST_PROXIED) {
952 proxy_wait_for_reply(request, action);
957 ERROR("(%u) Discarding duplicate request from "
958 "client %s port %d - ID: %u due to unfinished request",
959 request->number, request->client->shortname,
960 request->packet->src_port,request->packet->id);
963 case FR_ACTION_CONFLICTING:
965 * We're in the master thread, ask the child to
966 * stop processing the request.
968 request_done(request, action);
971 case FR_ACTION_TIMER:
972 request_process_timer(request);
976 case FR_ACTION_PROXY_REPLY:
977 DEBUG2("Reply from home server %s port %d - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'",
978 inet_ntop(request->proxy->src_ipaddr.af,
979 &request->proxy->src_ipaddr.ipaddr,
980 buffer, sizeof(buffer)),
981 request->proxy->dst_port, request->proxy->id,
987 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
992 STATE_MACHINE_DECL(request_cleanup_delay)
1001 if (request->reply->code != 0) {
1002 request->listener->send(request->listener, request);
1004 RDEBUG("No reply. Ignoring retransmit.");
1008 * Double the cleanup_delay to catch retransmits.
1010 when = request->reply->timestamp;
1011 request->delay += request->delay ;
1012 when.tv_sec += request->delay;
1014 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
1018 case FR_ACTION_PROXY_REPLY:
1020 case FR_ACTION_CONFLICTING:
1021 case FR_ACTION_TIMER:
1022 request_common(request, action);
1026 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
1031 STATE_MACHINE_DECL(request_reject_delay)
1033 TRACE_STATE_MACHINE;
1038 ERROR("(%u) Discarding duplicate request from "
1039 "client %s port %d - ID: %u due to delayed reject",
1040 request->number, request->client->shortname,
1041 request->packet->src_port,request->packet->id);
1045 case FR_ACTION_PROXY_REPLY:
1047 case FR_ACTION_CONFLICTING:
1048 case FR_ACTION_TIMER:
1049 request_common(request, action);
1053 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
1059 static int request_pre_handler(REQUEST *request, UNUSED int action)
1061 TRACE_STATE_MACHINE;
1065 if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
1068 * Don't decode the packet if it's an internal "fake"
1069 * request. Instead, just return so that the caller can
1072 if (request->packet->dst_port == 0) {
1073 request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
1074 request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
1080 * Put the decoded packet into it's proper place.
1082 if (request->proxy_reply != NULL) {
1084 * There may be a proxy reply, but it may be too late.
1086 if (!request->proxy_listener) return 0;
1088 rcode = request->proxy_listener->decode(request->proxy_listener, request);
1089 DEBUG_PACKET(request, request->proxy_reply, 0);
1092 * Pro-actively remove it from the proxy hash.
1093 * This is later than in 2.1.x, but it means that
1094 * the replies are authenticated before being
1095 * removed from the hash.
1098 (request->num_proxied_requests <= request->num_proxied_responses)) {
1099 remove_from_proxy_hash(request);
1104 if (request->packet->vps == NULL) {
1105 rcode = request->listener->decode(request->listener, request);
1108 if (debug_condition) {
1110 * Ignore parse errors.
1112 if (radius_evaluate_cond(request, RLM_MODULE_OK, 0, debug_condition)) {
1113 request->options = 2;
1114 request->radlog = vradlog_request;
1119 DEBUG_PACKET(request, request->packet, 0);
1125 RDEBUG("Dropping packet without response because of error: %s", fr_strerror());
1126 request->reply->offset = -2; /* bad authenticator */
1130 if (!request->username) {
1131 request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
1135 if (action == FR_ACTION_PROXY_REPLY) {
1136 return process_proxy_reply(request);
1143 STATE_MACHINE_DECL(request_finish)
1147 TRACE_STATE_MACHINE;
1149 (void) action; /* -Wunused */
1151 if (request->master_state == REQUEST_STOP_PROCESSING) return;
1154 * Don't send replies if there are none to send.
1156 if (!request->in_request_hash) {
1158 if ((request->listener->type == RAD_LISTEN_AUTH)
1159 #ifdef WITH_ACCOUNTING
1160 || (request->listener->type == RAD_LISTEN_ACCT)
1163 listen_socket_t *sock = request->listener->data;
1165 if (sock->proto == IPPROTO_UDP) return;
1168 * TCP packets aren't in the request
1178 * Override the response code if a control:Response-Packet-Type attribute is present.
1180 vp = pairfind(request->config_items, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
1182 if (vp->vp_integer == 256) {
1183 RDEBUG2("Not responding to request");
1184 request->reply->code = 0;
1186 request->reply->code = vp->vp_integer;
1190 * Catch Auth-Type := Reject BEFORE proxying the packet.
1192 else if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1193 if (request->reply->code == 0) {
1194 vp = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY);
1196 if (!vp || (vp->vp_integer != PW_AUTHENTICATION_REJECT)) {
1197 RDEBUG2("There was no response configured: "
1198 "rejecting request");
1201 request->reply->code = PW_AUTHENTICATION_REJECT;
1206 * Copy Proxy-State from the request to the reply.
1208 vp = paircopy2(request->reply, request->packet->vps,
1209 PW_PROXY_STATE, 0, TAG_ANY);
1210 if (vp) pairadd(&request->reply->vps, vp);
1212 switch (request->reply->code) {
1213 case PW_AUTHENTICATION_ACK:
1214 rad_postauth(request);
1216 case PW_ACCESS_CHALLENGE:
1217 pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0,
1219 vp = pairmake_config("Post-Auth-Type", "Challenge", T_OP_SET);
1220 if (vp) rad_postauth(request);
1227 * Run rejected packets through
1229 * Post-Auth-Type = Reject
1231 * We do this separately so ACK and challenge can change the code
1232 * to reject if a module returns reject.
1234 if (request->reply->code == PW_AUTHENTICATION_REJECT) {
1235 pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
1236 vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET);
1237 if (vp) rad_postauth(request);
1241 * Clean up. These are no longer needed.
1243 pairfree(&request->config_items);
1245 pairfree(&request->packet->vps);
1246 request->username = NULL;
1247 request->password = NULL;
1250 if (request->proxy) {
1251 pairfree(&request->proxy->vps);
1253 if (request->proxy_reply) {
1254 pairfree(&request->proxy_reply->vps);
1258 gettimeofday(&request->reply->timestamp, NULL);
1263 if ((request->reply->code != PW_AUTHENTICATION_REJECT) ||
1264 (request->root->reject_delay == 0)) {
1265 DEBUG_PACKET(request, request->reply, 1);
1266 request->listener->send(request->listener,
1268 pairfree(&request->reply->vps);
1270 RDEBUG2("Finished request %u.", request->number);
1271 #ifdef WITH_ACCOUNTING
1272 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1274 request->child_state = REQUEST_DONE;
1278 if (request->root->cleanup_delay == 0) {
1280 request->child_state = REQUEST_DONE;
1283 request->child_state = REQUEST_CLEANUP_DELAY;
1286 RDEBUG2("Delaying reject of request %u for %d seconds",
1288 request->root->reject_delay);
1290 request->child_state = REQUEST_REJECT_DELAY;
1294 STATE_MACHINE_DECL(request_running)
1296 TRACE_STATE_MACHINE;
1299 case FR_ACTION_TIMER:
1300 request_process_timer(request);
1303 case FR_ACTION_CONFLICTING:
1305 request_common(request, action);
1310 * This can happen due to a race condition where
1311 * we send a proxied request, and immediately get
1312 * another reply, before the timer has a chance
1313 * to update the various states.
1315 case FR_ACTION_PROXY_REPLY:
1316 request->child_state = REQUEST_RUNNING;
1317 request->process = proxy_running;
1322 if (!request_pre_handler(request, action)) {
1323 #ifdef DEBUG_STATE_MACHINE
1324 if (debug_flag) printf("(%u) ********\tSTATE %s failed in pre-handler C-%s -> C-%s\t********\n",
1325 request->number, __FUNCTION__,
1326 child_state_names[request->child_state],
1327 child_state_names[REQUEST_DONE]);
1331 request->child_state = REQUEST_DONE;
1335 rad_assert(request->handle != NULL);
1336 request->handle(request);
1340 * We may need to send a proxied request.
1342 if ((action == FR_ACTION_RUN) &&
1343 request_will_proxy(request)) {
1344 #ifdef DEBUG_STATE_MACHINE
1345 if (debug_flag) printf("(%u) ********\tWill Proxy\t********\n", request->number);
1349 * takes care of setting
1350 * up the post proxy fail
1353 if (request_proxy(request, 0) < 0) goto finished;
1357 #ifdef DEBUG_STATE_MACHINE
1358 if (debug_flag) printf("(%u) ********\tFinished\t********\n", request->number);
1363 * Maybe originate a CoA request.
1365 if ((action == FR_ACTION_RUN) && request->coa) {
1366 request_coa_originate(request);
1373 request_finish(request, action);
1378 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
1383 int request_receive(rad_listen_t *listener, RADIUS_PACKET *packet,
1384 RADCLIENT *client, RAD_REQUEST_FUNP fun)
1387 RADIUS_PACKET **packet_p;
1388 REQUEST *request = NULL;
1390 listen_socket_t *sock = NULL;
1393 * Set the last packet received.
1395 gettimeofday(&now, NULL);
1397 #ifdef WITH_ACCOUNTING
1398 if (listener->type != RAD_LISTEN_DETAIL)
1401 sock = listener->data;
1402 sock->last_packet = now.tv_sec;
1404 packet->timestamp = now;
1407 * Skip everything if required.
1409 if (listener->nodup) goto skip_dup;
1411 packet_p = fr_packet_list_find(pl, packet);
1413 request = fr_packet2myptr(REQUEST, packet, packet_p);
1414 rad_assert(request->in_request_hash);
1417 * Same src/dst ip/port, length, and
1418 * authentication vector: must be a duplicate.
1420 if ((request->packet->data_len == packet->data_len) &&
1421 (memcmp(request->packet->vector, packet->vector,
1422 sizeof(packet->vector)) == 0)) {
1425 switch (packet->code) {
1426 case PW_AUTHENTICATION_REQUEST:
1427 FR_STATS_INC(auth, total_dup_requests);
1430 #ifdef WITH_ACCOUNTING
1431 case PW_ACCOUNTING_REQUEST:
1432 FR_STATS_INC(acct, total_dup_requests);
1436 case PW_COA_REQUEST:
1437 FR_STATS_INC(coa, total_dup_requests);
1440 case PW_DISCONNECT_REQUEST:
1441 FR_STATS_INC(dsc, total_dup_requests);
1448 #endif /* WITH_STATS */
1450 request->process(request, FR_ACTION_DUP);
1455 * Say we're ignoring the old one, and continue
1456 * to process the new one.
1458 request->process(request, FR_ACTION_CONFLICTING);
1463 * Quench maximum number of outstanding requests.
1465 if (mainconfig.max_requests &&
1466 ((count = fr_packet_list_num_elements(pl)) > mainconfig.max_requests)) {
1467 static time_t last_complained = 0;
1469 if (last_complained == now.tv_sec) return 0;
1471 last_complained = now.tv_sec;
1473 ERROR("Dropping request (%d is too many): from client %s port %d - ID: %d", count,
1475 packet->src_port, packet->id);
1476 WARN("Please check the configuration file.\n"
1477 "\tThe value for 'max_requests' is probably set too low.\n");
1479 exec_trigger(NULL, NULL, "server.max_requests", true);
1485 * Rate-limit the incoming packets
1487 if (sock && sock->max_rate) {
1490 pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now,
1491 &sock->rate_time, &now);
1493 if (pps > sock->max_rate) {
1494 DEBUG("Dropping request due to rate limiting");
1497 sock->rate_pps_now++;
1500 request = request_setup(listener, packet, client, fun);
1501 if (!request) return 1;
1504 * Remember the request in the list.
1506 if (!listener->nodup) {
1507 if (!fr_packet_list_insert(pl, &request->packet)) {
1508 RERROR("Failed to insert request in the list of live requests: discarding it");
1509 request_done(request, FR_ACTION_DONE);
1513 request->in_request_hash = true;
1517 * Process it. Send a response, and free it.
1519 if (listener->synchronous) {
1520 request->listener->decode(request->listener, request);
1521 request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
1522 request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
1525 request->listener->send(request->listener, request);
1526 request_free(&request);
1531 * Otherwise, insert it into the state machine.
1532 * The child threads will take care of processing it.
1534 request_queue_or_run(request, request_running);
1540 static REQUEST *request_setup(rad_listen_t *listener, RADIUS_PACKET *packet,
1541 RADCLIENT *client, RAD_REQUEST_FUNP fun)
1546 * Create and initialize the new request.
1548 request = request_alloc(NULL);
1549 request->reply = rad_alloc(request, 0);
1550 if (!request->reply) {
1552 request_free(&request);
1556 request->listener = listener;
1557 request->client = client;
1558 request->packet = talloc_steal(request, packet);
1559 request->number = request_num_counter++;
1560 request->priority = listener->type;
1561 request->master_state = REQUEST_ACTIVE;
1562 #ifdef DEBUG_STATE_MACHINE
1563 if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n",
1564 request->number, __FUNCTION__,
1565 child_state_names[request->child_state],
1566 child_state_names[REQUEST_RUNNING]);
1568 request->child_state = REQUEST_RUNNING;
1569 request->handle = fun;
1573 request->listener->stats.last_packet = request->packet->timestamp.tv_sec;
1574 if (packet->code == PW_AUTHENTICATION_REQUEST) {
1575 request->client->auth.last_packet = request->packet->timestamp.tv_sec;
1576 radius_auth_stats.last_packet = request->packet->timestamp.tv_sec;
1577 #ifdef WITH_ACCOUNTING
1578 } else if (packet->code == PW_ACCOUNTING_REQUEST) {
1579 request->client->acct.last_packet = request->packet->timestamp.tv_sec;
1580 radius_acct_stats.last_packet = request->packet->timestamp.tv_sec;
1583 #endif /* WITH_STATS */
1586 * Status-Server packets go to the head of the queue.
1588 if (request->packet->code == PW_STATUS_SERVER) request->priority = 0;
1591 * Set virtual server identity
1593 if (client->server) {
1594 request->server = client->server;
1595 } else if (listener->server) {
1596 request->server = listener->server;
1598 request->server = NULL;
1601 request->root = &mainconfig;
1603 request->listener->count++;
1607 * The request passes many of our sanity checks.
1608 * From here on in, if anything goes wrong, we
1609 * send a reject message, instead of dropping the
1614 * Build the reply template from the request.
1617 request->reply->sockfd = request->packet->sockfd;
1618 request->reply->dst_ipaddr = request->packet->src_ipaddr;
1619 request->reply->src_ipaddr = request->packet->dst_ipaddr;
1620 request->reply->dst_port = request->packet->src_port;
1621 request->reply->src_port = request->packet->dst_port;
1622 request->reply->id = request->packet->id;
1623 request->reply->code = 0; /* UNKNOWN code */
1624 memcpy(request->reply->vector, request->packet->vector,
1625 sizeof(request->reply->vector));
1626 request->reply->vps = NULL;
1627 request->reply->data = NULL;
1628 request->reply->data_len = 0;
1634 /***********************************************************************
1638 ***********************************************************************/
1641 * Timer function for all TCP sockets.
1643 static void tcp_socket_timer(void *ctx)
1645 rad_listen_t *listener = ctx;
1646 listen_socket_t *sock = listener->data;
1647 struct timeval end, now;
1649 fr_socket_limit_t *limit;
1651 fr_event_now(el, &now);
1653 if (listener->status != RAD_LISTEN_STATUS_KNOWN) return;
1655 switch (listener->type) {
1657 case RAD_LISTEN_PROXY:
1658 limit = &sock->home->limit;
1662 case RAD_LISTEN_AUTH:
1663 #ifdef WITH_ACCOUNTING
1664 case RAD_LISTEN_ACCT:
1666 limit = &sock->limit;
1674 * If we enforce a lifetime, do it now.
1676 if (limit->lifetime > 0) {
1677 end.tv_sec = sock->opened + limit->lifetime;
1680 if (timercmp(&end, &now, <=)) {
1681 listener->print(listener, buffer, sizeof(buffer));
1682 DEBUG("Reached maximum lifetime on socket %s", buffer);
1686 listener->status = RAD_LISTEN_STATUS_EOL;
1687 event_new_fd(listener);
1696 * Enforce an idle timeout.
1698 if (limit->idle_timeout > 0) {
1699 struct timeval idle;
1701 rad_assert(sock->last_packet != 0);
1702 idle.tv_sec = sock->last_packet + limit->idle_timeout;
1705 if (timercmp(&idle, &now, <=)) {
1706 listener->print(listener, buffer, sizeof(buffer));
1707 DEBUG("Reached idle timeout on socket %s", buffer);
1712 * Enforce the minimum of idle timeout or lifetime.
1714 if (timercmp(&idle, &end, <)) {
1720 * Wake up at t + 0.5s. The code above checks if the timers
1721 * are <= t. This addition gives us a bit of leeway.
1723 end.tv_usec = USEC / 2;
1725 if (!fr_event_insert(el, tcp_socket_timer, listener, &end, &sock->ev)) {
1726 rad_panic("Failed to insert event");
1733 * Add +/- 2s of jitter, as suggested in RFC 3539
1736 static void add_jitter(struct timeval *when)
1743 jitter ^= (jitter >> 10);
1744 jitter &= ((1 << 22) - 1); /* 22 bits of 1 */
1747 * Add in ~ (4 * USEC) of jitter.
1749 tv_add(when, jitter);
1753 * Called by socket_del to remove requests with this socket
1755 static int eol_proxy_listener(void *ctx, void *data)
1757 rad_listen_t *this = ctx;
1758 RADIUS_PACKET **proxy_p = data;
1761 request = fr_packet2myptr(REQUEST, proxy, proxy_p);
1762 if (request->proxy_listener != this) return 0;
1765 * The normal "remove_from_proxy_hash" tries to grab the
1766 * proxy mutex. We already have it held, so grabbing it
1767 * again will cause a deadlock. Instead, call the "no
1768 * lock" version of the function.
1770 rad_assert(request->in_proxy_hash == true);
1771 remove_from_proxy_hash_nl(request, false);
1774 * Don't mark it as DONE. The client can retransmit, and
1775 * the packet SHOULD be re-proxied somewhere else.
1777 * Return "2" means that the rbtree code will remove it
1778 * from the tree, and we don't need to do it ourselves.
1782 #endif /* WITH_PROXY */
1784 static int eol_listener(void *ctx, void *data)
1786 rad_listen_t *this = ctx;
1787 RADIUS_PACKET **packet_p = data;
1790 request = fr_packet2myptr(REQUEST, packet, packet_p);
1791 if (request->listener != this) return 0;
1793 request->master_state = REQUEST_STOP_PROCESSING;
1797 #endif /* WITH_TCP */
1800 /***********************************************************************
1802 * Proxy handlers for the state machine.
1804 ***********************************************************************/
1807 * Called with the proxy mutex held
1809 static void remove_from_proxy_hash_nl(REQUEST *request, bool yank)
1811 if (!request->in_proxy_hash) return;
1813 fr_packet_list_id_free(proxy_list, request->proxy, yank);
1814 request->in_proxy_hash = false;
1817 * On the FIRST reply, decrement the count of outstanding
1818 * requests. Note that this is NOT the count of sent
1819 * packets, but whether or not the home server has
1822 if (request->home_server &&
1823 request->home_server->currently_outstanding) {
1824 request->home_server->currently_outstanding--;
1827 * If we're NOT sending it packets, then we don't know
1828 * if it's alive or dead.
1830 if ((request->home_server->currently_outstanding == 0) &&
1831 (request->home_server->state == HOME_STATE_ALIVE)) {
1832 request->home_server->state = HOME_STATE_UNKNOWN;
1833 request->home_server->last_packet_sent = 0;
1834 request->home_server->last_packet_recv = 0;
1839 rad_assert(request->proxy_listener != NULL);
1840 request->proxy_listener->count--;
1842 request->proxy_listener = NULL;
1845 * Got from YES in hash, to NO, not in hash while we hold
1846 * the mutex. This guarantees that when another thread
1847 * grabs the mutex, the "not in hash" flag is correct.
1849 RDEBUG3("proxy: request is no longer in proxy hash");
1852 static void remove_from_proxy_hash(REQUEST *request)
1855 * Check this without grabbing the mutex because it's a
1856 * lot faster that way.
1858 if (!request->in_proxy_hash) return;
1861 * The "not in hash" flag is definitive. However, if the
1862 * flag says that it IS in the hash, there might still be
1863 * a race condition where it isn't.
1865 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1867 if (!request->in_proxy_hash) {
1868 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1872 remove_from_proxy_hash_nl(request, true);
1874 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1877 static int insert_into_proxy_hash(REQUEST *request)
1881 void *proxy_listener;
1883 rad_assert(request->proxy != NULL);
1884 rad_assert(request->home_server != NULL);
1885 rad_assert(proxy_list != NULL);
1888 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1889 proxy_listener = NULL;
1890 request->num_proxied_requests = 1;
1891 request->num_proxied_responses = 0;
1893 for (tries = 0; tries < 2; tries++) {
1896 RDEBUG3("proxy: Trying to allocate ID (%d/2)", tries);
1897 rcode = fr_packet_list_id_alloc(proxy_list,
1898 request->home_server->proto,
1899 &request->proxy, &proxy_listener);
1900 if ((debug_flag > 2) && (rcode == 0)) {
1901 RDEBUG("proxy: Failed allocating ID: %s", fr_strerror());
1903 if (rcode > 0) break;
1904 if (tries > 0) continue; /* try opening new socket only once */
1906 #ifdef HAVE_PTHREAD_H
1907 if (proxy_no_new_sockets) break;
1910 RDEBUG3("proxy: Trying to open a new listener to the home server");
1911 this = proxy_new_listener(request->home_server, 0);
1913 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1917 request->proxy->src_port = 0; /* Use any new socket */
1918 proxy_listener = this;
1921 * Add it to the event loop (and to the packet list)
1922 * before we try to grab another Id.
1924 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1925 if (!event_new_fd(this)) {
1926 RDEBUG3("proxy: Failed inserting new socket into event loop");
1930 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1933 if (!proxy_listener || (rcode == 0)) {
1934 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1935 REDEBUG2("proxy: Failed allocating Id for proxied request");
1937 request->proxy_listener = NULL;
1938 request->in_proxy_hash = false;
1942 rad_assert(request->proxy->id >= 0);
1944 request->proxy_listener = proxy_listener;
1945 request->in_proxy_hash = true;
1946 RDEBUG3("proxy: request is now in proxy hash");
1949 * Keep track of maximum outstanding requests to a
1950 * particular home server. 'max_outstanding' is
1951 * enforced in home_server_ldb(), in realms.c.
1953 request->home_server->currently_outstanding++;
1956 request->proxy_listener->count++;
1959 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1961 RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
1962 inet_ntop(request->proxy->dst_ipaddr.af,
1963 &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
1964 request->proxy->dst_port,
1965 request->proxy->id);
1970 static int process_proxy_reply(REQUEST *request)
1973 int post_proxy_type = 0;
1977 * Delete any reply we had accumulated until now.
1979 pairfree(&request->reply->vps);
1982 * Run the packet through the post-proxy stage,
1983 * BEFORE playing games with the attributes.
1985 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
1988 * If we have a proxy_reply, and it was a reject, setup
1989 * post-proxy-type Reject
1991 if (!vp && request->proxy_reply &&
1992 request->proxy_reply->code == PW_AUTHENTICATION_REJECT) {
1995 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Reject");
1997 vp = radius_paircreate(request, &request->config_items,
1998 PW_POST_PROXY_TYPE, 0);
2000 vp->vp_integer = dval->value;
2005 post_proxy_type = vp->vp_integer;
2007 RDEBUG2(" Found Post-Proxy-Type %s",
2008 dict_valnamebyattr(PW_POST_PROXY_TYPE, 0,
2012 if (request->home_pool && request->home_pool->virtual_server) {
2013 char const *old_server = request->server;
2015 request->server = request->home_pool->virtual_server;
2016 RDEBUG2(" server %s {", request->server);
2017 rcode = process_post_proxy(post_proxy_type, request);
2019 request->server = old_server;
2021 rcode = process_post_proxy(post_proxy_type, request);
2025 if (request->packet->code == request->proxy->code)
2027 * Don't run the next bit if we originated a CoA
2028 * packet, after receiving an Access-Request or
2029 * Accounting-Request.
2034 * There may NOT be a proxy reply, as we may be
2035 * running Post-Proxy-Type = Fail.
2037 if (request->proxy_reply) {
2039 * Delete the Proxy-State Attributes from
2040 * the reply. These include Proxy-State
2041 * attributes from us and remote server.
2043 pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
2046 * Add the attributes left in the proxy
2047 * reply to the reply list.
2049 pairfilter(request->reply, &request->reply->vps,
2050 &request->proxy_reply->vps, 0, 0, TAG_ANY);
2053 * Free proxy request pairs.
2055 pairfree(&request->proxy->vps);
2059 default: /* Don't do anything */
2061 case RLM_MODULE_FAIL:
2064 case RLM_MODULE_HANDLED:
2071 int request_proxy_reply(RADIUS_PACKET *packet)
2073 RADIUS_PACKET **proxy_p;
2078 PTHREAD_MUTEX_LOCK(&proxy_mutex);
2079 proxy_p = fr_packet_list_find_byreply(proxy_list, packet);
2082 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
2083 PROXY( "No outstanding request was found for reply from host %s port %d - ID %u",
2084 inet_ntop(packet->src_ipaddr.af,
2085 &packet->src_ipaddr.ipaddr,
2086 buffer, sizeof(buffer)),
2087 packet->src_port, packet->id);
2091 request = fr_packet2myptr(REQUEST, proxy, proxy_p);
2092 request->num_proxied_responses++; /* needs to be protected by lock */
2094 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
2097 * No reply, BUT the current packet fails verification:
2098 * ignore it. This does the MD5 calculations in the
2099 * server core, but I guess we can fix that later.
2101 if (!request->proxy_reply &&
2102 (rad_verify(packet, request->proxy,
2103 request->home_server->secret) != 0)) {
2104 DEBUG("Ignoring spoofed proxy reply. Signature is invalid");
2109 * The home server sent us a packet which doesn't match
2110 * something we have: ignore it. This is done only to
2111 * catch the case of broken systems.
2113 if (request->proxy_reply &&
2114 (memcmp(request->proxy_reply->vector,
2116 sizeof(request->proxy_reply->vector)) != 0)) {
2117 RDEBUG2("Ignoring conflicting proxy reply");
2121 gettimeofday(&now, NULL);
2124 * Status-Server packets don't count as real packets.
2126 if (request->proxy->code != PW_STATUS_SERVER) {
2127 listen_socket_t *sock = request->proxy_listener->data;
2129 request->home_server->last_packet_recv = now.tv_sec;
2130 sock->last_packet = now.tv_sec;
2134 * If we have previously seen a reply, ignore the
2137 if (request->proxy_reply) {
2138 RDEBUG2("Discarding duplicate reply from host %s port %d - ID: %d",
2139 inet_ntop(packet->src_ipaddr.af,
2140 &packet->src_ipaddr.ipaddr,
2141 buffer, sizeof(buffer)),
2142 packet->src_port, packet->id);
2147 * Call the state machine to do something useful with the
2150 request->proxy_reply = packet;
2151 packet->timestamp = now;
2152 request->priority = RAD_LISTEN_PROXY;
2155 * We've received a reply. If we hadn't been sending it
2156 * packets for a while, just mark it alive.
2158 if (request->home_server->state == HOME_STATE_UNKNOWN) {
2159 request->home_server->state = HOME_STATE_ALIVE;
2163 request->home_server->stats.last_packet = packet->timestamp.tv_sec;
2164 request->proxy_listener->stats.last_packet = packet->timestamp.tv_sec;
2166 if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
2167 proxy_auth_stats.last_packet = packet->timestamp.tv_sec;
2168 #ifdef WITH_ACCOUNTING
2169 } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
2170 proxy_acct_stats.last_packet = packet->timestamp.tv_sec;
2173 #endif /* WITH_STATS */
2177 * When we originate CoA requests, we patch them in here
2178 * so that they don't affect the rest of the state
2181 if (request->parent) {
2182 rad_assert(request->parent->coa == request);
2183 rad_assert((request->proxy->code == PW_COA_REQUEST) ||
2184 (request->proxy->code == PW_DISCONNECT_REQUEST));
2185 rad_assert(request->process != NULL);
2186 request_coa_separate(request);
2190 request->process(request, FR_ACTION_PROXY_REPLY);
2196 static int setup_post_proxy_fail(REQUEST *request)
2198 DICT_VALUE const *dval = NULL;
2201 if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
2202 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
2203 "Fail-Authentication");
2205 } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
2206 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
2209 } else if (request->proxy->code == PW_COA_REQUEST) {
2210 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-CoA");
2212 } else if (request->proxy->code == PW_DISCONNECT_REQUEST) {
2213 dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Disconnect");
2216 WDEBUG("Unknown packet type in Post-Proxy-Type Fail: ignoring");
2220 if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail");
2223 pairdelete(&request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
2227 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
2228 if (!vp) vp = radius_paircreate(request, &request->config_items,
2229 PW_POST_PROXY_TYPE, 0);
2230 vp->vp_integer = dval->value;
2235 STATE_MACHINE_DECL(proxy_running)
2237 TRACE_STATE_MACHINE;
2240 case FR_ACTION_CONFLICTING:
2242 case FR_ACTION_TIMER:
2243 case FR_ACTION_PROXY_REPLY:
2244 request_common(request, action);
2248 request_running(request, action);
2252 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2257 STATE_MACHINE_DECL(request_virtual_server)
2261 TRACE_STATE_MACHINE;
2264 case FR_ACTION_CONFLICTING:
2266 case FR_ACTION_TIMER:
2267 case FR_ACTION_PROXY_REPLY:
2268 request_common(request, action);
2272 old = request->server;
2273 request->server = request->home_server->server;
2274 request_running(request, action);
2275 request->server = old;
2279 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2285 static int request_will_proxy(REQUEST *request)
2287 int rcode, pre_proxy_type = 0;
2288 char const *realmname = NULL;
2289 VALUE_PAIR *vp, *strippedname;
2290 home_server_t *home;
2291 REALM *realm = NULL;
2292 home_pool_t *pool = NULL;
2294 if (!request->root->proxy_requests) return 0;
2295 if (request->packet->dst_port == 0) return 0;
2296 if (request->packet->code == PW_STATUS_SERVER) return 0;
2297 if (request->in_proxy_hash) return 0;
2300 * FIXME: for 3.0, allow this only for rejects?
2302 if (request->reply->code != 0) return 0;
2304 vp = pairfind(request->config_items, PW_PROXY_TO_REALM, 0, TAG_ANY);
2306 realm = realm_find2(vp->vp_strvalue);
2308 REDEBUG2("Cannot proxy to unknown realm %s",
2313 realmname = vp->vp_strvalue;
2316 * Figure out which pool to use.
2318 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
2319 pool = realm->auth_pool;
2321 #ifdef WITH_ACCOUNTING
2322 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
2323 pool = realm->acct_pool;
2327 } else if ((request->packet->code == PW_COA_REQUEST) ||
2328 (request->packet->code == PW_DISCONNECT_REQUEST)) {
2329 pool = realm->coa_pool;
2339 vp = pairfind(request->config_items, PW_HOME_SERVER_POOL, 0, TAG_ANY);
2342 switch (request->packet->code) {
2343 case PW_AUTHENTICATION_REQUEST:
2344 pool_type = HOME_TYPE_AUTH;
2347 #ifdef WITH_ACCOUNTING
2348 case PW_ACCOUNTING_REQUEST:
2349 pool_type = HOME_TYPE_ACCT;
2354 case PW_COA_REQUEST:
2355 case PW_DISCONNECT_REQUEST:
2356 pool_type = HOME_TYPE_COA;
2364 pool = home_pool_byname(vp->vp_strvalue, pool_type);
2368 RWDEBUG2("Cancelling proxy as no home pool exists");
2372 if (request->listener->synchronous) {
2373 WARN("Cannot proxy a request which is from a 'synchronous' socket");
2377 request->home_pool = pool;
2379 home = home_server_ldb(realmname, pool, request);
2381 REDEBUG2("Failed to find live home server: Cancelling proxy");
2384 home_server_update_request(home, request);
2388 * Once we've decided to proxy a request, we cannot send
2389 * a CoA packet. So we free up any CoA packet here.
2391 if (request->coa) request_done(request->coa, FR_ACTION_DONE);
2395 * Remember that we sent the request to a Realm.
2397 if (realmname) pairmake_packet("Realm", realmname, T_OP_EQ);
2400 * Strip the name, if told to.
2402 * Doing it here catches the case of proxied tunneled
2405 if (realm && (realm->striprealm == true) &&
2406 (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY)) != NULL) {
2408 * If there's a Stripped-User-Name attribute in
2409 * the request, then use THAT as the User-Name
2410 * for the proxied request, instead of the
2413 * This is done by making a copy of the
2414 * Stripped-User-Name attribute, turning it into
2415 * a User-Name attribute, deleting the
2416 * Stripped-User-Name and User-Name attributes
2417 * from the vps list, and making the new
2418 * User-Name the head of the vps list.
2420 vp = pairfind(request->proxy->vps, PW_USER_NAME, 0, TAG_ANY);
2423 vp = radius_paircreate(request, NULL,
2425 rad_assert(vp != NULL); /* handled by above function */
2426 /* Insert at the START of the list */
2427 /* FIXME: Can't make assumptions about ordering */
2428 paircursor(&cursor, &vp);
2429 pairinsert(&cursor, request->proxy->vps);
2430 request->proxy->vps = vp;
2432 pairstrcpy(vp, strippedname->vp_strvalue);
2435 * Do NOT delete Stripped-User-Name.
2440 * If there is no PW_CHAP_CHALLENGE attribute but
2441 * there is a PW_CHAP_PASSWORD we need to add it
2442 * since we can't use the request authenticator
2443 * anymore - we changed it.
2445 if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
2446 pairfind(request->proxy->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
2447 pairfind(request->proxy->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
2449 vp = radius_paircreate(request, &request->proxy->vps,
2450 PW_CHAP_CHALLENGE, 0);
2451 vp->length = sizeof(request->packet->vector);
2452 vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
2454 memcpy(p, request->packet->vector,
2455 sizeof(request->packet->vector));
2459 * The RFC's say we have to do this, but FreeRADIUS
2462 vp = radius_paircreate(request, &request->proxy->vps,
2464 pairsprintf(vp, "%u", request->packet->id);
2467 * Should be done BEFORE inserting into proxy hash, as
2468 * pre-proxy may use this information, or change it.
2470 request->proxy->code = request->packet->code;
2473 * Call the pre-proxy routines.
2475 vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
2477 RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
2478 pre_proxy_type = vp->vp_integer;
2481 rad_assert(request->home_pool != NULL);
2483 if (request->home_pool->virtual_server) {
2484 char const *old_server = request->server;
2486 request->server = request->home_pool->virtual_server;
2487 RDEBUG2(" server %s {", request->server);
2488 rcode = process_pre_proxy(pre_proxy_type, request);
2490 request->server = old_server;
2492 rcode = process_pre_proxy(pre_proxy_type, request);
2495 case RLM_MODULE_FAIL:
2496 case RLM_MODULE_INVALID:
2497 case RLM_MODULE_NOTFOUND:
2498 case RLM_MODULE_USERLOCK:
2500 /* FIXME: debug print failed stuff */
2503 case RLM_MODULE_REJECT:
2504 case RLM_MODULE_HANDLED:
2508 * Only proxy the packet if the pre-proxy code succeeded.
2510 case RLM_MODULE_NOOP:
2512 case RLM_MODULE_UPDATED:
2519 static int request_proxy(REQUEST *request, int retransmit)
2523 rad_assert(request->parent == NULL);
2524 rad_assert(request->home_server != NULL);
2526 if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
2530 RWDEBUG("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request");
2531 request_done(request->coa, FR_ACTION_DONE);
2536 * The request may be sent to a virtual server. If we're
2537 * in a child thread, just process it here. If we're the
2538 * master, push it back onto the queue for later
2541 if (request->home_server->server) {
2542 DEBUG("Proxying to virtual server %s",
2543 request->home_server->server);
2545 if (!we_are_master()) {
2546 request_virtual_server(request, FR_ACTION_RUN);
2551 request_queue_or_run(request, request_virtual_server);
2556 * We're actually sending a proxied packet. Do that now.
2558 if (!request->in_proxy_hash && !insert_into_proxy_hash(request)) {
2559 EDEBUG("Failed to insert request into the proxy list.");
2563 rad_assert(request->proxy->id >= 0);
2566 if (request->home_server->tls) {
2567 RDEBUG2("Proxying request to home server %s port %d (TLS)",
2568 inet_ntop(request->proxy->dst_ipaddr.af,
2569 &request->proxy->dst_ipaddr.ipaddr,
2570 buffer, sizeof(buffer)),
2571 request->proxy->dst_port);
2574 RDEBUG2("Proxying request to home server %s port %d",
2575 inet_ntop(request->proxy->dst_ipaddr.af,
2576 &request->proxy->dst_ipaddr.ipaddr,
2577 buffer, sizeof(buffer)),
2578 request->proxy->dst_port);
2580 DEBUG_PACKET(request, request->proxy, 1);
2582 gettimeofday(&request->proxy_retransmit, NULL);
2584 request->proxy->timestamp = request->proxy_retransmit;
2585 request->home_server->last_packet_sent = request->proxy_retransmit.tv_sec;
2588 FR_STATS_TYPE_INC(request->home_server->stats.total_requests);
2590 request->child_state = REQUEST_PROXIED;
2591 request->proxy_listener->send(request->proxy_listener,
2597 * Proxy the packet as if it was new.
2599 static int request_proxy_anew(REQUEST *request)
2601 home_server_t *home;
2604 * Delete the request from the proxy list.
2606 * The packet list code takes care of ensuring that IDs
2607 * aren't reused until all 256 IDs have been used. So
2608 * there's a 1/256 chance of re-using the same ID when
2609 * we're sending to the same home server. Which is
2612 remove_from_proxy_hash(request);
2615 * Find a live home server for the request.
2617 home = home_server_ldb(NULL, request->home_pool, request);
2619 REDEBUG2("Failed to find live home server for request");
2621 if (setup_post_proxy_fail(request)) {
2622 request_queue_or_run(request, proxy_running);
2624 gettimeofday(&request->reply->timestamp, NULL);
2625 request_cleanup_delay_init(request, NULL);
2629 home_server_update_request(home, request);
2631 if (!insert_into_proxy_hash(request)) {
2632 RPROXY("Failed to insert retransmission into the proxy list.");
2633 goto post_proxy_fail;
2637 * Free the old packet, to force re-encoding
2639 talloc_free(request->proxy->data);
2640 request->proxy->data = NULL;
2641 request->proxy->data_len = 0;
2643 #ifdef WITH_ACCOUNTING
2645 * Update the Acct-Delay-Time attribute.
2647 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
2650 vp = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
2651 if (!vp) vp = radius_paircreate(request,
2652 &request->proxy->vps,
2653 PW_ACCT_DELAY_TIME, 0);
2657 gettimeofday(&now, NULL);
2658 vp->vp_integer += now.tv_sec - request->proxy_retransmit.tv_sec;
2663 if (request_proxy(request, 1) != 1) goto post_proxy_fail;
2668 STATE_MACHINE_DECL(request_ping)
2670 home_server_t *home = request->home_server;
2673 TRACE_STATE_MACHINE;
2677 case FR_ACTION_TIMER:
2678 ERROR("No response to status check %d for home server %s port %d",
2680 inet_ntop(request->proxy->dst_ipaddr.af,
2681 &request->proxy->dst_ipaddr.ipaddr,
2682 buffer, sizeof(buffer)),
2683 request->proxy->dst_port);
2686 case FR_ACTION_PROXY_REPLY:
2687 rad_assert(request->in_proxy_hash);
2689 request->home_server->num_received_pings++;
2690 RPROXY("Received response to status check %d (%d in current sequence)",
2691 request->number, home->num_received_pings);
2694 * Remove the request from any hashes
2696 fr_event_delete(el, &request->ev);
2697 remove_from_proxy_hash(request);
2700 * The control socket may have marked the home server as
2701 * alive. OR, it may have suddenly started responding to
2702 * requests again. If so, don't re-do the "make alive"
2705 if (home->state == HOME_STATE_ALIVE) break;
2708 * We haven't received enough ping responses to mark it
2709 * "alive". Wait a bit.
2711 if (home->num_received_pings < home->num_pings_to_alive) {
2716 * Mark it alive and delete any outstanding
2719 home->state = HOME_STATE_ALIVE;
2720 exec_trigger(request, home->cs, "home_server.alive", false);
2721 home->currently_outstanding = 0;
2722 home->num_sent_pings = 0;
2723 home->num_received_pings = 0;
2724 gettimeofday(&home->revive_time, NULL);
2726 fr_event_delete(el, &home->ev);
2728 RPROXY("Marking home server %s port %d alive",
2729 inet_ntop(request->proxy->dst_ipaddr.af,
2730 &request->proxy->dst_ipaddr.ipaddr,
2731 buffer, sizeof(buffer)),
2732 request->proxy->dst_port);
2736 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
2740 rad_assert(!request->in_request_hash);
2741 rad_assert(request->ev == NULL);
2742 request_done(request, FR_ACTION_DONE);
2746 * Called from start of zombie period, OR after control socket
2747 * marks the home server dead.
2749 static void ping_home_server(void *ctx)
2751 home_server_t *home = ctx;
2754 struct timeval when, now;
2756 if ((home->state == HOME_STATE_ALIVE) ||
2757 (home->ping_check == HOME_PING_CHECK_NONE) ||
2759 (home->proto == IPPROTO_TCP) ||
2761 (home->ev != NULL)) {
2765 gettimeofday(&now, NULL);
2767 if (home->state == HOME_STATE_ZOMBIE) {
2768 when = home->zombie_period_start;
2769 when.tv_sec += home->zombie_period;
2771 if (timercmp(&when, &now, <)) {
2772 DEBUG("PING: Zombie period is over for home server %s",
2774 mark_home_server_dead(home, &now);
2778 request = request_alloc(NULL);
2779 request->number = request_num_counter++;
2782 request->proxy = rad_alloc(request, 1);
2783 rad_assert(request->proxy != NULL);
2785 if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
2786 request->proxy->code = PW_STATUS_SERVER;
2788 pairmake(request->proxy, &request->proxy->vps,
2789 "Message-Authenticator", "0x00", T_OP_SET);
2791 } else if (home->type == HOME_TYPE_AUTH) {
2792 request->proxy->code = PW_AUTHENTICATION_REQUEST;
2794 pairmake(request->proxy, &request->proxy->vps,
2795 "User-Name", home->ping_user_name, T_OP_SET);
2796 pairmake(request->proxy, &request->proxy->vps,
2797 "User-Password", home->ping_user_password, T_OP_SET);
2798 pairmake(request->proxy, &request->proxy->vps,
2799 "Service-Type", "Authenticate-Only", T_OP_SET);
2800 pairmake(request->proxy, &request->proxy->vps,
2801 "Message-Authenticator", "0x00", T_OP_SET);
2804 #ifdef WITH_ACCOUNTING
2805 request->proxy->code = PW_ACCOUNTING_REQUEST;
2807 pairmake(request->proxy, &request->proxy->vps,
2808 "User-Name", home->ping_user_name, T_OP_SET);
2809 pairmake(request->proxy, &request->proxy->vps,
2810 "Acct-Status-Type", "Stop", T_OP_SET);
2811 pairmake(request->proxy, &request->proxy->vps,
2812 "Acct-Session-Id", "00000000", T_OP_SET);
2813 vp = pairmake(request->proxy, &request->proxy->vps,
2814 "Event-Timestamp", "0", T_OP_SET);
2815 vp->vp_date = now.tv_sec;
2817 rad_assert("Internal sanity check failed");
2821 vp = pairmake(request->proxy, &request->proxy->vps,
2822 "NAS-Identifier", "", T_OP_SET);
2824 pairsprintf(vp, "Status Check %u. Are you alive?",
2825 home->num_sent_pings);
2828 request->proxy->src_ipaddr = home->src_ipaddr;
2829 request->proxy->dst_ipaddr = home->ipaddr;
2830 request->proxy->dst_port = home->port;
2831 request->home_server = home;
2832 #ifdef DEBUG_STATE_MACHINE
2833 if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n", request->number, __FUNCTION__,
2834 child_state_names[request->child_state],
2835 child_state_names[REQUEST_DONE]);
2836 if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_ping");
2838 #ifdef HAVE_PTHREAD_H
2839 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
2841 request->child_state = REQUEST_DONE;
2842 request->process = request_ping;
2844 rad_assert(request->proxy_listener == NULL);
2846 if (!insert_into_proxy_hash(request)) {
2847 RPROXY("Failed to insert status check %d into proxy list. Discarding it.",
2850 rad_assert(!request->in_request_hash);
2851 rad_assert(!request->in_proxy_hash);
2852 rad_assert(request->ev == NULL);
2853 request_free(&request);
2858 * Set up the timer callback.
2861 when.tv_sec += home->ping_timeout;
2863 DEBUG("PING: Waiting %u seconds for response to ping",
2864 home->ping_timeout);
2866 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
2867 home->num_sent_pings++;
2869 rad_assert(request->proxy_listener != NULL);
2870 request->proxy_listener->send(request->proxy_listener,
2874 * Add +/- 2s of jitter, as suggested in RFC 3539
2875 * and in the Issues and Fixes draft.
2878 home->when.tv_sec += home->ping_interval;
2880 add_jitter(&home->when);
2882 DEBUG("PING: Next status packet in %u seconds", home->ping_interval);
2883 INSERT_EVENT(ping_home_server, home);
2886 static void home_trigger(home_server_t *home, char const *trigger)
2889 RADIUS_PACKET my_packet;
2891 memset(&my_request, 0, sizeof(my_request));
2892 memset(&my_packet, 0, sizeof(my_packet));
2893 my_request.proxy = &my_packet;
2894 my_packet.dst_ipaddr = home->ipaddr;
2895 my_packet.src_ipaddr = home->src_ipaddr;
2897 exec_trigger(&my_request, home->cs, trigger, false);
2900 static void mark_home_server_zombie(home_server_t *home)
2906 rad_assert((home->state == HOME_STATE_ALIVE) ||
2907 (home->state == HOME_STATE_UNKNOWN));
2910 if (home->proto == IPPROTO_TCP) {
2911 WDEBUG("Not marking TCP server %s zombie", home->name);
2916 home->state = HOME_STATE_ZOMBIE;
2917 home_trigger(home, "home_server.zombie");
2920 * Back-date the zombie period to when we last expected
2921 * to see a response. i.e. when we last sent a request.
2923 if (home->last_packet_sent == 0) {
2924 gettimeofday(&home->zombie_period_start, NULL);
2926 home->zombie_period_start.tv_sec = home->last_packet_sent;
2927 home->zombie_period_start.tv_usec = 0;
2930 fr_event_delete(el, &home->ev);
2931 home->num_sent_pings = 0;
2932 home->num_received_pings = 0;
2934 PROXY( "Marking home server %s port %d as zombie (it has not responded in %d seconds).",
2935 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
2936 buffer, sizeof(buffer)),
2937 home->port, home->response_window);
2939 ping_home_server(home);
2943 void revive_home_server(void *ctx)
2945 home_server_t *home = ctx;
2949 rad_assert(home->proto != IPPROTO_TCP);
2952 home->state = HOME_STATE_ALIVE;
2953 home_trigger(home, "home_server.alive");
2954 home->currently_outstanding = 0;
2955 gettimeofday(&home->revive_time, NULL);
2958 * Delete any outstanding events.
2960 if (home->ev) fr_event_delete(el, &home->ev);
2962 PROXY( "Marking home server %s port %d alive again... we have no idea if it really is alive or not.",
2963 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
2964 buffer, sizeof(buffer)),
2968 void mark_home_server_dead(home_server_t *home, struct timeval *when)
2970 int previous_state = home->state;
2974 if (home->proto == IPPROTO_TCP) {
2975 WDEBUG("Not marking TCP server dead");
2980 PROXY( "Marking home server %s port %d as dead.",
2981 inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
2982 buffer, sizeof(buffer)),
2985 home->state = HOME_STATE_IS_DEAD;
2986 home_trigger(home, "home_server.dead");
2988 if (home->ping_check != HOME_PING_CHECK_NONE) {
2990 * If the control socket marks us dead, start
2991 * pinging. Otherwise, we already started
2992 * pinging when it was marked "zombie".
2994 if (previous_state == HOME_STATE_ALIVE) {
2995 ping_home_server(home);
2997 DEBUG("PING: Already pinging home server %s",
3003 * Revive it after a fixed period of time. This
3004 * is very, very, bad.
3007 home->when.tv_sec += home->revive_interval;
3009 DEBUG("PING: Reviving home server %s in %u seconds",
3010 home->name, home->revive_interval);
3011 INSERT_EVENT(revive_home_server, home);
3015 STATE_MACHINE_DECL(proxy_wait_for_reply)
3017 struct timeval now, when;
3018 home_server_t *home = request->home_server;
3021 TRACE_STATE_MACHINE;
3023 rad_assert(request->packet->code != PW_STATUS_SERVER);
3024 rad_assert(request->home_server != NULL);
3026 if (request->master_state == REQUEST_STOP_PROCESSING) {
3027 request->child_state = REQUEST_DONE;
3031 gettimeofday(&now, NULL);
3035 if (request->proxy_reply) return;
3037 if ((home->state == HOME_STATE_IS_DEAD) ||
3038 !request->proxy_listener ||
3039 (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) {
3040 request_proxy_anew(request);
3045 if (home->proto == IPPROTO_TCP) {
3046 DEBUG2("Suppressing duplicate proxied request (tcp) to home server %s port %d proto TCP - ID: %d",
3047 inet_ntop(request->proxy->dst_ipaddr.af,
3048 &request->proxy->dst_ipaddr.ipaddr,
3049 buffer, sizeof(buffer)),
3050 request->proxy->dst_port,
3051 request->proxy->id);
3057 * More than one retransmit a second is stupid,
3058 * and should be suppressed by the proxy.
3060 when = request->proxy_retransmit;
3063 if (timercmp(&now, &when, <)) {
3064 DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d proto TCP - ID: %d",
3065 inet_ntop(request->proxy->dst_ipaddr.af,
3066 &request->proxy->dst_ipaddr.ipaddr,
3067 buffer, sizeof(buffer)),
3068 request->proxy->dst_port,
3069 request->proxy->id);
3073 #ifdef WITH_ACCOUNTING
3075 * If we update the Acct-Delay-Time, we need to
3078 if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
3079 pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY)) {
3080 request_proxy_anew(request);
3085 RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
3086 inet_ntop(request->proxy->dst_ipaddr.af,
3087 &request->proxy->dst_ipaddr.ipaddr,
3088 buffer, sizeof(buffer)),
3089 request->proxy->dst_port,
3090 request->proxy->id);
3091 request->num_proxied_requests++;
3093 rad_assert(request->proxy_listener != NULL);;
3094 DEBUG_PACKET(request, request->proxy, 1);
3095 FR_STATS_TYPE_INC(home->stats.total_requests);
3096 home->last_packet_sent = now.tv_sec;
3097 request->proxy_retransmit = now;
3098 request->proxy_listener->send(request->proxy_listener,
3102 case FR_ACTION_TIMER:
3104 if (!request->proxy_listener ||
3105 (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) {
3106 remove_from_proxy_hash(request);
3108 when = request->packet->timestamp;
3109 when.tv_sec += request->root->max_request_time;
3111 if (timercmp(&when, &now, >)) {
3112 RDEBUG("Waiting for client retransmission in order to do a proxy retransmit");
3113 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3120 * Wake up "response_window" time in the future.
3121 * i.e. when MY packet hasn't received a response.
3123 * Note that we DO NOT mark the home server as
3124 * zombie if it doesn't respond to us. It may be
3125 * responding to other (better looking) packets.
3127 when = request->proxy->timestamp;
3128 when.tv_sec += home->response_window;
3131 * Not at the response window. Set the timer for
3134 if (timercmp(&when, &now, >)) {
3135 RDEBUG("Expecting proxy response no later than %d seconds from now", home->response_window);
3136 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3141 RDEBUG("No proxy response, giving up on request and marking it done");
3144 * If we haven't received any packets for
3145 * "response_window", then mark the home server
3148 * If the connection is TCP, then another
3149 * "watchdog timer" function takes care of pings,
3150 * etc. So we don't need to do it here.
3152 * This check should really be part of a home
3153 * server state machine.
3155 if (((home->state == HOME_STATE_ALIVE) ||
3156 (home->state == HOME_STATE_UNKNOWN)) &&
3158 (home->proto != IPPROTO_TCP) &&
3160 ((home->last_packet_recv + home->response_window) <= now.tv_sec)) {
3161 mark_home_server_zombie(home);
3164 FR_STATS_TYPE_INC(home->stats.total_timeouts);
3165 if (home->type == HOME_TYPE_AUTH) {
3166 if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
3167 FR_STATS_TYPE_INC(proxy_auth_stats.total_timeouts);
3170 else if (home->type == HOME_TYPE_ACCT) {
3171 if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
3172 FR_STATS_TYPE_INC(proxy_acct_stats.total_timeouts);
3177 * There was no response within the window. Stop
3178 * the request. If the client retransmitted, it
3179 * may have failed over to another home server.
3180 * But that one may be dead, too.
3182 RERROR("Failing request - proxy ID %u, due to lack of any response from home server %s port %d",
3184 inet_ntop(request->proxy->dst_ipaddr.af,
3185 &request->proxy->dst_ipaddr.ipaddr,
3186 buffer, sizeof(buffer)),
3187 request->proxy->dst_port);
3189 if (!setup_post_proxy_fail(request)) {
3190 gettimeofday(&request->reply->timestamp, NULL);
3191 request_cleanup_delay_init(request, NULL);
3197 * Duplicate proxy replies have been quenched by
3198 * now. This state is only called ONCE, when we
3199 * receive a new reply from the home server.
3201 case FR_ACTION_PROXY_REPLY:
3202 request_queue_or_run(request, proxy_running);
3205 case FR_ACTION_CONFLICTING:
3206 request_done(request, action);
3210 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
3214 #endif /* WITH_PROXY */
3216 /***********************************************************************
3220 ***********************************************************************/
3222 static int null_handler(UNUSED REQUEST *request)
3228 * See if we need to originate a CoA request.
3230 static void request_coa_originate(REQUEST *request)
3232 int rcode, pre_proxy_type = 0;
3238 rad_assert(request != NULL);
3239 rad_assert(request->coa != NULL);
3240 rad_assert(request->proxy == NULL);
3241 rad_assert(!request->in_proxy_hash);
3242 rad_assert(request->proxy_reply == NULL);
3245 * Check whether we want to originate one, or cancel one.
3247 vp = pairfind(request->config_items, PW_SEND_COA_REQUEST, 0, TAG_ANY);
3249 vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST, 0, TAG_ANY);
3253 if (vp->vp_integer == 0) {
3255 request_done(request->coa, FR_ACTION_DONE);
3263 * src_ipaddr will be set up in proxy_encode.
3265 memset(&ipaddr, 0, sizeof(ipaddr));
3266 vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY);
3268 ipaddr.af = AF_INET;
3269 ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
3271 } else if ((vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY)) != NULL) {
3272 ipaddr.af = AF_INET6;
3273 ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
3275 } else if ((vp = pairfind(coa->proxy->vps, PW_HOME_SERVER_POOL, 0, TAG_ANY)) != NULL) {
3276 coa->home_pool = home_pool_byname(vp->vp_strvalue,
3278 if (!coa->home_pool) {
3279 RWDEBUG2("No such home_server_pool %s",
3285 * Prefer the pool to one server
3287 } else if (request->client->coa_pool) {
3288 coa->home_pool = request->client->coa_pool;
3290 } else if (request->client->coa_server) {
3291 coa->home_server = request->client->coa_server;
3295 * If all else fails, send it to the client that
3296 * originated this request.
3298 memcpy(&ipaddr, &request->packet->src_ipaddr, sizeof(ipaddr));
3302 * Use the pool, if it exists.
3304 if (coa->home_pool) {
3305 coa->home_server = home_server_ldb(NULL, coa->home_pool, coa);
3306 if (!coa->home_server) {
3307 RWDEBUG("No live home server for home_server_pool %s", coa->home_pool->name);
3310 home_server_update_request(coa->home_server, coa);
3312 } else if (!coa->home_server) {
3313 int port = PW_COA_UDP_PORT;
3315 vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
3316 if (vp) port = vp->vp_integer;
3318 coa->home_server = home_server_find(&ipaddr, port, IPPROTO_UDP);
3319 if (!coa->home_server) {
3320 RWDEBUG2("Unknown destination %s:%d for CoA request.",
3321 inet_ntop(ipaddr.af, &ipaddr.ipaddr,
3322 buffer, sizeof(buffer)), port);
3327 vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE, 0, TAG_ANY);
3329 switch (vp->vp_integer) {
3330 case PW_COA_REQUEST:
3331 case PW_DISCONNECT_REQUEST:
3332 coa->proxy->code = vp->vp_integer;
3336 DEBUG("Cannot set CoA Packet-Type to code %d",
3342 if (!coa->proxy->code) coa->proxy->code = PW_COA_REQUEST;
3345 * The rest of the server code assumes that
3346 * request->packet && request->reply exist. Copy them
3347 * from the original request.
3349 rad_assert(coa->packet != NULL);
3350 rad_assert(coa->packet->vps == NULL);
3351 memcpy(coa->packet, request->packet, sizeof(*request->packet));
3352 coa->packet->vps = paircopy(coa->packet, request->packet->vps);
3353 coa->packet->data = NULL;
3354 rad_assert(coa->reply != NULL);
3355 rad_assert(coa->reply->vps == NULL);
3356 memcpy(coa->reply, request->reply, sizeof(*request->reply));
3357 coa->reply->vps = paircopy(coa->reply, request->reply->vps);
3358 coa->reply->data = NULL;
3359 coa->config_items = paircopy(coa, request->config_items);
3360 coa->num_coa_requests = 0;
3361 coa->handle = null_handler;
3362 coa->number = request->number ^ (1 << 24);
3365 * Call the pre-proxy routines.
3367 vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
3369 RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
3370 pre_proxy_type = vp->vp_integer;
3373 if (coa->home_pool && coa->home_pool->virtual_server) {
3374 char const *old_server = coa->server;
3376 coa->server = coa->home_pool->virtual_server;
3377 RDEBUG2(" server %s {", coa->server);
3378 rcode = process_pre_proxy(pre_proxy_type, coa);
3380 coa->server = old_server;
3382 rcode = process_pre_proxy(pre_proxy_type, coa);
3389 * Only send the CoA packet if the pre-proxy code succeeded.
3391 case RLM_MODULE_NOOP:
3393 case RLM_MODULE_UPDATED:
3398 * Source IP / port is set when the proxy socket
3401 coa->proxy->dst_ipaddr = coa->home_server->ipaddr;
3402 coa->proxy->dst_port = coa->home_server->port;
3404 if (!insert_into_proxy_hash(coa)) {
3405 radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list.");
3410 * We CANNOT divorce the CoA request from the parent
3411 * request. This function is running in a child thread,
3412 * and we need access to the main event loop in order to
3413 * to add the timers for the CoA packet.
3415 * Instead, we wait for the timer on the parent request
3418 gettimeofday(&coa->proxy->timestamp, NULL);
3419 coa->packet->timestamp = coa->proxy->timestamp; /* for max_request_time */
3420 coa->delay = 0; /* need to calculate a new delay */
3422 DEBUG_PACKET(coa, coa->proxy, 1);
3424 coa->process = coa_wait_for_reply;
3425 #ifdef DEBUG_STATE_MACHINE
3426 if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n", request->number, __FUNCTION__,
3427 child_state_names[request->child_state],
3428 child_state_names[REQUEST_RUNNING]);
3430 coa->child_state = REQUEST_PROXIED;
3431 rad_assert(coa->proxy_reply == NULL);
3432 FR_STATS_TYPE_INC(coa->home_server->stats.total_requests);
3433 coa->home_server->last_packet_sent = coa->proxy->timestamp.tv_sec;
3434 coa->proxy_listener->send(coa->proxy_listener, coa);
3438 static void coa_timer(REQUEST *request)
3441 struct timeval now, when, mrd;
3443 rad_assert(request->parent == NULL);
3445 if (request->proxy_reply) return request_process_timer(request);
3447 gettimeofday(&now, NULL);
3449 if (request->delay == 0) {
3451 * Implement re-transmit algorithm as per RFC 5080
3454 * We want IRT + RAND*IRT
3455 * or 0.9 IRT + rand(0,.2) IRT
3457 * 2^20 ~ USEC, and we want 2.
3458 * rand(0,0.2) USEC ~ (rand(0,2^21) / 10)
3460 delay = (fr_rand() & ((1 << 22) - 1)) / 10;
3461 request->delay = delay * request->home_server->coa_irt;
3462 delay = request->home_server->coa_irt * USEC;
3463 delay -= delay / 10;
3464 delay += request->delay;
3465 request->delay = delay;
3467 when = request->proxy->timestamp;
3468 tv_add(&when, delay);
3470 if (timercmp(&when, &now, >)) {
3471 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3477 * Retransmit CoA request.
3481 * Cap count at MRC, if it is non-zero.
3483 if (request->home_server->coa_mrc &&
3484 (request->num_coa_requests >= request->home_server->coa_mrc)) {
3485 if (!setup_post_proxy_fail(request)) {
3489 request_queue_or_run(request, coa_running);
3494 * RFC 5080 Section 2.2.1
3496 * RT = 2*RTprev + RAND*RTprev
3497 * = 1.9 * RTprev + rand(0,.2) * RTprev
3498 * = 1.9 * RTprev + rand(0,1) * (RTprev / 5)
3501 delay ^= (delay >> 16);
3503 frac = request->delay / 5;
3504 delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
3506 delay += (2 * request->delay) - (request->delay / 10);
3509 * Cap delay at MRT, if MRT is non-zero.
3511 if (request->home_server->coa_mrt &&
3512 (delay > (request->home_server->coa_mrt * USEC))) {
3513 int mrt_usec = request->home_server->coa_mrt * USEC;
3516 * delay = MRT + RAND * MRT
3517 * = 0.9 MRT + rand(0,.2) * MRT
3520 delay ^= (delay >> 15);
3522 delay = ((mrt_usec >> 16) * delay) + (((mrt_usec & 0xffff) * delay) >> 16);
3523 delay += mrt_usec - (mrt_usec / 10);
3526 request->delay = delay;
3528 tv_add(&when, request->delay);
3529 mrd = request->proxy->timestamp;
3530 mrd.tv_sec += request->home_server->coa_mrd;
3533 * Cap duration at MRD.
3535 if (timercmp(&mrd, &when, <)) {
3538 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3540 request->num_coa_requests++; /* is NOT reset by code 3 lines above! */
3542 FR_STATS_TYPE_INC(request->home_server->stats.total_requests);
3545 * Status servers don't count as real packets sent.
3547 request->proxy_listener->send(request->proxy_listener,
3551 STATE_MACHINE_DECL(coa_wait_for_reply)
3553 rad_assert(request->parent == NULL);
3555 TRACE_STATE_MACHINE;
3558 case FR_ACTION_TIMER:
3560 * This is big enough to be in it's own function.
3565 case FR_ACTION_PROXY_REPLY:
3566 rad_assert(request->parent == NULL);
3567 #ifdef HAVE_PTHREAD_H
3569 * Catch the case of a proxy reply when called
3570 * from the main worker thread.
3572 if (we_are_master()) {
3573 request_queue_or_run(request, coa_running);
3579 request_running(request, action);
3583 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
3588 static void request_coa_separate(REQUEST *request)
3590 #ifdef DEBUG_STATE_MACHINE
3591 int action = FR_ACTION_TIMER;
3593 TRACE_STATE_MACHINE;
3595 rad_assert(request->parent != NULL);
3596 rad_assert(request->parent->coa == request);
3597 rad_assert(request->ev == NULL);
3598 rad_assert(!request->in_request_hash);
3600 rad_assert(request->proxy_listener != NULL);
3601 /* don't talloc_steal request, it will be cleaned up elsewhere */
3602 request->parent->coa = NULL;
3603 request->parent = NULL;
3606 * Should be coa_wait_for_reply()
3608 request->process(request, FR_ACTION_TIMER);
3611 STATE_MACHINE_DECL(coa_running)
3613 TRACE_STATE_MACHINE;
3616 case FR_ACTION_TIMER:
3617 request_process_timer(request);
3620 case FR_ACTION_PROXY_REPLY:
3621 request_common(request, action);
3625 request_running(request, FR_ACTION_PROXY_REPLY);
3629 RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
3633 #endif /* WITH_COA */
3635 /***********************************************************************
3637 * End of the State machine. Start of additional helper code.
3639 ***********************************************************************/
3641 /***********************************************************************
3645 ***********************************************************************/
3646 static void event_socket_handler(UNUSED fr_event_list_t *xel, UNUSED int fd, void *ctx)
3648 rad_listen_t *listener = ctx;
3650 rad_assert(xel == el);
3654 (listener->type != RAD_LISTEN_DETAIL) &&
3656 (listener->fd < 0)) {
3659 listener->print(listener, buffer, sizeof(buffer));
3660 ERROR("FATAL: Asked to read from closed socket: %s",
3663 rad_panic("Socket was closed on us!");
3667 listener->recv(listener);
3672 * This function is called periodically to see if this detail
3673 * file is available for reading.
3675 static void event_poll_detail(void *ctx)
3678 rad_listen_t *this = ctx;
3679 struct timeval when, now;
3680 listen_detail_t *detail = this->data;
3682 rad_assert(this->type == RAD_LISTEN_DETAIL);
3685 event_socket_handler(el, this->fd, this);
3687 fr_event_now(el, &now);
3691 * Backdoor API to get the delay until the next poll
3694 delay = this->encode(this, NULL);
3695 if (delay == 0) goto redo;
3697 tv_add(&when, delay);
3699 if (!fr_event_insert(el, event_poll_detail, this,
3700 &when, &detail->ev)) {
3701 ERROR("Failed creating handler");
3707 static void event_status(struct timeval *wake)
3709 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
3713 if (debug_flag == 0) {
3715 INFO("Ready to process requests.");
3716 just_started = false;
3722 INFO("Ready to process requests.");
3724 } else if ((wake->tv_sec != 0) ||
3725 (wake->tv_usec >= 100000)) {
3726 DEBUG("Waking up in %d.%01u seconds.",
3727 (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
3732 * FIXME: Put this somewhere else, where it isn't called
3733 * all of the time...
3736 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
3738 * If there are no child threads, then there may
3739 * be child processes. In that case, wait for
3740 * their exit status, and throw that exit status
3741 * away. This helps get rid of zxombie children.
3743 while (waitpid(-1, &argval, WNOHANG) > 0) {
3751 static void listener_free_cb(void *ctx)
3753 rad_listen_t *this = ctx;
3756 if (this->count > 0) {
3757 struct timeval when;
3758 listen_socket_t *sock = this->data;
3760 fr_event_now(el, &when);
3763 if (!fr_event_insert(el, listener_free_cb, this, &when,
3765 rad_panic("Failed to insert event");
3772 * It's all free, close the socket.
3775 this->print(this, buffer, sizeof(buffer));
3776 DEBUG("... cleaning up socket %s", buffer);
3782 static int proxy_eol_cb(void *ctx, void *data)
3784 struct timeval when;
3785 REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
3787 if (request->proxy_listener != ctx) return 0;
3790 * We don't care if it's being processed in a child thread.
3793 #ifdef WITH_ACCOUNTING
3795 * Accounting packets should be deleted immediately.
3796 * They will never be retransmitted by the client.
3798 if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
3799 RDEBUG("Stopping request due to failed connection to home server");
3800 request->master_state = REQUEST_STOP_PROCESSING;
3805 * Reset the timer to be now, so that the request is
3806 * quickly updated. But spread the requests randomly
3807 * over the next second, so that we don't overload the
3810 fr_event_now(el, &when);
3811 tv_add(&when, fr_rand() % USEC);
3812 STATE_MACHINE_TIMER(FR_ACTION_TIMER);
3815 * Don't delete it from the list.
3821 int event_new_fd(rad_listen_t *this)
3825 if (this->status == RAD_LISTEN_STATUS_KNOWN) return 1;
3827 this->print(this, buffer, sizeof(buffer));
3829 if (this->status == RAD_LISTEN_STATUS_INIT) {
3830 listen_socket_t *sock = this->data;
3833 DEBUG("Listening on %s", buffer);
3835 INFO(" ... adding new socket %s", buffer);
3840 * Add it to the list of sockets we can use.
3841 * Server sockets (i.e. auth/acct) are never
3842 * added to the packet list.
3844 if (this->type == RAD_LISTEN_PROXY) {
3845 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3846 if (!fr_packet_list_socket_add(proxy_list, this->fd,
3848 &sock->other_ipaddr, sock->other_port,
3851 #ifdef HAVE_PTHREAD_H
3852 proxy_no_new_sockets = true;
3854 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3857 * This is bad. However, the
3858 * packet list now supports 256
3859 * open sockets, which should
3860 * minimize this problem.
3862 ERROR("Failed adding proxy socket: %s",
3868 sock->home->limit.num_connections++;
3870 #ifdef HAVE_PTHREAD_H
3872 * If necessary, add it to the list of
3873 * new proxy listeners.
3875 if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
3876 this->next = proxy_listener_list;
3877 proxy_listener_list = this;
3881 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3884 * Tell the main thread that we've added
3885 * a proxy listener, but only if we need
3886 * to update the event list. Do this
3887 * with the mutex unlocked, to reduce
3891 if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
3892 radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
3900 * Detail files are always known, and aren't
3901 * put into the socket event loop.
3903 if (this->type == RAD_LISTEN_DETAIL) {
3904 this->status = RAD_LISTEN_STATUS_KNOWN;
3907 * Set up the first poll interval.
3909 event_poll_detail(this);
3916 * Add timers to child sockets, if necessary.
3918 if (sock->proto == IPPROTO_TCP && sock->opened &&
3919 (sock->limit.lifetime || sock->limit.idle_timeout)) {
3920 struct timeval when;
3924 when.tv_sec = sock->opened + 1;
3927 if (!fr_event_insert(el, tcp_socket_timer, this, &when,
3929 rad_panic("Failed to insert event");
3934 FD_MUTEX_LOCK(&fd_mutex);
3935 if (!fr_event_fd_insert(el, 0, this->fd,
3936 event_socket_handler, this)) {
3937 ERROR("Failed adding event handler for socket!");
3940 FD_MUTEX_UNLOCK(&fd_mutex);
3942 this->status = RAD_LISTEN_STATUS_KNOWN;
3948 * Stop using this socket, if at all possible.
3950 if (this->status == RAD_LISTEN_STATUS_EOL) {
3952 * Remove it from the list of live FD's.
3954 FD_MUTEX_LOCK(&fd_mutex);
3955 fr_event_fd_delete(el, 0, this->fd);
3956 FD_MUTEX_UNLOCK(&fd_mutex);
3960 * Proxy sockets get frozen, so that we don't use
3961 * them for new requests. But we do keep them
3962 * open to listen for replies to requests we had
3965 if (this->type == RAD_LISTEN_PROXY) {
3966 PTHREAD_MUTEX_LOCK(&proxy_mutex);
3967 if (!fr_packet_list_socket_freeze(proxy_list,
3969 ERROR("Fatal error freezing socket: %s", fr_strerror());
3973 fr_packet_list_walk(proxy_list, this, proxy_eol_cb);
3974 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
3979 * Requests are still using the socket. Wait for
3982 if (this->count > 0) {
3983 struct timeval when;
3984 listen_socket_t *sock = this->data;
3987 * Try again to clean up the socket in 30
3990 gettimeofday(&when, NULL);
3993 if (!fr_event_insert(el,
3994 (fr_event_callback_t) event_new_fd,
3995 this, &when, &sock->ev)) {
3996 rad_panic("Failed to insert event");
4003 * No one is using the socket. We can remove it now.
4005 this->status = RAD_LISTEN_STATUS_REMOVE_NOW;
4006 } /* socket is at EOL */
4012 if (this->status == RAD_LISTEN_STATUS_REMOVE_NOW) {
4015 listen_socket_t *sock = this->data;
4017 struct timeval when;
4020 * Re-open the socket, pointing it to /dev/null.
4021 * This means that all writes proceed without
4022 * blocking, and all reads return "no data".
4024 * This leaves the socket active, so any child
4025 * threads won't go insane. But it means that
4026 * they cannot send or receive any packets.
4028 * This is EXTRA work in the normal case, when
4029 * sockets are closed without error. But it lets
4030 * us have one simple processing method for all
4033 devnull = open("/dev/null", O_RDWR);
4035 ERROR("FATAL failure opening /dev/null: %s",
4036 fr_syserror(errno));
4039 if (dup2(devnull, this->fd) < 0) {
4040 ERROR("FATAL failure closing socket: %s",
4041 fr_syserror(errno));
4047 rad_assert(this->type != RAD_LISTEN_DETAIL);
4051 INFO(" ... shutting down socket %s", buffer);
4055 * The socket is dead. Force all proxied packets
4056 * to stop using it. And then remove it from the
4057 * list of outgoing sockets.
4059 if (this->type == RAD_LISTEN_PROXY) {
4060 PTHREAD_MUTEX_LOCK(&proxy_mutex);
4061 fr_packet_list_walk(proxy_list, this, eol_proxy_listener);
4063 if (!fr_packet_list_socket_del(proxy_list, this->fd)) {
4064 ERROR("Fatal error removing socket %s: %s",
4065 buffer, fr_strerror());
4068 if (sock->home && sock->home->limit.num_connections) {
4069 sock->home->limit.num_connections--;
4071 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
4076 * EOL all requests using this socket.
4078 fr_packet_list_walk(pl, this, eol_listener);
4082 * No child threads, clean it up now.
4085 if (sock->ev) fr_event_delete(el, &sock->ev);
4091 * Wait until all requests using this socket are done.
4093 gettimeofday(&when, NULL);
4096 if (!fr_event_insert(el, listener_free_cb, this, &when,
4098 rad_panic("Failed to insert event");
4101 #endif /* WITH_TCP */
4106 /***********************************************************************
4110 ***********************************************************************/
4112 static void handle_signal_self(int flag)
4114 if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
4115 if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
4116 INFO("Signalled to exit");
4117 fr_event_loop_exit(el, 1);
4119 INFO("Signalled to terminate");
4120 exec_trigger(NULL, NULL, "server.signal.term", true);
4121 fr_event_loop_exit(el, 2);
4125 } /* else exit/term flags weren't set */
4128 * Tell the even loop to stop processing.
4130 if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
4132 static time_t last_hup = 0;
4135 if ((int) (when - last_hup) < 5) {
4136 INFO("Ignoring HUP (less than 5s since last one)");
4140 INFO("Received HUP signal.");
4144 exec_trigger(NULL, NULL, "server.signal.hup", true);
4145 fr_event_loop_exit(el, 0x80);
4149 if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
4153 * FIXME: O(N) loops suck.
4155 for (this = mainconfig.listen;
4157 this = this->next) {
4158 if (this->type != RAD_LISTEN_DETAIL) continue;
4161 * This one didn't send the signal, skip
4164 if (!this->decode(this, NULL)) continue;
4167 * Go service the interrupt.
4169 event_poll_detail(this);
4176 #ifdef HAVE_PTHREAD_H
4178 * Add event handlers for idle timeouts && maximum lifetime.
4180 if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
4181 struct timeval when, now;
4183 fr_event_now(el, &now);
4185 PTHREAD_MUTEX_LOCK(&proxy_mutex);
4187 while (proxy_listener_list) {
4188 rad_listen_t *this = proxy_listener_list;
4189 listen_socket_t *sock = this->data;
4191 rad_assert(sock->proto == IPPROTO_TCP);
4192 proxy_listener_list = this->next;
4195 if (!sock->home) continue; /* skip UDP sockets */
4200 * Sockets should only be added to the
4201 * proxy_listener_list if they have limits.
4204 rad_assert(sock->home->limit.lifetime || sock->home->limit.idle_timeout);
4206 if (!fr_event_insert(el, tcp_socket_timer, this, &when,
4208 rad_panic("Failed to insert event");
4212 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
4214 #endif /* HAVE_PTHREAD_H */
4215 #endif /* WITH_PROXY */
4216 #endif /* WITH_TCP */
4219 #ifndef WITH_SELF_PIPE
4220 void radius_signal_self(int flag)
4222 handle_signal_self(flag);
4226 * Inform ourselves that we received a signal.
4228 void radius_signal_self(int flag)
4234 * The read MUST be non-blocking for this to work.
4236 rcode = read(self_pipe[0], buffer, sizeof(buffer));
4240 for (i = 0; i < rcode; i++) {
4241 buffer[0] |= buffer[i];
4249 write(self_pipe[1], buffer, 1);
4253 static void event_signal_handler(UNUSED fr_event_list_t *xel,
4254 UNUSED int fd, UNUSED void *ctx)
4259 rcode = read(self_pipe[0], buffer, sizeof(buffer));
4260 if (rcode <= 0) return;
4263 * Merge pending signals.
4265 for (i = 0; i < rcode; i++) {
4266 buffer[0] |= buffer[i];
4269 handle_signal_self(buffer[0]);
4273 /***********************************************************************
4275 * Bootstrapping code.
4277 ***********************************************************************/
4280 * Externally-visibly functions.
4282 int radius_event_init(CONF_SECTION *cs, bool have_children)
4284 rad_listen_t *head = NULL;
4288 time(&fr_start_time);
4290 el = fr_event_list_create(NULL, event_status);
4293 pl = fr_packet_list_create(0);
4294 if (!pl) return 0; /* leak el */
4296 request_num_counter = 0;
4299 if (mainconfig.proxy_requests) {
4301 * Create the tree for managing proxied requests and
4304 proxy_list = fr_packet_list_create(1);
4305 if (!proxy_list) return 0;
4307 #ifdef HAVE_PTHREAD_H
4308 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
4309 ERROR("FATAL: Failed to initialize proxy mutex: %s",
4310 fr_syserror(errno));
4318 * Move all of the thread calls to this file?
4320 * It may be best for the mutexes to be in this file...
4322 spawn_flag = have_children;
4324 #ifdef HAVE_PTHREAD_H
4325 NO_SUCH_CHILD_PID = pthread_self(); /* not a child thread */
4328 * Initialize the threads ONLY if we're spawning, AND
4329 * we're running normally.
4331 if (have_children && !check_config &&
4332 (thread_pool_init(cs, &spawn_flag) < 0)) {
4338 DEBUG("%s: #### Skipping IP addresses and Ports ####",
4340 if (listen_init(cs, &head, spawn_flag) < 0) {
4347 #ifdef WITH_SELF_PIPE
4349 * Child threads need a pipe to signal us, as do the
4352 if (pipe(self_pipe) < 0) {
4353 ERROR("radiusd: Error opening internal pipe: %s",
4354 fr_syserror(errno));
4357 if ((fcntl(self_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
4358 (fcntl(self_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
4359 ERROR("radiusd: Error setting internal flags: %s",
4360 fr_syserror(errno));
4363 if ((fcntl(self_pipe[1], F_SETFL, O_NONBLOCK) < 0) ||
4364 (fcntl(self_pipe[1], F_SETFD, FD_CLOEXEC) < 0)) {
4365 ERROR("radiusd: Error setting internal flags: %s",
4366 fr_syserror(errno));
4370 if (!fr_event_fd_insert(el, 0, self_pipe[0],
4371 event_signal_handler, el)) {
4372 ERROR("Failed creating handler for signals");
4375 #endif /* WITH_SELF_PIPE */
4377 DEBUG("%s: #### Opening IP addresses and Ports ####",
4381 * The server temporarily switches to an unprivileged
4382 * user very early in the bootstrapping process.
4383 * However, some sockets MAY require privileged access
4384 * (bind to device, or to port < 1024, or to raw
4385 * sockets). Those sockets need to call suid up/down
4386 * themselves around the functions that need a privileged
4389 if (listen_init(cs, &head, spawn_flag) < 0) {
4393 mainconfig.listen = head;
4396 * At this point, no one has any business *ever* going
4399 fr_suid_down_permanent();
4406 static int proxy_delete_cb(UNUSED void *ctx, void *data)
4408 REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
4410 request->master_state = REQUEST_STOP_PROCESSING;
4413 * Not done, or the child thread is still processing it.
4415 if (request->child_state != REQUEST_DONE) return 0; /* continue */
4417 #ifdef HAVE_PTHREAD_H
4418 if (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0) return 0;
4421 request->in_proxy_hash = false;
4424 * Delete it from the list.
4431 static int request_delete_cb(UNUSED void *ctx, void *data)
4433 REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
4435 request->master_state = REQUEST_STOP_PROCESSING;
4438 * Not done, or the child thread is still processing it.
4440 if (request->child_state < REQUEST_REJECT_DELAY) return 0; /* continue */
4442 #ifdef HAVE_PTHREAD_H
4443 if (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0) return 0;
4447 rad_assert(request->in_proxy_hash == false);
4450 request->in_request_hash = false;
4451 if (request->ev) fr_event_delete(el, &request->ev);
4453 if (mainconfig.memory_report) {
4454 RDEBUG2("Cleaning up request packet ID %u with timestamp +%d",
4455 request->packet->id,
4456 (unsigned int) (request->timestamp - fr_start_time));
4459 request_free(&request);
4462 * Delete it from the list, and continue;
4468 void radius_event_free(void)
4474 * There are requests in the proxy hash that aren't
4475 * referenced from anywhere else. Remove them first.
4478 fr_packet_list_walk(proxy_list, NULL, proxy_delete_cb);
4482 fr_packet_list_walk(pl, NULL, request_delete_cb);
4486 * Now that all requests have been marked "please stop",
4487 * ensure that all of the threads have exited.
4489 #ifdef HAVE_PTHREAD_H
4494 * Walk the lists again, ensuring that all
4495 * requests are done.
4497 if (mainconfig.memory_report) {
4502 fr_packet_list_walk(proxy_list, NULL, proxy_delete_cb);
4503 num = fr_packet_list_num_elements(proxy_list);
4505 ERROR("Proxy list has %d requests still in it.", num);
4510 fr_packet_list_walk(pl, NULL, request_delete_cb);
4511 num = fr_packet_list_num_elements(pl);
4513 ERROR("Request list has %d requests still in it.", num);
4518 fr_packet_list_free(pl);
4522 fr_packet_list_free(proxy_list);
4528 if (debug_condition) talloc_free(debug_condition);
4531 int radius_event_process(void)
4535 return fr_event_loop(el);