Linux网络接口:ifreq的使用

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地址等信息,从而实现对网络接口的控制和管理。

操作系统标签