123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /**
- * 获取网口信息,IP地址,MAC地址,状态,带宽等
- *
- * 日期:2020年10月16日
- * 作者:RToax
- */
- #ifndef __IF_INFO_H
- #define __IF_INFO_H 1
- /**
- * struct ifinfo - 网卡信息结构
- *
- * if_idx 网口在系统中的索引, 这里需要注意的是,派生的网口 em1:1 与 em1 的索引相同
- * if_name 网口名,例如:eth0
- * if_flag 网口状态,参见 IFSTAT_XXX 宏定义
- * if_ipv4 网口IP地址,例如:10.170.6.66
- * if_eth.if_ethmac 网口MAC地址,格式:28:6E:D4:88:C7:9A
- * if_eth.if_ethspeed 网口带宽,单位:Mbps
- */
- struct ifinfo {
- unsigned int if_idx; //接口索引号
- char if_name[32]; //接口名 如:eth0
- int if_flag;
- #define IFSTAT_UP 0x0001 /* 接口状态为 up */
- #define IFSTAT_BROADCAST 0x0002 /* 广播地址可用 */
- #define IFSTAT_LOOPBACK 0x0004 /* 该网口是回环口 */
- #define IFSTAT_POINTOPOINT 0x0010 /* 点对点连接 */
- #define IFSTAT_MULTICAST 0x0020 /* 支持多播 */
- char if_ipv4[16]; //接口IPv4地址
- struct {
- char if_ethmac[64]; //MAC地址
- unsigned int if_ethspeed; //速率 Mbps
- }if_eth;
- };
- /**
- * ifinfo_display - 网口状态查询回调函数
- *
- * info 网口信息结构指针,参见: struct ifinfo 说明
- * arg 调用 get_ifinfo 内存地址传入的 arg 地址指针
- */
- typedef void (*ifinfo_display)(const struct ifinfo* info, void* arg);
- /**
- * get_ifinfo - 获取网口信息
- *
- * 该接口可以获取网口的速率,但是,在虚拟机环境中,无法查询网口带宽
- *
- * display_fn 查询的回调函数,参见: ifinfo_display 说明
- * arg 回调函数被调用时的 arg 参数,该参数可以为 NULL
- *
- * return 失败,返回 -1, 成功,返回查询的网口总数
- */
- int get_ifinfo(ifinfo_display display_fn, void* arg);
- /**
- * 获取网口信息,IP地址,MAC地址,状态,带宽等
- *
- * 日期:2020年10月16日
- * 作者:RToax
- */
- #include <unistd.h>
- #include <string.h>
- #include <stdio.h>
- #include <netinet/in.h>
- #include <net/if.h>
- #include <sys/ioctl.h>
- #include <arpa/inet.h>
- #include <linux/sockios.h>
- #include <linux/ethtool.h>
- /* 创建Socket !!!使用完成一定要close 不关闭会导致too many open files */
- static int if_socket()
- {
- int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
- if (sock == -1) {
- return -1;
- }
- return sock;
- }
- /* 获取所有网口的句柄信息 */
- static int get_ifconf_r(int sockfd, struct ifconf* ifc, void* buf, int buf_len)
- {
- if (sockfd <= 2 || !ifc || !buf || buf_len <= 0) {
- return -1;
- }
- ifc->ifc_len = buf_len;
- ifc->ifc_buf = (char*)buf;
- if (ioctl(sockfd, SIOCGIFCONF, ifc) == -1) {
- return -1;
- }
- return 0;
- }
- /* 获取网口状态 */
- static int get_ifstat(int sockfd, const char* if_name, int* if_flag)
- {
- if (sockfd <= 2 || !if_name || !if_flag) {
- return -1;
- }
- struct ifreq ifr;
- *if_flag = 0;
- strcpy(ifr.ifr_name, if_name);
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {
- if (ifr.ifr_flags & IFF_UP) *if_flag |= IFSTAT_UP;
- if (ifr.ifr_flags & IFF_BROADCAST) *if_flag |= IFSTAT_BROADCAST;
- if (ifr.ifr_flags & IFF_LOOPBACK) *if_flag |= IFSTAT_LOOPBACK;
- if (ifr.ifr_flags & IFF_POINTOPOINT) *if_flag |= IFSTAT_POINTOPOINT;
- if (ifr.ifr_flags & IFF_MULTICAST) *if_flag |= IFSTAT_MULTICAST;
- }
- else {
- return -1;
- }
- return 0;
- }
- /* 查询网口 IPv4 地址 */
- static int get_ifaddr(int sockfd, const char* if_name, char* addr, int addr_len)
- {
- if (sockfd <= 2 || !if_name || !addr || addr_len <= 0) {
- return -1;
- }
-
- struct ifreq ifr;
- strcpy(ifr.ifr_name, if_name);
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0) {
- if (ioctl(sockfd, SIOCGIFADDR, &ifr) == 0) {
- snprintf(addr, addr_len, "%s",
- inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
- }
- }
- else {
- return -1;
- }
- return 0;
- }
- /* 查询网口 MAC 地址 */
- static int get_ifhwaddr(int sockfd, const char* if_name, char* hwaddr, int hwaddr_len)
- {
- if (sockfd <= 2 || !if_name || !hwaddr || hwaddr_len <= 0) {
- return -1;
- }
- struct ifreq ifr;
- strcpy(ifr.ifr_name, if_name);
- if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == 0) {
- unsigned char* ptr;
- ptr = (unsigned char*)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
- snprintf(hwaddr, hwaddr_len, "%02X:%02X:%02X:%02X:%02X:%02X",
- *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5));
- }
- else {
- return -1;
- }
- return 0;
- }
- static int get_ifnetMask(int sockfd, const char* if_name, char* netMask, int netMask_len)
- {
- if (sockfd <= 2 || !if_name || !netMask || netMask_len <= 0) {
- return -1;
- }
- struct ifreq ifr;
- strcpy(ifr.ifr_name, if_name);
- if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) == 0) {
- snprintf(netMask, netMask_len, "%s",
- inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
- }
- else {
- return -1;
- }
- return 0;
- }
- /* 查询网口带宽 */
- static int get_ifethspeed(int sockfd, const char* if_name, unsigned int* speed)
- {
- struct ifreq ifr;
- struct ethtool_cmd ep;
- strcpy(ifr.ifr_name, if_name);
- ep.cmd = ETHTOOL_GSET;
- ifr.ifr_data = (caddr_t)&ep;
- if (ioctl(sockfd, SIOCETHTOOL, &ifr) != 0) { // 如果出错退出;
- return -1;
- }
- *speed = ep.speed;
- return 0;
- }
- /**
- * get_ifinfo - 获取网口信息
- *
- * 该接口可以获取网口的速率,但是,在虚拟机环境中,无法查询网口带宽
- *
- * display_fn 查询的回调函数,参见: ifinfo_display 说明
- * arg 回调函数被调用时的 arg 参数,该参数可以为 NULL
- *
- * return 失败,返回 -1, 成功,返回查询的网口总数
- */
- int get_ifinfo(ifinfo_display display_fn, void* arg)
- {
- /* 如果回调函数为空,则返回失败 */
- if (!display_fn) {
- return -1;
- }
- struct ifconf ifc;
- struct ifinfo info;
- char buf[2048];
- int ret = 0;
- int count = 0;
- int sock = if_socket();/* 创建socket */
- ret = get_ifconf_r(sock, &ifc, buf, sizeof(buf));
- if (ret != 0) {
- close(sock);
- return -1;
- }
- /* 巧妙的网口结构保存 */
- struct ifreq* it = ifc.ifc_req;
- const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
- /* 轮询所有网口 */
- for (; it != end; ++it, count++) {
- memset(&info, 0, sizeof(struct ifinfo));
- strcpy(info.if_name, it->ifr_name);
- info.if_idx = if_nametoindex(info.if_name);
- /* 获取一系列的网口信息,当然可以在后面继续开发,
- 但不要忘记在 struct ifinfo 添加对应的单数字段 */
- get_ifstat(sock, info.if_name, &info.if_flag);
- get_ifaddr(sock, info.if_name, info.if_ipv4, sizeof(info.if_ipv4));
- get_ifhwaddr(sock, info.if_name, info.if_eth.if_ethmac, sizeof(info.if_eth.if_ethmac));
- get_ifethspeed(sock, info.if_name, &info.if_eth.if_ethspeed);
- /* 在这里,回调函数将被调用 */
- if (display_fn) display_fn(&info, arg);
- }
- close(sock);
- return count;
- }
- #endif /*<__IF_INFO_H>*/
|