Beispiel #1
0
def configure(update):
    hostConfig = update.new.getCache('hostConfig')

    snapd = SnapdClient(logging=True, wait_async=True)

    enabled = datastruct.getValue(hostConfig, "zerotier.enabled", False)
    if enabled:
        if not os.path.exists("/snap/zerotier-one"):
            snapd.installSnap('zerotier-one')

        snapd.updateSnap('zerotier-one', {'action': 'enable'})

        # These interfaces are not automatically connected, so take care of that.
        snapd.connect('zerotier-one', 'network-control', 'core',
                      'network-control')
        snapd.connect('paradrop-daemon', 'zerotier-control', 'zerotier-one',
                      'zerotier-control')

        old_networks = set()
        for network in get_networks():
            old_networks.add(network['id'])

        new_networks = set(
            datastruct.getValue(hostConfig, "zerotier.networks", []))

        # Leave old networks and join new networks.
        for net in (old_networks - new_networks):
            manage_network(net, action="leave")
        for net in (new_networks - old_networks):
            manage_network(net, action="join")

    else:
        # Disable the zerotier service.
        snapd.updateSnap('zerotier-one', {'action': 'disable'})
def getSubnetReservations(exclude=None):
    """
    Get current set of subnet reservations.

    Returns an instance of SubnetReservationSet.

    exclude: name of chute whose reservations should be excluded
    """
    reservations = SubnetReservationSet()

    if exclude != settings.RESERVED_CHUTE:
        hostConfig = prepareHostConfig()
        ipaddr = datastruct.getValue(hostConfig, 'lan.ipaddr', None)
        netmask = datastruct.getValue(hostConfig, 'lan.netmask', None)
        if ipaddr is not None and netmask is not None:
            network = ipaddress.ip_network(u'{}/{}'.format(ipaddr, netmask),
                                           strict=False)
            reservations.add(network)

    for chute in ChuteStorage.chuteList.values():
        if chute.name == exclude:
            continue

        for iface in chute.getCache('networkInterfaces'):
            if 'subnet' not in iface:
                continue

            subnet = iface['subnet']
            reservations.add(subnet)

    return reservations
Beispiel #3
0
def getSubnetReservations(exclude=None):
    """
    Get current set of subnet reservations.

    Returns an instance of SubnetReservationSet.

    exclude: name of chute whose reservations should be excluded
    """
    reservations = SubnetReservationSet()

    if exclude != constants.RESERVED_CHUTE_NAME:
        hostConfig = prepareHostConfig()
        ipaddr = datastruct.getValue(hostConfig, 'lan.ipaddr', None)
        netmask = datastruct.getValue(hostConfig, 'lan.netmask', None)
        if ipaddr is not None and netmask is not None:
            network = ipaddress.ip_network(u'{}/{}'.format(ipaddr, netmask),
                    strict=False)
            reservations.add(network)

    for chute in ChuteStorage.chuteList.values():
        if chute.name == exclude:
            continue

        for iface in chute.getCache('networkInterfaces'):
            if 'subnet' not in iface:
                continue

            subnet = iface['subnet']
            reservations.add(subnet)

    return reservations
Beispiel #4
0
def configure_telemetry(update):
    global telemetry_looping_call

    hostConfig = update.new.getCache('hostConfig')

    enabled = datastruct.getValue(hostConfig, 'telemetry.enabled', False)
    interval = datastruct.getValue(hostConfig, 'telemetry.interval', 60)

    # Cancel the old looping call.
    if telemetry_looping_call is not None:
        telemetry_looping_call.stop()
        telemetry_looping_call = None

    if enabled and interval > 0:
        telemetry_looping_call = LoopingCall(reporting.sendTelemetryReport)
        telemetry_looping_call.start(interval, now=False)
Beispiel #5
0
    def zoneFirewallSettings(name):
        # Create zone entry with defaults (input, output, forward policies and
        # other configuration).
        #
        # Make a copy of the object from hostconfig because we modify it.
        options = datastruct.getValue(hostConfig,
                name+".firewall.defaults", {}).copy()
        options['name'] = name
        options['network'] = [name]
        builder.add("firewall", "zone", options)

        # Add forwarding entries (rules that allow traffic to move from one
        # zone to another).
        rules = datastruct.getValue(hostConfig, name+".firewall.forwarding", [])
        for rule in rules:
            builder.add("firewall", "forwarding", rule)
Beispiel #6
0
def chooseSubnet(update, cfg, iface):
    reservations = update.new.getCache('subnetReservations')

    # Check if the chute configuration requests a specific network.
    #
    # TODO: Implement a mode where a chute can request a preferred network, but
    # do not fail if it is unavailable.
    requested = cfg.get('ipv4_network', None)
    if requested is not None:
        network = ipaddress.ip_network(unicode(requested))
        if network in reservations:
            raise Exception("Could not assign network {}, network already in use".format(
                requested))
        else:
            reservations.add(network)
            return network

    # Get subnet configuration settings from host configuration.
    host_config = update.new.getCache('hostConfig')
    network_pool = select_chute_subnet_pool(host_config)
    prefix_size = datastruct.getValue(host_config,
            "system.chutePrefixSize", SUBNET_SIZE)

    network = ipaddress.ip_network(unicode(network_pool))
    if prefix_size < network.prefixlen:
        raise Exception("Router misconfigured: prefix size {} is invalid for network {}".format(
            prefix_size, network))

    subnets = network.subnets(new_prefix=prefix_size)
    for subnet in subnets:
        if subnet not in reservations:
            reservations.add(subnet)
            return subnet

    raise Exception("Could not find an available subnet")
Beispiel #7
0
def configure_telemetry(update):
    global telemetry_looping_call

    hostConfig = update.cache_get('hostConfig')

    enabled = datastruct.getValue(hostConfig, 'telemetry.enabled', False)
    interval = datastruct.getValue(hostConfig, 'telemetry.interval', 60)

    # Cancel the old looping call.
    if telemetry_looping_call is not None:
        telemetry_looping_call.stop()
        telemetry_looping_call = None

    if enabled and interval > 0:
        telemetry_looping_call = LoopingCall(reporting.sendTelemetryReport)
        telemetry_looping_call.start(interval, now=False)
Beispiel #8
0
    def zoneFirewallSettings(name):
        # Create zone entry with defaults (input, output, forward policies and
        # other configuration).
        #
        # Make a copy of the object from hostconfig because we modify it.
        options = datastruct.getValue(hostConfig,
                name+".firewall.defaults", {}).copy()
        options['name'] = name
        options['network'] = [name]
        builder.add("firewall", "zone", options)

        # Add forwarding entries (rules that allow traffic to move from one
        # zone to another).
        rules = datastruct.getValue(hostConfig, name+".firewall.forwarding", [])
        for rule in rules:
            builder.add("firewall", "forwarding", rule)
Beispiel #9
0
def setHostConfig(update):
    """
    Write host configuration to persistent storage.

    Read host configuration from hostConfig.
    """
    config = update.cache_get('hostConfig')
    setAutoUpdate(datastruct.getValue(config, "system.autoUpdate", True))
    save(config)
Beispiel #10
0
def revertHostConfig(update):
    """
    Restore host configuration from before update.

    Uses oldHostConfig cache entry.
    """
    config = update.cache_get('oldHostConfig')
    setAutoUpdate(datastruct.getValue(config, "system.autoUpdate", True))
    save(config)
Beispiel #11
0
def configure(update):
    snap_name = os.environ.get('SNAP_NAME', None)
    if snap_name is None:
        # It seems we are not running as a snap, so this code is not going to
        # work.
        out.info("SNAP_NAME environment variable not found.")
        return

    hostConfig = update.cache_get('hostConfig')

    snapd = SnapdClient(logging=True, wait_async=True)

    enabled = datastruct.getValue(hostConfig, "zerotier.enabled", False)
    if enabled:
        if not os.path.exists("/snap/zerotier-one"):
            snapd.installSnap('zerotier-one')

        snapd.updateSnap('zerotier-one', {'action': 'enable'})

        # These interfaces are not automatically connected, so take care of that.
        snapd.connect('zerotier-one', 'network-control', 'core',
                'network-control')
        snapd.connect(snap_name, 'zerotier-control', 'zerotier-one',
                'zerotier-control')

        old_networks = set()
        for network in get_networks():
            old_networks.add(network['id'])

        new_networks = set(datastruct.getValue(hostConfig,
                "zerotier.networks", []))

        # Leave old networks and join new networks.
        for net in (old_networks - new_networks):
            manage_network(net, action="leave")
        for net in (new_networks - old_networks):
            manage_network(net, action="join")

    else:
        # Disable the zerotier service.
        snapd.updateSnap('zerotier-one', {'action': 'disable'})
Beispiel #12
0
def applyWaitOnlineFix(update):
    """
    Configure systemd-networkd to wait for WAN interface only.

    This fixes the long delay on system startup while it waits for all network
    interfaces to be connected.
    """
    hostConfig = update.cache_get('hostConfig')
    ifname = datastruct.getValue(hostConfig, 'wan.interface', None)

    if ifname is not None:
        with open(WAIT_ONLINE_FILE, "w") as output:
            output.write(WAIT_ONLINE_TEMPLATE.format(interface=ifname))
Beispiel #13
0
def configure(update):
    hostConfig = update.cache_get('hostConfig')

    # Check if ZeroTier is enabled in the node configuration and also whether
    # its data directory exists. We prefer not to wait for it if it is not even
    # installed.
    enabled = datastruct.getValue(hostConfig, "zerotier.enabled", False)
    if enabled and os.path.isdir(settings.ZEROTIER_LIB_DIR):
        new_networks = set(datastruct.getValue(hostConfig,
                "zerotier.networks", []))
        wait_for_zerotier()
    else:
        new_networks = set()

    old_networks = set()
    for network in get_networks(ignore_error=not enabled):
        old_networks.add(network['id'])

    # Leave old networks and join new networks.
    for net in (old_networks - new_networks):
        manage_network(net, action="leave")
    for net in (new_networks - old_networks):
        manage_network(net, action="join")
def getDeviceReservations(exclude=None):
    """
    Produce a dictionary mapping device names to DeviceReservations objects
    that describe the current usage of the device.

    The returned type is a defaultdict, so there is no need to check if a key
    exists before accessing it.

    exclude: name of chute whose device reservations should be excluded
    """
    reservations = collections.defaultdict(DeviceReservations)

    if exclude != settings.RESERVED_CHUTE:
        hostConfig = prepareHostConfig()

        wifiInterfaces = hostConfig.get('wifi-interfaces', [])
        for iface in wifiInterfaces:
            if 'device' not in iface:
                continue

            dev = iface['device']
            phy = getWirelessPhyName(dev)
            if phy is not None:
                # It is annoying to do this conversion everywhere, but it would
                # be painful to break compatibility with all of the devices out
                # there that use e.g. wlan0 instead of phy0 in their hostconfig.
                dev = phy

            reservations[dev].add(settings.RESERVED_CHUTE, 'wifi',
                                  iface.get('mode', 'ap'))

        lanInterfaces = datastruct.getValue(hostConfig, 'lan.interfaces', [])
        for iface in lanInterfaces:
            reservations[iface].add(settings.RESERVED_CHUTE, 'lan', None)

    for chute in ChuteStorage.chuteList.values():
        if chute.name == exclude:
            continue

        for iface in chute.getCache('networkInterfaces'):
            dev = iface.get('device', None)

            # Device is not set in cases such as vlan interfaces.
            if dev is None:
                continue

            reservations[dev].add(chute.name, iface['netType'],
                                  iface.get('mode', None))

    return reservations
Beispiel #15
0
def getDeviceReservations(exclude=None):
    """
    Produce a dictionary mapping device names to DeviceReservations objects
    that describe the current usage of the device.

    The returned type is a defaultdict, so there is no need to check if a key
    exists before accessing it.

    exclude: name of chute whose device reservations should be excluded
    """
    reservations = collections.defaultdict(DeviceReservations)

    if exclude != constants.RESERVED_CHUTE_NAME:
        hostConfig = prepareHostConfig()

        wifiInterfaces = hostConfig.get('wifi-interfaces', [])
        for iface in wifiInterfaces:
            if 'device' not in iface:
                continue

            dev = iface['device']
            phy = getWirelessPhyName(dev)
            if phy is not None:
                # It is annoying to do this conversion everywhere, but it would
                # be painful to break compatibility with all of the devices out
                # there that use e.g. wlan0 instead of phy0 in their hostconfig.
                dev = phy

            reservations[dev].add(constants.RESERVED_CHUTE_NAME, 'wifi',
                    iface.get('mode', 'ap'))

        lanInterfaces = datastruct.getValue(hostConfig, 'lan.interfaces', [])
        for iface in lanInterfaces:
            reservations[iface].add(constants.RESERVED_CHUTE_NAME, 'lan', None)

    for chute in ChuteStorage.chuteList.values():
        if chute.name == exclude:
            continue

        for iface in chute.getCache('networkInterfaces'):
            dev = iface.get('device', None)

            # Device is not set in cases such as vlan interfaces.
            if dev is None:
                continue

            reservations[dev].add(chute.name, iface['type'],
                    iface.get('mode', None))

    return reservations
Beispiel #16
0
def configure(update):
    hostConfig = update.cache_get('hostConfig')

    # Check if ZeroTier is enabled in the node configuration and also whether
    # its data directory exists. We prefer not to wait for it if it is not even
    # installed.
    enabled = datastruct.getValue(hostConfig, "zerotier.enabled", False)
    if enabled and os.path.isdir(settings.ZEROTIER_LIB_DIR):
        new_networks = set(
            datastruct.getValue(hostConfig, "zerotier.networks", []))
        wait_for_zerotier()
    else:
        new_networks = set()

    old_networks = set()
    for network in get_networks(ignore_error=not enabled):
        old_networks.add(network['id'])

    # Leave old networks and join new networks.
    for net in (old_networks - new_networks):
        manage_network(net, action="leave")
    for net in (new_networks - old_networks):
        manage_network(net, action="join")
Beispiel #17
0
def select_brlan_address(hostConfig):
    """
    Select IP address and netmask to use for LAN bridge.

    Behavior depends on the proto field, which can either be 'auto' or
    'static'. When proto is set to 'auto', we check the WAN interface address
    and choose either 10.0.0.0 or 192.168.0.1 to avoid conflict. Otherwise,
    when proto is set to 'static', we use the specified address.
    """
    proto = datastruct.getValue(hostConfig, 'lan.proto', 'auto')
    netmask = datastruct.getValue(hostConfig, 'lan.netmask', '255.255.255.0')
    wan_ifname = datastruct.getValue(hostConfig, 'wan.interface', 'eth0')

    if proto == 'auto':
        addresses = netifaces.ifaddresses(wan_ifname)
        ipv4_addrs = addresses.get(netifaces.AF_INET, [])

        if any(x['addr'].startswith("10.") for x in ipv4_addrs):
            return "192.168.0.1", netmask
        else:
            return "10.0.0.1", netmask

    else:
        return hostConfig['lan']['ipaddr'], netmask
Beispiel #18
0
def select_chute_subnet_pool(host_config):
    """
    Select IP subnet to use as pool for chutes.

    Behavior depends on whether a static subnet is configured or auto
    configuration is requested. If the chuteSubnetPool option is set to 'auto',
    then we check the WAN interface address and choose either 10.128.0.0/9 or
    192.168.128.0/17 to avoid conflict.  Otherwise, we used the specified
    subnet.
    """
    pool = datastruct.getValue(host_config, "system.chuteSubnetPool", 'auto')
    wan_ifname = datastruct.getValue(host_config, 'wan.interface', 'eth0')

    if pool == 'auto':
        addresses = netifaces.ifaddresses(wan_ifname)
        ipv4_addrs = addresses.get(netifaces.AF_INET, [])

        if any(x['addr'].startswith("10.") for x in ipv4_addrs):
            return "192.168.128.0/17"
        else:
            return "10.128.0.0/9"

    else:
        return pool
Beispiel #19
0
def select_brlan_address(hostConfig):
    """
    Select IP address and netmask to use for LAN bridge.

    Behavior depends on the proto field, which can either be 'auto' or
    'static'. When proto is set to 'auto', we check the WAN interface address
    and choose either 10.0.0.0 or 192.168.0.1 to avoid conflict. Otherwise,
    when proto is set to 'static', we use the specified address.
    """
    proto = datastruct.getValue(hostConfig, 'lan.proto', 'auto')
    netmask = datastruct.getValue(hostConfig, 'lan.netmask', '255.255.255.0')
    wan_ifname = datastruct.getValue(hostConfig, 'wan.interface', 'eth0')

    if proto == 'auto':
        addresses = netifaces.ifaddresses(wan_ifname)
        ipv4_addrs = addresses.get(netifaces.AF_INET, [])

        if any(x['addr'].startswith("10.") for x in ipv4_addrs):
            return "192.168.0.1", netmask
        else:
            return "10.0.0.1", netmask

    else:
        return hostConfig['lan']['ipaddr'], netmask
Beispiel #20
0
def select_chute_subnet_pool(host_config):
    """
    Select IP subnet to use as pool for chutes.

    Behavior depends on whether a static subnet is configured or auto
    configuration is requested. If the chuteSubnetPool option is set to 'auto',
    then we check the WAN interface address and choose either 10.128.0.0/9 or
    192.168.128.0/17 to avoid conflict.  Otherwise, we used the specified
    subnet.
    """
    pool = datastruct.getValue(host_config, "system.chuteSubnetPool", 'auto')
    wan_ifname = datastruct.getValue(host_config, 'wan.interface', 'eth0')

    if pool == 'auto':
        addresses = netifaces.ifaddresses(wan_ifname)
        ipv4_addrs = addresses.get(netifaces.AF_INET, [])

        if any(x['addr'].startswith("10.") for x in ipv4_addrs):
            return "192.168.128.0/17"
        else:
            return "10.128.0.0/9"

    else:
        return pool
Beispiel #21
0
def handleMissingWiFi(hostConfig):
    """
    Take appropriate action in response to missing WiFi devices.

    Depending on the host configuration, we may either emit a warning or reboot
    the system.
    """
    # Missing WiFi devices - check what we should do.
    action = datastruct.getValue(hostConfig, "system.onMissingWiFi")
    if action == "reboot":
        out.warn("Missing WiFi devices, system will be rebooted.")
        cmd = ["shutdown", "-r", "now"]
        subprocess.call(cmd)

    elif action == "warn":
        out.warn("Missing WiFi devices.")
Beispiel #22
0
def handleMissingWiFi(hostConfig):
    """
    Take appropriate action in response to missing WiFi devices.

    Depending on the host configuration, we may either emit a warning or reboot
    the system.
    """
    # Missing WiFi devices - check what we should do.
    action = datastruct.getValue(hostConfig, "system.onMissingWiFi")
    if action == "reboot":
        out.warn("Missing WiFi devices, system will be rebooted.")
        cmd = ["shutdown", "-r", "now"]
        subprocess.call(cmd)

    elif action == "warn":
        out.warn("Missing WiFi devices.")
Beispiel #23
0
def checkSystemDevices(update):
    """
    Check whether expected devices are present.

    This may reboot the machine if devices are missing and the host config is
    set to do that.
    """
    devices = update.new.getCache('networkDevices')
    hostConfig = update.new.getCache('hostConfig')

    if len(devices['wifi']) == 0:
        # No WiFi devices - check what we should do.
        action = datastruct.getValue(hostConfig, "system.onMissingWiFi")
        if action == "reboot":
            out.warn("No WiFi devices were detected, system will be rebooted.")
            cmd = ["shutdown", "-r", "now"]
            subprocess.call(cmd)

        elif action == "warn":
            out.warn("No WiFi devices were detected.")
Beispiel #24
0
def chooseSubnet(update, cfg, iface):
    reservations = update.cache_get('subnetReservations')

    # Check if the chute configuration requests a specific network.
    #
    # TODO: Implement a mode where a chute can request a preferred network, but
    # do not fail if it is unavailable.
    requested = cfg.get('ipv4_network', None)
    if requested is not None:
        network = ipaddress.ip_network(str(requested))
        if network in reservations:
            raise Exception(
                "Could not assign network {}, network already in use".format(
                    requested))
        else:
            reservations.add(network)
            return network

    # Get subnet configuration settings from host configuration.
    host_config = update.cache_get('hostConfig')
    network_pool = select_chute_subnet_pool(host_config)
    prefix_size = datastruct.getValue(host_config, "system.chutePrefixSize",
                                      SUBNET_SIZE)

    network = ipaddress.ip_network(str(network_pool))
    if prefix_size < network.prefixlen:
        raise Exception(
            "Router misconfigured: prefix size {} is invalid for network {}".
            format(prefix_size, network))

    subnets = network.subnets(new_prefix=prefix_size)
    for subnet in subnets:
        if subnet not in reservations:
            reservations.add(subnet)
            return subnet

    raise Exception("Could not find an available subnet")
def test_getValue():
    data = {"a": [1, 2, 3]}
    assert datastruct.getValue(data, "a.1") == 2
    assert datastruct.getValue(data, "a.3") is None
    assert datastruct.getValue(data, "a.1.b") is None
Beispiel #26
0
def setSystemDevices(update):
    """
    Initialize system configuration files.

    This section should only be run for host configuration updates.

    Creates basic sections that all chutes require such as the "wan" interface.
    """
    hostConfig = update.cache_get('hostConfig')
    networkDevices = update.cache_get('networkDevices')

    builder = UCIBuilder()

    # This section defines the default input, output, and forward policies for
    # the firewall.
    options = datastruct.getValue(hostConfig, "firewall.defaults", {})
    builder.add("firewall", "defaults", options)

    def zoneFirewallSettings(name):
        # Create zone entry with defaults (input, output, forward policies and
        # other configuration).
        #
        # Make a copy of the object from hostconfig because we modify it.
        options = datastruct.getValue(hostConfig,
                name+".firewall.defaults", {}).copy()
        options['name'] = name
        options['network'] = [name]
        builder.add("firewall", "zone", options)

        # Add forwarding entries (rules that allow traffic to move from one
        # zone to another).
        rules = datastruct.getValue(hostConfig, name+".firewall.forwarding", [])
        for rule in rules:
            builder.add("firewall", "forwarding", rule)

    if 'wan' in hostConfig:
        options = dict()
        options['ifname'] = hostConfig['wan']['interface']
        options['proto'] = "dhcp"
        builder.add("network", "interface", options, name="wan")

        zoneFirewallSettings("wan")

        options = {
            "enabled": 0
        }
        builder.add("qos", "interface", options, name="wan")

    if 'lan' in hostConfig:
        options = dict()
        options['type'] = "bridge"
        options['bridge_empty'] = "1"
        options['proto'] = 'static'
        options['ipaddr'], options['netmask'] = select_brlan_address(hostConfig)
        options['ifname'] = hostConfig['lan']['interfaces']
        builder.add("network", "interface", options, name="lan")

        if 'dhcp' in hostConfig['lan']:
            dhcp = hostConfig['lan']['dhcp']

            options = {
                'interface': 'lan',
                'domain': settings.LOCAL_DOMAIN
            }
            builder.add("dhcp", "dnsmasq", options)

            options = {
                'interface': 'lan',
                'start': dhcp['start'],
                'limit': dhcp['limit'],
                'leasetime': dhcp['leasetime']
            }
            builder.add("dhcp", "dhcp", options, name="lan")

            options = {
                'name': settings.LOCAL_DOMAIN,
                'ip': hostConfig['lan']['ipaddr']
            }
            builder.add("dhcp", "domain", options)

        zoneFirewallSettings("lan")

        options = {
            "enabled": 0
        }
        builder.add("qos", "interface", options, name="lan")

    # Automatically generate loopback section.  There is generally not much to
    # configure for loopback, but we could add support to the host
    # configuration.
    options = {
        'ifname': ['lo'],
        'proto': 'static',
        'ipaddr': '127.0.0.1',
        'netmask': '255.0.0.0'
    }
    builder.add("network", "interface", options, name="loopback")

    options = {
        'name': 'loopback',
        'masq': '0',
        'conntrack': '1',
        'input': 'ACCEPT',
        'forward': 'ACCEPT',
        'output': 'ACCEPT',
        'network': ['loopback']
    }
    builder.add("firewall", "zone", options)

    wifi = hostConfig.get('wifi', [])
    try:
        readHostconfigWifi(wifi, networkDevices, builder)
    except DeviceNotFoundException:
        handleMissingWiFi(hostConfig)

    wifiInterfaces = hostConfig.get('wifi-interfaces', [])
    readHostconfigWifiInterfaces(wifiInterfaces, networkDevices, builder)

    vlanInterfaces = hostConfig.get('vlan-interfaces', [])
    readHostconfigVlan(vlanInterfaces, builder)

    # Add additional firewall rules.
    rules = datastruct.getValue(hostConfig, "firewall.rules", [])
    for rule in rules:
        builder.add("firewall", "rule", rule)

    # Write all of the changes to UCI files at once.
    builder.write()
Beispiel #27
0
def readHostconfigVlan(vlanInterfaces, builder):
    for interface in vlanInterfaces:
        name = interface['name']

        options = {
            'proto': interface['proto']
        }

        if interface['proto'] == 'static':
            options['ipaddr'] = interface['ipaddr']
            options['netmask'] = interface['netmask']

        # TODO: Support VLANs on interfaces other than the lan bridge.
        ifname = "br-lan.{}".format(interface['id'])
        options['ifname'] = [ifname]

        builder.add("network", "interface", options, name=name)

        if 'dhcp' in interface:
            dhcp = interface['dhcp']

            options = {}
            options['interface'] = [name]
            builder.add("dhcp", "dnsmasq", options)

            options = {
                'interface': name,
                'start': dhcp['start'],
                'limit': dhcp['limit'],
                'leasetime': dhcp['leasetime']
            }
            builder.add("dhcp", "dhcp", options, name=name)

            # Allow DNS requests.
            options = {
                'src': name,
                'proto': 'udp',
                'dest_port': 53,
                'target': 'ACCEPT'
            }
            builder.add("firewall", "rule", options)

            # Allow DHCP requests.
            options = {
                'src': name,
                'proto': 'udp',
                'dest_port': 67,
                'target': 'ACCEPT'
            }
            builder.add("firewall", "rule", options)

        # Make a zone entry with defaults.
        options = datastruct.getValue(interface,
                "firewall.defaults", {}).copy()
        options['name'] = name
        options['network'] = [name]
        builder.add("firewall", "zone", options)

        # Add forwarding entries.
        rules = datastruct.getValue(interface, "firewall.forwarding", [])
        for rule in rules:
            builder.add("firewall", "forwarding", rule)

        rules = datastruct.getValue(interface, "firewall.rules", [])
        for rule in rules:
            builder.add("firewall", "rule", rule)
Beispiel #28
0
def readHostconfigVlan(vlanInterfaces, builder):
    for interface in vlanInterfaces:
        name = interface['name']

        options = {'proto': interface['proto']}

        if interface['proto'] == 'static':
            options['ipaddr'] = interface['ipaddr']
            options['netmask'] = interface['netmask']

        # TODO: Support VLANs on interfaces other than the lan bridge.
        ifname = "br-lan.{}".format(interface['id'])
        options['ifname'] = [ifname]

        builder.add("network", "interface", options, name=name)

        if 'dhcp' in interface:
            dhcp = interface['dhcp']

            options = {}
            options['interface'] = [name]
            builder.add("dhcp", "dnsmasq", options)

            options = {
                'interface': name,
                'start': dhcp['start'],
                'limit': dhcp['limit'],
                'leasetime': dhcp['leasetime']
            }
            builder.add("dhcp", "dhcp", options, name=name)

            # Allow DNS requests.
            options = {
                'src': name,
                'proto': 'udp',
                'dest_port': 53,
                'target': 'ACCEPT'
            }
            builder.add("firewall", "rule", options)

            # Allow DHCP requests.
            options = {
                'src': name,
                'proto': 'udp',
                'dest_port': 67,
                'target': 'ACCEPT'
            }
            builder.add("firewall", "rule", options)

        # Make a zone entry with defaults.
        options = datastruct.getValue(interface, "firewall.defaults",
                                      {}).copy()
        options['name'] = name
        options['network'] = [name]
        builder.add("firewall", "zone", options)

        # Add forwarding entries.
        rules = datastruct.getValue(interface, "firewall.forwarding", [])
        for rule in rules:
            builder.add("firewall", "forwarding", rule)

        rules = datastruct.getValue(interface, "firewall.rules", [])
        for rule in rules:
            builder.add("firewall", "rule", rule)
def test_getValue():
    data = {"a": [1, 2, 3]}
    assert datastruct.getValue(data, "a.1") == 2
    assert datastruct.getValue(data, "a.3") is None
    assert datastruct.getValue(data, "a.1.b") is None
Beispiel #30
0
def setSystemDevices(update):
    """
    Initialize system configuration files.

    This section should only be run for host configuration updates.

    Creates basic sections that all chutes require such as the "wan" interface.
    """
    hostConfig = update.cache_get('hostConfig')
    networkDevices = update.cache_get('networkDevices')

    builder = UCIBuilder()

    # This section defines the default input, output, and forward policies for
    # the firewall.
    options = datastruct.getValue(hostConfig, "firewall.defaults", {})
    builder.add("firewall", "defaults", options)

    def zoneFirewallSettings(name):
        # Create zone entry with defaults (input, output, forward policies and
        # other configuration).
        #
        # Make a copy of the object from hostconfig because we modify it.
        options = datastruct.getValue(hostConfig, name + ".firewall.defaults",
                                      {}).copy()
        options['name'] = name
        options['network'] = [name]
        builder.add("firewall", "zone", options)

        # Add forwarding entries (rules that allow traffic to move from one
        # zone to another).
        rules = datastruct.getValue(hostConfig, name + ".firewall.forwarding",
                                    [])
        for rule in rules:
            builder.add("firewall", "forwarding", rule)

    if 'wan' in hostConfig:
        options = dict()
        options['ifname'] = hostConfig['wan']['interface']
        options['proto'] = "dhcp"
        builder.add("network", "interface", options, name="wan")

        zoneFirewallSettings("wan")

        options = {"enabled": 0}
        builder.add("qos", "interface", options, name="wan")

    if 'lan' in hostConfig:
        options = dict()
        options['type'] = "bridge"
        options['bridge_empty'] = "1"
        options['proto'] = 'static'
        options['ipaddr'], options['netmask'] = select_brlan_address(
            hostConfig)
        options['ifname'] = hostConfig['lan']['interfaces']
        builder.add("network", "interface", options, name="lan")

        if 'dhcp' in hostConfig['lan']:
            dhcp = hostConfig['lan']['dhcp']

            options = {'interface': 'lan', 'domain': settings.LOCAL_DOMAIN}
            builder.add("dhcp", "dnsmasq", options)

            options = {
                'interface': 'lan',
                'start': dhcp['start'],
                'limit': dhcp['limit'],
                'leasetime': dhcp['leasetime']
            }
            builder.add("dhcp", "dhcp", options, name="lan")

            options = {
                'name': settings.LOCAL_DOMAIN,
                'ip': hostConfig['lan']['ipaddr']
            }
            builder.add("dhcp", "domain", options)

        zoneFirewallSettings("lan")

        options = {"enabled": 0}
        builder.add("qos", "interface", options, name="lan")

    # Automatically generate loopback section.  There is generally not much to
    # configure for loopback, but we could add support to the host
    # configuration.
    options = {
        'ifname': ['lo'],
        'proto': 'static',
        'ipaddr': '127.0.0.1',
        'netmask': '255.0.0.0'
    }
    builder.add("network", "interface", options, name="loopback")

    options = {
        'name': 'loopback',
        'masq': '0',
        'conntrack': '1',
        'input': 'ACCEPT',
        'forward': 'ACCEPT',
        'output': 'ACCEPT',
        'network': ['loopback']
    }
    builder.add("firewall", "zone", options)

    wifi = hostConfig.get('wifi', [])
    try:
        readHostconfigWifi(wifi, networkDevices, builder)
    except DeviceNotFoundException:
        handleMissingWiFi(hostConfig)

    wifiInterfaces = hostConfig.get('wifi-interfaces', [])
    readHostconfigWifiInterfaces(wifiInterfaces, networkDevices, builder)

    vlanInterfaces = hostConfig.get('vlan-interfaces', [])
    readHostconfigVlan(vlanInterfaces, builder)

    # Add additional firewall rules.
    rules = datastruct.getValue(hostConfig, "firewall.rules", [])
    for rule in rules:
        builder.add("firewall", "rule", rule)

    # Write all of the changes to UCI files at once.
    builder.write()