Pergunta

I need to collect all the interface names, even the ones that aren't up at the moment. Like ifconfig -a.

getifaddrs() is iterating through same interface name multiple times. How can I collect all the interface names just once using getifaddrs()?

Foi útil?

Solução

You could check which entries from getifaddrs belong to the AF_PACKET family. On my system that seems to list all interfaces:

struct ifaddrs *addrs,*tmp;

getifaddrs(&addrs);
tmp = addrs;

while (tmp)
{
    if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET)
        printf("%s\n", tmp->ifa_name);

    tmp = tmp->ifa_next;
}

freeifaddrs(addrs);

Outras dicas

getifaddrs() will only return your interfaces addresses, not the interfaces themselves.

What if any of your interface has no address, or no address of the requested family, as suggested with the 'AF_PACKET' one ?

Here, an example where I’ve got a tunnel interface (with an OpenVPN connexion), and where I’m listing all entries from getifaddrs() for each of my network interfaces:

[0] 1: lo                address family: 17 (AF_PACKET) b4:11:00:00:00:01
                         address family: 2 (AF_INET)    address: <127.0.0.1>
                         address family: 10 (AF_INET6)  address: <::1>
[...]

[5] 10: tun0             address family: 2 (AF_INET)    address: <172.16.0.14>
[EOF]

Bam. No AF_PACKET on the "tun0" interface, but it DOES exist on the system.

You should, instead, use if_nameindex() syscall, which does exactly what you want. In other words, with no arguments, it returns a list of all interfaces on your system:

#include <net/if.h>
#include <stdio.h>

int main (void)
{
    struct if_nameindex *if_nidxs, *intf;

    if_nidxs = if_nameindex();
    if ( if_nidxs != NULL )
    {
        for (intf = if_nidxs; intf->if_index != 0 || intf->if_name != NULL; intf++)
        {
            printf("%s\n", intf->if_name);
        }

        if_freenameindex(if_nidxs);
    }

    return 0;
}

And voilà.

It seems that ifconfig -a only lists active interfaces (at least on Fedora 19). I know I have at least one more network card that I'm not seeing. Anyway, I get the same list as:

ls -1 /sys/class/net

Which could easily be done programatically.

You are on the right track (it is getifaddrs). It returns each interface once per family, so you get eth0 for ipv4 and one for ipv6. If you just want each interface once you will have to uniq the output yourself.

I thing this show you all interface, at least for me

ip link show

ls -1 /sys/class/net

only show interface name

lo
p4p1

I need the main device that is being used by the system (assuming there is only one) such as eth0 wlan0 or whatever RHEL7 is trying to do...

The best I hacked together was this:

#!/bin/bash
# -- Get me the interface for the main ip on system

for each in $(ls -1 /sys/class/net) ;do 

    result=$(ip addr show $each | awk '$1 == "inet" {gsub(/\/.*$/, "", $2); print $2}' | grep "$(hostname -I | cut -d' ' -f1)")

    if [ ! -z "${result// }" ] && [ -d /sys/class/net/${each// } ] ;then
            echo "Device: $each IP: $result"
            break;
    fi

done

Sample output:

    ./maineth.sh  
    Device: enp0s25 IP: 192.168.1.6

Use this one. I added the appropriate comments for ease of understanding.

void extract_network_interface_names()
{
    /* DEFINITION
     *  #include <net/if.h>
     *  struct if_nameindex * if_nameindex() :  function that returns a pointer.
     *  The if_nameindex()  function returns an array of if_nameindex structs. There is one struct for each network interface
     *  The if_nameindex struct contains at least the following members:
     *      unsigned int if_index : which is the index of each network interface {1,2,..n}
     *      char * if_name : which is the name of the interface=the C style string= an array of characters terminated in the NULL character \0
     *
     *  The end of the array of struct is indicated by an entry with if_index=0 && if_name=NULL
     *  The if_nameindex() function returns an array of structs if successful, or NULL if some error occurred or not enough memory is available
     */
    puts("Extracting network interface names...");
    puts("Listing all available network interface names on this machine...");
    puts("********************************");

    int counter_network_interfaces=0;

    struct if_nameindex * interface_indexes;
    struct if_nameindex * interface;

    interface_indexes=if_nameindex();

    if(interface_indexes==NULL) //Some error occurred during the execution of if_nameindex() function or there is no enough memory available
    {
        perror("If_nameindex");
        printf("Ooops...error while extracting the network interface names.\n");
        exit(EXIT_FAILURE);
    }

    //Loop through the elements of the array of if_nameindex structs

    for(interface=interface_indexes;interface->if_index!=0 && interface->if_name!=NULL;interface++)
        {
            counter_network_interfaces++;
            printf("There exists a network interface called \"%s\" with index %d. \n",interface->if_name, interface->if_index);
        }

        puts("*******************************");
        printf("In total, there is a number of %d network interfaces on this machine.\n",counter_network_interfaces);


}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top