VirtualMailManager/network.py
author martin f. krafft <madduck@madduck.net>
Tue, 10 Apr 2012 22:56:30 +0200
branchv0.6.x
changeset 514 d863a44a6353
parent 421 ff2a61e155db
child 568 14abdd04ddf5
permissions -rw-r--r--
Make PL/pgSQL function feed back identity for mailboxes/relocated when there are catchall destinations. Without catchall aliases, if no virtual_alias matches, the query can just return NULL and Postfix will later check mailboxes/relocated for the address to rewrite. However, since virtual aliases are handled long before mailboxes/relocated, a catchall alias would also catch mail to mailboxes and relocated addresses, which we do not want. The way to tell postfix to keep delivering is for the virtual alias map to return the search key itself (identity function). This patch changes the postfix_virtual_alias_maps Pl/pgSQL function to do exactly that, but only if there are catchall destinations defined for the domain in question — otherwise it returns NULL when no match is found.
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 -*-
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
     2
# Copyright (c) 2011, Pascal Volk
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
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    13
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    14
class NetInfo(object):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    15
    """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
    16
    __slots__ = ('_addr', '_prefix', '_bits_max', '_family', '_nw_addr')
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    17
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    18
    def __init__(self, nw_address):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    19
        """Creates a new `NetInfo` instance.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    20
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    21
        Argument:
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
        `nw_address` : basestring
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    24
          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
    25
          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
    26
          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
    27
          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
    28
        """
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    29
        self._addr = None
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    30
        self._prefix = 0
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    31
        self._bits_max = 0
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    32
        self._family = 0
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    33
        self._nw_addr = nw_address
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    34
        self._parse_net_range()
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    35
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    36
    def __hash__(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    37
        return hash((self._addr, self._family, self._prefix))
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    38
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    39
    def __repr__(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    40
        return "NetInfo('%s')" % self._nw_addr
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    41
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    42
    def _parse_net_range(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    43
        """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
    44
        to the class attributes.
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    45
        `"""
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    46
        sep = '/'
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    47
        if self._nw_addr.count(sep):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    48
            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
    49
            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
    50
        else:
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(self._nw_addr)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    52
        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
    53
        if self._prefix is 0:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    54
            self._prefix = self._bits_max
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    55
        else:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    56
            try:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    57
                self._prefix = int(self._prefix)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    58
            except ValueError:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    59
                raise ValueError('Invalid prefix length: %r' % self._prefix)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    60
        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
    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
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    63
    @property
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    64
    def family(self):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    65
        """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
    66
        return self._family
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    67
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    68
    def address_in_net(self, ip_address):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    69
        """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
    70
        family, address = get_ip_addr_info(ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    71
        if family != self._family:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    72
            return False
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    73
        return address >> self._bits_max - self._prefix == \
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    74
               self._addr >> self._bits_max - self._prefix
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    75
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    76
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    77
def get_ip_addr_info(ip_address):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    78
    """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
    79
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    80
    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
    81
    `(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
    82
    `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
    83
    """
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    84
    if not isinstance(ip_address, basestring) or not ip_address:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    85
        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
    86
    if not ip_address.count(':'):
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    87
        family = socket.AF_INET
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    88
        try:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    89
            address = socket.inet_aton(ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    90
        except socket.error:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    91
            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
    92
    elif not socket.has_ipv6:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    93
        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
    94
    else:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    95
        family = socket.AF_INET6
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    96
        try:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    97
            address = socket.inet_pton(family, ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    98
        except socket.error:
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
    99
            raise ValueError('Not a valid IPv6 address: %r' % ip_address)
ff2a61e155db VMM/network: Added new module network.
Pascal Volk <neverseen@users.sourceforge.net>
parents:
diff changeset
   100
    return (family, long(address.encode('hex'), 16))