Skip to content

Commit 412d030

Browse files
committed
network: prevent adding endpoint routes for addresses on the network
Sometimes a peer might be reachable only over another peer. In that case PEX could announce an endpoint address already covered by the network routes. When connecting, asking netifd to route that address breaks access, since it's only reachable over unet. Detect this case and skip the netifd host route request. Signed-off-by: Felix Fietkau <[email protected]>
1 parent 6c888f8 commit 412d030

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

host.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,8 @@ network_hosts_connect_cb(struct uloop_timeout *t)
414414
if (!ep)
415415
continue;
416416

417-
if (memcmp(ep, &peer->state.endpoint, sizeof(*ep)) != 0)
417+
if (memcmp(ep, &peer->state.endpoint, sizeof(*ep)) != 0 &&
418+
!network_skip_endpoint_route(net, ep))
418419
unetd_ubus_netifd_add_route(net, ep);
419420

420421
wg_peer_connect(net, peer, ep);

network.c

+78
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,84 @@ network_fill_subnets(struct network *net, struct blob_buf *buf)
363363
__network_fill_subnets(net, buf, true);
364364
}
365365

366+
static bool
367+
__network_skip_endpoint_route(struct network *net, struct network_host *host,
368+
union network_endpoint *ep)
369+
{
370+
bool ipv6 = ep->sa.sa_family == AF_INET6;
371+
uint32_t *subnet32, *addr32, mask32;
372+
union network_addr addr = {};
373+
struct blob_attr *cur;
374+
int mask, rem;
375+
376+
blobmsg_for_each_attr(cur, host->peer.ipaddr, rem) {
377+
const char *str = blobmsg_get_string(cur);
378+
379+
if (!!strchr(str, ':') != ipv6)
380+
continue;
381+
382+
if (inet_pton(ep->sa.sa_family, str, &addr) != 1)
383+
continue;
384+
385+
if (ipv6) {
386+
if (!memcmp(&addr.in6, &ep->in6.sin6_addr, sizeof(addr.in6)))
387+
return true;
388+
} else {
389+
if (!memcmp(&addr.in, &ep->in.sin_addr, sizeof(addr.in)))
390+
return true;
391+
}
392+
}
393+
394+
if (ipv6)
395+
addr32 = (uint32_t *)&ep->in6.sin6_addr;
396+
else
397+
addr32 = (uint32_t *)&ep->in.sin_addr;
398+
399+
subnet32 = (uint32_t *)&addr;
400+
blobmsg_for_each_attr(cur, host->peer.subnet, rem) {
401+
const char *str = blobmsg_get_string(cur);
402+
int i;
403+
404+
if (!!strchr(str, ':') != ipv6)
405+
continue;
406+
407+
if (network_get_subnet(ep->sa.sa_family, &addr, &mask, str))
408+
continue;
409+
410+
if (mask <= 1)
411+
continue;
412+
413+
for (i = 0; i < (ipv6 ? 4 : 1); i++) {
414+
int cur_mask = mask > 32 ? 32 : mask;
415+
416+
if (mask > 32)
417+
mask -= 32;
418+
else
419+
mask = 0;
420+
421+
mask32 = ~0ULL << (32 - cur_mask);
422+
if (ntohl(subnet32[i] ^ addr32[i]) & mask32)
423+
continue;
424+
}
425+
426+
return true;
427+
}
428+
429+
return false;
430+
}
431+
432+
bool network_skip_endpoint_route(struct network *net, union network_endpoint *ep)
433+
{
434+
struct network_host *host;
435+
436+
avl_for_each_element(&net->hosts, host, node)
437+
if (__network_skip_endpoint_route(net, host, ep))
438+
return true;
439+
440+
return false;
441+
}
442+
443+
366444
static void
367445
network_do_update(struct network *net, bool up)
368446
{

network.h

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ static inline const char *network_name(struct network *net)
100100
return net->node.key;
101101
}
102102

103+
bool network_skip_endpoint_route(struct network *net, union network_endpoint *ep);
103104
void network_fill_host_addr(union network_addr *addr, uint8_t *key);
104105
int network_save_dynamic(struct network *net);
105106
void network_soft_reload(struct network *net);

0 commit comments

Comments
 (0)