From: Alan T. DeKok Date: Wed, 31 Mar 2021 18:41:17 +0000 (-0400) Subject: look for CoA requests from a home server, and send replies X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a9a30da150f0b6f9b8d4eeda58c8fc70279d253;p=thirdparty%2Ffreeradius-server.git look for CoA requests from a home server, and send replies --- diff --git a/src/include/radiusd.h b/src/include/radiusd.h index 81490a3396..b737b420b3 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -606,6 +606,7 @@ int dual_tls_send(rad_listen_t *listener, REQUEST *request); int proxy_tls_recv(rad_listen_t *listener); int proxy_tls_send(rad_listen_t *listener, REQUEST *request); #ifdef WITH_COA_TUNNEL +int proxy_tls_send_reply(rad_listen_t *listener, REQUEST *request); int dual_tls_send_coa_request(rad_listen_t *listener, REQUEST *request); #endif #endif diff --git a/src/main/listen.c b/src/main/listen.c index f665b4120b..110b4f53a3 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -748,7 +748,7 @@ static int dual_tcp_accept(rad_listen_t *listener) this->proxy_encode = master_listen[RAD_LISTEN_PROXY].encode; this->proxy_decode = master_listen[RAD_LISTEN_PROXY].decode; - // @todo - save this listener as being outbound to the NAS IP +// listener_store_byaddr(this, &sock->other_ipaddr); /* * Automatically create a home server for this @@ -2947,6 +2947,42 @@ rad_listen_t *proxy_new_listener(TALLOC_CTX *ctx, home_server_t *home, uint16_t this->recv = proxy_tls_recv; this->proxy_send = proxy_tls_send; + +#ifdef WITH_COA_TUNNEL + if (home->recv_coa) { + RADCLIENT *client; + + /* + * Don't set this->send_coa, as we are + * not sending CoA-Request packets to + * this home server. Instead, we are + * receiving CoA packets from this home + * server. + */ + this->send = proxy_tls_send_reply; + this->encode = master_listen[RAD_LISTEN_AUTH].encode; + this->decode = master_listen[RAD_LISTEN_AUTH].decode; + + /* + * Automatically create a client for this + * home server. There MAY be one already + * one for that IP in the configuration + * files, but there's no guarantee that + * it exists. + * + * The only real reason to use an + * existing client is to track various + * statistics. + */ + sock->client = client = talloc_zero(sock, RADCLIENT); + client->ipaddr = sock->other_ipaddr; + client->src_ipaddr = sock->my_ipaddr; + client->longname = client->shortname = talloc_typed_strdup(client, home->name); + client->secret = talloc_typed_strdup(client, home->secret); + client->nas_type = "none"; + client->server = talloc_typed_strdup(client, home->coa_server); + } +#endif } #endif #endif diff --git a/src/main/tls_listen.c b/src/main/tls_listen.c index 30b64140a2..2d7b9b9cf0 100644 --- a/src/main/tls_listen.c +++ b/src/main/tls_listen.c @@ -847,6 +847,10 @@ int proxy_tls_recv(rad_listen_t *listener) RADIUS_PACKET *packet; uint8_t *data; ssize_t data_len; +#ifdef WITH_COA_TUNNEL + bool is_request = false; + RADCLIENT *client = sock->client; +#endif if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; @@ -900,9 +904,26 @@ int proxy_tls_recv(rad_listen_t *listener) case PW_CODE_DISCONNECT_ACK: case PW_CODE_DISCONNECT_NAK: break; + +#ifdef WITH_COA_TUNNEL + case PW_CODE_COA_REQUEST: + if (!listener->send_coa) goto bad_packet; + FR_STATS_INC(coa, total_requests); + is_request = true; + break; + + case PW_CODE_DISCONNECT_REQUEST: + if (!listener->send_coa) goto bad_packet; + FR_STATS_INC(dsc, total_requests); + is_request = true; + break; +#endif #endif default: +#ifdef WITH_COA_TUNNEL + bad_packet: +#endif /* * FIXME: Update MIB for packet types? */ @@ -915,6 +936,15 @@ int proxy_tls_recv(rad_listen_t *listener) return 0; } +#ifdef WITH_COA_TUNNEL + if (is_request) { + if (!request_receive(NULL, listener, packet, client, rad_coa_recv)) { + FR_STATS_INC(auth, total_packets_dropped); + rad_free(&packet); + return 0; + } + } else +#endif if (!request_proxy_reply(packet)) { rad_free(&packet); return 0; @@ -985,6 +1015,71 @@ int proxy_tls_send(rad_listen_t *listener, REQUEST *request) return 1; } + +#ifdef WITH_COA_TUNNEL +int proxy_tls_send_reply(rad_listen_t *listener, REQUEST *request) +{ + int rcode; + listen_socket_t *sock = listener->data; + + VERIFY_REQUEST(request); + + rad_assert(sock->ssn->connected); + + if ((listener->status != RAD_LISTEN_STATUS_INIT && + (listener->status != RAD_LISTEN_STATUS_KNOWN))) return 0; + + /* + * Pack the VPs + */ + if (rad_encode(request->reply, request->packet, + request->client->secret) < 0) { + RERROR("Failed encoding packet: %s", fr_strerror()); + return 0; + } + + if (request->reply->data_len > (MAX_PACKET_LEN - 100)) { + RWARN("Packet is large, and possibly truncated - %zd vs max %d", + request->reply->data_len, MAX_PACKET_LEN); + } + + /* + * Sign the packet. + */ + if (rad_sign(request->reply, request->packet, + request->client->secret) < 0) { + RERROR("Failed signing packet: %s", fr_strerror()); + return 0; + } + + DEBUG3("Proxy is writing %u bytes to SSL", + (unsigned int) request->reply->data_len); + PTHREAD_MUTEX_LOCK(&sock->mutex); + rcode = SSL_write(sock->ssn->ssl, request->reply->data, + request->reply->data_len); + if (rcode < 0) { + int err; + + err = ERR_get_error(); + switch (err) { + case SSL_ERROR_NONE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + break; /* let someone else retry */ + + default: + tls_error_log(NULL, "Failed in proxy send"); + DEBUG("Closing TLS socket to home server"); + tls_socket_close(listener); + PTHREAD_MUTEX_UNLOCK(&sock->mutex); + return 0; + } + } + PTHREAD_MUTEX_UNLOCK(&sock->mutex); + + return 1; +} +#endif /* WITH_COA_TUNNEL */ #endif /* WITH_PROXY */ #endif /* WITH_TLS */