【小菜学网络】MAC地址详解 (2)

例子中,系统总共有 3 块已启用网卡,名字分别是 enp0s3 、 enp0s8 以及 lo 。其中 lo 是环回网卡,用于本机通讯。ether 08:00:27:49:50:dd 表明,网卡 enp0s3 的物理地址是 08:00:27:49:50:dd 。

请注意,ifconfig 是一个比较老旧的命令,正在慢慢淡出历史舞台。

ip 命令也可以查看系统网卡信息,默认显示所有网卡:

fasion@u2004 [ ~ ] ➜ ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:49:50:dd brd ff:ff:ff:ff:ff:ff 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:56:83:1c brd ff:ff:ff:ff:ff:ff

ip 命令输出信息比较紧凑, link/ether 08:00:27:49:50:dd 这行展示网卡的物理地址。

ip 命令是一个比较新的命令,功能非常强大。它除了可以用于管理网络设备,还可以用于管理路由表,策略路由以及各种隧道。因此,推荐重点学习掌握 ip 命令的用法。

编程获取网卡地址

如果程序中需要用到网卡地址,如何获取呢?

有个方法是执行 ip 命令输出网卡详情,然后从输出信息中截取网卡地址。例如:

fasion@u2004 [ ~ ] ➜ ip link show dev enp0s3 | grep \'link/ether\' | awk \'{print $2}\' 08:00:27:49:50:dd

这种方法多用于 Shell 编程中。

更优雅的办法是通过套接字编程,直接向操作系统获取。Linux 套接字支持通过 ioctl 系统调用获取网络设备信息,大致步骤如下:

创建一个套接字,任意类型均可;

准备 ifreq 结构体,用于保存网卡设备信息;

将待查询网卡名填充到 ifreq 结构体;

调用 ioctl 系统调用,向套接字发起 SIOCGIFHWADDR 请求,获取物理地址;

如无错漏,内核将被查询网卡的物理地址填充在 ifreq 结构体 ifr_hwaddr 字段中;

最后,附上一个完整的例子:

#include <net/if.h> #include <stdio.h> #include <string.h> #include <sys/ioctl.h> #include <sys/socket.h> /** * Convert binary MAC address to readable format. * * Arguments * n: binary format, must be 6 bytes. * * a: buffer for readable format, 18 bytes at least(`\0` included). **/ void mac_ntoa(unsigned char *n, char *a) { // traverse 6 bytes one by one sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", n[0], n[1], n[2], n[3], n[4], n[5]); } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "no iface given\n"); return 1; } // create a socket, any type is ok int s = socket(AF_INET, SOCK_STREAM, 0); if (-1 == s) { perror("Fail to create socket"); return 2; } // fill iface name to struct ifreq struct ifreq ifr; strncpy(ifr.ifr_name, argv[1], 15); // call ioctl to get hardware address int ret = ioctl(s, SIOCGIFHWADDR, &ifr); if (-1 == ret) { perror("Fail to get mac address"); return 3; } // convert to readable format char mac[18]; mac_ntoa((unsigned char *)ifr.ifr_hwaddr.sa_data, mac); // output result printf("IFace: %s\n", ifr.ifr_name); printf("MAC: %s\n", mac); return 0; }

其中,mac_ntoa 函数调用字符串格式化函数 sprintf 将原始 MAC 地址转换成冒分十六进制形式。

【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注:

【小菜学网络】MAC地址详解

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfysw.html