Как программно найти IP-адрес / маску сети / шлюз, настроенный для конкретного сетевого устройства в Linux? - PullRequest
8 голосов
/ 07 июня 2010

Я хотел бы написать фрагмент кода, который проверяет для каждого сетевого устройства (например, eth0, lo, master-устройства) некоторую статистику и данные конфигурации этого устройства.
Я мог найти статистические данные (и большую часть данных конфигурации) в / sys / class / net / ..., однако я не смог найти ни C / C ++ API, ни какую-либо запись в procfs / sysfs, перечисляющую inet addr, маска сети и шлюз.

Некоторые альтернативы, которые я проверил:

  • парсинг выходных данных ifconfig / route / некоторых других утилит: я не хочу запускать подпроцесс каждый раз, когда мне нужно выполнить проверку.
  • парсинг / etc / sysconfig / network-scripts /: даст мне только начальную конфигурацию, а не текущее состояние.

Кроме того, так как этот код предназначен для продукта на моем рабочем месте, где каждая внешняя библиотека тщательно проверяется (то есть, мне потребуется вечное добавление любой внешней библиотеки), я предпочитаю решения, основанные на собственном API Linux, а не на внешних библиотеках. .

Спасибо!

Ответы [ 3 ]

18 голосов
/ 07 июня 2010

Там наверняка используется структура вызовов ifreq и ioctl (), вы можете получить всю информацию интерфейса:

Man-страница находится здесь Ifreq manpage

/* local interface info */
    typedef struct{
        char *iface;
        struct ether_addr hwa;
        struct in_addr ipa;
        struct in_addr bcast;
        struct in_addr nmask;
        u_short mtu;
    } ifcfg_t; 
    /*
     * Grabs local network interface information and stores in a ifcfg_t 
     * defined in network.h, returns 0 on success -1 on failure
    */
    int get_local_info(int rsock, ifcfg_t *ifcfg)
    {
        struct ifreq ifr;

        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
        if((ioctl(rsock, SIOCGIFHWADDR, &ifr)) == -1){
            perror("ioctl():");
            return -1;
        }
        memcpy(&(ifcfg->hwa), &ifr.ifr_hwaddr.sa_data, 6);

        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
        if((ioctl(rsock, SIOCGIFADDR, &ifr)) == -1){
            perror("ioctl():");
            return -1;
        }
        memcpy(&ifcfg->ipa, &(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr, 4);

        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
        if((ioctl(rsock, SIOCGIFBRDADDR, &ifr)) == -1){
            perror("ioctl():");
            return -1;
        }
        memcpy(&ifcfg->bcast, &(*(struct sockaddr_in *)&ifr.ifr_broadaddr).sin_addr, 4);

        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
        if((ioctl(rsock, SIOCGIFNETMASK, &ifr)) == -1){
            perror("ioctl():");
            return -1;
        }
        memcpy(&ifcfg->nmask.s_addr, &(*(struct sockaddr_in *)&ifr.ifr_netmask).sin_addr, 4);

        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
        if((ioctl(rsock, SIOCGIFMTU, &ifr)) == -1){
            perror("ioctl():");
            return -1;
        }
        ifcfg->mtu = ifr.ifr_mtu;

        return 0;
    }

Быстрое редактирование, эта функция требует, чтобы интерфейс был назначен до его вызова, например:

strcpy(if_cfg->iface, iface)

Убедитесь, что вы сначала выделили память, а затем вызываете так

if((get_local_info(sock, if_cfg)) != 0){
    printf("Unable to get network device info\n");
    return -1;
}
10 голосов
/ 07 июня 2010

Запуск netstat через strace (на случайном компьютере с Linux), выявляет следующую последовательность происходящих вызовов:

socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
access("/proc/net/if_inet6", R_OK)      = 0
socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
[snip]
open("/proc/net/dev", O_RDONLY)         = 6
fstat64(6, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f91000
read(6, "Inter-|   Receive               "..., 1024) = 575
read(6, "", 1024)                       = 0
close(6)                                = 0
munmap(0xb7f91000, 4096)                = 0
ioctl(4, SIOCGIFCONF, {64, {{"lo", {AF_INET, inet_addr("127.0.0.1")}}, {"eth0", {AF_INET, inet_addr("192.168.0.
8")}}}}) = 0
ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=00:11:09:ca:d1:55}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0x4000, irq=10, dma=0, port=0
}}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0x4000, irq=10, dma=0, port=0
}}) = 0
ioctl(5, SIOCGIFTXQLEN, {ifr_name="eth0", ifr_qlen=1000}) = 0
ioctl(4, SIOCGIFADDR, {ifr_name="eth0", ifr_addr={AF_INET, inet_addr("192.168.0.8")}}) = 0
ioctl(4, SIOCGIFDSTADDR, {ifr_name="eth0", ifr_dstaddr={AF_INET, inet_addr("192.168.0.8")}}) = 0
ioctl(4, SIOCGIFBRDADDR, {ifr_name="eth0", ifr_broadaddr={AF_INET, inet_addr("192.168.0.255")}}) = 0
ioctl(4, SIOCGIFNETMASK, {ifr_name="eth0", ifr_netmask={AF_INET, inet_addr("255.255.255.0")}}) = 0

Итак, «секрет», по-видимому, заключается в создании сокета, а затем в связке ioctl() вызовов для доступа к текущей информации.

4 голосов
/ 21 октября 2014

Взгляните на /usr/include/ifaddrs.h.Для этого есть специальный API для GNU.

int getifaddrs (struct ifaddrs **ifap);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...