怎么利用Node獲取物理網(wǎng)卡mac地址

本篇內(nèi)容介紹了“怎么利用Node獲取物理網(wǎng)卡mac地址”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)主要從事成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)南召,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢(xún)建站服務(wù):028-86922220

在基于 Electron 的應(yīng)用中,有一個(gè)業(yè)務(wù)需求是獲取物理網(wǎng)卡的 Mac 地址以用于客戶(hù)機(jī)唯一性識(shí)別。

剛接到需求時(shí)你可能會(huì)想,這還不簡(jiǎn)單,調(diào)用 Node.js 的 os 模塊提供的 networkInterfaces API 就行了。

于是馬上開(kāi)干:

import { networkInterfaces } from 'os';

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

function getMac(family = 'IPv4') {
    const nif = networkInterfaces();
    for (const list of Object.values(nif)) {
        const item = list.find(d => !d.internal && !isZeroMac(d.mac) && (!d.family ||d.family === family));
        if (item) return item.mac;
   }

   return '';
}

兩分鐘就寫(xiě)完了,測(cè)試一下返回值也與 ipconfig/ifconfig 打印的信息一致,滿(mǎn)懷信心的提交代碼完工。

測(cè)試同學(xué)當(dāng)天驗(yàn)證了一下表示沒(méi)什么問(wèn)題,然而第二天卻找上門(mén)了:同一臺(tái)電腦今昨兩天取到的值不一樣。經(jīng)過(guò)各種排查分析,最后才發(fā)現(xiàn)原來(lái)這位測(cè)試妹妹因疫情管控居家了,用著 VPN 遠(yuǎn)程接入辦公網(wǎng)絡(luò)干活呢。

原來(lái)開(kāi) VPN 的時(shí)候使用了虛擬網(wǎng)卡,此時(shí)你才發(fā)現(xiàn)事情并沒(méi)有那么簡(jiǎn)單。實(shí)際上,在存在 VPN、虛擬機(jī)等場(chǎng)景下,都可能會(huì)使用到虛擬網(wǎng)卡。

1. 根據(jù) networkInterfaces 返回值的字段值過(guò)濾

networkInterfaces 可以獲取到所有網(wǎng)卡的基本信息,可根據(jù) internal、mac 等字段的值做一次過(guò)濾,得到有效的信息:

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

但是對(duì)于 VPN、虛擬機(jī)等存在虛擬網(wǎng)卡的場(chǎng)景下,僅根據(jù)該信息無(wú)法進(jìn)行有效區(qū)分。

2. 根據(jù)虛擬網(wǎng)卡 Mac 特征過(guò)濾

如果能夠得到虛擬網(wǎng)卡的特征,則可基于相關(guān)特征點(diǎn)進(jìn)行識(shí)別與過(guò)濾。

基于某內(nèi)部項(xiàng)目長(zhǎng)達(dá)六年的實(shí)踐積累以及參考 vscode 中類(lèi)似的實(shí)現(xiàn),我們得到了一個(gè)常見(jiàn)虛擬網(wǎng)卡默認(rèn) Mac 地址特征的列表,參考如下:

// see https://standards-oui.ieee.org/oui/oui.txt
const virtualMacPrefix = new Set([
  '00:05:69', // vmware1
  '00:0c:29', // vmware2
  '00:50:56', // vmware3
  '00:1c:14', // vmware
  '00:1c:42', // parallels1
  '02:00:4c', // Microsoft Loopback Adapter (微軟回環(huán)網(wǎng)卡)
  '00:03:ff', // microsoft virtual pc
  '00:0f:4b', // virtual iron 4
  '00:16:3e', // red hat xen , oracle vm , xen source, novell xen
  '08:00:27', // virtualbox
]);

于是可以據(jù)此實(shí)現(xiàn)一個(gè)是否為虛擬網(wǎng)卡的判斷方法 isVirtualMac

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

export function formatMac(mac: string) {
  return String(mac).trim().toLowerCase().replace(/-/g, ':');
}

export function isVirtualMac(mac: string) {
  return isMac(mac) && virtualMacPrefix.has(formatMac(mac).slice(0, 8));
}

據(jù)此可對(duì) getMac 方法改進(jìn)如下:

function getMac(family = 'IPv4') {
    const nif = networkInterfaces();
    for (const list of Object.values(nif)) {
        const item = list.find(d => !d.internal && !isZeroMac(d.mac) && (!d.family ||d.family === family) && !isVirtualMac(d.mac));
        if (item) return item.mac;
   }

   return '';
}

3. 根據(jù)描述關(guān)鍵字特征過(guò)濾

在 Windows 系統(tǒng)下,可以通過(guò)執(zhí)行 ipconfig /allwmic nic get 命令得到所有網(wǎng)卡的詳情,其中包含了描述信息。

基于實(shí)踐經(jīng)驗(yàn)分析,我們總結(jié)了一個(gè)常見(jiàn)虛擬網(wǎng)卡描述關(guān)鍵字的特征列表,參考如下:

const virtualDescList = ['virtual', ' vpn ', ' ssl ', 'tap-windows', 'hyper-v', 'km-test', 'microsoft loopback'];

若經(jīng)過(guò)前述規(guī)則過(guò)濾之后仍然存在多個(gè)網(wǎng)卡信息,則可繼續(xù)獲取網(wǎng)卡詳情,并基于 virtualDescList 列表以嘗試進(jìn)一步的過(guò)濾處理:

// 執(zhí)行 wmic nic get 命令獲取所有網(wǎng)卡詳情
function getNetworkIFacesInfoByWmic() {
  // 略
}

if (hasMutiMac(list)) {
  const info = await getNetworkIFacesInfoByWmic();

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

4. 按優(yōu)先級(jí)規(guī)則排序

過(guò)濾方式會(huì)將視為無(wú)效的項(xiàng)排除,但是可能會(huì)因規(guī)則的誤差而導(dǎo)致最后得到的列表為空。為了避免這種可能現(xiàn)象的出現(xiàn),可以將過(guò)濾排除改為優(yōu)先級(jí)排序方式,最后取列表第一項(xiàng)視為最優(yōu)選項(xiàng)。

排序方法實(shí)現(xiàn)示例:

/**
 * sort by: !internal > !zeroMac(mac) > visual > family=IPv4 
 */
function ifacesSort(list: NetworkInterfaceInfo[]) {
  return list.sort((a, b) => {
    if (a.internal !== b.internal) return a.internal ? 1 : -1;
    if (isZeroMac(a.mac) !== isZeroMac(b.mac)) return isZeroMac(a.mac) ? 1 : -1;

    const isVirtualA = isVirtualMac(a.mac);
    const isVirtualB = isVirtualMac(b.mac);
    if (isVirtualA !== isVirtualB) return isVirtualA ? 1 : -1;

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

于是最終的邏輯大致如下:

  • 獲取全部網(wǎng)卡信息

  • 基于 iface 特征排序取得全部列表:en0 - mac, eth4 - linux, ethernet - windows 優(yōu)先級(jí)更高

  • 基于 internal字段、虛擬網(wǎng)卡特征(mac)、family字段等進(jìn)行排序

  • 對(duì)排序的結(jié)果進(jìn)行基礎(chǔ)過(guò)濾:internal=true、isZeroMac

  • 若過(guò)濾后列表多于1個(gè),則基于虛擬網(wǎng)卡特征繼續(xù)過(guò)濾

  • 若過(guò)濾結(jié)果仍多余1個(gè),則基于描述特征繼續(xù)過(guò)濾

  • 取最終結(jié)果的第一項(xiàng)作為最優(yōu)選擇

“怎么利用Node獲取物理網(wǎng)卡mac地址”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

分享名稱(chēng):怎么利用Node獲取物理網(wǎng)卡mac地址
轉(zhuǎn)載源于:http://muchs.cn/article34/ipgjpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、做網(wǎng)站、云服務(wù)器、用戶(hù)體驗(yàn)網(wǎng)站策劃、靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名