我想编写一段代码,为每个网络设备(例如eth0,lo,主设备)检查有关该设备的一些统计信息和配置数据。
我可以在/ sys / class / net / ...中找到统计数据(和大多数配置数据),但是,我找不到任何C / C ++ API或procfs / sysfs中列出inet addr的任何条目,网络掩码和网关。
我检查了一些替代方案:
此外,由于此代码适用于我的工作场所中的产品,其中每个外部库都经过彻底检查(这意味着我将永远需要添加任何外部库)我更喜欢依赖Linux本机API而非外部库的解决方案
谢谢!
答案 0 :(得分:18)
确实使用了ifreq和ioctl()调用的结构,你可以获取所有接口信息:
手册页在这里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;
}
答案 1 :(得分:10)
通过strace运行netstat(在随机的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()
调用来访问当前信息。
答案 2 :(得分:4)
看看/usr/include/ifaddrs.h
。有一个GNU特定的API。
int getifaddrs (struct ifaddrs **ifap);