Como fazer uma mini calculadora CIDR IPv4

Recentemente precisei de uma ferramenta para extrair uma lista de ipv4s válidos de uma rede com a notação CIDR(https://pt.wikipedia.org/wiki/Classless_Inter-Domain_Routing)

exemplo:

192.168.0.0/24

10.0.0.0/8

precisava de uma coisa simples para ser incorporada em shell script.

Sem encontrar a solução resolvi implementá-la em python 3

Obs. Optei pelo uso do inglês pois o considero uma linguagem global.

Crie o arquivo get_ips_from_CIDR.py e adicione o código abaixo logo no início do arquivo

#!/usr/bin/env python3

import sys

Primeiramente vamos criar uma função para calcular o número de ipv4 possíveis, onde recebo o CIDR como parâmetro e retorno o total de ipv4 incluindo o endereço de de rede x.x.x.0 e o broadcast da rede x.x.x.255, em python ficou simples:

def calc_hosts_from_CIDR(CIDR):
    return 2**(32 - CIDR)

o artifício foi elevar 2 a diferença entre o total de bits possíveis no ipv4 e o CIDR, simplificando fica

N = 2^(32-CIDR)

onde:

N = número de ipv4 incluindo o endereço de de rede x.x.x.0 e o broadcast da rede x.x.x.255

32 = número total de bits de um endereço ipv4

CIDR =  Classless Inter-Domain Routing

A próxima função consiste em receber um número ipv4 no formato x.x.x.x e retornar o próximo endereço ip

Lembrando que o valor máximo em decimal que cada octeto do ipv4 pode suportar é 255.

primeiramente nesta função decompomos o ipv4 recebido em quatro octetos , e convertendo os valores dos três últimos octetos de string para decimal, após a conversão inicia-se uma série de checagens começando do último octeto (c) até o segundo (a) validando os limites do protocolo e incrementando no octeto que for possível. Após isso remonta-se a string ipv4 e a retorna

def increment(ip):
    prefix = ip.split('.')[0]
    a = ip.split('.')[1]
    b = ip.split('.')[2]
    c = ip.split('.')[3]

    prefix = int(prefix)
    a = int(a)
    b = int(b)
    c = int(c)

    if c == 255:
        c = 0
        if b == 255:
            b = 0
            if a == 255:
                a = 0
                prefix += 1
            else:
                a += 1
        else:
            b += 1
    else:
        c += 1

    return str(prefix)+'.'+str(a)+'.'+str(b)+'.'+str(c)
    

Pronto já temos uma função para calcular o número de ipv4s de um determinado CIDR, e temos uma função para incrementar um ipv4. Agora vamos implementar uma função que receba um ipv4 e um CIDR e gere uma lista com todos os ipv4s.


def generate(ip,number):
    ips = [ip]

    for i in range(number):
        j = increment(ips[-1])
        ips.append(j)

    return ips

Para finalizar vamos implementar uma função para mostrar a lista gerada na saída padrão (stdout) do shell

def dump(ips):
    for ip in ips:
        if ip.split('.')[-1] != '0' and ip.split('.')[-1] != '255':
            print(ip)

De posse das funções vamos ao final do arquivo e juntar tudo, recebendo os argumentos de delegando as funções


if len(sys.argv) != 2:
    help()
    sys.exit(1)

else:
    ip = sys.argv[1].split('/')[0]
    mask = sys.argv[1].split('/')[1]
    mask = int(mask)
    number = calc_hosts_from_CIDR(mask)
    ips = generate(ip, number)
    dump(ips)

O código é bastante  simples, não foi feito validações e meu ingrês é um pouco estranho mas a ferramenta ajudou bastante

o código completo pode ser encontrado no meu github aqui

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *