Определить тип физического носителя на канальном уровне - PullRequest
0 голосов
/ 04 января 2019

Используя getifaddrs, мы можем перебирать все доступные сетевые интерфейсы на машине. В этом вопросе меня интересуют только интерфейсы уровня 2 (канального уровня) - то есть интерфейсы семейства AF_PACKET.

Когда мы выполняем итерацию по всем интерфейсам, возвращаемым из getifaddrs, и находим экземпляр struct ifaddrs, чье поле ifa_addr->sa_family равно AF_PACKET, кажется, нам все еще нужна дополнительная информация о том, какой тип интерфейса уровня 2 мы имеют дело.

Мы можем исключить петлевые интерфейсы и двухточечные интерфейсы, проверив поле ifa_flags. Но кроме этого, как мы можем определить, является ли конкретный интерфейс AF_PACKET Ethernet или чем-то еще? Предположительно, это также может быть какая-то другая технология уровня 2, например, WiFi, Token-Ring или Bluetooth. Итак, как мы можем определить, является ли это Ethernet или чем-то еще?

Считая документацию для struct sockaddr_ll, появляется поле sll_protocol, которое содержит «стандартный тип протокола Ethernet в сетевом порядке байтов». Это немного смущает меня, потому что теперь я не уверен, должен ли sockaddr_ll использоваться только для Ethernet, или он должен использоваться в качестве универсального объекта сокета канального уровня. Тот факт, что в документации сказано, что sll_protocol содержит стандартный протокол ethernet , указывает мне, что sockaddr_ll предполагается использовать только для Ethernet. Но все же поле sll_addr кажется более общим (оно может содержать длину до 8 байт вместо 6-байтового MAC-адреса).

Я также не уверен, что именно семья AF_PACKET должна сказать мне, что физический носитель должен быть Ethernet.

Единственный другой ключ, который я могу найти о том, как это сделать, прибывает из http://www.microhowto.info/howto/get_the_mac_address_of_an_ethernet_interface_in_c_using_siocgifhwaddr.html. Это, кажется, подразумевает, что, используя более старый интерфейс struct ifreq и ioctl, наряду с SIOCGIFHWADDR, вы определенно можете скажите, является ли конкретный интерфейс Ethernet, проверив поле sa_family поля ifr_hwaddr в структуре ifreq. Если устройство является устройством Ethernet, поле sa_family должно быть установлено на ARPHRD_ETHER.

Но я не совсем понимаю, почему это не согласуется с getifaddrs, где поле ifa_addr->sa_family просто AF_PACKET для интерфейсов Ethernet уровня 2. Кажется, что этот более новый API (getifaddrs) не предоставляет никакого способа отличить, является ли конкретный сетевой интерфейс фактически Ethernet, по сравнению с какой-либо другой технологией уровня 2, такой как WIFI.

Итак, как лучше всего определить, является ли конкретный сетевой интерфейс Ethernet (в отличие от какой-либо другой технологии уровня 2)?

1 Ответ

0 голосов
/ 04 января 2019

Мы можем просто проверить значение ifa_addr->sa_family, и я думаю, что он должен дать вам слой procotol 2. Есть несколько классных ответов на stackoverflow, таких как здесь и здесь , которые используйте 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");
        }
}
...