1

Como calcular sub-redes IPv4 e máscaras CIDR usando operadores bitwise em JavaScript puro

Quem desenvolve ferramentas de infraestrutura, dashboards de cloud (AWS VPC, Azure VNet) ou sistemas de monitoramento de redes frequentemente precisa validar se um IP pertence a uma sub-rede, calcular o endereço de broadcast ou determinar o primeiro e último host utilizável.

A maioria dos iniciantes tenta resolver isso com expressões regulares gigantescas ou vários split('.') combinados com conversões de string. Isso não só é ineficiente em termos de CPU, mas extremamente frágil.

O protocolo IPv4 é, na sua essência, um número inteiro de 32 bits não assinado (uint32). Toda a matemática de redes (máscara, rede, broadcast, range) é resolvida com elegância usando operadores binários (bitwise).

Abaixo está uma implementação limpa, modular e sem dependências externas em JavaScript puro.


1. As Duas Funções Base: Conversão de e para Inteiro 32-bit

Cada octeto do IPv4 ocupa exatamente 8 bits (1 byte). Deslocamos cada octeto para a esquerda usando o operador bitwise shift (<<):

/**
 * Converte um IP em formato string ('192.168.1.50') para uint32
 */
function ipToInt(ip) {
  return ip
    .split('.')
    .reduce((acc, octeto) => ((acc << 8) + parseInt(octeto, 10)) >>> 0, 0);
}

/**
 * Converte um uint32 de volta para a notação com pontos ('192.168.1.50')
 */
function intToIp(int) {
  return [
    (int >>> 24) & 255,
    (int >>> 16) & 255,
    (int >>> 8) & 255,
    int & 255
  ].join('.');
}

💡 Por que o operador >>> 0?
No JavaScript, operadores bitwise padrão (<<, |, &) convertem o valor internamente para um inteiro de 32 bits com sinal (o que faria IPs que começam acima de 128.0.0.0 virarem números negativos). O operador Zero-fill Right Shift (>>> 0) força o interpretador V8 a tratar o número como inteiro não assinado (unsigned 32-bit).


2. A Máscara de Sub-rede a partir do CIDR

Em notação CIDR (ex: /24), o número indica quantos bits da esquerda para a direita são 1:

/**
 * Gera a máscara a partir do prefixo CIDR (ex: 24 -> '255.255.255.0')
 */
function cidrToMask(cidr) {
  if (cidr === 0) return 0;
  return ((0xFFFFFFFF << (32 - cidr)) >>> 0);
}

3. Endereço de Rede, Broadcast e Hosts Úteis

Com os operadores lógicos bitwise:

  • Endereço de Rede: Aplicação do operador AND (&) entre o IP e a Máscara.
  • Endereço de Broadcast: Aplicação do operador OR (|) entre a Rede e o inverso da Máscara (~mask).
function calcularSubrede(ipStr, cidr) {
  const ip = ipToInt(ipStr);
  const mask = cidrToMask(cidr);
  
  // Endereço de Rede
  const rede = (ip & mask) >>> 0;
  
  // Endereço de Broadcast
  const broadcast = (rede | (~mask >>> 0)) >>> 0;
  
  // Quantidade total de IPs e Hosts utilizáveis
  const totalIps = Math.pow(2, 32 - cidr);
  
  let primeiroHost = null;
  let ultimoHost = null;
  let hostsUtilizaveis = 0;

  // Tratamento de casos especiais (RFC 3021 para /31 e /32)
  if (cidr === 32) {
    primeiroHost = intToIp(rede);
    ultimoHost = intToIp(rede);
    hostsUtilizaveis = 1;
  } else if (cidr === 31) {
    // Links Ponto-a-Ponto sem broadcast
    primeiroHost = intToIp(rede);
    ultimoHost = intToIp(broadcast);
    hostsUtilizaveis = 2;
  } else {
    primeiroHost = intToIp(rede + 1);
    ultimoHost = intToIp(broadcast - 1);
    hostsUtilizaveis = totalIps - 2;
  }

  return {
    ip: ipStr,
    cidr: `/${cidr}`,
    mascara: intToIp(mask),
    rede: intToIp(rede),
    broadcast: intToIp(broadcast),
    primeiroHost,
    ultimoHost,
    hostsUtilizaveis
  };
}

4. Testando o Código

Você pode colar isso diretamente no Node.js ou no console do navegador:

console.log(calcularSubrede('192.168.10.45', 24));

Resultado:

{
  "ip": "192.168.10.45",
  "cidr": "/24",
  "mascara": "255.255.255.0",
  "rede": "192.168.10.0",
  "broadcast": "192.168.10.255",
  "primeiroHost": "192.168.10.1",
  "ultimoHost": "192.168.10.254",
  "hostsUtilizaveis": 254
}

E para checar se um IP pertence a uma determinada sub-rede em 1 linha:

function ipPertenceARede(ipTestado, rede, cidr) {
  const mask = cidrToMask(cidr);
  return ((ipToInt(ipTestado) & mask) >>> 0) === ((ipToInt(rede) & mask) >>> 0);
}

console.log(ipPertenceARede('10.0.5.88', '10.0.0.0', 16)); // true
console.log(ipPertenceARede('10.1.5.88', '10.0.0.0', 16)); // false

Como vocês costumam lidar com cálculos de infraestrutura de rede nas aplicações de vocês? Usam bibliotecas prontas como ipaddr.js ou funções nativas?


Calculadora visual completa de sub-redes e blocos VLSM: tecmestre.com.br/calculadora-de-redes/

Carregando publicação patrocinada...