#include <freeradius-devel/rad_assert.h>
#include <freeradius-devel/vqp.h>
#include <freeradius-devel/dhcp.h>
+#include <freeradius-devel/process.h>
#include <freeradius-devel/vmps.h>
#include <freeradius-devel/detail.h>
#endif
-void print_packet(RADIUS_PACKET *packet)
+static void print_packet(RADIUS_PACKET *packet)
{
char src[256], dst[256];
static rad_listen_t *listen_alloc(RAD_LISTEN_TYPE type);
/*
+ * Xlat for %{listen:foo}
+ */
+static size_t xlat_listen(UNUSED void *instance, REQUEST *request,
+ char *fmt, char *out,
+ size_t outlen,
+ UNUSED RADIUS_ESCAPE_STRING func)
+{
+ const char *value = NULL;
+ CONF_PAIR *cp;
+
+ if (!fmt || !out || (outlen < 1)) return 0;
+
+ if (!request || !request->listener) {
+ *out = '\0';
+ return 0;
+ }
+
+ cp = cf_pair_find(request->listener->cs, fmt);
+ if (!cp || !(value = cf_pair_value(cp))) {
+ *out = '\0';
+ return 0;
+ }
+
+ strlcpy(out, value, outlen);
+
+ return strlen(out);
+}
+
+/*
* Find a per-socket client.
*/
-RADCLIENT *client_listener_find(const rad_listen_t *listener,
+RADCLIENT *client_listener_find(rad_listen_t *listener,
const fr_ipaddr_t *ipaddr, int src_port)
{
#ifdef WITH_DYNAMIC_CLIENTS
request_free(&request);
goto unknown;
}
- request->packet->timestamp = request->timestamp;
+ gettimeofday(&request->packet->timestamp, NULL);
request->number = 0;
request->priority = listener->type;
request->server = client->client_server;
*/
if (!client_validate(clients, client, created)) goto unknown;
}
+
+ request->server = client->server;
+ exec_trigger(request, NULL, "server.client.add");
+
request_free(&request);
if (!created) goto unknown;
* Like rad_authenticate and rad_accounting this should
* live in it's own file but it's so small we don't bother.
*/
-static int rad_status_server(REQUEST *request)
+int rad_status_server(REQUEST *request)
{
int rcode = RLM_MODULE_OK;
DICT_VALUE *dval;
}
#ifdef WITH_TCP
-static int auth_tcp_recv(rad_listen_t *listener,
- RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+static int dual_tcp_recv(rad_listen_t *listener)
{
int rcode;
RADIUS_PACKET *packet;
return 0;
}
- RAD_STATS_TYPE_INC(listener, total_requests);
-
/*
* Some sanity checks, based on the packet code.
*/
switch(packet->code) {
case PW_AUTHENTICATION_REQUEST:
- RAD_STATS_CLIENT_INC(listener, client, total_requests);
+ if (listener->type != RAD_LISTEN_AUTH) goto bad_packet;
+ FR_STATS_INC(auth, total_requests);
fun = rad_authenticate;
break;
+#ifdef WITH_ACCOUNTING
+ case PW_ACCOUNTING_REQUEST:
+ if (listener->type != RAD_LISTEN_ACCT) goto bad_packet;
+ FR_STATS_INC(acct, total_requests);
+ fun = rad_accounting;
+ break;
+#endif
+
case PW_STATUS_SERVER:
if (!mainconfig.status_server) {
- RAD_STATS_TYPE_INC(listener, total_packets_dropped);
- RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped);
+ FR_STATS_INC(auth, total_unknown_types);
DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
rad_free(&sock->packet);
return 0;
break;
default:
- RAD_STATS_INC(radius_auth_stats.total_unknown_types);
- RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+ bad_packet:
+ FR_STATS_INC(auth, total_unknown_types);
- DEBUG("Invalid packet code %d sent to authentication port from client %s port %d : IGNORED",
+ DEBUG("Invalid packet code %d sent from client %s port %d : IGNORED",
packet->code, client->shortname, packet->src_port);
rad_free(&sock->packet);
return 0;
} /* switch over packet types */
- if (!received_request(listener, packet, prequest, sock->client)) {
- RAD_STATS_TYPE_INC(listener, total_packets_dropped);
- RAD_STATS_CLIENT_INC(listener, sock->client, total_packets_dropped);
+ if (!request_receive(listener, packet, client, fun)) {
+ FR_STATS_INC(auth, total_packets_dropped);
rad_free(&sock->packet);
return 0;
}
- *pfun = fun;
sock->packet = NULL; /* we have no need for more partial reads */
return 1;
}
-static int auth_tcp_accept(rad_listen_t *listener,
- UNUSED RAD_REQUEST_FUNP *pfun,
- UNUSED REQUEST **prequest)
+static int dual_tcp_accept(rad_listen_t *listener)
{
int newfd, src_port;
rad_listen_t *this;
struct sockaddr_storage src;
listen_socket_t *sock;
fr_ipaddr_t src_ipaddr;
- RADCLIENT *client;
+ RADCLIENT *client = NULL;
salen = sizeof(src);
/*
* Non-blocking sockets must handle this.
*/
+#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK) {
return 0;
}
+#endif
DEBUG2(" ... failed to accept connection.");
return -1;
if ((client = client_listener_find(listener,
&src_ipaddr, src_port)) == NULL) {
close(newfd);
- RAD_STATS_TYPE_INC(listener, total_invalid_requests);
+ FR_STATS_INC(auth, total_invalid_requests);
return 0;
}
sock->other_ipaddr = src_ipaddr;
sock->other_port = src_port;
sock->client = client;
+ sock->opened = sock->last_packet = time(NULL);
this->fd = newfd;
this->status = RAD_LISTEN_STATUS_INIT;
- this->recv = auth_tcp_recv;
+ this->recv = dual_tcp_recv;
+
+#ifdef WITH_TLS
+ if (this->tls) {
+ this->recv = dual_tls_recv;
+ this->send = dual_tls_send;
+ }
+#endif
/*
* FIXME: set O_NONBLOCK on the accept'd fd.
/*
* This function is stupid and complicated.
*/
-static int socket_print(rad_listen_t *this, char *buffer, size_t bufsize)
+static int socket_print(const rad_listen_t *this, char *buffer, size_t bufsize)
{
size_t len;
listen_socket_t *sock = this->data;
}
#ifdef WITH_TCP
- if (this->recv == auth_tcp_accept) {
+ if (this->recv == dual_tcp_accept) {
ADDSTRING(" proto tcp");
}
#endif
return 1;
}
+#ifdef WITH_PROXY
/*
* Maybe it's a socket that we opened to a home server.
*/
return 1;
}
-#endif
+#endif /* WITH_PROXY */
+#endif /* WITH_TCP */
ADDSTRING(" address ");
snprintf(buffer, bufsize, "%d", sock->my_port);
FORWARD;
+#ifdef WITH_TLS
+ if (this->tls) {
+ ADDSTRING(" (TLS)");
+ FORWARD;
+ }
+#endif
+
if (this->server) {
ADDSTRING(" as server ");
ADDSTRING(this->server);
return 1;
}
+extern int check_config; /* radiusd.c */
+
/*
* Parse an authentication or accounting socket.
char *section_name = NULL;
CONF_SECTION *client_cs, *parentcs;
+ this->cs = cs;
+
/*
* Try IPv4 first
*/
+ memset(&ipaddr, 0, sizeof(ipaddr));
ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
rcode = cf_item_parse(cs, "ipaddr", PW_TYPE_IPADDR,
&ipaddr.ipaddr.ip4addr, NULL);
return -1;
#else
char *proto = NULL;
-
+#ifdef WITH_TLS
+ CONF_SECTION *tls;
+#endif
rcode = cf_item_parse(cs, "proto", PW_TYPE_STRING_PTR,
&proto, "udp");
* TCP requires a destination IP for sockets.
* UDP doesn't, so it's allowed.
*/
+#ifdef WITH_PROXY
if ((this->type == RAD_LISTEN_PROXY) &&
(sock->proto != IPPROTO_UDP)) {
cf_log_err(cf_sectiontoitem(cs),
"Proxy listeners can only listen on proto = udp");
return -1;
}
+#endif /* WITH_PROXY */
+
+#ifdef WITH_TLS
+ tls = cf_section_sub_find(cs, "tls");
+
+ /*
+ * Don't allow TLS configurations for UDP sockets.
+ */
+ if (sock->proto != IPPROTO_TCP) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "TLS transport is not available for UDP sockets.");
+ return -1;
+ }
+
+ if (tls) {
+ /*
+ * FIXME: Make this better.
+ */
+ if (listen_port == 0) listen_port = 2083;
+
+ this->tls = tls_server_conf_parse(tls);
+ if (!this->tls) {
+ return -1;
+ }
+
+#ifdef HAVE_PTRHEAD_H
+ if (pthread_mutex_init(&sock->mutex, NULL) < 0) {
+ rad_assert(0 == 1);
+ listen_free(&this);
+ return 0;
+ }
#endif
+
+ }
+#else /* WITH_TLS */
+ /*
+ * Built without TLS. Disallow it.
+ */
+ if (cf_section_sub_find(cs, "tls")) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "TLS transport is not available in this executable.");
+ return -1;
+ }
+#endif /* WITH_TLS */
+
+#endif /* WITH_TCP */
+
+ /*
+ * No "proto" field. Disallow TLS.
+ */
+ } else if (cf_section_sub_find(cs, "tls")) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "TLS transport is not available in this \"listen\" section.");
+ return -1;
}
sock->my_ipaddr = ipaddr;
sock->my_port = listen_port;
+#ifdef WITH_PROXY
+ if (check_config) {
+ if (home_server_find(&sock->my_ipaddr, sock->my_port, sock->proto)) {
+ char buffer[128];
+
+ DEBUG("ERROR: We have been asked to listen on %s port %d, which is also listed as a home server. This can create a proxy loop.",
+ ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)),
+ sock->my_port);
+ return -1;
+ }
+
+ return 0; /* don't do anything */
+ }
+#endif
+
/*
* If we can bind to interfaces, do so,
* else don't.
* Re-write the listener receive function to
* allow us to accept the socket.
*/
- this->recv = auth_tcp_accept;
+ this->recv = dual_tcp_accept;
}
#endif
rad_assert(request->listener == listener);
rad_assert(listener->send == auth_socket_send);
- return rad_send(request->reply, request->packet,
- request->client->secret);
+ if (rad_send(request->reply, request->packet,
+ request->client->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed sending reply: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ return 0;
}
*/
if (request->reply->code == 0) return 0;
- return rad_send(request->reply, request->packet,
- request->client->secret);
+ if (rad_send(request->reply, request->packet,
+ request->client->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed sending reply: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ return 0;
}
#endif
rad_assert(request->proxy_listener == listener);
rad_assert(listener->send == proxy_socket_send);
- return rad_send(request->proxy, request->packet,
- request->home_server->secret);
+ if (rad_send(request->proxy, NULL,
+ request->home_server->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed sending proxied request: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ return 0;
}
#endif
* 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)
+static int stats_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
int code, src_port;
RADIUS_PACKET *packet;
- RADCLIENT *client;
+ RADCLIENT *client = NULL;
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);
+ FR_STATS_INC(auth, total_requests);
if (rcode < 20) { /* AUTH_HDR_LEN */
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(auth, 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);
+ FR_STATS_INC(auth, total_invalid_requests);
return 0;
}
+ FR_STATS_TYPE_INC(client->auth.total_requests);
+
/*
* We only understand Status-Server on this socket.
*/
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);
+ FR_STATS_INC(auth, total_unknown_types);
return 0;
}
*/
packet = rad_recv(listener->fd, 1); /* require message authenticator */
if (!packet) {
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(auth, 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);
+ if (!request_receive(listener, packet, client, rad_status_server)) {
+ FR_STATS_INC(auth, total_packets_dropped);
rad_free(&packet);
return 0;
}
- *pfun = rad_status_server;
return 1;
}
#endif
* 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)
+static int auth_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
int code, src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
- RADCLIENT *client;
+ RADCLIENT *client = NULL;
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);
+ FR_STATS_INC(auth, total_requests);
if (rcode < 20) { /* AUTH_HDR_LEN */
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(auth, 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);
+ FR_STATS_INC(auth, total_invalid_requests);
return 0;
}
+ FR_STATS_TYPE_INC(client->auth.total_requests);
+
/*
* 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);
+ FR_STATS_INC(auth, total_unknown_types);
DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
return 0;
}
default:
rad_recv_discard(listener->fd);
- RAD_STATS_INC(radius_auth_stats.total_unknown_types);
- RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+ FR_STATS_INC(auth,total_unknown_types);
DEBUG("Invalid packet code %d sent to authentication port from client %s port %d : IGNORED",
code, client->shortname, src_port);
*/
packet = rad_recv(listener->fd, client->message_authenticator);
if (!packet) {
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(auth, 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);
+ if (!request_receive(listener, packet, client, fun)) {
+ FR_STATS_INC(auth, total_packets_dropped);
rad_free(&packet);
return 0;
}
- *pfun = fun;
return 1;
}
/*
* Receive packets from an accounting socket
*/
-static int acct_socket_recv(rad_listen_t *listener,
- RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+static int acct_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
int code, src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
- RADCLIENT *client;
+ RADCLIENT *client = NULL;
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);
+ FR_STATS_INC(acct, total_requests);
if (rcode < 20) { /* AUTH_HDR_LEN */
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(acct, 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);
+ FR_STATS_INC(acct, total_invalid_requests);
return 0;
}
+ FR_STATS_TYPE_INC(client->acct.total_requests);
+
/*
* 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);
+ FR_STATS_INC(acct, total_unknown_types);
DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
return 0;
default:
rad_recv_discard(listener->fd);
- RAD_STATS_TYPE_INC(listener, total_unknown_types);
- RAD_STATS_CLIENT_INC(listener, client, total_unknown_types);
+ FR_STATS_INC(acct, total_unknown_types);
DEBUG("Invalid packet code %d sent to a accounting port from client %s port %d : IGNORED",
code, client->shortname, src_port);
*/
packet = rad_recv(listener->fd, 0);
if (!packet) {
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(acct, 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);
+ if (!request_receive(listener, packet, client, fun)) {
+ FR_STATS_INC(acct, total_packets_dropped);
rad_free(&packet);
return 0;
}
- *pfun = fun;
return 1;
}
#endif
#ifdef WITH_COA
-/*
- * For now, all CoA requests are *only* originated, and not
- * proxied. So all of the necessary work is done in the
- * post-proxy section, which is automatically handled by event.c.
- * As a result, we don't have to do anything here.
- */
-static int rad_coa_reply(REQUEST *request)
+static int do_proxy(REQUEST *request)
{
- VALUE_PAIR *s1, *s2;
-
- /*
- * Inform the user about RFC requirements.
- */
- s1 = pairfind(request->proxy->vps, PW_STATE, 0);
- if (s1) {
- s2 = pairfind(request->proxy_reply->vps, PW_STATE, 0);
+ VALUE_PAIR *vp;
- if (!s2) {
- DEBUG("WARNING: Client was sent State in CoA, and did not respond with State.");
+ if (request->in_proxy_hash ||
+ (request->proxy_reply && (request->proxy_reply->code != 0))) {
+ return 0;
+ }
- } else if ((s1->length != s2->length) ||
- (memcmp(s1->vp_octets, s2->vp_octets,
- s1->length) != 0)) {
- DEBUG("WARNING: Client was sent State in CoA, and did not respond with the same State.");
- }
+ vp = pairfind(request->config_items, PW_HOME_SERVER_POOL, 0);
+ if (!vp) return 0;
+
+ if (!home_pool_byname(vp->vp_strvalue, HOME_TYPE_COA)) {
+ RDEBUG2("ERROR: Cannot proxy to unknown pool %s",
+ vp->vp_strvalue);
+ return 0;
}
- return RLM_MODULE_OK;
+ return 1;
}
/*
case RLM_MODULE_NOTFOUND:
case RLM_MODULE_OK:
case RLM_MODULE_UPDATED:
+ if (do_proxy(request)) return RLM_MODULE_OK;
request->reply->code = ack;
break;
}
- } else {
+ } else if (request->proxy_reply) {
/*
* Start the reply code with the proxy reply
* code.
/*
* We may want to over-ride the reply.
*/
- rcode = module_send_coa(0, request);
- switch (rcode) {
- /*
- * We need to send CoA-NAK back if Service-Type
- * is Authorize-Only. Rely on the user's policy
- * to do that. We're not a real NAS, so this
- * restriction doesn't (ahem) apply to us.
- */
+ if (request->reply->code) {
+ rcode = module_send_coa(0, request);
+ switch (rcode) {
+ /*
+ * We need to send CoA-NAK back if Service-Type
+ * is Authorize-Only. Rely on the user's policy
+ * to do that. We're not a real NAS, so this
+ * restriction doesn't (ahem) apply to us.
+ */
case RLM_MODULE_FAIL:
case RLM_MODULE_INVALID:
case RLM_MODULE_REJECT:
request->reply->code = ack;
}
break;
-
+ }
}
return RLM_MODULE_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 coa_socket_recv(rad_listen_t *listener,
- RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+static int coa_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
int code, src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
- RADCLIENT *client;
+ RADCLIENT *client = NULL;
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);
+ FR_STATS_INC(coa, total_requests);
+ FR_STATS_INC(coa, 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);
+ FR_STATS_INC(coa, total_requests);
+ FR_STATS_INC(coa, total_invalid_requests);
return 0;
}
*/
switch(code) {
case PW_COA_REQUEST:
+ FR_STATS_INC(coa, total_requests);
+ fun = rad_coa_recv;
+ break;
+
case PW_DISCONNECT_REQUEST:
+ FR_STATS_INC(dsc, total_requests);
fun = rad_coa_recv;
break;
default:
rad_recv_discard(listener->fd);
+ FR_STATS_INC(coa, total_unknown_types);
DEBUG("Invalid packet code %d sent to coa port from client %s port %d : IGNORED",
code, client->shortname, src_port);
return 0;
- break;
} /* switch over packet types */
/*
*/
packet = rad_recv(listener->fd, client->message_authenticator);
if (!packet) {
- RAD_STATS_TYPE_INC(listener, total_malformed_requests);
+ FR_STATS_INC(coa, total_malformed_requests);
DEBUG("%s", fr_strerror());
return 0;
}
- if (!received_request(listener, packet, prequest, client)) {
+ if (!request_receive(listener, packet, client, fun)) {
+ FR_STATS_INC(coa, total_packets_dropped);
rad_free(&packet);
return 0;
}
- *pfun = fun;
return 1;
}
#endif
/*
* Recieve packets from a proxy socket.
*/
-static int proxy_socket_recv(rad_listen_t *listener,
- RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+static int proxy_socket_recv(rad_listen_t *listener)
{
- REQUEST *request;
RADIUS_PACKET *packet;
- RAD_REQUEST_FUNP fun = NULL;
char buffer[128];
packet = rad_recv(listener->fd, 0);
case PW_AUTHENTICATION_ACK:
case PW_ACCESS_CHALLENGE:
case PW_AUTHENTICATION_REJECT:
- fun = rad_authenticate;
break;
#ifdef WITH_ACCOUNTING
case PW_ACCOUNTING_RESPONSE:
- fun = rad_accounting;
break;
#endif
case PW_DISCONNECT_NAK:
case PW_COA_ACK:
case PW_COA_NAK:
- fun = rad_coa_reply;
break;
#endif
return 0;
}
- request = received_proxy_response(packet);
- if (!request) {
+ if (!request_proxy_reply(packet)) {
rad_free(&packet);
return 0;
}
-#ifdef WITH_COA
- /*
- * Distinguish proxied CoA requests from ones we
- * originate.
- */
- if ((fun == rad_coa_reply) &&
- (request->packet->code == request->proxy->code)) {
- fun = rad_coa_recv;
- }
-#endif
-
- rad_assert(fun != NULL);
- *pfun = fun;
- *prequest = request;
-
return 1;
}
/*
* Recieve packets from a proxy socket.
*/
-static int proxy_socket_tcp_recv(rad_listen_t *listener,
- RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+static int proxy_socket_tcp_recv(rad_listen_t *listener)
{
- REQUEST *request;
RADIUS_PACKET *packet;
- RAD_REQUEST_FUNP fun = NULL;
listen_socket_t *sock = listener->data;
char buffer[128];
case PW_AUTHENTICATION_ACK:
case PW_ACCESS_CHALLENGE:
case PW_AUTHENTICATION_REJECT:
- fun = rad_authenticate;
break;
#ifdef WITH_ACCOUNTING
case PW_ACCOUNTING_RESPONSE:
- fun = rad_accounting;
break;
#endif
*
* Close the socket on bad packets...
*/
- request = received_proxy_response(packet);
- if (!request) {
+ if (!request_proxy_reply(packet)) {
+ rad_free(&packet);
return 0;
}
- rad_assert(fun != NULL);
- sock->opened = sock->last_packet = request->timestamp;
-
- *pfun = fun;
- *prequest = request;
+ sock->opened = sock->last_packet = time(NULL);
return 1;
}
{
if (!request->reply->code) return 0;
- rad_encode(request->reply, request->packet,
- request->client->secret);
- rad_sign(request->reply, request->packet,
- request->client->secret);
+ if (rad_encode(request->reply, request->packet,
+ request->client->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed encoding packet: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ if (rad_sign(request->reply, request->packet,
+ request->client->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed signing packet: %s",
+ fr_strerror());
+ return -1;
+ }
return 0;
}
#ifdef WITH_PROXY
static int proxy_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
{
- rad_encode(request->proxy, NULL, request->home_server->secret);
- rad_sign(request->proxy, NULL, request->home_server->secret);
+ if (rad_encode(request->proxy, NULL, request->home_server->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed encoding proxied packet: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ if (rad_sign(request->proxy, NULL, request->home_server->secret) < 0) {
+ radlog_request(L_ERR, 0, request, "Failed signing proxied packet: %s",
+ fr_strerror());
+ return -1;
+ }
return 0;
}
#endif
default:
- radlog(L_ERR, "ERROR: Non-fatal internal sanity check failed in bind.");
+ DEBUG("WARNING: Internal sanity check failed in binding to socket. Ignoring problem.");
return -1;
}
}
/*
+ * Don't open sockets if we're checking the config.
+ */
+ if (check_config) {
+ this->fd = -1;
+ return 0;
+ }
+
+ /*
* Copy fr_socket() here, as we may need to bind to a device.
*/
this->fd = socket(sock->my_ipaddr.af, sock_type, 0);
if (this->fd < 0) {
- radlog(L_ERR, "Failed opening socket: %s", strerror(errno));
+ char buffer[256];
+
+ this->print(this, buffer, sizeof(buffer));
+
+ radlog(L_ERR, "Failed opening %s: %s", buffer, strerror(errno));
return -1;
}
if (sock->interface) {
#ifdef SO_BINDTODEVICE
struct ifreq ifreq;
- strcpy(ifreq.ifr_name, sock->interface);
+
+ memset(&ifreq, 0, sizeof(ifreq));
+ strlcpy(ifreq.ifr_name, sock->interface, sizeof(ifreq.ifr_name));
fr_suid_up();
rcode = setsockopt(this->fd, SOL_SOCKET, SO_BINDTODEVICE,
* Initialize udpfromto for all sockets.
*/
if (udpfromto_init(this->fd) != 0) {
+ radlog(L_ERR, "Failed initializing udpfromto: %s",
+ strerror(errno));
close(this->fd);
return -1;
}
{
rad_listen_t *this;
listen_socket_t *sock;
+#ifndef NDEBUG
+ char buffer[256];
+#endif
if (!home) return 0;
sock->my_port = src_port;
sock->proto = home->proto;
+ if (debug_flag >= 2) {
+ this->print(this, buffer, sizeof(buffer));
+ DEBUG("Opening new %s", buffer);
+ }
+
#ifdef WITH_TCP
- sock->last_packet = time(NULL);
+ sock->opened = sock->last_packet = time(NULL);
if (home->proto == IPPROTO_TCP) {
this->recv = proxy_socket_tcp_recv;
*/
this->fd = fr_tcp_client_socket(&home->src_ipaddr,
&home->ipaddr, home->port);
+#ifdef WITH_TLS
+ if (home->tls) {
+ DEBUG("Trying SSL to port %d\n", home->port);
+ sock->ssn = tls_new_client_session(home->tls, this->fd);
+ if (!sock->ssn) {
+ listen_free(&this);
+ return 0;
+ }
+
+ this->recv = proxy_tls_recv;
+ this->send = proxy_tls_send;
+ }
+#endif
} else
#endif
this->fd = fr_socket(&home->src_ipaddr, src_port);
if (this->fd < 0) {
- DEBUG("Failed opening client socket: %s", fr_strerror());
+ this->print(this, buffer,sizeof(buffer));
+ DEBUG("Failed opening client socket ::%s:: : %s",
+ buffer, fr_strerror());
listen_free(&this);
return 0;
}
return this;
}
+#ifdef WITH_PROXY
+static int is_loopback(const fr_ipaddr_t *ipaddr)
+{
+ /*
+ * We shouldn't proxy on loopback.
+ */
+ if ((ipaddr->af == AF_INET) &&
+ (ipaddr->ipaddr.ip4addr.s_addr == htonl(INADDR_LOOPBACK))) {
+ return 1;
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ if ((ipaddr->af == AF_INET6) &&
+ (IN6_IS_ADDR_LINKLOCAL(&ipaddr->ipaddr.ip6addr))) {
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+#endif
+
/*
* Generate a list of listeners. Takes an input list of
* listeners, too, so we don't close sockets with waiting packets.
*/
-int listen_init(CONF_SECTION *config, rad_listen_t **head)
+int listen_init(CONF_SECTION *config, rad_listen_t **head, int spawn_flag)
{
int override = FALSE;
int rcode;
#ifdef WITH_PROXY
int defined_proxy = 0;
#endif
+#ifndef WITH_TLS
+ spawn_flag = spawn_flag; /* -Wunused */
+#endif
/*
* We shouldn't be called with a pre-existing list.
add_sockets:
/*
+ * No sockets to receive packets, this is an error.
+ * proxying is pointless.
+ */
+ if (!*head) {
+ radlog(L_ERR, "The server is not configured to listen on any ports. Cannot start.");
+ return -1;
+ }
+
+ /*
* Print out which sockets we're listening on, and
* add them to the event list.
*/
}
#endif
- event_new_fd(this);
+
+#ifdef WITH_TLS
+ if (!spawn_flag && this->tls) {
+ cf_log_err(cf_sectiontoitem(this->cs), "Threading must be enabled for TLS sockets to function properly.");
+ cf_log_err(cf_sectiontoitem(this->cs), "You probably need to do 'radiusd -fxx -l stdout' for debugging");
+ return -1;
+ }
+#endif
+ if (!check_config) event_new_fd(this);
}
/*
*/
#ifdef WITH_PROXY
if ((mainconfig.proxy_requests == TRUE) &&
+ !check_config &&
(*head != NULL) && !defined_proxy) {
listen_socket_t *sock = NULL;
int port = 0;
for (this = *head; this != NULL; this = this->next) {
if (this->type == RAD_LISTEN_AUTH) {
sock = this->data;
+
+ if (is_loopback(&sock->my_ipaddr)) continue;
+
if (home.src_ipaddr.af == AF_UNSPEC) {
home.src_ipaddr = sock->my_ipaddr;
}
#ifdef WITH_ACCT
if (this->type == RAD_LISTEN_ACCT) {
sock = this->data;
+
+ if (is_loopback(&sock->my_ipaddr)) continue;
+
if (home.src_ipaddr.af == AF_UNSPEC) {
home.src_ipaddr = sock->my_ipaddr;
}
*/
if (!*head) return -1;
+ xlat_register("listen", xlat_listen, NULL);
return 0;
}
master_listen[this->type].free(this);
}
+#ifdef WITH_TLS
+ if (this->tls) tls_server_conf_free(this->tls);
+#endif
+
#ifdef WITH_TCP
- if ((this->type == RAD_LISTEN_AUTH) ||
+ if ((this->type == RAD_LISTEN_AUTH)
#ifdef WITH_ACCT
- (this->type == RAD_LISTEN_ACCT) ||
+ || (this->type == RAD_LISTEN_ACCT)
#endif
#ifdef WITH_PROXY
- (this->type == RAD_LISTEN_PROXY)
+ || (this->type == RAD_LISTEN_PROXY)
#endif
) {
listen_socket_t *sock = this->data;
- rad_free(&sock->packet);
- }
+
+#ifdef WITH_TLS
+ if (sock->request) {
+ pthread_mutex_destroy(&(sock->mutex));
+ request_free(&sock->request);
+ sock->packet = NULL;
+
+ if (sock->ssn) session_free(sock->ssn);
+ request_free(&sock->request);
+ } else
#endif
+ rad_free(&sock->packet);
+
+ }
+#endif /* WITH_TCP */
free(this->data);
free(this);
for (this = mainconfig.listen; this != NULL; this = this->next) {
listen_socket_t *sock;
- if ((this->type != RAD_LISTEN_AUTH) &&
- (this->type != RAD_LISTEN_ACCT)) continue;
+ if ((this->type != RAD_LISTEN_AUTH)
+#ifdef WITH_ACCOUNTING
+ && (this->type != RAD_LISTEN_ACCT)
+#endif
+ ) continue;
sock = this->data;
}
#endif
-rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port)
+rad_listen_t *listener_find_byipaddr(const fr_ipaddr_t *ipaddr, int port, int proto)
{
rad_listen_t *this;
for (this = mainconfig.listen; this != NULL; this = this->next) {
listen_socket_t *sock;
- /*
- * FIXME: For TCP, ignore the *secondary*
- * listeners associated with the main socket.
- */
- if ((this->type != RAD_LISTEN_AUTH) &&
- (this->type != RAD_LISTEN_ACCT)) continue;
-
sock = this->data;
- if ((sock->my_port == port) &&
- (fr_ipaddr_cmp(ipaddr, &sock->my_ipaddr) == 0)) {
- return this;
- }
+ if (sock->my_port != port) continue;
+ if (sock->proto != proto) continue;
+ if (fr_ipaddr_cmp(ipaddr, &sock->my_ipaddr) != 0) continue;
- if ((sock->my_port == port) &&
- ((sock->my_ipaddr.af == AF_INET) &&
- (sock->my_ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY))) {
- return this;
- }
+ return this;
+ }
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- if ((sock->my_port == port) &&
- (sock->my_ipaddr.af == AF_INET6) &&
- (IN6_IS_ADDR_UNSPECIFIED(&sock->my_ipaddr.ipaddr.ip6addr))) {
- return this;
- }
-#endif
+ /*
+ * Failed to find a specific one. Find INADDR_ANY
+ */
+ for (this = mainconfig.listen; this != NULL; this = this->next) {
+ listen_socket_t *sock;
+
+ sock = this->data;
+
+ if (sock->my_port != port) continue;
+ if (sock->proto != proto) continue;
+ if (!fr_inaddr_any(&sock->my_ipaddr)) continue;
+
+ return this;
}
return NULL;