VirtualMailManager/network.py
author Pascal Volk <user@localhost.localdomain.org>
Sat, 08 Jun 2013 15:12:16 +0000
branchv0.7.x
changeset 698 18a528d44055
parent 676 2bc11dada296
child 711 2a75058fc064
permissions -rw-r--r--
merged changes from default(61aaa7a98ec0).
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
421
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     1
# -*- coding: UTF-8 -*-
675
d24f094d1cb5 Updated copyright notices to include the year 2013.
Pascal Volk <user@localhost.localdomain.org>
parents: 568
diff changeset
     2
# Copyright (c) 2011 - 2013, Pascal Volk
421
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     3
# See COPYING for distribution information.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     4
"""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     5
    VirtualMailManager.network
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     6
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     7
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     8
    Network/IP address related class and function
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     9
"""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    10
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    11
import socket
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    12
672
d3fd9bb0a5ea VMM/network: Post-2to3 fix. s/addr.encode('hex')/b2a_hex(addr).
Pascal Volk <user@localhost.localdomain.org>
parents: 643
diff changeset
    13
from binascii import b2a_hex
d3fd9bb0a5ea VMM/network: Post-2to3 fix. s/addr.encode('hex')/b2a_hex(addr).
Pascal Volk <user@localhost.localdomain.org>
parents: 643
diff changeset
    14
421
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    15
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    16
class NetInfo(object):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    17
    """Simple class for CIDR network addresses an IP addresses."""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    18
    __slots__ = ('_addr', '_prefix', '_bits_max', '_family', '_nw_addr')
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    19
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    20
    def __init__(self, nw_address):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    21
        """Creates a new `NetInfo` instance.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    22
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    23
        Argument:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    24
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    25
        `nw_address` : basestring
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    26
          string representation of an IPv4/IPv6 address or network address.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    27
          E.g. 192.0.2.13, 192.0.2.0/24, 2001:db8::/32 or ::1
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    28
          When the address has no netmask the prefix length will be set to
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    29
          32 for IPv4 addresses and 128 for IPv6 addresses.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    30
        """
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    31
        self._addr = None
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    32
        self._prefix = 0
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    33
        self._bits_max = 0
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    34
        self._family = 0
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    35
        self._nw_addr = nw_address
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    36
        self._parse_net_range()
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    37
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    38
    def __hash__(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    39
        return hash((self._addr, self._family, self._prefix))
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    40
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    41
    def __repr__(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    42
        return "NetInfo('%s')" % self._nw_addr
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    43
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    44
    def _parse_net_range(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    45
        """Parse the network range of `self._nw_addr and assign values
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    46
        to the class attributes.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    47
        `"""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    48
        sep = '/'
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    49
        if self._nw_addr.count(sep):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    50
            ip_address, sep, self._prefix = self._nw_addr.partition(sep)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    51
            self._family, self._addr = get_ip_addr_info(ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    52
        else:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    53
            self._family, self._addr = get_ip_addr_info(self._nw_addr)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    54
        self._bits_max = (128, 32)[self._family is socket.AF_INET]
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    55
        if self._prefix is 0:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    56
            self._prefix = self._bits_max
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    57
        else:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    58
            try:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    59
                self._prefix = int(self._prefix)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    60
            except ValueError:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    61
                raise ValueError('Invalid prefix length: %r' % self._prefix)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    62
        if self._prefix > self._bits_max or self._prefix < 0:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    63
            raise ValueError('Invalid prefix length: %r' % self._prefix)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    64
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    65
    @property
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    66
    def family(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    67
        """Address family: `socket.AF_INET` or `socket.AF_INET6`"""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    68
        return self._family
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    69
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    70
    def address_in_net(self, ip_address):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    71
        """Checks if the `ip_address` belongs to the same subnet."""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    72
        family, address = get_ip_addr_info(ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    73
        if family != self._family:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    74
            return False
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    75
        return address >> self._bits_max - self._prefix == \
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    76
               self._addr >> self._bits_max - self._prefix
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    77
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    78
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    79
def get_ip_addr_info(ip_address):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    80
    """Checks if the string `ip_address` is a valid IPv4 or IPv6 address.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    81
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    82
    When the `ip_address` could be validated successfully a tuple
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    83
    `(address_family, address_as_long)` will be returned. The
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    84
    `address_family`will be either `socket.AF_INET` or `socket.AF_INET6`.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    85
    """
643
df1e3b67882a Ran 2to3 from Python 3.2.3.
Pascal Volk <user@localhost.localdomain.org>
parents: 568
diff changeset
    86
    if not isinstance(ip_address, str) or not ip_address:
421
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    87
        raise TypeError('ip_address must be a non empty string.')
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    88
    if not ip_address.count(':'):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    89
        family = socket.AF_INET
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    90
        try:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    91
            address = socket.inet_aton(ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    92
        except socket.error:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    93
            raise ValueError('Not a valid IPv4 address: %r' % ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    94
    elif not socket.has_ipv6:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    95
        raise ValueError('Unsupported IP address (IPv6): %r' % ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    96
    else:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    97
        family = socket.AF_INET6
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    98
        try:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    99
            address = socket.inet_pton(family, ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
   100
        except socket.error:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
   101
            raise ValueError('Not a valid IPv6 address: %r' % ip_address)
672
d3fd9bb0a5ea VMM/network: Post-2to3 fix. s/addr.encode('hex')/b2a_hex(addr).
Pascal Volk <user@localhost.localdomain.org>
parents: 643
diff changeset
   102
    return (family, int(b2a_hex(address), 16))