Build an IP Subnet Calculator 🌐
Subnet Calculators are essential for Network Engineers. They rely entirely on Bitwise Operations.
- Network Address:
IP & Mask - Broadcast Address:
IP | (~Mask) - Wildcard Mask:
~Mask
In this guide, we will build a calculator that performs these binary operations in the browser.
Step 1: The Bitwise Logic 🧬
JavaScript supports bitwise operators, but they work on 32-bit integers. First, we must convert an IP string (e.g., "192.168.1.1") into a long integer.
/* lib/subnet-utils.js */
// Convert "192.168.1.1" -> 3232235777
const ipToInt = (ip) => {
return ip.split('.').reduce((acc, octet) => {
return (acc << 8) + parseInt(octet, 10);
}, 0) >>> 0; // unsigned
}
// Convert 3232235777 -> "192.168.1.1"
const intToIp = (int) => {
return [
(int >>> 24) & 255,
(int >>> 16) & 255,
(int >>> 8) & 255,
int & 255
].join('.');
}
// Convert CIDR (/24) to Mask (255.255.255.0)
const cidrToMask = (cidr) => {
return -1 << (32 - cidr);
}
Step 2: The Calculation 🧮
Now we apply the formulas.
const calculateSubnet = (ip, cidr) => {
const ipInt = ipToInt(ip);
const maskInt = cidrToMask(cidr);
// 1. Network Address: IP AND Mask
const networkInt = ipInt & maskInt;
// 2. Broadcast Address: Network OR (NOT Mask)
const broadcastInt = networkInt | (~maskInt);
// 3. Hosts
const firstHost = networkInt + 1;
const lastHost = broadcastInt - 1;
const totalHosts = (broadcastInt - networkInt) - 1;
return {
network: intToIp(networkInt),
broadcast: intToIp(broadcastInt),
firstHost: intToIp(firstHost),
lastHost: intToIp(lastHost),
usableHosts: totalHosts > 0 ? totalHosts : 0
};
}
Step 3: The React UI Component 💻
Here is a tool that lets users input an IP and CIDR to see the network details.
"use client"
import { useState } from "react"
import { Network, Server, Globe } from "lucide-react"
// Helper functions from Step 1 go here...
const ipToInt = (ip: string) => ip.split('.').reduce((acc, val) => (acc << 8) + Number(val), 0) >>> 0;
const intToIp = (int: number) => [(int>>>24)&255, (int>>>16)&255, (int>>>8)&255, int&255].join('.');
export default function SubnetCalc() {
const [ip, setIp] = useState("192.168.1.10")
const [cidr, setCidr] = useState(24)
const [result, setResult] = useState<any>(null)
const handleCalculate = () => {
try {
const ipInt = ipToInt(ip)
const maskInt = -1 << (32 - cidr)
const networkInt = ipInt & maskInt
const broadcastInt = networkInt | (~maskInt)
setResult({
network: intToIp(networkInt),
broadcast: intToIp(broadcastInt),
netmask: intToIp(maskInt),
hosts: Math.pow(2, 32 - cidr) - 2
})
} catch(e) {
alert("Invalid IP Address")
}
}
return (
<div className="max-w-2xl mx-auto p-6 bg-slate-900 text-slate-100 rounded-xl shadow-2xl">
<div className="flex items-center gap-3 mb-8 pb-4 border-b border-slate-800">
<Globe className="text-blue-400" />
<h2 className="text-xl font-mono font-bold">IP Subnet Analyzer</h2>
</div>
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="col-span-2">
<label className="text-xs font-mono text-slate-400 uppercase">IP Address</label>
<input
value={ip} onChange={e => setIp(e.target.value)}
className="w-full p-2 bg-slate-800 border border-slate-700 rounded font-mono text-green-400 focus:outline-none focus:border-blue-500"
/>
</div>
<div>
<label className="text-xs font-mono text-slate-400 uppercase">CIDR (/{cidr})</label>
<input
type="number" min="0" max="32"
value={cidr} onChange={e => setCidr(Number(e.target.value))}
className="w-full p-2 bg-slate-800 border border-slate-700 rounded font-mono text-yellow-400 focus:outline-none focus:border-blue-500"
/>
</div>
</div>
<button
onClick={handleCalculate}
className="w-full bg-blue-600 hover:bg-blue-500 text-white font-bold py-2 rounded mb-8 transition"
>
CALCULATE Subnet
</button>
{result && (
<div className="grid grid-cols-2 gap-4 animate-in fade-in slide-in-from-bottom-4">
<div className="p-4 bg-slate-800 rounded border border-slate-700">
<div className="flex items-center gap-2 text-slate-400 text-xs uppercase mb-1">
<Network size={14} /> Network Address
</div>
<div className="text-xl font-mono text-blue-300">{result.network}</div>
</div>
<div className="p-4 bg-slate-800 rounded border border-slate-700">
<div className="flex items-center gap-2 text-slate-400 text-xs uppercase mb-1">
<Globe size={14} /> Broadcast Address
</div>
<div className="text-xl font-mono text-purple-300">{result.broadcast}</div>
</div>
<div className="p-4 bg-slate-800 rounded border border-slate-700">
<div className="flex items-center gap-2 text-slate-400 text-xs uppercase mb-1">
<Server size={14} /> Subnet Mask
</div>
<div className="font-mono text-slate-300">{result.netmask}</div>
</div>
<div className="p-4 bg-slate-800 rounded border border-slate-700">
<div className="flex items-center gap-2 text-slate-400 text-xs uppercase mb-1">
<Server size={14} /> Usable Hosts
</div>
<div className="font-mono text-green-400">{result.hosts.toLocaleString()}</div>
</div>
</div>
)}
</div>
)
}
Step 4: Visualizing Binary (Pro Tip) 👓
For an educational tool, showing the Binary Representation is incredibly helpful.
Just use .toString(2) on your integers.
ipToInt("192.168.1.1").toString(2).padStart(32, '0');
// Result: 11000000101010000000000100000001
Displaying this allows users to strictly see where the Netmask cuts off the Network bits from the Host bits!