From 035fcc56ef6020ac55bf3be4a175f8776170c54c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 16 Sep 2022 20:14:14 +0200 Subject: [PATCH] host: keep multiple endpoint candidates, one for each type Some discovery methods might be more reliable than others. Avoid having them overwrite each other's discovery result Signed-off-by: Felix Fietkau --- host.c | 38 +++++++++++++++++++++++++++++++------- host.h | 11 ++++++++++- pex.c | 10 +++++++--- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/host.c b/host.c index e0c5827..aa3c5b2 100644 --- a/host.c +++ b/host.c @@ -360,6 +360,35 @@ void network_hosts_update_done(struct network *net) return __network_hosts_update_done(net, false); } +static union network_endpoint * +network_peer_next_endpoint(struct network_peer *peer) +{ + union network_endpoint *ep; + int i; + + for (i = 0; i < __ENDPOINT_TYPE_MAX; i++) { + int cur = peer->state.next_endpoint_idx; + + if (++peer->state.next_endpoint_idx == __ENDPOINT_TYPE_MAX) + peer->state.next_endpoint_idx = 0; + + ep = &peer->state.next_endpoint[cur]; + if (cur == ENDPOINT_TYPE_STATIC && + (!peer->endpoint || + network_get_endpoint(ep, AF_UNSPEC, peer->endpoint, peer->port, + peer->state.connect_attempt++))) + continue; + + if (!ep->sa.sa_family) + continue; + + return ep; + } + + return NULL; +} + + static void network_hosts_connect_cb(struct uloop_timeout *t) { @@ -381,13 +410,8 @@ network_hosts_connect_cb(struct uloop_timeout *t) if (peer->state.connected) continue; - ep = &peer->state.next_endpoint; - if (peer->endpoint && - network_get_endpoint(ep, AF_UNSPEC, peer->endpoint, peer->port, - peer->state.connect_attempt++)) - continue; - - if (!ep->sa.sa_family) + ep = network_peer_next_endpoint(peer); + if (!ep) continue; if (memcmp(ep, &peer->state.endpoint, sizeof(*ep)) != 0) diff --git a/host.h b/host.h index 5eed711..b3fef03 100644 --- a/host.h +++ b/host.h @@ -5,6 +5,14 @@ #ifndef __UNETD_HOST_H #define __UNETD_HOST_H +enum peer_endpoint_type { + ENDPOINT_TYPE_STATIC, + ENDPOINT_TYPE_PEX, + ENDPOINT_TYPE_ENDPOINT_NOTIFY, + ENDPOINT_TYPE_ENDPOINT_PORT_NOTIFY, + __ENDPOINT_TYPE_MAX, +}; + struct network_peer { struct vlist_node node; uint8_t key[CURVE25519_KEY_SIZE]; @@ -25,7 +33,8 @@ struct network_peer { union network_addr local_ep_addr; union network_endpoint endpoint; - union network_endpoint next_endpoint; + uint8_t next_endpoint_idx; + union network_endpoint next_endpoint[__ENDPOINT_TYPE_MAX]; uint64_t last_ep_update; uint64_t rx_bytes; diff --git a/pex.c b/pex.c index 65cb1e5..b228576 100644 --- a/pex.c +++ b/pex.c @@ -485,7 +485,7 @@ network_pex_recv_peers(struct network *net, struct network_peer *peer, D_PEER(net, peer, "received peer address for %s", network_peer_name(cur)); flags = ntohs(data->flags); - ep = &cur->state.next_endpoint; + ep = &cur->state.next_endpoint[ENDPOINT_TYPE_PEX]; ep->sa.sa_family = (flags & PEER_EP_F_IPV6) ? AF_INET6 : AF_INET; addr = network_endpoint_addr(ep, &len); memcpy(addr, data->addr, len); @@ -904,6 +904,7 @@ global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr) char buf[INET6_ADDRSTRLEN]; void *data; int addr_len; + int ep_idx = ENDPOINT_TYPE_ENDPOINT_NOTIFY; if (stun_msg_is_valid(msg, msg_len)) { avl_for_each_element(&networks, net, node) @@ -949,6 +950,9 @@ global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr) case PEX_MSG_ENDPOINT_PORT_NOTIFY: if (hdr->len < sizeof(struct pex_endpoint_port_notify)) break; + + ep_idx = ENDPOINT_TYPE_ENDPOINT_PORT_NOTIFY; + fallthrough; case PEX_MSG_ENDPOINT_NOTIFY: peer = pex_msg_peer(net, hdr->id); if (!peer) @@ -958,14 +962,14 @@ global_pex_recv(void *msg, size_t msg_len, struct sockaddr_in6 *addr) inet_ntop(addr->sin6_family, network_endpoint_addr((void *)addr, &addr_len), buf, sizeof(buf))); - memcpy(&peer->state.next_endpoint, addr, sizeof(*addr)); + memcpy(&peer->state.next_endpoint[ep_idx], addr, sizeof(*addr)); if (hdr->opcode == PEX_MSG_ENDPOINT_PORT_NOTIFY) { struct pex_endpoint_port_notify *port = data; union network_endpoint host_ep = { .in6 = *addr }; - peer->state.next_endpoint.in.sin_port = port->port; + peer->state.next_endpoint[ep_idx].in.sin_port = port->port; if (net->pex.num_hosts < NETWORK_PEX_HOSTS_LIMIT) network_pex_create_host(net, &host_ep, 120); } -- 2.30.2