有一个非常有用的函数调用getifaddrs
可以检索所有机器网络地址。问题是我使用的是没有此功能的旧 glibc 版本。有替代品吗?我正在寻找并发现getipnodebyname
,但是当地址未映射到 /etc/hosts 文件中时它是无用的。
2 回答
执行等效操作的传统方法是使用SIOCGIFCONF
to 操作ioctl
。任何套接字都可以用于操作。不过,它不像单个函数调用那么容易。
要添加到先前的答案,这里是 - 方法的示例SIOCGIFCONF
。你必须做这样的事情:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int fd;
int get_iface_list(struct ifconf *ifconf)
{
int rval;
if((rval = ioctl(fd, SIOCGIFCONF , (char*) ifconf )) < 0 )
perror("ioctl(SIOGIFCONF)");
return rval;
}
int main()
{
static struct ifreq ifreqs[100];
static struct ifconf ifc;
char *ptr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
return 1;
ifc.ifc_buf = (char*) (ifreqs);
ifc.ifc_len = sizeof(ifreqs);
if(get_iface_list(&ifc) < 0) return -1;
/* Go through the list of interfaces */
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len;)
{
struct ifreq *ifr = (struct ifreq*)ptr;
int len = (sizeof(struct sockaddr) > ifr->ifr_addr.sa_len) ?
sizeof(struct sockaddr) : ifr->ifr_addr.sa_len;
ptr += sizeof(ifr->ifr_name) + len;
/* Do what you need with the ifr-structure.
* ifr->ifr_addr contains either sockaddr_dl,
* sockaddr_in or sockaddr_in6 depending on
* what addresses and L2 protocols the interface
* has associated in it.
*/
}
close(fd);
return 0;
}
当然,也有一些陷阱。根据 Unix Network Programming 第 17.6 章ioctl(fd, SIOCGIFCONF, array)
,如果参数中指向的数组太小,在某些平台上可能不会返回错误。然后将连接数据。解决此问题的唯一方法是ioctl()
在循环中调用,直到您获得相同的结果长度两次,同时增加数组的大小。当然,由于这是 2012 年,我不确定这是否相关。
在这种情况下,数组的大小ifreqs
纯粹是猜测。请记住,该数组将为struct ifreq
与接口关联的每个 L2 和 L3 地址包含一个。例如,假设您还有 IPv6 地址,对于 lo-interface,您将获得三个条目:以太网、IPv4 和 IPv6。因此保留足够的空间或应用kludge。
要获取广播地址和其他附加信息,您需要ioctl()
在循环中进行附加调用。当然,所有可能的选项都取决于您的操作系统提供的内容。
有关更多信息,我建议阅读 W. Richard Stevens 的 Unix Network Programming。这是关于这个主题的最全面的书。