一、MAC地址获取的可变因素
1、多样性
- 多网络接口:现代计算机和服务器通常配备有多个网络接口,包括物理网络接口和虚拟网络接口。每个接口都可能有自己的MAC地址,这增加了获取特定MAC地址的复杂性。
- 虚拟化环境:在虚拟化环境中,如VMware、KVM等,虚拟机会被分配虚拟网络接口和相应的MAC地址。这些MAC地址可能与宿主机的物理MAC地址不同,且可能随着虚拟机的迁移而发生变化。
2、可变性
- 硬件更换:更换网络接口卡(NIC)会直接导致MAC地址的更改。这是因为MAC地址是绑定在NIC上的,更换NIC后,新的NIC将具有不同的MAC地址。
- 操作系统和驱动程序:某些操作系统或驱动程序允许用户更改MAC地址,这称为MAC地址欺骗或克隆。虽然这种更改在大多数情况下是非法的,但在某些特定场景下(如测试或安全测试)可能会被使用。
- 网络管理策略:网络管理员可能会出于安全或管理目的更改MAC地址,例如,在部署新的网络设备或重新配置网络时。
3、人为因素
- 错误配置:网络管理员或用户在配置网络时可能会错误地输入MAC地址,导致无法正确识别设备。
- 恶意修改:恶意用户或软件可能会更改MAC地址以逃避检测或进行网络钓鱼攻击。
二、如何应对Mac地址可变性
虚拟化环境中MAC地址非唯一的情况:
- 检测虚拟化环境:首先确认系统是否运行在虚拟化环境中。
- 检查MAC地址唯一性:在虚拟化环境中,通过管理工具或脚本定期检查各虚拟机的MAC地址,确认其唯一性。
- MAC地址冲突检测:如果发现MAC地址冲突,应立即进行冲突检测,确定哪些虚拟机或设备使用了相同的MAC地址。
- 处理MAC地址冲突:
- 更新MAC地址:对于冲突的虚拟机,可以手动或通过自动化脚本更新其MAC地址。
- 更新映射表:确保网络设备的MAC地址表(如交换机的CAM表)得到更新,以反映最新的MAC地址与虚拟机/设备的映射关系。
处理Mac地址漂移情况:
- 监控MAC地址漂移:实施持续的监控机制,以检测网络中MAC地址的异常变化。
- 分析漂移原因:一旦检测到MAC地址漂移,立即分析其原因,可能包括配置错误、网络故障或安全事件等。
- 根据原因处理:
- 配置错误:检查并修改虚拟化配置,确保MAC地址分配正确无误。
- 网络故障:检查网络设备(如交换机、路由器)的运行状态,修复任何可能的故障。
- 安全事件:实施安全措施,如隔离受影响的虚拟机/设备,调查并防止进一步的攻击。
三、实现代码
1、获取电脑上所有的Mac地址
方法1 使用第三方库, npm install systeminformation
const si = require('systeminformation');
si.networkInterfaces().then(data => {
console.log(data); // 包含所有网络接口的详细信息,包括MAC地址
data.forEach(interface => {
console.log(`${interface.iface}: ${interface.mac}`);
});
}).catch(error => {
console.error(error);
});
方法二
/**
输出本机上所有的Mac地址
**/
const os = require('os');
function getPhysicalMacAddresses() {
const interfaces = os.networkInterfaces();
const macAddresses = { wired: [], wireless: [] };
for (const [name, ifaceArray] of Object.entries(interfaces)) {
ifaceArray.forEach(iface => {
console.log("name=>"+name);
console.log("ifaceArray=>"+ifaceArray);
}
}
2、思路以及实现
20240823完善代码
/**
1、检查并获取有线网卡的MAC地址(如果存在)。 如果没有有线网卡,则获取Wi-Fi接口的MAC地址。
2、最好用管理员打开。
3、如果系统上有多个网络接口(例如,多个有线网卡或多个Wi-Fi适配器),你需要确定选择哪个接口的MAC地址。通常,你会选择“主”接口,但这需要一种方法来识别它。
4、排除掉虚拟化的网络接口。
5、MAC地址可能被视为敏感信息,要告知用户。
6、MAC地址被篡改情况暂不考虑。
**/
const os = require('os');
function getPhysicalMacAddresses() {
const interfaces = os.networkInterfaces();
const macAddresses = { wired: [], wireless: [] };
for (const [name, ifaceArray] of Object.entries(interfaces)) {
ifaceArray.forEach(iface => {
if (!iface.internal && iface.family === 'IPv4') {
const isVirtual = name.toLowerCase().includes('vm') || name.toLowerCase().includes('vbox') || name.toLowerCase().includes('virtual');
if (!isVirtual) {
if (name.toLowerCase().includes('eth') || name.toLowerCase().includes('en')) {
macAddresses.wired.push(iface.mac);
} else if (name.toLowerCase().includes('wlan') || name.toLowerCase().includes('wi-fi') || name.toLowerCase().includes('wl')) {
macAddresses.wireless.push(iface.mac);
}
}
}
});
}
console.log("Wired MAC Addresses (Physical):", macAddresses.wired);
console.log("Wireless MAC Addresses:", macAddresses.wireless);
return macAddresses.wireless;
}
20240827完善代码
/**
* 1.优先尝试获取有线网卡的MAC地址。
2.如果没有找到,则尝试获取无线网卡的MAC地址。
3.如果仍然没有找到,最后获取虚拟网卡的MAC地址。
*/
const os = require('os');
function getPhysicalMacAddresses() {
const interfaces = os.networkInterfaces();
let macAddress = '';
function findMacAddress(keywords, excludeKeywords = []) {
// 对接口名称排序,保证每次处理的顺序一致
const sortedNames = Object.keys(interfaces).sort();
for (const name of sortedNames) {
const ifaceArray = interfaces[name];
const nameLower = name.toLowerCase();
if (excludeKeywords.some(keyword => nameLower.includes(keyword))) {
continue;
}
for (const iface of ifaceArray) {
if (!iface.internal && iface.family === 'IPv4') {
if (keywords.some(keyword => nameLower.includes(keyword))) {
return iface.mac;
}
}
}
}
return null;
}
// 优先顺序:有线 -> 无线 -> 虚拟
macAddress = findMacAddress(['eth', 'en', '本地连接'], ['vm', 'vbox', 'virtual', 'wsl']) ||
findMacAddress(['wlan', 'wi-fi', 'wl'], ['vm', 'vbox', 'virtual', 'wsl']) ||
findMacAddress(['vm', 'vbox', 'virtual', 'wsl']);
console.log("Selected MAC Address:", macAddress);
return macAddress;
}
getPhysicalMacAddresses();