=CIDR Tests= Copyright (c) 2008-2012, David P. D. Moss. All rights reserved. {{{ >>> from netaddr import * }}} ==Basic IP Range Tuple Sorting== {{{ >>> ranges = ( ... (IPAddress('::'), IPAddress('::')), ... (IPAddress('0.0.0.0'), IPAddress('255.255.255.255')), ... (IPAddress('::'), IPAddress('::255.255.255.255')), ... (IPAddress('0.0.0.0'), IPAddress('0.0.0.0')), ... ) >>> sorted(ranges) [(IPAddress('0.0.0.0'), IPAddress('0.0.0.0')), (IPAddress('0.0.0.0'), IPAddress('255.255.255.255')), (IPAddress('::'), IPAddress('::')), (IPAddress('::'), IPAddress('::255.255.255.255'))] }}} Worst case IPv4 range to CIDR conversion. {{{ >>> for ip in iprange_to_cidrs('0.0.0.1', '255.255.255.254'): ... ip ... IPNetwork('0.0.0.1/32') IPNetwork('0.0.0.2/31') IPNetwork('0.0.0.4/30') IPNetwork('0.0.0.8/29') IPNetwork('0.0.0.16/28') IPNetwork('0.0.0.32/27') IPNetwork('0.0.0.64/26') IPNetwork('0.0.0.128/25') IPNetwork('0.0.1.0/24') IPNetwork('0.0.2.0/23') IPNetwork('0.0.4.0/22') IPNetwork('0.0.8.0/21') IPNetwork('0.0.16.0/20') IPNetwork('0.0.32.0/19') IPNetwork('0.0.64.0/18') IPNetwork('0.0.128.0/17') IPNetwork('0.1.0.0/16') IPNetwork('0.2.0.0/15') IPNetwork('0.4.0.0/14') IPNetwork('0.8.0.0/13') IPNetwork('0.16.0.0/12') IPNetwork('0.32.0.0/11') IPNetwork('0.64.0.0/10') IPNetwork('0.128.0.0/9') IPNetwork('1.0.0.0/8') IPNetwork('2.0.0.0/7') IPNetwork('4.0.0.0/6') IPNetwork('8.0.0.0/5') IPNetwork('16.0.0.0/4') IPNetwork('32.0.0.0/3') IPNetwork('64.0.0.0/2') IPNetwork('128.0.0.0/2') IPNetwork('192.0.0.0/3') IPNetwork('224.0.0.0/4') IPNetwork('240.0.0.0/5') IPNetwork('248.0.0.0/6') IPNetwork('252.0.0.0/7') IPNetwork('254.0.0.0/8') IPNetwork('255.0.0.0/9') IPNetwork('255.128.0.0/10') IPNetwork('255.192.0.0/11') IPNetwork('255.224.0.0/12') IPNetwork('255.240.0.0/13') IPNetwork('255.248.0.0/14') IPNetwork('255.252.0.0/15') IPNetwork('255.254.0.0/16') IPNetwork('255.255.0.0/17') IPNetwork('255.255.128.0/18') IPNetwork('255.255.192.0/19') IPNetwork('255.255.224.0/20') IPNetwork('255.255.240.0/21') IPNetwork('255.255.248.0/22') IPNetwork('255.255.252.0/23') IPNetwork('255.255.254.0/24') IPNetwork('255.255.255.0/25') IPNetwork('255.255.255.128/26') IPNetwork('255.255.255.192/27') IPNetwork('255.255.255.224/28') IPNetwork('255.255.255.240/29') IPNetwork('255.255.255.248/30') IPNetwork('255.255.255.252/31') IPNetwork('255.255.255.254/32') }}} Worst case IPv4 mapped IPv6 range to CIDR. {{{ >>> for ip in iprange_to_cidrs('::ffff:1', '::ffff:255.255.255.254'): ... ip ... IPNetwork('::255.255.0.1/128') IPNetwork('::255.255.0.2/127') IPNetwork('::255.255.0.4/126') IPNetwork('::255.255.0.8/125') IPNetwork('::255.255.0.16/124') IPNetwork('::255.255.0.32/123') IPNetwork('::255.255.0.64/122') IPNetwork('::255.255.0.128/121') IPNetwork('::255.255.1.0/120') IPNetwork('::255.255.2.0/119') IPNetwork('::255.255.4.0/118') IPNetwork('::255.255.8.0/117') IPNetwork('::255.255.16.0/116') IPNetwork('::255.255.32.0/115') IPNetwork('::255.255.64.0/114') IPNetwork('::255.255.128.0/113') IPNetwork('::1:0:0/96') IPNetwork('::2:0:0/95') IPNetwork('::4:0:0/94') IPNetwork('::8:0:0/93') IPNetwork('::10:0:0/92') IPNetwork('::20:0:0/91') IPNetwork('::40:0:0/90') IPNetwork('::80:0:0/89') IPNetwork('::100:0:0/88') IPNetwork('::200:0:0/87') IPNetwork('::400:0:0/86') IPNetwork('::800:0:0/85') IPNetwork('::1000:0:0/84') IPNetwork('::2000:0:0/83') IPNetwork('::4000:0:0/82') IPNetwork('::8000:0:0/82') IPNetwork('::c000:0:0/83') IPNetwork('::e000:0:0/84') IPNetwork('::f000:0:0/85') IPNetwork('::f800:0:0/86') IPNetwork('::fc00:0:0/87') IPNetwork('::fe00:0:0/88') IPNetwork('::ff00:0:0/89') IPNetwork('::ff80:0:0/90') IPNetwork('::ffc0:0:0/91') IPNetwork('::ffe0:0:0/92') IPNetwork('::fff0:0:0/93') IPNetwork('::fff8:0:0/94') IPNetwork('::fffc:0:0/95') IPNetwork('::fffe:0:0/96') IPNetwork('::ffff:0.0.0.0/97') IPNetwork('::ffff:128.0.0.0/98') IPNetwork('::ffff:192.0.0.0/99') IPNetwork('::ffff:224.0.0.0/100') IPNetwork('::ffff:240.0.0.0/101') IPNetwork('::ffff:248.0.0.0/102') IPNetwork('::ffff:252.0.0.0/103') IPNetwork('::ffff:254.0.0.0/104') IPNetwork('::ffff:255.0.0.0/105') IPNetwork('::ffff:255.128.0.0/106') IPNetwork('::ffff:255.192.0.0/107') IPNetwork('::ffff:255.224.0.0/108') IPNetwork('::ffff:255.240.0.0/109') IPNetwork('::ffff:255.248.0.0/110') IPNetwork('::ffff:255.252.0.0/111') IPNetwork('::ffff:255.254.0.0/112') IPNetwork('::ffff:255.255.0.0/113') IPNetwork('::ffff:255.255.128.0/114') IPNetwork('::ffff:255.255.192.0/115') IPNetwork('::ffff:255.255.224.0/116') IPNetwork('::ffff:255.255.240.0/117') IPNetwork('::ffff:255.255.248.0/118') IPNetwork('::ffff:255.255.252.0/119') IPNetwork('::ffff:255.255.254.0/120') IPNetwork('::ffff:255.255.255.0/121') IPNetwork('::ffff:255.255.255.128/122') IPNetwork('::ffff:255.255.255.192/123') IPNetwork('::ffff:255.255.255.224/124') IPNetwork('::ffff:255.255.255.240/125') IPNetwork('::ffff:255.255.255.248/126') IPNetwork('::ffff:255.255.255.252/127') IPNetwork('::ffff:255.255.255.254/128') }}} RFC 4291 CIDR tests. {{{ >>> str(IPNetwork('2001:0DB8:0000:CD30:0000:0000:0000:0000/60')) '2001:db8:0:cd30::/60' >>> str(IPNetwork('2001:0DB8::CD30:0:0:0:0/60')) '2001:db8:0:cd30::/60' >>> str(IPNetwork('2001:0DB8:0:CD30::/60')) '2001:db8:0:cd30::/60' }}} Equality tests. {{{ >>> IPNetwork('192.0.2.0/255.255.254.0') == IPNetwork('192.0.2.0/23') True >>> IPNetwork('192.0.2.65/255.255.254.0') == IPNetwork('192.0.2.0/23') True >>> IPNetwork('192.0.2.65/255.255.254.0') == IPNetwork('192.0.2.65/23') True >>> IPNetwork('192.0.2.65/255.255.255.0') == IPNetwork('192.0.2.0/23') False >>> IPNetwork('192.0.2.65/255.255.254.0') == IPNetwork('192.0.2.65/24') False }}} Slicing tests. {{{ >>> ip = IPNetwork('192.0.2.0/23') >>> ip.first == 3221225984 True >>> ip.last == 3221226495 True >>> ip[0] IPAddress('192.0.2.0') >>> ip[-1] IPAddress('192.0.3.255') >>> list(ip[::128]) [IPAddress('192.0.2.0'), IPAddress('192.0.2.128'), IPAddress('192.0.3.0'), IPAddress('192.0.3.128')] >>> ip = IPNetwork('fe80::/10') >>> ip[0] IPAddress('fe80::') >>> ip[-1] IPAddress('febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff') >>> ip.size == 332306998946228968225951765070086144 True >>> list(ip[0:5:1]) Traceback (most recent call last): ... TypeError: IPv6 slices are not supported! }}} Membership tests. {{{ >>> IPAddress('192.0.2.1') in IPNetwork('192.0.2.0/24') True >>> IPAddress('192.0.2.255') in IPNetwork('192.0.2.0/24') True >>> IPNetwork('192.0.2.0/24') in IPNetwork('192.0.2.0/23') True >>> IPNetwork('192.0.2.0/24') in IPNetwork('192.0.2.0/24') True >>> IPAddress('ffff::1') in IPNetwork('ffff::/127') True >>> IPNetwork('192.0.2.0/23') in IPNetwork('192.0.2.0/24') False }}} Equality tests. {{{ >>> IPNetwork('192.0.2.0/24') == IPNetwork('192.0.2.0/24') True >>> IPNetwork('192.0.2.0/24') is not IPNetwork('192.0.2.0/24') True >>> IPNetwork('192.0.2.0/24') != IPNetwork('192.0.2.0/24') False >>> IPNetwork('192.0.2.0/24') is IPNetwork('192.0.2.0/24') False >>> IPNetwork('fe80::/10') == IPNetwork('fe80::/10') True >>> IPNetwork('fe80::/10') is not IPNetwork('fe80::/10') True >>> IPNetwork('fe80::/10') != IPNetwork('fe80::/10') False >>> IPNetwork('fe80::/10') is IPNetwork('fe80::/10') False }}} Exclusion tests. {{{ # Equivalent to :- # >>> set([1]) - set([1]) # set([1]) >>> cidr_exclude('192.0.2.1/32', '192.0.2.1/32') [] # Equivalent to :- # >>> set([1,2]) - set([2]) # set([1]) >>> cidr_exclude('192.0.2.0/31', '192.0.2.1/32') [IPNetwork('192.0.2.0/32')] # Equivalent to :- # >>> set([1,2,3,4,5,6,7,8]) - set([5,6,7,8]) # set([1, 2, 3, 4]) >>> cidr_exclude('192.0.2.0/24', '192.0.2.128/25') [IPNetwork('192.0.2.0/25')] # Equivalent to :- # >>> set([1,2,3,4,5,6,7,8]) - set([5,6]) # set([1, 2, 3, 4, 7, 8]) >>> cidr_exclude('192.0.2.0/24', '192.0.2.128/27') [IPNetwork('192.0.2.0/25'), IPNetwork('192.0.2.160/27'), IPNetwork('192.0.2.192/26')] # Subtracting a larger range from a smaller one results in an empty # list (rather than a negative CIDR - which would be rather odd)! # # Equivalent to :- # >>> set([1]) - set([1,2,3]) # set([]) >>> cidr_exclude('192.0.2.1/32', '192.0.2.0/24') [] }}} Please Note: excluding IP subnets that are not within each other and have no overlaps should return the original target IP object. {{{ # Equivalent to :- # >>> set([1,2,3]) - set([4]) # set([1,2,3]) >>> cidr_exclude('192.0.2.0/28', '192.0.2.16/32') [IPNetwork('192.0.2.0/28')] # Equivalent to :- # >>> set([1]) - set([2,3,4]) # set([1]) >>> cidr_exclude('192.0.1.255/32', '192.0.2.0/28') [IPNetwork('192.0.1.255/32')] }}} Merge tests. {{{ >>> cidr_merge(['192.0.128.0/24', '192.0.129.0/24']) [IPNetwork('192.0.128.0/23')] >>> cidr_merge(['192.0.129.0/24', '192.0.130.0/24']) [IPNetwork('192.0.129.0/24'), IPNetwork('192.0.130.0/24')] >>> cidr_merge(['192.0.2.112/30', '192.0.2.116/31', '192.0.2.118/31']) [IPNetwork('192.0.2.112/29')] >>> cidr_merge(['192.0.2.112/30', '192.0.2.116/32', '192.0.2.118/31']) [IPNetwork('192.0.2.112/30'), IPNetwork('192.0.2.116/32'), IPNetwork('192.0.2.118/31')] >>> cidr_merge(['192.0.2.112/31', '192.0.2.116/31', '192.0.2.118/31']) [IPNetwork('192.0.2.112/31'), IPNetwork('192.0.2.116/30')] >>> cidr_merge(['192.0.1.254/31', ... '192.0.2.0/28', ... '192.0.2.16/28', ... '192.0.2.32/28', ... '192.0.2.48/28', ... '192.0.2.64/28', ... '192.0.2.80/28', ... '192.0.2.96/28', ... '192.0.2.112/28', ... '192.0.2.128/28', ... '192.0.2.144/28', ... '192.0.2.160/28', ... '192.0.2.176/28', ... '192.0.2.192/28', ... '192.0.2.208/28', ... '192.0.2.224/28', ... '192.0.2.240/28', ... '192.0.3.0/28']) [IPNetwork('192.0.1.254/31'), IPNetwork('192.0.2.0/24'), IPNetwork('192.0.3.0/28')] }}} Extended merge tests. {{{ >>> import random # Start with a single /23 CIDR. >>> orig_cidr_ipv4 = IPNetwork('192.0.2.0/23') >>> orig_cidr_ipv6 = IPNetwork('::192.0.2.0/120') # Split it into /28 subnet CIDRs (mix CIDR objects and CIDR strings). >>> cidr_subnets = [] >>> cidr_subnets.extend([str(c) for c in orig_cidr_ipv4.subnet(28)]) >>> cidr_subnets.extend(list(orig_cidr_ipv4.subnet(28))) >>> cidr_subnets.extend([str(c) for c in orig_cidr_ipv6.subnet(124)]) >>> cidr_subnets.extend(list(orig_cidr_ipv6.subnet(124))) # Add a couple of duplicates in to make sure summarization is working OK. >>> cidr_subnets.append('192.0.2.1/32') >>> cidr_subnets.append('192.0.2.128/25') >>> cidr_subnets.append('::192.0.2.92/128') # Randomize the order of subnets. >>> random.shuffle(cidr_subnets) # Perform summarization operation. >>> merged_cidrs = cidr_merge(cidr_subnets) >>> merged_cidrs [IPNetwork('192.0.2.0/23'), IPNetwork('::192.0.2.0/120')] >>> merged_cidrs == [orig_cidr_ipv4, orig_cidr_ipv6] True }}}