From: Alan T. DeKok Date: Wed, 31 Mar 2021 16:52:25 +0000 (-0400) Subject: originate CoA requests to the NAS, and deal with the replies X-Git-Tag: release_3_0_24~168 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=14ebd63cb3e9e28e8b5d01f16149830fbfda548c;p=thirdparty%2Ffreeradius-server.git originate CoA requests to the NAS, and deal with the replies --- diff --git a/src/include/radiusd.h b/src/include/radiusd.h index fbb743419b7..9e22c0bb3c9 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -607,6 +607,9 @@ int dual_tls_recv(rad_listen_t *listener); 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 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 c9a143e3799..7468816f89e 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -772,6 +772,41 @@ static int dual_tcp_accept(rad_listen_t *listener) #endif } +#ifdef WITH_COA_TUNNEL + /* + * Originate CoA requests to a NAS. + */ + if (this->send_coa) { + home_server_t *home; + + rad_assert(this->type != RAD_LISTEN_PROXY); + + this->proxy_send = dual_tls_send_coa_request; + 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 + + /* + * Automatically create a home server for this + * client. There MAY be one already one for that + * IP in the configuration files, but it will not + * have this particular port. + */ + sock->home = home = talloc_zero(this, home_server_t); + home->ipaddr = sock->other_ipaddr; + home->port = sock->other_port; + home->proto = sock->proto; + home->secret = sock->client->secret; + + home->coa_irt = this->coa_irt; + home->coa_mrt = this->coa_mrt; + home->coa_mrc = this->coa_mrc; + home->coa_mrd = this->coa_mrd; + home->coa_server = this->server; + } +#endif + /* * FIXME: set O_NONBLOCK on the accept'd fd. * See djb's portability rants for details. diff --git a/src/main/tls_listen.c b/src/main/tls_listen.c index d769f0b3ba8..97de799edea 100644 --- a/src/main/tls_listen.c +++ b/src/main/tls_listen.c @@ -400,6 +400,9 @@ int dual_tls_recv(rad_listen_t *listener) listen_socket_t *sock = listener->data; RADCLIENT *client = sock->client; BIO *rbio; +#ifdef WITH_COA_TUNNEL + bool is_reply = false; +#endif if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; @@ -458,6 +461,14 @@ redo: FR_STATS_INC(dsc, total_requests); fun = rad_coa_recv; break; + +#ifdef WITH_COA_TUNNEL + case PW_CODE_COA_ACK: + case PW_CODE_COA_NAK: + if (!listener->send_coa) goto bad_packet; + is_reply = true; + break; +#endif #endif case PW_CODE_STATUS_SERVER: @@ -484,6 +495,15 @@ redo: return 0; } /* switch over packet types */ +#ifdef WITH_COA_TUNNEL + if (is_reply) { + if (!request_proxy_reply(packet)) { + rad_free(&packet); + return 0; + } + } else +#endif + if (!request_receive(NULL, listener, packet, client, fun)) { FR_STATS_INC(auth, total_packets_dropped); rad_free(&packet); @@ -609,6 +629,58 @@ int dual_tls_send(rad_listen_t *listener, REQUEST *request) return 0; } +#ifdef WITH_COA_TUNNEL +/* + * Send a CoA request to a NAS, as a proxied packet. + * + * The proxied packet MUST already have been encoded. + */ +int dual_tls_send_coa_request(rad_listen_t *listener, REQUEST *request) +{ + listen_socket_t *sock = listener->data; + + VERIFY_REQUEST(request); + + rad_assert(listener->proxy_send == dual_tls_send_coa_request); + + if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; + + rad_assert(request->proxy->data); + + if (request->proxy->data_len > (MAX_PACKET_LEN - 100)) { + RWARN("Packet is large, and possibly truncated - %zd vs max %d", + request->proxy->data_len, MAX_PACKET_LEN); + } + + PTHREAD_MUTEX_LOCK(&sock->mutex); + + /* + * Write the packet to the SSL buffers. + */ + sock->ssn->record_plus(&sock->ssn->clean_in, + request->proxy->data, request->proxy->data_len); + + dump_hex("TUNNELED DATA < ", sock->ssn->clean_in.data, sock->ssn->clean_in.used); + + /* + * Do SSL magic to get encrypted data. + */ + tls_handshake_send(request, sock->ssn); + + /* + * And finally write the data to the socket. + */ + if (sock->ssn->dirty_out.used > 0) { + dump_hex("WRITE TO SSL", sock->ssn->dirty_out.data, sock->ssn->dirty_out.used); + +// tls_socket_write(listener, request); + } + PTHREAD_MUTEX_UNLOCK(&sock->mutex); + + return 0; +} +#endif + static int try_connect(tls_session_t *ssn) { int ret;