Beispiel #1
0
    def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor):
        # setting base values
        if flavor == "suse":
            iface_cfg["BOOTPROTO"] = "static"
            if "BRIDGE" in iface_cfg:
                iface_cfg["BOOTPROTO"] = "dhcp"
                iface_cfg.drop("BRIDGE")
        else:
            iface_cfg["BOOTPROTO"] = "none"

        # modifying base values according to subnets
        for i, subnet in enumerate(subnets, start=len(iface_cfg.children)):
            mtu_key = "MTU"
            subnet_type = subnet.get("type")
            if subnet_type == "dhcp6" or subnet_type == "ipv6_dhcpv6-stateful":
                if flavor == "suse":
                    # User wants dhcp for both protocols
                    if iface_cfg["BOOTPROTO"] == "dhcp4":
                        iface_cfg["BOOTPROTO"] = "dhcp"
                    else:
                        # Only IPv6 is DHCP, IPv4 may be static
                        iface_cfg["BOOTPROTO"] = "dhcp6"
                    iface_cfg["DHCLIENT6_MODE"] = "managed"
                # only if rhel AND dhcpv6 stateful
                elif (flavor == "rhel"
                      and subnet_type == "ipv6_dhcpv6-stateful"):
                    iface_cfg["BOOTPROTO"] = "dhcp"
                    iface_cfg["DHCPV6C"] = True
                    iface_cfg["IPV6INIT"] = True
                    iface_cfg["IPV6_AUTOCONF"] = False
                else:
                    iface_cfg["IPV6INIT"] = True
                    # Configure network settings using DHCPv6
                    iface_cfg["DHCPV6C"] = True
            elif subnet_type == "ipv6_dhcpv6-stateless":
                if flavor == "suse":
                    # User wants dhcp for both protocols
                    if iface_cfg["BOOTPROTO"] == "dhcp4":
                        iface_cfg["BOOTPROTO"] = "dhcp"
                    else:
                        # Only IPv6 is DHCP, IPv4 may be static
                        iface_cfg["BOOTPROTO"] = "dhcp6"
                    iface_cfg["DHCLIENT6_MODE"] = "info"
                else:
                    iface_cfg["IPV6INIT"] = True
                    # Configure network settings using SLAAC from RAs and
                    # optional info from dhcp server using DHCPv6
                    iface_cfg["IPV6_AUTOCONF"] = True
                    iface_cfg["DHCPV6C"] = True
                    # Use Information-request to get only stateless
                    # configuration parameters (i.e., without address).
                    iface_cfg["DHCPV6C_OPTIONS"] = "-S"
            elif subnet_type == "ipv6_slaac":
                if flavor == "suse":
                    # User wants dhcp for both protocols
                    if iface_cfg["BOOTPROTO"] == "dhcp4":
                        iface_cfg["BOOTPROTO"] = "dhcp"
                    else:
                        # Only IPv6 is DHCP, IPv4 may be static
                        iface_cfg["BOOTPROTO"] = "dhcp6"
                    iface_cfg["DHCLIENT6_MODE"] = "info"
                else:
                    iface_cfg["IPV6INIT"] = True
                    # Configure network settings using SLAAC from RAs
                    iface_cfg["IPV6_AUTOCONF"] = True
            elif subnet_type in ["dhcp4", "dhcp"]:
                bootproto_in = iface_cfg["BOOTPROTO"]
                iface_cfg["BOOTPROTO"] = "dhcp"
                if flavor == "suse" and subnet_type == "dhcp4":
                    # If dhcp6 is already specified the user wants dhcp
                    # for both protocols
                    if bootproto_in != "dhcp6":
                        # Only IPv4 is DHCP, IPv6 may be static
                        iface_cfg["BOOTPROTO"] = "dhcp4"
            elif subnet_type in ["static", "static6"]:
                # RH info
                # grep BOOTPROTO sysconfig.txt -A2 | head -3
                # BOOTPROTO=none|bootp|dhcp
                # 'bootp' or 'dhcp' cause a DHCP client
                # to run on the device. Any other
                # value causes any static configuration
                # in the file to be applied.
                if subnet_is_ipv6(subnet) and flavor != "suse":
                    mtu_key = "IPV6_MTU"
                    iface_cfg["IPV6INIT"] = True
                if "mtu" in subnet:
                    mtu_mismatch = bool(
                        mtu_key in iface_cfg
                        and subnet["mtu"] != iface_cfg[mtu_key])
                    if mtu_mismatch:
                        LOG.warning(
                            "Network config: ignoring %s device-level mtu:%s"
                            " because ipv4 subnet-level mtu:%s provided.",
                            iface_cfg.name,
                            iface_cfg[mtu_key],
                            subnet["mtu"],
                        )
                    if subnet_is_ipv6(subnet):
                        if flavor == "suse":
                            # TODO(rjschwei) write mtu setting to
                            # /etc/sysctl.d/
                            pass
                        else:
                            iface_cfg[mtu_key] = subnet["mtu"]
                    else:
                        iface_cfg[mtu_key] = subnet["mtu"]

                if subnet_is_ipv6(subnet) and flavor == "rhel":
                    iface_cfg["IPV6_FORCE_ACCEPT_RA"] = False
                    iface_cfg["IPV6_AUTOCONF"] = False
            elif subnet_type == "manual":
                if flavor == "suse":
                    LOG.debug('Unknown subnet type setting "%s"', subnet_type)
                else:
                    # If the subnet has an MTU setting, then ONBOOT=True
                    # to apply the setting
                    iface_cfg["ONBOOT"] = mtu_key in iface_cfg
            else:
                raise ValueError(
                    "Unknown subnet type '%s' found for interface '%s'" %
                    (subnet_type, iface_cfg.name))
            if subnet.get("control") == "manual":
                if flavor == "suse":
                    iface_cfg["STARTMODE"] = "manual"
                else:
                    iface_cfg["ONBOOT"] = False

        # set IPv4 and IPv6 static addresses
        ipv4_index = -1
        ipv6_index = -1
        for i, subnet in enumerate(subnets, start=len(iface_cfg.children)):
            subnet_type = subnet.get("type")
            # metric may apply to both dhcp and static config
            if "metric" in subnet:
                if flavor != "suse":
                    iface_cfg["METRIC"] = subnet["metric"]
            if subnet_type in ["dhcp", "dhcp4"]:
                # On SUSE distros 'DHCLIENT_SET_DEFAULT_ROUTE' is a global
                # setting in /etc/sysconfig/network/dhcp
                if flavor != "suse":
                    if has_default_route and iface_cfg["BOOTPROTO"] != "none":
                        iface_cfg["DHCLIENT_SET_DEFAULT_ROUTE"] = False
                continue
            elif subnet_type in IPV6_DYNAMIC_TYPES:
                continue
            elif subnet_type in ["static", "static6"]:
                if subnet_is_ipv6(subnet):
                    ipv6_index = ipv6_index + 1
                    ipv6_cidr = "%s/%s" % (subnet["address"], subnet["prefix"])
                    if ipv6_index == 0:
                        if flavor == "suse":
                            iface_cfg["IPADDR6"] = ipv6_cidr
                        else:
                            iface_cfg["IPV6ADDR"] = ipv6_cidr
                    elif ipv6_index == 1:
                        if flavor == "suse":
                            iface_cfg["IPADDR6_1"] = ipv6_cidr
                        else:
                            iface_cfg["IPV6ADDR_SECONDARIES"] = ipv6_cidr
                    else:
                        if flavor == "suse":
                            iface_cfg["IPADDR6_%d" % ipv6_index] = ipv6_cidr
                        else:
                            iface_cfg["IPV6ADDR_SECONDARIES"] += (" " +
                                                                  ipv6_cidr)
                else:
                    ipv4_index = ipv4_index + 1
                    suff = "" if ipv4_index == 0 else str(ipv4_index)
                    iface_cfg["IPADDR" + suff] = subnet["address"]
                    iface_cfg["NETMASK" + suff] = net_prefix_to_ipv4_mask(
                        subnet["prefix"])

                if "gateway" in subnet and flavor != "suse":
                    iface_cfg["DEFROUTE"] = True
                    if is_ipv6_address(subnet["gateway"]):
                        iface_cfg["IPV6_DEFAULTGW"] = subnet["gateway"]
                    else:
                        iface_cfg["GATEWAY"] = subnet["gateway"]

                if "dns_search" in subnet and flavor != "suse":
                    iface_cfg["DOMAIN"] = " ".join(subnet["dns_search"])

                if "dns_nameservers" in subnet and flavor != "suse":
                    if len(subnet["dns_nameservers"]) > 3:
                        # per resolv.conf(5) MAXNS sets this to 3.
                        LOG.debug(
                            "%s has %d entries in dns_nameservers. "
                            "Only 3 are used.",
                            iface_cfg.name,
                            len(subnet["dns_nameservers"]),
                        )
                    for i, k in enumerate(subnet["dns_nameservers"][:3], 1):
                        iface_cfg["DNS" + str(i)] = k
Beispiel #2
0
def translate_network(settings):
    # Get the standard cmd, args from the ubuntu format
    entries = []
    for line in settings.splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        split_up = line.split(None, 1)
        if len(split_up) <= 1:
            continue
        entries.append(split_up)
    # Figure out where each iface section is
    ifaces = []
    consume = {}
    for (cmd, args) in entries:
        if cmd == "iface":
            if consume:
                ifaces.append(consume)
                consume = {}
            consume[cmd] = args
        else:
            consume[cmd] = args
    # Check if anything left over to consume
    absorb = False
    for (cmd, args) in consume.items():
        if cmd == "iface":
            absorb = True
    if absorb:
        ifaces.append(consume)
    # Now translate
    real_ifaces = {}
    for info in ifaces:
        if "iface" not in info:
            continue
        iface_details = info["iface"].split(None)
        # Check if current device *may* have an ipv6 IP
        use_ipv6 = False
        if "inet6" in iface_details:
            use_ipv6 = True
        dev_name = None
        if len(iface_details) >= 1:
            dev = iface_details[0].strip().lower()
            if dev:
                dev_name = dev
        if not dev_name:
            continue
        iface_info = {}
        iface_info["ipv6"] = {}
        if len(iface_details) >= 3:
            proto_type = iface_details[2].strip().lower()
            # Seems like this can be 'loopback' which we don't
            # really care about
            if proto_type in ["dhcp", "static"]:
                iface_info["bootproto"] = proto_type
        # These can just be copied over
        if use_ipv6:
            for k in ["address", "gateway"]:
                if k in info:
                    val = info[k].strip().lower()
                    if val:
                        iface_info["ipv6"][k] = val
        else:
            for k in ["netmask", "address", "gateway", "broadcast"]:
                if k in info:
                    val = info[k].strip().lower()
                    if val:
                        iface_info[k] = val
            # handle static ip configurations using
            # ipaddress/prefix-length format
            if "address" in iface_info:
                if "netmask" not in iface_info:
                    # check if the address has a network prefix
                    addr, _, prefix = iface_info["address"].partition("/")
                    if prefix:
                        iface_info["netmask"] = net_prefix_to_ipv4_mask(prefix)
                        iface_info["address"] = addr
                        # if we set the netmask, we also can set the broadcast
                        iface_info["broadcast"] = mask_and_ipv4_to_bcast_addr(
                            iface_info["netmask"], addr)

            # Name server info provided??
            if "dns-nameservers" in info:
                iface_info["dns-nameservers"] = info["dns-nameservers"].split()
            # Name server search info provided??
            if "dns-search" in info:
                iface_info["dns-search"] = info["dns-search"].split()
            # Is any mac address spoofing going on??
            if "hwaddress" in info:
                hw_info = info["hwaddress"].lower().strip()
                hw_split = hw_info.split(None, 1)
                if len(hw_split) == 2 and hw_split[0].startswith("ether"):
                    hw_addr = hw_split[1]
                    if hw_addr:
                        iface_info["hwaddress"] = hw_addr
        # If ipv6 is enabled, device will have multiple IPs, so we need to
        # update the dictionary instead of overwriting it...
        if dev_name in real_ifaces:
            real_ifaces[dev_name].update(iface_info)
        else:
            real_ifaces[dev_name] = iface_info
    # Check for those that should be started on boot via 'auto'
    for (cmd, args) in entries:
        args = args.split(None)
        if not args:
            continue
        dev_name = args[0].strip().lower()
        if cmd == "auto":
            # Seems like auto can be like 'auto eth0 eth0:1' so just get the
            # first part out as the device name
            if dev_name in real_ifaces:
                real_ifaces[dev_name]["auto"] = True
        if cmd == "iface" and "inet6" in args:
            real_ifaces[dev_name]["inet6"] = True
    return real_ifaces
Beispiel #3
0
def _normalize_net_keys(network, address_keys=()):
    """Normalize dictionary network keys returning prefix and address keys.

    @param network: A dict of network-related definition containing prefix,
        netmask and address_keys.
    @param address_keys: A tuple of keys to search for representing the address
        or cidr. The first address_key discovered will be used for
        normalization.

    @returns: A dict containing normalized prefix and matching addr_key.
    """
    net = dict((k, v) for k, v in network.items() if v)
    addr_key = None
    for key in address_keys:
        if net.get(key):
            addr_key = key
            break
    if not addr_key:
        message = "No config network address keys [%s] found in %s" % (
            ",".join(address_keys),
            network,
        )
        LOG.error(message)
        raise ValueError(message)

    addr = str(net.get(addr_key))
    if not is_ip_network(addr):
        LOG.error("Address %s is not a valid ip network", addr)
        raise ValueError(f"Address {addr} is not a valid ip address")

    ipv6 = is_ipv6_network(addr)
    ipv4 = is_ipv4_network(addr)

    netmask = net.get("netmask")
    if "/" in addr:
        addr_part, _, maybe_prefix = addr.partition("/")
        net[addr_key] = addr_part
        if ipv6:
            # this supports input of ffff:ffff:ffff::
            prefix = ipv6_mask_to_net_prefix(maybe_prefix)
        elif ipv4:
            # this supports input of 255.255.255.0
            prefix = ipv4_mask_to_net_prefix(maybe_prefix)
        else:
            # In theory this never happens, is_ip_network() should catch all
            # invalid networks
            LOG.error("Address %s is not a valid ip network", addr)
            raise ValueError(f"Address {addr} is not a valid ip address")
    elif "prefix" in net:
        prefix = int(net["prefix"])
    elif netmask and ipv4:
        prefix = ipv4_mask_to_net_prefix(netmask)
    elif netmask and ipv6:
        prefix = ipv6_mask_to_net_prefix(netmask)
    else:
        prefix = 64 if ipv6 else 24

    if "prefix" in net and str(net["prefix"]) != str(prefix):
        LOG.warning(
            "Overwriting existing 'prefix' with '%s' in network info: %s",
            prefix,
            net,
        )
    net["prefix"] = prefix

    if ipv6:
        # TODO: we could/maybe should add this back with the very uncommon
        # 'netmask' for ipv6.  We need a 'net_prefix_to_ipv6_mask' for that.
        if "netmask" in net:
            del net["netmask"]
    elif ipv4:
        net["netmask"] = net_prefix_to_ipv4_mask(net["prefix"])

    return net