2 * listen.c Handle socket stuff
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2005 The FreeRADIUS server project
21 * Copyright 2005 Alan DeKok <aland@ox.org>
24 #include <freeradius-devel/autoconf.h>
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
37 #include <sys/resource.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
47 #ifdef HAVE_SYS_STAT_H
52 #include <freeradius-devel/udpfromto.h>
57 #include <freeradius-devel/radiusd.h>
58 #include <freeradius-devel/rad_assert.h>
59 #include <freeradius-devel/conffile.h>
60 #include <freeradius-devel/token.h>
62 #include <freeradius-devel/radius_snmp.h>
63 #include <freeradius-devel/request_list.h>
65 static time_t start_time = 0;
68 * FIXME: Delete this crap!
70 extern time_t time_now;
73 * We'll use this below.
75 typedef int (*rad_listen_parse_t)(const char *, int, const CONF_SECTION *, rad_listen_t *);
76 typedef void (*rad_listen_free_t)(rad_listen_t *);
78 typedef struct rad_listen_master_t {
79 rad_listen_parse_t parse;
80 rad_listen_free_t free;
81 rad_listen_recv_t recv;
82 rad_listen_send_t send;
83 rad_listen_update_t update;
84 rad_listen_print_t print;
85 } rad_listen_master_t;
87 typedef struct listen_socket_t {
93 RADCLIENT_LIST *clients;
96 typedef struct listen_detail_t {
102 lrad_ipaddr_t client_ip;
109 * Find a per-socket client.
111 static RADCLIENT *client_listener_find(const rad_listen_t *listener,
112 const lrad_ipaddr_t *ipaddr)
114 const RADCLIENT_LIST *clients;
116 rad_assert(listener != NULL);
117 rad_assert(ipaddr != NULL);
119 rad_assert((listener->type == RAD_LISTEN_AUTH) ||
120 (listener->type == RAD_LISTEN_ACCT));
122 clients = ((listen_socket_t *)listener->data)->clients;
123 if (!clients) clients = mainconfig.clients;
125 rad_assert(clients != NULL);
127 return client_find(clients, ipaddr);
130 static int listen_bind(rad_listen_t *this);
133 * FIXME: have the detail reader use another config "exit when done",
134 * so that it can be used as a one-off tool to update stuff.
138 * Process and reply to a server-status request.
139 * Like rad_authenticate and rad_accounting this should
140 * live in it's own file but it's so small we don't bother.
142 static int rad_status_server(REQUEST *request)
149 * Reply with an ACK. We might want to add some more
150 * interesting reply attributes, such as server uptime.
152 t = request->timestamp - start_time;
153 sprintf(reply_msg, "FreeRADIUS up %d day%s, %02d:%02d",
154 (int)(t / 86400), (t / 86400) == 1 ? "" : "s",
155 (int)((t / 3600) % 24), (int)(t / 60) % 60);
156 request->reply->code = PW_AUTHENTICATION_ACK;
158 vp = pairmake("Reply-Message", reply_msg, T_OP_SET);
159 pairadd(&request->reply->vps, vp); /* don't need to check if !vp */
164 static int request_num_counter = 0;
167 * Check for dups, etc. Common to Access-Request &&
168 * Accounting-Request packets.
170 static int common_checks(rad_listen_t *listener,
171 RADIUS_PACKET *packet, REQUEST **prequest,
172 const RADCLIENT *client)
177 rad_assert(listener->rl != NULL);
180 * If there is no existing request of id, code, etc.,
181 * then we can return, and let it be processed.
183 if ((curreq = rl_find(listener->rl, packet)) == NULL) {
185 * Count the total number of requests, to see if
186 * there are too many. If so, return with an
189 if (mainconfig.max_requests) {
191 * FIXME: This is now per-socket,
192 * when it should really be global
195 int request_count = rl_num_requests(listener->rl);
198 * This is a new request. Let's see if
199 * it makes us go over our configured
202 if (request_count > mainconfig.max_requests) {
203 radlog(L_ERR, "Dropping request (%d is too many): "
204 "from client %s port %d - ID: %d", request_count,
206 packet->src_port, packet->id);
207 radlog(L_INFO, "WARNING: Please check the %s file.\n"
208 "\tThe value for 'max_requests' is probably set too low.\n", mainconfig.radiusd_conf);
210 } /* else there were a small number of requests */
211 } /* else there was no configured limit for requests */
214 * FIXME: Add checks for system load. If the
215 * system is busy, start dropping requests...
217 * We can probably keep some statistics
218 * ourselves... if there are more requests
219 * coming in than we can handle, start dropping
224 * The current request isn't finished, which
225 * means that the NAS sent us a new packet, while
226 * we are still processing the old request.
228 } else if (!curreq->finished) {
230 * If the authentication vectors are identical,
231 * then the NAS is re-transmitting it, trying to
232 * kick us into responding to the request.
234 if (memcmp(curreq->packet->vector, packet->vector,
235 sizeof(packet->vector)) == 0) {
236 RAD_SNMP_INC(rad_snmp.auth.total_dup_requests);
239 * It's not finished because the request
240 * was proxied, but there was no reply
241 * from the home server.
243 * This code will never get hit for
244 * accounting packets, as they're always
245 * updated, and never re-transmitted.
247 if (curreq->proxy && !curreq->proxy_reply) {
248 DEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
249 inet_ntop(curreq->proxy->dst_ipaddr.af,
250 &curreq->proxy->dst_ipaddr.ipaddr,
251 buffer, sizeof(buffer)), curreq->proxy->dst_port,
254 listener->send(curreq->proxy_listener, curreq);
256 } /* else the packet was not proxied */
259 * Someone's still working on it, so we
260 * ignore the duplicate request.
262 radlog(L_ERR, "Discarding duplicate request from "
263 "client %s port %d - ID: %d due to unfinished request %d",
265 packet->src_port, packet->id,
268 } /* else the authentication vectors were different */
271 * The authentication vectors are different, so
272 * the NAS has given up on us, as we've taken too
273 * long to process the request. This is a
276 RAD_SNMP_TYPE_INC(listener, total_packets_dropped);
278 radlog(L_ERR, "Dropping conflicting packet from "
279 "client %s port %d - ID: %d due to unfinished request %d",
281 packet->src_port, packet->id,
286 * The old request is finished. We now check the
287 * authentication vectors. If the client has sent us a
288 * request with identical code && ID, but different
289 * vector, then they MUST have gotten our response, so we
290 * can delete the original request, and process the new
293 * If the vectors are the same, then it's a duplicate
294 * request, and we can send a duplicate reply.
296 } else if (memcmp(curreq->packet->vector, packet->vector,
297 sizeof(packet->vector)) == 0) {
298 RAD_SNMP_INC(rad_snmp.auth.total_dup_requests);
301 * If the packet has been delayed, then silently
302 * send a response, and clear the delayed flag.
304 * Note that this means if the NAS kicks us while
305 * we're delaying a reject, then the reject may
306 * be sent sooner than otherwise.
308 * This COULD be construed as a bug. Maybe what
309 * we want to do is to ignore the duplicate
310 * packet, and send the reject later.
312 if (curreq->options & RAD_REQUEST_OPTION_DELAYED_REJECT) {
313 curreq->options &= ~RAD_REQUEST_OPTION_DELAYED_REJECT;
314 rad_assert(curreq->listener == listener);
315 listener->send(listener, curreq);
320 * Maybe we've saved a reply packet. If so,
321 * re-send it. Otherwise, just complain.
323 if (curreq->reply->code != 0) {
324 DEBUG2("Sending duplicate reply "
325 "to client %s port %d - ID: %d",
327 packet->src_port, packet->id);
328 rad_assert(curreq->listener == listener);
329 listener->send(listener, curreq);
334 * Else we never sent a reply to the NAS,
335 * as we decided somehow we didn't like the request.
337 * This shouldn't happen, in general...
339 DEBUG2("Discarding duplicate request from client %s port %d - ID: %d",
340 client->shortname, packet->src_port, packet->id);
342 } /* else the vectors were different, so we discard the old request. */
345 * 'packet' has the same source IP, source port, code,
346 * and Id as 'curreq', but a different authentication
347 * vector. We can therefore delete 'curreq', as we were
348 * only keeping it around to send out duplicate replies,
349 * if the first reply got lost in the network.
352 RADIUS_PACKET *reply = curreq->reply;
354 rl_yank(listener->rl, curreq);
355 rad_free(&curreq->packet);
358 reply = curreq->reply;
359 pairfree(&reply->vps);
361 memset(reply, 0, sizeof(*reply));
363 memset(curreq, 0, sizeof(*curreq));
365 curreq->magic = REQUEST_MAGIC;
367 curreq->timestamp = time(NULL);
368 curreq->child_pid = NO_SUCH_CHILD_PID;
369 curreq->options = RAD_REQUEST_OPTION_NONE;
370 curreq->reply = reply;
373 * A unique per-request counter.
375 curreq = request_alloc(); /* never fails */
377 if ((curreq->reply = rad_alloc(0)) == NULL) {
378 radlog(L_ERR, "No memory");
382 curreq->listener = listener;
383 curreq->packet = packet;
384 curreq->packet->timestamp = curreq->timestamp;
385 curreq->number = request_num_counter++;
386 strNcpy(curreq->secret, client->secret, sizeof(curreq->secret));
389 * Remember the request in the list.
391 if (!rl_add(listener->rl, curreq)) {
392 radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", curreq->number);
393 request_free(&curreq);
398 * ADD IN "server identifier" from "listen"
403 * The request passes many of our sanity checks.
404 * From here on in, if anything goes wrong, we
405 * send a reject message, instead of dropping the
410 * Build the reply template from the request.
413 curreq->reply->sockfd = curreq->packet->sockfd;
414 curreq->reply->dst_ipaddr = curreq->packet->src_ipaddr;
415 curreq->reply->src_ipaddr = curreq->packet->dst_ipaddr;
416 curreq->reply->dst_port = curreq->packet->src_port;
417 curreq->reply->src_port = curreq->packet->dst_port;
418 curreq->reply->id = curreq->packet->id;
419 curreq->reply->code = 0; /* UNKNOWN code */
420 memcpy(curreq->reply->vector, curreq->packet->vector,
421 sizeof(curreq->reply->vector));
422 curreq->reply->vps = NULL;
423 curreq->reply->data = NULL;
424 curreq->reply->data_len = 0;
431 static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
434 listen_socket_t *sock = this->data;
436 if ((sock->ipaddr.af == AF_INET) &&
437 (sock->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) {
440 ip_ntoh(&sock->ipaddr, buffer, bufsize);
443 len = strlen(buffer);
445 return len + snprintf(buffer + len, bufsize - len, " port %d",
451 * Parse an authentication or accounting socket.
453 static int common_socket_parse(const char *filename, int lineno,
454 const CONF_SECTION *cs, rad_listen_t *this)
458 lrad_ipaddr_t ipaddr;
459 listen_socket_t *sock = this->data;
460 const char *section_name = NULL;
461 CONF_SECTION *client_cs;
466 ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
467 rcode = cf_item_parse(cs, "ipaddr", PW_TYPE_IPADDR,
468 &ipaddr.ipaddr.ip4addr, NULL);
469 if (rcode < 0) return -1;
471 if (rcode == 0) { /* successfully parsed IPv4 */
474 } else { /* maybe IPv6? */
475 rcode = cf_item_parse(cs, "ipv6addr", PW_TYPE_IPV6ADDR,
476 &ipaddr.ipaddr.ip6addr, NULL);
477 if (rcode < 0) return -1;
480 radlog(L_ERR, "%s[%d]: No address specified in listen section",
484 ipaddr.af = AF_INET6;
487 rcode = cf_item_parse(cs, "port", PW_TYPE_INTEGER,
489 if (rcode < 0) return -1;
491 sock->ipaddr = ipaddr;
492 sock->port = listen_port;
495 * And bind it to the port.
497 if (listen_bind(this) < 0) {
499 radlog(L_CONS|L_ERR, "%s[%d]: Error binding to port for %s port %d",
500 filename, cf_section_lineno(cs),
501 ip_ntoh(&sock->ipaddr, buffer, sizeof(buffer)),
507 * If we can bind to interfaces, do so,
510 if (cf_pair_find(cs, "interface")) {
511 #ifndef SO_BINDTODEVICE
512 radlog(L_CONS|L_ERR, "%s[%d]: System does not support binding to interfaces, delete this line from the configuration file.",
513 filename, cf_section_lineno(cs));
517 const CONF_PAIR *cp = cf_pair_find(cs, "interface");
520 rad_assert(cp != NULL);
521 value = cf_pair_value(cp);
522 rad_assert(value != NULL);
524 strcpy(ifreq.ifr_name, value);
526 if (setsockopt(this->fd, SOL_SOCKET, SO_BINDTODEVICE,
527 (char *)&ifreq, sizeof(ifreq)) < 0) {
528 radlog(L_CONS|L_ERR, "%s[%d]: Failed binding to interface %s: %s",
529 filename, cf_section_lineno(cs),
530 value, strerror(errno));
532 } /* else it worked. */
537 * Look for the name of a section that holds a list
540 rcode = cf_item_parse(cs, "clients", PW_TYPE_STRING_PTR,
541 §ion_name, NULL);
542 if (rcode < 0) return -1; /* bad string */
543 if (rcode > 0) return 0; /* non-existent is OK. */
545 client_cs = cf_section_find(section_name);
547 radlog(L_CONS|L_ERR, "%s[%d]: Failed to find client section %s",
548 filename, cf_section_lineno(cs), section_name);
552 sock->clients = clients_parse_section(filename, client_cs);
553 if (!sock->clients) {
561 * Send an authentication response packet
563 static int auth_socket_send(rad_listen_t *listener, REQUEST *request)
565 rad_assert(request->listener == listener);
566 rad_assert(listener->send == auth_socket_send);
569 * Ensure that the reply is sane
571 if (request->reply->code == 0) {
572 DEBUG2("There was no response configured: rejecting request %d", request->number);
573 request->reply->code = PW_AUTHENTICATION_REJECT;
577 * If we're delaying authentication rejects, then
578 * mark the request as delayed, and do NOT send a
579 * response right now.
581 * However, if it's already marked as delayed, then
584 if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
585 ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) == 0) &&
586 (mainconfig.reject_delay > 0) &&
587 ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) == 0)) {
588 DEBUG2("Delaying request %d for %d seconds",
589 request->number, mainconfig.reject_delay);
590 request->options |= RAD_REQUEST_OPTION_DELAYED_REJECT;
594 return rad_send(request->reply, request->packet, request->secret);
599 * Send an accounting response packet (or not)
601 static int acct_socket_send(rad_listen_t *listener, REQUEST *request)
603 rad_assert(request->listener == listener);
604 rad_assert(listener->send == acct_socket_send);
607 * Accounting reject's are silently dropped.
609 * We do it here to avoid polluting the rest of the
610 * code with this knowledge
612 if (request->reply->code == 0) return 0;
614 return rad_send(request->reply, request->packet, request->secret);
619 * Send a packet to a home server.
621 * FIXME: have different code for proxy auth & acct!
623 static int proxy_socket_send(rad_listen_t *listener, REQUEST *request)
625 listen_socket_t *sock = listener->data;
627 rad_assert(request->proxy_listener == listener);
628 rad_assert(listener->send == proxy_socket_send);
630 request->proxy->src_ipaddr = sock->ipaddr;
631 request->proxy->src_port = sock->port;
633 return rad_send(request->proxy, request->packet, request->proxysecret);
638 * Check if an incoming request is "ok"
640 * It takes packets, not requests. It sees if the packet looks
641 * OK. If so, it does a number of sanity checks on it.
643 static int auth_socket_recv(rad_listen_t *listener,
644 RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
646 RADIUS_PACKET *packet;
647 RAD_REQUEST_FUNP fun = NULL;
651 packet = rad_recv(listener->fd);
653 radlog(L_ERR, "%s", librad_errstr);
657 RAD_SNMP_TYPE_INC(listener, total_requests); /* FIXME: auth specific */
659 if ((client = client_listener_find(listener,
660 &packet->src_ipaddr)) == NULL) {
661 RAD_SNMP_TYPE_INC(listener, total_invalid_requests);
663 radlog(L_ERR, "Ignoring request from unknown client %s port %d",
664 inet_ntop(packet->src_ipaddr.af,
665 &packet->src_ipaddr.ipaddr,
666 buffer, sizeof(buffer)),
673 * Some sanity checks, based on the packet code.
675 switch(packet->code) {
676 case PW_AUTHENTICATION_REQUEST:
677 fun = rad_authenticate;
680 case PW_STATUS_SERVER:
681 if (!mainconfig.status_server) {
682 DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
686 fun = rad_status_server;
690 RAD_SNMP_INC(rad_snmp.auth.total_unknown_types);
692 radlog(L_ERR, "Invalid packet code %d sent to authentication port from client %s port %d "
694 packet->code, client->shortname,
695 packet->src_port, packet->id);
699 } /* switch over packet types */
701 if (!common_checks(listener, packet, prequest, client)) {
712 * Receive packets from an accounting socket
714 static int acct_socket_recv(rad_listen_t *listener,
715 RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
717 RADIUS_PACKET *packet;
718 RAD_REQUEST_FUNP fun = NULL;
722 packet = rad_recv(listener->fd);
724 radlog(L_ERR, "%s", librad_errstr);
728 RAD_SNMP_TYPE_INC(listener, total_requests); /* FIXME: acct-specific */
730 if ((client = client_listener_find(listener,
731 &packet->src_ipaddr)) == NULL) {
732 RAD_SNMP_TYPE_INC(listener, total_invalid_requests);
734 radlog(L_ERR, "Ignoring request from unknown client %s port %d",
735 inet_ntop(packet->src_ipaddr.af,
736 &packet->src_ipaddr.ipaddr,
737 buffer, sizeof(buffer)),
743 switch(packet->code) {
744 case PW_ACCOUNTING_REQUEST:
745 fun = rad_accounting;
750 * FIXME: Update MIB for packet types?
752 radlog(L_ERR, "Invalid packet code %d sent to a accounting port "
753 "from client %s port %d - ID %d : IGNORED",
754 packet->code, client->shortname,
755 packet->src_port, packet->id);
761 * FIXME: Accounting duplicates should be handled
762 * differently than authentication duplicates.
764 if (!common_checks(listener, packet, prequest, client)) {
775 * Recieve packets from a proxy socket.
777 static int proxy_socket_recv(rad_listen_t *listener,
778 RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
782 RADIUS_PACKET *packet;
783 RAD_REQUEST_FUNP fun = NULL;
786 packet = rad_recv(listener->fd);
788 radlog(L_ERR, "%s", librad_errstr);
795 if (packet->src_ipaddr.af != AF_INET) {
796 rad_assert("PROXY IPV6 NOT SUPPORTED" == NULL);
800 * FIXME: Add support for home servers!
802 if ((cl = realm_findbyaddr(packet->src_ipaddr.ipaddr.ip4addr.s_addr,
803 packet->src_port)) == NULL) {
804 radlog(L_ERR, "Ignoring request from unknown home server %s port %d",
805 inet_ntop(packet->src_ipaddr.af,
806 &packet->src_ipaddr.ipaddr,
807 buffer, sizeof(buffer)),
814 * FIXME: Client MIB updates?
816 switch(packet->code) {
817 case PW_AUTHENTICATION_ACK:
818 case PW_ACCESS_CHALLENGE:
819 case PW_AUTHENTICATION_REJECT:
820 fun = rad_authenticate;
823 case PW_ACCOUNTING_RESPONSE:
824 fun = rad_accounting;
829 * FIXME: Update MIB for packet types?
831 radlog(L_ERR, "Invalid packet code %d sent to a proxy port "
832 "from home server %s port %d - ID %d : IGNORED",
834 ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
835 packet->src_port, packet->id);
841 * Find the original request in the request list
843 oldreq = rl_find_proxy(packet);
846 * If we haven't found the original request which was
847 * sent, to get this reply. Complain, and discard this
848 * request, as there's no way for us to send it to a NAS.
851 radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d",
852 inet_ntop(packet->src_ipaddr.af,
853 &packet->src_ipaddr.ipaddr,
854 buffer, sizeof(buffer)),
855 packet->src_port, packet->id);
861 * The proxy reply has arrived too late, as the original
862 * (old) request has timed out, been rejected, and marked
863 * as finished. The client has already received a
864 * response, so there is nothing that can be done. Delete
865 * the tardy reply from the home server, and return nothing.
867 if ((oldreq->reply->code != 0) ||
868 (oldreq->finished)) {
869 radlog(L_ERR, "Reply from home server %s port %d - ID: %d arrived too late for request %d. Try increasing 'retry_delay' or 'max_request_time'",
870 inet_ntop(packet->src_ipaddr.af,
871 &packet->src_ipaddr.ipaddr,
872 buffer, sizeof(buffer)),
873 packet->src_port, packet->id,
880 * If there is already a reply, maybe this one is a
883 if (oldreq->proxy_reply) {
884 if (memcmp(oldreq->proxy_reply->vector,
886 sizeof(oldreq->proxy_reply->vector)) == 0) {
887 radlog(L_ERR, "Discarding duplicate reply from home server %s port %d - ID: %d for request %d",
888 inet_ntop(packet->src_ipaddr.af,
889 &packet->src_ipaddr.ipaddr,
890 buffer, sizeof(buffer)),
891 packet->src_port, packet->id,
895 * ? The home server gave us a new proxy
896 * reply, which doesn't match the old
899 DEBUG2("Ignoring conflicting proxy reply");
903 * We've already received a reply, so
904 * we discard this one, as we don't want
905 * to do duplicate work.
909 } /* else there wasn't a proxy reply yet, so we can process it */
912 * Refresh the old request, and update it with the proxy
915 * ? Can we delete the proxy request here? * Is there
916 * any more need for it?
918 * FIXME: we probably shouldn't be updating the time
921 oldreq->timestamp = time_now;
922 oldreq->proxy_reply = packet;
925 * FIXME: we should really verify the digest here,
926 * before marking this packet as a valid response.
928 * This is a security problem, I think...
932 * Now that we've verified the packet IS actually from
933 * that home server, and not forged, we can go mark the
934 * entries for this home server as active.
936 * If we had done this check in the 'find realm by IP address'
937 * function, then an attacker could force us to use a home
938 * server which was inactive, by forging reply packets
939 * which didn't match any request. We would think that
940 * the reply meant the home server was active, would
941 * re-activate the realms, and THEN bounce the packet
944 for (cl = mainconfig.realms; cl != NULL; cl = cl->next) {
945 if (oldreq->proxy_reply->src_ipaddr.af != cl->ipaddr.af) continue;
946 if (cl->ipaddr.af != AF_INET) continue; /* FIXME */
948 if (oldreq->proxy_reply->src_ipaddr.ipaddr.ip4addr.s_addr == cl->ipaddr.ipaddr.ip4addr.s_addr) {
949 if (oldreq->proxy_reply->src_port == cl->auth_port) {
951 cl->last_reply = oldreq->timestamp;
952 } else if (oldreq->proxy_reply->src_port == cl->acct_port) {
953 cl->acct_active = TRUE;
954 cl->last_reply = oldreq->timestamp;
959 rad_assert(fun != NULL);
966 #define STATE_UNOPENED (0)
967 #define STATE_UNLOCKED (1)
968 #define STATE_HEADER (2)
969 #define STATE_READING (3)
970 #define STATE_DONE (4)
971 #define STATE_WAITING (5)
974 * If we're limiting outstanding packets, then mark the response
977 static int detail_send(rad_listen_t *listener, REQUEST *request)
979 listen_detail_t *data = listener->data;
981 rad_assert(request->listener == listener);
982 rad_assert(listener->send == detail_send);
984 if (request->simul_max >= 0) {
985 rad_assert(data->outstanding != NULL);
986 rad_assert(request->simul_max < data->max_outstanding);
988 data->outstanding[request->simul_max] = 0;
996 * Open the detail file..
998 * FIXME: create it, if it's not already there, so that the main
999 * server select() will wake us up if there's anything to read.
1001 static int detail_open(rad_listen_t *this)
1005 listen_detail_t *data = this->data;
1007 rad_assert(data->state == STATE_UNOPENED);
1008 snprintf(buffer, sizeof(buffer), "%s.work", data->detail);
1011 * FIXME: Have "one-shot" configuration, where it
1012 * will read the detail file, and exit once it's
1015 * FIXME: Try harder to open the detail file.
1016 * Maybe sleep for X usecs if it doesn't exist?
1020 * Open detail.work first, so we don't lose
1021 * accounting packets. It's probably better to
1022 * duplicate them than to lose them.
1024 * Note that we're not writing to the file, but
1025 * we've got to open it for writing in order to
1026 * establish the lock, to prevent rlm_detail from
1029 this->fd = open(buffer, O_RDWR);
1032 * Try reading the detail file. If it
1033 * doesn't exist, we can't do anything.
1035 * Doing the stat will tell us if the file
1036 * exists, even if we don't have permissions
1039 if (stat(data->detail, &st) < 0) {
1044 * Open it BEFORE we rename it, just to
1047 this->fd = open(data->detail, O_RDWR);
1049 radlog(L_ERR, "Failed to open %s: %s",
1050 data->detail, strerror(errno));
1055 * Rename detail to detail.work
1057 if (rename(data->detail, buffer) < 0) {
1062 } /* else detail.work existed, and we opened it */
1064 rad_assert(data->vps == NULL);
1066 rad_assert(data->fp == NULL);
1067 data->fp = fdopen(this->fd, "r");
1069 radlog(L_ERR, "Failed to re-open %s: %s",
1070 data->detail, strerror(errno));
1074 data->state = STATE_UNLOCKED;
1076 data->client_ip.af = AF_UNSPEC;
1077 data->timestamp = 0;
1083 * This is a bad hack, just so complaints have meaningful text.
1085 static const RADCLIENT detail_client = {
1100 static int detail_recv(rad_listen_t *listener,
1101 RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
1104 char key[256], value[1024];
1105 VALUE_PAIR *vp, **tail;
1106 RADIUS_PACKET *packet;
1108 listen_detail_t *data = listener->data;
1110 if (data->state == STATE_UNOPENED) {
1111 rad_assert(listener->fd < 0);
1112 if (!detail_open(listener)) return 0;
1114 rad_assert(listener->fd >= 0);
1117 * Try to lock fd. If we can't, return. If we can,
1118 * continue. This means that the server doesn't block
1119 * while waiting for the lock to open...
1121 if (data->state == STATE_UNLOCKED) {
1123 * Note that we do NOT block waiting for the
1124 * lock. We've re-named the file above, so we've
1125 * already guaranteed that any *new* detail
1126 * writer will not be opening this file. The
1127 * only purpose of the lock is to catch a race
1128 * condition where the execution "ping-pongs"
1129 * between radiusd & radrelay.
1131 if (rad_lockfd_nonblock(listener->fd, 0) < 0) {
1135 * Look for the header
1137 data->state = STATE_HEADER;
1141 * If we keep track of the outstanding requests, do so
1142 * here. Note that to minimize potential work, we do
1143 * so only once the file is opened & locked.
1145 if (data->max_outstanding) {
1148 for (i = 0; i < data->max_outstanding; i++) {
1149 if (!data->outstanding[i]) {
1156 * All of the slots are full, don't read data.
1158 if (free_slot < 0) return 0;
1162 * Catch an out of memory condition which will most likely
1165 if (data->state == STATE_DONE) goto alloc_packet;
1168 * If we're in another state, then it means that we read
1169 * a partial packet, which is bad.
1171 rad_assert(data->state == STATE_HEADER);
1172 rad_assert(data->vps == NULL);
1175 * We read the last packet, and returned it for
1176 * processing. We later come back here to shut
1177 * everything down, and unlink the file.
1179 if (feof(data->fp)) {
1180 rad_assert(data->state == STATE_HEADER);
1183 * Don't unlink the file until we've received
1184 * all of the responses.
1186 if (data->max_outstanding > 0) {
1189 for (i = 0; i < data->max_outstanding; i++) {
1191 * FIXME: close the file?
1193 if (data->outstanding[i]) {
1194 data->state = STATE_WAITING;
1201 rad_assert(data->vps == NULL);
1203 snprintf(buffer, sizeof(buffer), "%s.work", data->detail);
1205 fclose(data->fp); /* closes listener->fd */
1208 data->state = STATE_UNOPENED;
1211 * Try to open "detail" again. If we're on a
1212 * busy RADIUS server, odds are that it will
1215 detail_open(listener);
1222 * Fill the buffer...
1224 while (fgets(buffer, sizeof(buffer), data->fp)) {
1228 if (!strchr(buffer, '\n')) {
1229 pairfree(&data->vps);
1234 * We've read a header, possibly packet contents,
1235 * and are now at the end of the packet.
1237 if ((data->state == STATE_READING) &&
1238 (buffer[0] == '\n')) {
1239 data->state = STATE_DONE;
1244 * Look for date/time header, and read VP's if
1245 * found. If not, keep reading lines until we
1248 if (data->state == STATE_HEADER) {
1251 if (sscanf(buffer, "%*s %*s %*d %*d:%*d:%*d %d", &y)) {
1252 data->state = STATE_READING;
1258 * We have a full "attribute = value" line.
1259 * If it doesn't look reasonable, skip it.
1261 if (sscanf(buffer, "%255s = %1023s", key, value) != 2) {
1266 * Skip non-protocol attributes.
1268 if (!strcasecmp(key, "Request-Authenticator")) continue;
1271 * Set the original client IP address, based on
1272 * what's in the detail file.
1274 * Hmm... we don't set the server IP address.
1277 if (!strcasecmp(key, "Client-IP-Address")) {
1278 data->client_ip.af = AF_INET;
1279 ip_hton(value, AF_INET, &data->client_ip);
1284 * The original time at which we received the
1285 * packet. We need this to properly calculate
1288 if (!strcasecmp(key, "Timestamp")) {
1289 data->timestamp = atoi(value);
1296 * FIXME: do we want to check for non-protocol
1297 * attributes like radsqlrelay does?
1300 if ((userparse(buffer, &vp) > 0) &&
1308 * We got to EOF, If we're in STATE_HEADER, it's OK.
1309 * Otherwise it's a problem. In any case, nuke the file
1310 * and start over from scratch,
1312 if (feof(data->fp)) {
1317 * FIXME: Do load management.
1321 * If we're not done, then there's a problem. The checks
1324 rad_assert(data->state == STATE_DONE);
1327 * The packet we read was empty, re-set the state to look
1328 * for a header, and don't return anything.
1331 data->state = STATE_HEADER;
1336 * Allocate the packet. If we fail, it's a serious
1340 packet = rad_alloc(1);
1342 return 0; /* maybe memory will magically free up... */
1345 memset(packet, 0, sizeof(*packet));
1346 packet->sockfd = -1;
1347 packet->src_ipaddr.af = AF_INET;
1348 packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
1349 packet->code = PW_ACCOUNTING_REQUEST;
1350 packet->timestamp = time(NULL);
1353 * Look for Acct-Delay-Time, and update
1354 * based on Acct-Delay-Time += (time(NULL) - timestamp)
1356 vp = pairfind(packet->vps, PW_ACCT_DELAY_TIME);
1358 vp = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER);
1359 rad_assert(vp != NULL);
1361 if (data->timestamp != 0) {
1362 vp->lvalue += time(NULL) - data->timestamp;
1366 * Remember where it came from, so that we don't
1367 * proxy it to the place it came from...
1369 if (data->client_ip.af != AF_UNSPEC) {
1370 packet->src_ipaddr = data->client_ip;
1374 * We've got to give SOME value for Id & ports, so that
1375 * the packets can be added to the request queue.
1376 * However, we don't want to keep track of used/unused
1377 * id's and ports, as that's a lot of work. This hack
1378 * ensures that (if we have real random numbers), that
1379 * there will be a collision on every (2^(16+16+2+24))/2
1380 * packets, on average. That means we can read 2^32 (4G)
1381 * packets before having a collision, which means it's
1382 * effectively impossible. Having 4G packets currently
1383 * being process is ridiculous.
1385 packet->id = lrad_rand() & 0xff;
1386 packet->src_port = lrad_rand() & 0xffff;
1387 packet->dst_port = lrad_rand() & 0xffff;
1389 packet->dst_ipaddr.af = AF_INET;
1390 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl((INADDR_LOOPBACK & ~0xffffff) | (lrad_rand() & 0xffffff));
1392 packet->vps = data->vps;
1398 data->state = STATE_HEADER;
1401 * FIXME: many of these checks may not be necessary...
1403 if (!common_checks(listener, packet, prequest, &detail_client)) {
1409 * Keep track of free slots, as a hack, in an otherwise
1412 (*prequest)->simul_max = free_slot;
1413 if (free_slot) data->outstanding[free_slot] = 1;
1415 *pfun = rad_accounting;
1418 printf("detail_recv: Read packet from %s\n", data->detail);
1419 for (vp = packet->vps; vp; vp = vp->next) {
1421 vp_print(stdout, vp);
1431 * Free detail-specific stuff.
1433 static void detail_free(rad_listen_t *this)
1435 listen_detail_t *data = this->data;
1438 pairfree(&data->vps);
1439 free(data->outstanding);
1441 if (data->fp != NULL) fclose(data->fp);
1445 static int detail_print(rad_listen_t *this, char *buffer, size_t bufsize)
1447 return snprintf(buffer, bufsize, "%s",
1448 ((listen_detail_t *)(this->data))->detail);
1452 static const CONF_PARSER detail_config[] = {
1453 { "detail", PW_TYPE_STRING_PTR,
1454 offsetof(listen_detail_t, detail), NULL, NULL },
1455 { "max_outstanding", PW_TYPE_INTEGER,
1456 offsetof(listen_detail_t, max_outstanding), NULL, "100" },
1458 { NULL, -1, 0, NULL, NULL } /* end the list */
1463 * Parse a detail section.
1465 static int detail_parse(const char *filename, int lineno,
1466 const CONF_SECTION *cs, rad_listen_t *this)
1469 listen_detail_t *data;
1473 rcode = cf_section_parse(cs, data, detail_config);
1475 radlog(L_ERR, "%s[%d]: Failed parsing listen section",
1480 if (!data->detail) {
1481 radlog(L_ERR, "%s[%d]: No detail file specified in listen section",
1488 data->state = STATE_UNOPENED;
1490 if (data->max_outstanding > 32768) data->max_outstanding = 32768;
1492 if (data->max_outstanding > 0) {
1493 data->outstanding = rad_malloc(sizeof(int) * data->max_outstanding);
1503 * See radiusd.c & request_list.c
1505 #define SLEEP_FOREVER (65536)
1507 * A generic "update the request list once a second" function.
1509 static int generic_update(rad_listen_t *this, time_t now)
1511 if (!this->rl) return SLEEP_FOREVER;
1513 return rl_clean_list(this->rl, now);
1518 static const rad_listen_master_t master_listen[RAD_LISTEN_MAX] = {
1519 { NULL, NULL, NULL, NULL, NULL, NULL}, /* RAD_LISTEN_NONE */
1521 /* authentication */
1522 { common_socket_parse, NULL,
1523 auth_socket_recv, auth_socket_send,
1524 generic_update, socket_print },
1527 { common_socket_parse, NULL,
1528 acct_socket_recv, acct_socket_send,
1529 generic_update, socket_print},
1533 proxy_socket_recv, proxy_socket_send,
1534 generic_update, socket_print }, /* FIXME: update func is wrong! */
1537 { detail_parse, detail_free,
1538 detail_recv, detail_send,
1539 generic_update, detail_print }
1544 * Binds a listener to a socket.
1546 static int listen_bind(rad_listen_t *this)
1548 struct sockaddr salocal;
1550 rad_listen_t **last;
1551 listen_socket_t *sock = this->data;
1554 * If the port is zero, then it means the appropriate
1555 * thing from /etc/services.
1557 if (sock->port == 0) {
1558 struct servent *svp;
1560 switch (this->type) {
1561 case RAD_LISTEN_AUTH:
1562 svp = getservbyname ("radius", "udp");
1564 sock->port = ntohs(svp->s_port);
1566 sock->port = PW_AUTH_UDP_PORT;
1570 case RAD_LISTEN_ACCT:
1571 svp = getservbyname ("radacct", "udp");
1573 sock->port = ntohs(svp->s_port);
1575 sock->port = PW_ACCT_UDP_PORT;
1580 radlog(L_ERR|L_CONS, "ERROR: Non-fatal internal sanity check failed in bind.");
1586 * Find it in the old list, AFTER updating the port. If
1587 * it's there, use that, rather than creating a new
1588 * socket. This allows HUP's to re-use the old sockets,
1589 * which means that packets waiting in the socket queue
1592 for (last = &mainconfig.listen;
1594 last = &((*last)->next)) {
1595 if ((this->type == (*last)->type) &&
1596 (sock->port == ((listen_socket_t *)((*last)->data))->port) &&
1597 (sock->ipaddr.af == ((listen_socket_t *)((*last)->data))->ipaddr.af)) {
1600 if (sock->ipaddr.af == AF_INET) {
1601 equal = (sock->ipaddr.ipaddr.ip4addr.s_addr == ((listen_socket_t *)((*last)->data))->ipaddr.ipaddr.ip4addr.s_addr);
1602 } else if (sock->ipaddr.af == AF_INET6) {
1603 equal = IN6_ARE_ADDR_EQUAL(&(sock->ipaddr.ipaddr.ip6addr), &(((listen_socket_t *)((*last)->data))->ipaddr.ipaddr.ip6addr));
1609 this->rl = (*last)->rl;
1610 this->fd = (*last)->fd;
1619 * Create the socket.
1621 this->fd = socket(sock->ipaddr.af, SOCK_DGRAM, 0);
1623 radlog(L_ERR|L_CONS, "ERROR: Failed to open socket: %s",
1629 #ifdef WITH_UDPFROMTO
1631 * Initialize udpfromto for all sockets.
1633 if (udpfromto_init(this->fd) != 0) {
1634 radlog(L_ERR|L_CONS, "ERROR: udpfromto init failed.");
1638 if (sock->ipaddr.af == AF_INET) {
1639 struct sockaddr_in *sa;
1641 sa = (struct sockaddr_in *) &salocal;
1642 memset(sa, 0, sizeof(salocal));
1643 sa->sin_family = AF_INET;
1644 sa->sin_addr = sock->ipaddr.ipaddr.ip4addr;
1645 sa->sin_port = htons(sock->port);
1646 salen = sizeof(*sa);
1648 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1649 } else if (sock->ipaddr.af == AF_INET6) {
1650 struct sockaddr_in6 *sa;
1652 sa = (struct sockaddr_in6 *) &salocal;
1653 memset(sa, 0, sizeof(salocal));
1654 sa->sin6_family = AF_INET6;
1655 sa->sin6_addr = sock->ipaddr.ipaddr.ip6addr;
1656 sa->sin6_port = htons(sock->port);
1657 salen = sizeof(*sa);
1660 * Listening on '::' does NOT get you IPv4 to
1661 * IPv6 mapping. You've got to listen on an IPv4
1662 * address, too. This makes the rest of the server
1663 * design a little simpler.
1666 if (IN6_IS_ADDR_UNSPECIFIED(&sock->ipaddr.ipaddr.ip6addr)) {
1669 setsockopt(this->fd, IPPROTO_IPV6, IPV6_V6ONLY,
1670 (char *)&on, sizeof(on));
1672 #endif /* IPV6_V6ONLY */
1673 #endif /* HAVE_STRUCT_SOCKADDR_IN6 */
1675 radlog(L_ERR|L_CONS, "ERROR: Unsupported protocol family %d",
1682 if (bind(this->fd, &salocal, salen) < 0) {
1685 radlog(L_ERR|L_CONS, "ERROR: Bind to %s port %d failed: %s",
1686 inet_ntop(sock->ipaddr.af, &sock->ipaddr.ipaddr,
1687 buffer, sizeof(buffer)),
1688 sock->port, strerror(errno));
1700 * Allocate & initialize a new listener.
1702 static rad_listen_t *listen_alloc(RAD_LISTEN_TYPE type)
1706 this = rad_malloc(sizeof(*this));
1707 memset(this, 0, sizeof(*this));
1710 this->recv = master_listen[this->type].recv;
1711 this->send = master_listen[this->type].send;
1712 this->update = master_listen[this->type].update;
1713 this->print = master_listen[this->type].print;
1716 case RAD_LISTEN_AUTH:
1717 case RAD_LISTEN_ACCT:
1718 case RAD_LISTEN_PROXY:
1719 this->data = rad_malloc(sizeof(listen_socket_t));
1720 memset(this->data, 0, sizeof(listen_socket_t));
1723 case RAD_LISTEN_DETAIL:
1724 this->data = rad_malloc(sizeof(listen_detail_t));
1725 memset(this->data, 0, sizeof(listen_detail_t));
1736 * Externally visible function for creating a new proxy LISTENER.
1738 * For now, don't take ipaddr or port.
1740 * Not thread-safe, but all calls to it are protected by the
1741 * proxy mutex in request_list.c
1743 rad_listen_t *proxy_new_listener()
1745 int last_proxy_port, port;
1746 rad_listen_t *this, *tmp, **last;
1747 listen_socket_t *sock, *old;
1749 this = listen_alloc(RAD_LISTEN_PROXY);
1752 * Find an existing proxy socket to copy.
1754 * FIXME: Make it per-realm, or per-home server!
1756 last_proxy_port = 0;
1758 last = &mainconfig.listen;
1759 for (tmp = mainconfig.listen; tmp != NULL; tmp = tmp->next) {
1760 if (tmp->type == RAD_LISTEN_PROXY) {
1762 if (sock->port > last_proxy_port) {
1763 last_proxy_port = sock->port + 1;
1765 if (!old) old = sock;
1768 last = &(tmp->next);
1771 if (!old) return NULL; /* This is a serious error. */
1774 * FIXME: find a new IP address to listen on?
1777 memcpy(&sock->ipaddr, &old->ipaddr, sizeof(sock->ipaddr));
1780 * Keep going until we find an unused port.
1782 for (port = last_proxy_port; port < 64000; port++) {
1784 if (listen_bind(this) == 0) {
1786 * Add the new listener to the list of
1798 static const LRAD_NAME_NUMBER listen_compare[] = {
1799 { "auth", RAD_LISTEN_AUTH },
1800 { "acct", RAD_LISTEN_ACCT },
1801 { "detail", RAD_LISTEN_DETAIL },
1807 * Generate a list of listeners. Takes an input list of
1808 * listeners, too, so we don't close sockets with waiting packets.
1810 int listen_init(const char *filename, rad_listen_t **head)
1814 rad_listen_t **last;
1816 lrad_ipaddr_t server_ipaddr;
1820 * We shouldn't be called with a pre-existing list.
1822 rad_assert(head && (*head == NULL));
1824 if (start_time != 0) start_time = time(NULL);
1827 server_ipaddr.af = AF_UNSPEC;
1830 * If the port is specified on the command-line,
1831 * it over-rides the configuration file.
1833 if (mainconfig.port >= 0) {
1834 auth_port = mainconfig.port;
1836 rcode = cf_item_parse(mainconfig.config, "port",
1837 PW_TYPE_INTEGER, &auth_port,
1838 Stringify(PW_AUTH_UDP_PORT));
1839 if (rcode < 0) return -1; /* error parsing it */
1842 radlog(L_INFO, "WARNING: The directive 'port' is deprecated, and will be removed in future versions of FreeRADIUS. Please edit the configuration files to use the directive 'listen'.");
1846 * If the IP address was configured on the command-line,
1847 * use that as the "bind_address"
1849 if (mainconfig.myip.af != AF_UNSPEC) {
1850 memcpy(&server_ipaddr, &mainconfig.myip,
1851 sizeof(server_ipaddr));
1856 * Else look for bind_address and/or listen sections.
1858 server_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
1859 rcode = cf_item_parse(mainconfig.config, "bind_address",
1861 &server_ipaddr.ipaddr.ip4addr, NULL);
1862 if (rcode < 0) return -1; /* error parsing it */
1864 if (rcode == 0) { /* successfully parsed IPv4 */
1865 listen_socket_t *sock;
1866 server_ipaddr.af = AF_INET;
1868 radlog(L_INFO, "WARNING: The directive 'bind_adress' is deprecated, and will be removed in future versions of FreeRADIUS. Please edit the configuration files to use the directive 'listen'.");
1871 this = listen_alloc(RAD_LISTEN_AUTH);
1874 sock->ipaddr = server_ipaddr;
1875 sock->port = auth_port;
1877 if (listen_bind(this) < 0) {
1880 radlog(L_CONS|L_ERR, "There appears to be another RADIUS server running on the authentication port %d", sock->port);
1883 auth_port = sock->port; /* may have been updated in listen_bind */
1885 last = &(this->next);
1888 * Open Accounting Socket.
1890 * If we haven't already gotten acct_port from
1891 * /etc/services, then make it auth_port + 1.
1893 this = listen_alloc(RAD_LISTEN_ACCT);
1897 * Create the accounting socket.
1899 * The accounting port is always the
1900 * authentication port + 1
1902 sock->ipaddr = server_ipaddr;
1903 sock->port = auth_port + 1;
1905 if (listen_bind(this) < 0) {
1908 radlog(L_CONS|L_ERR, "There appears to be another RADIUS server running on the accounting port %d", sock->port);
1913 last = &(this->next);
1915 } else if (mainconfig.port > 0) { /* no bind address, but a port */
1916 radlog(L_CONS|L_ERR, "The command-line says \"-p %d\", but there is no associated IP address to use",
1922 * They specified an IP on the command-line, ignore
1923 * all listen sections.
1925 if (mainconfig.myip.af != AF_UNSPEC) goto do_proxy;
1928 * Walk through the "listen" sections, if they exist.
1930 for (cs = cf_subsection_find_next(mainconfig.config, NULL, "listen");
1932 cs = cf_subsection_find_next(mainconfig.config, cs, "listen")) {
1934 char *listen_type, *identity;
1935 int lineno = cf_section_lineno(cs);
1937 listen_type = identity = NULL;
1939 rcode = cf_item_parse(cs, "type", PW_TYPE_STRING_PTR,
1941 if (rcode < 0) return -1;
1945 radlog(L_ERR, "%s[%d]: No type specified in listen section",
1951 * See if there's an identity.
1953 rcode = cf_item_parse(cs, "identity", PW_TYPE_STRING_PTR,
1961 type = lrad_str2int(listen_compare, listen_type,
1964 if (type == RAD_LISTEN_NONE) {
1966 radlog(L_CONS|L_ERR, "%s[%d]: Invalid type in listen section.",
1972 * Set up cross-type data.
1974 this = listen_alloc(type);
1975 this->identity = identity;
1979 * Call per-type parser.
1981 if (master_listen[type].parse(filename, lineno,
1989 last = &(this->next);
1993 * If we're proxying requests, open the proxy FD.
1994 * Otherwise, don't do anything.
1997 if (mainconfig.proxy_requests == TRUE) {
1999 listen_socket_t *sock = NULL;
2002 * No sockets to receive packets, therefore
2003 * proxying is pointless.
2005 if (!*head) return -1;
2008 * If we previously had proxy sockets, copy them
2009 * to the new config.
2011 if (mainconfig.listen != NULL) {
2012 rad_listen_t *old, *next, **tail;
2014 tail = &mainconfig.listen;
2015 for (old = mainconfig.listen;
2020 if (old->type != RAD_LISTEN_PROXY) {
2021 tail = &((*tail)->next);
2028 last = &(old->next);
2035 * Find the first authentication port,
2038 for (this = *head; this != NULL; this = this->next) {
2039 if (this->type == RAD_LISTEN_AUTH) {
2041 if (server_ipaddr.af == AF_UNSPEC) {
2042 server_ipaddr = sock->ipaddr;
2044 port = sock->port + 2; /* skip acct port */
2048 rad_assert(port > 0); /* must have found at least one entry! */
2051 * Address is still unspecified, use IPv4.
2053 if (server_ipaddr.af == AF_UNSPEC) {
2054 server_ipaddr.af = AF_INET;
2055 server_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
2058 this = listen_alloc(RAD_LISTEN_PROXY);
2062 * Create the first proxy socket.
2064 sock->ipaddr = server_ipaddr;
2067 * Try to find a proxy port (value doesn't matter)
2069 for (sock->port = port;
2072 if (listen_bind(this) == 0) {
2074 last = &(this->next); /* just in case */
2079 if (sock->port >= 64000) {
2082 radlog(L_ERR|L_CONS, "Failed to open socket for proxying");
2088 * Sanity check the configuration.
2091 for (this = *head; this != NULL; this = this->next) {
2092 if ((this->type != RAD_LISTEN_PROXY) &&
2095 * FIXME: Pass type to rl_init, so that
2096 * it knows how to deal with accounting
2097 * packets. i.e. it caches them, but
2098 * doesn't bother trying to re-transmit.
2100 this->rl = rl_init();
2102 rad_assert(0 == 1); /* FIXME: */
2106 if (((this->type == RAD_LISTEN_ACCT) &&
2107 (rcode == RAD_LISTEN_DETAIL)) ||
2108 ((this->type == RAD_LISTEN_DETAIL) &&
2109 (rcode == RAD_LISTEN_ACCT))) {
2110 rad_assert(0 == 1); /* FIXME: configuration error */
2113 if (rcode != 0) continue;
2115 if ((this->type == RAD_LISTEN_ACCT) ||
2116 (this->type == RAD_LISTEN_DETAIL)) {
2126 * Free a linked list of listeners;
2128 void listen_free(rad_listen_t **head)
2132 if (!head || !*head) return;
2136 rad_listen_t *next = this->next;
2138 free(this->identity);
2140 rl_deinit(this->rl);
2143 * Other code may have eaten the FD.
2145 if (this->fd >= 0) close(this->fd);
2147 if (master_listen[this->type].free) {
2148 master_listen[this->type].free(this);