pex: track indirect hosts (reachable via gateway) as peers without adding them to wg
authorFelix Fietkau <nbd@nbd.name>
Mon, 21 Aug 2023 20:27:37 +0000 (22:27 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 21 Aug 2023 20:27:38 +0000 (22:27 +0200)
This allows other hosts to respond to them via global PEX, in order to help
them find their gateway

Signed-off-by: Felix Fietkau <nbd@nbd.name>
host.c
host.h
pex-stun.c
pex.c
wg.c

diff --git a/host.c b/host.c
index e4e38d33079978b6f4f5c402c601aa1e1d9c15eb..2bfc5004cd810bbec62ae3b0f990d86fd72b843a 100644 (file)
--- a/host.c
+++ b/host.c
@@ -40,6 +40,9 @@ network_peer_update(struct vlist_tree *tree,
                        return;
        }
 
+       if ((h_new ? h_new : h_old)->indirect)
+               return;
+
        if (h_new)
                ret = wg_peer_update(net, h_new, h_old ? WG_PEER_UPDATE : WG_PEER_CREATE);
        else
@@ -335,10 +338,11 @@ __network_hosts_update_done(struct network *net, bool free_net)
        avl_for_each_element(&net->hosts, host, node) {
                if (host == local)
                        continue;
+               host->peer.indirect = false;
                if (host->gateway && strcmp(host->gateway, local_name) != 0)
-                       continue;
+                       host->peer.indirect = true;
                if (local->gateway && strcmp(local->gateway, network_host_name(host)) != 0)
-                       continue;
+                       host->peer.indirect = true;
                vlist_add(&net->peers, &host->peer.node, host->peer.key);
        }
 
@@ -407,7 +411,7 @@ network_hosts_connect_cb(struct uloop_timeout *t)
        wg_peer_refresh(net);
 
        vlist_for_each_element(&net->peers, peer, node) {
-               if (peer->state.connected)
+               if (peer->state.connected || peer->indirect)
                        continue;
 
                ep = network_peer_next_endpoint(peer);
diff --git a/host.h b/host.h
index cb4085eecf3fe9ab3c58ed836e682a13715c6d97..56d359c7e0580aa9df5243c6bc7ce29c97487416 100644 (file)
--- a/host.h
+++ b/host.h
@@ -23,6 +23,7 @@ struct network_peer {
        int port;
        int pex_port;
        bool dynamic;
+       bool indirect;
 
        struct {
                int connect_attempt;
index 444612bbeec1ac9a728593295424e156c4c6f844..0be3160326fcbe77a791d20a6bb488f922714b09 100644 (file)
@@ -22,7 +22,7 @@ static bool has_connected_peer(struct network *net, bool pex)
                if (pex && !peer->pex_port)
                        continue;
 
-               if (peer->state.connected)
+               if (peer->state.connected || peer->indirect)
                        return true;
        }
 
diff --git a/pex.c b/pex.c
index 7db9ab841a2f13a5e142ef08e9d6c7d70c1c8cba..61977cc007ce1f2cb67a0048d0037a0a48340d6f 100644 (file)
--- a/pex.c
+++ b/pex.c
@@ -39,7 +39,7 @@ pex_msg_init_ext(struct network *net, uint8_t opcode, bool ext)
 }
 
 static struct network_peer *
-pex_msg_peer(struct network *net, const uint8_t *id)
+pex_msg_peer(struct network *net, const uint8_t *id, bool allow_indirect)
 {
        struct network_peer *peer;
        uint8_t key[WG_KEY_LEN] = {};
@@ -50,6 +50,8 @@ pex_msg_peer(struct network *net, const uint8_t *id)
                D_NET(net, "can't find peer %s", pex_peer_id_str(id));
                return NULL;
        }
+       if (peer->indirect && !allow_indirect)
+               return NULL;
 
        return peer;
 }
@@ -154,7 +156,7 @@ network_pex_handle_endpoint_change(struct network *net, struct network_peer *pee
        struct network_peer *cur;
 
        vlist_for_each_element(&net->peers, cur, node) {
-               if (cur == peer || !cur->state.connected)
+               if (cur == peer || !cur->state.connected || cur->indirect)
                        continue;
 
                pex_msg_init(net, PEX_MSG_NOTIFY_PEERS);
@@ -483,7 +485,7 @@ network_pex_recv_peers(struct network *net, struct network_peer *peer,
                        continue;
                }
 
-               cur = pex_msg_peer(net, data->peer_id);
+               cur = pex_msg_peer(net, data->peer_id, false);
                if (!cur || cur == peer)
                        continue;
 
@@ -507,7 +509,7 @@ network_pex_recv_query(struct network *net, struct network_peer *peer,
 
        pex_msg_init(net, PEX_MSG_NOTIFY_PEERS);
        for (; len >= 8; data += 8, len -= 8) {
-               cur = pex_msg_peer(net, data);
+               cur = pex_msg_peer(net, data, false);
                if (!cur || !cur->state.connected)
                        continue;
 
@@ -717,7 +719,7 @@ network_pex_fd_cb(struct uloop_fd *fd, unsigned int events)
                if (!hdr)
                        continue;
 
-               peer = pex_msg_peer(net, hdr->id);
+               peer = pex_msg_peer(net, hdr->id, false);
                if (!peer)
                        continue;
 
@@ -958,7 +960,7 @@ global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr)
        case PEX_MSG_PONG:
                break;
        case PEX_MSG_UPDATE_REQUEST:
-               peer = pex_msg_peer(net, hdr->id);
+               peer = pex_msg_peer(net, hdr->id, true);
                network_pex_recv_update_request(net, peer, data, hdr->len,
                                                addr);
                break;
@@ -974,7 +976,7 @@ global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr)
                ep_idx = ENDPOINT_TYPE_ENDPOINT_PORT_NOTIFY;
                fallthrough;
        case PEX_MSG_ENDPOINT_NOTIFY:
-               peer = pex_msg_peer(net, hdr->id);
+               peer = pex_msg_peer(net, hdr->id, true);
                if (!peer)
                        break;
 
diff --git a/wg.c b/wg.c
index 64687f181983c351e32d44a1aa587c3db844c2f5..1f80e00826c354e4558a60e8dbf970134d158bde 100644 (file)
--- a/wg.c
+++ b/wg.c
@@ -47,7 +47,7 @@ struct network_peer *wg_peer_update_start(struct network *net, const uint8_t *ke
        struct network_peer *peer;
 
        peer = vlist_find(&net->peers, key, peer, node);
-       if (!peer)
+       if (!peer || peer->indirect)
                return NULL;
 
        peer->state.handshake = false;