| .. _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 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: |
| |
| .. testsetup:: |
| >>> import ipaddress |
| |
| :: |
| |
| >>> 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) |
| |