从
ipaddress
课上,我知道了address_exclude
方法。以下是文档中的示例:
>>> n1 = ip_network('192.0.2.0/28')
>>> n2 = ip_network('192.0.2.1/32')
>>> list(n1.address_exclude(n2))
[IPv4Network('192.0.2.8/29'), IPv4Network('192.0.2.4/30'),
IPv4Network('192.0.2.2/31'), IPv4Network('192.0.2.0/32')]
但是如果我想从网络中删除两个或更多子网怎么办?例如,我如何从192.168.10.0/26中删除他的子网192.168.10.24/29和192.168.10.48/28?结果应为 192.168.10.0/28、192.168.10.16/29 和 192.168.10.32/28。
我正在尝试找到一种方法来使用
address_exclude
方法编写我在脑海中使用的算法,但我不能。有没有一种简单的方法来实现我刚才解释的内容?
扩展我在 @rdas 的回复中发布的脑电波,发布我的解决方案。
最好将初始网络分割成您要求的最小块,并对所有要删除的范围执行此操作。然后将它们从列表中排除并返回结果。
from ipaddress import ip_network, collapse_addresses
def remove_ranges(mynetwork,l_of_ranges):
# find smallest chunk
l_chunk = sorted(list(set([x.split('/')[1] for x in l_of_ranges])))
l_mynetwork = list(ip_network(mynetwork).subnets(new_prefix=int(l_chunk[-1])))
l_chunked_ranges = [ ]
for nw in l_of_ranges:
l_chunked_ranges.extend(list(ip_network(nw).subnets(new_prefix=int(l_chunk[-1]))))
#l_removed_networks = [ ]
#for mynw in l_mynetwork:
# if not mynw in l_chunked_ranges:
# l_removed_networks.append(mynw)
#result = list(collapse_addresses(l_removed_networks))
result = list(collapse_addresses(set(l_mynetwork) - set(l_chunked_ranges)))
return [str(r) for r in result]
if __name__ == '__main__':
mynetwork = "10.110.0.0/16"
l_of_ranges = ["10.110.0.0/18","10.110.72.0/21","10.110.80.0/21","10.110.96.0/21"]
print(f"My network: {mynetwork}, Existing: {l_of_ranges} ")
a = remove_ranges(mynetwork,l_of_ranges)
print(f"Remaining: {a}")
结果:
My network: 10.110.0.0/16, Existing: ['10.110.0.0/18', '10.110.72.0/21', '10.110.80.0/21', '10.110.96.0/21']
Remaining: ['10.110.64.0/21', '10.110.88.0/21', '10.110.104.0/21', '10.110.112.0/20', '10.110.128.0/17']
这似乎是有效的。
当您从另一个网络中排除一个网络时,结果可能是多个网络(原始网络被分割) - 因此,对于要排除的其余网络,您需要先找到它们适合的部分,然后再排除它们。
这是一种可能的解决方案:
from ipaddress import ip_network, collapse_addresses
complete = ip_network('192.168.10.0/26')
# I chose the larger subnet for exclusion first, can be automated with network comparison
subnets = list(complete.address_exclude(ip_network('192.168.10.48/28')))
# other network to exclude
other_exclude = ip_network('192.168.10.24/29')
result = []
# Find which subnet the other exclusion will happen in
for sub in subnets:
# If found, exclude & add the result
if other_exclude.subnet_of(sub):
result.extend(list(sub.address_exclude(other_exclude)))
else:
# Other subnets can be added directly
result.append(sub)
# Collapse in case of overlaps
print(list(collapse_addresses(result)))
输出:
[IPv4Network('192.168.10.0/28'), IPv4Network('192.168.10.16/29'), IPv4Network('192.168.10.32/28')]
感谢分享此代码,我在计算子网时遇到了消耗过多内存的问题,因此提供了此代码示例
import sys
import ipaddress
def parse_cidr(cidr):
try:
# Parse the CIDR notation and return the network object
return ipaddress.ip_network(cidr, strict=True)
except ValueError:
print(f"Invalid CIDR notation: {cidr}")
sys.exit(1)
def exclude_cidr(master, exclude):
# Parse the master and exclude CIDR notations
master_network = parse_cidr(master)
exclude_networks = [parse_cidr(e) for e in exclude]
# Exclude the exclude networks from the master network
remaining_networks = [master_network]
for exclude_net in exclude_networks:
new_remaining = []
for remaining_net in remaining_networks:
if exclude_net.overlaps(remaining_net):
new_remaining.extend(remaining_net.address_exclude(exclude_net))
else:
new_remaining.append(remaining_net)
remaining_networks = new_remaining
return remaining_networks
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python script.py <cidr_master> <cidr_exclude>")
sys.exit(1)
cidr_master = sys.argv[1]
cidr_exclude = sys.argv[2].split(",")
# Get the remaining networks
remaining_subnets = exclude_cidr(cidr_master, cidr_exclude)
# Print the remaining subnets in ascending order of IP address
for subnet in sorted(remaining_subnets, key=lambda x: x.network_address):
print(subnet)
输出示例:
python3 excluder.py 10.0.0.0/8 "10.20.20.0/24,10.20.30.0/24,10.1.1.1/32,10.98.0.0/16"
产生
10.0.0.0/16
10.1.0.0/24
10.1.1.0/32
10.1.1.2/31
10.1.1.4/30
10.1.1.8/29
10.1.1.16/28
10.1.1.32/27
10.1.1.64/26
10.1.1.128/25
10.1.2.0/23
10.1.4.0/22
10.1.8.0/21
10.1.16.0/20
10.1.32.0/19
10.1.64.0/18
10.1.128.0/17
10.2.0.0/15
10.4.0.0/14
10.8.0.0/13
10.16.0.0/14
10.20.0.0/20
10.20.16.0/22
10.20.21.0/24
10.20.22.0/23
10.20.24.0/22
10.20.28.0/23
10.20.31.0/24
10.20.32.0/19
10.20.64.0/18
10.20.128.0/17
10.21.0.0/16
10.22.0.0/15
10.24.0.0/13
10.32.0.0/11
10.64.0.0/11
10.96.0.0/15
10.99.0.0/16
10.100.0.0/14
10.104.0.0/13
10.112.0.0/12
10.128.0.0/9