是否可以直接从网卡读取MAC地址?我有下面的代码,但它只是从上面的层读取,而不是卡本身。
我正在尝试找出如何在我的 Linux 机器上找到以太网网卡的原始 MAC 地址。我了解如何使用 ifconfig 查找当前的 MAC 地址。
但是地址可以更改,例如使用
ifconfig eth0 hw ether uu:vv:ww:yy:xx:zz
或使用
/etc/sysconfig/network-scripts/ifcfg-eth0
“永久”设置它。
如何找到原始MAC地址?一定有办法找到它,因为它仍然永久地烧录到卡中,但我找不到读取烧录地址的工具。
有任何实用程序或命令吗?
我想应该可以为其编写C代码,下面的代码给出了我的当前MAC,但不是原始MAC:
#include <stdio.h> /* Standard I/O */
#include <stdlib.h> /* Standard Library */
#include <errno.h> /* Error number and related */
#define ENUMS
#include <sys/socket.h>
#include <net/route.h>
#include <net/if.h>
#include <features.h> /* for the glibc version number */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <netdb.h>
int main( int argc, char * argv[] ){
unsigned char mac[IFHWADDRLEN];
int i;
get_local_hwaddr( argv[1], mac );
for( i = 0; i < IFHWADDRLEN; i++ ){
printf( "%02X:", (unsigned int)(mac[i]) );
}
}
int get_local_hwaddr(const char *ifname, unsigned char *mac)
{
struct ifreq ifr;
int fd;
int rv; // return value - error value from df or ioctl call
/* determine the local MAC address */
strcpy(ifr.ifr_name, ifname);
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (fd < 0)
rv = fd;
else {
rv = ioctl(fd, SIOCGIFHWADDR, &ifr);
if (rv >= 0) /* worked okay */
memcpy(mac, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
}
return rv;
}
操作系统:Red Hat Linux,2.6.18.8-1
当然,在 ethtool 中,您可以只打印地址:
-P --show-permaddr Queries the specified network device for permanent hardware address.
例如
ethtool -P eth0
产生
永久地址:94:de:80:6a:21:25
如果使用 Fedora,请尝试
cat /sys/class/net/eth0/address
或 cat /sys/class/net/em1/address
。应该可以。
原始答案在这里:系统管理员的笔记
找到原始 MAC 地址的唯一方法是使用与网卡驱动程序相同的方法 - 不幸的是,我不相信有一种通用方法可以告诉驱动程序“由硬件提供”提供其 MAC 地址。当然,在某些情况下,该特定接口没有硬件网卡 - 例如用于虚拟化以及使用网桥和软件交换机时的虚拟网络驱动程序。
当然,硬件可能会导致您无法在被软件覆盖后真正读取“原始”MAC 地址,因为 MAC 地址本身只有一组寄存器。
我快速浏览了
pcnet32.c
驱动程序(因为它是网卡的型号之一,我大致了解它是如何工作的以及不同的寄存器在哪里等,所以我可以看到它的作用)。据我所知,它不支持实际询问“你的 PROM 以太网地址是什么”的方法 - MAC 地址是在模块初始化的“probe1”部分读出的,并存储起来。不会进一步访问这些硬件寄存器。
嗯,旧的以太网地址保留在卡 eeprom 的第一个字节中(至少对于某些类型的卡),因此可以使用
ethtool
提取它
bash$ sudo ethtool -e eth1
Offset Values
------ ------
0x0000 tt uu ww xx yy zz 79 03
0x....
其中 tt:uu:ww:xx:yy:zz 是旧的 Mac 地址
这可能不是编程方式,但为什么不搜索
dmesg
。我所有机器的 NIC 在检测时都会吐出 MAC 地址。
尝试这样的事情:
dmesg|grep eth0
不同的网卡显示的 MAC 地址不同,但日志将始终包含适配器的内核给定名称(大多数情况下为
eth0
或 wlan0
)。
在 Ubuntu 18.4 LTS 中
首先需要通过命令找到电脑上的网络接口名称
ls /sys/class/net
我的输出是
docker0 enp0s31f6 lo
现在您可以使用上面讨论的命令,不要忘记 sudo
sudo ethtool -P enp0s31f6
这显示了 Realtek 的真实 MAC,但不是 Intel 的(在我的例子中它显示了绑定 MAC),所以这都是关于驱动程序的。
dmesg | grep -Ei '([a-z0-9]{2}:){5}[a-z0-9]{2}'
此命令列出所有以太网设备和原始硬件地址。
dmesg | grep eth | grep IRQ | awk {'print "permanent address of " $5 " " $9'} |tr "," " "