summaryrefslogtreecommitdiffstats
path: root/Doc/howto/ipaddress.rst
diff options
context:
space:
mode:
Diffstat (limited to 'Doc/howto/ipaddress.rst')
-rw-r--r--Doc/howto/ipaddress.rst341
1 files changed, 341 insertions, 0 deletions
diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst
new file mode 100644
index 0000000..5e0ff3e
--- /dev/null
+++ b/Doc/howto/ipaddress.rst
@@ -0,0 +1,341 @@
+.. _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)
+