1

Using getifaddrs, we can iterate over all the available network interfaces on a machine. For this question, I'm only concerned with layer 2 (link layer) interfaces - i.e. interfaces of the AF_PACKET family.

When we are iterating over all the interfaces returned from getifaddrs, and we find a struct ifaddrs instance whose ifa_addr->sa_family field is AF_PACKET, it seems we still need further information about what type of layer 2 interface we are dealing with.

We can rule out loopback interfaces and point-to-point interfaces by checking the ifa_flags field. But apart from that, how can we tell if a particular AF_PACKET interface is Ethernet, or something else? Presumably, it could also be some other Layer 2 technology, like WiFi, token-ring, or Bluetooth. So how can we tell if it is Ethernet or something else?

Reading the documentation for struct sockaddr_ll, it appears there is a field sll_protocol that contains "the standard ethernet protocol type in network byte order". This confuses me a bit, because now I'm unsure whether sockaddr_ll is supposed to only be used for Ethernet, or whether it's supposed to be used as a generic link layer socket object. The fact that the documentation says that sll_protocol contains the standard ethernet protocol indicates to me that sockaddr_ll is supposed to only be used for Ethernet. But yet the sll_addr field seems to be more generic (it can contain a length up to 8 bytes, instead of just a 6 byte MAC address).

I'm also unsure if the family AF_PACKET itself is what is supposed to tell me that the physical media must be Ethernet.

The only other clue I can find on how to do this comes from http://www.microhowto.info/howto/get_the_mac_address_of_an_ethernet_interface_in_c_using_siocgifhwaddr.html. This seems to imply that by using the older struct ifreq and ioctl interface, along with SIOCGIFHWADDR, you can definitely tell if a particular interface is Ethernet by checking the sa_family field of the ifr_hwaddr field in the ifreq struct. If the device is an Ethernet device, the sa_family field should be set to ARPHRD_ETHER.

But I'm confused as to why this is not consistent with getifaddrs, where the ifa_addr->sa_family field is simply AF_PACKET for layer 2 Ethernet interfaces. It seems this newer API (getifaddrs) doesn't provide any way to distinguish if a particular network interface is actually Ethernet, versus some other Layer 2 technology like WIFI.

So what is the best way determine if a particular network interface is Ethernet (as opposed to some other Layer 2 technology)?

Siler
  • 8,976
  • 11
  • 64
  • 124
  • I think `getifaddrs` is supposed to work with IEEE 802. And I suspect the "ethernet" is the IEEE 802.3 standard. For ipv6 (is ipv6 also ethernet/) there is EUI-64, which takes 8 bytes, not EUI-48. `how can you determine if a particular network interface is Ethernet` - can you define what is Ethernet? – KamilCuk Jan 04 '19 at 20:30
  • I would define Ethernet as IEEE 802.3 – Siler Jan 04 '19 at 20:32

1 Answers1

0

We can just check ifa_addr->sa_family value and I think it is supposed to give you the procotol layer 2. There are some cool answers on stackoverflow, like here and here that use getifaddrs.

#define _GNU_SOURCE
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <netdb.h>
#include <stdlib.h>

int main() {

        struct ifaddrs *ifa;

        if (getifaddrs(&ifa) == -1) {
            perror("getifaddrs failed");
            exit(1);
        }

        for (struct ifaddrs *i = ifa; i; i = i->ifa_next) {
                printf("Name %s has ", i->ifa_name);
                if (i->ifa_addr == NULL) {
                        printf("no address!");
                } else if (i->ifa_addr->sa_family == AF_INET) {
                        printf("ipv4 (ie. ethernet, ie. IEEE 802.3)");
                } else if (i->ifa_addr->sa_family == AF_INET6) {
                        printf("ipv6");
                } else if (i->ifa_addr->sa_family == AF_BLUETOOTH) {
                        printf("bluetooth");
                } else {
                        printf("unhandled!");
                }
                printf("\n");
        }
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • So does `AF_PACKET` always indicate Ethernet (IEEE 802.3) then? – Siler Jan 04 '19 at 22:08
  • `AF_PACKET` is like your own protocol / no protocol. It's a "packet" protocol - there are packets (nothing more). AF_INET is ipv4. – KamilCuk Jan 04 '19 at 22:14
  • So if `AF_PACKET` is supposed to be just a "generic packet protocol", how does checking the `family` tell you if an interface is Ethernet? If `ifa_addr->sa_family == AF_PACKET`, are you guaranteed the interface is Ethernet? Or could it be something else, like WIFI for example? – Siler Jan 05 '19 at 04:11