1.基础用法,获取eth0的mac地址
- #include
- #include
- #include
- #include
- #include
-
- #include
// struct ifreq -
- int get_mac(unsigned char binMAC[6])
- {
- int sock;
- struct ifreq ifr;
- unsigned char *puc;
- memset(binMAC, 0, 6);
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock == -1)
- {
- perror("socket");
- return -1;
- }
- strcpy(ifr.ifr_name, "eth0"); // 虚拟机中是ens33
- if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
- {
- close(sock);
- perror("ioctl");
- return -1;
- }
- puc = ifr.ifr_hwaddr.sa_data;
- close(sock);
- memcpy(binMAC, puc, 6);
- return 0;
- }
-
- int main(){
- unsigned char mac[6];
- get_mac(mac);
- printf("get_mac: %02x-%02X-%02X-%02X-%02X-%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- }
此处是通过设置ifr_name,然后通过ioctl获取mac地址,ifr_name一般是eth0或者ens33。无论是否联网都可以获取到,但是当程序运行在其他客户端,不可能要求用户那里的网卡名称也是eth0,所以此方法仅能用作本地测试,或者用命令行方式传入网卡名称,然后获取指定网卡名称的mac地址。可是ifconfig命令不是更好用更方便吗?
2.遍历活动网卡
- #include
- #include
- #include
- #include
- #include
-
- #include
- #include
// struct ifreq -
- int print_macs()
- {
- int sock;
- int i = 0, ifCount = 0;
- int code = 0;
- struct ifreq ifr;
- struct ifreq* it = NULL;
- struct ifconf ifc;
- unsigned char* pBuffer = NULL;
- unsigned char *puc = NULL;
-
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock == -1)
- {
- perror("socket");
- return -1;
- }
-
- pBuffer = (unsigned char*)malloc(3000);
- ifc.ifc_len = 3000;
- ifc.ifc_buf = pBuffer;
-
- code = ioctl(sock, SIOCGIFCONF, &ifc);
- printf("ioctl return %d, ifc_len:3000->%d, ifr size:%d\n", code, ifc.ifc_len, sizeof(struct ifreq));
- if (code < 0)
- {
- free(pBuffer);
- close(sock);
- perror("ioctl");
- return -1;
- }
-
- it = ifc.ifc_req;
- ifCount = ifc.ifc_len/sizeof(struct ifreq);
-
- for(i = 0; i < ifCount; ++i){
- strcpy(ifr.ifr_name, it[i].ifr_name);
- code = ioctl(sock, SIOCGIFFLAGS, &ifr);
- printf("\n%d:%s:\n", i, ifr.ifr_name);
- if(0 == code){
- printf("flags:%x\n", ifr.ifr_flags);
- }else{
- printf("flagserror\n");
- }
-
- code = ioctl(sock, SIOCGIFHWADDR, &ifr);
- if(0 == code){
- puc = ifr.ifr_hwaddr.sa_data;
- printf("mac:%02x-%02x-%02x-%02x-%02x-%02x\n", \
- puc[0], puc[1], puc[2], puc[3], puc[4], puc[5]);
- }else{
- printf("mac:errrrrrrrr\n");
- }
- }
-
- close(sock);
- free(pBuffer);
-
- return 0;
- }
-
- int main(){
- print_macs();
- }
ioctl调用SIOCGIFCONF只能获取到活动网卡,如果把ens33或者eth0的网络连接断开,就获取不到了。
3.参考ifconfig
经过方式1和2,只要能获取到网卡的名称就能获取到mac地址了,但是方式2获取不到无连接的网卡,方式1能获取mac地址却不能提前知道网卡名称。只能想着用其他方式获取网卡名称了。
查看了ifconfig的部分源码发现:
interface name是从/proc/net/dev中读取的。如虚拟机从该文件中读到了ens33,
address是从/sys/class/net/ens33/address中读取的,ens33是interface name,address是ens33的其中一个属性,ens33目录下还有多个其他文件。通过文件属性查看是一个symbol link,指向一个device。
小贴士:
ioctl参数:
man ioctl_list
man的输出窗口中输入/sock可以搜索到关键词sock,下面就是sock相关的ioctl的command
sock的ioctl参数主要是ifreq和ifconf
man netdevice可以看到两个结构体的定义