From c293afa01c1328ee8a18fc407948d0529353d7eb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 27 Jan 2025 12:39:59 +0100 Subject: [PATCH] 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 --- network.c | 5 ++++ network.h | 2 ++ pex.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- pex.h | 7 +++-- ubus.c | 60 +++++++++++++++++++++++++++++++++++++++ ubus.h | 5 ++++ 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 -- 2.30.2