C++ 如何在 Linux 中以编程方式查找为特定网络设备配置的 IP 地址/网络掩码/网关?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2989419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I programmatically find the IP address/netmask/gateway configured for a specific network device in Linux?
提问by Oren S
I would like to write a piece of code which checks, for each network device (e.g. eth0, lo, master devices) some statistics and configuration data about that device.
I could find the statistics data (and most of the configuration data) in /sys/class/net/..., however, I couldn't find any C/C++ API or any entry in procfs/sysfs listing the inet addr, netmask and gateway.
我想编写一段代码来检查每个网络设备(例如 eth0、lo、master 设备)有关该设备的一些统计信息和配置数据。
我可以在 /sys/class/net/... 中找到统计数据(以及大部分配置数据),但是,我找不到任何 C/C++ API 或 procfs/sysfs 中列出 inet addr 的任何条目,网络掩码和网关。
Some alternatives I checked:
我检查了一些替代方案:
- parsing the output from ifconfig/route/some other utilities: I don't want to start a subprocess every time I need to do the inspection.
- parsing /etc/sysconfig/network-scripts/: will give me only the start-up configuration, and not the current state.
- 解析 ifconfig/route/一些其他实用程序的输出:我不想每次需要进行检查时都启动子进程。
- 解析 /etc/sysconfig/network-scripts/: 只会给我启动配置,而不是当前状态。
Also, since this code is intended for a product in my workplace, where every external library is inspected thoroughly (meaning it will take me forever to add any external library) I prefer solutions which rely on Linux native API and not external libraries.
此外,由于此代码适用于我工作场所的产品,其中每个外部库都经过彻底检查(这意味着我需要永远添加任何外部库),因此我更喜欢依赖于 Linux 本机 API 而不是外部库的解决方案。
Thanks!
谢谢!
回答by Bella
There sure is using a struct of ifreq and ioctl() calls you can grab all interface information:
确实使用了 ifreq 和 ioctl() 调用的结构,您可以获取所有接口信息:
Man page is here Ifreq manpage
手册页在这里Ifreq 手册页
/* 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;
}
Quick edit, this function requires that the interface has been assigned before it is called, like so:
快速编辑,这个函数要求在调用之前已经分配了接口,像这样:
strcpy(if_cfg->iface, iface)
Ensuring you have allocated the memory first, then call like so
确保您先分配了内存,然后像这样调用
if((get_local_info(sock, if_cfg)) != 0){
printf("Unable to get network device info\n");
return -1;
}
回答by unwind
Running netstat through strace (on a random Linux box), reveals the following sequence of calls taking place:
通过 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
So, the "secret" seems to be to create a socket, then do a bunch of ioctl()
calls to access the current information.
所以,“秘密”似乎是创建一个套接字,然后进行一堆ioctl()
调用来访问当前信息。
回答by jfranzoy
Take a look at /usr/include/ifaddrs.h
. There is a GNU specific API for this.
看看/usr/include/ifaddrs.h
。为此有一个 GNU 特定的 API。
int getifaddrs (struct ifaddrs **ifap);