C语言getifaddrs()通过网口IP获取网口名

原文地址:https://www.cnblogs.com/liqinglucky/p/getifaddrs.html

用C语言实现通过ip地址获取到本地网口名。比如我知道网口IP是173.1.4.53,怎么通过这个IP匹配出网口是ens9?

# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:f2:d2:cc brd ff:ff:ff:ff:ff:ff
    inet 193.9.3.23/24 brd 193.9.3.255 scope global ens3
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fef2:d2cc/64 scope link
       valid_lft forever preferred_lft forever
3: ens9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:6f:83:74 brd ff:ff:ff:ff:ff:ff
    inet 173.1.4.53/24 brd 173.1.4.255 scope global ens9
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe6f:8374/64 scope link
       valid_lft forever preferred_lft forever

初步思路是利用linux命令:ip addr获取接口和ip的方式遍历所有linux的ip和网口名。然后C语言去匹配过滤ip就能拿到对应的网口名。

调查发现linux命令:ip addr不是读文件的,直接调的接口getifaddrs[1]

遍历所有网口[2]

方案1:

代码iface.c

#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;
}

测试

# gcc iface.c -o iface
# ./iface
lo
ens3
ens9

方案2:

代码ifaddr.c

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

int main (void)
{
    struct ifaddrs *addrs,*tmp;

    getifaddrs(&addrs);
    tmp = addrs;

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

        tmp = tmp->ifa_next;
    }

    freeifaddrs(addrs);

    return 0;
}

测试:

# gcc ifaddr.c -o ifaddr
# ./ifaddr
lo ''
ens3 ''
ens9 ''

通过网口IP获取网口名[3]

这里代码参考[4]getifaddrs()官方例子。

官方代码运行:

# ./main
lo       AF_PACKET (17)
                tx_packets =   13989603; rx_packets =   13989603
                tx_bytes   = 1126608262; rx_bytes   = 1126608262
ens3     AF_PACKET (17)
                tx_packets =    4187731; rx_packets =    8975400
                tx_bytes   = 3827704908; rx_bytes   =  807683670
ens9     AF_PACKET (17)
                tx_packets =    1219601; rx_packets =    7449959
                tx_bytes   =  110307334; rx_bytes   =  696553525
lo       AF_INET (2)
                address: <127.0.0.1>
ens3     AF_INET (2)
                address: <193.9.3.23>
ens9     AF_INET (2)
                address: <173.1.4.53>

根据getifaddrs()官方示例代码,匹配ifa->ifa_addr后,ifa->ifa_name就是网卡名。
代码:

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
#include <string.h>

int main(int argc, char *argv[])
{
    struct ifaddrs *ifaddr;
    int family, s;
    char host[NI_MAXHOST];

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        exit(EXIT_FAILURE);
    }

    for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL)
            continue;

        family = ifa->ifa_addr->sa_family;

        if (family == AF_INET || family == AF_INET6) {
            s = getnameinfo(ifa->ifa_addr,
                    (family == AF_INET) ? sizeof(struct sockaddr_in) :
                                          sizeof(struct sockaddr_in6),
                    host, NI_MAXHOST,
                    NULL, 0, NI_NUMERICHOST);
            if (s != 0) {
                printf("getnameinfo() failed: %s\n", gai_strerror(s));
                exit(EXIT_FAILURE);
            }
            if( !strcmp(host, "173.1.4.53")){
                printf("%-8s ",ifa->ifa_name);
                printf("address: <%s>\n", host);
            }

        } 
    }

    freeifaddrs(ifaddr);
    exit(EXIT_SUCCESS);
}

测试:

# gcc main.c -o main
# ./main
ens9     address: <173.1.4.53>

参考:


  1. Linxu的struct ifaddrs 与getifaddrs()函数 - 月未央 - 博客园 (cnblogs.com) ↩︎

  2. c - Linux getting all network interface names - Stack Overflow ↩︎

  3. C code to get the interface name for the IP address in Linux - Stack Overflow ↩︎

  4. getifaddrs(3) - Linux manual page (man7.org) ↩︎

posted @ 2023-05-15 18:03  liqinglucky  阅读(713)  评论(0编辑  收藏  举报