IPv6地址计算器

IPv6地址压缩/展开、前缀计算、地址类型识别

📥 输入IPv6地址

function isValidIPv6(addr) { // 处理 :: 缩写 const expanded = expandIPv6(addr); if (!expanded) return false; const parts = expanded.split(':'); if (parts.length !== 8) return false; for (let p of parts) { if (!/^[0-9a-fA-F]{1,4}$/.test(p)) return false; } return true; } function expandIPv6(addr) { addr = addr.trim(); if (addr === '::') return '0000:0000:0000:0000:0000:0000:0000:0000'; let parts = addr.split(':'); const doubleColonIdx = parts.indexOf(''); if (doubleColonIdx === -1) { if (parts.length !== 8) return null; return parts.map(p => p.padStart(4, '0')).join(':'); } // 处理 :: 在开头或结尾 if (addr.startsWith('::')) { parts = parts.filter(p => p !== ''); const missing = 8 - parts.length; const zeros = Array(missing).fill('0000'); return [...zeros, ...parts.map(p => p.padStart(4, '0'))].join(':'); } if (addr.endsWith('::')) { parts = parts.filter(p => p !== ''); const missing = 8 - parts.length; const zeros = Array(missing).fill('0000'); return [...parts.map(p => p.padStart(4, '0')), ...zeros].join(':'); } // :: 在中间 const leftParts = parts.slice(0, doubleColonIdx); const rightParts = parts.slice(doubleColonIdx + 1).filter(p => p !== ''); const missing = 8 - leftParts.length - rightParts.length; if (missing <= 0) return null; const zeros = Array(missing).fill('0000'); return [...leftParts.map(p => p.padStart(4, '0')), ...zeros, ...rightParts.map(p => p.padStart(4, '0'))].join(':'); } function compressIPv6(expanded) { const parts = expanded.split(':'); // 找到最长的连续零段 let maxZeroStart = -1, maxZeroLen = 0; let curStart = -1, curLen = 0; for (let i = 0; i < parts.length; i++) { if (parts[i] === '0000') { if (curStart === -1) curStart = i; curLen++; } else { if (curLen > maxZeroLen) { maxZeroLen = curLen; maxZeroStart = curStart; } curStart = -1; curLen = 0; } } if (curLen > maxZeroLen) { maxZeroLen = curLen; maxZeroStart = curStart; } if (maxZeroLen >= 2) { const compressed = parts.map((p, i) => i >= maxZeroStart && i < maxZeroStart + maxZeroLen ? '' : p.replace(/^0+/, '') || '0').filter((v,i,arr) => !(v==='' && arr[i-1]==='')).join(':'); return compressed.replace(/:{2,}/g, '::'); } return parts.map(p => p.replace(/^0+/, '') || '0').join(':'); } function ipv6ToBinary(expanded) { const parts = expanded.split(':'); return parts.map(p => parseInt(p, 16).toString(2).padStart(16, '0')).join(' '); } function detectType(expanded) { const firstGroup = parseInt(expanded.split(':')[0], 16); // 未指定地址 if (expanded === '0000:0000:0000:0000:0000:0000:0000:0000') { return { type: '未指定地址', badge: 'type-special', desc: '::/128 - 表示没有分配地址,类似IPv4的0.0.0.0' }; } // 回环地址 if (expanded === '0000:0000:0000:0000:0000:0000:0000:0001') { return { type: '回环地址', badge: 'type-special', desc: '::1/128 - 类似IPv4的127.0.0.1' }; } // IPv4映射地址 if (expanded.startsWith('0000:0000:0000:0000:0000:ffff:')) { return { type: 'IPv4映射地址', badge: 'type-unicast', desc: '::ffff:x.x.x.x - 用于IPv4和IPv6双栈环境' }; } // 6to4地址 if (expanded.startsWith('2002:')) { return { type: '6to4地址', badge: 'type-unicast', desc: '2002::/16 - 用于IPv6 over IPv4隧道' }; } // Teredo地址 if (expanded.startsWith('2001:0000:')) { return { type: 'Teredo地址', badge: 'type-unicast', desc: '2001::/32 - NAT穿越隧道协议' }; } // 链路本地地址 if (expanded.startsWith('fe80:') || expanded.startsWith('febf:') || (firstGroup >= 0xfe80 && firstGroup <= 0xfebf)) { return { type: '链路本地地址', badge: 'type-linklocal', desc: 'fe80::/10 - 仅在同一链路上有效,不可路由' }; } // 唯一本地地址 (ULA) if ((firstGroup >= 0xfc00 && firstGroup <= 0xfdff)) { return { type: '唯一本地地址 (ULA)', badge: 'type-linklocal', desc: 'fc00::/7 - 类似IPv4的私有地址,fd00::/8常用' }; } // 组播地址 if ((firstGroup >= 0xff00 && firstGroup <= 0xffff)) { const scopeMap = { 1:'接口本地', 2:'链路本地', 5:'站点本地', 8:'组织本地', 14:'全局' }; const flags = (parseInt(expanded.split(':')[1], 16) >> 28) & 0xf; const scopeId = parseInt(expanded.split(':')[1], 16) & 0xf; return { type: '组播地址', badge: 'type-multicast', desc: `ff00::/8 | 标志:${flags===0?'永久':'临时'} | 范围:${scopeMap[scopeId]||'保留'}` }; } // 全局单播地址 if ((firstGroup >= 0x2000 && firstGroup <= 0x3fff)) { return { type: '全局单播地址 (GUA)', badge: 'type-unicast', desc: '2000::/3 - 可在Internet上路由的公网地址' }; } // 文档用途地址 if (expanded.startsWith('2001:0db8:')) { return { type: '文档用途地址', badge: 'type-unicast', desc: '2001:db8::/32 - RFC3849定义,仅用于文档示例' }; } return { type: '其他/保留', badge: 'type-special', desc: '该地址属于保留或特殊用途范围' }; } function calculatePrefixInfo(expanded, prefixLen) { if (isNaN(prefixLen) || prefixLen < 0 || prefixLen > 128) prefixLen = 64; const fullBin = expanded.split(':').map(g => parseInt(g, 16).toString(2).padStart(16, '0')).join(''); const prefixBin = fullBin.substring(0, prefixLen); const suffixBin = fullBin.substring(prefixLen); // 计算网络前缀 const networkBin = prefixBin + '0'.repeat(128 - prefixLen); const networkHex = []; for (let i = 0; i < 128; i += 16) { networkHex.push(parseInt(networkBin.substr(i, 16), 2).toString(16).padStart(4, '0')); } const networkAddr = networkHex.join(':'); // 总主机数 const hostBits = 128 - prefixLen; const totalHosts = hostBits > 78 ? '极大 (2^' + hostBits + ')' : BigInt(Math.pow(2, hostBits)).toLocaleString(); return { networkAddr, prefixLen, totalHosts, hostBits }; } function calculate() { document.getElementById('errorMsg').textContent = ''; const addr = document.getElementById('ipv6Input').value.trim(); if (!isValidIPv6(addr)) { document.getElementById('errorMsg').textContent = '❌ 无效的IPv6地址格式'; document.getElementById('resultCard').style.display = 'none'; document.getElementById('prefixCard').style.display = 'none'; document.getElementById('typeCard').style.display = 'none'; return; } const expanded = expandIPv6(addr); const compressed = compressIPv6(expanded); const binary = ipv6ToBinary(expanded); const typeInfo = detectType(expanded); const prefixInfo = calculatePrefixInfo(expanded, 64); // 结果展示 const results = [ { label: '完整格式 (展开)', value: expanded }, { label: '压缩格式', value: compressed, copy: true }, { label: '内嵌IPv4表示', value: getEmbeddedIPv4(expanded) || '-' }, { label: '总位数', value: '128位' }, { label: '段数', value: '8段 (每段16位)' } ]; let gridHtml = ''; results.forEach(r => { gridHtml += `
${r.label}
${r.value}${r.copy ? '' : ''}
`; }); document.getElementById('resultGrid').innerHTML = gridHtml; document.getElementById('resultCard').style.display = 'block'; // 前缀信息表格 document.querySelector('#prefixTable tbody').innerHTML = ` 网络前缀 (/64)${prefixInfo.networkAddr} 前缀长度${prefixInfo.prefixLen} 位 主机位长度${prefixInfo.hostBits} 位 可用主机数${prefixInfo.totalHosts} 二进制表示${binary} `; document.getElementById('prefixCard').style.display = 'block'; // 类型信息 document.getElementById('typeInfo').innerHTML = `
地址类型
${typeInfo.type}
详细说明
${typeInfo.desc}
`; document.getElementById('typeCard').style.display = 'block'; } function getEmbeddedIPv4(expanded) { // 检查IPv4映射 ::ffff:x.x.x.x if (expanded.startsWith('0000:0000:0000:0000:0000:ffff:')) { const last2 = expanded.split(':').slice(-2); const dec = last2.map(h => parseInt(h, 16)); return `${dec[0] >> 8}.${dec[0] & 255}.${dec[1] >> 8}.${dec[1] & 255}`; } // 检查IPv4兼容 ::x.x.x.x if (expanded.startsWith('0000:0000:0000:0000:0000:0000:')) { const last2 = expanded.split(':').slice(-2); const dec = last2.map(h => parseInt(h, 16)); return `${dec[0] >> 8}.${dec[0] & 255}.${dec[1] >> 8}.${dec[1] & 255}`; } return null; } function copyText(text) { navigator.clipboard.writeText(text).then(() => alert('已复制: ' + text)); } document.getElementById('ipv6Input').addEventListener('keypress', e => { if(e.key==='Enter') calculate(); }); window.onload = calculate;