]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
originate CoA requests to the NAS, and deal with the replies
authorAlan T. DeKok <aland@freeradius.org>
Wed, 31 Mar 2021 16:52:25 +0000 (12:52 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 22 Jul 2021 13:55:19 +0000 (09:55 -0400)
src/include/radiusd.h
src/main/listen.c
src/main/tls_listen.c

index fbb743419b78a901ebee17b911d7d8d388842d5f..9e22c0bb3c9d7d1196d089f21db1d3ba2dc254eb 100644 (file)
@@ -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
 
 /*
index c9a143e3799adf488c06018a082c60383c45a10a..7468816f89edbb5bd674cbfff0a070f865918e8e 100644 (file)
@@ -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.
index d769f0b3ba80d62df889c7694b930709caa23ba5..97de799edea54ebcfcd928da6b5f3a6070b5350a 100644 (file)
@@ -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;