Enumerate Android interfaces without anet

anet's only reason to need -ldflags=-checklinkname=0 is a pair of
//go:linkname pulls that refresh the IPv6 zone caches inside net and
x/net after it enumerates interfaces. localAddrs never resolves a zone
and drops link-local addresses anyway, so nebula was paying for that
flag, and disabling the linker's check for the whole binary, for
nothing it used.

Replace the dependency with the part of anet that matters: an
RTM_GETADDR dump on a netlink socket that is never bound, and
SIOCGIFNAME to name each index. Both are permitted to Android apps,
and it is the same path Bionic's getifaddrs takes for app UIDs. It is
built only for android; every other platform, Linux included, keeps
net.Interfaces.

One dump yields every interface with its addresses, so reshape the
seam to a single enumerator returning localInterface values with a
deferred Addrs. Android hands back what it already has; every other
platform still only asks for the addresses of interfaces the allow
list accepts.

Take the bind-free path unconditionally on android. The sepolicy is
keyed to the app's target SDK rather than the OS release, detecting
either needs cgo, and the path is valid on every release.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B15ivF2aJUtLFdqJ4iz6zs
This commit is contained in:
JackDoanandClaude Fable 5.1 committed 2026-09-14 13:26:20 -05:00
1 parent 8589b76e1f
commit fcc6008a78
7 files changed
+250 -49

No files matched your search

+13 -6
View File
@@ -868,19 +868,26 @@ func (i *HostInfo) logger(l *slog.Logger) *slog.Logger {
// Utility functions
func localAddrs(l *slog.Logger, allowList *LocalAllowList) ([]netip.Addr, error) {
return collectLocalAddrs(l, allowList, localInterfaces, localInterfaceAddrs)
// localInterface is what localAddrs needs from a net.Interface, provided per platform by
// localInterfaces. Addrs is deferred so platforms where address lookup is a separate kernel round
// trip only pay for interfaces the allow list accepts.
type localInterface struct {
Name string
Addrs func() ([]net.Addr, error)
}
// collectLocalAddrs takes its enumerators as arguments so tests can drive the filtering and the
func localAddrs(l *slog.Logger, allowList *LocalAllowList) ([]netip.Addr, error) {
return collectLocalAddrs(l, allowList, localInterfaces)
}
// collectLocalAddrs takes its enumerator as an argument so tests can drive the filtering and the
// failure branches without depending on the addresses of whatever host they run on. It reports
// failures to the caller rather than logging them, because it runs on every lighthouse update and
// only the caller can tell a new failure from a repeat of the same one.
func collectLocalAddrs(
l *slog.Logger,
allowList *LocalAllowList,
interfaces func() ([]net.Interface, error),
interfaceAddrs func(*net.Interface) ([]net.Addr, error),
interfaces func() ([]localInterface, error),
) ([]netip.Addr, error) {
//FIXME: This function is pretty garbage
var finalAddrs []netip.Addr
@@ -902,7 +909,7 @@ func collectLocalAddrs(
if !allow {
continue
}
addrs, err := interfaceAddrs(&i)
addrs, err := i.Addrs()
if err != nil {
errs = append(errs, fmt.Errorf("failed to get addresses for %s: %w", i.Name, err))
continue