Вычисление всех IP-адресов в подсети с использованием только встроенных модулей Python 2.7

Мне интересно, как создать скрипт, который принимает нотацию cidr следующим образом:

204.15.20.0/22

И вычисляет все возможные IP-адреса в этом диапазоне.

204.15.20.0
...
...
204.15.23.255

Теперь я, наконец, знаю математику, стоящую за этим, мне было интересно, как я могу сделать такой модуль на питоне.

Я знаю о готовых модулях, таких как netaddr.IPNetwork(), но мне интересно, как бы я это сделал, используя только встроенные модули в Python 2.7.

Спасибо :)


person Snowlav    schedule 29.12.2016    source источник
comment
Вы можете изменить этот адрес на целое число и использовать оттуда range.   -  person tdelaney    schedule 29.12.2016
comment
Я не думаю, что это так работает, поскольку один октет может иметь максимальное значение 255 (b11111111)   -  person Snowlav    schedule 29.12.2016
comment
@UrielEli не дубликат, я знаю математику, стоящую за этим, как сказано в моем OP. Мне интересно, как это сделать в Python, используя встроенные модули.   -  person Snowlav    schedule 29.12.2016


Ответы (1)


Вы можете преобразовывать IPv4-адреса в целые числа с помощью комбинации модулей socket и struct. После этого речь идет о маскировании целочисленного адреса и определении диапазона значений в подсети из значения cidr.

import re
import socket
import struct

def inet_atoi(ipv4_str):
    """Convert dotted ipv4 string to int"""
    # note: use socket for packed binary then struct to unpack
    return struct.unpack("!I", socket.inet_aton(ipv4_str))[0]

def inet_itoa(ipv4_int):
    """Convert int to dotted ipv4 string"""
    # note: use struct to pack then socket to string
    return socket.inet_ntoa(struct.pack("!I", ipv4_int))

def ipv4_range(ipaddr):
    """Return a list of IPv4 address contianed in a cidr address range"""
    # split out for example 192.168.1.1:22/24
    ipv4_str, port_str, cidr_str = re.match(
        r'([\d\.]+)(:\d+)?(/\d+)?', ipaddr).groups()

    # convert as needed
    ipv4_int = inet_atoi(ipv4_str)
    port_str = port_str or ''
    cidr_str = cidr_str or ''
    cidr_int = int(cidr_str[1:]) if cidr_str else 0

    # mask ipv4
    ipv4_base = ipv4_int & (0xffffffff << (32 - cidr_int))

    # generate list
    addrs = [inet_itoa(ipv4_base + val)
        for val in range(1 << (32 - cidr_int) + 2)]
    return addrs

print(ipv4_range('204.15.20.0/22'))
person tdelaney    schedule 29.12.2016