Skip to content

Instantly share code, notes, and snippets.

@sorrat
Last active May 14, 2020 18:28
Show Gist options
  • Save sorrat/90fe88b7f42db53267dde2497c302bcd to your computer and use it in GitHub Desktop.
Save sorrat/90fe88b7f42db53267dde2497c302bcd to your computer and use it in GitHub Desktop.
"""
Поиск минимальной подсети, содержащей заданный набор IP-адресов.
"""
import unittest
import struct
import socket
def ip_to_bin(ip) -> str:
ip_packed = socket.inet_aton(ip)
ip_int = struct.unpack('!I', ip_packed)[0]
return bin(ip_int)[2:].rjust(32, '0')
def bin_to_ip(ip_bin) -> str:
ip_int = int(ip_bin, 2)
ip_packed = struct.pack('!I', ip_int)
ip = socket.inet_ntoa(ip_packed)
return ip
def get_common_prefix(iterables) -> list:
prefix = []
for elems in zip(*iterables):
if len(set(elems)) == 1:
prefix.append(elems[0])
else:
break
return prefix
def get_min_subnet(ips) -> str:
"""Минимальная подсеть, содержащая адреса ips"""
subnet_bin_prefix = get_common_prefix(map(ip_to_bin, ips))
subnet_bin_ip = ''.join(subnet_bin_prefix).ljust(32, '0')
subnet_id = '%s/%s' % (bin_to_ip(subnet_bin_ip), len(subnet_bin_prefix))
return subnet_id
class TestMinSubnet(unittest.TestCase):
def test_get_min_subnet(self):
test_cases = [
('10.10.0.1/32', [
'10.10.0.1',
]),
('10.10.0.2/31', [
'10.10.0.2',
'10.10.0.3',
]),
('10.10.0.4/30', [
'10.10.0.5',
'10.10.0.6',
]),
('10.10.0.0/29', [
'10.10.0.3',
'10.10.0.4',
]),
('10.10.0.16/28', [
'10.10.0.17',
'10.10.0.24',
]),
('10.10.0.128/25', [
'10.10.0.130',
'10.10.0.200',
]),
('10.10.0.0/24', [
'10.10.0.5',
'10.10.0.128',
]),
('10.10.0.0/16', [
'10.10.10.0',
'10.10.128.2',
]),
('10.0.0.0/8', [
'10.0.1.1',
'10.240.1.2',
]),
('0.0.0.0/0', [
'0.1.0.0',
'240.10.1.2',
]),
]
for i, (expected, inp) in enumerate(test_cases):
with self.subTest(i=i, expected=expected, input=inp):
subnet_id = get_min_subnet(inp)
self.assertEqual(subnet_id, expected)
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment