您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么利用Node獲取物理網卡mac地址”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
在基于 Electron 的應用中,有一個業務需求是獲取物理網卡的 Mac 地址以用于客戶機唯一性識別。
剛接到需求時你可能會想,這還不簡單,調用 Node.js 的 os 模塊提供的 networkInterfaces
API 就行了。
于是馬上開干:
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、虛擬機等場景下,都可能會使用到虛擬網卡。
networkInterfaces
可以獲取到所有網卡的基本信息,可根據 internal
、mac
等字段的值做一次過濾,得到有效的信息:
const isValid = (item) => item.internal === false && !isZeroMac(item.mac);
但是對于 VPN、虛擬機等存在虛擬網卡的場景下,僅根據該信息無法進行有效區分。
如果能夠得到虛擬網卡的特征,則可基于相關特征點進行識別與過濾。
基于某內部項目長達六年的實踐積累以及參考 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 '';
}
在 Windows 系統下,可以通過執行 ipconfig /all
或 wmic 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));
});
}
過濾方式會將視為無效的項排除,但是可能會因規則的誤差而導致最后得到的列表為空。為了避免這種可能現象的出現,可以將過濾排除改為優先級排序方式,最后取列表第一項視為最優選項。
排序方法實現示例:
/**
* 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, eth4 - linux, ethernet - windows
優先級更高
基于 internal
字段、虛擬網卡特征(mac
)、family
字段等進行排序
對排序的結果進行基礎過濾:internal=true
、isZeroMac
若過濾后列表多于1個,則基于虛擬網卡特征繼續過濾
若過濾結果仍多余1個,則基于描述特征繼續過濾
取最終結果的第一項作為最優選擇
“怎么利用Node獲取物理網卡mac地址”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。