#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. Ого, боже мой! Спасибо!!!! Если ты когда-нибудь будешь в Миннеаполисе, дай мне знать, я куплю тебе пару кружек пива!