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>