ioctl 获取接口信息

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获得其他信息

猜你喜欢

转载自blog.csdn.net/rgbmarco/article/details/79437275