分享更有价值
被信任是一种快乐

怎么利用Node获取物理网卡mac地址

文章页正文上

本篇内容介绍了“怎么利用Node获取物理网卡mac地址”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带免费云主机、域名领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在基于 Electron 的应用中,有一个业务需求是获取物理网卡的 Mac 地址以用于客户机唯一性识别。刚接到需求时你可能会想,这还不简单,调用 Node.js 的 os 模块提供的 networkInterfaces API 就行了。于是马上开干:

import{networkInterfaces}from'os';

functionisZeroMac(mac){
return/^(0{1,2}[:-]){5}0{1,2}$/.test(mac);
}

functiongetMac(family='IPv4'){
constnif=networkInterfaces();
for(constlistofObject.values(nif)){
constitem=list.find(d=>!d.internal&&!isZeroMac(d.mac)&&(!d.family||d.family===family));
if(item)returnitem.mac;
}

return'';
}

两分钟就写完了,测试一下返回值也与 ipconfig/ifconfig 打印的信息一致,满怀信心的提交代码完工。测试同学当天验证了一下表示没什么问题,然而第二天却找上门了:同一台电脑今昨两天取到的值不一样。经过各种排查分析,最后才发现原来这位测试妹妹因疫情管控居家了,用着 VPN 远程接入办公网络干活呢。原来开 VPN 的时候使用了虚拟网卡,此时你才发现事情并没有那么简单。实际上,在存在 VPN、虚拟机等场景下,都可能会使用到虚拟网卡。networkInterfaces 可以获取到所有网卡的基本信息,可根据 internalmac 等字段的值做一次过滤,得到有效的信息:

constisValid=(item)=>item.internal===false&&!isZeroMac(item.mac);

但是对于 VPN、虚拟机等存在虚拟网卡的场景下,仅根据该信息无法进行有效区分。如果能够得到虚拟网卡的特征,则可基于相关特征点进行识别与过滤。基于某内部项目长达六年的实践积累以及参考 vscode 中类似的实现,我们得到了一个常见虚拟网卡默认 Mac 地址特征的列表,参考如下:

//seehttps://standards-oui.ieee.org/oui/oui.txt
constvirtualMacPrefix=newSet([
'00:05:69',//vmware1
'00:0c:29',//vmware2
'00:50:56',//vmware3
'00:1c:14',//vmware
'00:1c:42',//parallels1
'02:00:4c',//MicrosoftLoopbackAdapter(微软回环网卡)
'00:03:ff',//microsoftvirtualpc
'00:0f:4b',//virtualiron4
'00:16:3e',//redhatxen,oraclevm,xensource,novellxen
'08:00:27',//virtualbox
]);

于是可以据此实现一个是否为虚拟网卡的判断方法 isVirtualMac

exportfunctionisMac(mac:string){
return/^([da-f]{1,2}[:-]){5}([da-f]{1,2})$/i.test(mac);
}

exportfunctionformatMac(mac:string){
returnString(mac).trim().toLowerCase().replace(/-/g,':');
}

exportfunctionisVirtualMac(mac:string){
returnisMac(mac)&&virtualMacPrefix.has(formatMac(mac).slice(0,8));
}

据此可对 getMac 方法改进如下:

functiongetMac(family='IPv4'){
constnif=networkInterfaces();
for(constlistofObject.values(nif)){
constitem=list.find(d=>!d.internal&&!isZeroMac(d.mac)&&(!d.family||d.family===family)&&!isVirtualMac(d.mac));
if(item)returnitem.mac;
}

return'';
}

在 Windows 系统下,可以通过执行 ipconfig /allwmic nic get 命令得到所有网卡的详情,其中包含了描述信息。基于实践经验分析,我们总结了一个常见虚拟网卡描述关键字的特征列表,参考如下:

constvirtualDescList=['virtual','vpn','ssl','tap-windows','hyper-v','km-test','microsoftloopback'];

若经过前述规则过滤之后仍然存在多个网卡信息,则可继续获取网卡详情,并基于 virtualDescList 列表以尝试进一步的过滤处理:

//执行wmicnicget命令获取所有网卡详情
functiongetNetworkIFacesInfoByWmic(){
//略
}

if(hasMutiMac(list)){
constinfo=awaitgetNetworkIFacesInfoByWmic();

list=list.filter(item=>{
if(!info.config[item.mac])returntrue;
constdesc=String(info.config[item.mac].desc).toLowerCase();
return!virtualDescList.some(d=>desc.includes(d));
});
}

过滤方式会将视为无效的项排除,但是可能会因规则的误差而导致最后得到的列表为空。为了避免这种可能现象的出现,可以将过滤排除改为优先级排序方式,最后取列表第一项视为最优选项。排序方法实现示例:

/**
*sortby:!internal>!zeroMac(mac)>visual>family=IPv4
*/
functionifacesSort(list:NetworkInterfaceInfo[]){
returnlist.sort((a,b)=>{
if(a.internal!==b.internal)returna.internal?1:-1;
if(isZeroMac(a.mac)!==isZeroMac(b.mac))returnisZeroMac(a.mac)?1:-1;

constisVirtualA=isVirtualMac(a.mac);
constisVirtualB=isVirtualMac(b.mac);
if(isVirtualA!==isVirtualB)returnisVirtualA?1:-1;

if(a.family!==b.family)returna.family==='IPv6'?1:-1;
});
}

于是最终的逻辑大致如下:获取全部网卡信息基于 iface 特征排序取得全部列表:en0 - mac, eth4 - linux, ethernet - windows 优先级更高基于 internal字段、虚拟网卡特征(mac)、family字段等进行排序对排序的结果进行基础过滤:internal=trueisZeroMac若过滤后列表多于1个,则基于虚拟网卡特征继续过滤若过滤结果仍多余1个,则基于描述特征继续过滤取最终结果的第一项作为最优选择“怎么利用Node获取物理网卡mac地址”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注云技术网站,小编将为大家输出更多高质量的实用文章!

相关推荐: vue的生命周期分为几个阶段

本篇内容介绍了“vue的生命周期分为几个阶段”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! Vue.js是一种前端开发框架,它采用了一些方便开发者工作的技术,其…

文章页内容下
赞(0) 打赏
版权声明:本站采用知识共享、学习交流,不允许用于商业用途;文章由发布者自行承担一切责任,与本站无关。
文章页正文下
文章页评论上

云服务器、web空间可免费试用

宝塔面板主机、支持php,mysql等,SSL部署;安全高速企业专供99.999%稳定,另有高防主机、不限制内容等类型,具体可咨询QQ:360163164,Tel同微信:18905205712

主机选购导航云服务器试用

登录

找回密码

注册