p2p: filter tunnel device IPs from mDNS-advertised addresses

Co-authored-by: DavHau <hsngrmpf+github@gmail.com>
This commit is contained in:
Max 2026-06-06 19:19:52 +02:00
parent 1e757953bc
commit c7b48dc2d7
3 changed files with 94 additions and 1 deletions

53
p2p/addrs.go Normal file
View File

@ -0,0 +1,53 @@
package p2p
import (
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)
// resolveListenAddrs expands unspecified listen addresses (0.0.0.0, ::) into
// concrete per-interface addresses of physical interfaces.
// Specific addresses are returned as-is.
func resolveListenAddrs(addrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
physAddrs, err := physicalInterfaceAddrs()
if err != nil {
// If we can't enumerate interfaces, fall back to the
// original (unresolved) addresses.
logger.With(err).Warn("failed to enumerate interfaces")
return addrs, nil
}
if len(physAddrs) == 0 {
return addrs, nil
}
ifaceAddrs, err := manet.InterfaceMultiaddrs()
if err != nil {
return addrs, nil
}
filtered := ma.FilterAddrs(
ifaceAddrs,
func(addr ma.Multiaddr) bool {
return !manet.IsIPLoopback(addr)
},
func(addr ma.Multiaddr) bool {
ipAddr, err := manet.ToIP(addr)
if err != nil {
return true
} else {
for _, physAddr := range physAddrs {
if physAddr.Equal(ipAddr) {
return true
}
}
return false
}
},
)
resolved, err := manet.ResolveUnspecifiedAddresses(addrs, filtered)
if err != nil {
return addrs, nil
}
return resolved, nil
}

31
p2p/addrs_linux.go Normal file
View File

@ -0,0 +1,31 @@
//go:build linux
package p2p
import (
"net"
"github.com/vishvananda/netlink"
)
// physicalInterfaceAddrs returns all IP addresses assigned to physical interfaces.
func physicalInterfaceAddrs() ([]net.IP, error) {
links, err := netlink.LinkList()
if err != nil {
return nil, err
}
var ips []net.IP
for _, link := range links {
if link.Type() != "device" {
continue
}
addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
if err != nil {
continue
}
for _, addr := range addrs {
ips = append(ips, addr.IP)
}
}
return ips, nil
}

View File

@ -138,10 +138,19 @@ func CreateNode(ctx context.Context, privateKey crypto.PrivKey, listenAddreses [
peerChan := make(chan peer.AddrInfo)
logger.Debug("Creating libp2p node")
// Resolve unspecified listen addresses (0.0.0.0, ::) to concrete
// per-interface IPs, excluding tunnel devices to prevent advertising
// tunnel IPs via mDNS (VPN-over-VPN loop prevention).
resolved, err := resolveListenAddrs(listenAddreses)
if err != nil {
return nil, nil, err
}
// Create libp2p node
basicHost, err := libp2p.New(
maybePrivateNet,
libp2p.ListenAddrs(listenAddreses...),
libp2p.ListenAddrs(resolved...),
libp2p.Identity(privateKey),
libp2p.UserAgent("hyprspace"),
libp2p.DefaultSecurity,