Source code for univention.ipcalc

#!/usr/bin/python3
# SPDX-FileCopyrightText: 2011-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

"""Univention IP Calculator for DNS records (IPv6 edition)."""

from ipaddress import IPv4Interface, IPv6Interface


_Interface = IPv4Interface | IPv6Interface


def _prefixlen(interface: _Interface) -> int:  # PY2 VS PY3
    return interface.prefixlen if hasattr(interface, 'prefixlen') else interface.network.prefixlen  # type: ignore


# IPv4: 4.3.                            2.1.                        IN-ADDR.ARPA
# IPv6: f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.IP6.ARPA
#       \__________ pointer __________/ \__________ reverse __________/
# network: "full network address"
# reverse: dns/reverse_zone.subnet (forward notation)
#          dns/reverse_zone.zoneName (backward notation)
# pointer: dns/ptr_record.address (LDAP: relativeDomainName)


[docs] def calculate_ipv6_reverse(network: _Interface) -> str: """ Return reversed network part of IPv4 network. >>> calculate_ipv6_reverse(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/0')) '0' >>> calculate_ipv6_reverse(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/1')) '0' >>> calculate_ipv6_reverse(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/4')) '0' >>> calculate_ipv6_reverse(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/16')) '0123' >>> calculate_ipv6_reverse(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/124')) '0123:4567:89ab:cdef:0123:4567:89ab:cde' >>> calculate_ipv6_reverse(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/128')) '0123:4567:89ab:cdef:0123:4567:89ab:cde' """ # at least one part must remain for zone entry prefixlen = min(_prefixlen(network) // 4, network.max_prefixlen // 4 - 1) or 1 prefix = network.ip.exploded.replace(':', '')[:prefixlen] return ':'.join([prefix[i:i + 4] for i in range(0, len(prefix), 4)])
[docs] def calculate_ipv4_reverse(network: _Interface) -> str: """ Return reversed network part of IPv4 network. >>> calculate_ipv4_reverse(IPv4Interface(u'1.2.3.4/0')) '1' >>> calculate_ipv4_reverse(IPv4Interface(u'1.2.3.4/8')) '1' >>> calculate_ipv4_reverse(IPv4Interface(u'1.2.3.4/16')) '1.2' >>> calculate_ipv4_reverse(IPv4Interface(u'1.2.3.4/24')) '1.2.3' >>> calculate_ipv4_reverse(IPv4Interface(u'1.2.3.4/32')) '1.2.3' """ # at least one part must remain for zone entry prefixlen = min(_prefixlen(network) // 8, network.max_prefixlen // 8 - 1) or 1 prefix = network.ip.exploded.split('.')[:prefixlen] return '.'.join(prefix)
[docs] def calculate_ipv6_network(network: _Interface) -> str: """ Return network part of IPv6 network. >>> calculate_ipv6_network(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/0')) '' >>> calculate_ipv6_network(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/1')) '' >>> calculate_ipv6_network(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/4')) '0' >>> calculate_ipv6_network(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/16')) '0123' >>> calculate_ipv6_network(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/112')) '0123:4567:89ab:cdef:0123:4567:89ab' >>> calculate_ipv6_network(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/128')) '0123:4567:89ab:cdef:0123:4567:89ab:cdef' """ prefixlen = _prefixlen(network) // 4 prefix = network.ip.exploded.replace(':', '')[:prefixlen] return ':'.join([prefix[i:i + 4] for i in range(0, len(prefix), 4)])
[docs] def calculate_ipv4_network(network: _Interface) -> str: """ Return network part of IPv4 network. >>> calculate_ipv4_network(IPv4Interface(u'1.2.3.4/0')) '' >>> calculate_ipv4_network(IPv4Interface(u'1.2.3.4/1')) '' >>> calculate_ipv4_network(IPv4Interface(u'1.2.3.4/8')) '1' >>> calculate_ipv4_network(IPv4Interface(u'1.2.3.4/24')) '1.2.3' >>> calculate_ipv4_network(IPv4Interface(u'1.2.3.4/32')) '1.2.3.4' """ prefixlen = _prefixlen(network) // 8 prefix = network.ip.exploded.split('.')[:prefixlen] return '.'.join(prefix)
[docs] def calculate_ipv6_pointer(network: _Interface) -> str: """ Return host part of IPv6 network. >>> calculate_ipv6_pointer(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/0')) 'f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1' >>> calculate_ipv6_pointer(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/1')) 'f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1' >>> calculate_ipv6_pointer(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/4')) 'f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1' >>> calculate_ipv6_pointer(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/124')) 'f' >>> calculate_ipv6_pointer(IPv6Interface(u'0123:4567:89ab:cdef:0123:4567:89ab:cdef/128')) 'f' """ prefixlen = min(_prefixlen(network) // 4, network.max_prefixlen // 4 - 1) or 1 suffix = network.ip.exploded.replace(':', '')[prefixlen:] return '.'.join(reversed(suffix))
[docs] def calculate_ipv4_pointer(network: _Interface) -> str: """ Return host part of IPv4 network. >>> calculate_ipv4_pointer(IPv4Interface(u'1.2.3.4/0')) '4.3.2' >>> calculate_ipv4_pointer(IPv4Interface(u'1.2.3.4/1')) '4.3.2' >>> calculate_ipv4_pointer(IPv4Interface(u'1.2.3.4/8')) '4.3.2' >>> calculate_ipv4_pointer(IPv4Interface(u'1.2.3.4/24')) '4' >>> calculate_ipv4_pointer(IPv4Interface(u'1.2.3.4/32')) '4' """ prefixlen = min(_prefixlen(network) // 8, network.max_prefixlen // 8 - 1) or 1 suffix = network.ip.exploded.split('.')[prefixlen:] return '.'.join(reversed(suffix))