Initial commit: mwhois with SCION AS support and decimal AS conversion

Based on mwhois by Antonios A. Chariton
Modifications for SCION AS support by Olaf Baumert, Axpo Systems AG
This commit is contained in:
Olaf Baumert
2025-06-03 11:01:02 +00:00
commit 34c631a06d
340 changed files with 212460 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
=Abbreviated CIDR Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Abbreviation tests.
{{{
>>> 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'))]
# Integer values.
>>> cidr_abbrev_to_verbose(-1)
-1
# Class A
>>> cidr_abbrev_to_verbose(0)
'0.0.0.0/8'
>>> cidr_abbrev_to_verbose(10)
'10.0.0.0/8'
>>> cidr_abbrev_to_verbose(127)
'127.0.0.0/8'
# Class B
>>> cidr_abbrev_to_verbose(128)
'128.0.0.0/16'
>>> cidr_abbrev_to_verbose(191)
'191.0.0.0/16'
# Class C
>>> cidr_abbrev_to_verbose(192)
'192.0.0.0/24'
>>> cidr_abbrev_to_verbose(223)
'223.0.0.0/24'
# Class D (multicast)
>>> cidr_abbrev_to_verbose(224)
'224.0.0.0/4'
>>> cidr_abbrev_to_verbose(225)
'225.0.0.0/4'
>>> cidr_abbrev_to_verbose(239)
'239.0.0.0/4'
# Class E (reserved)
>>> cidr_abbrev_to_verbose(240)
'240.0.0.0/32'
>>> cidr_abbrev_to_verbose(254)
'254.0.0.0/32'
>>> cidr_abbrev_to_verbose(255)
'255.0.0.0/32'
>>> cidr_abbrev_to_verbose(256)
256
# String values.
>>> cidr_abbrev_to_verbose('-1')
'-1'
# Class A
>>> cidr_abbrev_to_verbose('0')
'0.0.0.0/8'
>>> cidr_abbrev_to_verbose('10')
'10.0.0.0/8'
>>> cidr_abbrev_to_verbose('127')
'127.0.0.0/8'
# Class B
>>> cidr_abbrev_to_verbose('128')
'128.0.0.0/16'
>>> cidr_abbrev_to_verbose('191')
'191.0.0.0/16'
# Class C
>>> cidr_abbrev_to_verbose('192')
'192.0.0.0/24'
>>> cidr_abbrev_to_verbose('223')
'223.0.0.0/24'
# Class D (multicast)
>>> cidr_abbrev_to_verbose('224')
'224.0.0.0/4'
>>> cidr_abbrev_to_verbose('225')
'225.0.0.0/4'
>>> cidr_abbrev_to_verbose('239')
'239.0.0.0/4'
# Class E (reserved)
>>> cidr_abbrev_to_verbose('240')
'240.0.0.0/32'
>>> cidr_abbrev_to_verbose('254')
'254.0.0.0/32'
>>> cidr_abbrev_to_verbose('255')
'255.0.0.0/32'
>>> cidr_abbrev_to_verbose('256')
'256'
>>> cidr_abbrev_to_verbose('128/8')
'128.0.0.0/8'
>>> cidr_abbrev_to_verbose('128.0/8')
'128.0.0.0/8'
>>> cidr_abbrev_to_verbose('128.0.0.0/8')
'128.0.0.0/8'
>>> cidr_abbrev_to_verbose('128.0.0/8')
'128.0.0.0/8'
>>> cidr_abbrev_to_verbose('192.168')
'192.168.0.0/24'
>>> cidr_abbrev_to_verbose('192.0.2')
'192.0.2.0/24'
>>> cidr_abbrev_to_verbose('192.0.2.0')
'192.0.2.0/24'
>>> cidr_abbrev_to_verbose('0.0.0.0')
'0.0.0.0/8'
# No IPv6 support current.
>>> cidr_abbrev_to_verbose('::/128')
'::/128'
# IPv6 proper, not IPv4 mapped?
>>> cidr_abbrev_to_verbose('::10/128')
'::10/128'
>>> cidr_abbrev_to_verbose('0.0.0.0.0')
'0.0.0.0.0'
>>> cidr_abbrev_to_verbose('')
''
>>> cidr_abbrev_to_verbose(None)
>>> cidr_abbrev_to_verbose([])
[]
>>> cidr_abbrev_to_verbose({})
{}
}}}
Negative testing.
{{{
>>> cidr_abbrev_to_verbose('192.0.2.0')
'192.0.2.0/24'
>>> cidr_abbrev_to_verbose('192.0.2.0/32')
'192.0.2.0/32'
#FIXME: >>> cidr_abbrev_to_verbose('192.0.2.0/33')
Traceback (most recent call last):
...
ValueError: prefixlen in address '192.0.2.0/33' out of range for IPv4!
}}}
IPv4 octet expansion routine.
{{{
>>> from netaddr.strategy import ipv4
>>> ipv4.expand_partial_address('10')
'10.0.0.0'
>>> ipv4.expand_partial_address('10.1')
'10.1.0.0'
>>> ipv4.expand_partial_address('192.168.1')
'192.168.1.0'
}}}
IPNetwork constructor testing.
{{{
>>> IPNetwork('192.168/16')
IPNetwork('192.168.0.0/16')
>>> IPNetwork('192.168.0.15')
IPNetwork('192.168.0.15/32')
>>> IPNetwork('192.168')
IPNetwork('192.168.0.0/32')
>>> IPNetwork('192.168', implicit_prefix=True)
IPNetwork('192.168.0.0/24')
>>> IPNetwork('192.168', True)
IPNetwork('192.168.0.0/24')
>>> IPNetwork('10.0.0.1', True)
IPNetwork('10.0.0.1/8')
}}}

View File

@@ -0,0 +1,68 @@
=Binary and numerical operations on IP addresses=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
==Addition and Subtraction ==
{{{
>>> IPAddress('192.0.2.0') + 1
IPAddress('192.0.2.1')
>>> 1 + IPAddress('192.0.2.0')
IPAddress('192.0.2.1')
>>> IPAddress('192.0.2.1') - 1
IPAddress('192.0.2.0')
>>> IPAddress('192.0.0.0') + IPAddress('0.0.0.42')
IPAddress('192.0.0.42')
>>> IPAddress('192.0.0.42') - IPAddress('0.0.0.42')
IPAddress('192.0.0.0')
>>> 1 - IPAddress('192.0.2.1')
Traceback (most recent call last):
...
IndexError: result outside valid IP address boundary!
>>> ip = IPAddress('10.0.0.1')
>>> ip += 1
>>> ip
IPAddress('10.0.0.2')
>>> ip -= 1
>>> ip
IPAddress('10.0.0.1')
>>> ip += IPAddress('0.0.0.42')
>>> ip
IPAddress('10.0.0.43')
>>> ip -= IPAddress('0.0.0.43')
>>> ip
IPAddress('10.0.0.0')
}}}
==Binary operations==
{{{
>>> IPAddress('192.0.2.15') & IPAddress('255.255.255.0')
IPAddress('192.0.2.0')
>>> IPAddress('255.255.0.0') | IPAddress('0.0.255.255')
IPAddress('255.255.255.255')
>>> IPAddress('255.255.0.0') ^ IPAddress('255.0.0.0')
IPAddress('0.255.0.0')
>>> IPAddress('1.2.3.4').packed
b'\x01\x02\x03\x04'
}}}

View File

@@ -0,0 +1,170 @@
=IP Range Boundary Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
>>> import pprint
}}}
`iter_iprange()` iterator boundary tests.
{{{
>>> pprint.pprint(list(iter_iprange('192.0.2.0', '192.0.2.7')))
[IPAddress('192.0.2.0'),
IPAddress('192.0.2.1'),
IPAddress('192.0.2.2'),
IPAddress('192.0.2.3'),
IPAddress('192.0.2.4'),
IPAddress('192.0.2.5'),
IPAddress('192.0.2.6'),
IPAddress('192.0.2.7')]
>>> pprint.pprint(list(iter_iprange('::ffff:192.0.2.0', '::ffff:192.0.2.7')))
[IPAddress('::ffff:192.0.2.0'),
IPAddress('::ffff:192.0.2.1'),
IPAddress('::ffff:192.0.2.2'),
IPAddress('::ffff:192.0.2.3'),
IPAddress('::ffff:192.0.2.4'),
IPAddress('::ffff:192.0.2.5'),
IPAddress('::ffff:192.0.2.6'),
IPAddress('::ffff:192.0.2.7')]
}}}
`IPNetwork()` iterator boundary tests.
{{{
>>> pprint.pprint(list(IPNetwork('192.0.2.0/29')[0:-1]))
[IPAddress('192.0.2.0'),
IPAddress('192.0.2.1'),
IPAddress('192.0.2.2'),
IPAddress('192.0.2.3'),
IPAddress('192.0.2.4'),
IPAddress('192.0.2.5'),
IPAddress('192.0.2.6')]
>>> pprint.pprint(list(IPNetwork('192.0.2.0/29')[::-1]))
[IPAddress('192.0.2.7'),
IPAddress('192.0.2.6'),
IPAddress('192.0.2.5'),
IPAddress('192.0.2.4'),
IPAddress('192.0.2.3'),
IPAddress('192.0.2.2'),
IPAddress('192.0.2.1'),
IPAddress('192.0.2.0')]
For IPv4, network (first) and broadcast (last) address must be skipped.
>>> pprint.pprint(list(IPNetwork('192.0.2.0/29').iter_hosts()))
[IPAddress('192.0.2.1'),
IPAddress('192.0.2.2'),
IPAddress('192.0.2.3'),
IPAddress('192.0.2.4'),
IPAddress('192.0.2.5'),
IPAddress('192.0.2.6')]
For IPv6, Subnet-Router anycast address (first) must be skipped.
>>> pprint.pprint(list(IPNetwork('::ffff:192.0.2.0/125').iter_hosts()))
[IPAddress('::ffff:192.0.2.1'),
IPAddress('::ffff:192.0.2.2'),
IPAddress('::ffff:192.0.2.3'),
IPAddress('::ffff:192.0.2.4'),
IPAddress('::ffff:192.0.2.5'),
IPAddress('::ffff:192.0.2.6'),
IPAddress('::ffff:192.0.2.7')]
Very small IPNetworks do contain some IP addresses
>>> list(IPNetwork("192.168.0.0/31"))
[IPAddress('192.168.0.0'), IPAddress('192.168.0.1')]
>>> list(IPNetwork("1234::/128"))
[IPAddress('1234::')]
But they have no IPs that can be assigned to hosts.
>>> list(IPNetwork("1234::/128").iter_hosts())
[]
>>> list(IPNetwork("192.168.0.0/31").iter_hosts())
[]
}}}
`IPRange()` iterator boundary tests.
{{{
>>> pprint.pprint(list(IPRange('192.0.2.0', '192.0.2.7')))
[IPAddress('192.0.2.0'),
IPAddress('192.0.2.1'),
IPAddress('192.0.2.2'),
IPAddress('192.0.2.3'),
IPAddress('192.0.2.4'),
IPAddress('192.0.2.5'),
IPAddress('192.0.2.6'),
IPAddress('192.0.2.7')]
>>> pprint.pprint(list(IPRange('::ffff:192.0.2.0', '::ffff:192.0.2.7')))
[IPAddress('::ffff:192.0.2.0'),
IPAddress('::ffff:192.0.2.1'),
IPAddress('::ffff:192.0.2.2'),
IPAddress('::ffff:192.0.2.3'),
IPAddress('::ffff:192.0.2.4'),
IPAddress('::ffff:192.0.2.5'),
IPAddress('::ffff:192.0.2.6'),
IPAddress('::ffff:192.0.2.7')]
}}}
Boolean contexts.
{{{
>>> bool(IPAddress('0.0.0.0'))
False
>>> bool(IPAddress('0.0.0.1'))
True
>>> bool(IPAddress('255.255.255.255'))
True
>>> bool(IPNetwork('0.0.0.0/0'))
True
>>> bool(IPNetwork('::/0'))
True
>>> bool(IPRange('0.0.0.0', '255.255.255.255'))
True
>>> bool(IPRange('0.0.0.0', '0.0.0.0'))
True
>>> bool(IPGlob('*.*.*.*'))
True
>>> bool(IPGlob('0.0.0.0'))
True
}}}
`IPAddress()` negative increment tests.
{{{
>>> ip = IPAddress('0.0.0.0')
>>> ip += -1
Traceback (most recent call last):
...
IndexError: result outside valid IP address boundary!
>>> ip = IPAddress('255.255.255.255')
>>> ip -= -1
Traceback (most recent call last):
...
IndexError: result outside valid IP address boundary!
}}}

View File

@@ -0,0 +1,449 @@
=CIDR Tests=
Copyright (c) 2008-2015, 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
}}}

View File

@@ -0,0 +1,234 @@
=IP Constructor Stress Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
IPAddress constructor - integer values.
{{{
>>> IPAddress(1)
IPAddress('0.0.0.1')
>>> IPAddress(1, 4)
IPAddress('0.0.0.1')
>>> IPAddress(1, 6)
IPAddress('::1')
>>> IPAddress(10)
IPAddress('0.0.0.10')
>>> IPAddress(0x1ffffffff)
IPAddress('::1:ffff:ffff')
>>> IPAddress(0xffffffff, 6)
IPAddress('::255.255.255.255')
>>> IPAddress(0x1ffffffff)
IPAddress('::1:ffff:ffff')
>>> IPAddress(2 ** 128 - 1)
IPAddress('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')
}}}
IPAddress constructor - IPv4 inet_aton behaviour (default).
{{{
# Hexadecimal octets.
>>> IPAddress('0x7f.0x1')
IPAddress('127.0.0.1')
>>> IPAddress('0x7f.0x0.0x0.0x1')
IPAddress('127.0.0.1')
# Octal octets.
>>> IPAddress('0177.01')
IPAddress('127.0.0.1')
# Mixed octets.
>>> IPAddress('0x7f.0.01')
IPAddress('127.0.0.1')
# Partial addresses - pretty weird ...
>>> IPAddress('127')
IPAddress('0.0.0.127')
>>> IPAddress('127')
IPAddress('0.0.0.127')
>>> IPAddress('127.1')
IPAddress('127.0.0.1')
>>> IPAddress('127.0.1')
IPAddress('127.0.0.1')
}}}
IPAddress constructor - IPv4 inet_pton behaviour (stricter parser).
{{{
# Octal octets.
>>> IPAddress('0177.01', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '0177.01'
# Mixed octets.
>>> IPAddress('0x7f.0.01', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '0x7f.0.01'
# Partial octets.
>>> IPAddress('10', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '10'
>>> IPAddress('10.1', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '10.1'
>>> IPAddress('10.0.1', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '10.0.1'
>>> IPAddress('10.0.0.1', flags=INET_PTON)
IPAddress('10.0.0.1')
}}}
IPAddress constructor - zero filled octets.
{{{
# This takes a lot of people by surprise ...
>>> IPAddress('010.000.000.001')
IPAddress('8.0.0.1')
# So, we need this!
>>> IPAddress('010.000.000.001', flags=ZEROFILL)
IPAddress('10.0.0.1')
# Zero-fill with inet_aton behaviour - partial octets are OK but zero-filled
# octets are interpreted as decimal ...
>>> IPAddress('010.000.001', flags=ZEROFILL)
IPAddress('10.0.0.1')
# Zero-fill with inet_pton behaviour - 4 octets only!
>>> IPAddress('010.000.001', flags=INET_PTON|ZEROFILL)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '010.000.001'
# Zero-fill with inet_pton behaviour - 4 octets only!
>>> IPAddress('010.000.000.001', flags=INET_PTON|ZEROFILL)
IPAddress('10.0.0.1')
# To save some typing there are short versions of these flags.
>>> IPAddress('010.000.000.001', flags=P|Z)
IPAddress('10.0.0.1')
}}}
IP network construction.
{{{
>>> IPNetwork('192.0.2.0/24')
IPNetwork('192.0.2.0/24')
>>> IPNetwork('192.0.2.0/255.255.255.0')
IPNetwork('192.0.2.0/24')
>>> IPNetwork('192.0.2.0/0.0.0.255')
IPNetwork('192.0.2.0/24')
>>> IPNetwork(IPNetwork('192.0.2.0/24'))
IPNetwork('192.0.2.0/24')
>>> IPNetwork(IPNetwork('::192.0.2.0/120'))
IPNetwork('::192.0.2.0/120')
>>> IPNetwork(IPNetwork('192.0.2.0/24'))
IPNetwork('192.0.2.0/24')
>>> IPNetwork('::192.0.2.0/120')
IPNetwork('::192.0.2.0/120')
>>> IPNetwork('::192.0.2.0/120', 6)
IPNetwork('::192.0.2.0/120')
}}}
Optional implicit IP network prefix selection rules.
{{{
>>> IPNetwork('192.0.2.0', implicit_prefix=True)
IPNetwork('192.0.2.0/24')
>>> IPNetwork('231.192.0.15', implicit_prefix=True)
IPNetwork('231.192.0.15/4')
>>> IPNetwork('10', implicit_prefix=True)
IPNetwork('10.0.0.0/8')
}}}
Optional flags for tweaking IPNetwork constructor behaviour.
{{{
>>> IPNetwork('172.24.200')
IPNetwork('172.24.200.0/32')
>>> IPNetwork('172.24.200', implicit_prefix=True)
IPNetwork('172.24.200.0/16')
# Truncate the host bits so we get a pure network.
>>> IPNetwork('172.24.200', implicit_prefix=True, flags=NOHOST)
IPNetwork('172.24.0.0/16')
}}}
Negative testing
{{{
>>> IPNetwork('foo')
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: invalid IPNetwork foo
}}}
Netmasks
{{{
>>> IPAddress('1.1.1.1').netmask_bits()
32
>>> IPAddress('255.255.255.254').netmask_bits()
31
>>> IPAddress('255.255.255.0').netmask_bits()
24
>>> IPAddress('::').netmask_bits()
128
}}}

View File

@@ -0,0 +1,27 @@
=IP formatting options=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
==IPAddress representations==
{{{
>>> hex(IPAddress(0))
'0x0'
>>> hex(IPAddress(0xffffffff))
'0xffffffff'
>>> oct(IPAddress(0))
'0o0'
>>> oct(IPAddress(0xffffffff))
'0o37777777777'
}}}

View File

@@ -0,0 +1,48 @@
=IP Function Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
During a cidr merge operation, the address 0.0.0.0/0, representing the whole of the IPv4 address space, should swallow anything it is merged with.
{{{
>>> cidr_merge(['0.0.0.0/0', '0.0.0.0'])
[IPNetwork('0.0.0.0/0')]
>>> cidr_merge(['0.0.0.0/0', '255.255.255.255'])
[IPNetwork('0.0.0.0/0')]
>>> cidr_merge(['0.0.0.0/0', '192.0.2.0/24', '10.0.0.0/8'])
[IPNetwork('0.0.0.0/0')]
}}}
Same goes for the IPv6 CIDR ::/0, representing the whole of the IPv6 address space.
{{{
>>> cidr_merge(['::/0', 'fe80::1'])
[IPNetwork('::/0')]
>>> cidr_merge(['::/0', '::'])
[IPNetwork('::/0')]
>>> cidr_merge(['::/0', '::192.0.2.0/124', 'ff00::101'])
[IPNetwork('::/0')]
}}}
This also applies to mixed IPv4 and IPv6 address lists.
{{{
>>> cidr_merge(['0.0.0.0/0', '0.0.0.0', '::/0', '::'])
[IPNetwork('0.0.0.0/0'), IPNetwork('::/0')]
}}}

View File

@@ -0,0 +1,72 @@
=IP Glob Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
IP Glob tests.
{{{
>>> cidr_to_glob('10.0.0.1/32')
'10.0.0.1'
>>> cidr_to_glob('192.0.2.0/24')
'192.0.2.*'
>>> cidr_to_glob('172.16.0.0/12')
'172.16-31.*.*'
>>> cidr_to_glob('0.0.0.0/0')
'*.*.*.*'
>>> glob_to_cidrs('10.0.0.1')
[IPNetwork('10.0.0.1/32')]
>>> glob_to_cidrs('192.0.2.*')
[IPNetwork('192.0.2.0/24')]
>>> glob_to_cidrs('172.16-31.*.*')
[IPNetwork('172.16.0.0/12')]
>>> glob_to_cidrs('*.*.*.*')
[IPNetwork('0.0.0.0/0')]
>>> glob_to_iptuple('*.*.*.*')
(IPAddress('0.0.0.0'), IPAddress('255.255.255.255'))
>>> iprange_to_globs('192.0.2.0', '192.0.2.255')
['192.0.2.*']
>>> iprange_to_globs('192.0.2.1', '192.0.2.15')
['192.0.2.1-15']
>>> iprange_to_globs('192.0.2.255', '192.0.4.1')
['192.0.2.255', '192.0.3.*', '192.0.4.0-1']
>>> iprange_to_globs('10.0.1.255', '10.0.255.255')
['10.0.1.255', '10.0.2-3.*', '10.0.4-7.*', '10.0.8-15.*', '10.0.16-31.*', '10.0.32-63.*', '10.0.64-127.*', '10.0.128-255.*']
}}}
Validity tests.
{{{
>>> valid_glob('1.1.1.a')
False
>>> valid_glob('1.1.1.1/32')
False
>>> valid_glob('1.1.1.a-b')
False
>>> valid_glob('1.1.a-b.*')
False
}}}

View File

@@ -0,0 +1,171 @@
=IPRange Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Constructor tests.
{{{
>>> iprange = IPRange('192.0.2.1', '192.0.2.254')
>>> iprange
IPRange('192.0.2.1', '192.0.2.254')
>>> '%s' % iprange
'192.0.2.1-192.0.2.254'
>>> IPRange('::ffff:192.0.2.1', '::ffff:192.0.2.254')
IPRange('::ffff:192.0.2.1', '::ffff:192.0.2.254')
>>> IPRange('192.0.2.1', '192.0.2.1')
IPRange('192.0.2.1', '192.0.2.1')
>>> IPRange('208.049.164.000', '208.050.066.255', flags=ZEROFILL)
IPRange('208.49.164.0', '208.50.66.255')
}}}
Bad constructor tests.
{{{
>>> IPRange('192.0.2.2', '192.0.2.1')
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: lower bound IP greater than upper bound!
>>> IPRange('::', '0.0.0.1')
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: base address '0.0.0.1' is not IPv6
>>> IPRange('0.0.0.0', '::1')
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: base address '::1' is not IPv4
}}}
Indexing and slicing tests.
{{{
>>> iprange = IPRange('192.0.2.1', '192.0.2.254')
>>> len(iprange)
254
>>> iprange.first == 3221225985
True
>>> iprange.last == 3221226238
True
>>> iprange[0]
IPAddress('192.0.2.1')
>>> iprange[-1]
IPAddress('192.0.2.254')
>>> iprange[512]
Traceback (most recent call last):
...
IndexError: index out range for address range size!
>>> list(iprange[0:3])
[IPAddress('192.0.2.1'), IPAddress('192.0.2.2'), IPAddress('192.0.2.3')]
>>> list(iprange[0:10:2])
[IPAddress('192.0.2.1'), IPAddress('192.0.2.3'), IPAddress('192.0.2.5'), IPAddress('192.0.2.7'), IPAddress('192.0.2.9')]
>>> list(iprange[0:1024:512])
[IPAddress('192.0.2.1')]
>>> IPRange('::ffff:192.0.2.1', '::ffff:192.0.2.254')[0:10:2]
Traceback (most recent call last):
...
TypeError: IPv6 slices are not supported!
}}}
Membership tests.
{{{
>>> IPRange('192.0.2.5', '192.0.2.10') in IPRange('192.0.2.1', '192.0.2.254')
True
>>> IPRange('fe80::1', 'fe80::fffe') in IPRange('fe80::', 'fe80::ffff:ffff:ffff:ffff')
True
>>> IPRange('192.0.2.5', '192.0.2.10') in IPRange('::', '::255.255.255.255')
False
}}}
Sorting tests.
{{{
>>> ipranges = (IPRange('192.0.2.40', '192.0.2.50'), IPRange('192.0.2.20', '192.0.2.30'), IPRange('192.0.2.1', '192.0.2.254'),)
>>> sorted(ipranges)
[IPRange('192.0.2.1', '192.0.2.254'), IPRange('192.0.2.20', '192.0.2.30'), IPRange('192.0.2.40', '192.0.2.50')]
>>> ipranges = list(ipranges)
>>> ipranges.append(IPRange('192.0.2.45', '192.0.2.49'))
>>> sorted(ipranges)
[IPRange('192.0.2.1', '192.0.2.254'), IPRange('192.0.2.20', '192.0.2.30'), IPRange('192.0.2.40', '192.0.2.50'), IPRange('192.0.2.45', '192.0.2.49')]
}}}
CIDR interoperability tests.
{{{
>>> IPRange('192.0.2.5', '192.0.2.10').cidrs()
[IPNetwork('192.0.2.5/32'), IPNetwork('192.0.2.6/31'), IPNetwork('192.0.2.8/31'), IPNetwork('192.0.2.10/32')]
>>> IPRange('fe80::', 'fe80::ffff:ffff:ffff:ffff').cidrs()
[IPNetwork('fe80::/64')]
}}}
Various additional tests.
{{{
>>> iprange.info
{'IPv4': [{'date': '1993-05',
'designation': 'Administered by ARIN',
'prefix': '192/8',
'status': 'Legacy',
'whois': 'whois.arin.net'}]}
>>> iprange.is_private()
True
>>> iprange.version
4
len() fails when the IPRange is longer than sys.maxint, which is quite likely with IPv6.
>>> from netaddr.compat import _sys_maxint
>>> r = IPRange(IPAddress("::0"), IPAddress(_sys_maxint, 6))
>>> len(r)
Traceback (most recent call last):
...
IndexError: range contains more than ...
>>> r = IPRange(IPAddress("::0"), IPAddress(_sys_maxint - 1, 6))
>>> len(r) == _sys_maxint
True
}}}

View File

@@ -0,0 +1,71 @@
=IP Matching Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
>>> largest_matching_cidr('192.0.2.0', ['192.0.2.0'])
IPNetwork('192.0.2.0/32')
>>> largest_matching_cidr('192.0.2.0', ['10.0.0.1', '192.0.2.0'])
IPNetwork('192.0.2.0/32')
>>> largest_matching_cidr('192.0.2.0', ['10.0.0.1', '192.0.2.0', '224.0.0.1'])
IPNetwork('192.0.2.0/32')
>>> smallest_matching_cidr('192.0.2.0', ['10.0.0.1', '192.0.2.0', '224.0.0.1'])
IPNetwork('192.0.2.0/32')
>>> smallest_matching_cidr('192.0.2.32', ['0.0.0.0/0', '10.0.0.0/8', '192.0.0.0/8', '192.0.1.0/24', '192.0.2.0/24', '192.0.3.0/24'])
IPNetwork('192.0.2.0/24')
>>> all_matching_cidrs('192.0.2.32', ['0.0.0.0/0', '10.0.0.0/8', '192.0.0.0/8', '192.0.1.0/24', '192.0.2.0/24', '192.0.3.0/24'])
[IPNetwork('0.0.0.0/0'), IPNetwork('192.0.0.0/8'), IPNetwork('192.0.2.0/24')]
>>> smallest_matching_cidr('192.0.2.0', ['10.0.0.1', '224.0.0.1'])
>>> largest_matching_cidr('192.0.2.0', ['10.0.0.1', '224.0.0.1'])
>>> networks = [str(c) for c in IPNetwork('192.0.2.128/27').supernet(22)]
>>> networks
['192.0.0.0/22', '192.0.2.0/23', '192.0.2.0/24', '192.0.2.128/25', '192.0.2.128/26']
>>> all_matching_cidrs('192.0.2.0', networks)
[IPNetwork('192.0.0.0/22'), IPNetwork('192.0.2.0/23'), IPNetwork('192.0.2.0/24')]
>>> smallest_matching_cidr('192.0.2.0', networks)
IPNetwork('192.0.2.0/24')
>>> largest_matching_cidr('192.0.2.0', networks)
IPNetwork('192.0.0.0/22')
}}}
Checking matches with varying IP address versions.
{{{
>>> all_matching_cidrs('192.0.2.0', ['192.0.2.0/24'])
[IPNetwork('192.0.2.0/24')]
>>> all_matching_cidrs('192.0.2.0', ['::/96'])
[]
>>> all_matching_cidrs('::ffff:192.0.2.1', ['::ffff:192.0.2.0/96'])
[IPNetwork('::ffff:192.0.2.0/96')]
>>> all_matching_cidrs('::192.0.2.1', ['::192.0.2.0/96'])
[IPNetwork('::192.0.2.0/96')]
>>> all_matching_cidrs('::192.0.2.1', ['192.0.2.0/23'])
[]
>>> all_matching_cidrs('::192.0.2.1', ['192.0.2.0/24', '::192.0.2.0/120'])
[IPNetwork('::192.0.2.0/120')]
>>> all_matching_cidrs('::192.0.2.1', [IPNetwork('192.0.2.0/24'), IPNetwork('::192.0.2.0/120')])
[IPNetwork('::192.0.2.0/120')]
}}}

View File

@@ -0,0 +1,30 @@
=IP Multicast Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
>>> ip = IPAddress('239.192.0.1')
>>> ip.is_multicast()
True
>>> ip = IPAddress(3221225984)
>>> ip = IPAddress('224.0.1.173')
>>> ip.info.IPv4[0].designation
'Multicast'
>>> ip.info.IPv4[0].prefix
'224/8'
>>> ip.info.IPv4[0].status
'Reserved'
>>> ip.info.Multicast[0].address
'224.0.1.173'
}}}

View File

@@ -0,0 +1,118 @@
=nmap IP Range Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
nmap IP range validation.
{{{
>>> valid_nmap_range('192.0.2.1')
True
>>> valid_nmap_range('192.0.2.0-31')
True
>>> valid_nmap_range('192.0.2-3.1-254')
True
>>> valid_nmap_range('0-255.0-255.0-255.0-255')
True
>>> valid_nmap_range('192.168.3-5,7.1')
True
>>> valid_nmap_range('192.168.3-5,7,10-12,13,14.1')
True
>>> valid_nmap_range(1)
False
>>> valid_nmap_range('1')
False
>>> valid_nmap_range([])
False
>>> valid_nmap_range({})
False
>>> valid_nmap_range('::')
False
>>> valid_nmap_range('255.255.255.256')
False
>>> valid_nmap_range('0-255.0-255.0-255.0-256')
False
>>> valid_nmap_range('0-255.0-255.0-255.-1-0')
False
>>> valid_nmap_range('0-255.0-255.0-255.256-0')
False
>>> valid_nmap_range('0-255.0-255.0-255.255-0')
False
>>> valid_nmap_range('a.b.c.d-e')
False
>>> valid_nmap_range('255.255.255.a-b')
False
}}}
nmap IP range iteration.
{{{
>>> list(iter_nmap_range('192.0.2.1'))
[IPAddress('192.0.2.1')]
>>> ip_list = list(iter_nmap_range('192.0.2.0-31'))
>>> len(ip_list)
32
>>> ip_list
[IPAddress('192.0.2.0'), IPAddress('192.0.2.1'), IPAddress('192.0.2.2'), IPAddress('192.0.2.3'), IPAddress('192.0.2.4'), IPAddress('192.0.2.5'), IPAddress('192.0.2.6'), IPAddress('192.0.2.7'), IPAddress('192.0.2.8'), IPAddress('192.0.2.9'), IPAddress('192.0.2.10'), IPAddress('192.0.2.11'), IPAddress('192.0.2.12'), IPAddress('192.0.2.13'), IPAddress('192.0.2.14'), IPAddress('192.0.2.15'), IPAddress('192.0.2.16'), IPAddress('192.0.2.17'), IPAddress('192.0.2.18'), IPAddress('192.0.2.19'), IPAddress('192.0.2.20'), IPAddress('192.0.2.21'), IPAddress('192.0.2.22'), IPAddress('192.0.2.23'), IPAddress('192.0.2.24'), IPAddress('192.0.2.25'), IPAddress('192.0.2.26'), IPAddress('192.0.2.27'), IPAddress('192.0.2.28'), IPAddress('192.0.2.29'), IPAddress('192.0.2.30'), IPAddress('192.0.2.31')]
>>> ip_list = list(iter_nmap_range('192.0.2-3.1-7'))
>>> len(ip_list)
14
>>> list(iter_nmap_range('192.0.2.1-3,5,7-9'))
[IPAddress('192.0.2.1'), IPAddress('192.0.2.2'), IPAddress('192.0.2.3'), IPAddress('192.0.2.5'), IPAddress('192.0.2.7'), IPAddress('192.0.2.8'), IPAddress('192.0.2.9')]
>>> for ip in ip_list:
... print(ip)
...
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
192.0.2.5
192.0.2.6
192.0.2.7
192.0.3.1
192.0.3.2
192.0.3.3
192.0.3.4
192.0.3.5
192.0.3.6
192.0.3.7
>>> list(iter_nmap_range('::'))
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: invalid nmap range: ::
Remove duplicates, just like nmap does.
>>> list(iter_nmap_range('10.0.0.42,42-42'))
[IPAddress('10.0.0.42')]
}}}

View File

@@ -0,0 +1,214 @@
=IP Persistence Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
>>> import pickle
}}}
IPAddress object pickling - IPv4.
{{{
>>> ip = IPAddress(3221225985)
>>> ip
IPAddress('192.0.2.1')
>>> buf = pickle.dumps(ip)
>>> ip2 = pickle.loads(buf)
>>> ip2 == ip
True
>>> id(ip2) != id(ip)
True
>>> ip2.value == 3221225985
True
>>> ip2.version
4
>>> del ip, buf, ip2
}}}
IPAddress object pickling - IPv6.
{{{
>>> ip = IPAddress('::ffff:192.0.2.1')
>>> ip
IPAddress('::ffff:192.0.2.1')
>>> ip.value == 281473902969345
True
>>> buf = pickle.dumps(ip)
>>> ip2 = pickle.loads(buf)
>>> ip2 == ip
True
>>> ip2.value == 281473902969345
True
>>> ip2.version
6
>>> del ip, buf, ip2
}}}
IPNetwork pickling - IPv4.
{{{
>>> cidr = IPNetwork('192.0.2.0/24')
>>> cidr
IPNetwork('192.0.2.0/24')
>>> buf = pickle.dumps(cidr)
>>> cidr2 = pickle.loads(buf)
>>> cidr2 == cidr
True
>>> id(cidr2) != id(cidr)
True
>>> cidr2.value == 3221225984
True
>>> cidr2.prefixlen
24
>>> cidr2.version
4
>>> del cidr, buf, cidr2
}}}
IPNetwork object pickling - IPv6.
{{{
>>> cidr = IPNetwork('::ffff:192.0.2.0/120')
>>> cidr
IPNetwork('::ffff:192.0.2.0/120')
>>> cidr.value == 281473902969344
True
>>> cidr.prefixlen
120
>>> buf = pickle.dumps(cidr)
>>> cidr2 = pickle.loads(buf)
>>> cidr2 == cidr
True
>>> cidr2.value == 281473902969344
True
>>> cidr2.prefixlen
120
>>> cidr2.version
6
>>> del cidr, buf, cidr2
}}}
}}}
IPRange object pickling - IPv4.
{{{
>>> iprange = IPRange('192.0.2.1', '192.0.2.254')
>>> iprange
IPRange('192.0.2.1', '192.0.2.254')
>>> iprange.first == 3221225985
True
>>> iprange.last == 3221226238
True
>>> iprange.version
4
>>> buf = pickle.dumps(iprange)
>>> iprange2 = pickle.loads(buf)
>>> iprange2 == iprange
True
>>> id(iprange2) != id(iprange)
True
>>> iprange2.first == 3221225985
True
>>> iprange2.last == 3221226238
True
>>> iprange2.version
4
>>> del iprange, buf, iprange2
}}}
IPRange object pickling - IPv6.
{{{
>>> iprange = IPRange('::ffff:192.0.2.1', '::ffff:192.0.2.254')
>>> iprange
IPRange('::ffff:192.0.2.1', '::ffff:192.0.2.254')
>>> iprange.first == 281473902969345
True
>>> iprange.last == 281473902969598
True
>>> iprange.version
6
>>> buf = pickle.dumps(iprange)
>>> iprange2 = pickle.loads(buf)
>>> iprange2 == iprange
True
>>> iprange2.first == 281473902969345
True
>>> iprange2.last == 281473902969598
True
>>> iprange2.version
6
>>> del iprange, buf, iprange2
}}}

View File

@@ -0,0 +1,90 @@
=Mac OSX Specific Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Worst case IPv4 compatible IPv6 range to CIDR.
{{{
>>> for ip in iprange_to_cidrs('::1', '::255.255.255.254'):
... ip
...
IPNetwork('::1/128')
IPNetwork('::0.0.0.2/127')
IPNetwork('::0.0.0.4/126')
IPNetwork('::0.0.0.8/125')
IPNetwork('::0.0.0.16/124')
IPNetwork('::0.0.0.32/123')
IPNetwork('::0.0.0.64/122')
IPNetwork('::0.0.0.128/121')
IPNetwork('::0.0.1.0/120')
IPNetwork('::0.0.2.0/119')
IPNetwork('::0.0.4.0/118')
IPNetwork('::0.0.8.0/117')
IPNetwork('::0.0.16.0/116')
IPNetwork('::0.0.32.0/115')
IPNetwork('::0.0.64.0/114')
IPNetwork('::0.0.128.0/113')
IPNetwork('::0.1.0.0/112')
IPNetwork('::0.2.0.0/111')
IPNetwork('::0.4.0.0/110')
IPNetwork('::0.8.0.0/109')
IPNetwork('::0.16.0.0/108')
IPNetwork('::0.32.0.0/107')
IPNetwork('::0.64.0.0/106')
IPNetwork('::0.128.0.0/105')
IPNetwork('::1.0.0.0/104')
IPNetwork('::2.0.0.0/103')
IPNetwork('::4.0.0.0/102')
IPNetwork('::8.0.0.0/101')
IPNetwork('::16.0.0.0/100')
IPNetwork('::32.0.0.0/99')
IPNetwork('::64.0.0.0/98')
IPNetwork('::128.0.0.0/98')
IPNetwork('::192.0.0.0/99')
IPNetwork('::224.0.0.0/100')
IPNetwork('::240.0.0.0/101')
IPNetwork('::248.0.0.0/102')
IPNetwork('::252.0.0.0/103')
IPNetwork('::254.0.0.0/104')
IPNetwork('::255.0.0.0/105')
IPNetwork('::255.128.0.0/106')
IPNetwork('::255.192.0.0/107')
IPNetwork('::255.224.0.0/108')
IPNetwork('::255.240.0.0/109')
IPNetwork('::255.248.0.0/110')
IPNetwork('::255.252.0.0/111')
IPNetwork('::255.254.0.0/112')
IPNetwork('::255.255.0.0/113')
IPNetwork('::255.255.128.0/114')
IPNetwork('::255.255.192.0/115')
IPNetwork('::255.255.224.0/116')
IPNetwork('::255.255.240.0/117')
IPNetwork('::255.255.248.0/118')
IPNetwork('::255.255.252.0/119')
IPNetwork('::255.255.254.0/120')
IPNetwork('::255.255.255.0/121')
IPNetwork('::255.255.255.128/122')
IPNetwork('::255.255.255.192/123')
IPNetwork('::255.255.255.224/124')
IPNetwork('::255.255.255.240/125')
IPNetwork('::255.255.255.248/126')
IPNetwork('::255.255.255.252/127')
IPNetwork('::255.255.255.254/128')
# inet_pton has to be different on Mac OSX *sigh*
>>> IPAddress('010.000.000.001', flags=INET_PTON)
IPAddress('10.0.0.1')
>>> from netaddr.strategy.ipv6 import int_to_str
>>> int_to_str(0xffff)
'::0.0.255.255'
}}}

View File

@@ -0,0 +1,94 @@
=Linux Specific Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Worst case IPv4 compatible IPv6 range to CIDR.
{{{
>>> for ip in iprange_to_cidrs('::1', '::255.255.255.254'):
... ip
...
IPNetwork('::1/128')
IPNetwork('::2/127')
IPNetwork('::4/126')
IPNetwork('::8/125')
IPNetwork('::10/124')
IPNetwork('::20/123')
IPNetwork('::40/122')
IPNetwork('::80/121')
IPNetwork('::100/120')
IPNetwork('::200/119')
IPNetwork('::400/118')
IPNetwork('::800/117')
IPNetwork('::1000/116')
IPNetwork('::2000/115')
IPNetwork('::4000/114')
IPNetwork('::8000/113')
IPNetwork('::0.1.0.0/112')
IPNetwork('::0.2.0.0/111')
IPNetwork('::0.4.0.0/110')
IPNetwork('::0.8.0.0/109')
IPNetwork('::0.16.0.0/108')
IPNetwork('::0.32.0.0/107')
IPNetwork('::0.64.0.0/106')
IPNetwork('::0.128.0.0/105')
IPNetwork('::1.0.0.0/104')
IPNetwork('::2.0.0.0/103')
IPNetwork('::4.0.0.0/102')
IPNetwork('::8.0.0.0/101')
IPNetwork('::16.0.0.0/100')
IPNetwork('::32.0.0.0/99')
IPNetwork('::64.0.0.0/98')
IPNetwork('::128.0.0.0/98')
IPNetwork('::192.0.0.0/99')
IPNetwork('::224.0.0.0/100')
IPNetwork('::240.0.0.0/101')
IPNetwork('::248.0.0.0/102')
IPNetwork('::252.0.0.0/103')
IPNetwork('::254.0.0.0/104')
IPNetwork('::255.0.0.0/105')
IPNetwork('::255.128.0.0/106')
IPNetwork('::255.192.0.0/107')
IPNetwork('::255.224.0.0/108')
IPNetwork('::255.240.0.0/109')
IPNetwork('::255.248.0.0/110')
IPNetwork('::255.252.0.0/111')
IPNetwork('::255.254.0.0/112')
IPNetwork('::255.255.0.0/113')
IPNetwork('::255.255.128.0/114')
IPNetwork('::255.255.192.0/115')
IPNetwork('::255.255.224.0/116')
IPNetwork('::255.255.240.0/117')
IPNetwork('::255.255.248.0/118')
IPNetwork('::255.255.252.0/119')
IPNetwork('::255.255.254.0/120')
IPNetwork('::255.255.255.0/121')
IPNetwork('::255.255.255.128/122')
IPNetwork('::255.255.255.192/123')
IPNetwork('::255.255.255.224/124')
IPNetwork('::255.255.255.240/125')
IPNetwork('::255.255.255.248/126')
IPNetwork('::255.255.255.252/127')
IPNetwork('::255.255.255.254/128')
# Sadly, inet_pton cannot help us here ...
>>> IPAddress('010.000.000.001', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '010.000.000.001'
>>> from netaddr.strategy.ipv6 import int_to_str
>>> int_to_str(0xffff)
'::ffff'
}}}

View File

@@ -0,0 +1,92 @@
=Windows Specific Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Worst case IPv4 compatible IPv6 range to CIDR.
{{{
>>> for ip in iprange_to_cidrs('::1', '::255.255.255.254'):
... ip
...
IPNetwork('::1/128')
IPNetwork('::2/127')
IPNetwork('::4/126')
IPNetwork('::8/125')
IPNetwork('::10/124')
IPNetwork('::20/123')
IPNetwork('::40/122')
IPNetwork('::80/121')
IPNetwork('::100/120')
IPNetwork('::200/119')
IPNetwork('::400/118')
IPNetwork('::800/117')
IPNetwork('::1000/116')
IPNetwork('::2000/115')
IPNetwork('::4000/114')
IPNetwork('::8000/113')
IPNetwork('::0.1.0.0/112')
IPNetwork('::0.2.0.0/111')
IPNetwork('::0.4.0.0/110')
IPNetwork('::0.8.0.0/109')
IPNetwork('::0.16.0.0/108')
IPNetwork('::0.32.0.0/107')
IPNetwork('::0.64.0.0/106')
IPNetwork('::0.128.0.0/105')
IPNetwork('::1.0.0.0/104')
IPNetwork('::2.0.0.0/103')
IPNetwork('::4.0.0.0/102')
IPNetwork('::8.0.0.0/101')
IPNetwork('::16.0.0.0/100')
IPNetwork('::32.0.0.0/99')
IPNetwork('::64.0.0.0/98')
IPNetwork('::128.0.0.0/98')
IPNetwork('::192.0.0.0/99')
IPNetwork('::224.0.0.0/100')
IPNetwork('::240.0.0.0/101')
IPNetwork('::248.0.0.0/102')
IPNetwork('::252.0.0.0/103')
IPNetwork('::254.0.0.0/104')
IPNetwork('::255.0.0.0/105')
IPNetwork('::255.128.0.0/106')
IPNetwork('::255.192.0.0/107')
IPNetwork('::255.224.0.0/108')
IPNetwork('::255.240.0.0/109')
IPNetwork('::255.248.0.0/110')
IPNetwork('::255.252.0.0/111')
IPNetwork('::255.254.0.0/112')
IPNetwork('::255.255.0.0/113')
IPNetwork('::255.255.128.0/114')
IPNetwork('::255.255.192.0/115')
IPNetwork('::255.255.224.0/116')
IPNetwork('::255.255.240.0/117')
IPNetwork('::255.255.248.0/118')
IPNetwork('::255.255.252.0/119')
IPNetwork('::255.255.254.0/120')
IPNetwork('::255.255.255.0/121')
IPNetwork('::255.255.255.128/122')
IPNetwork('::255.255.255.192/123')
IPNetwork('::255.255.255.224/124')
IPNetwork('::255.255.255.240/125')
IPNetwork('::255.255.255.248/126')
IPNetwork('::255.255.255.252/127')
IPNetwork('::255.255.255.254/128')
# Sadly, inet_pton cannot help us here ...
>>> IPAddress('010.000.000.001', flags=INET_PTON)
Traceback (most recent call last):
...
netaddr.core.AddrFormatError: failed to detect a valid IP address from '010.000.000.001'
>>> from netaddr.strategy.ipv6 import int_to_str
>>> int_to_str(0xffff)
'::ffff'
}}}

View File

@@ -0,0 +1,33 @@
=RFC 1924 Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
The example from the RFC.
{{{
>>> from netaddr.ip.rfc1924 import ipv6_to_base85, base85_to_ipv6
>>> ip_addr = '1080::8:800:200c:417a'
>>> ip_addr
'1080::8:800:200c:417a'
>>> base85 = ipv6_to_base85(ip_addr)
>>> base85
'4)+k&C#VzJ4br>0wv%Yp'
RFC specifies that "leading zeroes are never omitted"
>>> ipv6_to_base85("::1")
'00000000000000000001'
>>> base85_to_ipv6(base85)
'1080::8:800:200c:417a'
Invalid length for a base85 encoded IPv6 address
>>> base85_to_ipv6('not 20 chars')
Traceback (most recent call last):
netaddr.core.AddrFormatError: Invalid base 85 IPv6 address: 'not 20 chars'
}}}

View File

@@ -0,0 +1,695 @@
=IPSet Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Basic operations.
{{{
>>> IPSet()
IPSet([])
>>> IPSet([])
IPSet([])
>>> len(IPSet([]))
0
len() fails when the IPSet is longer than sys.maxint, which is most likely with IPv6.
>>> from netaddr.compat import _sys_maxint
>>> s = IPSet(IPRange(IPAddress("::0"), IPAddress(_sys_maxint, 6)))
>>> len(s)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
...
IndexError: range contains more than ...
>>> s = IPSet(IPRange(IPAddress("::0"), IPAddress(_sys_maxint - 1, 6)))
>>> len(s) == _sys_maxint
True
IPSets must be usable in boolean context, even when they are very large.
>>> s6 = IPSet(['2405:8100::/32'])
>>> bool(s6)
True
>>> bool(IPSet())
False
>>> IPSet(['192.0.2.0'])
IPSet(['192.0.2.0/32'])
>>> IPSet([IPAddress('192.0.2.0')])
IPSet(['192.0.2.0/32'])
>>> IPSet([IPNetwork('192.0.2.0')])
IPSet(['192.0.2.0/32'])
>>> IPSet(IPNetwork('1234::/32'))
IPSet(['1234::/32'])
>>> IPSet([IPNetwork('192.0.2.0/24')])
IPSet(['192.0.2.0/24'])
>>> IPSet(IPSet(['192.0.2.0/32']))
IPSet(['192.0.2.0/32'])
>>> IPSet(IPRange("10.0.0.0", "10.0.1.31"))
IPSet(['10.0.0.0/24', '10.0.1.0/27'])
>>> IPSet(IPRange('0.0.0.0', '255.255.255.255'))
IPSet(['0.0.0.0/0'])
>>> for ip in IPSet(['192.0.2.0/28', '::192.0.2.0/124']):
... print(ip)
192.0.2.0
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
192.0.2.5
192.0.2.6
192.0.2.7
192.0.2.8
192.0.2.9
192.0.2.10
192.0.2.11
192.0.2.12
192.0.2.13
192.0.2.14
192.0.2.15
::192.0.2.0
::192.0.2.1
::192.0.2.2
::192.0.2.3
::192.0.2.4
::192.0.2.5
::192.0.2.6
::192.0.2.7
::192.0.2.8
::192.0.2.9
::192.0.2.10
::192.0.2.11
::192.0.2.12
::192.0.2.13
::192.0.2.14
::192.0.2.15
}}}
Adding and removing elements.
{{{
>>> s1 = IPSet()
>>> s1.add('192.0.2.0')
>>> s1
IPSet(['192.0.2.0/32'])
>>> s1.remove('192.0.2.0')
>>> s1
IPSet([])
>>> s1.remove('192.0.2.0')
>>> s1
IPSet([])
>>> s1.add(IPRange("10.0.0.0", "10.0.0.255"))
>>> s1
IPSet(['10.0.0.0/24'])
>>> s1.remove(IPRange("10.0.0.128", "10.10.10.10"))
>>> s1
IPSet(['10.0.0.0/25'])
This hits a special case in IPSet._compact_single_network()
>>> s1.add('10.0.0.0/24')
>>> s1
IPSet(['10.0.0.0/24'])
Various places must also accept integers.
>>> integer1 = int(IPAddress('10.0.0.1'))
>>> integer2 = int(IPAddress('fe80::'))
>>> integer3 = int(IPAddress('10.0.0.2'))
>>> s2 = IPSet([integer1, integer2])
>>> s2
IPSet(['10.0.0.1/32', 'fe80::/128'])
>>> s2.add(integer3)
>>> s2
IPSet(['10.0.0.1/32', '10.0.0.2/32', 'fe80::/128'])
>>> s2.remove(integer2)
>>> s2
IPSet(['10.0.0.1/32', '10.0.0.2/32'])
>>> s2.update([integer2])
>>> s2
IPSet(['10.0.0.1/32', '10.0.0.2/32', 'fe80::/128'])
}}}
Set membership.
{{{
>>> iprange = IPRange('192.0.1.255', '192.0.2.16')
>>> iprange.cidrs()
[IPNetwork('192.0.1.255/32'), IPNetwork('192.0.2.0/28'), IPNetwork('192.0.2.16/32')]
>>> ipset = IPSet(['192.0.2.0/28'])
>>> for ip in iprange:
... print(ip, ip in ipset)
192.0.1.255 False
192.0.2.0 True
192.0.2.1 True
192.0.2.2 True
192.0.2.3 True
192.0.2.4 True
192.0.2.5 True
192.0.2.6 True
192.0.2.7 True
192.0.2.8 True
192.0.2.9 True
192.0.2.10 True
192.0.2.11 True
192.0.2.12 True
192.0.2.13 True
192.0.2.14 True
192.0.2.15 True
192.0.2.16 False
>>> bigone = IPSet(['0.0.0.0/0'])
>>> IPAddress("10.0.0.1") in bigone
True
>>> IPAddress("0.0.0.0") in bigone
True
>>> IPAddress("255.255.255") in bigone
True
>>> IPNetwork("10.0.0.0/24") in bigone
True
>>> IPAddress("::1") in bigone
False
>>> smallone = IPSet(["10.0.0.42/32"])
>>> IPAddress("10.0.0.42") in smallone
True
>>> IPAddress("10.0.0.41") in smallone
False
>>> IPAddress("10.0.0.43") in smallone
False
>>> IPNetwork("10.0.0.42/32") in smallone
True
>>> IPNetwork("10.0.0.42/31") in smallone
False
}}}
Set union.
{{{
>>> IPSet(['192.0.2.0'])
IPSet(['192.0.2.0/32'])
>>> IPSet(['192.0.2.0']) | IPSet(['192.0.2.1'])
IPSet(['192.0.2.0/31'])
>>> IPSet(['192.0.2.0']) | IPSet(['192.0.2.1']) | IPSet(['192.0.2.3'])
IPSet(['192.0.2.0/31', '192.0.2.3/32'])
>>> IPSet(['192.0.2.0']) | IPSet(['192.0.2.1']) | IPSet(['192.0.2.3/30'])
IPSet(['192.0.2.0/30'])
>>> IPSet(['192.0.2.0']) | IPSet(['192.0.2.1']) | IPSet(['192.0.2.3/31'])
IPSet(['192.0.2.0/30'])
>>> IPSet(['192.0.2.0/24']) | IPSet(['192.0.3.0/24']) | IPSet(['192.0.4.0/24'])
IPSet(['192.0.2.0/23', '192.0.4.0/24'])
}}}
A joined up example of the union, intersection and symmetric difference operations.
{{{
>>> adj_cidrs = list(IPNetwork('192.0.2.0/24').subnet(28))
>>> even_cidrs = adj_cidrs[::2]
>>> evens = IPSet(even_cidrs)
>>> evens
IPSet(['192.0.2.0/28', '192.0.2.32/28', '192.0.2.64/28', '192.0.2.96/28', '192.0.2.128/28', '192.0.2.160/28', '192.0.2.192/28', '192.0.2.224/28'])
>>> IPSet(['192.0.2.0/24']) & evens
IPSet(['192.0.2.0/28', '192.0.2.32/28', '192.0.2.64/28', '192.0.2.96/28', '192.0.2.128/28', '192.0.2.160/28', '192.0.2.192/28', '192.0.2.224/28'])
>>> odds = IPSet(['192.0.2.0/24']) ^ evens
>>> odds
IPSet(['192.0.2.16/28', '192.0.2.48/28', '192.0.2.80/28', '192.0.2.112/28', '192.0.2.144/28', '192.0.2.176/28', '192.0.2.208/28', '192.0.2.240/28'])
>>> evens | odds
IPSet(['192.0.2.0/24'])
>>> evens & odds
IPSet([])
>>> evens ^ odds
IPSet(['192.0.2.0/24'])
}}}
Superset and subset tests.
{{{
>>> s1 = IPSet(['192.0.2.0/24', '192.0.4.0/24'])
>>> s2 = IPSet(['192.0.2.0', '192.0.4.0'])
>>> s1
IPSet(['192.0.2.0/24', '192.0.4.0/24'])
>>> s2
IPSet(['192.0.2.0/32', '192.0.4.0/32'])
>>> s1.issuperset(s2)
True
>>> s2.issubset(s1)
True
>>> s2.issuperset(s1)
False
>>> s1.issubset(s2)
False
}}}
{{{
>>> ipv4_addr_space = IPSet(['0.0.0.0/0'])
>>> private = IPSet(['10.0.0.0/8', '172.16.0.0/12', '192.0.2.0/24', '192.168.0.0/16', '239.192.0.0/14'])
>>> reserved = IPSet(['225.0.0.0/8', '226.0.0.0/7', '228.0.0.0/6', '234.0.0.0/7', '236.0.0.0/7', '238.0.0.0/8', '240.0.0.0/4'])
>>> unavailable = reserved | private
>>> available = ipv4_addr_space ^ unavailable
>>> for cidr in available.iter_cidrs():
... print(cidr, cidr[0], cidr[-1])
0.0.0.0/5 0.0.0.0 7.255.255.255
8.0.0.0/7 8.0.0.0 9.255.255.255
11.0.0.0/8 11.0.0.0 11.255.255.255
12.0.0.0/6 12.0.0.0 15.255.255.255
16.0.0.0/4 16.0.0.0 31.255.255.255
32.0.0.0/3 32.0.0.0 63.255.255.255
64.0.0.0/2 64.0.0.0 127.255.255.255
128.0.0.0/3 128.0.0.0 159.255.255.255
160.0.0.0/5 160.0.0.0 167.255.255.255
168.0.0.0/6 168.0.0.0 171.255.255.255
172.0.0.0/12 172.0.0.0 172.15.255.255
172.32.0.0/11 172.32.0.0 172.63.255.255
172.64.0.0/10 172.64.0.0 172.127.255.255
172.128.0.0/9 172.128.0.0 172.255.255.255
173.0.0.0/8 173.0.0.0 173.255.255.255
174.0.0.0/7 174.0.0.0 175.255.255.255
176.0.0.0/4 176.0.0.0 191.255.255.255
192.0.0.0/23 192.0.0.0 192.0.1.255
192.0.3.0/24 192.0.3.0 192.0.3.255
192.0.4.0/22 192.0.4.0 192.0.7.255
192.0.8.0/21 192.0.8.0 192.0.15.255
192.0.16.0/20 192.0.16.0 192.0.31.255
192.0.32.0/19 192.0.32.0 192.0.63.255
192.0.64.0/18 192.0.64.0 192.0.127.255
192.0.128.0/17 192.0.128.0 192.0.255.255
192.1.0.0/16 192.1.0.0 192.1.255.255
192.2.0.0/15 192.2.0.0 192.3.255.255
192.4.0.0/14 192.4.0.0 192.7.255.255
192.8.0.0/13 192.8.0.0 192.15.255.255
192.16.0.0/12 192.16.0.0 192.31.255.255
192.32.0.0/11 192.32.0.0 192.63.255.255
192.64.0.0/10 192.64.0.0 192.127.255.255
192.128.0.0/11 192.128.0.0 192.159.255.255
192.160.0.0/13 192.160.0.0 192.167.255.255
192.169.0.0/16 192.169.0.0 192.169.255.255
192.170.0.0/15 192.170.0.0 192.171.255.255
192.172.0.0/14 192.172.0.0 192.175.255.255
192.176.0.0/12 192.176.0.0 192.191.255.255
192.192.0.0/10 192.192.0.0 192.255.255.255
193.0.0.0/8 193.0.0.0 193.255.255.255
194.0.0.0/7 194.0.0.0 195.255.255.255
196.0.0.0/6 196.0.0.0 199.255.255.255
200.0.0.0/5 200.0.0.0 207.255.255.255
208.0.0.0/4 208.0.0.0 223.255.255.255
224.0.0.0/8 224.0.0.0 224.255.255.255
232.0.0.0/7 232.0.0.0 233.255.255.255
239.0.0.0/9 239.0.0.0 239.127.255.255
239.128.0.0/10 239.128.0.0 239.191.255.255
239.196.0.0/14 239.196.0.0 239.199.255.255
239.200.0.0/13 239.200.0.0 239.207.255.255
239.208.0.0/12 239.208.0.0 239.223.255.255
239.224.0.0/11 239.224.0.0 239.255.255.255
>>> ipv4_addr_space ^ available
IPSet(['10.0.0.0/8', '172.16.0.0/12', '192.0.2.0/24', '192.168.0.0/16', '225.0.0.0/8', '226.0.0.0/7', '228.0.0.0/6', '234.0.0.0/7', '236.0.0.0/7', '238.0.0.0/8', '239.192.0.0/14', '240.0.0.0/4'])
}}}
==Tests on combined IPv4 and IPv6 sets==
{{{
>>> s1 = IPSet(['192.0.2.0', '::192.0.2.0', '192.0.2.2', '::192.0.2.2'])
>>> s2 = IPSet(['192.0.2.2', '::192.0.2.2', '192.0.2.4', '::192.0.2.4'])
IPSets with IPNetworks that need to be merged or split (sometimes multiple times) during various set operations.
IPNetwork('10.0.0.64/30') is the same as IPRange('10.0.0.64', '10.0.0.67')
>>> s3 = IPSet(['0.0.0.1', '10.0.0.64/30', '255.255.255.1'])
>>> s4 = IPSet(['10.0.0.64', '10.0.0.66'])
>>> s4b = IPSet(['10.0.0.64', '10.0.0.66', '111.111.111.111'])
>>> s5 = IPSet(['10.0.0.65', '10.0.0.67'])
>>> s1
IPSet(['192.0.2.0/32', '192.0.2.2/32', '::192.0.2.0/128', '::192.0.2.2/128'])
>>> s2
IPSet(['192.0.2.2/32', '192.0.2.4/32', '::192.0.2.2/128', '::192.0.2.4/128'])
}}}
Set union.
{{{
>>> s1 | s2
IPSet(['192.0.2.0/32', '192.0.2.2/32', '192.0.2.4/32', '::192.0.2.0/128', '::192.0.2.2/128', '::192.0.2.4/128'])
>>> s2 | s1
IPSet(['192.0.2.0/32', '192.0.2.2/32', '192.0.2.4/32', '::192.0.2.0/128', '::192.0.2.2/128', '::192.0.2.4/128'])
}}}
Set intersection.
{{{
>>> s1 & s2
IPSet(['192.0.2.2/32', '::192.0.2.2/128'])
>>> s2 & s1
IPSet(['192.0.2.2/32', '::192.0.2.2/128'])
>>> s3 & s4
IPSet(['10.0.0.64/32', '10.0.0.66/32'])
>>> s4 & s3
IPSet(['10.0.0.64/32', '10.0.0.66/32'])
>>> s3 & s5
IPSet(['10.0.0.65/32', '10.0.0.67/32'])
>>> s5 & s3
IPSet(['10.0.0.65/32', '10.0.0.67/32'])
}}}
Set difference.
{{{
>>> s1 - s2
IPSet(['192.0.2.0/32', '::192.0.2.0/128'])
>>> s2 - s1
IPSet(['192.0.2.4/32', '::192.0.2.4/128'])
>>> s3 - s4
IPSet(['0.0.0.1/32', '10.0.0.65/32', '10.0.0.67/32', '255.255.255.1/32'])
>>> s4 - s3
IPSet([])
>>> s3 - s4b
IPSet(['0.0.0.1/32', '10.0.0.65/32', '10.0.0.67/32', '255.255.255.1/32'])
>>> s3 - s5
IPSet(['0.0.0.1/32', '10.0.0.64/32', '10.0.0.66/32', '255.255.255.1/32'])
>>> s5 - s3
IPSet([])
}}}
Symmetric set difference.
{{{
>>> s1 ^ s2
IPSet(['192.0.2.0/32', '192.0.2.4/32', '::192.0.2.0/128', '::192.0.2.4/128'])
>>> s2 ^ s1
IPSet(['192.0.2.0/32', '192.0.2.4/32', '::192.0.2.0/128', '::192.0.2.4/128'])
>>> IPSet([]) ^ IPSet([])
IPSet([])
>>> IPSet(['0.0.0.1/32']) ^ IPSet([])
IPSet(['0.0.0.1/32'])
>>> IPSet(['0.0.0.1/32']) ^ IPSet(['0.0.0.1/32'])
IPSet([])
>>> s3 ^ s4
IPSet(['0.0.0.1/32', '10.0.0.65/32', '10.0.0.67/32', '255.255.255.1/32'])
>>> s4 ^ s3
IPSet(['0.0.0.1/32', '10.0.0.65/32', '10.0.0.67/32', '255.255.255.1/32'])
>>> s3 ^ s4b
IPSet(['0.0.0.1/32', '10.0.0.65/32', '10.0.0.67/32', '111.111.111.111/32', '255.255.255.1/32'])
>>> s3 ^ s5
IPSet(['0.0.0.1/32', '10.0.0.64/32', '10.0.0.66/32', '255.255.255.1/32'])
>>> s5 ^ s3
IPSet(['0.0.0.1/32', '10.0.0.64/32', '10.0.0.66/32', '255.255.255.1/32'])
}}}
Disjointed sets.
{{{
>>> s1 = IPSet(['192.0.2.0', '192.0.2.1', '192.0.2.2'])
>>> s2 = IPSet(['192.0.2.2', '192.0.2.3', '192.0.2.4'])
>>> s1 & s2
IPSet(['192.0.2.2/32'])
>>> s1.isdisjoint(s2)
False
>>> s1 = IPSet(['192.0.2.0', '192.0.2.1'])
>>> s2 = IPSet(['192.0.2.3', '192.0.2.4'])
>>> s1 & s2
IPSet([])
>>> s1.isdisjoint(s2)
True
}}}
Updating a set.
{{{
>>> s1 = IPSet(['192.0.2.0/25'])
>>> s1
IPSet(['192.0.2.0/25'])
>>> s2 = IPSet(['192.0.2.128/25'])
>>> s2
IPSet(['192.0.2.128/25'])
>>> s1.update(s2)
>>> s1
IPSet(['192.0.2.0/24'])
>>> s1.update(['192.0.0.0/24', '192.0.1.0/24', '192.0.3.0/24'])
>>> s1
IPSet(['192.0.0.0/22'])
>>> s2 = IPSet(['10.0.0.0/16'])
>>> s2.update(IPRange('10.1.0.0', '10.1.255.255'))
>>> s2
IPSet(['10.0.0.0/15'])
>>> s2.clear()
>>> s2
IPSet([])
}}}
Removing IP addresses from an IPSet.
{{{
>>> s1 = IPSet(['0.0.0.0/0'])
>>> s1
IPSet(['0.0.0.0/0'])
>>> s1.remove('255.255.255.255')
>>> s1
IPSet(['0.0.0.0/1', '128.0.0.0/2', ..., '255.255.255.252/31', '255.255.255.254/32'])
>>> list(s1.iter_cidrs())
[IPNetwork('0.0.0.0/1'), IPNetwork('128.0.0.0/2'), ..., IPNetwork('255.255.255.252/31'), IPNetwork('255.255.255.254/32')]
>>> len(list(s1.iter_cidrs()))
32
>>> list(s1.iter_cidrs()) == cidr_exclude('0.0.0.0/0', '255.255.255.255')
True
>>> s1.remove('0.0.0.0')
>>> s1
IPSet(['0.0.0.1/32', '0.0.0.2/31', ..., '255.255.255.252/31', '255.255.255.254/32'])
>>> len(list(s1.iter_cidrs()))
62
}}}
Adding IP address to an IPSet.
{{{
>>> s1.add('255.255.255.255')
>>> s1
IPSet(['0.0.0.1/32', '0.0.0.2/31', ..., '64.0.0.0/2', '128.0.0.0/1'])
>>> list(s1.iter_cidrs())
[IPNetwork('0.0.0.1/32'), IPNetwork('0.0.0.2/31'), ..., IPNetwork('64.0.0.0/2'), IPNetwork('128.0.0.0/1')]
>>> len(list(s1.iter_cidrs()))
32
>>> s1.add('0.0.0.0')
>>> s1
IPSet(['0.0.0.0/0'])
}}}
Converting an IP set to an IP range
{{{
>>> s1 = IPSet(['10.0.0.0/25', '10.0.0.128/25'])
>>> s1.iprange()
IPRange('10.0.0.0', '10.0.0.255')
>>> s1.iscontiguous()
True
>>> s1.remove('10.0.0.16')
>>> s1
IPSet(['10.0.0.0/28', '10.0.0.17/32', '10.0.0.18/31', '10.0.0.20/30', '10.0.0.24/29', '10.0.0.32/27', '10.0.0.64/26', '10.0.0.128/25'])
>>> s1.iscontiguous()
False
>>> s1.iprange()
Traceback (most recent call last):
...
ValueError: IPSet is not contiguous
>>> list(s1.iter_ipranges())
[IPRange('10.0.0.0', '10.0.0.15'), IPRange('10.0.0.17', '10.0.0.255')]
>>> list(IPSet().iter_ipranges())
[]
>>> list(IPSet([IPAddress('10.0.0.1')]).iter_ipranges())
[IPRange('10.0.0.1', '10.0.0.1')]
Adjacent, non-mergable CIDRs must be merged by iter_ipranges().
>>> list(IPSet([IPAddress('10.0.0.1'), IPAddress('10.0.0.2')]).iter_ipranges())
[IPRange('10.0.0.1', '10.0.0.2')]
IPv4 and IPv6 addresses must not be merged.
>>> list(IPSet([IPAddress(1, 4), IPAddress(1, 6)]).iter_ipranges())
[IPRange('0.0.0.1', '0.0.0.1'), IPRange('::1', '::1')]
>>> s2 = IPSet(['0.0.0.0/0'])
>>> s2.iscontiguous()
True
>>> s2.iprange()
IPRange('0.0.0.0', '255.255.255.255')
>>> s3 = IPSet()
>>> s3.iscontiguous()
True
>>> s3.iprange()
>>> s4 = IPSet(IPRange('10.0.0.0', '10.0.0.8'))
>>> s4.iscontiguous()
True
}}}
Pickling of IPSet objects
{{{
>>> import pickle
>>> ip_data = IPSet(['10.0.0.0/16', 'fe80::/64'])
>>> buf = pickle.dumps(ip_data)
>>> ip_data_unpickled = pickle.loads(buf)
>>> ip_data == ip_data_unpickled
True
}}}
Compare IPSet objects
{{{
>>> x = IPSet(['fc00::/2'])
>>> y = IPSet(['fc00::/3'])
>>> x > y
True
>>> x < y
False
>>> x != y
True
}}}
Various exceptions
{{{
>>> s1 = IPSet(['10.0.0.1'])
>>> hash(s1)
Traceback (most recent call last):
TypeError: IP sets are unhashable!
>>> s1.update(42)
Traceback (most recent call last):
TypeError: an iterable was expected!
In the following cases, the exceptions are caught and translated to booleans.
>>> s1 == 42
False
>>> s1 != 42
True
}}}

View File

@@ -0,0 +1,88 @@
=Socket Fallback Module Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr.fbsocket import *
}}}
IPv6 '::' compression algorithm tests.
{{{
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '0:0:0:0:0:0:0:0'))
'::'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '0:0:0:0:0:0:0:A'))
'::a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:0:0:0:0:0:0'))
'a::'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:A:0:0:0:0:0'))
'a:0:a::'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:0:0:0:0:0:A'))
'a::a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '0:A:0:0:0:0:0:A'))
'0:a::a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:A:0:0:0:0:A'))
'a:0:a::a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '0:0:0:A:0:0:0:A'))
'::a:0:0:0:a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '0:0:0:0:A:0:0:A'))
'::a:0:0:a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:0:0:0:A:0:A'))
'a::a:0:a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:0:A:0:0:A:0'))
'a::a:0:0:a:0'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'A:0:A:0:A:0:A:0'))
'a:0:a:0:a:0:a:0'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '0:A:0:A:0:A:0:A'))
'0:a:0:a:0:a:0:a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, '1080:0:0:0:8:800:200C:417A'))
'1080::8:800:200c:417a'
>>> inet_ntop(AF_INET6, inet_pton(AF_INET6, 'FEDC:BA98:7654:3210:FEDC:BA98:7654:3210'))
'fedc:ba98:7654:3210:fedc:ba98:7654:3210'
}}}
IPv4 failure tests
{{{
>>> inet_ntoa(1)
Traceback (most recent call last):
...
TypeError: string type expected, not <class 'int'>
>>> inet_ntoa('\x00')
Traceback (most recent call last):
...
ValueError: invalid length of packed IP address string
}}}
IPv6 failure tests.
{{{
>>> inet_pton(AF_INET6, '::0x07f')
Traceback (most recent call last):
...
ValueError: illegal IP address string '::0x07f'
}}}

View File

@@ -0,0 +1,108 @@
=IP Subnet Tests=
Copyright (c) 2008-2015, David P. D. Moss. All rights reserved.
{{{
>>> from netaddr import *
}}}
Incrementing IP objects.
{{{
>>> ip = IPNetwork('192.0.2.0/28')
>>> for i in range(16):
... str(ip)
... ip += 1
'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'
>>> ip = IPNetwork('2001:470:1f04::/48')
>>> for i in ip.subnet(128):
... print (i)
... break
2001:470:1f04::/128
}}}
IP address and subnet sortability.
{{{
>>> ip_list = []
>>> for subnet in IPNetwork('192.0.2.0/24').subnet(28, 3):
... ip_list.append(subnet)
... ip_list.extend([ip for ip in subnet])
>>> for addr in sorted(ip_list):
... print('%r' % addr)
IPNetwork('192.0.2.0/28')
IPAddress('192.0.2.0')
IPAddress('192.0.2.1')
IPAddress('192.0.2.2')
IPAddress('192.0.2.3')
IPAddress('192.0.2.4')
IPAddress('192.0.2.5')
IPAddress('192.0.2.6')
IPAddress('192.0.2.7')
IPAddress('192.0.2.8')
IPAddress('192.0.2.9')
IPAddress('192.0.2.10')
IPAddress('192.0.2.11')
IPAddress('192.0.2.12')
IPAddress('192.0.2.13')
IPAddress('192.0.2.14')
IPAddress('192.0.2.15')
IPNetwork('192.0.2.16/28')
IPAddress('192.0.2.16')
IPAddress('192.0.2.17')
IPAddress('192.0.2.18')
IPAddress('192.0.2.19')
IPAddress('192.0.2.20')
IPAddress('192.0.2.21')
IPAddress('192.0.2.22')
IPAddress('192.0.2.23')
IPAddress('192.0.2.24')
IPAddress('192.0.2.25')
IPAddress('192.0.2.26')
IPAddress('192.0.2.27')
IPAddress('192.0.2.28')
IPAddress('192.0.2.29')
IPAddress('192.0.2.30')
IPAddress('192.0.2.31')
IPNetwork('192.0.2.32/28')
IPAddress('192.0.2.32')
IPAddress('192.0.2.33')
IPAddress('192.0.2.34')
IPAddress('192.0.2.35')
IPAddress('192.0.2.36')
IPAddress('192.0.2.37')
IPAddress('192.0.2.38')
IPAddress('192.0.2.39')
IPAddress('192.0.2.40')
IPAddress('192.0.2.41')
IPAddress('192.0.2.42')
IPAddress('192.0.2.43')
IPAddress('192.0.2.44')
IPAddress('192.0.2.45')
IPAddress('192.0.2.46')
IPAddress('192.0.2.47')
}}}

File diff suppressed because it is too large Load Diff