diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/firewall-interface.py | 2 | ||||
-rwxr-xr-x | src/conf_mode/firewall.py | 6 | ||||
-rwxr-xr-x | src/conf_mode/policy-local-route.py | 47 | ||||
-rwxr-xr-x | src/conf_mode/policy-route.py | 26 | ||||
-rwxr-xr-x | src/conf_mode/policy.py | 6 | ||||
-rwxr-xr-x | src/conf_mode/service_upnp.py | 155 | ||||
-rw-r--r-- | src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper | 16 | ||||
-rw-r--r-- | src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup | 2 | ||||
-rwxr-xr-x | src/migration-scripts/firewall/6-to-7 | 189 | ||||
-rwxr-xr-x | src/op_mode/monitor_bandwidth_test.sh | 3 | ||||
-rw-r--r-- | src/systemd/miniupnpd.service | 13 |
11 files changed, 396 insertions, 69 deletions
diff --git a/src/conf_mode/firewall-interface.py b/src/conf_mode/firewall-interface.py index b0df9dff4..a7442ecbd 100755 --- a/src/conf_mode/firewall-interface.py +++ b/src/conf_mode/firewall-interface.py @@ -150,7 +150,7 @@ def apply(if_firewall): rule_action = 'insert' rule_prefix = '' - handle = state_policy_handle('ip filter', chain) + handle = state_policy_handle('ip6 filter', ipv6_chain) if handle: rule_action = 'add' rule_prefix = f'position {handle}' diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index 82223d60b..358b938e3 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -184,6 +184,12 @@ def verify_rule(firewall, rule_conf, ipv6): if duplicates: raise ConfigError(f'Cannot match a tcp flag as set and not set') + if 'protocol' in rule_conf: + if rule_conf['protocol'] == 'icmp' and ipv6: + raise ConfigError(f'Cannot match IPv4 ICMP protocol on IPv6, use ipv6-icmp') + if rule_conf['protocol'] == 'ipv6-icmp' and not ipv6: + raise ConfigError(f'Cannot match IPv6 ICMP protocol on IPv4, use icmp') + for side in ['destination', 'source']: if side in rule_conf: side_conf = rule_conf[side] diff --git a/src/conf_mode/policy-local-route.py b/src/conf_mode/policy-local-route.py index 6dabb37ae..71183c6ba 100755 --- a/src/conf_mode/policy-local-route.py +++ b/src/conf_mode/policy-local-route.py @@ -69,20 +69,47 @@ def get_config(config=None): # delete policy local-route rule x fwmark x # delete policy local-route rule x destination x.x.x.x if 'rule' in pbr[route]: - for rule in pbr[route]['rule']: + for rule, rule_config in pbr[route]['rule'].items(): src = leaf_node_changed(conf, base_rule + [rule, 'source']) fwmk = leaf_node_changed(conf, base_rule + [rule, 'fwmark']) dst = leaf_node_changed(conf, base_rule + [rule, 'destination']) + # keep track of changes in configuration + # otherwise we might remove an existing node although nothing else has changed + changed = False rule_def = {} - if src: - rule_def = dict_merge({'source' : src}, rule_def) - if fwmk: - rule_def = dict_merge({'fwmark' : fwmk}, rule_def) - if dst: - rule_def = dict_merge({'destination' : dst}, rule_def) - dict = dict_merge({dict_id : {rule : rule_def}}, dict) - pbr.update(dict) + # src is None if there are no changes to src + if src is None: + # if src hasn't changed, include it in the removal selector + # if a new selector is added, we have to remove all previous rules without this selector + # to make sure we remove all previous rules with this source(s), it will be included + if 'source' in rule_config: + rule_def = dict_merge({'source': rule_config['source']}, rule_def) + else: + # if src is not None, it's previous content will be returned + # this can be an empty array if it's just being set, or the previous value + # either way, something has to be changed and we only want to remove previous values + changed = True + # set the old value for removal if it's not empty + if len(src) > 0: + rule_def = dict_merge({'source' : src}, rule_def) + if fwmk is None: + if 'fwmark' in rule_config: + rule_def = dict_merge({'fwmark': rule_config['fwmark']}, rule_def) + else: + changed = True + if len(fwmk) > 0: + rule_def = dict_merge({'fwmark' : fwmk}, rule_def) + if dst is None: + if 'destination' in rule_config: + rule_def = dict_merge({'destination': rule_config['destination']}, rule_def) + else: + changed = True + if len(dst) > 0: + rule_def = dict_merge({'destination' : dst}, rule_def) + if changed: + dict = dict_merge({dict_id : {rule : rule_def}}, dict) + pbr.update(dict) return pbr @@ -116,6 +143,8 @@ def apply(pbr): if not pbr: return None + print(pbr) + # Delete old rule if needed for rule_rm in ['rule_remove', 'rule6_remove']: if rule_rm in pbr: diff --git a/src/conf_mode/policy-route.py b/src/conf_mode/policy-route.py index ee5197af0..7dcab4b58 100755 --- a/src/conf_mode/policy-route.py +++ b/src/conf_mode/policy-route.py @@ -205,6 +205,7 @@ def generate(policy): def apply_table_marks(policy): for route in ['route', 'route6']: if route in policy: + cmd_str = 'ip' if route == 'route' else 'ip -6' for name, pol_conf in policy[route].items(): if 'rule' in pol_conf: for rule_id, rule_conf in pol_conf['rule'].items(): @@ -213,20 +214,21 @@ def apply_table_marks(policy): if set_table == 'main': set_table = '254' table_mark = mark_offset - int(set_table) - cmd(f'ip rule add fwmark {table_mark} table {set_table}') + cmd(f'{cmd_str} rule add pref {set_table} fwmark {table_mark} table {set_table}') def cleanup_table_marks(): - json_rules = cmd('ip -j -N rule list') - rules = loads(json_rules) - for rule in rules: - if 'fwmark' not in rule or 'table' not in rule: - continue - fwmark = rule['fwmark'] - table = int(rule['table']) - if fwmark[:2] == '0x': - fwmark = int(fwmark, 16) - if (int(fwmark) == (mark_offset - table)): - cmd(f'ip rule del fwmark {fwmark} table {table}') + for cmd_str in ['ip', 'ip -6']: + json_rules = cmd(f'{cmd_str} -j -N rule list') + rules = loads(json_rules) + for rule in rules: + if 'fwmark' not in rule or 'table' not in rule: + continue + fwmark = rule['fwmark'] + table = int(rule['table']) + if fwmark[:2] == '0x': + fwmark = int(fwmark, 16) + if (int(fwmark) == (mark_offset - table)): + cmd(f'{cmd_str} rule del fwmark {fwmark} table {table}') def apply(policy): install_result = run(f'nft -f {nftables_conf}') diff --git a/src/conf_mode/policy.py b/src/conf_mode/policy.py index e251396c7..6b1d3bf1a 100755 --- a/src/conf_mode/policy.py +++ b/src/conf_mode/policy.py @@ -87,6 +87,7 @@ def verify(policy): # human readable instance name (hypen instead of underscore) policy_hr = policy_type.replace('_', '-') + entries = [] for rule, rule_config in instance_config['rule'].items(): mandatory_error = f'must be specified for "{policy_hr} {instance} rule {rule}"!' if 'action' not in rule_config: @@ -113,6 +114,11 @@ def verify(policy): if 'prefix' not in rule_config: raise ConfigError(f'A prefix {mandatory_error}') + # Check prefix duplicates + if rule_config['prefix'] in entries and ('ge' not in rule_config and 'le' not in rule_config): + raise ConfigError(f'Prefix {rule_config["prefix"]} is duplicated!') + entries.append(rule_config['prefix']) + # route-maps tend to be a bit more complex so they get their own verify() section if 'route_map' in policy: diff --git a/src/conf_mode/service_upnp.py b/src/conf_mode/service_upnp.py new file mode 100755 index 000000000..638296f45 --- /dev/null +++ b/src/conf_mode/service_upnp.py @@ -0,0 +1,155 @@ +#!/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 + +from sys import exit +import uuid +import netifaces +from ipaddress import IPv4Network +from ipaddress import IPv6Network + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.configdict import dict_search +from vyos.configdict import get_interface_dict +from vyos.configverify import verify_vrf +from vyos.util import call +from vyos.template import render +from vyos.template import is_ipv4 +from vyos.template import is_ipv6 +from vyos.xml import defaults +from vyos import ConfigError +from vyos import airbag +airbag.enable() + +config_file = r'/run/upnp/miniupnp.conf' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['service', 'upnp'] + upnpd = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + + if not upnpd: + return None + + if dict_search('rule', upnpd): + default_member_values = defaults(base + ['rule']) + for rule,rule_config in upnpd['rule'].items(): + upnpd['rule'][rule] = dict_merge(default_member_values, upnpd['rule'][rule]) + + uuidgen = uuid.uuid1() + upnpd.update({'uuid': uuidgen}) + + return upnpd + +def get_all_interface_addr(prefix, filter_dev, filter_family): + list_addr = [] + interfaces = netifaces.interfaces() + + for interface in interfaces: + if filter_dev and interface in filter_dev: + continue + addrs = netifaces.ifaddresses(interface) + if netifaces.AF_INET in addrs.keys(): + if netifaces.AF_INET in filter_family: + for addr in addrs[netifaces.AF_INET]: + if prefix: + # we need to manually assemble a list of IPv4 address/prefix + prefix = '/' + \ + str(IPv4Network('0.0.0.0/' + addr['netmask']).prefixlen) + list_addr.append(addr['addr'] + prefix) + else: + list_addr.append(addr['addr']) + if netifaces.AF_INET6 in addrs.keys(): + if netifaces.AF_INET6 in filter_family: + for addr in addrs[netifaces.AF_INET6]: + if prefix: + # we need to manually assemble a list of IPv4 address/prefix + bits = bin(int(addr['netmask'].replace(':', '').split('/')[0], 16)).count('1') + prefix = '/' + str(bits) + list_addr.append(addr['addr'] + prefix) + else: + list_addr.append(addr['addr']) + + return list_addr + +def verify(upnpd): + if not upnpd: + return None + + if 'wan_interface' not in upnpd: + raise ConfigError('To enable UPNP, you must have the "wan-interface" option!') + + if dict_search('rules', upnpd): + for rule,rule_config in upnpd['rule'].items(): + for option in ['external_port_range', 'internal_port_range', 'ip', 'action']: + if option not in rule_config: + raise ConfigError(f'A UPNP rule must have an "{option}" option!') + + if dict_search('stun', upnpd): + for option in ['host', 'port']: + if option not in upnpd['stun']: + raise ConfigError(f'A UPNP stun support must have an "{option}" option!') + + # Check the validity of the IP address + listen_dev = [] + system_addrs_cidr = get_all_interface_addr(True, [], [netifaces.AF_INET, netifaces.AF_INET6]) + system_addrs = get_all_interface_addr(False, [], [netifaces.AF_INET, netifaces.AF_INET6]) + for listen_if_or_addr in upnpd['listen']: + if listen_if_or_addr not in netifaces.interfaces(): + listen_dev.append(listen_if_or_addr) + if (listen_if_or_addr not in system_addrs) and (listen_if_or_addr not in system_addrs_cidr) and (listen_if_or_addr not in netifaces.interfaces()): + if is_ipv4(listen_if_or_addr) and IPv4Network(listen_if_or_addr).is_multicast: + raise ConfigError(f'The address "{listen_if_or_addr}" is an address that is not allowed to listen on. It is not an interface address nor a multicast address!') + if is_ipv6(listen_if_or_addr) and IPv6Network(listen_if_or_addr).is_multicast: + raise ConfigError(f'The address "{listen_if_or_addr}" is an address that is not allowed to listen on. It is not an interface address nor a multicast address!') + + system_listening_dev_addrs_cidr = get_all_interface_addr(True, listen_dev, [netifaces.AF_INET6]) + system_listening_dev_addrs = get_all_interface_addr(False, listen_dev, [netifaces.AF_INET6]) + for listen_if_or_addr in upnpd['listen']: + if listen_if_or_addr not in netifaces.interfaces() and (listen_if_or_addr not in system_listening_dev_addrs_cidr) and (listen_if_or_addr not in system_listening_dev_addrs) and is_ipv6(listen_if_or_addr) and (not IPv6Network(listen_if_or_addr).is_multicast): + raise ConfigError(f'{listen_if_or_addr} must listen on the interface of the network card') + +def generate(upnpd): + if not upnpd: + return None + + if os.path.isfile(config_file): + os.unlink(config_file) + + render(config_file, 'firewall/upnpd.conf.tmpl', upnpd) + +def apply(upnpd): + if not upnpd: + # Stop the UPNP service + call('systemctl stop miniupnpd.service') + else: + # Start the UPNP service + call('systemctl restart miniupnpd.service') + +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/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper index 74a7e83bf..9d5505758 100644 --- a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper +++ b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper @@ -4,7 +4,7 @@ IF_METRIC=${IF_METRIC:-210} # Check if interface is inside a VRF -VRF_OPTION=$(/usr/sbin/ip -j -d link show ${interface} | awk '{if(match($0, /.*"master":"(\w+)".*"info_slave_kind":"vrf"/, IFACE_DETAILS)) printf("vrf %s", IFACE_DETAILS[1])}') +VRF_OPTION=$(ip -j -d link show ${interface} | awk '{if(match($0, /.*"master":"(\w+)".*"info_slave_kind":"vrf"/, IFACE_DETAILS)) printf("vrf %s", IFACE_DETAILS[1])}') # get status of FRR function frr_alive () { @@ -66,9 +66,9 @@ function iptovtysh () { # delete the same route from kernel before adding new one function delroute () { logmsg info "Checking if the route presented in kernel: $@ $VRF_OPTION" - if /usr/sbin/ip route show $@ $VRF_OPTION | grep -qx "$1 " ; then - logmsg info "Deleting IP route: \"/usr/sbin/ip route del $@ $VRF_OPTION\"" - /usr/sbin/ip route del $@ $VRF_OPTION + if ip route show $@ $VRF_OPTION | grep -qx "$1 " ; then + logmsg info "Deleting IP route: \"ip route del $@ $VRF_OPTION\"" + ip route del $@ $VRF_OPTION fi } @@ -76,8 +76,8 @@ function delroute () { function ip () { # pass comand to system `ip` if this is not related to routes change if [ "$2" != "route" ] ; then - logmsg info "Passing command to /usr/sbin/ip: \"$@\"" - /usr/sbin/ip $@ + logmsg info "Passing command to iproute2: \"$@\"" + ip $@ else # if we want to work with routes, try to use FRR first if frr_alive ; then @@ -87,8 +87,8 @@ function ip () { vtysh -c "conf t" -c "$VTYSH_CMD" else # add ip route to kernel - logmsg info "Modifying routes in kernel: \"/usr/sbin/ip $@\"" - /usr/sbin/ip $@ $VRF_OPTION + logmsg info "Modifying routes in kernel: \"ip $@\"" + ip $@ $VRF_OPTION fi 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..a6989441b 100644 --- a/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup +++ b/src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup @@ -1,7 +1,7 @@ ## ## VyOS cleanup ## -# NOTE: here we use 'ip' wrapper, therefore a route will be actually deleted via /usr/sbin/ip or vtysh, according to the system state +# NOTE: here we use 'ip' wrapper, therefore a route will be actually deleted via ip or vtysh, according to the system state hostsd_client="/usr/bin/vyos-hostsd-client" hostsd_changes= # check vyos-hostsd status diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7 index bc0b19325..efc901530 100755 --- a/src/migration-scripts/firewall/6-to-7 +++ b/src/migration-scripts/firewall/6-to-7 @@ -17,8 +17,11 @@ # T2199: Remove unavailable nodes due to XML/Python implementation using nftables # monthdays: nftables does not have a monthdays equivalent # utc: nftables userspace uses localtime and calculates the UTC offset automatically +# icmp/v6: migrate previously available `type-name` to valid type/code # T4178: Update tcp flags to use multi value node +import re + from sys import argv from sys import exit @@ -41,49 +44,159 @@ if not config.exists(base): # Nothing to do exit(0) +icmp_remove = ['any'] +icmp_translations = { + 'ping': 'echo-request', + 'pong': 'echo-reply', + 'ttl-exceeded': 'time-exceeded', + # Network Unreachable + 'network-unreachable': [3, 0], + 'host-unreachable': [3, 1], + 'protocol-unreachable': [3, 2], + 'port-unreachable': [3, 3], + 'fragmentation-needed': [3, 4], + 'source-route-failed': [3, 5], + 'network-unknown': [3, 6], + 'host-unknown': [3, 7], + 'network-prohibited': [3, 9], + 'host-prohibited': [3, 10], + 'TOS-network-unreachable': [3, 11], + 'TOS-host-unreachable': [3, 12], + 'communication-prohibited': [3, 13], + 'host-precedence-violation': [3, 14], + 'precedence-cutoff': [3, 15], + # Redirect + 'network-redirect': [5, 0], + 'host-redirect': [5, 1], + 'TOS-network-redirect': [5, 2], + 'TOS host-redirect': [5, 3], + # Time Exceeded + 'ttl-zero-during-transit': [11, 0], + 'ttl-zero-during-reassembly': [11, 1], + # Parameter Problem + 'ip-header-bad': [12, 0], + 'required-option-missing': [12, 1] +} + +icmpv6_remove = [] +icmpv6_translations = { + 'ping': 'echo-request', + 'pong': 'echo-reply', + # Destination Unreachable + 'no-route': [1, 0], + 'communication-prohibited': [1, 1], + 'address-unreachble': [1, 3], + 'port-unreachable': [1, 4], + # Redirect + 'redirect': 'nd-redirect', + # Time Exceeded + 'ttl-zero-during-transit': [3, 0], + 'ttl-zero-during-reassembly': [3, 1], + # Parameter Problem + 'bad-header': [4, 0], + 'unknown-header-type': [4, 1], + 'unknown-option': [4, 2] +} + if config.exists(base + ['name']): for name in config.list_nodes(base + ['name']): - if config.exists(base + ['name', name, 'rule']): - for rule in config.list_nodes(base + ['name', name, 'rule']): - rule_time = base + ['name', name, 'rule', rule, 'time'] - rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags'] - - if config.exists(rule_time + ['monthdays']): - config.delete(rule_time + ['monthdays']) - - if config.exists(rule_time + ['utc']): - config.delete(rule_time + ['utc']) - - if config.exists(rule_tcp_flags): - tmp = config.return_value(rule_tcp_flags) - config.delete(rule_tcp_flags) - for flag in tmp.split(","): - if flag[0] == '!': - config.set(rule_tcp_flags + ['not', flag[1:].lower()]) - else: - config.set(rule_tcp_flags + [flag.lower()]) + if not config.exists(base + ['name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['name', name, 'rule']): + rule_time = base + ['name', name, 'rule', rule, 'time'] + rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags'] + rule_icmp = base + ['name', name, 'rule', rule, 'icmp'] + + if config.exists(rule_time + ['monthdays']): + config.delete(rule_time + ['monthdays']) + + if config.exists(rule_time + ['utc']): + config.delete(rule_time + ['utc']) + + if config.exists(rule_tcp_flags): + tmp = config.return_value(rule_tcp_flags) + config.delete(rule_tcp_flags) + for flag in tmp.split(","): + if flag[0] == '!': + config.set(rule_tcp_flags + ['not', flag[1:].lower()]) + else: + config.set(rule_tcp_flags + [flag.lower()]) + + if config.exists(rule_icmp + ['type-name']): + tmp = config.return_value(rule_icmp + ['type-name']) + if tmp in icmp_remove: + config.delete(rule_icmp + ['type-name']) + elif tmp in icmp_translations: + translate = icmp_translations[tmp] + if isinstance(translate, str): + config.set(rule_icmp + ['type-name'], value=translate) + elif isinstance(translate, list): + config.delete(rule_icmp + ['type-name']) + config.set(rule_icmp + ['type'], value=translate[0]) + config.set(rule_icmp + ['code'], value=translate[1]) + + for src_dst in ['destination', 'source']: + pg_base = base + ['name', name, 'rule', rule, src_dst, 'group', 'port-group'] + proto_base = base + ['name', name, 'rule', rule, 'protocol'] + if config.exists(pg_base) and not config.exists(proto_base): + config.set(proto_base, value='tcp_udp') if config.exists(base + ['ipv6-name']): for name in config.list_nodes(base + ['ipv6-name']): - if config.exists(base + ['ipv6-name', name, 'rule']): - for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): - rule_time = base + ['ipv6-name', name, 'rule', rule, 'time'] - rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags'] - - if config.exists(rule_time + ['monthdays']): - config.delete(rule_time + ['monthdays']) - - if config.exists(rule_time + ['utc']): - config.delete(rule_time + ['utc']) - - if config.exists(rule_tcp_flags): - tmp = config.return_value(rule_tcp_flags) - config.delete(rule_tcp_flags) - for flag in tmp.split(","): - if flag[0] == '!': - config.set(rule_tcp_flags + ['not', flag[1:].lower()]) - else: - config.set(rule_tcp_flags + [flag.lower()]) + if not config.exists(base + ['ipv6-name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): + rule_time = base + ['ipv6-name', name, 'rule', rule, 'time'] + rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags'] + rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6'] + + if config.exists(rule_time + ['monthdays']): + config.delete(rule_time + ['monthdays']) + + if config.exists(rule_time + ['utc']): + config.delete(rule_time + ['utc']) + + if config.exists(rule_tcp_flags): + tmp = config.return_value(rule_tcp_flags) + config.delete(rule_tcp_flags) + for flag in tmp.split(","): + if flag[0] == '!': + config.set(rule_tcp_flags + ['not', flag[1:].lower()]) + else: + config.set(rule_tcp_flags + [flag.lower()]) + + if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']): + tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol']) + if tmp == 'icmpv6': + config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp') + + if config.exists(rule_icmp + ['type']): + tmp = config.return_value(rule_icmp + ['type']) + type_code_match = re.match(r'^(\d+)/(\d+)$', tmp) + + if type_code_match: + config.set(rule_icmp + ['type'], value=type_code_match[1]) + config.set(rule_icmp + ['code'], value=type_code_match[2]) + elif tmp in icmpv6_remove: + config.delete(rule_icmp + ['type']) + elif tmp in icmpv6_translations: + translate = icmpv6_translations[tmp] + if isinstance(translate, str): + config.delete(rule_icmp + ['type']) + config.set(rule_icmp + ['type-name'], value=translate) + elif isinstance(translate, list): + config.set(rule_icmp + ['type'], value=translate[0]) + config.set(rule_icmp + ['code'], value=translate[1]) + else: + config.rename(rule_icmp + ['type'], 'type-name') + + for src_dst in ['destination', 'source']: + pg_base = base + ['ipv6-name', name, 'rule', rule, src_dst, 'group', 'port-group'] + proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol'] + if config.exists(pg_base) and not config.exists(proto_base): + config.set(proto_base, value='tcp_udp') try: with open(file_name, 'w') as f: diff --git a/src/op_mode/monitor_bandwidth_test.sh b/src/op_mode/monitor_bandwidth_test.sh index 900223bca..a6ad0b42c 100755 --- a/src/op_mode/monitor_bandwidth_test.sh +++ b/src/op_mode/monitor_bandwidth_test.sh @@ -24,6 +24,9 @@ elif [[ $(dig $1 AAAA +short | grep -v '\.$' | wc -l) -gt 0 ]]; then # Set address family to IPv6 when FQDN has at least one AAAA record OPT="-V" +else + # It's not IPv6, no option needed + OPT="" fi /usr/bin/iperf $OPT -c $1 $2 diff --git a/src/systemd/miniupnpd.service b/src/systemd/miniupnpd.service new file mode 100644 index 000000000..51cb2eed8 --- /dev/null +++ b/src/systemd/miniupnpd.service @@ -0,0 +1,13 @@ +[Unit] +Description=UPnP service +ConditionPathExists=/run/upnp/miniupnp.conf +After=vyos-router.service +StartLimitIntervalSec=0 + +[Service] +WorkingDirectory=/run/upnp +Type=simple +ExecStart=/usr/sbin/miniupnpd -d -f /run/upnp/miniupnp.conf +PrivateTmp=yes +PIDFile=/run/miniupnpd.pid +Restart=on-failure |