[C++] Come rilevare la modifica dell'indirizzo IP in modo programmatico in Linux?



Answers

eccoci qua ... lo fa senza sondaggi.

ascolta solo RTM_NEWADDR ma dovrebbe essere facile da modificare per supportare RTM_DELADDR se è necessario

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>

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;
}
Question

C'è un modo per rilevare le modifiche agli indirizzi IP sulla macchina locale in Linux a livello di programmazione usando C ++?




Dalla pagina man di rtnetlink:

DESCRIZIONE

Rtnetlink consente di leggere e modificare le tabelle di routing del kernel. Viene usato all'interno del kernel per comunicare tra vari sottosistemi, sebbene questo uso non sia documentato qui, e per la comunicazione con i programmi dello spazio utente. Percorsi di rete, indirizzi IP, parametri di collegamento, configurazioni vicine, discipline di accodamento, classi di traffico e classificatori di pacchetti possono essere controllati tramite socket NETLINK_ROUTE. Si basa sui messaggi netlink, vedi netlink (7) per maggiori informazioni.




Se i tuoi utenti utilizzano NetworkManager, puoi eseguire il polling su NetworkManager.Connection.Active e NetworkManager.IP4Config tramite D-Bus per ottenere un metodo di distribuzione più incrociato per determinare queste informazioni.




il suggerimento di ste di utilizzare ioctl SIOCGIFADDR era tecnicamente corretto, sfortunatamente non è affidabile per i moderni sistemi Linux, in cui una singola interfaccia può avere più indirizzi senza utilizzare sub-interfacce (ad es. eth0: 1) come è stato fatto con l'ifconfig ormai obsoleto.

La soluzione migliore è usare getifaddrs (3), che è presente in glibc 2.3: http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html

Sfortunatamente è un po 'inefficiente (si recupera un elenco collegato di tutti gli indirizzi su tutte le interfacce e si dovrà eseguire un'iterazione per trovare quelli a cui si è interessati), ma nella maggior parte dei casi probabilmente non lo si controlla più di una volta al minuto o così, rendendo tollerabile l'overhead.




Links