+#endif
+
+#ifdef WITH_PROXY
+/*
+ * Send a packet to a home server.
+ *
+ * FIXME: have different code for proxy auth & acct!
+ */
+static int proxy_socket_send(rad_listen_t *listener, REQUEST *request)
+{
+ rad_assert(request->proxy_listener == listener);
+ rad_assert(listener->send == proxy_socket_send);
+
+ return rad_send(request->proxy, request->packet,
+ request->home_server->secret);
+}
+#endif
+
+#ifdef WITH_STATS
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int stats_socket_recv(rad_listen_t *listener,
+ RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+{
+ ssize_t rcode;
+ int code, src_port;
+ RADIUS_PACKET *packet;
+ RADCLIENT *client;
+ fr_ipaddr_t src_ipaddr;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ RAD_STATS_TYPE_INC(listener, total_requests);
+
+ if (rcode < 20) { /* AUTH_HDR_LEN */
+ RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_invalid_requests);
+ return 0;
+ }
+
+ /*
+ * We only understand Status-Server on this socket.
+ */
+ if (code != PW_STATUS_SERVER) {
+ DEBUG("Ignoring packet code %d sent to Status-Server port",
+ code);
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_unknown_types);
+ RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+ return 0;
+ }
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(listener->fd, 1); /* require message authenticator */
+ if (!packet) {
+ RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ DEBUG("%s", fr_strerror());
+ return 0;
+ }
+
+ if (!received_request(listener, packet, prequest, client)) {
+ RAD_STATS_TYPE_INC(listener, total_packets_dropped);
+ RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped);
+ rad_free(&packet);
+ return 0;
+ }
+
+ *pfun = rad_status_server;
+ return 1;
+}
+#endif
+
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int auth_socket_recv(rad_listen_t *listener,
+ RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+{
+ ssize_t rcode;
+ int code, src_port;
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ RADCLIENT *client;
+ fr_ipaddr_t src_ipaddr;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ RAD_STATS_TYPE_INC(listener, total_requests);
+
+ if (rcode < 20) { /* AUTH_HDR_LEN */
+ RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_invalid_requests);
+ return 0;
+ }
+
+ /*
+ * Some sanity checks, based on the packet code.
+ */
+ switch(code) {
+ case PW_AUTHENTICATION_REQUEST:
+ RAD_STATS_CLIENT_INC(listener, client, total_requests);
+ fun = rad_authenticate;
+ break;
+
+ case PW_STATUS_SERVER:
+ if (!mainconfig.status_server) {
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_packets_dropped);
+ RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped);
+ DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
+ return 0;
+ }
+ fun = rad_status_server;
+ break;
+
+ default:
+ rad_recv_discard(listener->fd);
+ RAD_STATS_INC(radius_auth_stats.total_unknown_types);
+ RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+
+ DEBUG("Invalid packet code %d sent to authentication port from client %s port %d : IGNORED",
+ code, client->shortname, src_port);
+ return 0;
+ break;
+ } /* switch over packet types */
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(listener->fd, client->message_authenticator);
+ if (!packet) {
+ RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ DEBUG("%s", fr_strerror());
+ return 0;
+ }
+
+ if (!received_request(listener, packet, prequest, client)) {
+ RAD_STATS_TYPE_INC(listener, total_packets_dropped);
+ RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped);
+ rad_free(&packet);
+ return 0;
+ }
+
+ *pfun = fun;
+ return 1;
+}
+
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Receive packets from an accounting socket
+ */
+static int acct_socket_recv(rad_listen_t *listener,
+ RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+{
+ ssize_t rcode;
+ int code, src_port;
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ RADCLIENT *client;
+ fr_ipaddr_t src_ipaddr;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ RAD_STATS_TYPE_INC(listener, total_requests);
+
+ if (rcode < 20) { /* AUTH_HDR_LEN */
+ RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_invalid_requests);
+ return 0;
+ }
+
+ /*
+ * Some sanity checks, based on the packet code.
+ */
+ switch(code) {
+ case PW_ACCOUNTING_REQUEST:
+ RAD_STATS_CLIENT_INC(listener, client, total_requests);
+ fun = rad_accounting;
+ break;
+
+ case PW_STATUS_SERVER:
+ if (!mainconfig.status_server) {
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_packets_dropped);
+ RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+
+ DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
+ return 0;
+ }
+ fun = rad_status_server;
+ break;
+
+ default:
+ rad_recv_discard(listener->fd);
+ RAD_STATS_TYPE_INC(listener, total_unknown_types);
+ RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+
+ DEBUG("Invalid packet code %d sent to a accounting port from client %s port %d : IGNORED",
+ code, client->shortname, src_port);
+ return 0;
+ } /* switch over packet types */
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(listener->fd, 0);
+ if (!packet) {
+ RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ radlog(L_ERR, "%s", fr_strerror());
+ return 0;
+ }
+
+ /*
+ * There can be no duplicate accounting packets.
+ */
+ if (!received_request(listener, packet, prequest, client)) {
+ RAD_STATS_TYPE_INC(listener, total_packets_dropped);
+ RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped);
+ rad_free(&packet);
+ return 0;
+ }
+
+ *pfun = fun;
+ return 1;
+}
+#endif