| 平台 | PAT 埠範圍 | 每 IP 埠數 | 最大轉譯次數 |
| Cisco IOS/IOS-XE | 1024–65535 | 64,512 | 64,512 × outside IPs |
| Cisco ASA | 1024–65535 (default) | 64,512 | 受限於 xlate 表記憶體 |
| Linux iptables/nftables | 1024–65535 (default) | 64,512 | 受限於 conntrack 表大小 |
| Windows Server NAT | 1025–5000 (legacy) / 1024–65535 | 63,511 | 透過登錄檔設定 |
| RFC 4787 (BEHAVE) | 建議保留來源埠 | — | 每個終端機對應埠 |
const PAT_PORTS = 64512; // 65535 - 1024 + 1 (ports 1024-65535)
let natEntries = [];
let nextPatPort = 1024;
function calcPat() {
const hosts = parseInt(document.getElementById('insideHosts').value);
const ips = parseInt(document.getElementById('outsideIps').value);
const sessPerHost = parseInt(document.getElementById('sessPerHost').value);
const proto = document.getElementById('natProto').value;
const section = document.getElementById('patResult');
const content = document.getElementById('patResultContent');
section.style.display = 'block';
if (isNaN(hosts) || isNaN(ips) || isNaN(sessPerHost) || hosts < 1 || ips < 1 || sessPerHost < 1) {
content.innerHTML = 'Invalid input. All fields must be positive numbers.
';
return;
}
const poolSize = proto === 'both' ? PAT_PORTS * 2 * ips : PAT_PORTS * ips;
const totalSessions = hosts * sessPerHost;
const utilPct = Math.min((totalSessions / poolSize) * 100, 100);
const isExhausted = totalSessions > poolSize;
const overflow = isExhausted ? totalSessions - poolSize : 0;
const barColor = utilPct > 90 ? '#dc3545' : utilPct > 70 ? '#f7971e' : '#4CAF50';
content.innerHTML = `
${poolSize.toLocaleString()}
Total PAT slots (pool)
${totalSessions.toLocaleString()}
Sessions required
${utilPct.toFixed(1)}%
Pool utilization
${isExhausted ? `
${overflow.toLocaleString()}
Sessions DROPPED (overflow)
` : ''}
${isExhausted
? `Port exhaustion! Need ${Math.ceil(totalSessions / PAT_PORTS)} outside IPs to support current session load.`
: `Sufficient capacity. ${(poolSize - totalSessions).toLocaleString()} PAT slots remaining.`}
Formula: ${ips} IP(s) × ${proto === 'both' ? '2 × ' : ''}64,512 ports = ${poolSize.toLocaleString()} slots
`;
}
function addNatEntry() {
const insideIp = document.getElementById('simInsideIp').value.trim();
const insidePort = parseInt(document.getElementById('simInsidePort').value);
const outsideIp = document.getElementById('simOutsideIp').value.trim();
const dstIpPort = document.getElementById('simDstIpPort').value.trim();
if (!insideIp || !outsideIp || !dstIpPort || isNaN(insidePort)) {
alert('Fill in all simulator fields.');
return;
}
const patPort = nextPatPort++;
if (patPort > 65535) { alert('PAT pool exhausted (port 65535 reached).'); return; }
natEntries.push({ insideIp, insidePort, outsideIp, patPort, dstIpPort, proto: 'TCP' });
renderNatTable();
// Auto-increment inside port for easy demo
document.getElementById('simInsidePort').value = insidePort + 1;
}
function clearNatTable() {
natEntries = [];
nextPatPort = 1024;
renderNatTable();
}
function renderNatTable() {
const div = document.getElementById('natTable');
const section = document.getElementById('natTableSection');
if (!natEntries.length) {
section.style.display = 'none';
div.innerHTML = '';
return;
}
section.style.display = 'block';
let rows = natEntries.map((e, i) => `
| ${i + 1} |
${e.insideIp}:${e.insidePort} |
${e.outsideIp}:${e.patPort} |
${e.dstIpPort} |
${e.proto} |
`).join('');
div.innerHTML = `
| # | Inside Local | Inside Global (PAT) | Destination | Proto |
${rows}
${natEntries.length} entries | Next PAT port: ${nextPatPort}
`;
}