diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/container.py | 5 | ||||
| -rwxr-xr-x | src/conf_mode/policy-route-interface.py | 132 | ||||
| -rwxr-xr-x | src/conf_mode/policy-route.py | 106 | ||||
| -rw-r--r-- | src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf | 4 | ||||
| -rw-r--r-- | src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup | 4 | ||||
| -rw-r--r-- | src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook | 6 | ||||
| -rwxr-xr-x | src/etc/ppp/ip-down.d/98-vyos-pppoe-cleanup-nameservers | 15 | ||||
| -rwxr-xr-x | src/etc/ppp/ip-up.d/98-vyos-pppoe-setup-nameservers | 24 | ||||
| -rwxr-xr-x | src/helpers/vyos-domain-resolver.py | 4 | ||||
| -rwxr-xr-x | src/migration-scripts/policy/4-to-5 | 92 | ||||
| -rwxr-xr-x | src/op_mode/accelppp.py | 133 | ||||
| -rwxr-xr-x | src/op_mode/bridge.py | 6 | ||||
| -rwxr-xr-x | src/op_mode/firewall.py | 2 | ||||
| -rwxr-xr-x | src/op_mode/ping.py | 11 | ||||
| -rwxr-xr-x | src/op_mode/policy_route.py | 42 | ||||
| -rwxr-xr-x | src/op_mode/traceroute.py | 85 | ||||
| -rwxr-xr-x | src/services/vyos-hostsd | 3 | ||||
| -rwxr-xr-x | src/services/vyos-http-api-server | 14 | 
18 files changed, 365 insertions, 323 deletions
| diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 70d149f0d..8efeaed54 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -207,6 +207,7 @@ def verify(container):  def generate_run_arguments(name, container_config):      image = container_config['image']      memory = container_config['memory'] +    shared_memory = container_config['shared_memory']      restart = container_config['restart']      # Add capability options. Should be in uppercase @@ -254,9 +255,9 @@ def generate_run_arguments(name, container_config):              volume += f' -v {svol}:{dvol}'      container_base_cmd = f'--detach --interactive --tty --replace {cap_add} ' \ -                         f'--memory {memory}m --memory-swap 0 --restart {restart} ' \ +                         f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \                           f'--name {name} {device} {port} {volume} {env_opt}' -     +      if 'allow_host_networks' in container_config:          return f'{container_base_cmd} --net host {image}' diff --git a/src/conf_mode/policy-route-interface.py b/src/conf_mode/policy-route-interface.py deleted file mode 100755 index 58c5fd93d..000000000 --- a/src/conf_mode/policy-route-interface.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2021 VyOS maintainers and contributors -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 or later as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program.  If not, see <http://www.gnu.org/licenses/>. - -import os -import re - -from sys import argv -from sys import exit - -from vyos.config import Config -from vyos.ifconfig import Section -from vyos.template import render -from vyos.util import cmd -from vyos.util import run -from vyos import ConfigError -from vyos import airbag -airbag.enable() - -def get_config(config=None): -    if config: -        conf = config -    else: -        conf = Config() - -    ifname = argv[1] -    ifpath = Section.get_config_path(ifname) -    if_policy_path = f'interfaces {ifpath} policy' - -    if_policy = conf.get_config_dict(if_policy_path, key_mangling=('-', '_'), get_first_key=True, -                                    no_tag_node_value_mangle=True) - -    if_policy['ifname'] = ifname -    if_policy['policy'] = conf.get_config_dict(['policy'], key_mangling=('-', '_'), get_first_key=True, -                                    no_tag_node_value_mangle=True) - -    return if_policy - -def verify_chain(table, chain): -    # Verify policy route applied -    code = run(f'nft list chain {table} {chain}') -    return code == 0 - -def verify(if_policy): -    # bail out early - looks like removal from running config -    if not if_policy: -        return None - -    for route in ['route', 'route6']: -        if route in if_policy: -            if route not in if_policy['policy']: -                raise ConfigError('Policy route not configured') - -            route_name = if_policy[route] - -            if route_name not in if_policy['policy'][route]: -                raise ConfigError(f'Invalid policy route name "{name}"') - -            nft_prefix = 'VYOS_PBR6_' if route == 'route6' else 'VYOS_PBR_' -            nft_table = 'ip6 mangle' if route == 'route6' else 'ip mangle' - -            if not verify_chain(nft_table, nft_prefix + route_name): -                raise ConfigError('Policy route did not apply') - -    return None - -def generate(if_policy): -    return None - -def cleanup_rule(table, chain, ifname, new_name=None): -    results = cmd(f'nft -a list chain {table} {chain}').split("\n") -    retval = None -    for line in results: -        if f'ifname "{ifname}"' in line: -            if new_name and f'jump {new_name}' in line: -                # new_name is used to clear rules for any previously referenced chains -                # returns true when rule exists and doesn't need to be created -                retval = True -                continue - -            handle_search = re.search('handle (\d+)', line) -            if handle_search: -                cmd(f'nft delete rule {table} {chain} handle {handle_search[1]}') -    return retval - -def apply(if_policy): -    ifname = if_policy['ifname'] - -    route_chain = 'VYOS_PBR_PREROUTING' -    ipv6_route_chain = 'VYOS_PBR6_PREROUTING' - -    if 'route' in if_policy: -        name = 'VYOS_PBR_' + if_policy['route'] -        rule_exists = cleanup_rule('ip mangle', route_chain, ifname, name) - -        if not rule_exists: -            cmd(f'nft insert rule ip mangle {route_chain} iifname {ifname} counter jump {name}') -    else: -        cleanup_rule('ip mangle', route_chain, ifname) - -    if 'route6' in if_policy: -        name = 'VYOS_PBR6_' + if_policy['route6'] -        rule_exists = cleanup_rule('ip6 mangle', ipv6_route_chain, ifname, name) - -        if not rule_exists: -            cmd(f'nft insert rule ip6 mangle {ipv6_route_chain} iifname {ifname} counter jump {name}') -    else: -        cleanup_rule('ip6 mangle', ipv6_route_chain, ifname) - -    return None - -if __name__ == '__main__': -    try: -        c = get_config() -        verify(c) -        generate(c) -        apply(c) -    except ConfigError as e: -        print(e) -        exit(1) diff --git a/src/conf_mode/policy-route.py b/src/conf_mode/policy-route.py index 00539b9c7..1d016695e 100755 --- a/src/conf_mode/policy-route.py +++ b/src/conf_mode/policy-route.py @@ -15,7 +15,6 @@  # along with this program.  If not, see <http://www.gnu.org/licenses/>.  import os -import re  from json import loads  from sys import exit @@ -25,7 +24,6 @@ from vyos.config import Config  from vyos.template import render  from vyos.util import cmd  from vyos.util import dict_search_args -from vyos.util import dict_search_recursive  from vyos.util import run  from vyos import ConfigError  from vyos import airbag @@ -34,48 +32,13 @@ airbag.enable()  mark_offset = 0x7FFFFFFF  nftables_conf = '/run/nftables_policy.conf' -ROUTE_PREFIX = 'VYOS_PBR_' -ROUTE6_PREFIX = 'VYOS_PBR6_' - -preserve_chains = [ -    'VYOS_PBR_PREROUTING', -    'VYOS_PBR_POSTROUTING', -    'VYOS_PBR6_PREROUTING', -    'VYOS_PBR6_POSTROUTING' -] -  valid_groups = [      'address_group', +    'domain_group',      'network_group',      'port_group'  ] -group_set_prefix = { -    'A_': 'address_group', -    'A6_': 'ipv6_address_group', -#    'D_': 'domain_group', -    'M_': 'mac_group', -    'N_': 'network_group', -    'N6_': 'ipv6_network_group', -    'P_': 'port_group' -} - -def get_policy_interfaces(conf): -    out = {} -    interfaces = conf.get_config_dict(['interfaces'], key_mangling=('-', '_'), get_first_key=True, -                                    no_tag_node_value_mangle=True) -    def find_interfaces(iftype_conf, output={}, prefix=''): -        for ifname, if_conf in iftype_conf.items(): -            if 'policy' in if_conf: -                output[prefix + ifname] = if_conf['policy'] -            for vif in ['vif', 'vif_s', 'vif_c']: -                if vif in if_conf: -                    output.update(find_interfaces(if_conf[vif], output, f'{prefix}{ifname}.')) -        return output -    for iftype, iftype_conf in interfaces.items(): -        out.update(find_interfaces(iftype_conf)) -    return out -  def get_config(config=None):      if config:          conf = config @@ -88,7 +51,6 @@ def get_config(config=None):      policy['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True,                                      no_tag_node_value_mangle=True) -    policy['interfaces'] = get_policy_interfaces(conf)      return policy @@ -132,8 +94,8 @@ def verify_rule(policy, name, rule_conf, ipv6, rule_id):              side_conf = rule_conf[side]              if 'group' in side_conf: -                if {'address_group', 'network_group'} <= set(side_conf['group']): -                    raise ConfigError('Only one address-group or network-group can be specified') +                if len({'address_group', 'domain_group', 'network_group'} & set(side_conf['group'])) > 1: +                    raise ConfigError('Only one address-group, domain-group or network-group can be specified')                  for group in valid_groups:                      if group in side_conf['group']: @@ -168,73 +130,11 @@ def verify(policy):                      for rule_id, rule_conf in pol_conf['rule'].items():                          verify_rule(policy, name, rule_conf, ipv6, rule_id) -    for ifname, if_policy in policy['interfaces'].items(): -        name = dict_search_args(if_policy, 'route') -        ipv6_name = dict_search_args(if_policy, 'route6') - -        if name and not dict_search_args(policy, 'route', name): -            raise ConfigError(f'Policy route "{name}" is still referenced on interface {ifname}') - -        if ipv6_name and not dict_search_args(policy, 'route6', ipv6_name): -            raise ConfigError(f'Policy route6 "{ipv6_name}" is still referenced on interface {ifname}') -      return None -def cleanup_commands(policy): -    commands = [] -    commands_chains = [] -    commands_sets = [] -    for table in ['ip mangle', 'ip6 mangle']: -        route_node = 'route' if table == 'ip mangle' else 'route6' -        chain_prefix = ROUTE_PREFIX if table == 'ip mangle' else ROUTE6_PREFIX - -        json_str = cmd(f'nft -t -j list table {table}') -        obj = loads(json_str) -        if 'nftables' not in obj: -            continue -        for item in obj['nftables']: -            if 'chain' in item: -                chain = item['chain']['name'] -                if chain in preserve_chains or not chain.startswith("VYOS_PBR"): -                    continue - -                if dict_search_args(policy, route_node, chain.replace(chain_prefix, "", 1)) != None: -                    commands.append(f'flush chain {table} {chain}') -                else: -                    commands_chains.append(f'delete chain {table} {chain}') - -            if 'rule' in item: -                rule = item['rule'] -                chain = rule['chain'] -                handle = rule['handle'] - -                if chain not in preserve_chains: -                    continue - -                target, _ = next(dict_search_recursive(rule['expr'], 'target')) - -                if target.startswith(chain_prefix): -                    if dict_search_args(policy, route_node, target.replace(chain_prefix, "", 1)) == None: -                        commands.append(f'delete rule {table} {chain} handle {handle}') - -            if 'set' in item: -                set_name = item['set']['name'] - -                for prefix, group_type in group_set_prefix.items(): -                    if set_name.startswith(prefix): -                        group_name = set_name.replace(prefix, "", 1) -                        if dict_search_args(policy, 'firewall_group', group_type, group_name) != None: -                            commands_sets.append(f'flush set {table} {set_name}') -                        else: -                            commands_sets.append(f'delete set {table} {set_name}') - -    return commands + commands_chains + commands_sets -  def generate(policy):      if not os.path.exists(nftables_conf):          policy['first_install'] = True -    else: -        policy['cleanup_commands'] = cleanup_commands(policy)      render(nftables_conf, 'firewall/nftables-policy.j2', policy)      return None diff --git a/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf b/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf index b1902b585..518abeaec 100644 --- a/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf +++ b/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf @@ -33,8 +33,8 @@ if /usr/bin/systemctl -q is-active vyos-hostsd; then          if [ -n "$new_dhcp6_name_servers" ]; then              logmsg info "Deleting nameservers with tag \"dhcpv6-$interface\" via vyos-hostsd-client"              $hostsd_client --delete-name-servers --tag "dhcpv6-$interface" -            logmsg info "Adding nameservers \"$new_dhcpv6_name_servers\" with tag \"dhcpv6-$interface\" via vyos-hostsd-client" -            $hostsd_client --add-name-servers $new_dhcpv6_name_servers --tag "dhcpv6-$interface" +            logmsg info "Adding nameservers \"$new_dhcp6_name_servers\" with tag \"dhcpv6-$interface\" via vyos-hostsd-client" +            $hostsd_client --add-name-servers $new_dhcp6_name_servers --tag "dhcpv6-$interface"              hostsd_changes=y          fi diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup b/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup index ad6a1d5eb..da1bda137 100644 --- a/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup +++ b/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup @@ -8,7 +8,7 @@ hostsd_changes=  /usr/bin/systemctl -q is-active vyos-hostsd  hostsd_status=$? -if [[ $reason =~ (EXPIRE|FAIL|RELEASE|STOP) ]]; then +if [[ $reason =~ ^(EXPIRE|FAIL|RELEASE|STOP)$ ]]; then      if [[ $hostsd_status -eq 0 ]]; then          # delete search domains and nameservers via vyos-hostsd          logmsg info "Deleting search domains with tag \"dhcp-$interface\" via vyos-hostsd-client" @@ -96,7 +96,7 @@ if [[ $reason =~ (EXPIRE|FAIL|RELEASE|STOP) ]]; then      fi  fi -if [[ $reason =~ (EXPIRE6|RELEASE6|STOP6) ]]; then +if [[ $reason =~ ^(EXPIRE6|RELEASE6|STOP6)$ ]]; then      if [[ $hostsd_status -eq 0 ]]; then          # delete search domains and nameservers via vyos-hostsd          logmsg info "Deleting search domains with tag \"dhcpv6-$interface\" via vyos-hostsd-client" diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook index eeb8b0782..49bb18372 100644 --- a/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook +++ b/src/etc/dhcp/dhclient-exit-hooks.d/vyatta-dhclient-hook @@ -8,12 +8,12 @@  # This program is free software; you can redistribute it and/or modify  # it under the terms of the GNU General Public License version 2 as  # published by the Free Software Foundation. -#  +#  # This program is distributed in the hope that it will be useful, but  # WITHOUT ANY WARRANTY; without even the implied warranty of  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  # General Public License for more details. -#  +#  # This code was originally developed by Vyatta, Inc.  # Portions created by Vyatta are Copyright (C) 2006, 2007, 2008 Vyatta, Inc.  # All Rights Reserved. @@ -23,7 +23,7 @@  RUN="yes"  proto="" -if [[ $reason =~ (REBOOT6|INIT6|EXPIRE6|RELEASE6|STOP6|INFORM6|BOUND6|REBIND6|DELEGATED6) ]]; then +if [[ $reason =~ ^(REBOOT6|INIT6|EXPIRE6|RELEASE6|STOP6|INFORM6|BOUND6|REBIND6|DELEGATED6)$ ]]; then          proto="v6"  fi diff --git a/src/etc/ppp/ip-down.d/98-vyos-pppoe-cleanup-nameservers b/src/etc/ppp/ip-down.d/98-vyos-pppoe-cleanup-nameservers new file mode 100755 index 000000000..222c75f21 --- /dev/null +++ b/src/etc/ppp/ip-down.d/98-vyos-pppoe-cleanup-nameservers @@ -0,0 +1,15 @@ +#!/bin/bash +### Autogenerated by interfaces-pppoe.py ### + +interface=$6 +if [ -z "$interface" ]; then +    exit +fi + +if ! /usr/bin/systemctl -q is-active vyos-hostsd; then +    exit  # vyos-hostsd is not running +fi + +hostsd_client="/usr/bin/vyos-hostsd-client" +$hostsd_client --delete-name-servers --tag "dhcp-$interface" +$hostsd_client --apply diff --git a/src/etc/ppp/ip-up.d/98-vyos-pppoe-setup-nameservers b/src/etc/ppp/ip-up.d/98-vyos-pppoe-setup-nameservers new file mode 100755 index 000000000..0fcedbedc --- /dev/null +++ b/src/etc/ppp/ip-up.d/98-vyos-pppoe-setup-nameservers @@ -0,0 +1,24 @@ +#!/bin/bash +### Autogenerated by interfaces-pppoe.py ### + +interface=$6 +if [ -z "$interface" ]; then +    exit +fi + +if ! /usr/bin/systemctl -q is-active vyos-hostsd; then +    exit  # vyos-hostsd is not running +fi + +hostsd_client="/usr/bin/vyos-hostsd-client" + +$hostsd_client --delete-name-servers --tag "dhcp-$interface" + +if [ "$USEPEERDNS" ] && [ -n "$DNS1" ]; then +$hostsd_client --add-name-servers "$DNS1" --tag "dhcp-$interface" +fi +if [ "$USEPEERDNS" ] && [ -n "$DNS2" ]; then +$hostsd_client --add-name-servers "$DNS2" --tag "dhcp-$interface" +fi + +$hostsd_client --apply diff --git a/src/helpers/vyos-domain-resolver.py b/src/helpers/vyos-domain-resolver.py index 035c208b2..e31d9238e 100755 --- a/src/helpers/vyos-domain-resolver.py +++ b/src/helpers/vyos-domain-resolver.py @@ -35,13 +35,13 @@ cache = False  domain_state = {}  ipv4_tables = { -    'ip mangle', +    'ip vyos_mangle',      'ip vyos_filter',      'ip vyos_nat'  }  ipv6_tables = { -    'ip6 mangle', +    'ip6 vyos_mangle',      'ip6 vyos_filter'  } diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5 new file mode 100755 index 000000000..33c9e6ade --- /dev/null +++ b/src/migration-scripts/policy/4-to-5 @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +# T2199: Migrate interface policy nodes to policy route <name> interface <ifname> + +import re + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.ifconfig import Section + +if (len(argv) < 1): +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +base4 = ['policy', 'route'] +base6 = ['policy', 'route6'] +config = ConfigTree(config_file) + +if not config.exists(base4) and not config.exists(base6): +    # Nothing to do +    exit(0) + +def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None): +    if_path = ['interfaces', iftype, ifname] +    ifname_full = ifname + +    if vif: +        if_path += ['vif', vif] +        ifname_full = f'{ifname}.{vif}' +    elif vifs: +        if_path += ['vif-s', vifs] +        ifname_full = f'{ifname}.{vifs}' +        if vifc: +            if_path += ['vif-c', vifc] +            ifname_full = f'{ifname}.{vifs}.{vifc}' + +    if not config.exists(if_path + ['policy']): +        return + +    if config.exists(if_path + ['policy', 'route']): +        route_name = config.return_value(if_path + ['policy', 'route']) +        config.set(base4 + [route_name, 'interface'], value=ifname_full, replace=False) + +    if config.exists(if_path + ['policy', 'route6']): +        route_name = config.return_value(if_path + ['policy', 'route6']) +        config.set(base6 + [route_name, 'interface'], value=ifname_full, replace=False) + +    config.delete(if_path + ['policy']) + +for iftype in config.list_nodes(['interfaces']): +    for ifname in config.list_nodes(['interfaces', iftype]): +        migrate_interface(config, iftype, ifname) + +        if config.exists(['interfaces', iftype, ifname, 'vif']): +            for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): +                migrate_interface(config, iftype, ifname, vif=vif) + +        if config.exists(['interfaces', iftype, ifname, 'vif-s']): +            for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): +                migrate_interface(config, iftype, ifname, vifs=vifs) + +                if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): +                    for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): +                        migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1) diff --git a/src/op_mode/accelppp.py b/src/op_mode/accelppp.py new file mode 100755 index 000000000..2fd045dc3 --- /dev/null +++ b/src/op_mode/accelppp.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +import sys + +import vyos.accel_ppp +import vyos.opmode + +from vyos.configquery import ConfigTreeQuery +from vyos.util import rc_cmd + + +accel_dict = { +    'ipoe': { +        'port': 2002, +        'path': 'service ipoe-server' +    }, +    'pppoe': { +        'port': 2001, +        'path': 'service pppoe-server' +    }, +    'pptp': { +        'port': 2003, +        'path': 'vpn pptp' +    }, +    'l2tp': { +        'port': 2004, +        'path': 'vpn l2tp' +    }, +    'sstp': { +        'port': 2005, +        'path': 'vpn sstp' +    } +} + + +def _get_raw_statistics(accel_output, pattern): +    return vyos.accel_ppp.get_server_statistics(accel_output, pattern, sep=':') + + +def _get_raw_sessions(port): +    cmd_options = 'show sessions ifname,username,ip,ip6,ip6-dp,type,state,' \ +                  'uptime-raw,calling-sid,called-sid,sid,comp,rx-bytes-raw,' \ +                  'tx-bytes-raw,rx-pkts,tx-pkts' +    output = vyos.accel_ppp.accel_cmd(port, cmd_options) +    parsed_data: list[dict[str, str]] = vyos.accel_ppp.accel_out_parse( +        output.splitlines()) +    return parsed_data + + +def _verify(func): +    """Decorator checks if accel-ppp protocol +    ipoe/pppoe/pptp/l2tp/sstp is configured + +    for example: +        service ipoe-server +        vpn sstp +    """ +    from functools import wraps + +    @wraps(func) +    def _wrapper(*args, **kwargs): +        config = ConfigTreeQuery() +        protocol_list = accel_dict.keys() +        protocol = kwargs.get('protocol') +        # unknown or incorrect protocol query +        if protocol not in protocol_list: +            unconf_message = f'unknown protocol "{protocol}"' +            raise vyos.opmode.UnconfiguredSubsystem(unconf_message) +        # Check if config does not exist +        config_protocol_path = accel_dict[protocol]['path'] +        if not config.exists(config_protocol_path): +            unconf_message = f'"{config_protocol_path}" is not configured' +            raise vyos.opmode.UnconfiguredSubsystem(unconf_message) +        return func(*args, **kwargs) + +    return _wrapper + + +@_verify +def show_statistics(raw: bool, protocol: str): +    """show accel-cmd statistics +    CPU utilization and amount of sessions + +    protocol: ipoe/pppoe/ppptp/l2tp/sstp +    """ +    pattern = f'{protocol}:' +    port = accel_dict[protocol]['port'] +    rc, output = rc_cmd(f'/usr/bin/accel-cmd -p {port} show stat') + +    if raw: +        return _get_raw_statistics(output, pattern) + +    return output + + +@_verify +def show_sessions(raw: bool, protocol: str): +    """show accel-cmd sessions + +    protocol: ipoe/pppoe/ppptp/l2tp/sstp +    """ +    port = accel_dict[protocol]['port'] +    if raw: +        return _get_raw_sessions(port) + +    return vyos.accel_ppp.accel_cmd(port, +                                    'show sessions ifname,username,ip,ip6,ip6-dp,' +                                    'calling-sid,rate-limit,state,uptime,rx-bytes,tx-bytes') + + +if __name__ == '__main__': +    try: +        res = vyos.opmode.run(sys.modules[__name__]) +        if res: +            print(res) +    except (ValueError, vyos.opmode.Error) as e: +        print(e) +        sys.exit(1) diff --git a/src/op_mode/bridge.py b/src/op_mode/bridge.py index 5a821a287..d6098c158 100755 --- a/src/op_mode/bridge.py +++ b/src/op_mode/bridge.py @@ -32,7 +32,7 @@ def _get_json_data():      """      Get bridge data format JSON      """ -    return cmd(f'sudo bridge --json link show') +    return cmd(f'bridge --json link show')  def _get_raw_data_summary(): @@ -48,7 +48,7 @@ def _get_raw_data_vlan():      """      :returns dict      """ -    json_data = cmd('sudo bridge --json --compressvlans vlan show') +    json_data = cmd('bridge --json --compressvlans vlan show')      data_dict = json.loads(json_data)      return data_dict @@ -57,7 +57,7 @@ def _get_raw_data_fdb(bridge):      """Get MAC-address for the bridge brX      :returns list      """ -    code, json_data = rc_cmd(f'sudo bridge --json fdb show br {bridge}') +    code, json_data = rc_cmd(f'bridge --json fdb show br {bridge}')      # From iproute2 fdb.c, fdb_show() will only exit(-1) in case of      # non-existent bridge device; raise error.      if code == 255: diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py index 950feb625..46bda5f7e 100755 --- a/src/op_mode/firewall.py +++ b/src/op_mode/firewall.py @@ -63,7 +63,7 @@ def get_config_firewall(conf, name=None, ipv6=False, interfaces=True):                                  get_first_key=True, no_tag_node_value_mangle=True)      if firewall and interfaces:          if name: -            firewall['interface'] = [] +            firewall['interface'] = {}          else:              if 'name' in firewall:                  for fw_name, name_conf in firewall['name'].items(): diff --git a/src/op_mode/ping.py b/src/op_mode/ping.py index 5e5b95a0a..610e63cb3 100755 --- a/src/op_mode/ping.py +++ b/src/op_mode/ping.py @@ -18,8 +18,7 @@ import os  import sys  import socket  import ipaddress -import json -from vyos.util import cmd, rc_cmd +from vyos.util import get_all_vrfs  from vyos.ifconfig import Section @@ -36,13 +35,7 @@ def vrf_list() -> list:      Get list of VRFs in system      :rtype: list      """ -    result = cmd(f'sudo ip --json --brief link show type vrf') -    data = json.loads(result) -    vrflist: list = [] -    for o in data: -        if 'ifname' in o: -            vrflist.append(o['ifname']) -    return vrflist +    return list(get_all_vrfs().keys())  options = { diff --git a/src/op_mode/policy_route.py b/src/op_mode/policy_route.py index 5be40082f..5953786f3 100755 --- a/src/op_mode/policy_route.py +++ b/src/op_mode/policy_route.py @@ -22,53 +22,13 @@ from vyos.config import Config  from vyos.util import cmd  from vyos.util import dict_search_args -def get_policy_interfaces(conf, policy, name=None, ipv6=False): -    interfaces = conf.get_config_dict(['interfaces'], key_mangling=('-', '_'), -                                      get_first_key=True, no_tag_node_value_mangle=True) - -    routes = ['route', 'route6'] - -    def parse_if(ifname, if_conf): -        if 'policy' in if_conf: -            for route in routes: -                if route in if_conf['policy']: -                    route_name = if_conf['policy'][route] -                    name_str = f'({ifname},{route})' - -                    if not name: -                        policy[route][route_name]['interface'].append(name_str) -                    elif not ipv6 and name == route_name: -                        policy['interface'].append(name_str) - -        for iftype in ['vif', 'vif_s', 'vif_c']: -            if iftype in if_conf: -                for vifname, vif_conf in if_conf[iftype].items(): -                    parse_if(f'{ifname}.{vifname}', vif_conf) - -    for iftype, iftype_conf in interfaces.items(): -        for ifname, if_conf in iftype_conf.items(): -            parse_if(ifname, if_conf) - -def get_config_policy(conf, name=None, ipv6=False, interfaces=True): +def get_config_policy(conf, name=None, ipv6=False):      config_path = ['policy']      if name:          config_path += ['route6' if ipv6 else 'route', name]      policy = conf.get_config_dict(config_path, key_mangling=('-', '_'),                                  get_first_key=True, no_tag_node_value_mangle=True) -    if policy and interfaces: -        if name: -            policy['interface'] = [] -        else: -            if 'route' in policy: -                for route_name, route_conf in policy['route'].items(): -                    route_conf['interface'] = [] - -            if 'route6' in policy: -                for route_name, route_conf in policy['route6'].items(): -                    route_conf['interface'] = [] - -        get_policy_interfaces(conf, policy, name, ipv6)      return policy diff --git a/src/op_mode/traceroute.py b/src/op_mode/traceroute.py index 4299d6e5f..6c7030ea0 100755 --- a/src/op_mode/traceroute.py +++ b/src/op_mode/traceroute.py @@ -18,6 +18,25 @@ import os  import sys  import socket  import ipaddress +from vyos.util import get_all_vrfs +from vyos.ifconfig import Section + + +def interface_list() -> list: +    """ +    Get list of interfaces in system +    :rtype: list +    """ +    return Section.interfaces() + + +def vrf_list() -> list: +    """ +    Get list of VRFs in system +    :rtype: list +    """ +    return list(get_all_vrfs().keys()) +  options = {      'backward-hops': { @@ -48,6 +67,7 @@ options = {      'interface': {          'traceroute': '{command} -i {value}',          'type': '<interface>', +        'helpfunction': interface_list,          'help': 'Source interface'      },      'lookup-as': { @@ -99,6 +119,7 @@ options = {          'traceroute': 'sudo ip vrf exec {value} {command}',          'type': '<vrf>',          'help': 'Use specified VRF table', +        'helpfunction': vrf_list,          'dflt': 'default'}  } @@ -108,20 +129,33 @@ traceroute = {  } -class List (list): -    def first (self): +class List(list): +    def first(self):          return self.pop(0) if self else ''      def last(self):          return self.pop() if self else '' -    def prepend(self,value): -        self.insert(0,value) +    def prepend(self, value): +        self.insert(0, value) + + +def completion_failure(option: str) -> None: +    """ +    Shows failure message after TAB when option is wrong +    :param option: failure option +    :type str: +    """ +    sys.stderr.write('\n\n Invalid option: {}\n\n'.format(option)) +    sys.stdout.write('<nocomps>') +    sys.exit(1)  def expension_failure(option, completions):      reason = 'Ambiguous' if completions else 'Invalid' -    sys.stderr.write('\n\n  {} command: {} [{}]\n\n'.format(reason,' '.join(sys.argv), option)) +    sys.stderr.write( +        '\n\n  {} command: {} [{}]\n\n'.format(reason, ' '.join(sys.argv), +                                               option))      if completions:          sys.stderr.write('  Possible completions:\n   ')          sys.stderr.write('\n   '.join(completions)) @@ -160,30 +194,46 @@ if __name__ == '__main__':          sys.exit("traceroute: Missing host")      if host == '--get-options': -        args.first()  # pop traceroute +        args.first()  # pop ping          args.first()  # pop IP +        usedoptionslist = []          while args: -            option = args.first() - -            matched = complete(option) +            option = args.first()  # pop option +            matched = complete(option)  # get option parameters +            usedoptionslist.append(option)  # list of used options +            # Select options              if not args: +                # remove from Possible completions used options +                for o in usedoptionslist: +                    if o in matched: +                        matched.remove(o)                  sys.stdout.write(' '.join(matched))                  sys.exit(0) -            if len(matched) > 1 : +            if len(matched) > 1:                  sys.stdout.write(' '.join(matched))                  sys.exit(0) +            # If option doesn't have value +            if matched: +                if options[matched[0]]['type'] == 'noarg': +                    continue +            else: +                # Unexpected option +                completion_failure(option) -            if options[matched[0]]['type'] == 'noarg': -                continue - -            value = args.first() +            value = args.first()  # pop option's value              if not args:                  matched = complete(option) -                sys.stdout.write(options[matched[0]]['type']) +                helplines = options[matched[0]]['type'] +                # Run helpfunction to get list of possible values +                if 'helpfunction' in options[matched[0]]: +                    result = options[matched[0]]['helpfunction']() +                    if result: +                        helplines = '\n' + ' '.join(result) +                sys.stdout.write(helplines)                  sys.exit(0) -    for name,option in options.items(): +    for name, option in options.items():          if 'dflt' in option and name not in args:              args.append(name)              args.append(option['dflt']) @@ -200,8 +250,7 @@ if __name__ == '__main__':      except ValueError:          sys.exit(f'traceroute: Unknown host: {host}') -    command = convert(traceroute[version],args) +    command = convert(traceroute[version], args)      # print(f'{command} {host}')      os.system(f'{command} {host}') - diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd index 9ae7b1ea9..a380f2e66 100755 --- a/src/services/vyos-hostsd +++ b/src/services/vyos-hostsd @@ -406,8 +406,7 @@ def validate_schema(data):  def pdns_rec_control(command): -    # pdns-r process name is NOT equal to the name shown in ps -    if not process_named_running('pdns-r/worker'): +    if not process_named_running('pdns_recursor'):          logger.info(f'pdns_recursor not running, not sending "{command}"')          return diff --git a/src/services/vyos-http-api-server b/src/services/vyos-http-api-server index 3c390d9dc..60ea9a5ee 100755 --- a/src/services/vyos-http-api-server +++ b/src/services/vyos-http-api-server @@ -659,10 +659,18 @@ def graphql_init(fast_api_app):      if app.state.vyos_origins:          origins = app.state.vyos_origins -        app.add_route('/graphql', CORSMiddleware(GraphQL(schema, context_value=get_user_context, debug=True, introspection=in_spec), allow_origins=origins, allow_methods=("GET", "POST", "OPTIONS"))) +        app.add_route('/graphql', CORSMiddleware(GraphQL(schema, +                                                         context_value=get_user_context, +                                                         debug=True, +                                                         introspection=in_spec), +                                                 allow_origins=origins, +                                                 allow_methods=("GET", "POST", "OPTIONS"), +                                                 allow_headers=("Authorization",)))      else: -        app.add_route('/graphql', GraphQL(schema, context_value=get_user_context, debug=True, introspection=in_spec)) - +        app.add_route('/graphql', GraphQL(schema, +                                          context_value=get_user_context, +                                          debug=True, +                                          introspection=in_spec))  ###  if __name__ == '__main__': | 
