Free Course

Dec 7th

Free Course

Dec 7th

Using Python's ipaddress library

By Kirk Byers
2015-10-08

Python has numerous libraries pertaining to IP addresses. In 2012, a standardized IP address library was proposed (PEP3144); this PEP has been implemented in the ipaddress Library which is integrated into Python as of Python 3.3 and has been back-ported to Python 2.6, 2.7, and 3.2.

What follows are some useful things you can do with the ipaddress Library.


First, you can create both IPv4Address and IPv6Address objects.

>>> import ipaddress
>>> alt_ip = ipaddress.ip_address(u'10.220.7.193')
>>> alt_ip
IPv4Address(u'10.220.7.193')
>>> str(alt_ip)
'10.220.7.193'

>>> myipv6 = ipaddress.ip_address(u'ff05::1:3')
>>> str(myipv6)
'ff05::1:3'
>>> myipv6.exploded
u'ff05:0000:0000:0000:0000:0000:0001:0003'
>>> myipv6
IPv6Address(u'ff05::1:3') 

The ip_address() call is a factory function that determines the proper class to use based on the input you provide. You can also directly create an object using ipaddress.IPv4Address().

Note, when creating IPv4Address/IPv6Address objects, a unicode string is required.


There really isn't all that much you can do with straight IPv4Address/IPv6Address objects. Of more value are the IPv4Network and IPv6Network classes:

>>> my_net = ipaddress.ip_network(u'10.220.192.192/29')
>>> my_net
IPv4Network(u'10.220.192.192/29')

>>> ipv6_net = ipaddress.ip_network(u'fe80::0202:b3ff:fe1e:8329/64', strict=False)
>>> ipv6_net
IPv6Network(u'fe80::/64') 

By default, both the IPv4Network class and the IPv6Network class require the host portion of the address to be all zeroes. You can change this behavior by setting the 'strict=False' flag as I did with above IPv6 address. The 'strict=False' flag will cause the class to accept the network, but it will still zero out the host component. If you want to support both a network component and a host component, see the IPv4Interface/IPv6Interface classes (described below).

There are several alternate forms that you can use to create an IPv4Network object:

>>> my_net = ipaddress.ip_network(u'10.220.192.192/255.255.255.248')
>>> my_net
IPv4Network(u'10.220.192.192/29')
>>> my_net = ipaddress.ip_network(u'10.220.192.192/0.0.0.7')
>>> my_net
IPv4Network(u'10.220.192.192/29') 

There are also several useful attributes of IPv4Network objects:

>>> my_net.network_address
IPv4Address(u'10.220.192.192')
>>> my_net.broadcast_address
IPv4Address(u'10.220.192.199')

>>> my_net.hostmask
IPv4Address(u'0.0.0.7')
>>> my_net.netmask
IPv4Address(u'255.255.255.248')

>>> my_net.with_netmask
u'10.220.192.192/255.255.255.248'
>>> my_net.with_hostmask
u'10.220.192.192/0.0.0.7'

>>> my_net.with_prefixlen
u'10.220.192.192/29'
>>> my_net.prefixlen
29

>>> my_net.num_addresses
8 

You can iterate over the hosts of a network (this excludes the network number and the broadcast address):

>>> for test_ip in my_net.hosts():
...      print test_ip
... 
10.220.192.193
10.220.192.194
10.220.192.195
10.220.192.196
10.220.192.197
10.220.192.198 

You can find the subnets of a given network (fixed-length subnets):

>>> my_net = ipaddress.ip_network(u'10.220.2.0/24')
>>> my_net
IPv4Network(u'10.220.2.0/24')
>>> for subnet in my_net.subnets(new_prefix=27):
...       print subnet
... 
10.220.2.0/27
10.220.2.32/27
10.220.2.64/27
10.220.2.96/27
10.220.2.128/27
10.220.2.160/27
10.220.2.192/27
10.220.2.224/27 

You can also find a supernet of a given network:

>>> ipaddress.ip_network(u'10.220.167.0/24').supernet(new_prefix=20)
IPv4Network(u'10.220.160.0/20') 

Finally, the ipaddress library includes both IPv4Interface and IPv6Interface classes. These classes allow both a host component and a network component in one object:

>>> my_ip = ipaddress.ip_interface(u'10.220.192.194/29')
>>> my_ip
IPv4Interface(u'10.220.192.194/29')

>>> my_ipv6 = ipaddress.ip_interface(u'fe80::0202:b3ff:fe1e:8329/64')
>>> my_ipv6
IPv6Interface(u'fe80::202:b3ff:fe1e:8329/64') 

From this you can obtain both the IP address and the IP network:

>>> my_ip.ip
IPv4Address(u'10.220.192.194')
>>> my_ip.network
IPv4Network(u'10.220.192.192/29') 


The ipaddress library (while by no means earth-shattering) has some useful features that could be used for ACL construction, ping sweeping, input validation, network-subnet determination, etc. Why reinvent the wheel when a good enough one already exists?

Follow-up: Jeremy Schulman (@nwkautomaniac on Twitter) responded to this article with example code that he wrote demonstrating how to dynamically allocate interface IP addresses given a base network using the ipaddress Library.


If you want to learn more about network automation, Python, and Ansible—then join my email-list. I also periodically run a free Python for Network Engineers email course which you can sign-up for here.

router image

Kirk Byers
CCIE #6243 emeritus
Twitter: @kirkbyers

Using Python's ipaddress library

By Kirk Byers
2015-10-08

Python has numerous libraries pertaining to IP addresses. In 2012, a standardized IP address library was proposed (PEP3144); this PEP has been implemented in the ipaddress Library which is integrated into Python as of Python 3.3 and has been back-ported to Python 2.6, 2.7, and 3.2.

What follows are some useful things you can do with the ipaddress Library.


First, you can create both IPv4Address and IPv6Address objects.

>>> import ipaddress
>>> alt_ip = ipaddress.ip_address(u'10.220.7.193')
>>> alt_ip
IPv4Address(u'10.220.7.193')
>>> str(alt_ip)
'10.220.7.193'

>>> myipv6 = ipaddress.ip_address(u'ff05::1:3')
>>> str(myipv6)
'ff05::1:3'
>>> myipv6.exploded
u'ff05:0000:0000:0000:0000:0000:0001:0003'
>>> myipv6
IPv6Address(u'ff05::1:3') 

The ip_address() call is a factory function that determines the proper class to use based on the input you provide. You can also directly create an object using ipaddress.IPv4Address().

Note, when creating IPv4Address/IPv6Address objects, a unicode string is required.


There really isn't all that much you can do with straight IPv4Address/IPv6Address objects. Of more value are the IPv4Network and IPv6Network classes:

>>> my_net = ipaddress.ip_network(u'10.220.192.192/29')
>>> my_net
IPv4Network(u'10.220.192.192/29')

>>> ipv6_net = ipaddress.ip_network(u'fe80::0202:b3ff:fe1e:8329/64', strict=False)
>>> ipv6_net
IPv6Network(u'fe80::/64') 

By default, both the IPv4Network class and the IPv6Network class require the host portion of the address to be all zeroes. You can change this behavior by setting the 'strict=False' flag as I did with above IPv6 address. The 'strict=False' flag will cause the class to accept the network, but it will still zero out the host component. If you want to support both a network component and a host component, see the IPv4Interface/IPv6Interface classes (described below).

There are several alternate forms that you can use to create an IPv4Network object:

>>> my_net = ipaddress.ip_network(u'10.220.192.192/255.255.255.248')
>>> my_net
IPv4Network(u'10.220.192.192/29')
>>> my_net = ipaddress.ip_network(u'10.220.192.192/0.0.0.7')
>>> my_net
IPv4Network(u'10.220.192.192/29') 

There are also several useful attributes of IPv4Network objects:

>>> my_net.network_address
IPv4Address(u'10.220.192.192')
>>> my_net.broadcast_address
IPv4Address(u'10.220.192.199')

>>> my_net.hostmask
IPv4Address(u'0.0.0.7')
>>> my_net.netmask
IPv4Address(u'255.255.255.248')

>>> my_net.with_netmask
u'10.220.192.192/255.255.255.248'
>>> my_net.with_hostmask
u'10.220.192.192/0.0.0.7'

>>> my_net.with_prefixlen
u'10.220.192.192/29'
>>> my_net.prefixlen
29

>>> my_net.num_addresses
8 

You can iterate over the hosts of a network (this excludes the network number and the broadcast address):

>>> for test_ip in my_net.hosts():
...      print test_ip
... 
10.220.192.193
10.220.192.194
10.220.192.195
10.220.192.196
10.220.192.197
10.220.192.198 

You can find the subnets of a given network (fixed-length subnets):

>>> my_net = ipaddress.ip_network(u'10.220.2.0/24')
>>> my_net
IPv4Network(u'10.220.2.0/24')
>>> for subnet in my_net.subnets(new_prefix=27):
...       print subnet
... 
10.220.2.0/27
10.220.2.32/27
10.220.2.64/27
10.220.2.96/27
10.220.2.128/27
10.220.2.160/27
10.220.2.192/27
10.220.2.224/27 

You can also find a supernet of a given network:

>>> ipaddress.ip_network(u'10.220.167.0/24').supernet(new_prefix=20)
IPv4Network(u'10.220.160.0/20') 

Finally, the ipaddress library includes both IPv4Interface and IPv6Interface classes. These classes allow both a host component and a network component in one object:

>>> my_ip = ipaddress.ip_interface(u'10.220.192.194/29')
>>> my_ip
IPv4Interface(u'10.220.192.194/29')

>>> my_ipv6 = ipaddress.ip_interface(u'fe80::0202:b3ff:fe1e:8329/64')
>>> my_ipv6
IPv6Interface(u'fe80::202:b3ff:fe1e:8329/64') 

From this you can obtain both the IP address and the IP network:

>>> my_ip.ip
IPv4Address(u'10.220.192.194')
>>> my_ip.network
IPv4Network(u'10.220.192.192/29') 


The ipaddress library (while by no means earth-shattering) has some useful features that could be used for ACL construction, ping sweeping, input validation, network-subnet determination, etc. Why reinvent the wheel when a good enough one already exists?

Follow-up: Jeremy Schulman (@nwkautomaniac on Twitter) responded to this article with example code that he wrote demonstrating how to dynamically allocate interface IP addresses given a base network using the ipaddress Library.


If you want to learn more about network automation, Python, and Ansible—then join my email-list. I also periodically run a free Python for Network Engineers email course which you can sign-up for here.

router image

Kirk Byers
CCIE #6243 emeritus
Twitter: @kirkbyers