/** * Optimized IP Address Utilities * * High-performance versions for hot paths */ // CIDR cache for repeated lookups const cidrCache = new Map(); const CIDR_CACHE_SIZE = 1000; /** * Fast IPv4 check - less strict but much faster * Only validates format, not strict numeric ranges */ export function isIPv4Fast(ip) { if (typeof ip !== 'string') return false; // Quick length check (min: 7 for "0.0.0.0", max: 15 for "255.255.255.255") if (ip.length < 7 || ip.length > 15) return false; let dots = 0; for (let i = 0; i < ip.length; i++) { const c = ip.charCodeAt(i); if (c === 46) { // '.' dots++; } else if (c < 48 || c > 57) { // not 0-9 return false; } } return dots === 3; } /** * Ultra-fast IP to integer conversion * Direct character parsing, no string splitting */ export function ipToIntFast(ip) { let result = 0; let octet = 0; let shift = 24; for (let i = 0; i < ip.length; i++) { const c = ip.charCodeAt(i); if (c === 46) { // '.' result |= (octet << shift); octet = 0; shift -= 8; } else { octet = octet * 10 + (c - 48); } } return (result | octet) >>> 0; } /** * Fast CIDR parsing with caching */ export function parseCidrCached(cidr) { // Check cache first let cached = cidrCache.get(cidr); if (cached) return cached; // Parse and cache const slashIdx = cidr.indexOf('/'); if (slashIdx === -1) return null; const ip = cidr.slice(0, slashIdx); const prefix = parseInt(cidr.slice(slashIdx + 1), 10); const mask = -1 << (32 - prefix); cached = { network: ipToIntFast(ip), mask, prefix }; // Simple LRU - clear if too big if (cidrCache.size >= CIDR_CACHE_SIZE) { cidrCache.clear(); } cidrCache.set(cidr, cached); return cached; } /** * Ultra-fast IP in CIDR check * Uses caching and optimized parsing */ export function isIpInCidrFast(ip, cidr) { const cached = parseCidrCached(cidr); if (!cached) return false; const ipInt = ipToIntFast(ip); return (ipInt & cached.mask) === (cached.network & cached.mask); } /** * Fast private IP check using bit manipulation */ export function isPrivateIpFast(ip) { const ipInt = ipToIntFast(ip); // 10.0.0.0/8: 0x0A000000 to 0x0AFFFFFF if ((ipInt >>> 24) === 10) return true; // 172.16.0.0/12: 0xAC100000 to 0xAC1FFFFF const high16 = ipInt >>> 16; if (high16 >= 0xAC10 && high16 <= 0xAC1F) return true; // 192.168.0.0/16: 0xC0A80000 to 0xC0A8FFFF if (high16 === 0xC0A8) return true; // 127.0.0.0/8: 0x7F000000 to 0x7FFFFFFF if ((ipInt >>> 24) === 127) return true; // 169.254.0.0/16: 0xA9FE0000 to 0xA9FEFFFF if (high16 === 0xA9FE) return true; return false; } /** * Optimized built-in function evaluator * Direct dispatch without object lookups */ export function evaluateBuiltInFast(name, args) { switch (name) { case 'ip_in_cidr': return isIpInCidrFast(args[0], args[1]); case 'ip_is_private': return isPrivateIpFast(args[0]); case 'ip_is_loopback': return (ipToIntFast(args[0]) >>> 24) === 127; case 'ip_version': return isIPv4Fast(args[0]) ? 4 : (args[0].includes(':') ? 6 : null); case 'ip_equals': return args[0] === args[1]; case 'contains': return String(args[0]).includes(String(args[1])); case 'starts_with': return String(args[0]).startsWith(String(args[1])); case 'ends_with': return String(args[0]).endsWith(String(args[1])); case 'equals': return args[0] === args[1]; case 'greater_than': return args[0] > args[1]; case 'less_than': return args[0] < args[1]; case 'in_range': return args[0] >= args[1] && args[0] <= args[2]; case 'hour_of_day': return new Date(args[0]).getHours(); case 'day_of_week': return new Date(args[0]).getDay(); default: throw new Error(`Unknown: ${name}`); } } // Re-export original functions for compatibility export { isIPv4, isIPv6, isLoopbackIp, getIpVersion, normalizeIp } from './ip-utils.js'; export { isIpInCidr, isPrivateIp } from './ip-utils.js';