ubus: add support for adding auth_connect hosts at runtime
authorFelix Fietkau <nbd@nbd.name>
Wed, 31 Aug 2022 18:37:05 +0000 (20:37 +0200)
committerFelix Fietkau <nbd@nbd.name>
Wed, 31 Aug 2022 18:38:39 +0000 (20:38 +0200)
These hosts always need to have a timeout value. After the timeout, they
are automatically deleted. Other than that, they work just like regular
configured auth_host entries

Signed-off-by: Felix Fietkau <nbd@nbd.name>
network.c
pex.c
pex.h
ubus.c
utils.c
utils.h

index b39deb4c8f1c6733f843092dbba8f28e001cb635..beb023010fd9320047dbc2bdd6eaf6a18a533ad0 100644 (file)
--- a/network.c
+++ b/network.c
@@ -445,6 +445,7 @@ static void network_teardown(struct network *net)
        uloop_timeout_cancel(&net->reload_timer);
        network_do_update(net, false);
        network_pex_close(net);
+       network_pex_free(net);
        network_hosts_free(net);
        network_services_free(net);
        wg_cleanup_network(net);
diff --git a/pex.c b/pex.c
index 839567dd2763a7b4ec1c339b10e34eba8a7e87c4..5234e10509e5eaf5f64054dc52973ca838b70718 100644 (file)
--- a/pex.c
+++ b/pex.c
@@ -261,10 +261,17 @@ network_pex_request_update_cb(struct uloop_timeout *t)
 
        uloop_timeout_set(t, 5000);
 
+retry:
        if (list_empty(&pex->hosts))
                return;
 
        host = list_first_entry(&pex->hosts, struct network_pex_host, list);
+       if (host->timeout && host->timeout < unet_gettime()) {
+               list_del(&host->list);
+               free(host);
+               goto retry;
+       }
+
        list_move_tail(&host->list, &pex->hosts);
        network_pex_host_request_update(net, host);
 }
@@ -667,15 +674,29 @@ network_pex_fd_cb(struct uloop_fd *fd, unsigned int events)
        }
 }
 
-static void
-network_pex_create_host(struct network *net, union network_endpoint *ep)
+void network_pex_create_host(struct network *net, union network_endpoint *ep,
+                            unsigned int timeout)
 {
        struct network_pex *pex = &net->pex;
        struct network_pex_host *host;
+       bool new_host = false;
+
+       list_for_each_entry(host, &pex->hosts, list) {
+               if (memcmp(&host->endpoint, ep, sizeof(host->endpoint)) != 0)
+                       continue;
+
+               list_move_tail(&host->list, &pex->hosts);
+               goto out;
+       }
 
        host = calloc(1, sizeof(*host));
+       new_host = true;
        memcpy(&host->endpoint, ep, sizeof(host->endpoint));
        list_add_tail(&host->list, &pex->hosts);
+
+out:
+       if (timeout && (new_host || host->timeout))
+               host->timeout = timeout + unet_gettime();
        network_pex_host_request_update(net, host);
 }
 
@@ -703,7 +724,7 @@ network_pex_open_auth_connect(struct network *net)
                        continue;
 
                ep.in.sin_port = htons(UNETD_GLOBAL_PEX_PORT);
-               network_pex_create_host(net, &ep);
+               network_pex_create_host(net, &ep, 0);
        }
 
        if (!net->config.auth_connect)
@@ -716,7 +737,7 @@ network_pex_open_auth_connect(struct network *net)
                                         UNETD_GLOBAL_PEX_PORT, 0) < 0)
                        continue;
 
-               network_pex_create_host(net, &ep);
+               network_pex_create_host(net, &ep, 0);
        }
 }
 
@@ -778,6 +799,9 @@ void network_pex_close(struct network *net)
 
        uloop_timeout_cancel(&pex->request_update_timer);
        list_for_each_entry_safe(host, tmp, &pex->hosts, list) {
+               if (host->timeout)
+                       continue;
+
                list_del(&host->list);
                free(host);
        }
@@ -790,6 +814,17 @@ void network_pex_close(struct network *net)
        network_pex_init(net);
 }
 
+void network_pex_free(struct network *net)
+{
+       struct network_pex *pex = &net->pex;
+       struct network_pex_host *host, *tmp;
+
+       list_for_each_entry_safe(host, tmp, &pex->hosts, list) {
+               list_del(&host->list);
+               free(host);
+       }
+}
+
 static struct network *
 global_pex_find_network(const uint8_t *id)
 {
diff --git a/pex.h b/pex.h
index 11f783fc398d6846401a430829efbf8aa07b1570..123b4a97537945a75a0bd2b850205a42469b47bc 100644 (file)
--- a/pex.h
+++ b/pex.h
@@ -11,6 +11,7 @@ struct network;
 
 struct network_pex_host {
        struct list_head list;
+       uint64_t timeout;
        union network_endpoint endpoint;
 };
 
@@ -30,9 +31,12 @@ enum pex_event {
 void network_pex_init(struct network *net);
 int network_pex_open(struct network *net);
 void network_pex_close(struct network *net);
+void network_pex_free(struct network *net);
 
 void network_pex_event(struct network *net, struct network_peer *peer,
                       enum pex_event ev);
+void network_pex_create_host(struct network *net, union network_endpoint *ep,
+                            unsigned int timeout);
 
 static inline bool network_pex_active(struct network_pex *pex)
 {
diff --git a/ubus.c b/ubus.c
index 6d3f9c95f2a3cd8f82a6e0055e489d6e92022ae4..323fe44cfa6aba9b79c66f888c196ac9de60fe4c 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -195,12 +195,69 @@ ubus_service_get(struct ubus_context *ctx, struct ubus_object *obj,
        return 0;
 }
 
+enum {
+    CONNECT_ATTR_NAME,
+    CONNECT_ATTR_ADDRESS,
+    CONNECT_ATTR_TIMEOUT,
+    __CONNECT_ATTR_MAX
+};
+
+static const struct blobmsg_policy connect_policy[__CONNECT_ATTR_MAX] = {
+       [CONNECT_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
+       [CONNECT_ATTR_ADDRESS] = { "address", BLOBMSG_TYPE_STRING },
+       [CONNECT_ATTR_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+ubus_network_connect(struct ubus_context *ctx, struct ubus_object *obj,
+                    struct ubus_request_data *req, const char *method,
+                    struct blob_attr *msg)
+{
+       struct blob_attr *tb[__CONNECT_ATTR_MAX];
+       union network_endpoint ep = {};
+       struct blob_attr *cur;
+       struct network *net;
+       unsigned int timeout;
+       const char *name;
+
+       blobmsg_parse(connect_policy, __CONNECT_ATTR_MAX, tb,
+                     blobmsg_data(msg), blobmsg_len(msg));
+
+       if ((cur = tb[CONNECT_ATTR_NAME]) != NULL)
+               name = blobmsg_get_string(cur);
+       else
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       if ((cur = tb[CONNECT_ATTR_TIMEOUT]) != NULL)
+               timeout = blobmsg_get_u32(cur);
+       else
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       if ((cur = tb[CONNECT_ATTR_ADDRESS]) == NULL ||
+           network_get_endpoint(&ep, blobmsg_get_string(cur), UNETD_GLOBAL_PEX_PORT, 0) < 0 ||
+           !ep.in.sin_port)
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       net = avl_find_element(&networks, name, net, node);
+       if (!net)
+               return UBUS_STATUS_NOT_FOUND;
+
+       if (net->config.type != NETWORK_TYPE_DYNAMIC)
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       network_pex_create_host(net, &ep, timeout);
+
+       return 0;
+}
+
+
 static const struct ubus_method unetd_methods[] = {
        UBUS_METHOD("network_add", ubus_network_add, network_policy),
        UBUS_METHOD_MASK("network_del", ubus_network_del, network_policy,
                         (1 << NETWORK_ATTR_NAME)),
        UBUS_METHOD_MASK("network_get", ubus_network_get, network_policy,
                         (1 << NETWORK_ATTR_NAME)),
+       UBUS_METHOD("network_connect", ubus_network_connect, connect_policy),
        UBUS_METHOD("service_get", ubus_service_get, service_policy),
 };
 
diff --git a/utils.c b/utils.c
index 95ab08bb570b3d9360d96876eeb1a640242f4c48..abaa73d2367edecaab68f36003e6407efadfdcb5 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -8,6 +8,9 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <stdio.h>
+
+#include <libubox/utils.h>
+
 #include "unetd.h"
 
 int network_get_endpoint(union network_endpoint *dest, const char *str,
@@ -179,3 +182,12 @@ error:
        *len = 0;
        return NULL;
 }
+
+uint64_t unet_gettime(void)
+{
+       struct timespec ts;
+
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+
+       return ts.tv_sec;
+}
diff --git a/utils.h b/utils.h
index 94cf057d367a2b1ef946d1e92295c163a5707bc0..d79d96c1e9a7c1dcfa8f20845c4390ea5dc00652 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -123,4 +123,6 @@ static inline uint64_t get_unaligned_le64(const uint8_t *p)
 int rtnl_init(void);
 int rtnl_call(struct nl_msg *msg);
 
+uint64_t unet_gettime(void);
+
 #endif