| .. testsetup:: | |
| import ipaddress | |
| .. _ipaddress-howto: | |
| *************************************** | |
| An introduction to the ipaddress module | |
| *************************************** | |
| :author: Peter Moody | |
| :author: Nick Coghlan | |
| .. topic:: Overview | |
| This document aims to provide a gentle introduction to the | |
| :mod:`ipaddress` module. It is aimed primarily at users that aren't | |
| already familiar with IP networking terminology, but may also be useful | |
| to network engineers wanting an overview of how :mod:`ipaddress` | |
| represents IP network addressing concepts. | |
| Creating Address/Network/Interface objects | |
| ========================================== | |
| Since :mod:`ipaddress` is a module for inspecting and manipulating IP addresses, | |
| the first thing you'll want to do is create some objects. You can use | |
| :mod:`ipaddress` to create objects from strings and integers. | |
| A Note on IP Versions | |
| --------------------- | |
| For readers that aren't particularly familiar with IP addressing, it's | |
| important to know that the Internet Protocol (IP) is currently in the process | |
| of moving from version 4 of the protocol to version 6. This transition is | |
| occurring largely because version 4 of the protocol doesn't provide enough | |
| addresses to handle the needs of the whole world, especially given the | |
| increasing number of devices with direct connections to the internet. | |
| Explaining the details of the differences between the two versions of the | |
| protocol is beyond the scope of this introduction, but readers need to at | |
| least be aware that these two versions exist, and it will sometimes be | |
| necessary to force the use of one version or the other. | |
| IP Host Addresses | |
| ----------------- | |
| Addresses, often referred to as "host addresses" are the most basic unit | |
| when working with IP addressing. The simplest way to create addresses is | |
| to use the :func:`ipaddress.ip_address` factory function, which automatically | |
| determines whether to create an IPv4 or IPv6 address based on the passed in | |
| value: | |
| >>> ipaddress.ip_address('192.0.2.1') | |
| IPv4Address('192.0.2.1') | |
| >>> ipaddress.ip_address('2001:DB8::1') | |
| IPv6Address('2001:db8::1') | |
| Addresses can also be created directly from integers. Values that will | |
| fit within 32 bits are assumed to be IPv4 addresses:: | |
| >>> ipaddress.ip_address(3221225985) | |
| IPv4Address('192.0.2.1') | |
| >>> ipaddress.ip_address(42540766411282592856903984951653826561) | |
| IPv6Address('2001:db8::1') | |
| To force the use of IPv4 or IPv6 addresses, the relevant classes can be | |
| invoked directly. This is particularly useful to force creation of IPv6 | |
| addresses for small integers:: | |
| >>> ipaddress.ip_address(1) | |
| IPv4Address('0.0.0.1') | |
| >>> ipaddress.IPv4Address(1) | |
| IPv4Address('0.0.0.1') | |
| >>> ipaddress.IPv6Address(1) | |
| IPv6Address('::1') | |
| Defining Networks | |
| ----------------- | |
| Host addresses are usually grouped together into IP networks, so | |
| :mod:`ipaddress` provides a way to create, inspect and manipulate network | |
| definitions. IP network objects are constructed from strings that define the | |
| range of host addresses that are part of that network. The simplest form | |
| for that information is a "network address/network prefix" pair, where the | |
| prefix defines the number of leading bits that are compared to determine | |
| whether or not an address is part of the network and the network address | |
| defines the expected value of those bits. | |
| As for addresses, a factory function is provided that determines the correct | |
| IP version automatically:: | |
| >>> ipaddress.ip_network('192.0.2.0/24') | |
| IPv4Network('192.0.2.0/24') | |
| >>> ipaddress.ip_network('2001:db8::0/96') | |
| IPv6Network('2001:db8::/96') | |
| Network objects cannot have any host bits set. The practical effect of this | |
| is that ``192.0.2.1/24`` does not describe a network. Such definitions are | |
| referred to as interface objects since the ip-on-a-network notation is | |
| commonly used to describe network interfaces of a computer on a given network | |
| and are described further in the next section. | |
| By default, attempting to create a network object with host bits set will | |
| result in :exc:`ValueError` being raised. To request that the | |
| additional bits instead be coerced to zero, the flag ``strict=False`` can | |
| be passed to the constructor:: | |
| >>> ipaddress.ip_network('192.0.2.1/24') | |
| Traceback (most recent call last): | |
| ... | |
| ValueError: 192.0.2.1/24 has host bits set | |
| >>> ipaddress.ip_network('192.0.2.1/24', strict=False) | |
| IPv4Network('192.0.2.0/24') | |
| While the string form offers significantly more flexibility, networks can | |
| also be defined with integers, just like host addresses. In this case, the | |
| network is considered to contain only the single address identified by the | |
| integer, so the network prefix includes the entire network address:: | |
| >>> ipaddress.ip_network(3221225984) | |
| IPv4Network('192.0.2.0/32') | |
| >>> ipaddress.ip_network(42540766411282592856903984951653826560) | |
| IPv6Network('2001:db8::/128') | |
| As with addresses, creation of a particular kind of network can be forced | |
| by calling the class constructor directly instead of using the factory | |
| function. | |
| Host Interfaces | |
| --------------- | |
| As mentioned just above, if you need to describe an address on a particular | |
| network, neither the address nor the network classes are sufficient. | |
| Notation like ``192.0.2.1/24`` is commonly used by network engineers and the | |
| people who write tools for firewalls and routers as shorthand for "the host | |
| ``192.0.2.1`` on the network ``192.0.2.0/24``", Accordingly, :mod:`ipaddress` | |
| provides a set of hybrid classes that associate an address with a particular | |
| network. The interface for creation is identical to that for defining network | |
| objects, except that the address portion isn't constrained to being a network | |
| address. | |
| >>> ipaddress.ip_interface('192.0.2.1/24') | |
| IPv4Interface('192.0.2.1/24') | |
| >>> ipaddress.ip_interface('2001:db8::1/96') | |
| IPv6Interface('2001:db8::1/96') | |
| Integer inputs are accepted (as with networks), and use of a particular IP | |
| version can be forced by calling the relevant constructor directly. | |
| Inspecting Address/Network/Interface Objects | |
| ============================================ | |
| You've gone to the trouble of creating an IPv(4|6)(Address|Network|Interface) | |
| object, so you probably want to get information about it. :mod:`ipaddress` | |
| tries to make doing this easy and intuitive. | |
| Extracting the IP version:: | |
| >>> addr4 = ipaddress.ip_address('192.0.2.1') | |
| >>> addr6 = ipaddress.ip_address('2001:db8::1') | |
| >>> addr6.version | |
| 6 | |
| >>> addr4.version | |
| 4 | |
| Obtaining the network from an interface:: | |
| >>> host4 = ipaddress.ip_interface('192.0.2.1/24') | |
| >>> host4.network | |
| IPv4Network('192.0.2.0/24') | |
| >>> host6 = ipaddress.ip_interface('2001:db8::1/96') | |
| >>> host6.network | |
| IPv6Network('2001:db8::/96') | |
| Finding out how many individual addresses are in a network:: | |
| >>> net4 = ipaddress.ip_network('192.0.2.0/24') | |
| >>> net4.num_addresses | |
| 256 | |
| >>> net6 = ipaddress.ip_network('2001:db8::0/96') | |
| >>> net6.num_addresses | |
| 4294967296 | |
| Iterating through the "usable" addresses on a network:: | |
| >>> net4 = ipaddress.ip_network('192.0.2.0/24') | |
| >>> for x in net4.hosts(): | |
| ... print(x) # doctest: +ELLIPSIS | |
| 192.0.2.1 | |
| 192.0.2.2 | |
| 192.0.2.3 | |
| 192.0.2.4 | |
| ... | |
| 192.0.2.252 | |
| 192.0.2.253 | |
| 192.0.2.254 | |
| Obtaining the netmask (i.e. set bits corresponding to the network prefix) or | |
| the hostmask (any bits that are not part of the netmask): | |
| >>> net4 = ipaddress.ip_network('192.0.2.0/24') | |
| >>> net4.netmask | |
| IPv4Address('255.255.255.0') | |
| >>> net4.hostmask | |
| IPv4Address('0.0.0.255') | |
| >>> net6 = ipaddress.ip_network('2001:db8::0/96') | |
| >>> net6.netmask | |
| IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::') | |
| >>> net6.hostmask | |
| IPv6Address('::ffff:ffff') | |
| Exploding or compressing the address:: | |
| >>> addr6.exploded | |
| '2001:0db8:0000:0000:0000:0000:0000:0001' | |
| >>> addr6.compressed | |
| '2001:db8::1' | |
| >>> net6.exploded | |
| '2001:0db8:0000:0000:0000:0000:0000:0000/96' | |
| >>> net6.compressed | |
| '2001:db8::/96' | |
| While IPv4 doesn't support explosion or compression, the associated objects | |
| still provide the relevant properties so that version neutral code can | |
| easily ensure the most concise or most verbose form is used for IPv6 | |
| addresses while still correctly handling IPv4 addresses. | |
| Networks as lists of Addresses | |
| ============================== | |
| It's sometimes useful to treat networks as lists. This means it is possible | |
| to index them like this:: | |
| >>> net4[1] | |
| IPv4Address('192.0.2.1') | |
| >>> net4[-1] | |
| IPv4Address('192.0.2.255') | |
| >>> net6[1] | |
| IPv6Address('2001:db8::1') | |
| >>> net6[-1] | |
| IPv6Address('2001:db8::ffff:ffff') | |
| It also means that network objects lend themselves to using the list | |
| membership test syntax like this:: | |
| if address in network: | |
| # do something | |
| Containment testing is done efficiently based on the network prefix:: | |
| >>> addr4 = ipaddress.ip_address('192.0.2.1') | |
| >>> addr4 in ipaddress.ip_network('192.0.2.0/24') | |
| True | |
| >>> addr4 in ipaddress.ip_network('192.0.3.0/24') | |
| False | |
| Comparisons | |
| =========== | |
| :mod:`ipaddress` provides some simple, hopefully intuitive ways to compare | |
| objects, where it makes sense:: | |
| >>> ipaddress.ip_address('192.0.2.1') < ipaddress.ip_address('192.0.2.2') | |
| True | |
| A :exc:`TypeError` exception is raised if you try to compare objects of | |
| different versions or different types. | |
| Using IP Addresses with other modules | |
| ===================================== | |
| Other modules that use IP addresses (such as :mod:`socket`) usually won't | |
| accept objects from this module directly. Instead, they must be coerced to | |
| an integer or string that the other module will accept:: | |
| >>> addr4 = ipaddress.ip_address('192.0.2.1') | |
| >>> str(addr4) | |
| '192.0.2.1' | |
| >>> int(addr4) | |
| 3221225985 | |
| Getting more detail when instance creation fails | |
| ================================================ | |
| When creating address/network/interface objects using the version-agnostic | |
| factory functions, any errors will be reported as :exc:`ValueError` with | |
| a generic error message that simply says the passed in value was not | |
| recognized as an object of that type. The lack of a specific error is | |
| because it's necessary to know whether the value is *supposed* to be IPv4 | |
| or IPv6 in order to provide more detail on why it has been rejected. | |
| To support use cases where it is useful to have access to this additional | |
| detail, the individual class constructors actually raise the | |
| :exc:`ValueError` subclasses :exc:`ipaddress.AddressValueError` and | |
| :exc:`ipaddress.NetmaskValueError` to indicate exactly which part of | |
| the definition failed to parse correctly. | |
| The error messages are significantly more detailed when using the | |
| class constructors directly. For example:: | |
| >>> ipaddress.ip_address("192.168.0.256") | |
| Traceback (most recent call last): | |
| ... | |
| ValueError: '192.168.0.256' does not appear to be an IPv4 or IPv6 address | |
| >>> ipaddress.IPv4Address("192.168.0.256") | |
| Traceback (most recent call last): | |
| ... | |
| ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.0.256' | |
| >>> ipaddress.ip_network("192.168.0.1/64") | |
| Traceback (most recent call last): | |
| ... | |
| ValueError: '192.168.0.1/64' does not appear to be an IPv4 or IPv6 network | |
| >>> ipaddress.IPv4Network("192.168.0.1/64") | |
| Traceback (most recent call last): | |
| ... | |
| ipaddress.NetmaskValueError: '64' is not a valid netmask | |
| However, both of the module specific exceptions have :exc:`ValueError` as their | |
| parent class, so if you're not concerned with the particular type of error, | |
| you can still write code like the following:: | |
| try: | |
| network = ipaddress.IPv4Network(address) | |
| except ValueError: | |
| print('address/netmask is invalid for IPv4:', address) | |