'use strict'; Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const node_buffer = require('node:buffer'); const os = require('node:os'); const net = require('node:net'); const isOctal = (byte) => { const str = String(byte); return str.startsWith('0') && /^[0-7]+$/.test(str); }; const parseOctets = (addr) => { return addr .toLowerCase() .split('.') .map((octet) => { if (octet.startsWith('0x')) { return parseInt(octet, 16); } if (isOctal(octet)) { return parseInt(octet, 8); } if (/^[1-9]\d*$/.test(octet)) { return parseInt(octet, 10); } return NaN; }); }; const parseWords = (addr) => { return addr.split(':').flatMap((word) => { if (word === '') { return []; } if (word.includes('.')) { return parseOctets(word); } const int16 = parseInt(word, 16); return [(int16 >> 8) & 0xff, int16 & 0xff]; }); }; const compressv6 = (words) => { const currentZeroSequence = { start: null, length: 0 }; const longestZeroSequence = { start: null, length: 0 }; words.forEach((word, index) => { var _a; if (word === '0') { (_a = currentZeroSequence.start) !== null && _a !== void 0 ? _a : (currentZeroSequence.start = index); currentZeroSequence.length += 1; return; } if (currentZeroSequence.length > longestZeroSequence.length) { Object.assign(longestZeroSequence, currentZeroSequence); } Object.assign(currentZeroSequence, { start: null, length: 0 }); }); if (currentZeroSequence.length > longestZeroSequence.length) { Object.assign(longestZeroSequence, currentZeroSequence); } if (longestZeroSequence.length === 8) { return '::'; } if (longestZeroSequence.length > 1 && longestZeroSequence.start !== null) { words.splice(longestZeroSequence.start, longestZeroSequence.length, ''); } const compressed = words.join(':'); if (compressed.startsWith(':')) { return ':' + compressed; } if (compressed.endsWith(':')) { return compressed + ':'; } return compressed; }; const v4toUInt8Array = (addr) => { if (addr === '') { throw new Error('invalid ip address'); } if (typeof addr !== 'string' && typeof addr !== 'number') { throw new Error('invalid ip address'); } if (typeof addr === 'number' || String(addr).includes('.') === false) { const int32 = isOctal(addr) ? parseInt(String(addr), 8) : Number(addr); return new Uint8Array([ (int32 >> 24) & 0xff, (int32 >> 16) & 0xff, (int32 >> 8) & 0xff, int32 & 0xff, ]); } const FOUR_BYTES = 4; let parts = parseOctets(addr); if (parts.length > FOUR_BYTES) { throw new Error('invalid ip address'); } if (parts.some(Number.isNaN)) { throw new Error('invalid ip address'); } if (parts.some((part) => part < 0 || part > 255)) { throw new Error('invalid ip address'); } if (parts.some((part) => part !== (part | 0))) { throw new Error('invalid ip address'); } if (parts.length < FOUR_BYTES) { parts = parts .slice(0, -1) .concat(Array(4 - parts.length).fill(0), parts.slice(-1)); } return Uint8Array.from(parts); }; const v6toUInt8Array = (addr) => { if (addr === '') { throw new Error('invalid ip address'); } if (typeof addr !== 'string') { throw new Error('invalid ip address'); } if (net.isIPv6(addr) === false) { throw new Error('invalid ip address'); } const SIXTEEN_BYTES = 16; let words; if (addr.includes('::') === false) { words = parseWords(addr); if (words.length > SIXTEEN_BYTES) { throw new Error('invalid ip address'); } } else { const [left, right] = addr.toLowerCase().split('::'); const leftWords = parseWords(left); const rightWords = parseWords(right); if (leftWords.length + rightWords.length > SIXTEEN_BYTES) { throw new Error('invalid ip address 3'); } const padding = Array(SIXTEEN_BYTES).fill(0); words = leftWords.concat(padding.slice(leftWords.length + rightWords.length), rightWords); } if (words.some(Number.isNaN)) { throw new Error('invalid ip address'); } return Uint8Array.from(words); }; const getWordAtIndex = (bytes, index) => { return (bytes[index * 2] << 8) + bytes[index * 2 + 1]; }; const isV4MappedV6 = (bytes) => { if (bytes.length !== 16) { return false; } const sixthWord = getWordAtIndex(bytes, 5); return sixthWord === 0xffff && bytes.slice(0, 10).every((byte) => byte === 0); }; const normalizeFamily = (family) => { if (String(family) === '6' || String(family).toLowerCase() === 'ipv6') { return 'ipv6'; } return 'ipv4'; }; const isV4Format = (addr) => net.isIPv4(addr); const isV6Format = (addr) => net.isIPv6(addr); const toUInt8Array = (addr) => { if (typeof addr === 'string' && addr.includes(':')) { return v6toUInt8Array(addr); } return v4toUInt8Array(addr); }; const toBuffer = (addr, buf, offset) => { offset = ~~Number(offset); const bytes = toUInt8Array(addr); const result = buf || node_buffer.Buffer.alloc(offset + bytes.length); bytes.forEach((byte, index) => (result[offset + index] = byte)); return result; }; const bufferToString = (buf, offset, length) => { offset = ~~Number(offset); length = length || buf.length - offset; if (length === 4) { return buf.subarray(offset, offset + length).join('.'); } if (length === 16) { const words = []; for (let i = 0; i < length; i += 2) { const int16 = buf.readUInt16BE(offset + i); words.push(int16.toString(16)); } return compressv6(words); } throw new Error('invalid ip address'); }; const toString = (bytes, offset, length) => { if (node_buffer.Buffer.isBuffer(bytes)) { return bufferToString(bytes, offset, length); } if (bytes instanceof Uint8Array === false) { throw new Error('argument must be Buffer or a Uint8Array'); } if (bytes.length === 4) { return bytes.join('.'); } if (bytes.length === 16) { const words = []; for (let i = 0; i < bytes.length; i += 2) { const int16 = (bytes[i] << 8) + bytes[i + 1]; words.push(int16.toString(16)); } return compressv6(words); } throw new Error('invalid ip address'); }; const fromPrefixLen = (prefixLength, family) => { if (prefixLength > 32) { family = 'ipv6'; } else { family = normalizeFamily(family); } const len = family === 'ipv6' ? 16 : 4; const bytes = new Uint8Array(len); for (let i = 0; i < len; i += 1) { let bits = 8; if (prefixLength < 8) { bits = prefixLength; } prefixLength -= bits; bytes[i] = ~(0xff >> bits) & 0xff; } return toString(bytes); }; const mask = (addr, subnetMask) => { const addrBytes = toUInt8Array(addr); const maskBytes = toUInt8Array(subnetMask); const result = new Uint8Array(Math.max(addrBytes.length, maskBytes.length)); if (addrBytes.length === maskBytes.length) { for (let i = 0; i < addrBytes.length; i += 1) { result[i] = addrBytes[i] & maskBytes[i]; } return toString(result); } if (maskBytes.length === 4) { for (let i = 0; i < maskBytes.length; i += 1) { result[12 + i] = addrBytes[12 + i] & maskBytes[i]; } return toString(result); } if (addrBytes.length === 4) { result[10] = 0xff; result[11] = 0xff; for (let i = 0; i < addrBytes.length; i += 1) { result[12 + i] = addrBytes[i] & maskBytes[12 + i]; } return toString(result); } throw new Error('invalid ip address'); }; const cidr = (cidrString) => { const [addr, prefixLength, ...rest] = cidrString.split('/'); if (rest.length !== 0) { throw new Error(`invalid CIDR subnet: ${addr}`); } const maskLength = fromPrefixLen(parseInt(prefixLength, 10)); return mask(addr, maskLength); }; const subnet = (addr, subnetMask) => { const maskLong = toLong(subnetMask); let maskLength = 0; for (let i = 0; i < 32; i += 1) { maskLength += (maskLong >> i) & 1; } const addressLong = toLong(mask(addr, subnetMask)); const numberOfAddresses = Math.pow(2, 32 - maskLength); return { networkAddress: fromLong(addressLong), firstAddress: numberOfAddresses > 2 ? fromLong(addressLong + 1) : fromLong(addressLong), lastAddress: numberOfAddresses > 2 ? fromLong(addressLong + numberOfAddresses - 2) : fromLong(addressLong + numberOfAddresses - 1), broadcastAddress: fromLong(addressLong + numberOfAddresses - 1), subnetMask: fromLong(maskLong), subnetMaskLength: maskLength, numHosts: numberOfAddresses > 2 ? numberOfAddresses - 2 : numberOfAddresses, length: numberOfAddresses, contains: (other) => addressLong === toLong(mask(other, subnetMask)), }; }; const cidrSubnet = (cidrString) => { const [addr, prefixLength, ...rest] = cidrString.split('/'); if (rest.length !== 0) { throw new Error(`invalid CIDR subnet: ${addr}`); } const maskBytes = fromPrefixLen(parseInt(prefixLength, 10)); return subnet(addr, maskBytes); }; const not = (addr) => { const bytes = toUInt8Array(addr); for (let i = 0; i < bytes.length; i += 1) { bytes[i] = 0xff ^ bytes[i]; } return toString(bytes); }; const or = (addr1, addr2) => { const a = toUInt8Array(addr1); const b = toUInt8Array(addr2); if (a.length === b.length) { for (let i = 0; i < a.length; i += 1) { a[i] |= b[i]; } return toString(a); } let buff = a; let other = b; if (b.length > a.length) { buff = b; other = a; } const offset = buff.length - other.length; for (let i = offset; i < buff.length; i += 1) { buff[i] |= other[i - offset]; } return toString(buff); }; const isEqual = (addr1, addr2) => { let a = toUInt8Array(addr1); let b = toUInt8Array(addr2); if (a.length === b.length) { return a.every((byte, index) => byte === b[index]); } if (b.length === 4) { const t = b; b = a; a = t; } for (let i = 0; i < 10; i += 1) { if (b[i] !== 0) { return false; } } const sixthWord = getWordAtIndex(b, 5); if (sixthWord !== 0xffff && sixthWord !== 0) { return false; } for (let i = 0; i < 4; i += 1) { if (a[i] !== b[i + 12]) { return false; } } return true; }; const isLoopback = (addr) => { let bytes; try { bytes = toUInt8Array(addr); } catch (ignore) { return false; } if (isV4MappedV6(bytes)) { bytes = bytes.slice(12); } if (bytes.length === 4) { return bytes[0] === 127; } return bytes[15] === 1 && bytes.slice(0, -1).every((byte) => byte === 0); }; const isLinkLocal = (addr) => { let bytes; try { bytes = toUInt8Array(addr); } catch (ignore) { return false; } if (isV4MappedV6(bytes)) { bytes = bytes.slice(12); } if (bytes.length === 4) { return bytes[0] === 169 && bytes[1] === 254; } const firstWord = getWordAtIndex(bytes, 0); return firstWord >= 0xfe80 && firstWord <= 0xfebf; }; const isReserved = (addr) => { let bytes; try { bytes = toUInt8Array(addr); } catch (ignore) { return false; } if (isV4MappedV6(bytes)) { bytes = bytes.slice(12); } if (bytes.length === 4) { if (bytes[0] === 0) { return true; } if (bytes.every((byte) => byte === 255)) { return true; } if (bytes[0] === 192 && bytes[1] === 0 && bytes[2] === 2) { return true; } if (bytes[0] === 198 && bytes[1] === 51 && bytes[2] === 100) { return true; } if (bytes[0] === 203 && bytes[1] === 0 && bytes[2] === 113) { return true; } if (bytes[0] >= 224 && bytes[0] <= 239) { return true; } if (bytes[0] === 192 && bytes[1] === 0 && bytes[2] === 0) { return true; } if (bytes[0] === 192 && bytes[1] === 88 && bytes[2] === 99) { return true; } if (bytes[0] === 198 && bytes[1] >= 18 && bytes[1] <= 19) { return true; } return false; } const firstWord = getWordAtIndex(bytes, 0); if (firstWord === 0xff00) { return true; } if (firstWord === 0x0100) { return true; } if (firstWord === 0x2001) { return true; } if (firstWord === 0x2002) { return true; } if (bytes.every((byte) => byte === 0)) { return true; } return bytes.every((byte) => byte === 0xff); }; const isPrivate = (addr) => { if (isLoopback(addr)) { return true; } if (isLinkLocal(addr)) { return true; } if (isReserved(addr)) { return true; } let bytes; try { bytes = toUInt8Array(addr); } catch (ignore) { return false; } if (isV4MappedV6(bytes)) { bytes = bytes.slice(12); } if (bytes.length === 4) { if (bytes[0] === 10) { return true; } if (bytes[0] === 172 && bytes[1] >= 16 && bytes[1] <= 31) { return true; } if (bytes[0] === 192 && bytes[1] === 168) { return true; } } const firstWord = getWordAtIndex(bytes, 0); if (firstWord >= 0xfc00 && firstWord <= 0xfdff) { return true; } if (firstWord >= 0xfe80 && firstWord <= 0xfebf) { return true; } return false; }; const isPublic = (addr) => { if (typeof addr === 'string' && net.isIP(addr) === 0) { return false; } try { return isPrivate(addr) === false; } catch (ignore) { return false; } }; const loopback = (family) => { family = normalizeFamily(family); if (family !== 'ipv4' && family !== 'ipv6') { throw new Error('family must be ipv4 or ipv6'); } return family === 'ipv4' ? '127.0.0.1' : 'fe80::1'; }; const address = (name, family) => { var _a; const interfaces = os.networkInterfaces(); family = normalizeFamily(family); if (name && name !== 'public' && name !== 'private') { const res = (_a = interfaces[name]) === null || _a === void 0 ? void 0 : _a.filter((details) => { const itemFamily = normalizeFamily(details.family); return itemFamily === family; }); if (!res || res.length === 0) { return undefined; } return res[0].address; } const inter = Object.values(interfaces).flatMap((nic) => { if (!nic) { return []; } return nic.filter((details) => { if (isLoopback(details.address) || isLinkLocal(details.address)) { return false; } if (normalizeFamily(details.family) !== family) { return false; } if (!name) { return true; } if (name === 'public' && isPublic(details.address)) { return true; } if (name === 'private' && isPrivate(details.address)) { return true; } return false; }); }); if (inter.length === 0) { return loopback(family); } return inter[0].address; }; const toLong = (addr) => { const bytes = toUInt8Array(addr); if (bytes.length !== 4) { throw new Error('invalid ip address'); } return bytes.reduce((acc, byte) => acc * 256 + byte, 0); }; const fromLong = (int32) => { if (int32 >>> 0 !== int32) { throw new Error('invalid long value'); } return `${int32 >>> 24}.${(int32 >> 16) & 255}.${(int32 >> 8) & 255}.${int32 & 255}`; }; const normalizeToLong = (addr) => { try { return toLong(addr); } catch (ignore) { return -1; } }; const normalize = (addr) => { return toString(toUInt8Array(addr)); }; exports.address = address; exports.cidr = cidr; exports.cidrSubnet = cidrSubnet; exports.fromLong = fromLong; exports.fromPrefixLen = fromPrefixLen; exports.isEqual = isEqual; exports.isLinkLocal = isLinkLocal; exports.isLoopback = isLoopback; exports.isPrivate = isPrivate; exports.isPublic = isPublic; exports.isReserved = isReserved; exports.isV4Format = isV4Format; exports.isV6Format = isV6Format; exports.loopback = loopback; exports.mask = mask; exports.normalize = normalize; exports.normalizeToLong = normalizeToLong; exports.not = not; exports.or = or; exports.subnet = subnet; exports.toBuffer = toBuffer; exports.toLong = toLong; exports.toString = toString; exports.toUInt8Array = toUInt8Array;