/** * IP Address Utilities */ import { createRequire } from 'node:module'; /** * Check if string is IPv4 */ export function isIPv4(ip) { if (typeof ip !== 'string') return false; const parts = ip.split('.'); if (parts.length !== 4) return false; return parts.every(part => { const num = parseInt(part, 10); return !isNaN(num) && num >= 0 && num <= 255 && part === String(num); }); } /** * Check if string is IPv6 */ export function isIPv6(ip) { if (typeof ip !== 'string') return false; // Simple check - contains colons and valid hex return ip.includes(':') && /^[0-9a-fA-F:]+$/.test(ip); } /** * Check if IP is in private range (RFC 1918) */ export function isPrivateIp(ip) { if (!isIPv4(ip)) return false; const parts = ip.split('.').map(Number); const [a, b, c, d] = parts; // 10.0.0.0/8 if (a === 10) return true; // 172.16.0.0/12 if (a === 172 && b >= 16 && b <= 31) return true; // 192.168.0.0/16 if (a === 192 && b === 168) return true; // 127.0.0.0/8 (loopback) if (a === 127) return true; // 169.254.0.0/16 (link-local) if (a === 169 && b === 254) return true; return false; } /** * Check if IP is loopback */ export function isLoopbackIp(ip) { if (!isIPv4(ip)) return false; return ip.startsWith('127.'); } /** * Convert IP to integer for range comparison */ export function ipToInt(ip) { return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0; } /** * Parse CIDR notation */ export function parseCidr(cidr) { const [ip, prefix] = cidr.split('/'); const mask = -1 << (32 - parseInt(prefix, 10)); return { ip: ipToInt(ip), mask }; } /** * Check if IP is in CIDR range */ export function isIpInCidr(ip, cidr) { if (!isIPv4(ip)) return false; try { const ipInt = ipToInt(ip); const { ip: networkInt, mask } = parseCidr(cidr); return (ipInt & mask) === (networkInt & mask); } catch (err) { return false; } } /** * Check if two IPs are equal */ export function ipEquals(ip1, ip2) { return ip1 === ip2; } /** * Get IP version (4 or 6) */ export function getIpVersion(ip) { if (isIPv4(ip)) return 4; if (isIPv6(ip)) return 6; return null; } /** * Normalize IP (remove leading zeros, etc.) */ export function normalizeIp(ip) { if (!isIPv4(ip)) return ip; return ip .split('.') .map(part => parseInt(part, 10).toString()) .join('.'); }