2017-02-17 2 views
1

Ich lerne die Netlink-Bibliothek Version 3 und ich möchte wissen, wie Sie die IPV4-Adresse einer angegebenen Netzwerkschnittstelle erhalten. Ich kann die MAC-Adresse und sogar requery den Schnittstellennamen von einer Verbindungsdatenstruktur erhalten, aber ich kann nicht herausfinden, wie man die IP-Adresse unter Verwendung der libnl und der libnl-route libs erhält. Ich habe einen Code gefunden, um die IP-Adresse mit der Libnl-CLI-Lib zu erhalten, aber das ist zum Dumping der Ergebnisse in einen Dateideskriptor (think stdout). Ich habe eine Mail an die Mailingliste für diese Bibliothek gesendet, aber ich habe keine Antwort erhalten.Wie bekomme ich die IPv4-Adresse einer Schnittstelle mit libnl3 (netlink Version 3) auf Linux?

Hier ist mein Code: https://gist.github.com/netskink/4f554ed6657954b17ab255ad5bc6d1f0

Hier meine Ergebnisse sind:

./stats 
Returned link name is enp6s0 
Returned link addr is a0:36:9f:66:93:13 

den Mechanismus gesehen Ive die IP-Adresse mit ioctls abzurufen, aber da netlink lib können die IP-Adresse mit der Rückkehr CLI Subbibliothek Ich denke, es kann getan werden, aber ich kann keinen Weg finden.

+0

Möglicherweise ist die Quelle zu 'nl-addr-list' von Interesse? https: // GitHub.com/thom311/libnl/blob/master/src/nl-addr-list.c – larsks

+0

Dieser Code verwendet die CLI-Subbibliothek. Das interessiert mich nicht. Siehe meine ursprüngliche Frage. – netskink

Antwort

3

Schnittstelle kann mehrere Adressen haben (IPV4 und IPV6 Adressen - Codebeispiel gab mir einen ipv4 und einen ipv6), also gibt es keine solche Funktion, die eine Adresse für die Schnittstelle zurückgibt. Wenn Sie nur eine bestimmte lokale Adresse hätten, hätten Sie rtnl_addr_get aufrufen können. Stattdessen können Sie Adressen iterieren.

#include <libnl3/netlink/cache.h> 

void addr_cb(struct nl_object *o, void *data) 
{ 
    int ifindex = (int)(intptr_t)data; 
    struct rtnl_addr *addr = (rtnl_addr *)o; 
    if (NULL == addr) { 
     /* error */ 
     printf("addr is NULL %d\n", errno); 
     return; 
    } 

    int cur_ifindex = rtnl_addr_get_ifindex(addr); 
    if(cur_ifindex != ifindex) 
     return; 

    const struct nl_addr *local = rtnl_addr_get_local(addr); 
    if (NULL == local) { 
     /* error */ 
     printf("rtnl_addr_get failed\n"); 
     return; 
    } 

    char addr_str[ADDR_STR_BUF_SIZE]; 
    const char *addr_s = nl_addr2str(local, addr_str, sizeof(addr_str)); 
    if (NULL == addr_s) { 
     /* error */ 
     printf("nl_addr2str failed\n"); 
     return; 
    } 
    fprintf(stdout, "\naddr is: %s\n", addr_s); 
} 

Sie können Adressen aus dem Cache iterieren und sehen, ob sie die benötigte Adresse enthalten (siehe ifindex). Bitte beachten Sie https://www.infradead.org/~tgr/libnl/doc/api/cache_8c_source.html für nützliche Funktionen (es gibt einige Filterfunktion).

int ifindex = rtnl_link_get_ifindex(p_rtnl_link); 
printf("ifindex: %d\n", ifindex); 

bool empty = nl_cache_is_empty(addr_cache); 
printf("empty: %d\n", empty); 

nl_cache_foreach(addr_cache, 
     addr_cb, (void*)(intptr_t)ifindex); 

Und um IP-Version zu überprüfen, verwenden Sie rtnl_addr_get_family.

+0

Danke. Ich werde versuchen, Ihre Lösung morgen zu verwenden. Danke vielmals. – netskink

+0

Das funktioniert tatsächlich. Danke vielmals. Ich habe Ihre Lösung als Antwort markiert und für Sichtbarkeit ausgewählt. Ich schätze deine Hilfe sehr. – netskink

1

Aufbauend auf der Antwort von user2518959.

Der rtnl_addr_alloc_cache und der rtnl_link_alloc_cache liefern beide ein nl_cache Objekt/Struktur zurück. Selbst wenn diese beiden Ergebnisse vom selben Typ sind, haben sie unterschiedliche Routinen, die bei jedem verwendet werden können.

Der von rtnl_addr_alloc_cache zurückgegebene nl_cache kann verwendet werden, um rtnl_addr-Objekt/Strukturen zu erhalten. Diese wiederum können verwendet werden, um rtnl_addr_get_local aufzurufen, um die ipv4- oder ipv6-Adresse zu erhalten.

Im Gegensatz dazu kann der von rtnl_link_alloc_cache zurückgegebene nl_cache verwendet werden, um den Schnittstellennamen (eth0, enp6s0, ...) und die MAC-Adresse zu erhalten. Die Routinen sind rtnl_link_get_by_name bzw. rtnl_link_get_addr. In beiden Fällen ist die gemeinsame Verbindung zwischen den beiden die Routine rtnl_addr_get_index und rtnl_link_get_index, die einen Schnittstellenindex zurückgeben, der verwendet werden kann, um jeden Eintrag von jedem Cache in Beziehung zu setzen. dh. Schnittstelle 1 von der Addr-Version von nl_cache und Schnittstelle 1 von der Verbindung nl_cache sind die gleiche Schnittstelle. Einer gibt die IP-Adresse und der andere die MAC-Adresse und den Namen.

Schließlich wird ein Tunnel eine IP-Adresse haben, aber kein Mac, so dass es keinen Link-Namen oder Mac-Adresse haben wird.

Hier ist ein Code, der user25185959 Ansatz und eine alternative Methode zeigt, die die Beziehung explizit zeigt. User2518959 hat die Schnittstellennummer in den Callback übergeben, um Interfaces herauszufiltern.

#include <libnl3/netlink/netlink.h> 
#include <libnl3/netlink/route/link.h> 
#include <libnl3/netlink/route/addr.h> 
#include <libnl3/netlink/cache.h> 
#include <libnl3/netlink/route/addr.h> 

#include <errno.h> 



/* 
gcc ipchange.c -o ipchange $(pkg-config --cflags --libs libnl-3.0 libnl-route-3.0 libnl-cli-3.0) 
*/ 

#include <stdbool.h> 

#define ADDR_STR_BUF_SIZE 80 

void addr_cb(struct nl_object *p_nl_object, void *data) { 

    int ifindex = (int) (intptr_t) data; // this is the link index passed as a parm 
    struct rtnl_addr *p_rtnl_addr; 
    p_rtnl_addr = (struct rtnl_addr *) p_nl_object; 
    int result; 

    if (NULL == p_rtnl_addr) { 
     /* error */ 
     printf("addr is NULL %d\n", errno); 
     return; 
    } 

    // This routine is not mentioned in the doxygen help. 
    // It is listed under Attributes, but no descriptive text. 
    // this routine just returns p_rtnl_addr->a_ifindex 
    int cur_ifindex = rtnl_addr_get_ifindex(p_rtnl_addr); 
    if(cur_ifindex != ifindex) { 
     // skip interaces where the index differs. 
     return; 
    } 

    // Adding this to see if I can filter on ipv4 addr 
    // this routine just returns p_rtnl_addr->a_family 
    // this is not the one to use 
    // ./linux/netfilter.h: NFPROTO_IPV6 = 10, 
    // ./linux/netfilter.h: NFPROTO_IPV4 = 2, 
    // this is the one to use 
    // x86_64-linux-gnu/bits/socket.h 
    // defines AF_INET6 = PF_INET6 = 10 
    // defines AF_INET = PF_INET = 2 
    result = rtnl_addr_get_family(p_rtnl_addr); 
    // printf("family is %d\n",result); 
    if (AF_INET6 == result) { 
    // early exit, I don't care about IPV6 
    return; 
    } 

    // This routine just returns p_rtnl_addr->a_local 
    const struct nl_addr *p_nl_addr_local = rtnl_addr_get_local(p_rtnl_addr); 
    if (NULL == p_nl_addr_local) { 
     /* error */ 
     printf("rtnl_addr_get failed\n"); 
     return; 
    } 

    char addr_str[ADDR_STR_BUF_SIZE]; 
    const char *addr_s = nl_addr2str(p_nl_addr_local, addr_str, sizeof(addr_str)); 
    if (NULL == addr_s) { 
     /* error */ 
     printf("nl_addr2str failed\n"); 
     return; 
    } 
    fprintf(stdout, "\naddr is: %s\n", addr_s); 

} 

int main(int argc, char **argv, char **envp) { 

    int err; 

    struct nl_sock *p_nl_sock; 
    struct nl_cache *link_cache; 
    struct nl_cache *addr_cache; 

    struct rtnl_addr *p_rtnl_addr; 
    struct nl_addr *p_nl_addr; 
    struct nl_link *p_nl_link; 

    struct rtnl_link *p_rtnl_link; 


    char addr_str[ADDR_STR_BUF_SIZE]; 

    char *pchLinkName; 
    char *pchLinkAddr; 
    char *pchIPAddr; 
    char *interface; 
    interface = "enp6s0"; 
    pchLinkAddr = malloc(40); 
    pchIPAddr = malloc(40); 
    strcpy(pchLinkAddr,"11:22:33:44:55:66"); 
    strcpy(pchIPAddr,"123.456.789.abc"); 





    p_nl_sock = nl_socket_alloc(); 
    if (!p_nl_sock) { 
     fprintf(stderr, "Could not allocate netlink socket.\n"); 
     exit(ENOMEM); 
    } 



    // Connect to socket 
    if(err = nl_connect(p_nl_sock, NETLINK_ROUTE)) { 
     fprintf(stderr, "netlink error: %s\n", nl_geterror(err)); 
     p_nl_sock = NULL; 
     exit(err); 
    } 


    // Either choice, the result below is a mac address 
    err = rtnl_link_alloc_cache(p_nl_sock, AF_UNSPEC, &link_cache); 
    //err = rtnl_link_alloc_cache(p_nl_sock, AF_INET, &link_cache); 
    //err = rtnl_link_alloc_cache(p_nl_sock, IFA_LOCAL, &link_cache); 
    if (0 != err) { 
     /* error */ 
    printf("rtnl_link_alloc_cache failed: %s\n", nl_geterror(err)); 
    return(EXIT_FAILURE); 
    } 

    err = rtnl_addr_alloc_cache(p_nl_sock, &addr_cache); 
    if (0 != err) { 
     /* error */ 
    printf("rtnl_addr_alloc_cache failed: %s\n", nl_geterror(err)); 
    return(EXIT_FAILURE); 
    } 



    p_rtnl_link = rtnl_link_get_by_name(link_cache, "enp6s0"); 
    if (NULL == p_rtnl_link) { 
     /* error */ 
    printf("rtnl_link_get_by_name failed\n"); 
    return(EXIT_FAILURE); 
    } 


    pchLinkName = rtnl_link_get_name(p_rtnl_link); 
    if (NULL == pchLinkName) { 
     /* error */ 
    printf("rtnl_link_get_name failed\n"); 
    return(EXIT_FAILURE); 
    } 
    printf("Returned link name is %s\n",pchLinkName); 


    ////////////////////////////////// mac address 
    p_nl_addr = rtnl_link_get_addr(p_rtnl_link); 
    if (NULL == p_nl_addr) { 
     /* error */ 
    printf("rtnl_link_get_addr failed\n"); 
    return(EXIT_FAILURE); 
    } 


    pchLinkAddr = nl_addr2str(p_nl_addr, pchLinkAddr, 40); 
    if (NULL == pchLinkAddr) { 
     /* error */ 
    printf("rtnl_link_get_name failed\n"); 
    return(EXIT_FAILURE); 
    } 
    printf("Returned link addr is %s\n",pchLinkAddr); 



    ////////////////////////////////// ip address 
    // How to get ip address for a specified interface? 








    // 
    // The way she showed me. 
    // 


    // Return interface index of link object 
    int ifindex = rtnl_link_get_ifindex(p_rtnl_link); 
    printf("ifindex: %d\n", ifindex); 

    // She gave me this but its not necessary 
    // Returns true if the cache is empty. True if the cache is empty. 
    // bool empty = nl_cache_is_empty(addr_cache); 
    // printf("empty: %d\n", empty); 

    // Call a callback on each element of the cache. The 
    // arg is passed on the callback function. 
    // addr_cache is the cache to iterate on 
    // addr_cb is the callback function 
    // ifindex is the argument passed to the callback function 
    // 
    nl_cache_foreach(addr_cache, addr_cb, (void*)(intptr_t)ifindex); 



    // This shows that the link index returned from rtnl_addr_get_index 
    // and rtnl_link_get_index are equivalent when using the rtnl_addr 
    // and rtnl_link from the two respective caches. 


    // Another way... 
    // This will iterate through the cache of ip's 
    printf("Getting the list of interfaces by ip addr cache\n"); 
    int count = nl_cache_nitems(addr_cache); 
    printf("addr_cache has %d items\n",count); 
    struct nl_object *p_nl_object; 
    p_nl_object = nl_cache_get_first(addr_cache); 
    p_rtnl_addr = (struct rtnl_addr *) p_nl_object; 
    for (int i=0; i<count; i++) { 
    // This routine just returns p_rtnl_addr->a_local 
    const struct nl_addr *p_nl_addr_local = rtnl_addr_get_local(p_rtnl_addr); 
    if (NULL == p_nl_addr_local) { 
     /* error */ 
     printf("rtnl_addr_get failed\n"); 
     return(EXIT_FAILURE); 
    } 



    int cur_ifindex = rtnl_addr_get_ifindex(p_rtnl_addr); 
    printf("This is index %d\n",cur_ifindex); 

    const char *addr_s = nl_addr2str(p_nl_addr_local, addr_str, sizeof(addr_str)); 
    if (NULL == addr_s) { 
     /* error */ 
     printf("nl_addr2str failed\n"); 
     return(EXIT_FAILURE); 
    } 
    fprintf(stdout, "\naddr is: %s\n", addr_s); 

    //  
    printf("%d\n",i); 
    p_nl_object = nl_cache_get_next(p_nl_object); 
     p_rtnl_addr = (struct rtnl_addr *) p_nl_object; 

    // Just for grins 


    } 



    // Another way... 
    // This will iterate through the cache of LLC 
    printf("Getting the list of interfaces by mac cache\n"); 
    count = nl_cache_nitems(link_cache); 
    printf("addr_cache has %d items\n",count); 
    p_nl_object = nl_cache_get_first(link_cache); 
    p_rtnl_link = (struct rtnl_link *) p_nl_object; 
    for (int i=0; i<count; i++) { 
    // This routine just returns p_rtnl_addr->a_local 
    const struct nl_addr *p_nl_addr_mac = rtnl_link_get_addr(p_rtnl_link); 
    if (NULL == p_nl_addr_mac) { 
     /* error */ 
     printf("rtnl_addr_get failed\n"); 
     return(EXIT_FAILURE); 
    } 

    int cur_ifindex = rtnl_link_get_ifindex(p_rtnl_link); 
    printf("This is index %d\n",cur_ifindex); 

    const char *addr_s = nl_addr2str(p_nl_addr_mac, addr_str, sizeof(addr_str)); 
    if (NULL == addr_s) { 
     /* error */ 
     printf("nl_addr2str failed\n"); 
     return(EXIT_FAILURE); 
    } 
    fprintf(stdout, "\naddr is: %s\n", addr_s); 

    //  
    printf("%d\n",i); 
    p_nl_object = nl_cache_get_next(p_nl_object); 
     p_rtnl_link = (struct rtnl_link *) p_nl_object; 

    } 


    return(EXIT_SUCCESS); 
} 
Verwandte Themen