Skip to content

Commit

Permalink
network: add support for configuring extra peers via a separate json …
Browse files Browse the repository at this point in the history
…file

Peers added to this file are only used locally and not advertised on the
network. Peers should use IP addresses that are part of locally announced
or otherwise configured subnets

Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
nbd168 committed Sep 1, 2022
1 parent 8ad1197 commit 26dc527
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 53 deletions.
8 changes: 8 additions & 0 deletions examples/net0.peers
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"test": {
"key": "uEXsoKYc31VH/kzv55eHVmKlzvmoGOPwA7xeTjGgLXc=",
"endpoint": "192.168.1.4:51830",
"ipaddr": [ "192.168.99.1" ]
}
}

1 change: 1 addition & 0 deletions examples/test-net0.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ ip link add dev $ifname type wireguard > /dev/null 2>&1
"tunnels": {
"vx0": "l2-tunnel"
},
"peer_data": [ "'"$PWD/net0.peers"'" ],
"update-cmd": "'"$PWD/../scripts/update-cmd.pl"'"
}'
179 changes: 129 additions & 50 deletions host.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
*/
#include <libubox/avl-cmp.h>
#include <libubox/blobmsg_json.h>
#include "unetd.h"

static LIST_HEAD(old_hosts);
static struct blob_buf b;

static int avl_key_cmp(const void *k1, const void *k2, void *ptr)
{
Expand Down Expand Up @@ -83,41 +85,43 @@ network_host_add_group(struct network *net, struct network_host *host,
group->members[group->n_members - 1] = host;
}

enum {
NETWORK_HOST_KEY,
NETWORK_HOST_GROUPS,
NETWORK_HOST_IPADDR,
NETWORK_HOST_SUBNET,
NETWORK_HOST_PORT,
NETWORK_HOST_PEX_PORT,
NETWORK_HOST_ENDPOINT,
NETWORK_HOST_GATEWAY,
__NETWORK_HOST_MAX
};

static const struct blobmsg_policy host_policy[__NETWORK_HOST_MAX] = {
[NETWORK_HOST_KEY] = { "key", BLOBMSG_TYPE_STRING },
[NETWORK_HOST_GROUPS] = { "groups", BLOBMSG_TYPE_ARRAY },
[NETWORK_HOST_IPADDR] = { "ipaddr", BLOBMSG_TYPE_ARRAY },
[NETWORK_HOST_SUBNET] = { "subnet", BLOBMSG_TYPE_ARRAY },
[NETWORK_HOST_PORT] = { "port", BLOBMSG_TYPE_INT32 },
[NETWORK_HOST_PEX_PORT] = { "peer-exchange-port", BLOBMSG_TYPE_INT32 },
[NETWORK_HOST_ENDPOINT] = { "endpoint", BLOBMSG_TYPE_STRING },
[NETWORK_HOST_GATEWAY] = { "gateway", BLOBMSG_TYPE_STRING },
};

static void
network_host_create(struct network *net, struct blob_attr *attr)
network_host_create(struct network *net, struct blob_attr *attr, bool dynamic)
{
enum {
NETWORK_HOST_KEY,
NETWORK_HOST_GROUPS,
NETWORK_HOST_IPADDR,
NETWORK_HOST_SUBNET,
NETWORK_HOST_PORT,
NETWORK_HOST_PEX_PORT,
NETWORK_HOST_ENDPOINT,
NETWORK_HOST_GATEWAY,
__NETWORK_HOST_MAX
};
static const struct blobmsg_policy policy[__NETWORK_HOST_MAX] = {
[NETWORK_HOST_KEY] = { "key", BLOBMSG_TYPE_STRING },
[NETWORK_HOST_GROUPS] = { "groups", BLOBMSG_TYPE_ARRAY },
[NETWORK_HOST_IPADDR] = { "ipaddr", BLOBMSG_TYPE_ARRAY },
[NETWORK_HOST_SUBNET] = { "subnet", BLOBMSG_TYPE_ARRAY },
[NETWORK_HOST_PORT] = { "port", BLOBMSG_TYPE_INT32 },
[NETWORK_HOST_PEX_PORT] = { "peer-exchange-port", BLOBMSG_TYPE_INT32 },
[NETWORK_HOST_ENDPOINT] = { "endpoint", BLOBMSG_TYPE_STRING },
[NETWORK_HOST_GATEWAY] = { "gateway", BLOBMSG_TYPE_STRING },
};
struct blob_attr *tb[__NETWORK_HOST_MAX];
struct blob_attr *cur, *ipaddr, *subnet;
uint8_t key[CURVE25519_KEY_SIZE];
struct network_host *host;
struct network_host *host = NULL;
struct network_peer *peer;
int ipaddr_len, subnet_len;
const char *name, *endpoint, *gateway;
char *name_buf, *endpoint_buf, *gateway_buf;
const char *endpoint, *gateway;
char *endpoint_buf, *gateway_buf;
int rem;

blobmsg_parse(policy, __NETWORK_HOST_MAX, tb, blobmsg_data(attr), blobmsg_len(attr));
blobmsg_parse(host_policy, __NETWORK_HOST_MAX, tb, blobmsg_data(attr), blobmsg_len(attr));

if (!tb[NETWORK_HOST_KEY])
return;
Expand All @@ -137,7 +141,7 @@ network_host_create(struct network *net, struct blob_attr *attr)
else
endpoint = NULL;

if ((cur = tb[NETWORK_HOST_GATEWAY]) != NULL)
if (!dynamic && (cur = tb[NETWORK_HOST_GATEWAY]) != NULL)
gateway = blobmsg_get_string(cur);
else
gateway = NULL;
Expand All @@ -146,18 +150,41 @@ network_host_create(struct network *net, struct blob_attr *attr)
sizeof(key)) != sizeof(key))
return;

name = blobmsg_name(attr);
host = avl_find_element(&net->hosts, name, host, node);
if (host)
return;
if (dynamic) {
struct network_dynamic_peer *dyn_peer;

/* don't override/alter hosts configured via network data */
peer = vlist_find(&net->peers, key, peer, node);
if (peer && !peer->dynamic &&
peer->node.version == net->peers.version)
return;

dyn_peer = calloc_a(sizeof(*dyn_peer),
&ipaddr, ipaddr_len,
&subnet, subnet_len,
&endpoint_buf, endpoint ? strlen(endpoint) + 1 : 0);
list_add_tail(&dyn_peer->list, &net->dynamic_peers);
peer = &dyn_peer->peer;
} else {
const char *name;
char *name_buf;

name = blobmsg_name(attr);
host = avl_find_element(&net->hosts, name, host, node);
if (host)
return;

host = calloc_a(sizeof(*host),
&name_buf, strlen(name) + 1,
&ipaddr, ipaddr_len,
&subnet, subnet_len,
&endpoint_buf, endpoint ? strlen(endpoint) + 1 : 0,
&gateway_buf, gateway ? strlen(endpoint) + 1 : 0);
peer = &host->peer;
host = calloc_a(sizeof(*host),
&name_buf, strlen(name) + 1,
&ipaddr, ipaddr_len,
&subnet, subnet_len,
&endpoint_buf, endpoint ? strlen(endpoint) + 1 : 0,
&gateway_buf, gateway ? strlen(endpoint) + 1 : 0);
host->node.key = strcpy(name_buf, name);
peer = &host->peer;
}

peer->dynamic = dynamic;
if ((cur = tb[NETWORK_HOST_IPADDR]) != NULL && ipaddr_len)
peer->ipaddr = memcpy(ipaddr, cur, ipaddr_len);
if ((cur = tb[NETWORK_HOST_SUBNET]) != NULL && subnet_len)
Expand All @@ -172,16 +199,19 @@ network_host_create(struct network *net, struct blob_attr *attr)
peer->pex_port = net->net_config.pex_port;
if (endpoint)
peer->endpoint = strcpy(endpoint_buf, endpoint);
if (gateway)
host->gateway = strcpy(gateway_buf, gateway);
memcpy(peer->key, key, sizeof(key));
host->node.key = strcpy(name_buf, name);

memcpy(&peer->local_addr.network_id,
&net->net_config.addr.network_id,
sizeof(peer->local_addr.network_id));
network_fill_host_addr(&peer->local_addr, peer->key);

if (!host)
return;

if (gateway)
host->gateway = strcpy(gateway_buf, gateway);

blobmsg_for_each_attr(cur, tb[NETWORK_HOST_GROUPS], rem) {
if (!blobmsg_check_attr(cur, false) ||
blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
Expand All @@ -200,6 +230,36 @@ network_host_create(struct network *net, struct blob_attr *attr)
}
}

static void
network_hosts_load_dynamic_file(struct network *net, const char *file)
{
struct blob_attr *cur;
int rem;

blob_buf_init(&b, 0);

if (!blobmsg_add_json_from_file(&b, file))
return;

blob_for_each_attr(cur, b.head, rem)
network_host_create(net, cur, true);
}

static void
network_hosts_load_dynamic(struct network *net)
{
struct blob_attr *cur;
int rem;

if (!net->config.peer_data)
return;

blobmsg_for_each_attr(cur, net->config.peer_data, rem)
network_hosts_load_dynamic_file(net, blobmsg_get_string(cur));

blob_buf_free(&b);
}

void network_hosts_update_start(struct network *net)
{
struct network_host *host, *htmp;
Expand All @@ -216,11 +276,18 @@ void network_hosts_update_start(struct network *net)
vlist_update(&net->peers);
}

void network_hosts_update_done(struct network *net)
static void
__network_hosts_update_done(struct network *net, bool free_net)
{
struct network_host *local, *host, *tmp;
struct network_dynamic_peer *dyn, *dyn_tmp;
LIST_HEAD(old_dynamic);
const char *local_name;

list_splice_init(&net->dynamic_peers, &old_dynamic);
if (free_net)
goto out;

local = net->net_config.local_host;
if (!local)
goto out;
Expand All @@ -240,20 +307,36 @@ void network_hosts_update_done(struct network *net)
vlist_add(&net->peers, &host->peer.node, host->peer.key);
}

network_hosts_load_dynamic(net);

list_for_each_entry(dyn, &net->dynamic_peers, list)
vlist_add(&net->peers, &dyn->peer.node, &dyn->peer.key);

out:
vlist_flush(&net->peers);

list_for_each_entry_safe(dyn, dyn_tmp, &old_dynamic, list) {
list_del(&dyn->list);
free(dyn);
}

list_for_each_entry_safe(host, tmp, &old_hosts, node.list) {
list_del(&host->node.list);
free(host);
}
}

void network_hosts_update_done(struct network *net)
{
return __network_hosts_update_done(net, false);
}

static void
network_hosts_connect_cb(struct uloop_timeout *t)
{
struct network *net = container_of(t, struct network, connect_timer);
struct network_host *host;
struct network_peer *peer;
union network_endpoint *ep;

avl_for_each_element(&net->hosts, host, node)
Expand All @@ -265,12 +348,7 @@ network_hosts_connect_cb(struct uloop_timeout *t)

wg_peer_refresh(net);

avl_for_each_element(&net->hosts, host, node) {
struct network_peer *peer = &host->peer;

if (!network_host_is_peer(host))
continue;

vlist_for_each_element(&net->peers, peer, node) {
if (peer->state.connected)
continue;

Expand Down Expand Up @@ -300,11 +378,12 @@ void network_hosts_add(struct network *net, struct blob_attr *hosts)
int rem;

blobmsg_for_each_attr(cur, hosts, rem)
network_host_create(net, cur);
network_host_create(net, cur, false);
}

void network_hosts_init(struct network *net)
{
INIT_LIST_HEAD(&net->dynamic_peers);
avl_init(&net->hosts, avl_strcmp, false, NULL);
vlist_init(&net->peers, avl_key_cmp, network_peer_update);
avl_init(&net->groups, avl_strcmp, false, NULL);
Expand All @@ -315,5 +394,5 @@ void network_hosts_free(struct network *net)
{
uloop_timeout_cancel(&net->connect_timer);
network_hosts_update_start(net);
network_hosts_update_done(net);
__network_hosts_update_done(net, true);
}
9 changes: 8 additions & 1 deletion host.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct network_peer {
struct blob_attr *subnet;
int port;
int pex_port;
bool dynamic;

struct {
int connect_attempt;
Expand All @@ -34,6 +35,12 @@ struct network_peer {
} state;
};

struct network_dynamic_peer {
struct list_head list;

struct network_peer peer;
};

struct network_host {
struct avl_node node;

Expand Down Expand Up @@ -66,7 +73,7 @@ static inline const char *network_peer_name(struct network_peer *peer)
{
struct network_host *host;

if (!peer)
if (!peer || peer->dynamic)
return "(none)";

host = container_of(peer, struct network_host, peer);
Expand Down
5 changes: 5 additions & 0 deletions network.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const struct blobmsg_policy network_policy[__NETWORK_ATTR_MAX] = {
[NETWORK_ATTR_UPDATE_CMD] = { "update-cmd", BLOBMSG_TYPE_STRING },
[NETWORK_ATTR_TUNNELS] = { "tunnels", BLOBMSG_TYPE_TABLE },
[NETWORK_ATTR_AUTH_CONNECT] = { "auth_connect", BLOBMSG_TYPE_ARRAY },
[NETWORK_ATTR_PEER_DATA] = { "peer_data", BLOBMSG_TYPE_ARRAY },
};

AVL_TREE(networks, avl_strcmp, false, NULL);
Expand Down Expand Up @@ -537,6 +538,10 @@ network_set_config(struct network *net, struct blob_attr *config)
blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
net->config.auth_connect = cur;

if ((cur = tb[NETWORK_ATTR_PEER_DATA]) != NULL &&
blobmsg_check_array(cur, BLOBMSG_TYPE_STRING) > 0)
net->config.peer_data = cur;

if ((cur = tb[NETWORK_ATTR_KEY]) == NULL)
goto invalid;

Expand Down
4 changes: 4 additions & 0 deletions network.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct network {
struct blob_attr *tunnels;
struct blob_attr *net_data;
struct blob_attr *auth_connect;
struct blob_attr *peer_data;
} config;

struct {
Expand All @@ -58,6 +59,8 @@ struct network {

int ifindex;
struct network_host *prev_local_host;

struct list_head dynamic_peers;
struct avl_tree hosts;
struct vlist_tree peers;

Expand All @@ -82,6 +85,7 @@ enum {
NETWORK_ATTR_DOMAIN,
NETWORK_ATTR_TUNNELS,
NETWORK_ATTR_AUTH_CONNECT,
NETWORK_ATTR_PEER_DATA,
__NETWORK_ATTR_MAX,
};

Expand Down
Loading

0 comments on commit 26dc527

Please sign in to comment.