美文网首页我爱编程
翻译:How to detect IP address chan

翻译:How to detect IP address chan

作者: 东东东东东东丶 | 来源:发表于2018-06-21 19:13 被阅读0次

    Stack overflow地址:c++ - How to detect IP address change programmatically in Linux? - Stack Overflow

    翻译:

    有监测本机 IP地址修改的,使用C++在Linux上编程的方法吗?


    Answers1:

    在C语言中,我使用的获取当前IP的方法:

    int s;

    struct ifreq ifr = {};

    s = socket(PF_INET, SOCK_DGRAM, 0);

    strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));

    if (ioctl(s, SIOCGIFADDR, &ifr) >= 0)

    printf("%s\n",

      inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));

    使用你感兴趣的网卡代替"eth0"。你需要做的就是轮询检查网卡IP是否有改变。


    Answers2:

    你来这里,这不需要轮询。

    它只监听了 RTM_NEWADDR,但是它是很容易修改支持 RTM_DELADDR,如果你需要的话。

    #include

    #include

    #include

    #include

    #include

    #include

    int main()

    {

        struct sockaddr_nl addr;

        int sock, len;

        char buffer[4096];

        struct nlmsghdr *nlh;

        if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {

            perror("couldn't open NETLINK_ROUTE socket");

            return 1;

        }

        memset(&addr, 0, sizeof(addr));

        addr.nl_family = AF_NETLINK;

        addr.nl_groups = RTMGRP_IPV4_IFADDR;

        if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {

            perror("couldn't bind");

            return 1;

        }

        nlh = (struct nlmsghdr *)buffer;

        while ((len = recv(sock, nlh, 4096, 0)) > 0) {

            while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {

                if (nlh->nlmsg_type == RTM_NEWADDR) {

                    struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);

                    struct rtattr *rth = IFA_RTA(ifa);

                    int rtl = IFA_PAYLOAD(nlh);

                    while (rtl && RTA_OK(rth, rtl)) {

                        if (rth->rta_type == IFA_LOCAL) {

                            uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));

                            char name[IFNAMSIZ];

                            if_indextoname(ifa->ifa_index, name);

                            printf("%s is now %d.%d.%d.%d\n",

                                  name,

                                  (ipaddr >> 24) & 0xff,

                                  (ipaddr >> 16) & 0xff,

                                  (ipaddr >> 8) & 0xff,

                                  ipaddr & 0xff);

                        }

                        rth = RTA_NEXT(rth, rtl);

                    }

                }

                nlh = NLMSG_NEXT(nlh, len);

            }

        }

        return 0;

    }


    Answers3:

    没有一种很容易的方式。每个Linux发行版使用不同的地方存储IP地址等(如果你考虑UNIX的变体将会有更多的版本)。例如,你可以使用,/sbin/ifconfig来获取接口的IP地址,但是你甚至不能确定你能找到它。

    或者,给你一个可执行程序,你不得不建立一个线程在一定的时间周期内(比如5秒)获取数据,并中断进行输出。例如,如果你有桥梁,这可能会有所不同,但是这不是很容易的。

    我想到的另一个解决方案是,如果你有机会使用 GNOME或者其他像 KDE的发行版本,你可以依赖它们提供的消息/信息。例如,NetworkManager输出一个信号到  DBUS standard bus,当设备改变时。你需要为这些信号添加一个监听器,监听这里的信息(不立即工作,在这里是一个缓存)。请注意,当一个新接口添加或者其中一个接口修改IP地址时会有不同的消息。这是我现在能想到的最好的方法。


    Answers4:

    如果你得用户使用 NetworkManager,你可以轮询 NetworkManager.Connection.Active和 NetworkManager.IP4Config通过 D-Bus,获取更多确定信息。


    Answers5:

    如果 iproute2安装了,你可以在 2.6版本的内核上这么做:

    /sbin/ip monitor

    如果本地网卡的状态和地址改变的话,会输出到控制台上。你的程序可以读这个信息。

    你也可以使用其他类似 iproute2的低等级机制(我认为它是一个 netlink套接字)。


    Answers6:

    ste's建议使用 ioctl,使用 SIOCGIFADDR是技术正确的,不幸的是,它是不可行的对于现代的 Linux操作系统,这里一个网卡可以拥有多个地址在不使用子网卡的情况下(例如:eth0:1),就像现在已经过时的ifconfig所做的那样。

    你最好使用 getifaddrs(3),这是 glibc2.3提供的: http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html

    不幸的是它效率不高(你会得到所有网卡的一个链表,并且不得不遍历它找到那个你想要的网卡),但是大多数情况下你检查它不超过一分钟一次,这是可以接受的。


    Answers7:

    一个方法是写一个计划任务,它包含调用 gethost family的相关库函数。如果你使用 gethostbyname()你可以比较返回值中的 h_addr_list。具体细节看 man gethostbyname。

    如果你想要在你的程序中做这件事,创建一个线程做相同的事,然后睡眠一定的时间。


    Answers8:

    从 rtnetlink的man页引用:

    描述:

    Rtnetlink允许读取并修改内核路由表。它在内核中使用并在不同的子系统中通信,尽管它的用户空间通信的使用没有文档。网络路由,IP地址,link参数,相关设置,排队规则,流量类别和分组类别都可以被 NETLINK_ROUTE控制。它基于 netlink消息,看 netlink(7)获取更多的消息。


    Answers9:

    完整的C语言测试示例,并在不同的线程中进行通知:

    #include // AF_INET, socket(), bind()

    #include // struct ifaddrs, getifaddrs()

    #include // struct sockaddr_in

    #include // inet_ntoa(), htonl()

    #include // if_indextoname()

    #include

    #include

    #include

    #include

    #include

    typedef enum {

        IP_ADDR_ADD,

        IP_ADDR_REMOVE

    } ip_address_change_notification_type_t;

    typedef void (*ip_address_change_notification_callback_t)(ip_address_change_notification_type_t type, uint32_t ipaddr, void *userdata);

    static int ip_address_change_notification_socket = -1;

    static pthread_t ip_address_change_notification_thread;

    static ip_address_change_notification_callback_t ip_address_change_notification_callback;

    static void *ip_address_change_notification_callback_userdata;

    void *ip_address_change_notification_worker(void *arg)

    {

        fprintf(stderr, "ip_address_change_notification_worker entered.\n");

        if (ip_address_change_notification_socket == -1) {

            goto done;

        }

        char buffer[4096];

        struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;

        int len;

        while ((len = recv(ip_address_change_notification_socket, nlh, sizeof(buffer), 0)) > 0) {

            for (; (NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE); nlh = NLMSG_NEXT(nlh, len)) {

                if (nlh->nlmsg_type == RTM_NEWADDR) {

                    fprintf(stderr, "Netlink: RTM_NEWADDR\n");

                } else if (nlh->nlmsg_type == RTM_DELADDR) {

                    fprintf(stderr, "Netlink: RTM_DELADDR\n");

                } else {

                    fprintf(stderr, "Netlink: nlmsg_type=%d\n", nlh->nlmsg_type);

                    continue; // Some other kind of announcement.

                }

                struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh);

                struct rtattr *rth = IFA_RTA(ifa);

                int rtl = IFA_PAYLOAD(nlh);

                for (; rtl && RTA_OK(rth, rtl); rth = RTA_NEXT(rth,rtl)) {

                    char name[IFNAMSIZ];

                    uint32_t ipaddr;

                    if (rth->rta_type != IFA_LOCAL) continue;

                    ipaddr = *((uint32_t *)RTA_DATA(rth)); // In network byte-order.

                    fprintf(stderr, "Interface %s %s has IP address %s\n", if_indextoname(ifa->ifa_index, name), (nlh->nlmsg_type == RTM_NEWADDR ? "now" : "no longer"), inet_ntoa(*((struct in_addr *)&ipaddr)));

                    if (ip_address_change_notification_callback) (*ip_address_change_notification_callback)((nlh->nlmsg_type == RTM_NEWADDR ? IP_ADDR_ADD : IP_ADDR_REMOVE), ipaddr, ip_address_change_notification_callback_userdata);

                }

            }

        }

    done:

        fprintf(stderr, "ip_address_change_notification_worker exited.\n");

        return (NULL);

    }

    bool begin_ip_address_change_notifications(ip_address_change_notification_callback_t callback, void *userdata)

    {

        if (ip_address_change_notification_socket != -1) return false;

        ip_address_change_notification_callback = callback;

        ip_address_change_notification_callback_userdata = userdata;

        if ((ip_address_change_notification_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {

            perror("begin_ip_address_change_notifications socket");

            return false;

        }

        struct sockaddr_nl addr;

        memset(&addr, 0, sizeof(addr));

        addr.nl_family = AF_NETLINK;

        addr.nl_groups = RTMGRP_IPV4_IFADDR;

        if (bind(ip_address_change_notification_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {

            perror("begin_ip_address_change_notifications bind");

            goto bail;

        }

        pthread_attr_t attr;

        pthread_attr_init(&attr);

        pthread_attr_setdetachstate(&attr, 1); // Preclude the need to do pthread_join on the thread after it exits.

        int err = pthread_create(&ip_address_change_notification_thread, &attr, ip_address_change_notification_worker, NULL);

        pthread_attr_destroy(&attr);

        if (err != 0) {

            fprintf(stderr, "Error creating ip address change notification thread.\n");

            goto bail;

        }

        return (true);

    bail:

        close(ip_address_change_notification_socket);

        ip_address_change_notification_socket = -1;

        ip_address_change_notification_callback = NULL;

        ip_address_change_notification_callback_userdata = NULL;

        return false;

    }

    void end_ip_address_change_notifications(void)

    {

        if (ip_address_change_notification_socket == -1) return;

        pthread_cancel(ip_address_change_notification_thread);

        close(ip_address_change_notification_socket);

        ip_address_change_notification_socket = -1;

        ip_address_change_notification_callback = NULL;

        ip_address_change_notification_callback_userdata = NULL;

    }

    相关文章

      网友评论

        本文标题:翻译:How to detect IP address chan

        本文链接:https://www.haomeiwen.com/subject/bpxfyftx.html