def terminate_sessions(username='', interface='', protocol=''): # Reset vpn connections by username if protocol in cmd_dict['vpn_types']: if username == "all_users": run(cmd_dict['cmd_base'].format(cmd_dict['vpn_types'][protocol], 'all', '')) else: run(cmd_dict['cmd_base'].format(cmd_dict['vpn_types'][protocol], 'username', username)) # Reset vpn connections by ifname elif interface: for proto in cmd_dict['vpn_types']: run(cmd_dict['cmd_base'].format(cmd_dict['vpn_types'][proto], 'if', interface)) elif username: # Reset all vpn connections if username == "all_users": for proto in cmd_dict['vpn_types']: run(cmd_dict['cmd_base'].format(cmd_dict['vpn_types'][proto], 'all', '')) else: for proto in cmd_dict['vpn_types']: run(cmd_dict['cmd_base'].format(cmd_dict['vpn_types'][proto], 'username', username))
def main(): #parese args parser = argparse.ArgumentParser() parser.add_argument('--action', help='Control action', required=True) parser.add_argument('--selector', help='Selector username|ifname|sid', required=False) parser.add_argument('--target', help='Target must contain username|ifname|sid', required=False) args = parser.parse_args() # Check is IPoE configured is_ipoe_configured() if args.action == "restart": run(cmd_dict['cmd_base'] + "restart") sys.exit(0) if args.action in cmd_dict['actions']: if args.selector in cmd_dict['selector'] and args.target: run(cmd_dict['cmd_base'] + "{0} {1} {2}".format(args.action, args.selector, args.target)) else: output, err = popen(cmd_dict['cmd_base'] + cmd_dict['actions'][args.action], decode='utf-8') if not err: print(output) else: print("IPoE server is not running")
def apply(opt): # Beep action if opt['beep_if_fully_booted']: run('systemctl enable vyos-beep.service') else: run('systemctl disable vyos-beep.service') # Ctrl-Alt-Delete action if opt['ctrl_alt_del'] == 'ignore': if os.path.exists(systemd_ctrl_alt_del): os.unlink('/lib/systemd/system/ctrl-alt-del.target') elif opt['ctrl_alt_del'] == 'reboot': if os.path.exists(systemd_ctrl_alt_del): os.unlink(systemd_ctrl_alt_del) os.symlink('/lib/systemd/system/reboot.target', systemd_ctrl_alt_del) elif opt['ctrl_alt_del'] == 'poweroff': if os.path.exists(systemd_ctrl_alt_del): os.unlink(systemd_ctrl_alt_del) os.symlink('/lib/systemd/system/poweroff.target', systemd_ctrl_alt_del) # Reboot system on kernel panic with open('/proc/sys/kernel/panic', 'w') as f: if opt['reboot_on_panic']: f.write('60') else: f.write('0')
def apply(config): if config is None: return None ## Send the updated data to vyos-hostsd # vyos-hostsd uses "tags" to identify data sources tag = "static" try: client = vyos.hostsd_client.Client() # Check if disable-dhcp-nameservers is configured, and if yes - delete DNS servers added by DHCP if config['no_dhcp_ns']: client.delete_name_servers('dhcp-.+') client.set_host_name(config['hostname'], config['domain_name'], config['domain_search']) client.delete_name_servers(tag) client.add_name_servers(tag, config['nameserver']) client.delete_hosts(tag) client.add_hosts(tag, config['static_host_mapping']) except vyos.hostsd_client.VyOSHostsdError as e: raise ConfigError(str(e)) ## Actually update the hostname -- vyos-hostsd doesn't do that # No domain name -- the Debian way. hostname_new = config['hostname'] # rsyslog runs into a race condition at boot time with systemd # restart rsyslog only if the hostname changed. hostname_old = cmd('hostnamectl --static') call(f'hostnamectl set-hostname --static {hostname_new}') # Restart services that use the hostname if hostname_new != hostname_old: call("systemctl restart rsyslog.service") # If SNMP is running, restart it too ret = run("pgrep snmpd") if ret == 0: call("systemctl restart snmpd.service") # restart pdns if it is used ret = run('/usr/bin/rec_control ping') if ret == 0: call('/etc/init.d/pdns-recursor restart >/dev/null') return None
def cancel_shutdown(): output = get_shutdown_status() if output and 'MODE' in output: timenow = datetime.now().strftime('%Y-%m-%d %H:%M:%S') try: cmd('/sbin/shutdown -c --no-wall') except OSError as e: sys.exit("Could not cancel a reboot or poweroff: %s" % e) message = "Scheduled %s has been cancelled %s" % (output['MODE'], timenow) run(f'wall {message}') else: print("Reboot or poweroff is not scheduled")
def apply(config): for intf, addresses in config.items(): # bring the interface up cmd = ["ip", "link", "set", "dev", intf, "up"] sl.syslog(sl.LOG_NOTICE, " ".join(cmd)) run(cmd) # add configured addresses to interface for addr in addresses: if addr == "dhcp": cmd = ["dhclient", intf] else: cmd = ["ip", "address", "add", addr, "dev", intf] sl.syslog(sl.LOG_NOTICE, " ".join(cmd)) run(cmd)
def check_kmod(): """ check if kmod is loaded, if not load it """ if not os.path.exists('/sys/module/wireguard'): sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod") if run('sudo modprobe wireguard') != 0: sl.syslog(sl.LOG_ERR, "modprobe wireguard failed") raise ConfigError("modprobe wireguard failed")
def apply(c): if c['ipsec_conf']: # Shutdown VPN service which can use QAT vpn_control('stop') # Disable QAT service if c['qat_conf'] == None: run('sudo /etc/init.d/qat_service stop') if c['ipsec_conf']: vpn_control('start') return # Run qat init.d script run('sudo /etc/init.d/qat_service start') if c['ipsec_conf']: # Recovery VPN service vpn_control('start')
def apply(config): if config is None: return None ## Send the updated data to vyos-hostsd # vyos-hostsd uses "tags" to identify data sources tag = "static" try: client = vyos.hostsd_client.Client() # Check if disable-dhcp-nameservers is configured, and if yes - delete DNS servers added by DHCP if config['no_dhcp_ns']: client.delete_name_servers('dhcp-.+') client.set_host_name(config['hostname'], config['domain_name'], config['domain_search']) client.delete_name_servers(tag) client.add_name_servers(tag, config['nameserver']) client.delete_hosts(tag) client.add_hosts(tag, config['static_host_mapping']) except vyos.hostsd_client.VyOSHostsdError as e: raise ConfigError(str(e)) ## Actually update the hostname -- vyos-hostsd doesn't do that # No domain name -- the Debian way. hostname_new = config['hostname'] # rsyslog runs into a race condition at boot time with systemd # restart rsyslog only if the hostname changed. hostname_old = cmd('hostnamectl --static') call(f'hostnamectl set-hostname --static {hostname_new}') # Restart services that use the hostname if hostname_new != hostname_old: call("systemctl restart rsyslog.service") # If SNMP is running, restart it too if process_named_running('snmpd'): call('systemctl restart snmpd.service') # restart pdns if it is used - we check for the control dir to not raise # an exception on system startup # # File "/usr/lib/python3/dist-packages/vyos/configsession.py", line 128, in __run_command # raise ConfigSessionError(output) # vyos.configsession.ConfigSessionError: [ system domain-name vyos.io ] # Fatal: Unable to generate local temporary file in directory '/run/powerdns': No such file or directory if os.path.isdir('/run/powerdns'): ret = run('/usr/bin/rec_control --socket-dir=/run/powerdns ping') if ret == 0: call('systemctl restart pdns-recursor.service') return None
def generate_keypair(pk, pub): """ generates a keypair which is stored in /config/auth/wireguard """ old_umask = os.umask(0o027) if run(f'wg genkey | tee {pk} | wg pubkey > {pub}') != 0: raise ConfigError("wireguard key-pair generation failed") else: sl.syslog(sl.LOG_NOTICE, "new keypair wireguard key generated in " + dir) os.umask(old_umask)
def get_full_version_data(fname=version_file): version_data = get_version_data(fname) # Get system architecture (well, kernel architecture rather) version_data['system_arch'], _ = popen('uname -m', stderr=DEVNULL) hypervisor, code = popen('hvinfo', stderr=DEVNULL) if code == 1: # hvinfo returns 1 if it cannot detect any hypervisor version_data['system_type'] = 'bare metal' else: version_data['system_type'] = f"{hypervisor} guest" # Get boot type, it can be livecd, installed image, or, possible, a system installed # via legacy "install system" mechanism # In installed images, the squashfs image file is named after its image version, # while on livecd it's just "filesystem.squashfs", that's how we tell a livecd boot # from an installed image boot_via = "installed image" if run(""" grep -e '^overlay.*/filesystem.squashfs' /proc/mounts >/dev/null""" ) == 0: boot_via = "livecd" elif run(""" grep '^overlay /' /proc/mounts >/dev/null """) != 0: boot_via = "legacy non-image installation" version_data['boot_via'] = boot_via # Get hardware details from DMI dmi = '/sys/class/dmi/id' version_data['hardware_vendor'] = read_file(dmi + '/sys_vendor', 'Unknown') version_data['hardware_model'] = read_file(dmi + '/product_name', 'Unknown') # These two assume script is run as root, normal users can't access those files subsystem = '/sys/class/dmi/id/subsystem/id' version_data['hardware_serial'] = read_file(subsystem + '/product_serial', 'Unknown') version_data['hardware_uuid'] = read_file(subsystem + '/product_uuid', 'Unknown') return version_data
def apply(c): if c == None: if os.path.exists(pidfile): _accel_cmd('shutdown hard') if os.path.exists(pidfile): os.remove(pidfile) return None if not os.path.exists(pidfile): ret = run(f'/usr/sbin/accel-pppd -c {pppoe_conf} -p {pidfile} -d') _chk_con() if ret != 0 and os.path.exists(pidfile): os.remove(pidfile) raise ConfigError('accel-pppd failed to start') else: _accel_cmd('restart')
def genkey(location): """ helper function to check, regenerate the keypair """ pk = "{}/private.key".format(location) pub = "{}/public.key".format(location) old_umask = os.umask(0o027) if os.path.exists(pk) and os.path.exists(pub): try: choice = input( "You already have a wireguard key-pair, do you want to re-generate? [y/n] " ) if choice == 'y' or choice == 'Y': generate_keypair(pk, pub) except KeyboardInterrupt: sys.exit(0) else: """ if keypair is bing executed from a running iso """ if not os.path.exists(location): run(f'sudo mkdir -p {location}') run(f'sudo chgrp vyattacfg {location}') run(f'sudo chmod 750 {location}') generate_keypair(pk, pub) os.umask(old_umask)
def _uacctd_running(): command = 'systemctl status uacctd.service > /dev/null' return run(command) == 0
def vpn_control(action): # XXX: Should these commands report failure if action == 'restore' and gl_ipsec_conf: return run('sudo ipsec start') return run(f'sudo ipsec {action}')
def feature(ifname, option, value): run(f'/sbin/ethtool -K {ifname} {option} {value}', 'ifconfig') return False
if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument( '-i', '--interface', action='store', help= 'Interface name which should be added to bridge it is configured for', required=True) args, unknownargs = parser.parse_known_args() conf = Config() if not conf.list_nodes('interfaces bridge'): # no bridge interfaces exist .. bail out early exit(0) else: for bridge in conf.list_nodes('interfaces bridge'): for member_if in conf.list_nodes( 'interfaces bridge {} member interface'.format(bridge)): if args.interface == member_if: command = 'brctl addif "{}" "{}"'.format( bridge, args.interface) # let interfaces etc. settle - especially required for OpenVPN bridged interfaces sleep(4) # XXX: This is ignoring any issue, should be cmd but kept as it # XXX: during the migration to not cause any regression run(command) exit(0)
def _accel_cmd(command): return run(f'/usr/bin/accel-cmd {command}')
def _accel_cmd(command): return run('/usr/bin/accel-cmd -p 2003 {command}')
def apply(wifi): if wifi['deleted']: w = WiFiIf(wifi['intf']) # delete interface w.remove() else: # WiFi interface needs to be created on-block (e.g. mode or physical # interface) instead of passing a ton of arguments, I just use a dict # that is managed by vyos.ifconfig conf = deepcopy(WiFiIf.get_config()) # Assign WiFi instance configuration parameters to config dict conf['phy'] = wifi['phy'] # Finally create the new interface w = WiFiIf(wifi['intf'], **conf) # assign/remove VRF w.set_vrf(wifi['vrf']) # update interface description used e.g. within SNMP w.set_alias(wifi['description']) if wifi['dhcp_client_id']: w.dhcp.v4.options['client_id'] = wifi['dhcp_client_id'] if wifi['dhcp_hostname']: w.dhcp.v4.options['hostname'] = wifi['dhcp_hostname'] if wifi['dhcp_vendor_class_id']: w.dhcp.v4.options['vendor_class_id'] = wifi['dhcp_vendor_class_id'] if wifi['dhcpv6_prm_only']: w.dhcp.v6.options['dhcpv6_prm_only'] = True if wifi['dhcpv6_temporary']: w.dhcp.v6.options['dhcpv6_temporary'] = True # ignore link state changes w.set_link_detect(wifi['disable_link_detect']) # Change interface MAC address - re-set to real hardware address (hw-id) # if custom mac is removed if wifi['mac']: w.set_mac(wifi['mac']) elif wifi['hw_id']: w.set_mac(wifi['hw_id']) # configure ARP filter configuration w.set_arp_filter(wifi['ip_disable_arp_filter']) # configure ARP accept w.set_arp_accept(wifi['ip_enable_arp_accept']) # configure ARP announce w.set_arp_announce(wifi['ip_enable_arp_announce']) # configure ARP ignore w.set_arp_ignore(wifi['ip_enable_arp_ignore']) # IPv6 address autoconfiguration w.set_ipv6_autoconf(wifi['ipv6_autoconf']) # IPv6 EUI-based address w.set_ipv6_eui64_address(wifi['ipv6_eui64_prefix']) # IPv6 forwarding w.set_ipv6_forwarding(wifi['ipv6_forwarding']) # IPv6 Duplicate Address Detection (DAD) tries w.set_ipv6_dad_messages(wifi['ipv6_dup_addr_detect']) # Configure interface address(es) # - not longer required addresses get removed first # - newly addresses will be added second for addr in wifi['address_remove']: w.del_addr(addr) for addr in wifi['address']: w.add_addr(addr) # remove no longer required VLAN interfaces (vif) for vif in wifi['vif_remove']: e.del_vlan(vif) # create VLAN interfaces (vif) for vif in wifi['vif']: # QoS priority mapping can only be set during interface creation # so we delete the interface first if required. if vif['egress_qos_changed'] or vif['ingress_qos_changed']: try: # on system bootup the above condition is true but the interface # does not exists, which throws an exception, but that's legal e.del_vlan(vif['id']) except: pass vlan = e.add_vlan(vif['id']) apply_vlan_config(vlan, vif) # Enable/Disable interface - interface is always placed in # administrative down state in WiFiIf class if not wifi['disable']: w.set_admin_state('up') # Physical interface is now configured. Proceed by starting hostapd or # wpa_supplicant daemon. When type is monitor we can just skip this. if wifi['op_mode'] == 'ap': command = 'start-stop-daemon' command += ' --start ' command += ' --quiet' command += ' --oknodo' command += ' --pidfile ' + get_pid('hostapd', wifi['intf']) command += ' --exec /usr/sbin/hostapd' # now pass arguments to hostapd binary command += ' -- ' command += ' -B' command += ' -P ' + get_pid('hostapd', wifi['intf']) command += ' ' + get_conf_file('hostapd', wifi['intf']) # execute assembled command run(command) elif wifi['op_mode'] == 'station': command = 'start-stop-daemon' command += ' --start ' command += ' --quiet' command += ' --oknodo' command += ' --pidfile ' + get_pid('hostapd', wifi['intf']) command += ' --exec /sbin/wpa_supplicant' # now pass arguments to hostapd binary command += ' -- ' command += ' -s -B -D nl80211' command += ' -P ' + get_pid('wpa_supplicant', wifi['intf']) command += ' -i ' + wifi['intf'] command += ' -c ' + \ get_conf_file('wpa_supplicant', wifi['intf']) # execute assembled command run(command) return None
def apply(c): if not c: return run('systemctl stop syslog') return run('systemctl restart syslog')
system_type = "bare metal" try: hypervisor = cmd('hvinfo', stderr=DEVNULL) system_type = "{0} guest".format(hypervisor) except OSError: # hvinfo returns 1 if it cannot detect any hypervisor pass version_data['system_type'] = system_type # Get boot type, it can be livecd, installed image, or, possible, a system installed # via legacy "install system" mechanism # In installed images, the squashfs image file is named after its image version, # while on livecd it's just "filesystem.squashfs", that's how we tell a livecd boot # from an installed image boot_via = "installed image" if run(""" grep -e '^overlay.*/filesystem.squashfs' /proc/mounts >/dev/null""" ) == 0: boot_via = "livecd" elif run(""" grep '^overlay /' /proc/mounts >/dev/null """) != 0: boot_via = "legacy non-image installation" version_data['boot_via'] = boot_via # Get hardware details from DMI version_data['hardware_vendor'] = read_file('/sys/class/dmi/id/sys_vendor') version_data['hardware_model'] = read_file( '/sys/class/dmi/id/product_name') # These two assume script is run as root, normal users can't access those files version_data['hardware_serial'] = read_file( '/sys/class/dmi/id/subsystem/id/product_serial') version_data['hardware_uuid'] = read_file( '/sys/class/dmi/id/subsystem/id/product_uuid')
def _accel_cmd(command): return run('/usr/bin/accel-cmd -p {cmd_port} {command}')
def _uacctd_running(): command = '/usr/bin/sudo /bin/systemctl status uacctd > /dev/null' return run(command) == 0
def generate(wifi): # Prepare Jinja2 template loader from files tmpl_path = os.path.join(vyos_data_dir["data"], "templates", "wifi") fs_loader = FileSystemLoader(tmpl_path) env = Environment(loader=fs_loader) # always stop hostapd service first before reconfiguring it pidfile = get_pid('hostapd', wifi['intf']) if process_running(pidfile): command = 'start-stop-daemon' command += ' --stop ' command += ' --quiet' command += ' --oknodo' command += ' --pidfile ' + pidfile run(command) # always stop wpa_supplicant service first before reconfiguring it pidfile = get_pid('wpa_supplicant', wifi['intf']) if process_running(pidfile): command = 'start-stop-daemon' command += ' --stop ' command += ' --quiet' command += ' --oknodo' command += ' --pidfile ' + pidfile run(command) # Delete config files if interface is removed if wifi['deleted']: if os.path.isfile(get_conf_file('hostapd', wifi['intf'])): os.unlink(get_conf_file('hostapd', wifi['intf'])) if os.path.isfile(get_conf_file('wpa_supplicant', wifi['intf'])): os.unlink(get_conf_file('wpa_supplicant', wifi['intf'])) return None if not wifi['mac']: # http://wiki.stocksy.co.uk/wiki/Multiple_SSIDs_with_hostapd # generate locally administered MAC address from used phy interface with open('/sys/class/ieee80211/{}/addresses'.format(wifi['phy']), 'r') as f: # some PHYs tend to have multiple interfaces and thus supply multiple MAC # addresses - we only need the first one for our calculation tmp = f.readline().rstrip() tmp = EUI(tmp).value # mask last nibble from the MAC address tmp &= 0xfffffffffff0 # set locally administered bit in MAC address tmp |= 0x020000000000 # we now need to add an offset to our MAC address indicating this # subinterfaces index tmp += int(findall(r'\d+', wifi['intf'])[0]) # convert integer to "real" MAC address representation mac = EUI(hex(tmp).split('x')[-1]) # change dialect to use : as delimiter instead of - mac.dialect = mac_unix_expanded wifi['mac'] = str(mac) # render appropriate new config files depending on access-point or station mode if wifi['op_mode'] == 'ap': tmpl = env.get_template('hostapd.conf.tmpl') config_text = tmpl.render(wifi) with open(get_conf_file('hostapd', wifi['intf']), 'w') as f: f.write(config_text) elif wifi['op_mode'] == 'station': tmpl = env.get_template('wpa_supplicant.conf.tmpl') config_text = tmpl.render(wifi) with open(get_conf_file('wpa_supplicant', wifi['intf']), 'w') as f: f.write(config_text) return None