Скрипт для вычисления выходных данных сетевых хостов с помощью подстановочных знаков

#python #python-3.x #networking

#python #python-3.x #сеть

Вопрос:

Мне нужно загрузить диапазон IP-адресов в приложение для создания отчетов, и, к сожалению, приложение не понимает подсетей и также не позволит мне загрузить в него пару миллионов IP-адресов. Однако это позволяет мне загружать данные с использованием подстановочных знаков, поэтому я надеюсь, что смогу сократить свой список IP-адресов до более управляемого размера путем объединения подобных IP-адресов в сети с использованием подстановочных знаков, но я также не хочу непреднамеренно включать IP-адреса, которых нет в списке сетей, что усложняет задачу.

У меня есть список сетей в формате CIDR (например: 192.168.1.0 / 24), и я могу достаточно легко получить минимальный и максимальный IP-адреса следующим образом

 import ipaddress

TheSubnets = open('Networks.txt', 'r')
for network in TheSubnets.readlines():
    AllIPs = ipaddress.IPv4Network(network.strip())
    minIP = AllIPs[0]
    maxIP = AllIPs[-1]
  

Однако чего я не могу понять, так это как эффективно объединить их, чтобы сгенерировать кучу IP-адресов с подстановочными знаками, которые охватывали бы каждый IP-адрес в сети.

24-разрядные маски подсети просты, я просто удаляю последний октет, поэтому 192.168.1.0 / 24 будет просто 192.168.1.*

Однако с разными подсетями это становится сложнее:

требуется вывод

Есть ли простой способ объединить список хостов в список с подстановочными знаками, который также гарантирует, что только IP-адреса в каждой сети соответствуют значениям подстановочных знаков?

Комментарии:

1. Какие подстановочные знаки поддерживаются? * Имеет ли обычное значение (например, с glob ) «ноль или более символов»? Если это так, ваш 13* может совпадать 13 с самим собой, поэтому поддерживается ли 13? ( ? соответствует ровно одному символу)? Также поддерживаются ли диапазоны символов, например [1-5] , в качестве подстановочных знаков?

2. Диапазоны не поддерживаются. * соответствует 1 или более, и он поддерживает? для сопоставления 1 числа / символа. Итак, *.*.*.?? будет соответствовать любому IP-адресу с 2 цифрами в последнем октете.

3. и да, * ведет себя как glob , поэтому 13 * будет соответствовать 13 и 133, что я только сейчас понял, когда вы спросили, а также понял, что мой список примеров выше на самом деле не точен сейчас.

Ответ №1:

Это стало намного сложнее, чем я рассчитывал, но это должно сработать … convert_range это основная функция.

 def gen_patterns(start, end):
    """
    generator that yields patterns representing a given range of integers
    e.g. for inputs 7, 31 will yield the sequence '7' '8' '9' '1?' '2?' '30' '31'
    """
    endp1 = end   1
    
    while end > start:
        mult = 1
        mult_next = 10
        mult_col = 0
        while (start % mult_next == 0
               and endp1 - start >= mult * 10):
            mult *= 10
            mult_next *= 10
            mult_col  = 1
            
        first_digit = (start // mult) % 10

        start_upper = start // mult_next
        
        if endp1 // mult_next > start_upper:
            last_digit = 9            
        else:
            last_digit = (endp1 // mult) % 10 - 1

        prefix = str(start_upper) if start_upper else ''
        suffix = '?' * mult_col
            
        for digit in range(first_digit, last_digit   1):
            if start_upper or digit:
                yield f'{prefix}{digit}{suffix}'
            else:
                for i in range(1, mult_col   1):
                    yield '?' * i

        start  = mult * (last_digit - first_digit   1)


def convert_range(network):
    """
    Convert a network range (IPv4Network object) into a list of
    string patterns that represent it.
    """
    bits = network.prefixlen
    if bits == 0:
        return '*'
    
    num_fixed = bits // 8  # number of octets that are same for all addresses
    num_star = (32 - bits) // 8  # number of octets that have '*'

    first_addr_octets = str(network[0]).split('.')
    last_addr_octets = str(network[-1]).split('.')

    prefix = '.'.join(first_addr_octets[:num_fixed])

    #suffix = '.*' * num_star            # version that produces e.g. 10.*.*.*
    suffix = '.*' if num_star else ''    # version that produces e.g. 10.*

    if num_fixed   num_star == 4:
        return [prefix   suffix]

    else:
        start = int(first_addr_octets[num_fixed])
        end = int(last_addr_octets[num_fixed])

        patterns = gen_patterns(start, end)
        if prefix:
            prefix  = '.'
        return [prefix   pattern   suffix for pattern in patterns]

#===================================================================

if __name__ == '__main__':

    import ipaddress

    # test it with all the different ranges that include
    # the single address 10.124.148.135
    test_ranges = """
    0.0.0.0/0
    0.0.0.0/1
    0.0.0.0/2
    0.0.0.0/3
    0.0.0.0/4
    8.0.0.0/5
    8.0.0.0/6
    10.0.0.0/7
    10.0.0.0/8
    10.0.0.0/9
    10.64.0.0/10
    10.96.0.0/11
    10.112.0.0/12
    10.120.0.0/13
    10.124.0.0/14
    10.124.0.0/15
    10.124.0.0/16
    10.124.128.0/17
    10.124.128.0/18
    10.124.128.0/19
    10.124.144.0/20
    10.124.144.0/21
    10.124.148.0/22
    10.124.148.0/23
    10.124.148.0/24
    10.124.148.128/25
    10.124.148.128/26
    10.124.148.128/27
    10.124.148.128/28
    10.124.148.128/29
    10.124.148.132/30
    10.124.148.134/31
    10.124.148.135/32
    """.strip().split()

    for nstr in test_ranges:

        network = ipaddress.IPv4Network(nstr)    
        print(f'Network: {nstr}')
        print(f'Range: {network[0]} - {network[-1]}' )
        print('Patterns:')
        for pattern in convert_range(network):
            print(f'   {pattern}')

        print()
  

Вывод всех тестовых примеров:

 Network: 0.0.0.0/0
Range: 0.0.0.0 - 255.255.255.255
Patterns:
   *

Network: 0.0.0.0/1
Range: 0.0.0.0 - 127.255.255.255
Patterns:
   ?.*
   ??.*
   10?.*
   11?.*
   120.*
   121.*
   122.*
   123.*
   124.*
   125.*
   126.*
   127.*

Network: 0.0.0.0/2
Range: 0.0.0.0 - 63.255.255.255
Patterns:
   ?.*
   1?.*
   2?.*
   3?.*
   4?.*
   5?.*
   60.*
   61.*
   62.*
   63.*

Network: 0.0.0.0/3
Range: 0.0.0.0 - 31.255.255.255
Patterns:
   ?.*
   1?.*
   2?.*
   30.*
   31.*

Network: 0.0.0.0/4
Range: 0.0.0.0 - 15.255.255.255
Patterns:
   ?.*
   10.*
   11.*
   12.*
   13.*
   14.*
   15.*

Network: 8.0.0.0/5
Range: 8.0.0.0 - 15.255.255.255
Patterns:
   8.*
   9.*
   10.*
   11.*
   12.*
   13.*
   14.*
   15.*

Network: 8.0.0.0/6
Range: 8.0.0.0 - 11.255.255.255
Patterns:
   8.*
   9.*
   10.*
   11.*

Network: 10.0.0.0/7
Range: 10.0.0.0 - 11.255.255.255
Patterns:
   10.*
   11.*

Network: 10.0.0.0/8
Range: 10.0.0.0 - 10.255.255.255
Patterns:
   10.*

Network: 10.0.0.0/9
Range: 10.0.0.0 - 10.127.255.255
Patterns:
   10.?.*
   10.??.*
   10.10?.*
   10.11?.*
   10.120.*
   10.121.*
   10.122.*
   10.123.*
   10.124.*
   10.125.*
   10.126.*
   10.127.*

Network: 10.64.0.0/10
Range: 10.64.0.0 - 10.127.255.255
Patterns:
   10.64.*
   10.65.*
   10.66.*
   10.67.*
   10.68.*
   10.69.*
   10.7?.*
   10.8?.*
   10.9?.*
   10.10?.*
   10.11?.*
   10.120.*
   10.121.*
   10.122.*
   10.123.*
   10.124.*
   10.125.*
   10.126.*
   10.127.*

Network: 10.96.0.0/11
Range: 10.96.0.0 - 10.127.255.255
Patterns:
   10.96.*
   10.97.*
   10.98.*
   10.99.*
   10.10?.*
   10.11?.*
   10.120.*
   10.121.*
   10.122.*
   10.123.*
   10.124.*
   10.125.*
   10.126.*
   10.127.*

Network: 10.112.0.0/12
Range: 10.112.0.0 - 10.127.255.255
Patterns:
   10.112.*
   10.113.*
   10.114.*
   10.115.*
   10.116.*
   10.117.*
   10.118.*
   10.119.*
   10.120.*
   10.121.*
   10.122.*
   10.123.*
   10.124.*
   10.125.*
   10.126.*
   10.127.*

Network: 10.120.0.0/13
Range: 10.120.0.0 - 10.127.255.255
Patterns:
   10.120.*
   10.121.*
   10.122.*
   10.123.*
   10.124.*
   10.125.*
   10.126.*
   10.127.*

Network: 10.124.0.0/14
Range: 10.124.0.0 - 10.127.255.255
Patterns:
   10.124.*
   10.125.*
   10.126.*
   10.127.*

Network: 10.124.0.0/15
Range: 10.124.0.0 - 10.125.255.255
Patterns:
   10.124.*
   10.125.*

Network: 10.124.0.0/16
Range: 10.124.0.0 - 10.124.255.255
Patterns:
   10.124.*

Network: 10.124.128.0/17
Range: 10.124.128.0 - 10.124.255.255
Patterns:
   10.124.128.*
   10.124.129.*
   10.124.13?.*
   10.124.14?.*
   10.124.15?.*
   10.124.16?.*
   10.124.17?.*
   10.124.18?.*
   10.124.19?.*
   10.124.20?.*
   10.124.21?.*
   10.124.22?.*
   10.124.23?.*
   10.124.24?.*
   10.124.250.*
   10.124.251.*
   10.124.252.*
   10.124.253.*
   10.124.254.*
   10.124.255.*

Network: 10.124.128.0/18
Range: 10.124.128.0 - 10.124.191.255
Patterns:
   10.124.128.*
   10.124.129.*
   10.124.13?.*
   10.124.14?.*
   10.124.15?.*
   10.124.16?.*
   10.124.17?.*
   10.124.18?.*
   10.124.190.*
   10.124.191.*

Network: 10.124.128.0/19
Range: 10.124.128.0 - 10.124.159.255
Patterns:
   10.124.128.*
   10.124.129.*
   10.124.13?.*
   10.124.14?.*
   10.124.15?.*

Network: 10.124.144.0/20
Range: 10.124.144.0 - 10.124.159.255
Patterns:
   10.124.144.*
   10.124.145.*
   10.124.146.*
   10.124.147.*
   10.124.148.*
   10.124.149.*
   10.124.15?.*

Network: 10.124.144.0/21
Range: 10.124.144.0 - 10.124.151.255
Patterns:
   10.124.144.*
   10.124.145.*
   10.124.146.*
   10.124.147.*
   10.124.148.*
   10.124.149.*
   10.124.150.*
   10.124.151.*

Network: 10.124.148.0/22
Range: 10.124.148.0 - 10.124.151.255
Patterns:
   10.124.148.*
   10.124.149.*
   10.124.150.*
   10.124.151.*

Network: 10.124.148.0/23
Range: 10.124.148.0 - 10.124.149.255
Patterns:
   10.124.148.*
   10.124.149.*

Network: 10.124.148.0/24
Range: 10.124.148.0 - 10.124.148.255
Patterns:
   10.124.148.*

Network: 10.124.148.128/25
Range: 10.124.148.128 - 10.124.148.255
Patterns:
   10.124.148.128
   10.124.148.129
   10.124.148.13?
   10.124.148.14?
   10.124.148.15?
   10.124.148.16?
   10.124.148.17?
   10.124.148.18?
   10.124.148.19?
   10.124.148.20?
   10.124.148.21?
   10.124.148.22?
   10.124.148.23?
   10.124.148.24?
   10.124.148.250
   10.124.148.251
   10.124.148.252
   10.124.148.253
   10.124.148.254
   10.124.148.255

Network: 10.124.148.128/26
Range: 10.124.148.128 - 10.124.148.191
Patterns:
   10.124.148.128
   10.124.148.129
   10.124.148.13?
   10.124.148.14?
   10.124.148.15?
   10.124.148.16?
   10.124.148.17?
   10.124.148.18?
   10.124.148.190
   10.124.148.191

Network: 10.124.148.128/27
Range: 10.124.148.128 - 10.124.148.159
Patterns:
   10.124.148.128
   10.124.148.129
   10.124.148.13?
   10.124.148.14?
   10.124.148.15?

Network: 10.124.148.128/28
Range: 10.124.148.128 - 10.124.148.143
Patterns:
   10.124.148.128
   10.124.148.129
   10.124.148.13?
   10.124.148.140
   10.124.148.141
   10.124.148.142
   10.124.148.143

Network: 10.124.148.128/29
Range: 10.124.148.128 - 10.124.148.135
Patterns:
   10.124.148.128
   10.124.148.129
   10.124.148.130
   10.124.148.131
   10.124.148.132
   10.124.148.133
   10.124.148.134
   10.124.148.135

Network: 10.124.148.132/30
Range: 10.124.148.132 - 10.124.148.135
Patterns:
   10.124.148.132
   10.124.148.133
   10.124.148.134
   10.124.148.135

Network: 10.124.148.134/31
Range: 10.124.148.134 - 10.124.148.135
Patterns:
   10.124.148.134
   10.124.148.135

Network: 10.124.148.135/32
Range: 10.124.148.135 - 10.124.148.135
Patterns:
   10.124.148.135
  

Обратите внимание, что gen_patterns он не пытается использовать тот факт, что 255 является наивысшим допустимым значением, поэтому некоторые диапазоны, заканчивающиеся на 255, будут иметь явно 250 , 251 , …, 255 вместо 25? .

Комментарии:

1. Ого, боже мой! Спасибо!!!! Если ты когда-нибудь будешь в Миннеаполисе, дай мне знать, я куплю тебе пару кружек пива!