subnet rfc

This commit is contained in:
whilb 2025-09-01 22:04:35 -07:00
parent 19711f2153
commit bd8a817484
2 changed files with 594 additions and 11 deletions

View file

@ -142,6 +142,328 @@ export default {
return 'Unknown';
}
function getRFCNetworkInfo(ip, cidr) {
const ipLong = ipToLong(ip);
const parts = ip.split('.');
const firstOctet = parseInt(parts[0]);
const secondOctet = parseInt(parts[1]);
// Check for specific RFC-defined ranges
if (firstOctet === 0) {
return {
type: 'Current Network',
description: 'RFC 1122: "This host on this network" - used only as source address',
rfc: 'RFC 1122',
cidr: '0.0.0.0/8'
};
}
if (firstOctet === 10) {
return {
type: 'Private Network',
description: 'RFC 1918: Private IP address range for Class A networks',
rfc: 'RFC 1918',
cidr: '10.0.0.0/8'
};
}
if (firstOctet === 127) {
return {
type: 'Loopback',
description: 'RFC 1122: Loopback addresses - packets sent to this address are processed locally',
rfc: 'RFC 1122',
cidr: '127.0.0.0/8'
};
}
if (firstOctet === 169 && secondOctet === 254) {
return {
type: 'Link-Local',
description: 'RFC 3927: Automatic Private IP Addressing (APIPA) - used when DHCP fails',
rfc: 'RFC 3927',
cidr: '169.254.0.0/16'
};
}
if (firstOctet === 172 && secondOctet >= 16 && secondOctet <= 31) {
return {
type: 'Private Network',
description: 'RFC 1918: Private IP address range for Class B networks',
rfc: 'RFC 1918',
cidr: '172.16.0.0/12'
};
}
if (firstOctet === 192 && secondOctet === 168) {
return {
type: 'Private Network',
description: 'RFC 1918: Private IP address range for Class C networks',
rfc: 'RFC 1918',
cidr: '192.168.0.0/16'
};
}
if (firstOctet === 192 && secondOctet === 0 && parseInt(parts[2]) === 0) {
return {
type: 'IETF Protocol Assignments',
description: 'RFC 5736: Reserved for IETF protocol assignments',
rfc: 'RFC 5736',
cidr: '192.0.0.0/24'
};
}
if (firstOctet === 192 && secondOctet === 0 && parseInt(parts[2]) === 2) {
return {
type: 'Test-Net',
description: 'RFC 5737: Documentation and example code (TEST-NET-1)',
rfc: 'RFC 5737',
cidr: '192.0.2.0/24'
};
}
if (firstOctet === 192 && secondOctet === 88 && parseInt(parts[2]) === 99) {
return {
type: '6to4 Relay',
description: 'RFC 3068: IPv6 to IPv4 relay anycast addresses',
rfc: 'RFC 3068',
cidr: '192.88.99.0/24'
};
}
if (firstOctet === 198 && secondOctet === 18) {
return {
type: 'Benchmark Testing',
description: 'RFC 2544: Network interconnect device benchmark testing',
rfc: 'RFC 2544',
cidr: '198.18.0.0/15'
};
}
if (firstOctet === 198 && secondOctet === 51 && parseInt(parts[2]) === 100) {
return {
type: 'Test-Net',
description: 'RFC 5737: Documentation and example code (TEST-NET-2)',
rfc: 'RFC 5737',
cidr: '198.51.100.0/24'
};
}
if (firstOctet === 203 && secondOctet === 0 && parseInt(parts[2]) === 113) {
return {
type: 'Test-Net',
description: 'RFC 5737: Documentation and example code (TEST-NET-3)',
rfc: 'RFC 5737',
cidr: '203.0.113.0/24'
};
}
if (firstOctet === 100 && secondOctet >= 64 && secondOctet <= 127) {
return {
type: 'CGNAT',
description: 'RFC 6598: Carrier-Grade NAT (CGN) shared address space',
rfc: 'RFC 6598',
cidr: '100.64.0.0/10'
};
}
if (firstOctet >= 224 && firstOctet <= 239) {
return {
type: 'Multicast',
description: 'RFC 1112: Multicast addresses - used for one-to-many communication',
rfc: 'RFC 1112',
cidr: '224.0.0.0/4'
};
}
if (firstOctet >= 240 && firstOctet <= 255) {
return {
type: 'Reserved',
description: 'RFC 1112: Reserved for future use (formerly Class E)',
rfc: 'RFC 1112',
cidr: '240.0.0.0/4'
};
}
if (ipLong === 0xFFFFFFFF) {
return {
type: 'Broadcast',
description: 'RFC 919: Limited broadcast address - reaches all hosts on the local network',
rfc: 'RFC 919'
};
}
// Check for other broadcast addresses based on CIDR
if (cidr < 32) {
const networkLong = (ipLong & ((0xFFFFFFFF << (32 - cidr)) >>> 0)) >>> 0;
const broadcastLong = (networkLong | (~((0xFFFFFFFF << (32 - cidr)) >>> 0)) >>> 0) >>> 0;
if (ipLong === broadcastLong) {
return {
type: 'Network Broadcast',
description: `Broadcast address for /${cidr} network - reaches all hosts in this subnet`,
rfc: 'RFC 919'
};
}
}
// Default case - public IP
return {
type: 'Public IP',
description: 'Globally routable IP address on the Internet',
rfc: null
};
}
function getIPv6NetworkInfo(ipv6, cidr) {
const expanded = expandIPv6(ipv6);
const parts = expanded.split(':');
// Convert to BigInt for comparison
let ipv6Long = 0n;
for (let i = 0; i < 8; i++) {
const part = parseInt(parts[i], 16);
ipv6Long = (ipv6Long << 16n) + BigInt(part);
}
// Check for specific IPv6 reserved ranges
// ::/128 - Unspecified address
if (ipv6Long === 0n) {
return {
type: 'Unspecified',
description: 'RFC 4291: Unspecified address - used only as source address',
rfc: 'RFC 4291',
cidr: '::/128'
};
}
// ::1/128 - Loopback
if (ipv6Long === 1n) {
return {
type: 'Loopback',
description: 'RFC 4291: Loopback address - equivalent to IPv4 127.0.0.1',
rfc: 'RFC 4291',
cidr: '::1/128'
};
}
// 2000::/3 - Global Unicast (public IPv6)
if ((ipv6Long >> 125n) === 4n) { // First 3 bits are 001
return {
type: 'Global Unicast',
description: 'RFC 4291: Globally routable IPv6 addresses (public Internet)',
rfc: 'RFC 4291',
cidr: '2000::/3'
};
}
// fc00::/7 - Unique Local Address (ULA)
if ((ipv6Long >> 121n) === 0x7Dn) { // First 7 bits are 1111110
return {
type: 'Unique Local Address',
description: 'RFC 4193: Private IPv6 addresses (equivalent to IPv4 private ranges)',
rfc: 'RFC 4193',
cidr: 'fc00::/7'
};
}
// fe80::/10 - Link-Local
if ((ipv6Long >> 118n) === 0xFE80n >> 6n) { // First 10 bits are 1111111010
return {
type: 'Link-Local',
description: 'RFC 4291: Link-local addresses - valid only on the local network segment',
rfc: 'RFC 4291',
cidr: 'fe80::/10'
};
}
// ff00::/8 - Multicast
if ((ipv6Long >> 120n) === 0xFFn) { // First 8 bits are 11111111
return {
type: 'Multicast',
description: 'RFC 4291: IPv6 multicast addresses - used for one-to-many communication',
rfc: 'RFC 4291',
cidr: 'ff00::/8'
};
}
// 2001:db8::/32 - Documentation
if ((ipv6Long >> 96n) === 0x20010DB8n) {
return {
type: 'Documentation',
description: 'RFC 3849: Reserved for documentation and example code',
rfc: 'RFC 3849',
cidr: '2001:db8::/32'
};
}
// 2001::/32 - Teredo
if ((ipv6Long >> 96n) === 0x20010000n) {
return {
type: 'Teredo',
description: 'RFC 4380: Teredo tunneling - IPv6 over UDP over IPv4',
rfc: 'RFC 4380',
cidr: '2001::/32'
};
}
// 2002::/16 - 6to4
if ((ipv6Long >> 112n) === 0x2002n) {
return {
type: '6to4',
description: 'RFC 3056: 6to4 tunneling - automatic IPv6 over IPv4 tunneling',
rfc: 'RFC 3056',
cidr: '2002::/16'
};
}
// 64:ff9b::/96 - IPv4-IPv6 Translation
if ((ipv6Long >> 96n) === 0x64FF9B000000000000000000n) {
return {
type: 'IPv4-IPv6 Translation',
description: 'RFC 6052: Well-known prefix for IPv4-IPv6 translation',
rfc: 'RFC 6052',
cidr: '64:ff9b::/96'
};
}
// 100::/64 - Discard-Only
if ((ipv6Long >> 64n) === 0x100000000000000n) {
return {
type: 'Discard-Only',
description: 'RFC 6666: Discard-only address block - packets are discarded',
rfc: 'RFC 6666',
cidr: '100::/64'
};
}
// ::ffff:0:0/96 - IPv4-mapped IPv6
if ((ipv6Long >> 96n) === 0xFFFF00000000n) {
return {
type: 'IPv4-mapped IPv6',
description: 'RFC 4291: IPv4 addresses mapped to IPv6 format',
rfc: 'RFC 4291',
cidr: '::ffff:0:0/96'
};
}
// ::/96 - IPv4-compatible IPv6 (deprecated)
if ((ipv6Long >> 96n) === 0n && (ipv6Long & 0xFFFFFFFF00000000n) === 0n) {
return {
type: 'IPv4-compatible IPv6',
description: 'RFC 4291: IPv4-compatible IPv6 addresses (deprecated)',
rfc: 'RFC 4291',
cidr: '::/96'
};
}
// Default case - other reserved or unknown
return {
type: 'Reserved/Unknown',
description: 'Reserved or unassigned IPv6 address range',
rfc: null
};
}
function ipToLong(ip) {
return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet), 0) >>> 0;
}
@ -375,19 +697,52 @@ export default {
const networkSize = Math.pow(2, 32 - cidr);
const baseLong = ipToLong(baseIP);
// Calculate the base network for the IP (up to /16 level)
// For example: 192.168.1.0 -> 192.168.0.0 (base /16 network)
const baseNetworkLong = baseLong & ((0xFFFFFFFF << (32 - 16)) >>> 0);
const networkLong = baseNetworkLong;
// Calculate the base network for the IP based on the CIDR
// For larger subnets (CIDR < 16), we need to find the appropriate base network
let baseNetworkLong;
let maxNetworks;
// Show up to 64 networks
const count = Math.min(64, Math.floor(65536 / networkSize));
if (cidr <= 8) {
// For /8 and larger, use /8 as the base (Class A)
baseNetworkLong = baseLong & ((0xFFFFFFFF << (32 - 8)) >>> 0);
maxNetworks = Math.min(64, Math.floor(16777216 / networkSize)); // 2^24 / networkSize
} else if (cidr <= 16) {
// For /9 to /16, use /16 as the base (Class B)
baseNetworkLong = baseLong & ((0xFFFFFFFF << (32 - 16)) >>> 0);
maxNetworks = Math.min(64, Math.floor(65536 / networkSize)); // 2^16 / networkSize
} else {
// For /17 and smaller, use the actual network as base
baseNetworkLong = baseLong & ((0xFFFFFFFF << (32 - cidr)) >>> 0);
maxNetworks = Math.min(64, Math.floor(65536 / networkSize));
}
// Show up to 64 networks, but limit based on what makes sense
const count = Math.min(maxNetworks, 64);
for (let i = 0; i < count; i++) {
const networkAddr = networkLong + (i * networkSize);
const networkAddr = baseNetworkLong + (i * networkSize);
const broadcastAddr = networkAddr + networkSize - 1;
const firstHost = networkAddr + 1;
const lastHost = broadcastAddr - 1;
// Handle edge cases for host calculations
let firstHost, lastHost;
if (cidr === 32) {
// /32 - single host, no usable hosts
firstHost = networkAddr;
lastHost = networkAddr;
} else if (cidr === 31) {
// /31 - point-to-point, no usable hosts
firstHost = networkAddr;
lastHost = broadcastAddr;
} else if (cidr === 30) {
// /30 - 4 total hosts, 2 usable
firstHost = networkAddr + 1;
lastHost = broadcastAddr - 1;
} else {
// Normal case - calculate usable hosts
firstHost = networkAddr + 1;
lastHost = broadcastAddr - 1;
}
networks.push({
network: longToIp(networkAddr),
@ -452,13 +807,27 @@ export default {
lastHostLong = broadcastLong - 1;
}
// Calculate total possible networks
// Calculate total possible networks based on CIDR
const networkSize = Math.pow(2, 32 - calculatedCidr);
const totalPossibleNetworks = Math.floor(65536 / networkSize);
let totalPossibleNetworks;
if (calculatedCidr <= 8) {
// For /8 and larger, calculate based on Class A space
totalPossibleNetworks = Math.floor(16777216 / networkSize); // 2^24 / networkSize
} else if (calculatedCidr <= 16) {
// For /9 to /16, calculate based on Class B space
totalPossibleNetworks = Math.floor(65536 / networkSize); // 2^16 / networkSize
} else {
// For /17 and smaller, use the standard calculation
totalPossibleNetworks = Math.floor(65536 / networkSize);
}
// Generate available networks table
const availableNetworks = generateAvailableNetworks(ipAddress, calculatedCidr);
// Get RFC network information
const rfcInfo = getRFCNetworkInfo(ipAddress, calculatedCidr);
out.innerHTML = `
<div style="font-size: 24px; font-weight: 700; color: var(--accent); margin-bottom: 15px;">
IPv4 Subnet Information
@ -505,6 +874,22 @@ export default {
</div>
</div>
<div style="background: var(--border); padding: 15px; border-radius: 8px; margin-top: 15px;">
<h4 style="color: var(--accent); margin-bottom: 10px;">Network Type Information</h4>
<div style="color: var(--text); margin-bottom: 5px;">
<strong>Network Type:</strong> ${rfcInfo.type}
</div>
<div style="color: var(--text); margin-bottom: 5px;">
<strong>Description:</strong> ${rfcInfo.description}
</div>
${rfcInfo.cidr ? `<div style="color: var(--text); margin-bottom: 5px;">
<strong>RFC Range:</strong> ${rfcInfo.cidr}
</div>` : ''}
${rfcInfo.rfc ? `<div style="color: var(--text); margin-bottom: 5px;">
<strong>RFC Reference:</strong> ${rfcInfo.rfc}
</div>` : ''}
</div>
<div style="background: var(--border); padding: 15px; border-radius: 8px; margin-top: 15px;">
<h4 style="color: var(--accent); margin-bottom: 10px;">Binary Representation</h4>
<div style="font-family: monospace; font-size: 14px; color: var(--text); margin-bottom: 5px;">
@ -617,6 +1002,9 @@ export default {
});
}
// Get IPv6 network information
const ipv6NetworkInfo = getIPv6NetworkInfo(ipv6Address, ipv6Cidr);
// Format large numbers for display
function formatBigInt(num) {
if (num < BigInt(1e6)) {
@ -688,6 +1076,22 @@ export default {
</div>
</div>
<div style="background: var(--border); padding: 15px; border-radius: 8px; margin-top: 15px;">
<h4 style="color: var(--accent); margin-bottom: 10px;">Network Type Information</h4>
<div style="color: var(--text); margin-bottom: 5px;">
<strong>Network Type:</strong> ${ipv6NetworkInfo.type}
</div>
<div style="color: var(--text); margin-bottom: 5px;">
<strong>Description:</strong> ${ipv6NetworkInfo.description}
</div>
${ipv6NetworkInfo.cidr ? `<div style="color: var(--text); margin-bottom: 5px;">
<strong>RFC Range:</strong> ${ipv6NetworkInfo.cidr}
</div>` : ''}
${ipv6NetworkInfo.rfc ? `<div style="color: var(--text); margin-bottom: 5px;">
<strong>RFC Reference:</strong> ${ipv6NetworkInfo.rfc}
</div>` : ''}
</div>
<div style="background: var(--border); padding: 15px; border-radius: 8px; margin-top: 15px;">
<h4 style="color: var(--accent); margin-bottom: 10px;">Available Networks</h4>
<div style="overflow-x: auto;">