summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2025-01-27 11:39:59 +0000
committerFelix Fietkau2025-01-27 11:40:04 +0000
commitc293afa01c1328ee8a18fc407948d0529353d7eb (patch)
tree218751552d0b618f29ccb3731ff5c25a699683a7
parentd13752814651c70d2afc71383612fafc835b631b (diff)
downloadunetd-c293afa01c1328ee8a18fc407948d0529353d7eb.tar.gz
network: add support for the local_network option
This lets unetd automatically query netifd for local addresses in order to add broadcast addresses as PEX hosts for discovering peers. Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--network.c5
-rw-r--r--network.h2
-rw-r--r--pex.c85
-rw-r--r--pex.h7
-rw-r--r--ubus.c60
-rw-r--r--ubus.h5
6 files changed, 160 insertions, 4 deletions
diff --git a/network.c b/network.c
index fe1b2c9..721d48e 100644
--- a/network.c
+++ b/network.c
@@ -57,6 +57,7 @@ const struct blobmsg_policy network_policy[__NETWORK_ATTR_MAX] = {
[NETWORK_ATTR_DOMAIN] = { "domain", BLOBMSG_TYPE_STRING },
[NETWORK_ATTR_UPDATE_CMD] = { "update-cmd", BLOBMSG_TYPE_STRING },
[NETWORK_ATTR_TUNNELS] = { "tunnels", BLOBMSG_TYPE_TABLE },
+ [NETWORK_ATTR_LOCAL_NET] = { "local_network", BLOBMSG_TYPE_ARRAY },
[NETWORK_ATTR_AUTH_CONNECT] = { "auth_connect", BLOBMSG_TYPE_ARRAY },
[NETWORK_ATTR_PEER_DATA] = { "peer_data", BLOBMSG_TYPE_ARRAY },
};
@@ -656,6 +657,10 @@ network_set_config(struct network *net, struct blob_attr *config)
if ((cur = tb[NETWORK_ATTR_TUNNELS]) != NULL)
net->config.tunnels = cur;
+ if ((cur = tb[NETWORK_ATTR_LOCAL_NET]) != NULL &&
+ blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
+ net->config.local_network = cur;
+
if ((cur = tb[NETWORK_ATTR_AUTH_CONNECT]) != NULL &&
blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
net->config.auth_connect = cur;
diff --git a/network.h b/network.h
index bfd4c78..f713fd3 100644
--- a/network.h
+++ b/network.h
@@ -37,6 +37,7 @@ struct network {
const char *domain;
struct blob_attr *tunnels;
struct blob_attr *net_data;
+ struct blob_attr *local_network;
struct blob_attr *auth_connect;
struct blob_attr *peer_data;
} config;
@@ -87,6 +88,7 @@ enum {
NETWORK_ATTR_KEEPALIVE,
NETWORK_ATTR_DOMAIN,
NETWORK_ATTR_TUNNELS,
+ NETWORK_ATTR_LOCAL_NET,
NETWORK_ATTR_AUTH_CONNECT,
NETWORK_ATTR_PEER_DATA,
__NETWORK_ATTR_MAX,
diff --git a/pex.c b/pex.c
index 8a13c80..db143fc 100644
--- a/pex.c
+++ b/pex.c
@@ -740,8 +740,9 @@ network_pex_fd_cb(struct uloop_fd *fd, unsigned int events)
}
}
-void network_pex_create_host(struct network *net, union network_endpoint *ep,
- unsigned int timeout)
+struct network_pex_host *
+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;
@@ -768,6 +769,7 @@ void network_pex_create_host(struct network *net, union network_endpoint *ep,
out:
if (timeout && (new_host || host->timeout))
host->timeout = timeout + unet_gettime();
+ return host;
}
static void
@@ -812,6 +814,84 @@ network_pex_open_auth_connect(struct network *net)
}
+static void
+__network_pex_reload_iface(struct network *net, struct blob_attr *data)
+{
+ static const struct blobmsg_policy policy[] = {
+ { "address", BLOBMSG_TYPE_STRING },
+ { "mask", BLOBMSG_TYPE_INT32 },
+ };
+ struct network_pex_host *host;
+ struct blob_attr *tb[2], *cur;
+ size_t rem;
+
+ if (!data)
+ return;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ union network_endpoint ep = {};
+ uint32_t mask;
+
+ blobmsg_parse_attr(policy, ARRAY_SIZE(policy), tb, cur);
+ if (!tb[0] || !tb[1])
+ continue;
+
+ mask = blobmsg_get_u32(tb[1]);
+ if (mask >= 31 || !mask)
+ continue;
+
+ if (network_get_endpoint(&ep, AF_INET, blobmsg_get_string(tb[0]),
+ UNETD_GLOBAL_PEX_PORT, 0) < 0)
+ continue;
+
+ *(uint32_t *)&ep.in.sin_addr |= htonl((~0U) >> mask);
+ host = network_pex_create_host(net, &ep, 0);
+ host->interface = true;
+ }
+}
+
+static void
+__network_pex_reload(struct network *net)
+{
+ struct network_pex *pex = &net->pex;
+ struct network_pex_host *host, *tmp;
+ struct blob_attr *cur;
+ size_t rem;
+
+ if (!net->config.local_network)
+ return;
+
+ list_for_each_entry_safe(host, tmp, &pex->hosts, list)
+ if (host->interface)
+ network_pex_free_host(net, host);
+
+ blobmsg_for_each_attr(cur, net->config.local_network, rem) {
+ const char *name = blobmsg_get_string(cur);
+ struct blob_attr *addrs;
+
+ addrs = unetd_ubus_get_network_addr_list(name);
+ __network_pex_reload_iface(net, addrs);
+ }
+}
+
+static void
+network_pex_reload_cb(struct uloop_timeout *t)
+{
+ struct network *net;
+
+ avl_for_each_element(&networks, net, node)
+ __network_pex_reload(net);
+}
+
+void network_pex_reload(void)
+{
+ static struct uloop_timeout timer = {
+ .cb = network_pex_reload_cb,
+ };
+
+ uloop_timeout_set(&timer, 1);
+}
+
int network_pex_open(struct network *net)
{
struct network_host *local_host = net->net_config.local_host;
@@ -822,6 +902,7 @@ int network_pex_open(struct network *net)
int fd;
network_pex_open_auth_connect(net);
+ __network_pex_reload(net);
if (!local_host || !local_host->peer.pex_port)
return 0;
diff --git a/pex.h b/pex.h
index 271d998..f0173a6 100644
--- a/pex.h
+++ b/pex.h
@@ -18,6 +18,7 @@ struct network_pex_host {
uint64_t timeout;
uint64_t last_active;
uint64_t last_ping;
+ bool interface;
union network_endpoint endpoint;
};
@@ -76,11 +77,13 @@ 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_reload();
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);
+struct network_pex_host *
+network_pex_create_host(struct network *net, union network_endpoint *ep,
+ unsigned int timeout);
void network_stun_init(struct network *net);
void network_stun_free(struct network *net);
diff --git a/ubus.c b/ubus.c
index 2377acc..6e289da 100644
--- a/ubus.c
+++ b/ubus.c
@@ -8,6 +8,7 @@
#include "enroll.h"
static struct ubus_auto_conn conn;
+static struct ubus_subscriber sub;
static struct blob_buf b;
static int
@@ -446,6 +447,7 @@ ubus_connect_handler(struct ubus_context *ctx)
{
int ret;
+ ubus_register_subscriber(ctx, &sub);
ret = ubus_add_object(ctx, &unetd_object);
if (ret)
fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
@@ -514,6 +516,47 @@ void unetd_ubus_netifd_update(struct blob_attr *data)
ubus_invoke(&conn.ctx, id, "notify_proto", data, NULL, NULL, 5000);
}
+static void
+ubus_network_status_cb(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ static const struct blobmsg_policy policy =
+ { "ipv4-address", BLOBMSG_TYPE_ARRAY };
+ struct blob_attr *attr, *cur;
+ size_t rem;
+
+ blobmsg_parse_attr(&policy, 1, &attr, msg);
+ if (!attr)
+ return;
+
+ if (blobmsg_check_array(attr, BLOBMSG_TYPE_TABLE) < 0)
+ return;
+
+ blobmsg_for_each_attr(cur, attr, rem)
+ blobmsg_add_blob(&b, cur);
+}
+
+struct blob_attr *unetd_ubus_get_network_addr_list(const char *name)
+{
+ char *objname;
+ uint32_t id;
+ size_t len;
+
+ if (strlen(name) > 64)
+ return NULL;
+
+ len = sizeof("network.interface.") + strlen(name) + 1;
+ objname = alloca(len);
+ snprintf(objname, len, "network.interface.%s", name);
+
+ if (ubus_lookup_id(&conn.ctx, objname, &id))
+ return NULL;
+
+ blob_buf_init(&b, 0);
+ ubus_invoke(&conn.ctx, id, "status", b.head, ubus_network_status_cb, NULL, 10000);
+
+ return b.head;
+}
+
void unetd_ubus_netifd_add_route(struct network *net, union network_endpoint *ep)
{
uint32_t id;
@@ -543,8 +586,25 @@ void unetd_ubus_netifd_add_route(struct network *net, union network_endpoint *ep
ubus_invoke(&conn.ctx, id, "add_host_route", b.head, NULL, NULL, -1);
}
+static int
+unetd_netifd_sub_cb(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req,
+ const char *method, struct blob_attr *msg)
+{
+ network_pex_reload();
+ return 0;
+}
+
+static bool
+unetd_new_object_sub_cb(struct ubus_context *ctx, struct ubus_subscriber *sub, const char *path)
+{
+ return path && !strcmp(path, "network.interface");
+}
+
void unetd_ubus_init(void)
{
+ sub.cb = unetd_netifd_sub_cb;
+ sub.new_obj_cb = unetd_new_object_sub_cb;
conn.cb = ubus_connect_handler;
ubus_auto_connect(&conn);
}
diff --git a/ubus.h b/ubus.h
index 1c42894..90a6e76 100644
--- a/ubus.h
+++ b/ubus.h
@@ -11,6 +11,7 @@ void unetd_ubus_notify(const char *type, struct blob_attr *data);
void unetd_ubus_network_notify(struct network *net);
void unetd_ubus_netifd_update(struct blob_attr *data);
void unetd_ubus_netifd_add_route(struct network *net, union network_endpoint *ep);
+struct blob_attr *unetd_ubus_get_network_addr_list(const char *name);
#else
static inline void unetd_ubus_init(void)
{
@@ -27,6 +28,10 @@ static inline void unetd_ubus_netifd_update(struct blob_attr *data)
static inline void unetd_ubus_netifd_add_route(struct network *net, union network_endpoint *ep)
{
}
+static inline struct blob_attr *unetd_ubus_get_network_addr_list(const char *name)
+{
+ return NULL;
+}
#endif
#endif