def getNetworkConfigWifi(update, name, cfg, iface): dtype, mode = split_interface_type(cfg['type']) # Later code still depends on the mode field. iface['mode'] = mode # Generate a name for the new interface in the host. iface['externalIntf'] = chooseExternalIntf(update, iface) if len(iface['externalIntf']) > MAX_INTERFACE_NAME_LEN: out.warn("Interface name ({}) is too long\n".format( iface['externalIntf'])) raise Exception("Interface name is too long") wireless = cfg.get("wireless", {}) iface['wireless'] = wireless if iface['type'] in ["wifi-ap", "wifi-sta"]: # Check for required fields. res = pdutils.check(wireless, dict, ['ssid']) if res: out.warn('WiFi network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface['ssid'] = wireless['ssid'] # Optional encryption settings getWifiKeySettings(wireless, iface) # Give a warning if the dhcp block is missing, since it is likely # that developers will want a DHCP server to go with their AP. if 'dhcp' not in cfg: out.warn("No dhcp block found for interface {}; " "will not run a DHCP server".format(name))
def getNetworkConfigWifi(update, name, cfg, iface): dtype, mode = split_interface_type(cfg['type']) # Later code still depends on the mode field. iface['mode'] = mode # Generate a name for the new interface in the host. iface['externalIntf'] = chooseExternalIntf(update, iface) if len(iface['externalIntf']) > constants.MAX_INTERFACE_NAME_LEN: out.warn("Interface name ({}) is too long\n".format( iface['externalIntf'])) raise Exception("Interface name is too long") wireless = cfg.get("wireless", {}) iface['wireless'] = wireless if iface['type'] in ["wifi-ap", "wifi-sta"]: # Check for required fields. res = pdutils.check(wireless, dict, ['ssid']) if res: out.warn('WiFi network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface['ssid'] = wireless['ssid'] # Optional encryption settings getWifiKeySettings(wireless, iface) # Give a warning if the dhcp block is missing, since it is likely # that developers will want a DHCP server to go with their AP. if 'dhcp' not in cfg: out.warn("No dhcp block found for interface {}; " "will not run a DHCP server".format(name))
def getNetworkConfigWifi(update, name, cfg, iface): iface['mode'] = cfg.get("mode", "ap") # Make a dictionary of old interfaces. Any new interfaces that are # identical to an old one do not need to be changed. oldInterfaces = getInterfaceDict(update.old) # Generate a name for the new interface in the host. iface['externalIntf'] = chooseExternalIntf(update, iface) if len(iface['externalIntf']) > MAX_INTERFACE_NAME_LEN: out.warn("Interface name ({}) is too long\n".format(iface['externalIntf'])) raise Exception("Interface name is too long") if iface['mode'] in ["ap", "sta"]: # Check for required fields. res = pdutils.check(cfg, dict, ['ssid']) if res: out.warn('WiFi network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface['ssid'] = cfg['ssid'] # Optional encryption settings getWifiKeySettings(cfg, iface) # Give a warning if the dhcp block is missing, since it is likely # that developers will want a DHCP server to go with their AP. if 'dhcp' not in cfg: out.warn("No dhcp block found for interface {}; " "will not run a DHCP server".format(name))
def getNetworkConfigVlan(update, name, cfg, iface): res = pdutils.check(cfg, dict, ['vlan_id']) if res: raise Exception("Interface definition missing field(s)") # Generate a name for the new interface in the host. iface['externalIntf'] = "br-lan.{}".format(cfg['vlan_id']) # Prevent multiple chutes from using the same VLAN. reservations = update.cache_get('interfaceReservations') if iface['externalIntf'] in reservations: raise Exception("Interface {} already in use".format( iface['externalIntf'])) reservations.add(iface['externalIntf'])
def getVirtDHCPSettings(update): """ Looks at the runtime rules the developer defined to see if they want a dhcp server. If so it generates the data and stores it into the chute cache key:virtDHCPSettings. """ interfaces = update.cache_get('networkInterfaces') if interfaces is None: return dhcpSettings = list() for iface in interfaces: # Only look at interfaces with DHCP server requested. if 'dhcp' not in iface: continue dhcp = iface['dhcp'] # Construct a path for the lease file that will be visible inside the # chute. leasefile = os.path.join( update.cache_get('externalSystemDir'), "dnsmasq-{}.leases".format(iface['name']) ) # NOTE: Having one dnsmasq section for each interface deviates from how # OpenWRT does things, where they assume a single instance of dnsmasq # will be handling all DHCP and DNS needs. config = {'type': 'dnsmasq'} options = { 'leasefile': leasefile, 'interface': [iface['externalIntf']] } # Optional: developer can pass in a list of DNS nameservers to use # instead of the system default. # # This path -> clients query our dnsmasq server; dnsmasq uses the # specified nameservers and caches the results. if DNSMASQ_CACHE_ENABLED and 'dns' in dhcp: options['noresolv'] = '1' options['server'] = dhcp['dns'] # Disable authoritative mode if serving as a relay. relay = dhcp.get('relay', None) if relay is not None: options['authoritative'] = False dhcpSettings.append((config, options)) # Check for fields that are required if not in relay mode. res = pdutils.check(dhcp, dict, ['lease', 'start', 'limit']) if relay is None and res: out.warn('DHCP server definition {}\n'.format(res)) raise Exception("DHCP server definition missing field(s)") config = {'type': 'dhcp', 'name': iface['externalIntf']} options = { 'interface': iface['externalIntf'], 'start': dhcp.get('start', None), 'limit': dhcp.get('limit', None), 'leasetime': dhcp.get('lease', None), 'dhcp_option': [] } # This option tells clients that the router is the interface inside the # chute not the one in the host. options['dhcp_option'].append("option:router,{}".format(iface['internalIpaddr'])) # Optional: developer can pass in a list of DNS nameservers to use # instead of the system default. # # This path -> clients receive the list of DNS servers and query them # directly. if not DNSMASQ_CACHE_ENABLED and 'dns' in dhcp: options['dhcp_option'].append(",".join(["option:dns-server"] + dhcp['dns'])) # Interpret the optional DHCP relay configuration. # - string: interpret as the IP address of the relay server. # - list: interpret as list of strings to pass to dnsmasq (--dhcp-relay options). if isinstance(relay, six.string_types): # TODO: Set the optional third argument (interface) to the name of # the network interface on which we expect DHCP response. This # could be the WAN interface or it could be VPN interface. options['relay'] = ["{},{}".format(iface['externalIpaddr'], relay)] elif isinstance(relay, list): options['relay'] = relay dhcpSettings.append((config, options)) update.cache_set('virtDHCPSettings', dhcpSettings)
def getVirtDHCPSettings(update): """ Looks at the runtime rules the developer defined to see if they want a dhcp server. If so it generates the data and stores it into the chute cache key:virtDHCPSettings. """ interfaces = update.cache_get('networkInterfaces') if interfaces is None: return dhcpSettings = list() for iface in interfaces: # Only look at interfaces with DHCP server requested. if 'dhcp' not in iface: continue dhcp = iface['dhcp'] # Construct a path for the lease file that will be visible inside the # chute. leasefile = os.path.join(update.cache_get('externalSystemDir'), "dnsmasq-{}.leases".format(iface['name'])) # NOTE: Having one dnsmasq section for each interface deviates from how # OpenWRT does things, where they assume a single instance of dnsmasq # will be handling all DHCP and DNS needs. config = {'type': 'dnsmasq'} options = { 'leasefile': leasefile, 'interface': [iface['externalIntf']] } # Optional: developer can pass in a list of DNS nameservers to use # instead of the system default. # # This path -> clients query our dnsmasq server; dnsmasq uses the # specified nameservers and caches the results. if DNSMASQ_CACHE_ENABLED and 'dns' in dhcp: options['noresolv'] = '1' options['server'] = dhcp['dns'] # Disable authoritative mode if serving as a relay. relay = dhcp.get('relay', None) if relay is not None: options['authoritative'] = False dhcpSettings.append((config, options)) # Check for fields that are required if not in relay mode. res = pdutils.check(dhcp, dict, ['lease', 'start', 'limit']) if relay is None and res: out.warn('DHCP server definition {}\n'.format(res)) raise Exception("DHCP server definition missing field(s)") config = {'type': 'dhcp', 'name': iface['externalIntf']} options = { 'interface': iface['externalIntf'], 'start': dhcp.get('start', None), 'limit': dhcp.get('limit', None), 'leasetime': dhcp.get('lease', None), 'dhcp_option': [] } # This option tells clients that the router is the interface inside the # chute not the one in the host. options['dhcp_option'].append("option:router,{}".format( iface['internalIpaddr'])) # Optional: developer can pass in a list of DNS nameservers to use # instead of the system default. # # This path -> clients receive the list of DNS servers and query them # directly. if not DNSMASQ_CACHE_ENABLED and 'dns' in dhcp: options['dhcp_option'].append(",".join(["option:dns-server"] + dhcp['dns'])) # Interpret the optional DHCP relay configuration. # - string: interpret as the IP address of the relay server. # - list: interpret as list of strings to pass to dnsmasq (--dhcp-relay options). if isinstance(relay, six.string_types): # TODO: Set the optional third argument (interface) to the name of # the network interface on which we expect DHCP response. This # could be the WAN interface or it could be VPN interface. options['relay'] = ["{},{}".format(iface['externalIpaddr'], relay)] elif isinstance(relay, list): options['relay'] = relay dhcpSettings.append((config, options)) update.cache_set('virtDHCPSettings', dhcpSettings)
def getNetworkConfig(update): """ For the Chute provided, return the dict object of a 100% filled out configuration set of network configuration. This would include determining what the IP addresses, interfaces names, etc... Store configuration in networkInterfaces cache entry. """ # Notes: # # Fill in the gaps of knowledge between what the dev provided us in their # config and what would be required to add all the config changes to get # the chute working By the end of this function there should be a # cache:networkInterfaces key containing a list of dictionary objects for # each interface we will need to create, including netmasks IP addresses, # etc.. this is important to allow all other modules to know what the IP # addr is for this chute, etc.. # # old code under lib.internal.chs.chutelxc same function name interfaces = list() # Put the list in the cache now (shared reference), so that if we fail out # of this function after partial completion, the abort function can take # care of what made it into the list. update.cache_set('networkInterfaces', interfaces) # Make sure we only assign interfaces to running chutes. if not update.new.isRunning(): return None devices = update.cache_get('networkDevices') for service in update.new.get_services(): for name, cfg in six.iteritems(service.interfaces): # Check for required fields. res = pdutils.check(cfg, dict, ['type']) if res: out.warn('Network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface = { 'name': name, # Name (not used?) 'service': service.name, # Service name 'type': cfg['type'], # Type (wan, lan, wifi) 'internalIntf': cfg['intfName'], # Interface name in chute 'l3bridge': cfg.get('l3bridge', None) # Optional } getInterfaceAddress(update, name, cfg, iface) if cfg['type'].startswith("wifi"): # Try to find a physical device of the requested type. # # Note: we try this first because it can fail, and then we will not try # to allocate any resources for it. device = fulfillDeviceRequest(update, cfg, devices) iface['device'] = device['name'] iface['phy'] = device['phy'] getNetworkConfigWifi(update, name, cfg, iface) elif cfg['type'] == "vlan": getNetworkConfigVlan(update, name, cfg, iface) elif cfg['type'] == "lan": device = fulfillDeviceRequest(update, cfg, devices) iface['device'] = device['name'] getNetworkConfigLan(update, name, cfg, iface) else: raise Exception("Unsupported network type, {}".format( cfg['type'])) # Pass on DHCP configuration if it exists. if 'dhcp' in cfg: iface['dhcp'] = cfg['dhcp'] # TODO: Refactor! The problem here is that `cfg` contains a mixture of # fields, some that we will interpret and some that we will pass on to # pdconf. The result is a lot of logic that tests and copies without # actually accomplishing much. iface['options'] = getExtraOptions(cfg) interfaces.append(iface) update.cache_set('networkInterfaces', interfaces)
def getNetworkConfig(update): """ For the Chute provided, return the dict object of a 100% filled out configuration set of network configuration. This would include determining what the IP addresses, interfaces names, etc... Store configuration in networkInterfaces cache entry. """ # Notes: # # Fill in the gaps of knowledge between what the dev provided us in their # config and what would be required to add all the config changes to get # the chute working By the end of this function there should be a # cache:networkInterfaces key containing a list of dictionary objects for # each interface we will need to create, including netmasks IP addresses, # etc.. this is important to allow all other modules to know what the IP # addr is for this chute, etc.. # # old code under lib.internal.chs.chutelxc same function name interfaces = list() # Put the list in the cache now (shared reference), so that if we fail out # of this function after partial completion, the abort function can take # care of what made it into the list. update.cache_set('networkInterfaces', interfaces) # Deprecated: we set this value in the chute cache here because there is # still code that depends on reading this from the chute storage. This can # be removed when the corresponding call to getCache is removed. update.new.setCache('networkInterfaces', interfaces) # Make sure we only assign interfaces to running chutes. if not update.new.isRunning(): return None devices = update.cache_get('networkDevices') for service in update.new.get_services(): for name, cfg in six.iteritems(service.interfaces): # Check for required fields. res = pdutils.check(cfg, dict, ['type']) if res: out.warn('Network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface = { 'name': name, # Name (not used?) 'service': service.name, # Service name 'type': cfg['type'], # Type (wan, lan, wifi) 'internalIntf': cfg['intfName'], # Interface name in chute 'l3bridge': cfg.get('l3bridge', None) # Optional } getInterfaceAddress(update, name, cfg, iface) if cfg['type'].startswith("wifi"): # Try to find a physical device of the requested type. # # Note: we try this first because it can fail, and then we will not try # to allocate any resources for it. device = fulfillDeviceRequest(update, cfg, devices) iface['device'] = device['name'] iface['phy'] = device['phy'] getNetworkConfigWifi(update, name, cfg, iface) elif cfg['type'] == "vlan": getNetworkConfigVlan(update, name, cfg, iface) elif cfg['type'] == "lan": device = fulfillDeviceRequest(update, cfg, devices) iface['device'] = device['name'] getNetworkConfigLan(update, name, cfg, iface) else: raise Exception("Unsupported network type, {}".format( cfg['type'])) # Pass on DHCP configuration if it exists. if 'dhcp' in cfg: iface['dhcp'] = cfg['dhcp'] # TODO: Refactor! The problem here is that `cfg` contains a mixture of # fields, some that we will interpret and some that we will pass on to # pdconf. The result is a lot of logic that tests and copies without # actually accomplishing much. iface['options'] = getExtraOptions(cfg) interfaces.append(iface) update.cache_set('networkInterfaces', interfaces) # Deprecated: we set this value in the chute cache here because there is # still code that depends on reading this from the chute storage. This can # be removed when the corresponding call to getCache is removed. update.new.setCache('networkInterfaces', interfaces)