A 32-bit street address
An IPv4 address like 192.168.1.77 is really one 32-bit number written as four bytes. A subnet in CIDR notation, 192.168.1.0/24, says the first 24 bits name the network and the rest number the hosts. Bits again — the same masks you used in Assembly.
Masks do the work
function ipToInt(ip) {
const parts = ip.split(".");
if (parts.length !== 4 || parts.some((p) => !/^\d{1,3}$/.test(p) || Number(p) > 255)) {
throw new Error(`Bad IP: ${ip}`);
}
return parts.reduce((n, p) => n * 256 + Number(p), 0);
}
function intToIp(n) {
return [n >>> 24, (n >>> 16) & 255, (n >>> 8) & 255, n & 255].join(".");
}
function maskOf(bits) {
return bits === 0 ? 0 : (0xffffffff << (32 - bits)) >>> 0;
}
function subnetInfo(cidr) {
const [ip, b] = cidr.split("/");
const bits = Number(b);
const mask = maskOf(bits);
const network = (ipToInt(ip) & mask) >>> 0;
const broadcast = (network | (~mask >>> 0)) >>> 0;
const hosts = bits >= 31 ? 0 : 2 ** (32 - bits) - 2; // minus network and broadcast
return { network: intToIp(network), broadcast: intToIp(broadcast), mask: intToIp(mask), hosts };
}
function inSubnet(ip, cidr) {
const [net, b] = cidr.split("/");
const mask = maskOf(Number(b));
return ((ipToInt(ip) & mask) >>> 0) === ((ipToInt(net) & mask) >>> 0);
}