如何从网络中删除两个或多个子网?

问题描述 投票:0回答:3

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
方法编写我在脑海中使用的算法,但我不能。有没有一种简单的方法来实现我刚才解释的内容?

python networking ipv4
3个回答
1
投票

扩展我在 @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']

这似乎是有效的。


0
投票

当您从另一个网络中排除一个网络时,结果可能是多个网络(原始网络被分割) - 因此,对于要排除的其余网络,您需要先找到它们适合的部分,然后再排除它们。

这是一种可能的解决方案:

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')]

0
投票

感谢分享此代码,我在计算子网时遇到了消耗过多内存的问题,因此提供了此代码示例

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
© www.soinside.com 2019 - 2024. All rights reserved.