Exemple #1
0
#!/usr/bin/env python3.8

import os
from pathlib import Path
from ipaddress import IPv4Network
from urllib.request import urlretrieve

import pytest

from ips import (ServiceIPRange, parse_ipv4_service_ranges,
                 get_aws_service_range)

URL = "https://bites-data.s3.us-east-2.amazonaws.com/ip-ranges.json"
TMP = os.getenv("TMP", "/tmp")
PATH = Path(TMP, "ip-ranges.json")
IP = IPv4Network('192.0.2.8/29')


@pytest.fixture(scope='module')
def json_file():
    """Import data into tmp folder"""
    urlretrieve(URL, PATH)
    return PATH


# write your pytest code ...
def test_dataclass():
    sipr = ServiceIPRange("TestService", "TestRegion", IP)
    assert str(
        sipr
    ) == f"{IP} is allocated to the TestService service in the TestRegion region"
Exemple #2
0
    for vlan_interface in vlan_interfaces:
        # determine current ip address
        ipv4_addr = vlan_interface.re_match_iter_typed(r"ip\saddress\s(\S+\s+\S+)", result_type=IPv4Obj)

        # determine the current interface name and VLAN ID
        vlan_interface_string = vlan_interface.text.lstrip("interface ")
        vlan_id = vlan_interface_string.lstrip("Vlan")

        # the current SVI address is used as a HSRP virtual IP
        virtual_ip = ipv4_addr.ip_object

        # at this point we need to determine the next addresses which are used for the primary and secondary switch
        # we will try, if the next two addresses are part of the network, otherwise we will use the previous two
        # addresses
        ipv4_network = IPv4Network(ipv4_addr.network)
        if (ipv4_addr.ip_object + 1) in ipv4_network.hosts():
            primary_ip = ipv4_addr.ip_object + 1
            secondary_ip = ipv4_addr.ip_object + 2
        else:
            primary_ip = ipv4_addr.ip_object - 1
            secondary_ip = ipv4_addr.ip_object - 2

        # check for secondary IPv4 addresses
        add_ip_addresses = []
        secondary_ipv4_address_lines = vlan_interface.re_search_children(r"^ ip address .* secondary$")
        for sec_ipv4_cmd in secondary_ipv4_address_lines:
            # another way to convert the ip address command
            sec_ipv4_addr = sec_ipv4_cmd.text[len(" ip address "):]
            sec_ipv4_addr = sec_ipv4_addr.rstrip(" secondary")
            sec_ipv4_addr = sec_ipv4_addr.replace(" ", "/")
Exemple #3
0
    def l2_assignment_strategy(self):

        self.add_switches()
        ip_generator = IPv4Network(str("10.0.0.0/16")).hosts()

        #add links and configure them: ips, macs, etc
        #assumes hosts are connected to one switch only

        #reserve ips for normal hosts
        for host_name in self._hosts:
            if self.check_host_valid_ip_from_name(host_name):
                host_num = int(host_name[1:])
                upper_byte = (host_num & 0xff00) >> 8
                lower_byte = (host_num & 0x00ff)
                host_ip = "10.0.%d.%d" % (upper_byte, lower_byte)
                self.reserved_ips[host_name] = host_ip

        for link in self._links:

            if self.is_host_link(link):
                host_name = link[self.get_host_position(link)]
                direct_sw = link[self.get_sw_position(link)]

                if self.check_host_valid_ip_from_name(host_name):
                    host_ip = self.reserved_ips[host_name]

                    #we check if for some reason the ip was already given by the ip_generator. This
                    #can only happen if the host naming is not <h_x>
                    #this should not be possible anymore since we reserve ips for h_x hosts
                    while host_ip in self.already_assigned_ips:
                        host_ip = str(next(ip_generator).compressed)
                    self.already_assigned_ips.add(host_ip)
                else:
                    host_ip = next(ip_generator).compressed
                    #we check if for some reason the ip was already given by the ip_generator. This
                    #can only happen if the host naming is not <h_x>
                    while host_ip in self.already_assigned_ips or host_ip in list(
                            self.reserved_ips.values()):
                        host_ip = str(next(ip_generator).compressed)
                    self.already_assigned_ips.add(host_ip)

                host_mac = ip_address_to_mac(host_ip) % (0)
                direct_sw_mac = ip_address_to_mac(host_ip) % (1)

                ops = self._hosts[host_name]
                ops.pop("ip", None)
                ops.pop("mac", None)

                self.addHost(host_name,
                             ip=host_ip + "/16",
                             mac=host_mac,
                             **ops)
                self.addLink(host_name,
                             direct_sw,
                             delay=link['delay'],
                             bw=link['bw'],
                             loss=link['loss'],
                             addr1=host_mac,
                             addr2=direct_sw_mac,
                             weight=link["weight"],
                             max_queue_size=link["queue_length"])
                self.addSwitchPort(direct_sw, host_name)
                self.hosts_info[host_name] = {
                    "sw": direct_sw,
                    "ip": host_ip,
                    "mac": host_mac,
                    "mask": 24
                }

            #switch to switch link
            else:
                self.addLink(link['node1'],
                             link['node2'],
                             delay=link['delay'],
                             bw=link['bw'],
                             loss=link['loss'],
                             weight=link["weight"],
                             max_queue_size=link["queue_length"])
                self.addSwitchPort(link['node1'], link['node2'])
                self.addSwitchPort(link['node2'], link['node1'])

        self.add_cpu_port()
        self.printPortMapping()
Exemple #4
0
    def mixed_assignment_strategy(self):

        sw_to_id = self.add_switches()
        sw_to_generator = {}
        #change the id to a generator for that subnet
        for sw, sw_id in list(sw_to_id.items()):
            upper_bytex = (sw_id & 0xff00) >> 8
            lower_bytex = (sw_id & 0x00ff)
            net = "10.%d.%d.0/24" % (upper_bytex, lower_bytex)
            sw_to_generator[sw] = IPv4Network(str(net)).hosts()

        #reserve ips
        for link in self._links:
            if self.is_host_link(link):
                host_name = link[self.get_host_position(link)]
                direct_sw = link[self.get_sw_position(link)]

                sw_id = sw_to_id[direct_sw]
                upper_byte = (sw_id & 0xff00) >> 8
                lower_byte = (sw_id & 0x00ff)
                if self.check_host_valid_ip_from_name(host_name):
                    host_num = int(host_name[1:])
                    assert host_num < 254
                    host_ip = "10.%d.%d.%d" % (upper_byte, lower_byte,
                                               host_num)
                    self.reserved_ips[host_name] = host_ip

        #add links and configure them: ips, macs, etc
        #assumes hosts are connected to one switch only
        for link in self._links:

            if self.is_host_link(link):
                host_name = link[self.get_host_position(link)]
                direct_sw = link[self.get_sw_position(link)]

                sw_id = sw_to_id[direct_sw]
                upper_byte = (sw_id & 0xff00) >> 8
                lower_byte = (sw_id & 0x00ff)
                ip_generator = sw_to_generator[direct_sw]

                if self.check_host_valid_ip_from_name(host_name):
                    host_ip = self.reserved_ips[host_name]
                    #we check if for some reason the ip was already given by the ip_generator. This
                    #can only happen if the host naming is not <h_x>
                    while host_ip in self.already_assigned_ips:
                        host_ip = str(next(ip_generator).compressed)
                    self.already_assigned_ips.add(host_ip)
                else:
                    host_ip = next(ip_generator).compressed
                    #we check if for some reason the ip was already given by the ip_generator. This
                    #can only happen if the host naming is not <h_x>
                    while host_ip in self.already_assigned_ips or host_ip in list(
                            self.reserved_ips.values()):
                        host_ip = str(next(ip_generator).compressed)
                    self.already_assigned_ips.add(host_ip)

                host_gw = "10.%d.%d.254" % (upper_byte, lower_byte)

                host_mac = ip_address_to_mac(host_ip) % (0)
                direct_sw_mac = ip_address_to_mac(host_ip) % (1)

                ops = self._hosts[host_name]
                ops.pop("ip", None)
                ops.pop("mac", None)

                self.addHost(host_name,
                             ip=host_ip + "/24",
                             mac=host_mac,
                             defaultRoute='via %s' % host_gw,
                             **ops)
                self.addLink(host_name,
                             direct_sw,
                             delay=link['delay'],
                             bw=link['bw'],
                             loss=link['loss'],
                             addr1=host_mac,
                             addr2=direct_sw_mac,
                             weight=link["weight"],
                             max_queue_size=link["queue_length"])
                self.addSwitchPort(direct_sw, host_name)
                self.hosts_info[host_name] = {
                    "sw": direct_sw,
                    "ip": host_ip,
                    "mac": host_mac,
                    "mask": 24
                }

            #switch to switch link
            else:
                self.addLink(link['node1'],
                             link['node2'],
                             delay=link['delay'],
                             bw=link['bw'],
                             loss=link['loss'],
                             weight=link["weight"],
                             max_queue_size=link["queue_length"])
                self.addSwitchPort(link['node1'], link['node2'])
                self.addSwitchPort(link['node2'], link['node1'])

        self.add_cpu_port()
        self.printPortMapping()
 def ipv4_slash_zero(self) -> bool:
     """Returns True if `CidrIp` matches `0.0.0.0/0`, otherwise False."""
     # Remove after this is fixed https://bugs.python.org/issue38655
     if not self.CidrIp:
         return False
     return self.CidrIp == IPv4Network(IPV4_ZERO_VALUE)
            tcpr = sr1(tcps[pkt], timeout=t,
                       verbose=v)  # Send packet and capture response

            if tcpr is None:  # No response
                print "Port", stport, "is filtered"
            elif (tcpr[TCP].flags == 0x12):  # SYN-ACK
                print "Port", stport, "is open"
            elif (tcpr[TCP].flags == 0x14):  # RST
                print "Port", stport, "is closed"
        stport += 1


# If an IP range is specified, identify input as such and make list of addresses using ipv4network
for i in range(0, len(sip)):
    if (sip[i] == "/"):
        sips = IPv4Network(sip)
        for host in sips:  # Feed each of these IP's in one by one to spkt so appropriate ports can be probed
            spkt(host)

    elif (
            sip[i] != "/"
    ):  # Loop through all characters of IP to see if a range is specified
        i += 1
        if (i == len(sip)
            ):  # Single IP addresses will not have '/' characters at any point
            host = sip
            spkt(
                host
            )  # Therefore, such IPs can be passed straight into our packet creator function
        else:
            continue
Exemple #7
0
 def __init__(self, wanted_ip: str) -> None:
     self.name = wanted_ip
     self.wanted_ip = IPv4Network(wanted_ip)
def main(args):
    try:
        config = get_config(args.config, CONFIG_PARAMETERS)

        email = read_email(args.input)
    except Exception as ex:
        write_log(args.log, ex)

        return ReturnCode.ERROR

    if "Received" not in email:
        write_log(args.log, "Header received does not exist")

        return ReturnCode.ERROR

    header_received = str(email.get("Received"))

    if not header_received:
        write_log(args.log, "Header received is empty")

        return ReturnCode.ERROR

    sender_ip = re.search(r"\[([0-9.]+)\]", header_received)

    if not sender_ip:
        write_log(args.log, "Cannot find sender IP")

        return ReturnCode.ERROR

    sender_ip = sender_ip.group(1)

    try:
        ipv4_address = IPv4Address(sender_ip)
    except Exception:
        write_log(args.log, "Invalid sender IP")

        return ReturnCode.ERROR

    for network in config.internal_networks:
        try:
            ipv4_network = IPv4Network(network)
        except Exception:
            write_log(args.log, "Invalid CIDR '{}'".format(network))

            return ReturnCode.ERROR

        if ipv4_address in ipv4_network:
            break
    else:
        return ReturnCode.SENDER_EXTERNAL

    if "From" not in email:
        write_log(args.log, "Header does not exist")

        return ReturnCode.ERROR

    header_from = str(email.get("From"))

    if not header_from:
        write_log(args.log, "Header from is empty")

        return ReturnCode.ERROR

    sender_address = extract_email_address(header_from)

    if not sender_address:
        write_log(args.log, "Cannot find sender address")

        return ReturnCode.ERROR

    sender_address = sender_address.group(1)

    index_at = sender_address.find("@")

    if index_at == -1:
        write_log(args.log, "Invalid sender address")

        return ReturnCode.ERROR

    sender_domain = sender_address[index_at + 1:]

    if not sender_domain:
        write_log(args.log, "Empty sender domain")

        return ReturnCode.ERROR

    try:
        set_address = get_address_list(config.name_address_list)
    except Exception as ex:
        write_log(args.log, ex)

        return ReturnCode.ERROR

    if not set_address:
        write_log(args.log, "Address list is empty")

        return ReturnCode.ERROR

    set_domain = {
        email_address[email_address.find("@") + 1:]
        for email_address in set_address
    }

    if sender_domain not in set_domain:
        return ReturnCode.SENDER_EXTERNAL

    return ReturnCode.SENDER_INTERNAL
def configure():
    hookenv.log('Configuring isc-dhcp')
    managed_network = IPv4Network(config()["managed-network"])
    # We know what network we should be managing. This IPNetwork object has the
    # following properties:
    #   .ip            # Original ip from config value
    #   .network       # network ip
    #   .netmmask
    #   .broadcast_address
    #
    # What we don't know is what interface this network is connected to. The
    # following code tries to find out:
    #   1. what interface is connected to the network
    #   2. what the ip is of that interface
    #   3. what other interfaces this network has, ie interfaces that are unmanaged.
    #   4. what the public ip of the server is
    #
    # Then we do two sanity checks: the broadcast and netmask of that interface
    # must be the same as for the managed network.
    #
    mn_iface = None
    mn_iface_ip = None
    unmanaged_ifs = []
    public_ip = None
    for interface in netifaces.interfaces():
        af_inet = netifaces.ifaddresses(interface).get(AF_INET)
        if af_inet and af_inet[0].get('broadcast'):
            addr = IPv4Address(netifaces.ifaddresses(interface)[AF_INET][0]['addr'])
            if not addr.is_private: # Can't use is_global in 14.04 because of: https://bugs.python.org/issue21386
                # We found #4!
                public_ip = str(addr)
            if addr in managed_network:
                # We found #1 and #2 !
                mn_iface = interface
                mn_iface_ip = str(addr)
                # Sanity check
                assert(str(managed_network.broadcast_address) == netifaces.ifaddresses(interface)[AF_INET][0]['broadcast'])
                assert(str(managed_network.netmask) == netifaces.ifaddresses(interface)[AF_INET][0]['netmask'])
            else:
                # to find #3
                unmanaged_ifs.append(interface)
    if not public_ip:
        # No public address found, so we'll use the address of the interface
        # that is used to connect to the internet.
        public_ip = get_gateway_source_ip()
    if not mn_iface:
        # We are not connected to the network we have to manage. We don't know
        # what to do in this case so just tell that to the admin. We know this
        # handler will rerun when the config changes.
        hookenv.status_set(
            'blocked',
            'Cannot find interface that is connected to network {}.'.format(managed_network))
        return

    # Now that we know what interface we have to manage, let's check if there is
    # a dhcp server responding to requests from that interface. If there is no
    # dhcp server, we should install one.
    output = subprocess.check_output(['nmap', '--script', 'broadcast-dhcp-discover', '-e', mn_iface], stderr=subprocess.STDOUT, universal_newlines=True)
    print(output)
    if 'DHCPOFFER' in output: # pylint: disable=E1135
        print('DHCP server found on this network. Will NOT create one.')
        remove_state('role.dhcp-server')
    else:
        print('No DHCP server found on this network, will create one.')
        set_state('role.dhcp-server')

    # Configure ourselves as a NAT gateway regardless of network topology so
    # port-forwarding always works.
    configure_nat_gateway(mn_iface, unmanaged_ifs)

    # If our default gateway is not part of the managed network then we must
    # tell the clients on the managed network that we are their default gateway.
    # Otherwise, just pass our default gateway to the clients.
    gateway_if, gateway_ip = get_gateway()
    if gateway_if != mn_iface:
        print('Default gateway is NOT in the managed network so we tell potential clients we are their default gateway.')
        gateway_ip = mn_iface_ip
    else:
        print('Default gateway is on the managed network so we pass our default gateway to potential clients.')


    # Save these values so other handlers can use them.

    kv = unitdata.kv()
    kv.set('mn.iface', mn_iface)
    kv.set('mn.iface-ip', mn_iface_ip)
    kv.set('mn.gateway', gateway_ip)
    kv.set('public-ip', public_ip)
    set_state('gateway.installed')
    # Now we let the dhcp-server handlers know that they potentially have to
    # reconfigure their settings.
    remove_state('dhcp-server.configured')
Exemple #10
0
    def allocate(
        self, *, rid: ID, requested_ns: NetworkServiceSliver,
        owner_switch: NodeSliver,
        existing_reservations: List[ABCReservationMixin]
    ) -> NetworkServiceSliver:
        """
        Allocate Network Service Sliver (Only for L3 Service)
            - grab the /17 or /48 from BQM Site specific NetworkService
            - divide it into /24 or /64 subnets
            - exclude the 1st subnet (reserved for control plane)
            - exclude the subnets already assigned to other V3/V4 NetworkService on the same owner switch
            - allocate the first available subnet to the NetworkService
        :param requested_ns: Requested NetworkService
        :param owner_switch: BQM Owner site switch identified to serve the NetworkService
        :param existing_reservations: Existing Reservations which also are served by the owner switch
        :return NetworkService updated with the allocated subnet for FABNetv4 and FABNetv6 services
        Return the sliver updated with the subnet
        """
        if requested_ns.get_type(
        ) != ServiceType.FABNetv4 and requested_ns.get_type(
        ) != ServiceType.FABNetv6:
            return requested_ns

        for ns in owner_switch.network_service_info.network_services.values():
            if requested_ns.get_type() == ns.get_type():
                # Grab Label Delegations
                delegation_id, delegated_label = self._get_delegations(
                    lab_cap_delegations=ns.get_label_delegations())

                subnet_list = None
                # Get Subnet
                if ns.get_type() == ServiceType.FABNetv6:
                    ip_network = IPv6Network(delegated_label.ipv6_subnet)
                    subnet_list = list(ip_network.subnets(new_prefix=64))

                elif ns.get_type() == ServiceType.FABNetv4:
                    ip_network = IPv4Network(delegated_label.ipv4_subnet)
                    subnet_list = list(ip_network.subnets(new_prefix=24))

                # Exclude the 1st subnet as it is reserved for control plane
                subnet_list.pop(0)

                # Exclude the already allocated VLANs and subnets
                for reservation in existing_reservations:
                    if rid == reservation.get_reservation_id():
                        continue
                    # For Active or Ticketed or Ticketing reservations; reduce the counts from available
                    allocated_sliver = None
                    if reservation.is_ticketing(
                    ) and reservation.get_approved_resources() is not None:
                        allocated_sliver = reservation.get_approved_resources(
                        ).get_sliver()

                    if (reservation.is_active() or reservation.is_ticketed()) and \
                            reservation.get_resources() is not None:
                        allocated_sliver = reservation.get_resources(
                        ).get_sliver()

                    self.logger.debug(
                        f"Existing res# {reservation.get_reservation_id()} allocated: {allocated_sliver}"
                    )

                    if allocated_sliver is None:
                        continue

                    if allocated_sliver.get_type() != requested_ns.get_type():
                        continue

                    if allocated_sliver.get_type() == ServiceType.FABNetv4:
                        subnet_to_remove = IPv4Network(
                            allocated_sliver.get_gateway().lab.ipv4_subnet)
                        subnet_list.remove(subnet_to_remove)
                        self.logger.debug(
                            f"Excluding already allocated IP4Subnet: "
                            f"{allocated_sliver.get_gateway().lab.ipv4_subnet}"
                            f" to res# {reservation.get_reservation_id()}")

                    elif allocated_sliver.get_gateway(
                    ).lab.ipv6_subnet is not None:
                        subnet_to_remove = IPv6Network(
                            allocated_sliver.get_gateway().lab.ipv6_subnet)
                        subnet_list.remove(subnet_to_remove)
                        self.logger.debug(
                            f"Excluding already allocated IPv6Subnet: "
                            f"{allocated_sliver.get_gateway().lab.ipv6_subnet}"
                            f" to res# {reservation.get_reservation_id()}")

                gateway_labels = Labels()
                if requested_ns.get_type() == ServiceType.FABNetv4:
                    gateway_labels.ipv4_subnet = subnet_list[0].with_prefixlen
                    gateway_labels.ipv4 = str(next(subnet_list[0].hosts()))

                elif requested_ns.get_type() == ServiceType.FABNetv6:
                    gateway_labels.ipv6_subnet = subnet_list[0].with_prefixlen
                    gateway_labels.ipv6 = str(next(subnet_list[0].hosts()))

                requested_ns.gateway = Gateway(lab=gateway_labels)
                break
        return requested_ns
Exemple #11
0
def get_domain_subnets(path="./subnets.yml"):
    return {k: IPv4Network(v) for k, v in yaml.safe_load(open(path)).items()}
Exemple #12
0
# -*- coding: utf-8 -*-

from ipaddress import IPv4Network

from ..datasource import DataSource, Dormitory
from . import user


def init_context(app):
    app.extensions['gerok_api'] = {
        'endpoint': app.config['GEROK_ENDPOINT'],
        'token': app.config['GEROK_API_TOKEN']
    }


datasource = DataSource(name='gerok',
                        user_class=user.User,
                        mail_server="wh17.tu-dresden.de",
                        webmailer_url="https://wh17.tu-dresden.de/webmail/",
                        support_mail="*****@*****.**",
                        init_context=init_context)

dormitories = [
    Dormitory(name='gerok',
              display_name="Gerokstraße",
              datasource=datasource,
              subnets=[IPv4Network('141.76.124.0/24')])
]
Exemple #13
0
 def set_interface_data(self, ip, netmask, mac):
     self.ip_addr = ip
     self.mac_addr = mac
     n = IPv4Network(ip + "/" + netmask, strict=False)
     self.broadcast_addr = str(n.broadcast_address)
Exemple #14
0
 def test_retrieves_ipv4_ipnetwork_type(self):
     instance = CidrArrayTestModel(field=['10.1.1.0/24'])
     instance.save()
     instance = CidrArrayTestModel.objects.get(id=instance.id)
     self.assertEqual(instance.field, [IPv4Network('10.1.1.0/24')])
     self.assertIsInstance(instance.field[0], IPv4Network)
Exemple #15
0
 def validate(self) -> EnsureVPNResult:
     checker = IPChecker(
         validation_func=lambda ip: self.wanted_ip.overlaps(IPv4Network(ip))
     )
     return checker.run()
Exemple #16
0
def ipv4_networks(val: str) -> List[IPv4Network]:
    return [IPv4Network(s.strip()) for s in val.split(",")]
Exemple #17
0
 def __init__(self, ip, mask):
     try:
         IPv4Network.__init__(self, (ip, mask), strict=False)
     except AddressValueError:
         print("Error generate network")
Exemple #18
0
def verify(openvpn):
    if openvpn['deleted']:
        if openvpn['is_bridge_member']:
            raise ConfigError(
                (f'Cannot delete interface "{openvpn["intf"]}" as it is a '
                 f'member of bridge "{openvpn["is_bridge_menber"]}"!'))
        return None

    if not openvpn['mode']:
        raise ConfigError('Must specify OpenVPN operation mode')

    # Check if we have disabled ncp and at the same time specified ncp-ciphers
    if openvpn['disable_ncp'] and openvpn['ncp_ciphers']:
        raise ConfigError(
            'Cannot specify both "encryption disable-ncp" and "encryption ncp-ciphers"'
        )
    #
    # OpenVPN client mode - VERIFY
    #
    if openvpn['mode'] == 'client':
        if openvpn['local_port']:
            raise ConfigError('Cannot specify "local-port" in client mode')

        if openvpn['local_host']:
            raise ConfigError('Cannot specify "local-host" in client mode')

        if openvpn['protocol'] == 'tcp-passive':
            raise ConfigError(
                'Protocol "tcp-passive" is not valid in client mode')

        if not openvpn['remote_host']:
            raise ConfigError('Must specify "remote-host" in client mode')

        if openvpn['tls_dh'] and openvpn['tls_dh'] != 'none':
            raise ConfigError('Cannot specify "tls dh-file" in client mode')

    #
    # OpenVPN site-to-site - VERIFY
    #
    if openvpn['mode'] == 'site-to-site':
        if openvpn['ncp_ciphers']:
            raise ConfigError(
                'encryption ncp-ciphers cannot be specified in site-to-site mode, only server or client'
            )

    if openvpn['mode'] == 'site-to-site' and not openvpn['is_bridge_member']:
        if not (openvpn['local_address'] or openvpn['ipv6_local_address']):
            raise ConfigError(
                'Must specify "local-address" or add interface to bridge')

        if len(openvpn['local_address']) > 1 or len(
                openvpn['ipv6_local_address']) > 1:
            raise ConfigError(
                'Cannot specify more than 1 IPv4 and 1 IPv6 "local-address"')

        if len(openvpn['remote_address']) > 1 or len(
                openvpn['ipv6_remote_address']) > 1:
            raise ConfigError(
                'Cannot specify more than 1 IPv4 and 1 IPv6 "remote-address"')

        for host in openvpn['remote_host']:
            if host in openvpn['remote_address'] or host in openvpn[
                    'ipv6_remote_address']:
                raise ConfigError(
                    '"remote-address" cannot be the same as "remote-host"')

        if openvpn['local_address'] and not (openvpn['remote_address'] or
                                             openvpn['local_address_subnet']):
            raise ConfigError(
                'IPv4 "local-address" requires IPv4 "remote-address" or IPv4 "local-address subnet"'
            )

        if openvpn['remote_address'] and not openvpn['local_address']:
            raise ConfigError(
                'IPv4 "remote-address" requires IPv4 "local-address"')

        if openvpn['ipv6_local_address'] and not openvpn['ipv6_remote_address']:
            raise ConfigError(
                'IPv6 "local-address" requires IPv6 "remote-address"')

        if openvpn['ipv6_remote_address'] and not openvpn['ipv6_local_address']:
            raise ConfigError(
                'IPv6 "remote-address" requires IPv6 "local-address"')

        if openvpn['type'] == 'tun':
            if not (openvpn['remote_address']
                    or openvpn['ipv6_remote_address']):
                raise ConfigError('Must specify "remote-address"')

            if ((openvpn['local_address']
                 and openvpn['local_address'] == openvpn['remote_address'])
                    or (openvpn['ipv6_local_address']
                        and openvpn['ipv6_local_address']
                        == openvpn['ipv6_remote_address'])):
                raise ConfigError(
                    '"local-address" and "remote-address" cannot be the same')

            if openvpn['local_host'] in openvpn['local_address'] or openvpn[
                    'local_host'] in openvpn['ipv6_local_address']:
                raise ConfigError(
                    '"local-address" cannot be the same as "local-host"')

    else:
        # checks for client-server or site-to-site bridged
        if openvpn['local_address'] or openvpn['ipv6_local_address'] or openvpn[
                'remote_address'] or openvpn['ipv6_remote_address']:
            raise ConfigError(
                'Cannot specify "local-address" or "remote-address" in client-server or bridge mode'
            )

    #
    # OpenVPN server mode - VERIFY
    #
    if openvpn['mode'] == 'server':
        if openvpn['protocol'] == 'tcp-active':
            raise ConfigError(
                'Protocol "tcp-active" is not valid in server mode')

        if openvpn['remote_port']:
            raise ConfigError('Cannot specify "remote-port" in server mode')

        if openvpn['remote_host']:
            raise ConfigError('Cannot specify "remote-host" in server mode')

        if openvpn['protocol'] == 'tcp-passive' and len(
                openvpn['remote_host']) > 1:
            raise ConfigError(
                'Cannot specify more than 1 "remote-host" with "tcp-passive"')

        if not openvpn['tls_dh'] and not checkCertHeader(
                '-----BEGIN EC PRIVATE KEY-----', openvpn['tls_key']):
            raise ConfigError(
                'Must specify "tls dh-file" when not using EC keys in server mode'
            )

        if len(openvpn['server_subnet']) > 1 or len(
                openvpn['server_ipv6_subnet']) > 1:
            raise ConfigError(
                'Cannot specify more than 1 IPv4 and 1 IPv6 server subnet')

        for client in openvpn['client']:
            if len(client['ip']) > 1 or len(client['ipv6_ip']) > 1:
                raise ConfigError(
                    f'Server client "{client["name"]}": cannot specify more than 1 IPv4 and 1 IPv6 IP'
                )

        if openvpn['server_subnet']:
            subnet = IPv4Network(openvpn['server_subnet'][0].replace(' ', '/'))

            if openvpn['type'] == 'tun' and subnet.prefixlen > 29:
                raise ConfigError(
                    'Server subnets smaller than /29 with device type "tun" are not supported'
                )
            elif openvpn['type'] == 'tap' and subnet.prefixlen > 30:
                raise ConfigError(
                    'Server subnets smaller than /30 with device type "tap" are not supported'
                )

            for client in openvpn['client']:
                if client['ip'] and not IPv4Address(client['ip'][0]) in subnet:
                    raise ConfigError(
                        f'Client "{client["name"]}" IP {client["ip"][0]} not in server subnet {subnet}'
                    )

        else:
            if not openvpn['is_bridge_member']:
                raise ConfigError(
                    'Must specify "server subnet" or add interface to bridge in server mode'
                )

        if openvpn['server_pool']:
            if not (openvpn['server_pool_start']
                    and openvpn['server_pool_stop']):
                raise ConfigError(
                    'Server client-ip-pool requires both start and stop addresses in bridged mode'
                )
            else:
                v4PoolStart = IPv4Address(openvpn['server_pool_start'])
                v4PoolStop = IPv4Address(openvpn['server_pool_stop'])
                if v4PoolStart > v4PoolStop:
                    raise ConfigError(
                        f'Server client-ip-pool start address {v4PoolStart} is larger than stop address {v4PoolStop}'
                    )

                v4PoolSize = int(v4PoolStop) - int(v4PoolStart)
                if v4PoolSize >= 65536:
                    raise ConfigError(
                        f'Server client-ip-pool is too large [{v4PoolStart} -> {v4PoolStop} = {v4PoolSize}], maximum is 65536 addresses.'
                    )

                v4PoolNets = list(
                    summarize_address_range(v4PoolStart, v4PoolStop))
                for client in openvpn['client']:
                    if client['ip']:
                        for v4PoolNet in v4PoolNets:
                            if IPv4Address(client['ip'][0]) in v4PoolNet:
                                print(
                                    f'Warning: Client "{client["name"]}" IP {client["ip"][0]} is in server IP pool, it is not reserved for this client.',
                                    file=stderr)

        if openvpn['server_ipv6_subnet']:
            if not openvpn['server_subnet']:
                raise ConfigError('IPv6 server requires an IPv4 server subnet')

            if openvpn['server_ipv6_pool']:
                if not openvpn['server_pool']:
                    raise ConfigError(
                        'IPv6 server pool requires an IPv4 server pool')

                if int(openvpn['server_ipv6_pool_prefixlen']) >= 112:
                    raise ConfigError(
                        'IPv6 server pool must be larger than /112')

                v6PoolStart = IPv6Address(openvpn['server_ipv6_pool_base'])
                v6PoolStop = IPv6Network(
                    (v6PoolStart, openvpn['server_ipv6_pool_prefixlen']),
                    strict=False)[
                        -1]  # don't remove the parentheses, it's a 2-tuple
                v6PoolSize = int(v6PoolStop) - int(v6PoolStart) if int(
                    openvpn['server_ipv6_pool_prefixlen']) > 96 else 65536
                if v6PoolSize < v4PoolSize:
                    raise ConfigError(
                        f'IPv6 server pool must be at least as large as the IPv4 pool (current sizes: IPv6={v6PoolSize} IPv4={v4PoolSize})'
                    )

                v6PoolNets = list(
                    summarize_address_range(v6PoolStart, v6PoolStop))
                for client in openvpn['client']:
                    if client['ipv6_ip']:
                        for v6PoolNet in v6PoolNets:
                            if IPv6Address(client['ipv6_ip'][0]) in v6PoolNet:
                                print(
                                    f'Warning: Client "{client["name"]}" IP {client["ipv6_ip"][0]} is in server IP pool, it is not reserved for this client.',
                                    file=stderr)

        else:
            if openvpn['server_ipv6_push_route']:
                raise ConfigError(
                    'IPv6 push-route requires an IPv6 server subnet')

            for client in openvpn['client']:
                if client['ipv6_ip']:
                    raise ConfigError(
                        f'Server client "{client["name"]}" IPv6 IP requires an IPv6 server subnet'
                    )
                if client['ipv6_push_route']:
                    raise ConfigError(
                        f'Server client "{client["name"]} IPv6 push-route requires an IPv6 server subnet"'
                    )
                if client['ipv6_subnet']:
                    raise ConfigError(
                        f'Server client "{client["name"]} IPv6 subnet requires an IPv6 server subnet"'
                    )

    else:
        # checks for both client and site-to-site go here
        if openvpn['server_reject_unconfigured']:
            raise ConfigError(
                'reject-unconfigured-clients is only supported in OpenVPN server mode'
            )

        if openvpn['server_topology']:
            raise ConfigError(
                'The "topology" option is only valid in server mode')

        if (not openvpn['remote_host']) and openvpn['redirect_gateway']:
            raise ConfigError(
                'Cannot set "replace-default-route" without "remote-host"')

    #
    # OpenVPN common verification section
    # not depending on any operation mode
    #

    # verify specified IP address is present on any interface on this system
    if openvpn['local_host']:
        if not is_addr_assigned(openvpn['local_host']):
            raise ConfigError(
                'No interface on system with specified local-host IP address: {}'
                .format(openvpn['local_host']))

    # TCP active
    if openvpn['protocol'] == 'tcp-active':
        if openvpn['local_port']:
            raise ConfigError('Cannot specify "local-port" with "tcp-active"')

        if not openvpn['remote_host']:
            raise ConfigError('Must specify "remote-host" with "tcp-active"')

    # shared secret and TLS
    if not (openvpn['shared_secret_file'] or openvpn['tls']):
        raise ConfigError(
            'Must specify one of "shared-secret-key-file" and "tls"')

    if openvpn['shared_secret_file'] and openvpn['tls']:
        raise ConfigError(
            'Can only specify one of "shared-secret-key-file" and "tls"')

    if openvpn['mode'] in ['client', 'server']:
        if not openvpn['tls']:
            raise ConfigError('Must specify "tls" in client-server mode')

    #
    # TLS/encryption
    #
    if openvpn['shared_secret_file']:
        if openvpn['encryption'] in ['aes128gcm', 'aes192gcm', 'aes256gcm']:
            raise ConfigError(
                'GCM encryption with shared-secret-key-file is not supported')

        if not checkCertHeader('-----BEGIN OpenVPN Static key V1-----',
                               openvpn['shared_secret_file']):
            raise ConfigError(
                'Specified shared-secret-key-file "{}" is not valid'.format(
                    openvpn['shared_secret_file']))

    if openvpn['tls']:
        if not openvpn['tls_ca_cert']:
            raise ConfigError('Must specify "tls ca-cert-file"')

        if not (openvpn['mode'] == 'client' and openvpn['auth']):
            if not openvpn['tls_cert']:
                raise ConfigError('Must specify "tls cert-file"')

            if not openvpn['tls_key']:
                raise ConfigError('Must specify "tls key-file"')

        if openvpn['tls_auth'] and openvpn['tls_crypt']:
            raise ConfigError('TLS auth and crypt are mutually exclusive')

        if not checkCertHeader('-----BEGIN CERTIFICATE-----',
                               openvpn['tls_ca_cert']):
            raise ConfigError('Specified ca-cert-file "{}" is invalid'.format(
                openvpn['tls_ca_cert']))

        if openvpn['tls_auth']:
            if not checkCertHeader('-----BEGIN OpenVPN Static key V1-----',
                                   openvpn['tls_auth']):
                raise ConfigError('Specified auth-file "{}" is invalid'.format(
                    openvpn['tls_auth']))

        if openvpn['tls_cert']:
            if not checkCertHeader('-----BEGIN CERTIFICATE-----',
                                   openvpn['tls_cert']):
                raise ConfigError('Specified cert-file "{}" is invalid'.format(
                    openvpn['tls_cert']))

        if openvpn['tls_key']:
            if not checkCertHeader('-----BEGIN (?:RSA |EC )?PRIVATE KEY-----',
                                   openvpn['tls_key']):
                raise ConfigError(
                    'Specified key-file "{}" is not valid'.format(
                        openvpn['tls_key']))

        if openvpn['tls_crypt']:
            if not checkCertHeader('-----BEGIN OpenVPN Static key V1-----',
                                   openvpn['tls_crypt']):
                raise ConfigError(
                    'Specified TLS crypt-file "{}" is invalid'.format(
                        openvpn['tls_crypt']))

        if openvpn['tls_crl']:
            if not checkCertHeader('-----BEGIN X509 CRL-----',
                                   openvpn['tls_crl']):
                raise ConfigError('Specified crl-file "{} not valid'.format(
                    openvpn['tls_crl']))

        if openvpn['tls_dh'] and openvpn['tls_dh'] != 'none':
            if not checkCertHeader('-----BEGIN DH PARAMETERS-----',
                                   openvpn['tls_dh']):
                raise ConfigError('Specified dh-file "{}" is not valid'.format(
                    openvpn['tls_dh']))

        if openvpn['tls_role']:
            if openvpn['mode'] in ['client', 'server']:
                if not openvpn['tls_auth']:
                    raise ConfigError(
                        'Cannot specify "tls role" in client-server mode')

            if openvpn['tls_role'] == 'active':
                if openvpn['protocol'] == 'tcp-passive':
                    raise ConfigError(
                        'Cannot specify "tcp-passive" when "tls role" is "active"'
                    )

                if openvpn['tls_dh'] and openvpn['tls_dh'] != 'none':
                    raise ConfigError(
                        'Cannot specify "tls dh-file" when "tls role" is "active"'
                    )

            elif openvpn['tls_role'] == 'passive':
                if openvpn['protocol'] == 'tcp-active':
                    raise ConfigError(
                        'Cannot specify "tcp-active" when "tls role" is "passive"'
                    )

                if not openvpn['tls_dh']:
                    raise ConfigError(
                        'Must specify "tls dh-file" when "tls role" is "passive"'
                    )

        if openvpn['tls_key'] and checkCertHeader(
                '-----BEGIN EC PRIVATE KEY-----', openvpn['tls_key']):
            if openvpn['tls_dh'] and openvpn['tls_dh'] != 'none':
                print(
                    'Warning: using dh-file and EC keys simultaneously will lead to DH ciphers being used instead of ECDH'
                )
            else:
                print(
                    'Diffie-Hellman prime file is unspecified, assuming ECDH')

    #
    # Auth user/pass
    #
    if openvpn['auth']:
        if not openvpn['auth_user']:
            raise ConfigError('Username for authentication is missing')

        if not openvpn['auth_pass']:
            raise ConfigError('Password for authentication is missing')

    if openvpn['vrf']:
        if openvpn['vrf'] not in interfaces():
            raise ConfigError(f'VRF "{openvpn["vrf"]}" does not exist')

        if openvpn['is_bridge_member']:
            raise ConfigError((
                f'Interface "{openvpn["intf"]}" cannot be member of VRF '
                f'"{openvpn["vrf"]}" and bridge "{openvpn["is_bridge_member"]}" '
                f'at the same time!'))

    return None
 def set_CidrIp(cls, v):
     return IPv4Network(v, strict=False)