import os from "os"; import { exec } from "child_process"; export interface ARPCacheEntry { ip: string, mac: string } export class ARPCache { private constructor() {} // Matches IP address and MAC address in an ARP cache entry. // // Note on IP address part: This part of the regular expression is created for extraction, not for validation of IP addresses. // Note on MAC address part: Modified from https://stackoverflow.com/a/4260512/2013757 private static readonly RE_ARP_CACHE_ENTRY: RegExp = /^.*?((?:[0-9]{1,3}\.){3}(?:[0-9]{1,3})){1}.*?((?:[0-9A-Fa-f]{1,2}[:-]){5}(?:[0-9A-Fa-f]{1,2})).*$/gm; static async getRawARPCache(): Promise { let cmd: string = ""; switch (os.platform()) { case "darwin": cmd = "arp -a -n"; break; case "linux": cmd = "/usr/sbin/arp -a -n"; break; case "win32": cmd = "arp -a"; break; default: throw new Error("OS not supported."); } const promise = new Promise((resolve, reject) => { exec(cmd, (error, stdout, stderr) => { if (error) { reject(error); return; } if (stderr && stderr.length > 0) { reject(new Error(stderr)); return; } resolve(stdout); }); }); return await promise; } static async getARPCache(): Promise { const rawARPCache = await this.getRawARPCache(); const rawEntries = [...rawARPCache.matchAll(this.RE_ARP_CACHE_ENTRY)]; const arpCache: ARPCacheEntry[] = rawEntries.map((rawEntry) => { return { ip: rawEntry[1], mac: rawEntry[2] }; }); return arpCache; } }