summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2022-08-31 18:37:05 +0000
committerFelix Fietkau2022-08-31 18:38:39 +0000
commit8ad119715168c730e1800c3b13f6d762530c9beb (patch)
tree59700d9173bdc4eaaccf537a761bc20215a39779
parentc3b1127236a0c0372da3f711c8701d1a36434b48 (diff)
downloadunetd-8ad119715168c730e1800c3b13f6d762530c9beb.tar.gz
ubus: add support for adding auth_connect hosts at runtime
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>
-rw-r--r--network.c1
-rw-r--r--pex.c43
-rw-r--r--pex.h4
-rw-r--r--ubus.c57
-rw-r--r--utils.c12
-rw-r--r--utils.h2
6 files changed, 115 insertions, 4 deletions
diff --git a/network.c b/network.c
index b39deb4..beb0230 100644
--- 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 839567d..5234e10 100644
--- 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 11f783f..123b4a9 100644
--- 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 6d3f9c9..323fe44 100644
--- 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 95ab08b..abaa73d 100644
--- 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 94cf057..d79d96c 100644
--- 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