summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/firewall-interface.py2
-rwxr-xr-xsrc/conf_mode/firewall.py6
-rwxr-xr-xsrc/conf_mode/policy-local-route.py47
-rwxr-xr-xsrc/conf_mode/policy-route.py26
-rwxr-xr-xsrc/conf_mode/policy.py6
-rwxr-xr-xsrc/conf_mode/service_upnp.py155
-rw-r--r--src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper16
-rw-r--r--src/etc/dhcp/dhclient-exit-hooks.d/01-vyos-cleanup2
-rwxr-xr-xsrc/migration-scripts/firewall/6-to-7189
-rwxr-xr-xsrc/op_mode/monitor_bandwidth_test.sh3
-rw-r--r--src/systemd/miniupnpd.service13
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