calculando rede e broadcast com python

Talvez você esteja se perguntando: por que em C é tão simples e com python o inet_aton() não retorna nada útil para ser usado com & (and)? hehe. É que o inet_aton() do python retorna uma string, e com o módulo struct você poderá obter o long int que tanto deseja.

Imagino que seja isso que você procura:

$ ./netcalc.py
use: netcalc.py ip/[mask|cidr]  

$ ./netcalc.py 192.168.0.200/25
cidr=25, effective networks=2, effective hosts=126

address   :    192.168.0.200 (11000000.10101000.00000000.11001000)
netmask   :  255.255.255.128 (11111111.11111111.11111111.10000000)
network   :    192.168.0.128 (11000000.10101000.00000000.10000000)
broadcast :    192.168.0.255 (11000000.10101000.00000000.11111111)  

$ ./netcalc.py 192.168.0.100/255.255.255.240
cidr=28, effective networks=16, effective hosts=14

address   :    192.168.0.100 (11000000.10101000.00000000.01100100)
netmask   :  255.255.255.240 (11111111.11111111.11111111.11110000)
network   :     192.168.0.96 (11000000.10101000.00000000.01100000)
broadcast :    192.168.0.111 (11000000.10101000.00000000.01101111)

Bom, pra facilitar sua vida, já escrevi o código. Ele é bem simples – chega a ser tosco – e não faz nenhum tipo de validação nos endereços IP. na verdade, ele usa que o inet_aton() retorna – isso significa que se você usar o IP 100.200.300 e o inet_aton() permitir, o programa vai retornar algo inesperado.

Este programa usa o módulo bitprint que já postei aqui, pra imprimir o conteúdo binário dos endereços. O cálculo do endereço de rede e broadcast é simples e genérico:

network = ip & netmask
broadcast = ~network ^ netmask

Enfim, segue aí o código:

#!/usr/bin/env python
# coding: utf-8
# netcalc.py 20080318 AF

import sys, bitprint
from struct import pack, unpack
from socket import inet_ntoa, inet_aton

mask = 1L<<31
xnet = (1L<<32)-1
cidr_range = range(9, 32)

def bp(addr):
    buff = []
    bits = str(bitprint.XBits(addr))
    for n in range(4):
        pos = n*8
        buff.append(bits[pos:pos+8])

    return '.'.join(buff)

def cidr_to_netmask(cidr):
    return ((1L<<cidr)-1)<<(32-cidr)

def netmask_to_cidr(netmask):
    cidr = 0
    mm = mask
    for n in range(32):
        if netmask & mm: cidr+=1
        mm>>=1

    return cidr

if __name__ == '__main__':
    try:
        ip_s, temp = sys.argv[1].split('/')
    except:
        print 'use: %s ip/[mask|cidr]' % sys.argv[0]
        sys.exit(1)

    if temp.isdigit():
        cidr = long(temp)
        if cidr not in cidr_range:
            print 'cidr inválido: %d' % cidr
            sys.exit(1)
        nm = cidr_to_netmask(cidr)
    else:
        nm = unpack('>L', inet_aton(temp))[0]
        cidr = netmask_to_cidr(nm)

    ip = unpack('>L', inet_aton(ip_s))[0]
    nw = ip & nm
    bc = (~nw ^ nm) & xnet

    nets = pow(2, cidr%8)
    hosts = pow(2, 32-cidr)-2

    print 'cidr=%d, effective networks=%d, effective hosts=%d\n' % (cidr, nets, hosts)

    print 'address   : % 16s (%s)' % (ip_s, bp(ip))
    print 'netmask   : % 16s (%s)' % (inet_ntoa(pack('>L', nm)), bp(nm))
    print 'network   : % 16s (%s)' % (inet_ntoa(pack('>L', nw)), bp(nw))
    print 'broadcast : % 16s (%s)' % (inet_ntoa(pack('>L', bc)), bp(bc))

Divirta-se!


One Comment on “calculando rede e broadcast com python”

  1. Lucas disse:

    Olá,

    saberia me dizer como eu faria para saber se um IP pertence a uma rede ou não?

    preciso de um programinha em python que veja o IP da máquina local(DHCP) e verifique com um IP que eu vou definir se esse IP que eu definir pertence a sub-rede do DHCP. Finalidade evitar conflitos de IP de rede local com IP de VPN.

    Obrigado,

    Lucas.


Deixar mensagem para Lucas Cancelar resposta