1. 简介
Linux网络接口提供了一组用于管理和配置网络接口的函数和结构。其中一个常用的结构是ifreq结构体,它用于向内核查询和设置网络接口的各种属性。通过使用ifreq,可以获取和修改网络接口的MAC地址、IP地址、网络掩码等信息,还可以控制接口的状态和特性。
2. ifreq结构体
ifreq结构体定义在头文件<netinet/if.h>
中,它包含了两个成员变量:
ifrn_name:一个字符数组,用于保存接口的名称。
ifru_data:一个联合体,根据不同的操作类型来保存查询或设置的结果。
ifreq结构体的定义如下:
struct ifreq {
char ifrn_name[IFNAMSIZ]; // 接口名称
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ];
char ifru_newname[IFNAMSIZ];
void __user *ifru_data;
struct if_settings ifru_settings;
} ifr_ifru;
};
3. 查询接口的MAC地址
3.1. 查询接口名称
在使用ifreq查询接口的MAC地址之前,首先需要确定要查询的接口名称。可以使用ifconf结构体配合ioctl函数来获取系统中所有可用的网络接口名称。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
int main() {
struct ifconf ifc;
struct ifreq *ifr;
char buf[BUFSIZ];
int sockfd, num, i;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
perror("ioctl");
exit(1);
}
num = ifc.ifc_len / sizeof(struct ifreq);
ifr = ifc.ifc_req;
for (i = 0; i < num; i++) {
printf("Interface name: %s\n", ifr[i].ifr_name);
}
close(sockfd);
return 0;
}
运行以上程序,可以输出系统中所有可用的网络接口名称。
3.2. 查询MAC地址
已知接口名称后,可以通过ifreq结构体和ioctl函数来查询接口的MAC地址。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
int main() {
struct ifreq ifr;
int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
strncpy(ifr.ifrn_name, "eth0", IFNAMSIZ);
if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
perror("ioctl");
close(sockfd);
exit(1);
}
unsigned char *mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;
printf("MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
close(sockfd);
return 0;
}
以上代码将查询名为"eth0"的接口的MAC地址,并打印输出。可以根据实际情况修改接口名称。
4. 查询和设置IP地址
4.1. 查询IP地址
与查询MAC地址类似,查询IP地址也是通过ifreq结构体和ioctl函数实现。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
int main() {
struct ifreq ifr;
int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
strncpy(ifr.ifrn_name, "eth0", IFNAMSIZ);
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {
perror("ioctl");
close(sockfd);
exit(1);
}
struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
printf("IP address: %s\n", inet_ntoa(addr->sin_addr));
close(sockfd);
return 0;
}
以上代码将查询名为"eth0"的接口的IP地址,并打印输出。仍然可以根据实际情况修改接口名称。
4.2. 设置IP地址
要设置接口的IP地址,可以根据所需的IP地址和子网掩码构造一个sockaddr_in结构,并将其存储到ifreq结构体的ifru_addr成员中,然后使用ioctl函数进行设置。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
int main() {
struct ifreq ifr;
int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
strncpy(ifr.ifrn_name, "eth0", IFNAMSIZ);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
inet_pton(AF_INET, "192.168.1.100", &addr.sin_addr);
memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));
if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
perror("ioctl");
close(sockfd);
exit(1);
}
printf("IP address set successfully.\n");
close(sockfd);
return 0;
}
以上代码将设置名为"eth0"的接口的IP地址为"192.168.1.100"。同样,可以根据实际情况修改接口名称和IP地址。
5. 其他操作
除了查询和设置MAC地址、IP地址之外,ifreq还可以用于设置其他网络接口的属性,如MTU和标志位等。具体的操作和使用方法可以参考Linux的相关文档和头文件。
6. 结论
ifreq结构体提供了一种方便的方法来查询和设置Linux网络接口的各种属性。通过使用ifreq结构体和ioctl函数,可以轻松地获取和修改接口的MAC地址、IP地址等信息,从而实现对网络接口的控制和管理。