1.首先通过SIOCGIFCONF选项,获取所有接口表项(注:无ip地址的接口无法通过SIOCGIFCONF选项获得,需要访问特定文件才能获得,下图会有提示)
2.使用SIOCGIFADDR只能获得ipv4地址,ipv6需要访问特定获得文件(下图有提示)
本人电脑运行的结果也印证上面两点
代码:
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
const char* Inet_ntop(struct sockaddr*);
struct ifreq_own {
char* ifro;
size_t ifro_len;
int ifro_fd;
};
void* Malloc(size_t len) {
void* ptr;
if ((ptr = malloc(len)) == NULL) {
printf("malloc error: %s\n",strerror(errno));
exit(1);
}else {
return ptr;
}
}
void* Calloc(size_t n,size_t len) {
void* ptr;
if ((ptr = calloc(n,len)) == NULL) {
printf("calloc error: %s\n",strerror(errno));
exit(1);
}else {
return ptr;
}
}
struct ifreq_own get_ifreq() {
int sockfd;
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
printf("socket error %s:", strerror(errno));
exit(1);
}
char *buf;
size_t lastlen = 0;
size_t nowlen = 10 * sizeof(struct ifreq);
struct ifconf ifc;
for (; ;) {
buf = Malloc(nowlen);
ifc.ifc_buf = buf;
ifc.ifc_len = nowlen;
if (ioctl(sockfd,SIOCGIFCONF,&ifc) < 0) {
if (errno != EINVAL || lastlen != 0) {
printf("ioctl error: %s\n",strerror(errno));
exit(1);
}
}else {
if (ifc.ifc_len == lastlen) {
break;
}else {
lastlen = ifc.ifc_len;
}
}
nowlen += 10 * sizeof(struct ifreq);
free(buf);
}
size_t size = ifc.ifc_len / sizeof(struct ifreq);
struct ifreq_own ret;
ret.ifro = buf;
ret.ifro_len = size;
ret.ifro_fd = sockfd;
return ret;
}
void free_ifreq(void* ptr) {
if (ptr == NULL) {
return;
}else {
free(ptr);
}
}
void printInterface() {
struct ifreq_own get = get_ifreq();
char* beg = get.ifro;
struct ifreq* ifr;
for (size_t i = 0; i < get.ifro_len; ++i,beg += sizeof(struct ifreq)) {
ifr = (struct ifreq*)beg;
printf("接口名称: %s\n",ifr->ifr_name);
if (ioctl(get.ifro_fd,SIOCGIFADDR,ifr) < 0) {
printf("ioctl error: %s\n",strerror(errno));
continue;
}
printf("接口地址: %s\n",Inet_ntop(&(ifr->ifr_addr)));
if (ioctl(get.ifro_fd,SIOCGIFHWADDR,ifr) < 0) {
printf("ioctl error: %s\n",strerror(errno));
continue;
}
printf("硬件地址:" );
unsigned char g_hwaddr[IFHWADDRLEN];
memcpy(g_hwaddr,ifr->ifr_addr.sa_data,IFHWADDRLEN);
int j = 0;
for (; j < IFHWADDRLEN - 1; ++j) {
printf("%.2x:",g_hwaddr[j]);
}
printf("%.2x\n",g_hwaddr[j]);
if (ioctl(get.ifro_fd,SIOCGIFFLAGS,ifr) < 0) {
printf("ioctl error: %s\n",strerror(errno));
continue;
}
short flags = ifr->ifr_flags;
char str[128] = "< ";
if (flags & IFF_UP) {
char* ptr = "UP ";
strncat(str,ptr,128);
}
if (flags & IFF_BROADCAST) {
if (ioctl(get.ifro_fd,SIOCGIFBRDADDR,ifr) < 0) {
printf("ioctl error: %s\n",strerror(errno));
continue;
}
printf("广播地址: %s\n",Inet_ntop(&(ifr->ifr_addr)));
char* ptr = "BROADCAST ";
strncat(str,ptr,128);
}
if (flags & IFF_MULTICAST) {
char* ptr = "MULTICAST ";
strncat(str,ptr,128);
}
if (flags & IFF_POINTOPOINT) {
if (ioctl(get.ifro_fd,SIOCGIFDSTADDR,ifr) < 0) {
printf("ioctl error: %s\n",strerror(errno));
continue;
}
printf("目的地址: %s\n",Inet_ntop(&(ifr->ifr_addr)));
}
if (flags & IFF_RUNNING) {
char* ptr = "RUNNING ";
strncat(str,ptr,128);
}
if (flags & IFF_LOOPBACK) {
char* ptr = "LOOP ";
strncat(str,ptr,128);
}
strncat(str,">",128);
printf("%s ",str);
if (ioctl(get.ifro_fd,SIOCGIFMTU,ifr) < 0) {
printf("ioctl error: %s\n",strerror(errno));
continue;
}
int mtu = ifr->ifr_mtu; //别用short,否则可能会溢出
printf("MTU: %d\n",mtu);
printf("\n\n");
}
free_ifreq(get.ifro);
}
const char* Inet_ntop(struct sockaddr* src) {
char str4[INET_ADDRSTRLEN];
return inet_ntop(AF_INET,&((struct sockaddr_in*)src)->sin_addr,str4,INET_ADDRSTRLEN);
}
int main() {
printInterface();
}
ifconfig结果:
本人运行结果:
enp1s0没分配ip,是不会获取到的,但是我们可以通过他的名字填充struct ifreq里的ifr_name,调用ioctl获得其他信息