diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/pki.py | 61 | ||||
-rwxr-xr-x | src/conf_mode/protocols_static_multicast.py | 6 | ||||
-rwxr-xr-x | src/conf_mode/service_ipoe-server.py | 35 | ||||
-rwxr-xr-x | src/conf_mode/system_config-management.py | 3 | ||||
-rw-r--r-- | src/etc/sudoers.d/vyos | 3 | ||||
-rwxr-xr-x | src/init/vyos-router | 6 | ||||
-rwxr-xr-x | src/op_mode/bridge.py | 47 |
7 files changed, 109 insertions, 52 deletions
diff --git a/src/conf_mode/pki.py b/src/conf_mode/pki.py index 45e0129a3..acea2c9be 100755 --- a/src/conf_mode/pki.py +++ b/src/conf_mode/pki.py @@ -50,6 +50,7 @@ from vyos import airbag airbag.enable() vyos_certbot_dir = directories['certbot'] +vyos_ca_certificates_dir = directories['ca_certificates'] # keys to recursively search for under specified path sync_search = [ @@ -149,35 +150,15 @@ def get_config(config=None): if len(argv) > 1 and argv[1] == 'certbot_renew': pki['certbot_renew'] = {} - tmp = node_changed(conf, base + ['ca'], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - if tmp: - if 'changed' not in pki: pki.update({'changed':{}}) - pki['changed'].update({'ca' : tmp}) - - tmp = node_changed(conf, base + ['certificate'], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - if tmp: - if 'changed' not in pki: pki.update({'changed':{}}) - pki['changed'].update({'certificate' : tmp}) + changed_keys = ['ca', 'certificate', 'dh', 'key-pair', 'openssh', 'openvpn'] - tmp = node_changed(conf, base + ['dh'], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - if tmp: - if 'changed' not in pki: pki.update({'changed':{}}) - pki['changed'].update({'dh' : tmp}) + for key in changed_keys: + tmp = node_changed(conf, base + [key], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - tmp = node_changed(conf, base + ['key-pair'], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - if tmp: - if 'changed' not in pki: pki.update({'changed':{}}) - pki['changed'].update({'key_pair' : tmp}) - - tmp = node_changed(conf, base + ['openssh'], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - if tmp: - if 'changed' not in pki: pki.update({'changed':{}}) - pki['changed'].update({'openssh' : tmp}) + if 'changed' not in pki: + pki.update({'changed':{}}) - tmp = node_changed(conf, base + ['openvpn', 'shared-secret'], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD) - if tmp: - if 'changed' not in pki: pki.update({'changed':{}}) - pki['changed'].update({'openvpn' : tmp}) + pki['changed'].update({key.replace('-', '_') : tmp}) # We only merge on the defaults of there is a configuration at all if conf.exists(base): @@ -417,10 +398,33 @@ def verify(pki): return None +def cleanup_system_ca(): + if not os.path.exists(vyos_ca_certificates_dir): + os.mkdir(vyos_ca_certificates_dir) + else: + for filename in os.listdir(vyos_ca_certificates_dir): + full_path = os.path.join(vyos_ca_certificates_dir, filename) + if os.path.isfile(full_path): + os.unlink(full_path) + def generate(pki): if not pki: + cleanup_system_ca() return None + # Create or cleanup CA install directory + if 'changed' in pki and 'ca' in pki['changed']: + cleanup_system_ca() + + if 'ca' in pki: + for ca, ca_conf in pki['ca'].items(): + if 'system_install' in ca_conf: + ca_obj = load_certificate(ca_conf['certificate']) + ca_path = os.path.join(vyos_ca_certificates_dir, f'{ca}.crt') + + with open(ca_path, 'w') as f: + f.write(encode_certificate(ca_obj)) + # Certbot renewal only needs to re-trigger the services to load up the # new PEM file if 'certbot_renew' in pki: @@ -487,6 +491,7 @@ def apply(pki): systemd_certbot_name = 'certbot.timer' if not pki: call(f'systemctl stop {systemd_certbot_name}') + call('update-ca-certificates') return None has_certbot = False @@ -504,6 +509,10 @@ def apply(pki): if 'changed' in pki: call_dependents() + # Rebuild ca-certificates bundle + if 'ca' in pki['changed']: + call('update-ca-certificates') + return None if __name__ == '__main__': diff --git a/src/conf_mode/protocols_static_multicast.py b/src/conf_mode/protocols_static_multicast.py index d323ceb4f..c8894fd41 100755 --- a/src/conf_mode/protocols_static_multicast.py +++ b/src/conf_mode/protocols_static_multicast.py @@ -86,10 +86,10 @@ def verify(mroute): if mroute is None: return None - for route in mroute['mroute']: - route = route.split('/') + for mcast_route in mroute['mroute']: + route = mcast_route.split('/') if IPv4Address(route[0]) < IPv4Address('224.0.0.0'): - raise ConfigError(route + " not a multicast network") + raise ConfigError(f'{mcast_route} not a multicast network') def generate(mroute): diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py index c7e3ef033..a14d4b5b6 100755 --- a/src/conf_mode/service_ipoe-server.py +++ b/src/conf_mode/service_ipoe-server.py @@ -31,6 +31,7 @@ from vyos.accel_ppp_util import verify_accel_ppp_ip_pool from vyos.accel_ppp_util import verify_accel_ppp_authentication from vyos import ConfigError from vyos import airbag + airbag.enable() @@ -52,7 +53,9 @@ def get_config(config=None): if dict_search('client_ip_pool', ipoe): # Multiple named pools require ordered values T5099 - ipoe['ordered_named_pools'] = get_pools_in_order(dict_search('client_ip_pool', ipoe)) + ipoe['ordered_named_pools'] = get_pools_in_order( + dict_search('client_ip_pool', ipoe) + ) ipoe['server_type'] = 'ipoe' return ipoe @@ -68,11 +71,23 @@ def verify(ipoe): for interface, iface_config in ipoe['interface'].items(): verify_interface_exists(ipoe, interface, warning_only=True) if 'client_subnet' in iface_config and 'vlan' in iface_config: - raise ConfigError('Option "client-subnet" and "vlan" are mutually exclusive, ' - 'use "client-ip-pool" instead!') - if 'vlan_mon' in iface_config and not 'vlan' in iface_config: + raise ConfigError( + 'Options "client-subnet" and "vlan" are mutually exclusive, ' + 'use "client-ip-pool" instead!' + ) + if 'vlan_mon' in iface_config and 'vlan' not in iface_config: raise ConfigError('Option "vlan-mon" requires "vlan" to be set!') + if 'lua_username' in iface_config: + if 'lua_file' not in ipoe: + raise ConfigError( + 'Option "lua-username" requires "lua-file" to be set!' + ) + if dict_search('authentication.mode', ipoe) != 'radius': + raise ConfigError( + 'Can configure username with Lua script only for RADIUS authentication' + ) + verify_accel_ppp_authentication(ipoe, local_users=False) verify_accel_ppp_ip_pool(ipoe) verify_accel_ppp_name_servers(ipoe) @@ -88,14 +103,15 @@ def generate(ipoe): render(ipoe_conf, 'accel-ppp/ipoe.config.j2', ipoe) if dict_search('authentication.mode', ipoe) == 'local': - render(ipoe_chap_secrets, 'accel-ppp/chap-secrets.ipoe.j2', - ipoe, permission=0o640) + render( + ipoe_chap_secrets, 'accel-ppp/chap-secrets.ipoe.j2', ipoe, permission=0o640 + ) return None def apply(ipoe): systemd_service = 'accel-ppp@ipoe.service' - if ipoe == None: + if ipoe is None: call(f'systemctl stop {systemd_service}') for file in [ipoe_conf, ipoe_chap_secrets]: if os.path.exists(file): @@ -103,7 +119,10 @@ def apply(ipoe): return None - call(f'systemctl reload-or-restart {systemd_service}') + # Accel-pppd does not do soft-reload correctly. + # Most of the changes require restarting the service + call(f'systemctl restart {systemd_service}') + if __name__ == '__main__': try: diff --git a/src/conf_mode/system_config-management.py b/src/conf_mode/system_config-management.py index 8de4e5342..a3ce66512 100755 --- a/src/conf_mode/system_config-management.py +++ b/src/conf_mode/system_config-management.py @@ -39,6 +39,9 @@ def get_config(config=None): def verify(mgmt): + if mgmt is None: + return + d = mgmt.config_dict confirm = d.get('commit_confirm', {}) if confirm.get('action', '') == 'reload' and 'commit_revisions' not in d: diff --git a/src/etc/sudoers.d/vyos b/src/etc/sudoers.d/vyos index 67d7babc4..198b9b9aa 100644 --- a/src/etc/sudoers.d/vyos +++ b/src/etc/sudoers.d/vyos @@ -1,7 +1,8 @@ # # VyOS modifications to sudo configuration # -Defaults syslog_goodpri=info +Defaults !syslog +Defaults !pam_session Defaults env_keep+=VYATTA_* # diff --git a/src/init/vyos-router b/src/init/vyos-router index 8825cc16a..f8cc87507 100755 --- a/src/init/vyos-router +++ b/src/init/vyos-router @@ -471,6 +471,12 @@ start () touch /tmp/vyos.smoketest.debug fi + # Cleanup PKI CAs + if [ -d /usr/local/share/ca-certificates/vyos ]; then + rm -f /usr/local/share/ca-certificates/vyos/*.crt + update-ca-certificates >/dev/null 2>&1 + fi + log_action_begin_msg "Mounting VyOS Config" # ensure the vyatta_configdir supports a large number of inodes since # the config hierarchy is often inode-bound (instead of size). diff --git a/src/op_mode/bridge.py b/src/op_mode/bridge.py index e80b1c21d..c4293a77c 100755 --- a/src/op_mode/bridge.py +++ b/src/op_mode/bridge.py @@ -23,10 +23,11 @@ from tabulate import tabulate from vyos.utils.process import cmd from vyos.utils.process import rc_cmd -from vyos.utils.process import call +from vyos.utils.process import call import vyos.opmode + def _get_json_data(): """ Get bridge data format JSON @@ -43,7 +44,7 @@ def _get_raw_data_summary(): return data_dict -def _get_raw_data_vlan(tunnel:bool=False): +def _get_raw_data_vlan(tunnel: bool = False): """ :returns dict """ @@ -54,14 +55,18 @@ def _get_raw_data_vlan(tunnel:bool=False): data_dict = json.loads(json_data) return data_dict + def _get_raw_data_vni() -> dict: """ :returns dict """ - json_data = cmd(f'bridge --json vni show') + code, json_data = rc_cmd(f'bridge --json vni show') + if code != 0: + raise vyos.opmode.UnconfiguredObject('VNI is not configured') data_dict = json.loads(json_data) return data_dict + def _get_raw_data_fdb(bridge): """Get MAC-address for the bridge brX :returns list @@ -70,7 +75,9 @@ def _get_raw_data_fdb(bridge): # From iproute2 fdb.c, fdb_show() will only exit(-1) in case of # non-existent bridge device; raise error. if code == 255: - raise vyos.opmode.UnconfiguredObject(f"bridge {bridge} does not exist in the system") + raise vyos.opmode.UnconfiguredObject( + f'bridge {bridge} does not exist in the system' + ) data_dict = json.loads(json_data) return data_dict @@ -116,8 +123,8 @@ def _get_formatted_output_summary(data): flags = ','.join(option.get('flags')).lower() prio = option.get('priority') member_entries.append([interface, state, mtu, flags, prio]) - member_headers = ["Member", "State", "MTU", "Flags", "Prio"] - output_members = tabulate(member_entries, member_headers, numalign="left") + member_headers = ['Member', 'State', 'MTU', 'Flags', 'Prio'] + output_members = tabulate(member_entries, member_headers, numalign='left') output_bridge = f"""Bridge interface {bridge}: {output_members} @@ -138,13 +145,14 @@ def _get_formatted_output_vlan(data): vlan_end = vlan_entry.get('vlanEnd') vlan = f'{vlan}-{vlan_end}' flags_raw = vlan_entry.get('flags') - flags = ', '.join(flags_raw if isinstance(flags_raw,list) else "").lower() + flags = ', '.join(flags_raw if isinstance(flags_raw, list) else '').lower() data_entries.append([interface, vlan, flags]) - headers = ["Interface", "VLAN", "Flags"] + headers = ['Interface', 'VLAN', 'Flags'] output = tabulate(data_entries, headers) return output + def _get_formatted_output_vlan_tunnel(data): data_entries = [] for entry in data: @@ -166,10 +174,11 @@ def _get_formatted_output_vlan_tunnel(data): # 200 200 data_entries.append(['', vlan, vni]) - headers = ["Interface", "VLAN", "VNI"] + headers = ['Interface', 'VLAN', 'VNI'] output = tabulate(data_entries, headers) return output + def _get_formatted_output_vni(data): data_entries = [] for entry in data: @@ -182,10 +191,11 @@ def _get_formatted_output_vni(data): vlan = f'{vlan}-{vlan_end}' data_entries.append([interface, vlan]) - headers = ["Interface", "VNI"] + headers = ['Interface', 'VNI'] output = tabulate(data_entries, headers) return output + def _get_formatted_output_fdb(data): data_entries = [] for entry in data: @@ -195,8 +205,8 @@ def _get_formatted_output_fdb(data): flags = ','.join(entry['flags']) data_entries.append([interface, mac, state, flags]) - headers = ["Interface", "Mac address", "State", "Flags"] - output = tabulate(data_entries, headers, numalign="left") + headers = ['Interface', 'Mac address', 'State', 'Flags'] + output = tabulate(data_entries, headers, numalign='left') return output @@ -209,28 +219,33 @@ def _get_formatted_output_mdb(data): state = mdb_entry.get('state') flags = ','.join(mdb_entry.get('flags')) data_entries.append([interface, group, state, flags]) - headers = ["Interface", "Group", "State", "Flags"] + headers = ['Interface', 'Group', 'State', 'Flags'] output = tabulate(data_entries, headers) return output + def _get_bridge_detail(iface): """Get interface detail statistics""" return call(f'vtysh -c "show interface {iface}"') + def _get_bridge_detail_nexthop_group(iface): """Get interface detail nexthop_group statistics""" return call(f'vtysh -c "show interface {iface} nexthop-group"') + def _get_bridge_detail_nexthop_group_raw(iface): out = cmd(f'vtysh -c "show interface {iface} nexthop-group"') return out + def _get_bridge_detail_raw(iface): """Get interface detail json statistics""" - data = cmd(f'vtysh -c "show interface {iface} json"') + data = cmd(f'vtysh -c "show interface {iface} json"') data_dict = json.loads(data) return data_dict + def show(raw: bool): bridge_data = _get_raw_data_summary() if raw: @@ -249,6 +264,7 @@ def show_vlan(raw: bool, tunnel: typing.Optional[bool]): else: return _get_formatted_output_vlan(bridge_vlan) + def show_vni(raw: bool): bridge_vni = _get_raw_data_vni() if raw: @@ -256,6 +272,7 @@ def show_vni(raw: bool): else: return _get_formatted_output_vni(bridge_vni) + def show_fdb(raw: bool, interface: str): fdb_data = _get_raw_data_fdb(interface) if raw: @@ -271,6 +288,7 @@ def show_mdb(raw: bool, interface: str): else: return _get_formatted_output_mdb(mdb_data) + def show_detail(raw: bool, nexthop_group: typing.Optional[bool], interface: str): if raw: if nexthop_group: @@ -283,6 +301,7 @@ def show_detail(raw: bool, nexthop_group: typing.Optional[bool], interface: str) else: return _get_bridge_detail(interface) + if __name__ == '__main__': try: res = vyos.opmode.run(sys.modules[__name__]) |