Subnet Calculator: IP Address, Subnet Mask, Network, Broadcast, Usable IPs
:root {
–primary-color: #004a99;
–success-color: #28a745;
–background-color: #f8f9fa;
–text-color: #333;
–border-color: #ddd;
–card-background: #fff;
–shadow: 0 2px 5px rgba(0,0,0,0.1);
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(–background-color);
color: var(–text-color);
line-height: 1.6;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 20px;
padding-bottom: 40px;
}
.container {
width: 100%;
max-width: 960px;
background-color: var(–card-background);
padding: 30px;
border-radius: 8px;
box-shadow: var(–shadow);
margin: 0 auto;
box-sizing: border-box;
}
h1, h2, h3 {
color: var(–primary-color);
text-align: center;
margin-bottom: 20px;
}
h1 {
font-size: 2.2em;
margin-bottom: 30px;
}
h2 {
font-size: 1.8em;
border-bottom: 2px solid var(–primary-color);
padding-bottom: 10px;
margin-top: 40px;
}
h3 {
font-size: 1.4em;
margin-top: 30px;
margin-bottom: 15px;
}
.loan-calc-container {
background-color: var(–card-background);
padding: 25px;
border-radius: 8px;
box-shadow: var(–shadow);
margin-bottom: 30px;
}
.input-group {
margin-bottom: 20px;
text-align: left;
}
.input-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: var(–primary-color);
}
.input-group input[type="text"],
.input-group input[type="number"],
.input-group select {
width: calc(100% – 22px);
padding: 12px;
border: 1px solid var(–border-color);
border-radius: 4px;
font-size: 1em;
box-sizing: border-box;
transition: border-color 0.3s ease;
}
.input-group input:focus,
.input-group select:focus {
border-color: var(–primary-color);
outline: none;
}
.input-group .helper-text {
font-size: 0.85em;
color: #666;
margin-top: 5px;
display: block;
}
.error-message {
color: #dc3545;
font-size: 0.85em;
margin-top: 5px;
display: block;
min-height: 1.2em; /* Prevent layout shift */
}
.button-group {
display: flex;
justify-content: space-between;
margin-top: 25px;
gap: 10px;
}
button {
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1em;
font-weight: bold;
transition: background-color 0.3s ease, transform 0.2s ease;
flex-grow: 1;
}
button.primary {
background-color: var(–primary-color);
color: white;
}
button.primary:hover {
background-color: #003366;
transform: translateY(-1px);
}
button.secondary {
background-color: #6c757d;
color: white;
}
button.secondary:hover {
background-color: #5a6268;
transform: translateY(-1px);
}
button.reset {
background-color: #ffc107;
color: #212529;
}
button.reset:hover {
background-color: #e0a800;
transform: translateY(-1px);
}
#results {
margin-top: 30px;
padding: 25px;
background-color: var(–primary-color);
color: white;
border-radius: 8px;
box-shadow: var(–shadow);
text-align: center;
}
#results h3 {
color: white;
margin-bottom: 15px;
}
.result-item {
margin-bottom: 10px;
font-size: 1.1em;
}
.result-item strong {
color: #fff;
font-weight: normal;
}
.main-result {
font-size: 1.8em;
font-weight: bold;
margin-top: 10px;
margin-bottom: 15px;
padding: 10px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 4px;
}
.formula-explanation {
font-size: 0.9em;
color: rgba(255, 255, 255, 0.8);
margin-top: 15px;
border-top: 1px solid rgba(255, 255, 255, 0.3);
padding-top: 10px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
margin-bottom: 30px;
box-shadow: var(–shadow);
}
th, td {
padding: 12px 15px;
text-align: left;
border: 1px solid var(–border-color);
}
thead {
background-color: var(–primary-color);
color: white;
}
tbody tr:nth-child(even) {
background-color: #f2f2f2;
}
tbody tr:hover {
background-color: #e9ecef;
}
caption {
font-size: 1.1em;
font-weight: bold;
color: var(–primary-color);
margin-bottom: 10px;
caption-side: top;
text-align: left;
}
canvas {
display: block;
margin: 20px auto;
background-color: var(–card-background);
border-radius: 4px;
box-shadow: var(–shadow);
}
.article-content {
margin-top: 40px;
background-color: var(–card-background);
padding: 30px;
border-radius: 8px;
box-shadow: var(–shadow);
}
.article-content p, .article-content ul, .article-content ol {
margin-bottom: 15px;
}
.article-content ul, .article-content ol {
padding-left: 25px;
}
.article-content li {
margin-bottom: 8px;
}
.article-content a {
color: var(–primary-color);
text-decoration: none;
font-weight: bold;
}
.article-content a:hover {
text-decoration: underline;
}
.faq-item {
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px dashed var(–border-color);
}
.faq-item:last-child {
border-bottom: none;
}
.faq-item strong {
display: block;
color: var(–primary-color);
margin-bottom: 5px;
cursor: pointer;
}
.faq-item p {
margin-bottom: 0;
display: none; /* Hidden by default, JS will toggle */
}
.related-tools ul {
list-style: none;
padding: 0;
}
.related-tools li {
margin-bottom: 15px;
}
.related-tools a {
font-weight: bold;
}
.related-tools span {
font-size: 0.9em;
color: #666;
display: block;
margin-top: 3px;
}
.highlight {
background-color: var(–success-color);
color: white;
padding: 2px 5px;
border-radius: 3px;
font-weight: bold;
}
.error-highlight input[type="text"],
.error-highlight input[type="number"],
.error-highlight select {
border-color: #dc3545 !important;
}
Calculation Results
Network Address:
Subnet Mask:
Wildcard Mask:
Network Size:
Usable IP Range:
First Usable IP:
Last Usable IP:
Broadcast Address:
CIDR Notation:
Total Usable IPs:
Formula Used: Network Address = IP Address AND Subnet Mask. Broadcast Address = Network Address OR Wildcard Mask. Usable IPs = Network Size – 2 (Network & Broadcast).
IP Address Distribution
Visualizing Network, Usable IPs, and Broadcast Address.
Subnet Details Summary
| Metric |
Value |
| Network Address |
|
| Subnet Mask |
|
| Wildcard Mask |
|
| CIDR Notation |
|
| Total IPs in Subnet |
|
| Usable IPs |
|
| First Usable IP |
|
| Last Usable IP |
|
| Broadcast Address |
|
What is Subnetting?
Subnetting is a fundamental networking technique that involves dividing a larger IP network into smaller, more manageable subnetworks, or "subnets." This process is crucial for efficient network management, improved performance, and enhanced security. Essentially, it allows administrators to segment a single block of IP addresses into distinct groups, each with its own network and broadcast address. This is particularly important in larger organizations where a single flat network would become unwieldy and prone to broadcast storms.
Who Should Use Subnetting?
Subnetting is primarily used by network administrators, IT professionals, and anyone responsible for designing, implementing, or managing IP networks. This includes:
- Large Enterprises: To segment departments (e.g., Sales, Engineering, HR) for better traffic control and security policies.
- Small and Medium Businesses (SMBs): To organize devices and manage IP address allocation efficiently.
- Internet Service Providers (ISPs): To allocate IP address blocks to their customers.
- Educational Institutions: To separate student networks from administrative networks.
- Home Network Enthusiasts: For advanced users looking to segment their home network for specific purposes like IoT devices or guest access.
Common Misconceptions about Subnetting
Several misconceptions surround subnetting:
- "Subnetting wastes IP addresses": While it's true that the network and broadcast addresses are unusable for hosts, proper subnetting actually conserves IP addresses by allowing you to create networks of the exact size needed, rather than allocating a massive block that goes unused.
- "Subnetting is overly complex": While it requires understanding binary and IP addressing, modern tools like this subnet calculator simplify the process significantly. The core concepts are logical and manageable.
- "Subnetting is only for huge networks": Even small networks can benefit from subnetting for organizational purposes, security segmentation, or future growth planning.
Subnetting Formula and Mathematical Explanation
Understanding the core formulas behind subnetting is key to mastering IP network design. The process relies heavily on binary arithmetic, specifically the bitwise AND operation.
Key Concepts:
- IP Address: A unique numerical label assigned to each device connected to a computer network that uses the Internet Protocol for communication. In IPv4, it's a 32-bit number, typically represented as four decimal numbers (0-255) separated by dots (e.g., 192.168.1.10).
- Subnet Mask: A 32-bit number used to separate the network portion of an IP address from the host portion. It has a contiguous sequence of 1s (for the network bits) followed by a contiguous sequence of 0s (for the host bits).
- Network Address: The first address in any IP subnet. It is calculated by performing a bitwise AND operation between the IP address and the subnet mask. All host bits are set to 0. This address identifies the network itself and cannot be assigned to a device.
- Broadcast Address: The last address in any IP subnet. It is used to send data to all devices within that specific subnet. It's calculated by taking the network address and setting all host bits to 1. This address also cannot be assigned to a device.
- Wildcard Mask: The inverse of the subnet mask. It's used in access control lists (ACLs) and some other network configurations. It's calculated by subtracting the subnet mask from 255.255.255.255.
- CIDR Notation: Classless Inter-Domain Routing notation represents the network prefix length (the number of bits used for the network portion). For example, /24 means the first 24 bits of the IP address define the network.
The Core Calculation:
- Network Address Calculation:
Perform a bitwise AND operation between the IP Address and the Subnet Mask.
Example (Binary):
IP Address: 192.168.1.75 (11000000.10101000.00000001.01001011)
Subnet Mask: 255.255.255.248 (11111111.11111111.11111111.11111000)
——————————————————————–
Network Address: 192.168.1.72 (11000000.10101000.00000001.01001000)
- Broadcast Address Calculation:
Invert the Subnet Mask to get the Wildcard Mask. Then, perform a bitwise OR operation between the Network Address and the Wildcard Mask.
Example (Binary):
Network Address: 192.168.1.72 (11000000.10101000.00000001.01001000)
Wildcard Mask: 0.0.0.7 (00000000.00000000.00000000.00000111)
——————————————————————–
Broadcast Address: 192.168.1.79 (11000000.10101000.00000001.01001111)
- Usable IP Range:
The usable IP addresses are all addresses between the Network Address and the Broadcast Address, excluding both.
First Usable IP: Network Address + 1
Last Usable IP: Broadcast Address – 1
- Network Size:
The total number of IP addresses within the subnet. This is calculated as 2(32 – Number of Network Bits). For example, a /24 network has 32 – 24 = 8 host bits, so 28 = 256 addresses.
- Total Usable IPs:
Network Size – 2 (for the Network Address and Broadcast Address).
Variables Table:
Subnetting Variables Explained
| Variable |
Meaning |
Unit |
Typical Range |
| IP Address |
The specific address of a device or the starting point for calculation. |
IPv4 Address |
0.0.0.0 – 255.255.255.255 |
| Subnet Mask |
Defines the network and host portions of an IP address. |
IPv4 Address / CIDR |
e.g., 255.255.255.0 / /24 |
| Network Address |
The first address identifying the subnet. |
IPv4 Address |
Valid IP within the subnet |
| Broadcast Address |
The last address used to send data to all hosts in the subnet. |
IPv4 Address |
Valid IP within the subnet |
| Wildcard Mask |
Inverse of the subnet mask, used for ACLs. |
IPv4 Address |
e.g., 0.0.0.255 |
| CIDR Notation |
Prefix length indicating the number of network bits. |
Integer (0-32) |
0 – 32 |
| Network Size |
Total number of addresses in the subnet. |
Count |
2n (where n is number of host bits) |
| Usable IPs |
Number of addresses assignable to devices. |
Count |
Network Size – 2 |
Practical Examples (Real-World Use Cases)
Example 1: Small Office Network
A small business has been given the IP address range 172.16.10.0 with a subnet mask of 255.255.255.0 (which is /24 in CIDR notation). They want to segment their network for better organization.
Inputs:
- IP Address:
172.16.10.50
- Subnet Mask:
255.255.255.0
Calculator Output:
- Network Address:
172.16.10.0
- Subnet Mask:
255.255.255.0
- CIDR Notation:
/24
- Network Size: 256
- Usable IPs: 254
- First Usable IP:
172.16.10.1
- Last Usable IP:
172.16.10.254
- Broadcast Address:
172.16.10.255
Interpretation: This configuration provides a standard Class C-like network segment suitable for a small office. All devices within this range can communicate directly. The network and broadcast addresses are reserved, leaving 254 addresses for computers, printers, servers, etc.
Example 2: Larger Departmental Network
A university IT department needs to create a subnet for the Computer Science department. They have a larger block of addresses and want to create a subnet that can accommodate around 100 devices.
Inputs:
- IP Address:
10.50.20.100
- Subnet Mask:
255.255.255.128 (This mask provides 7 host bits: 27 = 128 total addresses, 126 usable)
Calculator Output:
- Network Address:
10.50.20.64
- Subnet Mask:
255.255.255.128
- CIDR Notation:
/25
- Network Size: 128
- Usable IPs: 126
- First Usable IP:
10.50.20.65
- Last Usable IP:
10.50.20.190
- Broadcast Address:
10.50.20.191
Interpretation: This subnet provides 126 usable IP addresses, which is more than enough for the department's current needs and allows for future growth. By creating this specific subnet, network traffic within the CS department is isolated from other departments, improving performance and security. The network address 10.50.20.64 identifies this specific segment.
How to Use This Subnet Calculator
Using our subnet calculator is straightforward. Follow these steps:
- Enter IP Address: Input any valid IPv4 address that falls within the network range you are analyzing. This could be an existing device's IP or the network's base address.
- Enter Subnet Mask: Provide the corresponding subnet mask. You can enter it in the standard dotted-decimal format (e.g.,
255.255.255.0) or in CIDR notation (e.g., /24). The calculator will automatically convert CIDR to dotted-decimal and vice-versa.
- Click Calculate: Press the "Calculate" button.
Reading the Results:
- Network Address: The identifier for this specific subnet.
- Subnet Mask & CIDR: Shows how the IP address space is divided.
- Wildcard Mask: Useful for firewall rules and ACLs.
- Network Size: The total number of IP addresses in this subnet (including network and broadcast).
- Usable IP Range: The range of addresses that can be assigned to devices.
- First/Last Usable IP: The specific start and end points for device assignment.
- Broadcast Address: The address used to send messages to all devices in the subnet.
- Total Usable IPs: The key metric for how many devices can be connected.
Decision-Making Guidance:
Use the results to determine if your current subnetting scheme is efficient. If you need more or fewer IP addresses, you may need to adjust your subnet mask. For instance, if you need more addresses, use a mask with fewer '1's (e.g., move from /26 to /25). If you need to divide a network further, use a mask with more '1's (e.g., move from /24 to /25).
Key Factors That Affect Subnetting Results
Several factors influence the design and outcome of subnetting:
- Network Size Requirements: The primary driver. How many IP addresses do you need per subnet? This dictates the number of host bits, which in turn determines the subnet mask.
- Number of Subnets Needed: If you need to create many subnets from a larger block, you'll "borrow" bits from the host portion, resulting in smaller subnets.
- Future Growth: Always plan for expansion. Creating subnets slightly larger than immediately needed prevents frequent re-subnetting.
- Security Policies: Subnetting is key for network segmentation. Different security zones (e.g., DMZ, internal servers, user workstations) should reside on separate subnets with specific firewall rules between them.
- Broadcast Domain Reduction: Each subnet is a separate broadcast domain. Smaller broadcast domains reduce unnecessary network traffic and improve performance.
- IP Address Management (IPAM): Efficient subnetting is part of good IPAM. It ensures addresses are allocated logically and prevents conflicts. Tools like this calculator are essential for effective IPAM.
- Routing Efficiency: Subnetting allows routers to aggregate routes, making routing tables smaller and more efficient, especially in large networks.
- Organizational Structure: Aligning subnets with physical locations or departments simplifies management and troubleshooting.
Frequently Asked Questions (FAQ)
What is the difference between a subnet mask and a wildcard mask?
A subnet mask uses '1's to identify the network portion and '0's for the host portion. A wildcard mask does the opposite: '0's indicate bits that must match exactly, and '1's indicate bits that can be anything (don't care). Wildcard masks are often used in Access Control Lists (ACLs) on routers and firewalls.
Can I use CIDR notation directly in the calculator?
Yes, this calculator accepts both dotted-decimal subnet masks (e.g., 255.255.255.0) and CIDR notation (e.g., /24). It will automatically convert between the two formats.
Why are the network address and broadcast address not usable for hosts?
By convention in IP networking, the network address (all host bits are 0) is reserved to identify the network itself. The broadcast address (all host bits are 1) is reserved for sending messages to all devices within that specific subnet. Assigning these addresses to devices would cause conflicts and prevent proper network operation.
What happens if I enter an IP address that doesn't match the subnet mask?
The calculator will still perform the calculation based on the provided IP and mask. However, in a real network, an IP address assigned to a device must fall within the range defined by the network address and broadcast address derived from that specific subnet mask. For example, if the subnet is 192.168.1.0/24, an IP like 10.0.0.1 would not belong to this subnet.
How many usable IPs can I get from a /30 subnet?
A /30 subnet has 32 – 30 = 2 host bits. This results in 22 = 4 total addresses. Subtracting the network and broadcast addresses leaves 4 – 2 = 2 usable IP addresses. This is commonly used for point-to-point links between routers.
What is the smallest possible subnet?
The smallest practical subnet is a /30, providing 2 usable IPs. A /31 is sometimes used for point-to-point links where the network and broadcast addresses are permitted for host use, but /30 is the most common minimum for general subnets.
Can this calculator handle IPv6 addresses?
No, this calculator is specifically designed for IPv4 subnetting. IPv6 subnetting uses a different structure and prefix lengths (e.g., /64 is common).
How does subnetting improve network security?
By dividing a network into smaller segments (subnets), you can apply specific security policies and firewall rules between them. For example, you can restrict traffic from a user subnet to a server subnet, limiting the potential impact of a security breach in one area.
// Helper function to convert dotted decimal IP to binary string
function ipToBinary(ip) {
var parts = ip.split('.');
var binaryParts = parts.map(function(part) {
var binary = parseInt(part, 10).toString(2);
return '0'.repeat(8 – binary.length) + binary;
});
return binaryParts.join(");
}
// Helper function to convert binary string to dotted decimal IP
function binaryToIp(binary) {
var parts = [];
for (var i = 0; i < binary.length; i += 8) {
var byte = binary.substring(i, i + 8);
parts.push(parseInt(byte, 2));
}
return parts.join('.');
}
// Helper function for bitwise AND
function bitwiseAnd(ipBinary, maskBinary) {
var result = '';
for (var i = 0; i < 32; i++) {
result += (ipBinary[i] === '1' && maskBinary[i] === '1') ? '1' : '0';
}
return result;
}
// Helper function for bitwise OR
function bitwiseOr(ipBinary, maskBinary) {
var result = '';
for (var i = 0; i < 32; i++) {
result += (ipBinary[i] === '1' || maskBinary[i] === '1') ? '1' : '0';
}
return result;
}
// Helper function to convert CIDR to subnet mask and vice versa
function cidrToSubnetMask(cidr) {
if (cidr 32) return null;
var mask = '1'.repeat(cidr) + '0'.repeat(32 – cidr);
return binaryToIp(mask);
}
function subnetMaskToCidr(mask) {
var binaryMask = ipToBinary(mask);
var cidr = 0;
for (var i = 0; i = 0 && cidr <= 32;
} else if (ddRegex.test(input)) {
// More thorough check for valid mask structure (contiguous 1s then 0s)
var binaryMask = ipToBinary(input);
var firstZero = binaryMask.indexOf('0');
if (firstZero === -1) return true; // All 1s (/32)
for (var i = firstZero; i < binaryMask.length; i++) {
if (binaryMask[i] === '1') return false; // Found a 1 after a 0
}
return true;
}
return false;
}
// Function to clear error messages
function clearErrors() {
var errorElements = document.querySelectorAll('.error-message');
for (var i = 0; i < errorElements.length; i++) {
errorElements[i].textContent = '';
}
var inputGroups = document.querySelectorAll('.input-group');
for (var i = 0; i < inputGroups.length; i++) {
inputGroups[i].classList.remove('error-highlight');
}
}
// Function to display error
function showError(elementId, message) {
var errorElement = document.getElementById(elementId + 'Error');
if (errorElement) {
errorElement.textContent = message;
}
var inputGroup = document.getElementById(elementId).closest('.input-group');
if (inputGroup) {
inputGroup.classList.add('error-highlight');
}
}
var chartInstance = null; // To hold the chart instance
function calculateSubnet() {
clearErrors();
var ipAddressInput = document.getElementById('ipAddress');
var subnetMaskInput = document.getElementById('subnetMask');
var resultsDiv = document.getElementById('results');
var chartContainer = document.getElementById('chartContainer');
var tableContainer = document.getElementById('tableContainer');
var ipAddress = ipAddressInput.value.trim();
var subnetMaskInputVal = subnetMaskInput.value.trim();
// — Input Validation —
if (!ipAddress) {
showError('ipAddress', 'IP Address is required.');
return;
}
if (!isValidIp(ipAddress)) {
showError('ipAddress', 'Invalid IP Address format.');
return;
}
if (!subnetMaskInputVal) {
showError('subnetMask', 'Subnet Mask is required.');
return;
}
var subnetMask = subnetMaskInputVal;
var cidr = null;
// Handle CIDR input
if (subnetMaskInputVal.startsWith('/')) {
try {
cidr = parseInt(subnetMaskInputVal.substring(1), 10);
if (isNaN(cidr) || cidr 32) {
throw new Error("Invalid CIDR value");
}
subnetMask = cidrToSubnetMask(cidr);
if (!subnetMask) throw new Error("Invalid CIDR value");
subnetMaskInput.value = subnetMask; // Update input to dotted decimal
} catch (e) {
showError('subnetMask', 'Invalid CIDR format or value (0-32).');
return;
}
} else {
if (!isValidSubnetInput(subnetMask)) {
showError('subnetMask', 'Invalid Subnet Mask format.');
return;
}
cidr = subnetMaskToCidr(subnetMask);
}
// — Calculations —
var ipBinary = ipToBinary(ipAddress);
var maskBinary = ipToBinary(subnetMask);
var networkAddressBinary = bitwiseAnd(ipBinary, maskBinary);
var networkAddress = binaryToIp(networkAddressBinary);
var wildcardMaskBinary = ";
for (var i = 0; i < 32; i++) {
wildcardMaskBinary += (maskBinary[i] === '0') ? '1' : '0';
}
var wildcardMask = binaryToIp(wildcardMaskBinary);
var broadcastAddressBinary = bitwiseOr(networkAddressBinary, wildcardMaskBinary);
var broadcastAddress = binaryToIp(broadcastAddressBinary);
var hostBits = 32 – cidr;
var networkSize = Math.pow(2, hostBits);
var totalUsableIps = networkSize – 2;
// Handle edge cases for /31 and /32
if (cidr === 31) {
totalUsableIps = 2; // Typically used for point-to-point
} else if (cidr === 32) {
totalUsableIps = 1; // Single host address
networkSize = 1;
}
var firstUsableIpBinary = bitwiseAnd(networkAddressBinary, maskBinary); // Network address
var firstUsableIpParts = firstUsableIpBinary.split('');
if (cidr < 32) firstUsableIpParts[31] = '1'; // Set last bit to 1
var firstUsableIp = binaryToIp(firstUsableIpParts.join(''));
if (cidr === 32) firstUsableIp = networkAddress; // For /32, the only usable IP is the network address itself
var lastUsableIpBinary = bitwiseOr(networkAddressBinary, wildcardMaskBinary); // Broadcast address
var lastUsableIpParts = lastUsableIpBinary.split('');
if (cidr = 0 ? totalUsableIps : 0; // Ensure non-negative
resultsDiv.style.display = 'block';
chartContainer.style.display = 'block';
tableContainer.style.display = 'block';
// — Update Table —
document.getElementById('tableNetworkAddress').textContent = networkAddress;
document.getElementById('tableSubnetMask').textContent = subnetMask;
document.getElementById('tableWildcardMask').textContent = wildcardMask;
document.getElementById('tableCidrNotation').textContent = '/' + cidr;
document.getElementById('tableNetworkSize').textContent = networkSize;
document.getElementById('tableTotalUsableIps').textContent = totalUsableIps >= 0 ? totalUsableIps : 0;
document.getElementById('tableFirstUsableIp').textContent = firstUsableIp;
document.getElementById('tableLastUsableIp').textContent = lastUsableIp;
document.getElementById('tableBroadcastAddress').textContent = broadcastAddress;
// — Update Chart —
updateChart(networkAddress, firstUsableIp, lastUsableIp, broadcastAddress, networkSize, totalUsableIps, cidr);
}
function updateChart(networkAddr, firstUsable, lastUsable, broadcastAddr, networkSize, usableIps, cidr) {
var ctx = document.getElementById('subnetChart').getContext('2d');
// Destroy previous chart instance if it exists
if (chartInstance) {
chartInstance.destroy();
}
// Prepare data for the chart
var labels = [];
var networkData = [];
var usableData = [];
var broadcastData = [];
// Generate labels and data points based on network size
// For simplicity and performance, we'll represent ranges rather than every single IP for large subnets.
// For very small subnets (/30, /31, /32), we can show individual points.
var chartData = {
labels: [],
datasets: [
{
label: 'Network Address',
data: [],
backgroundColor: 'rgba(54, 162, 235, 0.6)', // Blue
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1,
pointRadius: 5,
pointHoverRadius: 7
},
{
label: 'Usable IP Range',
data: [],
backgroundColor: 'rgba(40, 167, 69, 0.6)', // Green
borderColor: 'rgba(40, 167, 69, 1)',
borderWidth: 1,
pointRadius: 5,
pointHoverRadius: 7
},
{
label: 'Broadcast Address',
data: [],
backgroundColor: 'rgba(255, 99, 132, 0.6)', // Red
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1,
pointRadius: 5,
pointHoverRadius: 7
}
]
};
// Simplified representation for large subnets
if (networkSize <= 32) { // Show individual points for smaller subnets
var currentIpBinary = ipToBinary(networkAddr);
for (var i = 0; i < networkSize; i++) {
var currentIp = binaryToIp(currentIpBinary);
labels.push(currentIp);
if (currentIp === networkAddr) {
chartData.datasets[0].data.push({ x: currentIp, y: 1 });
chartData.datasets[1].data.push(null); // No usable IP here
chartData.datasets[2].data.push(null); // No broadcast here
} else if (currentIp === broadcastAddr) {
chartData.datasets[0].data.push(null); // No network address here
chartData.datasets[1].data.push(null); // No usable IP here
chartData.datasets[2].data.push({ x: currentIp, y: 1 });
} else {
chartData.datasets[0].data.push(null); // No network address here
chartData.datasets[1].data.push({ x: currentIp, y: 1 }); // Usable IP
chartData.datasets[2].data.push(null); // No broadcast here
}
// Increment IP for next iteration
var ipParts = currentIp.split('.').map(Number);
var ipInt = (ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] <>> 0).toString(2); // Ensure unsigned 32-bit
currentIpBinary = '0'.repeat(32 – currentIpBinary.length) + currentIpBinary;
}
} else { // Represent ranges for larger subnets
labels.push('Network');
chartData.datasets[0].data.push({ x: networkAddr, y: 1 });
chartData.datasets[1].data.push(null);
chartData.datasets[2].data.push(null);
labels.push('Usable');
chartData.datasets[0].data.push(null);
chartData.datasets[1].data.push({ x: firstUsable, y: 1 }); // Mark start of usable range
chartData.datasets[2].data.push(null);
labels.push('Broadcast');
chartData.datasets[0].data.push(null);
chartData.datasets[1].data.push(null);
chartData.datasets[2].data.push({ x: broadcastAddr, y: 1 });
}
// Create the chart
chartInstance = new Chart(ctx, {
type: 'scatter', // Use scatter for precise point placement
data: {
datasets: chartData.datasets
},
options: {
responsive: true,
maintainAspectRatio: true,
scales: {
x: {
type: 'category', // Treat IPs as categories for ordering
labels: labels,
title: {
display: true,
text: 'IP Address'
}
},
y: {
beginAtZero: true,
max: 1.5, // Simple scale to show points
display: false // Hide Y-axis as it's not meaningful here
}
},
plugins: {
title: {
display: true,
text: 'IP Address Distribution in Subnet'
},
tooltip: {
callbacks: {
label: function(context) {
var label = context.dataset.label || ";
if (label) {
label += ': ';
}
if (context.parsed.x) {
label += context.parsed.x;
}
return label;
}
}
}
}
}
});
}
// Function to reset form to default values
function resetForm() {
document.getElementById('ipAddress').value = '192.168.1.0';
document.getElementById('subnetMask').value = '255.255.255.0';
document.getElementById('results').style.display = 'none';
document.getElementById('chartContainer').style.display = 'none';
document.getElementById('tableContainer').style.display = 'none';
clearErrors();
// Optionally call calculateSubnet() to show default results
// calculateSubnet();
}
// Function to copy results to clipboard
function copyResults() {
var resultsText = "Subnet Calculation Results:\n\n";
resultsText += "Network Address: " + document.getElementById('networkAddress').textContent + "\n";
resultsText += "Subnet Mask: " + document.getElementById('displaySubnetMask').textContent + "\n";
resultsText += "Wildcard Mask: " + document.getElementById('wildcardMask').textContent + "\n";
resultsText += "Network Size: " + document.getElementById('networkSize').textContent + "\n";
resultsText += "Usable IP Range: " + document.getElementById('usableIpRange').textContent + "\n";
resultsText += "First Usable IP: " + document.getElementById('firstUsableIp').textContent + "\n";
resultsText += "Last Usable IP: " + document.getElementById('lastUsableIp').textContent + "\n";
resultsText += "Broadcast Address: " + document.getElementById('broadcastAddress').textContent + "\n";
resultsText += "CIDR Notation: " + document.getElementById('cidrNotation').textContent + "\n\n";
resultsText += "Total Usable IPs: " + document.getElementById('totalUsableIps').textContent + "\n";
var textArea = document.createElement("textarea");
textArea.value = resultsText;
textArea.style.position = "fixed";
textArea.style.left = "-9999px";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'Results copied!' : 'Copying failed';
// Optionally show a temporary message to the user
var copyButton = document.querySelector('button.secondary');
var originalText = copyButton.textContent;
copyButton.textContent = msg;
setTimeout(function() {
copyButton.textContent = originalText;
}, 2000);
} catch (err) {
console.error('Unable to copy results', err);
var copyButton = document.querySelector('button.secondary');
var originalText = copyButton.textContent;
copyButton.textContent = 'Copying failed';
setTimeout(function() {
copyButton.textContent = originalText;
}, 2000);
} finally {
document.body.removeChild(textArea);
}
}
// Add event listener for Enter key on input fields to trigger calculation
document.getElementById('ipAddress').addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
event.preventDefault();
calculateSubnet();
}
});
document.getElementById('subnetMask').addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
event.preventDefault();
calculateSubnet();
}
});
// Initial setup for the chart (needs Chart.js library)
// Since Chart.js is not allowed, we'll use a placeholder or a very basic SVG/Canvas approach if possible.
// For this example, I'll include a basic Chart.js setup assuming it might be available or as a placeholder.
// NOTE: The prompt strictly forbids external libraries. A pure JS/SVG/Canvas solution would be needed.
// For demonstration, I'll simulate the chart update logic.
// A true pure JS chart requires significant SVG/Canvas manipulation.
// Placeholder for Chart.js if it were allowed:
//
// If Chart.js is NOT allowed, the updateChart function needs a complete rewrite using Canvas API or SVG.
// — Pure Canvas Implementation for Chart —
function updateChart(networkAddr, firstUsable, lastUsable, broadcastAddr, networkSize, usableIps, cidr) {
var canvas = document.getElementById('subnetChart');
var ctx = canvas.getContext('2d');
canvas.width = canvas.parentElement.offsetWidth * 0.9; // Responsive width
canvas.height = 300; // Fixed height
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear previous drawing
var chartWidth = canvas.width;
var chartHeight = canvas.height;
var padding = 40;
var usableAreaWidth = chartWidth – 2 * padding;
var usableAreaHeight = chartHeight – 2 * padding;
// Draw axes and labels
ctx.strokeStyle = '#ccc';
ctx.lineWidth = 1;
ctx.font = '12px Arial';
ctx.fillStyle = '#333';
ctx.textAlign = 'center';
// X-axis
ctx.beginPath();
ctx.moveTo(padding, chartHeight – padding);
ctx.lineTo(chartWidth – padding, chartHeight – padding);
ctx.stroke();
ctx.fillText('IP Address Range', chartWidth / 2, chartHeight – padding / 4);
// Y-axis (simplified, just for visual separation)
ctx.beginPath();
ctx.moveTo(padding, padding);
ctx.lineTo(padding, chartHeight – padding);
ctx.stroke();
// — Data Representation —
// We need a way to map IP addresses to positions on the x-axis.
// For simplicity, we'll use relative positions.
var ipToInt = function(ip) {
return ip.split('.').reduce(function(int, octet) { return (int <>> 0;
};
var networkInt = ipToInt(networkAddr);
var broadcastInt = ipToInt(broadcastAddr);
var firstUsableInt = ipToInt(firstUsable);
var lastUsableInt = ipToInt(lastUsable);
var totalRange = broadcastInt – networkInt + 1; // Total IPs in the subnet
// Function to get x-coordinate for an IP integer
var getX = function(ipInt) {
if (totalRange === 0) return padding; // Avoid division by zero
var relativePos = (ipInt – networkInt) / totalRange;
return padding + relativePos * usableAreaWidth;
};
// Draw Network Address point
ctx.fillStyle = 'rgba(54, 162, 235, 0.8)'; // Blue
var netX = getX(networkInt);
ctx.beginPath();
ctx.arc(netX, chartHeight – padding – usableAreaHeight / 2, 8, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.fillText('Network', netX, chartHeight – padding – usableAreaHeight / 2 – 15);
ctx.fillText(networkAddr, netX, chartHeight – padding + 15);
// Draw Broadcast Address point
ctx.fillStyle = 'rgba(255, 99, 132, 0.8)'; // Red
var broadX = getX(broadcastInt);
ctx.beginPath();
ctx.arc(broadX, chartHeight – padding – usableAreaHeight / 2, 8, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.fillText('Broadcast', broadX, chartHeight – padding – usableAreaHeight / 2 – 15);
ctx.fillText(broadcastAddr, broadX, chartHeight – padding + 15);
// Draw Usable IP Range (as a line or points)
if (usableIps > 0) {
ctx.fillStyle = 'rgba(40, 167, 69, 0.8)'; // Green
var firstX = getX(firstUsableInt);
var lastX = getX(lastUsableInt);
// Draw a line representing the usable range
ctx.beginPath();
ctx.moveTo(firstX, chartHeight – padding – usableAreaHeight / 2 + 15); // Slightly offset
ctx.lineTo(lastX, chartHeight – padding – usableAreaHeight / 2 + 15);
ctx.lineWidth = 10; // Make the line thicker
ctx.strokeStyle = 'rgba(40, 167, 69, 0.6)';
ctx.stroke();
ctx.lineWidth = 1; // Reset line width
ctx.strokeStyle = '#ccc';
// Mark start and end points
ctx.beginPath();
ctx.arc(firstX, chartHeight – padding – usableAreaHeight / 2 + 15, 6, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.fillText('Usable Start', firstX, chartHeight – padding – usableAreaHeight / 2 + 35);
ctx.fillText(firstUsable, firstX, chartHeight – padding + 35);
ctx.beginPath();
ctx.arc(lastX, chartHeight – padding – usableAreaHeight / 2 + 15, 6, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.fillText('Usable End', lastX, chartHeight – padding – usableAreaHeight / 2 + 35);
ctx.fillText(lastUsable, lastX, chartHeight – padding + 35);
ctx.fillStyle = '#000'; // Reset fill style
ctx.fillText('Usable IPs: ' + usableIps, chartWidth / 2, padding / 2);
} else if (cidr === 32) { // Special case for /32
ctx.fillStyle = 'rgba(40, 167, 69, 0.8)'; // Green
var singleX = getX(firstUsableInt);
ctx.beginPath();
ctx.arc(singleX, chartHeight – padding – usableAreaHeight / 2, 8, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.fillText('Usable IP', singleX, chartHeight – padding – usableAreaHeight / 2 – 15);
ctx.fillText(firstUsable, singleX, chartHeight – padding + 15);
}
// Add legend manually
ctx.textAlign = 'left';
var legendX = padding;
var legendY = padding / 2;
ctx.fillStyle = 'rgba(54, 162, 235, 0.8)';
ctx.fillRect(legendX, legendY, 15, 10);
ctx.fillStyle = '#333';
ctx.fillText('Network Address', legendX + 20, legendY + 8);
legendX += 150; // Adjust position for next item
ctx.fillStyle = 'rgba(40, 167, 69, 0.8)';
ctx.fillRect(legendX, legendY, 15, 10);
ctx.fillStyle = '#333';
ctx.fillText('Usable IP Range', legendX + 20, legendY + 8);
legendX += 150;
ctx.fillStyle = 'rgba(255, 99, 132, 0.8)';
ctx.fillRect(legendX, legendY, 15, 10);
ctx.fillStyle = '#333';
ctx.fillText('Broadcast Address', legendX + 20, legendY + 8);
}
// Initialize FAQ toggles
var faqItems = document.querySelectorAll('.faq-item strong');
for (var i = 0; i < faqItems.length; i++) {
faqItems[i].addEventListener('click', function() {
var p = this.nextElementSibling;
if (p.style.display === 'block') {
p.style.display = 'none';
} else {
p.style.display = 'block';
}
});
}
// Initial calculation on load with default values
document.addEventListener('DOMContentLoaded', function() {
calculateSubnet();
});