针对 Android API 30 时无法绑定 () netlink 套接字

Jor*_*ndo 4 android android-ndk netlink

我已经使用以下命令创建一个 netlink 套接字已经有一段时间了:

NetLinkLocalNetworkInfo::NetLinkSocket::NetLinkSocket() :
fd(0)
{
    fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if(fd < 0)
    {
        throw std::runtime_error("Failed to create NetLink socket");
    }

    struct sockaddr_nl addr;
    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;

    int err = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    if(err < 0)
    {
        close(fd);
        throw std::runtime_error("Failed to bind NetLink socket");
    }
}
Run Code Online (Sandbox Code Playgroud)

这用于我们使用ICE执行自动 NAT 遍历的网络逻辑的一部分。当针对 API 30 时,调用bindnow 返回 -1 并且errno“权限被拒绝”。

现在,针对 API 30 的应用程序的行为发生了变化,这意味着这bind()是一个受限的调用。(谷歌开发者页面上有一个文档,但如果我能再次找到它,我就该死了。它曾经在这里,但自从几个月前我第一次遇到这个问题以来,该页面已经改变了。)应该会影响所有针对 API 30 的应用程序,但我发现只有针对 API 30在运行 Android 11 的设备(物理设备或模拟器)上运行的应用程序才会受到影响。我第一次遇到这种情况时的笔记也提到了建议使用ConnectivityManager 的文章,但这需要想出某种方法将信息传递给本机代码,或者让本机代码通过 JNI 调用 Android 平台代码。如果这是必须发生的事情,我对其中任何一个都很好,但我想知道是否还有我不知道的另一种选择。

我也看到了这个类似的问题,但其中一个答案中有一个链接表明它应该是可能的,至少在 API 30 之前是这样。

现在我们不允许打电话bind(),还有什么其他选择?

Jor*_*ndo 6

找到了解决这个问题的方法。事实证明,我们使用 NetLink 套接字来发现网络接口地址信息,因为ifaddrs当时在 Android 上不可用(或者,未完全实现,或类似的东西 - 这里没有人能确切地记得为什么我们不能使用它)。自 API 24ifaddrs起现已可用。我们将实现切换为使用ifaddrs. 只要您支持的最低版本是 API 24 或更高版本,您就可以执行相同的操作。

  • `ifaddrs` 是 NDK 中的一个实用程序 (https://android.googlesource.com/platform/prebuilts/ndk/+/dev/platform/sysroot/usr/include/ifaddrs.h)。敲击的‘ifaddrs’包含了接口信息。您基本上只需创建一个“ifaddrs”结构,然后将其传递给“getifaddrs()”,它将填充字段。`ifa_name` 是接口名称,`ifa_addr` 是 `sockaddr` 等。`ifaddrs.h` 标头包含您需要的文档。 (2认同)