def test_add_remove_member(self): members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! for tmp in Section.interfaces("ethernet"): if not '.' in tmp: members.append(tmp) for intf in self._interfaces: cost = 1000 priority = 10 self.session.set(self._base_path + [intf, 'stp']) # assign members to bridge interface for member in members: self.session.set(self._base_path + [intf, 'member', 'interface', member]) self.session.set( self._base_path + [intf, 'member', 'interface', member, 'cost', str(cost)]) self.session.set(self._base_path + [ intf, 'member', 'interface', member, 'priority', str(priority) ]) cost += 1 priority += 1 self.session.commit() for intf in self._interfaces: self.session.delete(self._base_path + [intf, 'member']) self.session.commit()
def test_add_remove_member(self): members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! for tmp in Section.interfaces("ethernet"): if not '.' in tmp: members.append(tmp) for intf in self._interfaces: for member in members: # We can not enslave an interface when there is an address # assigned - take care here - or find them dynamically if a user # runs vyos-smoketest on his production device? self.session.set(self._base_path + [intf, 'member', 'interface', member]) self.session.commit() # check validate() - we can only add existing interfaces self.session.set(self._base_path + [intf, 'member', 'interface', 'eth99']) with self.assertRaises(ConfigSessionError): self.session.commit() # check if member deletion works as expected self.session.delete(self._base_path + [intf, 'member']) self.session.commit()
def add_to_bridge(self, br): """ Adds the interface to the bridge with the passed port config. Returns False if bridge doesn't exist. """ # check if the bridge exists (on boot it doesn't) if br not in Section.interfaces('bridge'): return False self.flush_addrs() # add interface to bridge - use Section.klass to get BridgeIf class Section.klass(br)(br, create=False).add_port(self.ifname) # TODO: port config (STP) return True
def setUp(self): super().setUp() self._base_path = ['interfaces', 'ethernet'] self._test_mtu = True self._interfaces = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! for tmp in Section.interfaces("ethernet"): if not '.' in tmp: self._interfaces.append(tmp)
def setUp(self): super().setUp() self._base_path = ['interfaces', 'macsec'] self._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] } # if we have a physical eth1 interface, add a second macsec instance if 'eth1' in Section.interfaces("ethernet"): macsec = { 'macsec1': ['source-interface eth1', 'security cipher gcm-aes-128'] } self._options.update(macsec) self._interfaces = list(self._options)
def apply(wwan): if wwan['deleted']: # bail out early return None if not wwan['disable']: # "dial" WWAN connection intf = wwan['intf'] call(f'systemctl start ppp@{intf}.service') # re-add ourselves to any bridge we might have fallen out of # FIXME: wwan isn't under vyos.ifconfig so we can't call # Interfaces.add_to_bridge() so STP settings won't get applied if wwan['is_bridge_member'] in Section.interfaces('bridge'): BridgeIf(wwan['is_bridge_member'], create=False).add_port(wwan['intf']) return None
def setUp(self): super().setUp() self._base_path = ['interfaces', 'ethernet'] self._test_ip = True self._test_mtu = True self._test_vlan = True self._test_qinq = True self._test_ipv6 = True self._interfaces = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: tmp = os.environ['TEST_ETH'].split() self._interfaces = tmp else: for tmp in Section.interfaces("ethernet"): if not '.' in tmp: self._interfaces.append(tmp) def test_dhcp_disable(self): """ When interface is configured as admin down, it must be admin down even """ for interface in self._interfaces: self.session.set(self._base_path + [interface, 'disable']) for option in self._options.get(interface, []): self.session.set(self._base_path + [interface] + option.split()) # Also enable DHCP (ISC DHCP always places interface in admin up # state so we check that we do not start DHCP client. # https://phabricator.vyos.net/T2767 self.session.set(self._base_path + [interface, 'address', 'dhcp']) self.session.commit() # Validate interface state for interface in self._interfaces: with open(f'/sys/class/net/{interface}/flags', 'r') as f: flags = f.read() self.assertEqual(int(flags, 16) & 1, 0)
def setUp(self): super().setUp() self._test_ipv6 = True self._base_path = ['interfaces', 'bridge'] self._interfaces = ['br0'] self._members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: self._members = os.environ['TEST_ETH'].split() else: for tmp in Section.interfaces("ethernet"): if not '.' in tmp: self._members.append(tmp) self._options['br0'] = [] for member in self._members: self._options['br0'].append(f'member interface {member}')
def _sflow_default_agentip(config): # check if any of BGP, OSPF, OSPFv3 protocols are configured and use router-id from there if config.exists('protocols bgp'): bgp_router_id = config.return_value("protocols bgp {} parameters router-id".format(config.list_nodes('protocols bgp')[0])) if bgp_router_id: return bgp_router_id if config.return_value('protocols ospf parameters router-id'): return config.return_value('protocols ospf parameters router-id') if config.return_value('protocols ospfv3 parameters router-id'): return config.return_value('protocols ospfv3 parameters router-id') # if router-id was not found, use first available ip of any interface for iface in Section.interfaces(): for address in Interface(iface).get_addr(): # return an IP, if this is not loopback regex_filter = re.compile('^(?!(127)|(::1)|(fe80))(?P<ipaddr>[a-f\d\.:]+)/\d+$') if regex_filter.search(address): return regex_filter.search(address).group('ipaddr') # return nothing by default return None
def has_address_configured(conf, intf): """ Checks if interface has an address configured. Checks the following config nodes: 'address', 'ipv6 address eui64', 'ipv6 address autoconf' Returns True if interface has address configured, False if it doesn't. """ from vyos.ifconfig import Section ret = False old_level = conf.get_level() conf.set_level([]) intfpath = 'interfaces ' + Section.get_config_path(intf) if (conf.exists(f'{intfpath} address') or conf.exists(f'{intfpath} ipv6 address autoconf') or conf.exists(f'{intfpath} ipv6 address eui64')): ret = True conf.set_level(old_level) return ret
def matching(feature): for section in Section.feature(feature): for intf in Section.interfaces(section): yield intf
action="store_true", help="List all broadcast interfaces") group.add_argument("-br", "--bridgeable", action="store_true", help="List all bridgeable interfaces") group.add_argument("-bo", "--bondable", action="store_true", help="List all bondable interfaces") args = parser.parse_args() if args.type: try: interfaces = Section.interfaces(args.type) print(" ".join(interfaces)) except ValueError as e: print(e, file=sys.stderr) print("") elif args.broadcast: print(" ".join(matching("broadcast"))) elif args.bridgeable: print(" ".join(matching("bridgeable"))) elif args.bondable: # we need to filter out VLAN interfaces identified by a dot (.) in their name print(" ".join([intf for intf in matching("bondable") if '.' not in intf]))
def verify(config): # Verify that configuration is valid # skip all checks if flow-accounting was removed if not config['flow-accounting-configured']: return True # check if at least one collector is enabled if not (config['sflow']['configured'] or config['netflow']['configured'] or not config['disable-imt']): raise ConfigError( "You need to configure at least one sFlow or NetFlow protocol, or not set \"disable-imt\" for flow-accounting" ) # Check if at least one interface is configured if not config['interfaces']: raise ConfigError( "You need to configure at least one interface for flow-accounting") # check that all configured interfaces exists in the system for iface in config['interfaces']: if not iface in Section.interfaces(): # chnged from error to warning to allow adding dynamic interfaces and interface templates # raise ConfigError("The {} interface is not presented in the system".format(iface)) print("Warning: the {} interface is not presented in the system". format(iface)) # check sFlow configuration if config['sflow']['configured']: # check if at least one sFlow collector is configured if sFlow configuration is presented if not config['sflow']['servers']: raise ConfigError( "You need to configure at least one sFlow server") # check that all sFlow collectors use the same IP protocol version sflow_collector_ipver = None for sflow_collector in config['sflow']['servers']: if sflow_collector_ipver: if sflow_collector_ipver != ip_address( sflow_collector['address']).version: raise ConfigError( "All sFlow servers must use the same IP protocol") else: sflow_collector_ipver = ip_address( sflow_collector['address']).version # check agent-id for sFlow: we should avoid mixing IPv4 agent-id with IPv6 collectors and vice-versa for sflow_collector in config['sflow']['servers']: if ip_address(sflow_collector['address']).version != ip_address( config['sflow']['agent-address']).version: raise ConfigError( "Different IP address versions cannot be mixed in \"sflow agent-address\" and \"sflow server\". You need to set manually the same IP version for \"agent-address\" as for all sFlow servers" ) # check if configured sFlow agent-id exist in the system agent_id_presented = None for iface in Section.interfaces(): for address in Interface(iface).get_addr(): # check an IP, if this is not loopback regex_filter = re.compile( '^(?!(127)|(::1)|(fe80))(?P<ipaddr>[a-f\d\.:]+)/\d+$') if regex_filter.search(address): if regex_filter.search(address).group( 'ipaddr') == config['sflow']['agent-address']: agent_id_presented = True break if not agent_id_presented: raise ConfigError( "Your \"sflow agent-address\" does not exist in the system") # check NetFlow configuration if config['netflow']['configured']: # check if at least one NetFlow collector is configured if NetFlow configuration is presented if not config['netflow']['servers']: raise ConfigError( "You need to configure at least one NetFlow server") # check if configured netflow source-ip exist in the system if config['netflow']['source-ip']: source_ip_presented = None for iface in Interface.listing(): for address in Interface(iface).get_addr(): # check an IP regex_filter = re.compile( '^(?!(127)|(::1)|(fe80))(?P<ipaddr>[a-f\d\.:]+)/\d+$') if regex_filter.search(address): if regex_filter.search(address).group( 'ipaddr') == config['netflow']['source-ip']: source_ip_presented = True break if not source_ip_presented: raise ConfigError( "Your \"netflow source-ip\" does not exist in the system") # check if engine-id compatible with selected protocol version if config['netflow']['engine-id']: v5_filter = '^(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]):(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$' v9v10_filter = '^(\d|[1-9]\d{1,8}|[1-3]\d{9}|4[01]\d{8}|42[0-8]\d{7}|429[0-3]\d{6}|4294[0-8]\d{5}|42949[0-5]\d{4}|429496[0-6]\d{3}|4294967[01]\d{2}|42949672[0-8]\d|429496729[0-5])$' if config['netflow']['version'] == '5': regex_filter = re.compile(v5_filter) if not regex_filter.search(config['netflow']['engine-id']): raise ConfigError( "You cannot use NetFlow engine-id {} together with NetFlow protocol version {}" .format(config['netflow']['engine-id'], config['netflow']['version'])) else: regex_filter = re.compile(v9v10_filter) if not regex_filter.search(config['netflow']['engine-id']): raise ConfigError( "You cannot use NetFlow engine-id {} together with NetFlow protocol version {}" .format(config['netflow']['engine-id'], config['netflow']['version'])) # return True if all checks were passed return True
def get_config(): bridge = deepcopy(default_config_data) conf = Config() # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') bridge['intf'] = os.environ['VYOS_TAGNODE_VALUE'] # Check if bridge has been removed if not conf.exists('interfaces bridge ' + bridge['intf']): bridge['deleted'] = True return bridge # set new configuration level conf.set_level('interfaces bridge ' + bridge['intf']) # retrieve configured interface addresses if conf.exists('address'): bridge['address'] = conf.return_values('address') # Determine interface addresses (currently effective) - to determine which # address is no longer valid and needs to be removed eff_addr = conf.return_effective_values('address') bridge['address_remove'] = list_diff(eff_addr, bridge['address']) # retrieve aging - how long addresses are retained if conf.exists('aging'): bridge['aging'] = int(conf.return_value('aging')) # retrieve interface description if conf.exists('description'): bridge['description'] = conf.return_value('description') # get DHCP client identifier if conf.exists('dhcp-options client-id'): bridge['dhcp_client_id'] = conf.return_value('dhcp-options client-id') # DHCP client host name (overrides the system host name) if conf.exists('dhcp-options host-name'): bridge['dhcp_hostname'] = conf.return_value('dhcp-options host-name') # DHCP client vendor identifier if conf.exists('dhcp-options vendor-class-id'): bridge['dhcp_vendor_class_id'] = conf.return_value( 'dhcp-options vendor-class-id') # DHCPv6 only acquire config parameters, no address if conf.exists('dhcpv6-options parameters-only'): bridge['dhcpv6_prm_only'] = True # DHCPv6 temporary IPv6 address if conf.exists('dhcpv6-options temporary'): bridge['dhcpv6_temporary'] = True # Disable this bridge interface if conf.exists('disable'): bridge['disable'] = True # Ignore link state changes if conf.exists('disable-link-detect'): bridge['disable_link_detect'] = 2 # Forwarding delay if conf.exists('forwarding-delay'): bridge['forwarding_delay'] = int(conf.return_value('forwarding-delay')) # Hello packet advertisment interval if conf.exists('hello-time'): bridge['hello_time'] = int(conf.return_value('hello-time')) # Enable Internet Group Management Protocol (IGMP) querier if conf.exists('igmp querier'): bridge['igmp_querier'] = 1 # ARP cache entry timeout in seconds if conf.exists('ip arp-cache-timeout'): bridge['arp_cache_tmo'] = int( conf.return_value('ip arp-cache-timeout')) # ARP filter configuration if conf.exists('ip disable-arp-filter'): bridge['ip_disable_arp_filter'] = 0 # ARP enable accept if conf.exists('ip enable-arp-accept'): bridge['ip_enable_arp_accept'] = 1 # ARP enable announce if conf.exists('ip enable-arp-announce'): bridge['ip_enable_arp_announce'] = 1 # ARP enable ignore if conf.exists('ip enable-arp-ignore'): bridge['ip_enable_arp_ignore'] = 1 # Enable acquisition of IPv6 address using stateless autoconfig (SLAAC) if conf.exists('ipv6 address autoconf'): bridge['ipv6_autoconf'] = 1 # Get prefixes for IPv6 addressing based on MAC address (EUI-64) if conf.exists('ipv6 address eui64'): bridge['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64') # Determine currently effective EUI64 addresses - to determine which # address is no longer valid and needs to be removed eff_addr = conf.return_effective_values('ipv6 address eui64') bridge['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, bridge['ipv6_eui64_prefix']) # Remove the default link-local address if set. if conf.exists('ipv6 address no-default-link-local'): bridge['ipv6_eui64_prefix_remove'].append('fe80::/64') else: # add the link-local by default to make IPv6 work bridge['ipv6_eui64_prefix'].append('fe80::/64') # Disable IPv6 forwarding on this interface if conf.exists('ipv6 disable-forwarding'): bridge['ipv6_forwarding'] = 0 # IPv6 Duplicate Address Detection (DAD) tries if conf.exists('ipv6 dup-addr-detect-transmits'): bridge['ipv6_dup_addr_detect'] = int( conf.return_value('ipv6 dup-addr-detect-transmits')) # Media Access Control (MAC) address if conf.exists('mac'): bridge['mac'] = conf.return_value('mac') # Find out if MAC has changed - if so, we need to delete all IPv6 EUI64 addresses # before re-adding them if (bridge['mac'] and bridge['intf'] in Section.interfaces(section='bridge') and bridge['mac'] != BridgeIf(bridge['intf'], create=False).get_mac()): bridge['ipv6_eui64_prefix_remove'] += bridge['ipv6_eui64_prefix'] # to make IPv6 SLAAC and DHCPv6 work with forwarding=1, # accept_ra must be 2 if bridge['ipv6_autoconf'] or 'dhcpv6' in bridge['address']: bridge['ipv6_accept_ra'] = 2 # Interval at which neighbor bridges are removed if conf.exists('max-age'): bridge['max_age'] = int(conf.return_value('max-age')) # Determine bridge member interface (currently configured) for intf in conf.list_nodes('member interface'): # defaults are stored in util.py (they can't be here as all interface # scripts use the function) memberconf = get_bridge_member_config(conf, bridge['intf'], intf) if memberconf: memberconf['name'] = intf bridge['member'].append(memberconf) # Determine bridge member interface (currently effective) - to determine which # interfaces is no longer assigend to the bridge and thus can be removed eff_intf = conf.list_effective_nodes('member interface') act_intf = conf.list_nodes('member interface') bridge['member_remove'] = list_diff(eff_intf, act_intf) # Priority for this bridge if conf.exists('priority'): bridge['priority'] = int(conf.return_value('priority')) # Enable spanning tree protocol if conf.exists('stp'): bridge['stp'] = 1 # retrieve VRF instance if conf.exists('vrf'): bridge['vrf'] = conf.return_value('vrf') return bridge
if line.startswith("Common Name,"): dump = True continue if line.startswith("ROUTING TABLE"): dump = False continue if dump: # client entry in this file looks like # client1,172.18.202.10:47495,2957,2851,Sat Aug 17 00:07:11 2019 # we are only interested in the client name 'client1' clients.append(line.split(',')[0]) return clients if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-i", "--interface", type=str, help="List connected clients per interface") parser.add_argument("-a", "--all", action='store_true', help="List all connected OpenVPN clients") args = parser.parse_args() clients = [] if args.interface: clients = get_client_from_interface(args.interface) elif args.all: for interface in Section.interfaces("openvpn"): clients += get_client_from_interface(interface) print(" ".join(clients))