diff --git a/p2p/addrs.go b/p2p/addrs.go new file mode 100644 index 0000000..23a3e1b --- /dev/null +++ b/p2p/addrs.go @@ -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 +} diff --git a/p2p/addrs_linux.go b/p2p/addrs_linux.go new file mode 100644 index 0000000..4325c6c --- /dev/null +++ b/p2p/addrs_linux.go @@ -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 +} diff --git a/p2p/node.go b/p2p/node.go index b87af82..b78be23 100644 --- a/p2p/node.go +++ b/p2p/node.go @@ -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,