1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2018 F5 Networks Inc.
4# GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6from __future__ import absolute_import, division, print_function
7__metaclass__ = type
8
9from ansible.module_utils.network.common.utils import validate_ip_address
10
11try:
12    # Ansible 2.6 and later
13    from ansible.module_utils.network.common.utils import validate_ip_v6_address
14except ImportError:
15    import socket
16
17    # Ansible 2.5 and earlier
18    #
19    # This method is simply backported from the 2.6 source code.
20    def validate_ip_v6_address(address):
21        try:
22            socket.inet_pton(socket.AF_INET6, address)
23        except socket.error:
24            return False
25        return True
26
27
28try:
29    from library.module_utils.compat.ipaddress import ip_interface
30    from library.module_utils.compat.ipaddress import ip_network
31except ImportError:
32    from ansible.module_utils.compat.ipaddress import ip_interface
33    from ansible.module_utils.compat.ipaddress import ip_network
34
35
36def is_valid_ip(addr, type='all'):
37    if type in ['all', 'ipv4']:
38        if validate_ip_address(addr):
39            return True
40    if type in ['all', 'ipv6']:
41        if validate_ip_v6_address(addr):
42            return True
43    return False
44
45
46def ipv6_netmask_to_cidr(mask):
47    """converts an IPv6 netmask to CIDR form
48
49    According to the link below, CIDR is the only official way to specify
50    a subset of IPv6. With that said, the same link provides a way to
51    loosely convert an netmask to a CIDR.
52
53    Arguments:
54      mask (string): The IPv6 netmask to convert to CIDR
55
56    Returns:
57      int: The CIDR representation of the netmask
58
59    References:
60      https://stackoverflow.com/a/33533007
61      http://v6decode.com/
62    """
63    bit_masks = [
64        0, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800,
65        0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0,
66        0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe,
67        0xffff
68    ]
69    count = 0
70    try:
71        for w in mask.split(':'):
72            if not w or int(w, 16) == 0:
73                break
74            count += bit_masks.index(int(w, 16))
75        return count
76    except Exception:
77        return -1
78
79
80def is_valid_ip_network(address):
81    try:
82        ip_network(u'{0}'.format(address))
83        return True
84    except ValueError:
85        return False
86
87
88def is_valid_ip_interface(address):
89    try:
90        ip_interface(u'{0}'.format(address))
91        return True
92    except ValueError:
93        return False
94
95
96def get_netmask(address):
97    addr = ip_network(u'{0}'.format(address))
98    netmask = addr.netmask.compressed
99    return netmask
100
101
102def compress_address(address):
103    addr = ip_network(u'{0}'.format(address))
104    result = addr.compressed.split('/')[0]
105    return result
106