站長資訊網
        最全最豐富的資訊網站

        如何利用Node獲取物理網卡mac地址

        本篇文章介紹一下利用Node獲取真實物理網卡的 MAC 地址的方法,其中主要討論了基于實踐經驗對虛擬網卡的識別處理方式,希望對大家有所幫助!

        如何利用Node獲取物理網卡mac地址

        node.js極速入門課程:進入學習

        在基于 Electron 的應用中,有一個業務需求是獲取物理網卡的 Mac 地址以用于客戶機唯一性識別。

        剛接到需求時你可能會想,這還不簡單,調用 Node.js 的 os 模塊提供的 networkInterfaces API 就行了。【相關教程推薦:nodejs視頻教程】

        于是馬上開干:

        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 ''; }
        登錄后復制

        兩分鐘就寫完了,測試一下返回值也與 ipconfig/ifconfig 打印的信息一致,滿懷信心的提交代碼完工。

        測試同學當天驗證了一下表示沒什么問題,然而第二天卻找上門了:同一臺電腦今昨兩天取到的值不一樣。經過各種排查分析,最后才發現原來這位測試妹妹因疫情管控居家了,用著 VPN 遠程接入辦公網絡干活呢。

        原來開 VPN 的時候使用了虛擬網卡,此時你才發現事情并沒有那么簡單。實際上,在存在 VPN、虛擬機等場景下,都可能會使用到虛擬網卡。

        1. 根據 networkInterfaces 返回值的字段值過濾

        networkInterfaces 可以獲取到所有網卡的基本信息,可根據 internalmac 等字段的值做一次過濾,得到有效的信息:

        const isValid = (item) => item.internal === false && !isZeroMac(item.mac);
        登錄后復制

        但是對于 VPN、虛擬機等存在虛擬網卡的場景下,僅根據該信息無法進行有效區分。

        2. 根據虛擬網卡 Mac 特征過濾

        如果能夠得到虛擬網卡的特征,則可基于相關特征點進行識別與過濾。

        基于某內部項目長達六年的實踐積累以及參考 vscode 中類似的實現,我們得到了一個常見虛擬網卡默認 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 (微軟回環網卡)   '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 ]);
        登錄后復制

        于是可以據此實現一個是否為虛擬網卡的判斷方法 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)); }
        登錄后復制

        據此可對 getMac 方法改進如下:

        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. 根據描述關鍵字特征過濾

        在 Windows 系統下,可以通過執行 ipconfig /allwmic nic get 命令得到所有網卡的詳情,其中包含了描述信息。

        基于實踐經驗分析,我們總結了一個常見虛擬網卡描述關鍵字的特征列表,參考如下:

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

        若經過前述規則過濾之后仍然存在多個網卡信息,則可繼續獲取網卡詳情,并基于 virtualDescList 列表以嘗試進一步的過濾處理:

        // 執行 wmic nic get 命令獲取所有網卡詳情 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));   }); }
        登錄后復制

        getNetworkIFacesInfoByWmic 方法的具體實現可以參見這里:

        https://github.com/lzwme/get-physical-address/blob/main/src/getIFacesByExec.ts#L121

        4. 按優先級規則排序

        過濾方式會將視為無效的項排除,但是可能會因規則的誤差而導致最后得到的列表為空。為了避免這種可能現象的出現,可以將過濾排除改為優先級排序方式,最后取列表第一項視為最優選項。

        排序方法實現示例:

        /**  * 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;   }); }
        登錄后復制

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

        • 獲取全部網卡信息
        • 基于 iface 特征排序取得全部列表:en0 - mac, eth3 - linux, ethernet - windows 優先級更高
        • 基于 internal字段、虛擬網卡特征(mac)、family字段等進行排序
        • 對排序的結果進行基礎過濾:internal=trueisZeroMac
        • 若過濾后列表多于1個,則基于虛擬網卡特征繼續過濾
        • 若過濾結果仍多余1個,則基于描述特征繼續過濾
        • 取最終結果的第一項作為最優選擇

        如何利用Node獲取物理網卡mac地址

        5. 總結與參考

        實際上社區里已經有 address、getmac和macaddress 等較為流行的相關庫,但它們都不涉及虛擬網卡的識別。 本文主要介紹了基于實踐經驗對虛擬網卡的識別處理方式,與 vscode 中的相關實現邏輯較為相似,但又增加了基于描述信息過濾的規則邏輯。

        • www.npmjs.com/package/add…
        • www.npmjs.com/package/get…
        • www.npmjs.com/package/mac…
        • github.com/sebhildebra…
        • github.com/microsoft/v…
        • github.com/lzwme/get-p…
        • lzw.me/a/nodejs-ge…

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 亚洲精品456播放| 国产女主播精品大秀系列| 亚洲AV无码久久精品成人| 亚洲国产精品第一区二区| 亚洲av无码国产精品色午夜字幕| 国产精品V亚洲精品V日韩精品| 1000部精品久久久久久久久| 亚洲一区无码精品色| 国产精品一区三区| 精品少妇一区二区三区视频| 久久精品午夜一区二区福利| 亚洲精品黄色视频在线观看免费资源| 久久亚洲精品中文字幕三区| 精品无码久久久久国产| 正在播放国产精品每日更新| 人妻偷人精品成人AV| 国产亚洲精品自在线观看| 99国内精品久久久久久久| 精品在线免费观看| 91探花福利精品国产自产在线| 精品无码一区二区三区爱欲九九| 午夜精品久久久久久久| 亚洲国产精品无码专区| 日韩精品在线播放| 老司机精品影院91| 精品一区二区三区在线观看| 国产精品主播一区二区| 国产精品理论片在线观看| AAA级久久久精品无码区| 亚洲欧洲国产日韩精品| 亚洲综合国产精品| 日韩精品一区二区三区大桥未久 | 亚洲AV永久纯肉无码精品动漫| 日韩熟女精品一区二区三区 | 久久精品嫩草影院| 国内精品久久久久久野外| 国产精品视频第一页| 久久精品国产亚洲麻豆| 日韩欧国产精品一区综合无码| 欧美精品国产日韩综合在线| 99久久国产综合精品网成人影院|