如何在Linux中异步检查ipv6网络接口是否将状态从暂定状态更改为“有效”状态?

时间:2019-04-10 13:49:59

标签: linux sockets linux-kernel netlink

在分配IPv6地址之前和之后,它会经历各种状态,例如临时地址,重复地址和首选地址。这些地址状态适用于手动和自动配置的地址。 我在临时状态下使用网络接口时遇到对服务器的请求无限期阻塞的情况。 (从python脚本中调用rdate实用程序时)。通过实验,我设法得出结论,当接口的暂定状态是问题时调用rdate。

我看到了

ip-monitor
可以使用

命令并通过AF_NETLINK套接字在此处找到一些有趣的想法 On Linux: how can I programmatically determine if a NIC interface is enabled and plugged in?

我正在尝试设置一些异步调用(最好在python3中),一旦接口准备好并且rdate可以恢复,它将返回。而netlink套接字似乎只是解决问题的工具。 阅读this和netlink(7)后,我发现我需要类似的东西

s = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

但是我找不到从套接字获得输出后要检查的结构域/设备标志的正确信息。 在netdevice(7)中我发现了

IFF_UP            Interface is running.

但是我不确定在暂定状态下这是否也不会成立。

当然,最简单的方法就是循环睡眠并通过

检查
ip a show dev devName

直到状态有效为止,但在异步调用失败的情况下,我将其保留为最后手段。

1 个答案:

答案 0 :(得分:1)

如果要监视IPv6地址的更改和状态,可以采用您提到的我的example

只要您只对IPv6地址通知感兴趣,则应替换以下字符串:

local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;

与此:

local.nl_groups = RTMGRP_IPV6_IFADDR;

如果是RTM_NEWADDR / RTM_DELADDR,这是您应该做的事情:

struct ifaddrmsg *ifa = NLMSG_DATA(h);
struct rtattr *tb[IFLA_MAX + 1];

parseRtattr(tb, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));

if (!tb[IFA_LOCAL]) {
    tb[IFA_LOCAL] = tb[IFA_ADDRESS];
}

if (!tb[IFA_ADDRESS]) {
    tb[IFA_ADDRESS] = tb[IFA_LOCAL];
}

char ifAddress[INET6_ADDRSTRLEN];

switch (h->nlmsg_type) {
    case RTM_NEWADDR:
        if (tb[IFA_LOCAL]) {
            inet_ntop(AF_INET6, RTA_DATA(tb[IFA_LOCAL]), ifAddress, sizeof(ifAddress));
            printf("New local IPv6 address: %s\n", ifAddress);
        } else if (tb[IFA_BROADCAST]) {
            inet_ntop(AF_INET6, RTA_DATA(tb[IFA_BROADCAST]), ifAddress, sizeof(ifAddress));
            printf("New local IPv6 address: %s\n", ifAddress);
        } else if (tb[IFA_ANYCAST]) {
            inet_ntop(AF_INET6, RTA_DATA(tb[IFA_ANYCAST]), ifAddress, sizeof(ifAddress));
            printf("New anycast IPv6 address: %s\n", ifAddress);
        }

        if (tb[IFA_CACHEINFO]) {
            struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);

            if (ci->ifa_valid == 0xFFFFFFFFU) {
                printf("ifa_valid infinity\n");
            } else {
                printf("ifa_valid = %u sec\n", ci->ifa_valid);
            }

            if (ci->ifa_prefered == 0xFFFFFFFFU) {
                printf("ifa_prefered = %u sec\n", ci->ifa_prefered);
            }
        }

        break;

    case RTM_DELADDR:
        printf("IPv6 address was deleted\n");
        break;
}

这是一个快速而肮脏的示例,但是您应该了解它是如何工作的。 在此示例中,我们处理netlink消息中的ifaddrmsg数据,获取分配的ipv6地址。

也许最有趣的部分是IFA_CACHEINFO。 在这一点上,我们可以检查地址缓存并获取一些有关地址的有效和首选状态的有用信息。 如您所见,可能有一些设置的超时或无穷大值。 您可以使用网络接口来发现IPv6地址和IFA_CACHEINFO状态的不同状态。