summaryrefslogtreecommitdiff
path: root/src/conf_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-xsrc/conf_mode/firewall.py70
-rwxr-xr-xsrc/conf_mode/interfaces_openvpn.py6
-rwxr-xr-xsrc/conf_mode/policy_route.py29
-rwxr-xr-xsrc/conf_mode/system_conntrack.py21
4 files changed, 99 insertions, 27 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index ec6b86ef2..352d5cbb1 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -128,7 +128,49 @@ def get_config(config=None):
return firewall
-def verify_rule(firewall, rule_conf, ipv6):
+def verify_jump_target(firewall, root_chain, jump_target, ipv6, recursive=False):
+ targets_seen = []
+ targets_pending = [jump_target]
+
+ while targets_pending:
+ target = targets_pending.pop()
+
+ if not ipv6:
+ if target not in dict_search_args(firewall, 'ipv4', 'name'):
+ raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
+ target_rules = dict_search_args(firewall, 'ipv4', 'name', target, 'rule')
+ else:
+ if target not in dict_search_args(firewall, 'ipv6', 'name'):
+ raise ConfigError(f'Invalid jump-target. Firewall ipv6 name {target} does not exist on the system')
+ target_rules = dict_search_args(firewall, 'ipv6', 'name', target, 'rule')
+
+ no_ipsec_in = root_chain in ('output', )
+
+ if target_rules:
+ for target_rule_conf in target_rules.values():
+ # Output hook types will not tolerate 'meta ipsec exists' matches even in jump targets:
+ if no_ipsec_in and (dict_search_args(target_rule_conf, 'ipsec', 'match_ipsec_in') is not None \
+ or dict_search_args(target_rule_conf, 'ipsec', 'match_none_in') is not None):
+ if not ipv6:
+ raise ConfigError(f'Invalid jump-target for {root_chain}. Firewall name {target} rules contain incompatible ipsec inbound matches')
+ else:
+ raise ConfigError(f'Invalid jump-target for {root_chain}. Firewall ipv6 name {target} rules contain incompatible ipsec inbound matches')
+ # Make sure we're not looping back on ourselves somewhere:
+ if recursive and 'jump_target' in target_rule_conf:
+ child_target = target_rule_conf['jump_target']
+ if child_target in targets_seen:
+ if not ipv6:
+ raise ConfigError(f'Loop detected in jump-targets, firewall name {target} refers to previously traversed name {child_target}')
+ else:
+ raise ConfigError(f'Loop detected in jump-targets, firewall ipv6 name {target} refers to previously traversed ipv6 name {child_target}')
+ targets_pending.append(child_target)
+ if len(targets_seen) == 7:
+ path_txt = ' -> '.join(targets_seen)
+ Warning(f'Deep nesting of jump targets has reached 8 levels deep, following the path {path_txt} -> {child_target}!')
+
+ targets_seen.append(target)
+
+def verify_rule(firewall, chain_name, rule_conf, ipv6):
if 'action' not in rule_conf:
raise ConfigError('Rule action must be defined')
@@ -139,12 +181,10 @@ def verify_rule(firewall, rule_conf, ipv6):
if 'jump' not in rule_conf['action']:
raise ConfigError('jump-target defined, but action jump needed and it is not defined')
target = rule_conf['jump_target']
- if not ipv6:
- if target not in dict_search_args(firewall, 'ipv4', 'name'):
- raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
+ if chain_name != 'name': # This is a bit clumsy, but consolidates a chunk of code.
+ verify_jump_target(firewall, chain_name, target, ipv6, recursive=True)
else:
- if target not in dict_search_args(firewall, 'ipv6', 'name'):
- raise ConfigError(f'Invalid jump-target. Firewall ipv6 name {target} does not exist on the system')
+ verify_jump_target(firewall, chain_name, target, ipv6, recursive=False)
if rule_conf['action'] == 'offload':
if 'offload_target' not in rule_conf:
@@ -185,8 +225,10 @@ def verify_rule(firewall, rule_conf, ipv6):
raise ConfigError('Limit rate integer cannot be less than 1')
if 'ipsec' in rule_conf:
- if {'match_ipsec', 'match_non_ipsec'} <= set(rule_conf['ipsec']):
- raise ConfigError('Cannot specify both "match-ipsec" and "match-non-ipsec"')
+ if {'match_ipsec_in', 'match_none_in'} <= set(rule_conf['ipsec']):
+ raise ConfigError('Cannot specify both "match-ipsec" and "match-none"')
+ if {'match_ipsec_out', 'match_none_out'} <= set(rule_conf['ipsec']):
+ raise ConfigError('Cannot specify both "match-ipsec" and "match-none"')
if 'recent' in rule_conf:
if not {'count', 'time'} <= set(rule_conf['recent']):
@@ -349,13 +391,11 @@ def verify(firewall):
raise ConfigError('default-jump-target defined, but default-action jump needed and it is not defined')
if name_conf['default_jump_target'] == name_id:
raise ConfigError(f'Loop detected on default-jump-target.')
- ## Now need to check that default-jump-target exists (other firewall chain/name)
- if target not in dict_search_args(firewall['ipv4'], 'name'):
- raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
+ verify_jump_target(firewall, name, target, False, recursive=True)
if 'rule' in name_conf:
for rule_id, rule_conf in name_conf['rule'].items():
- verify_rule(firewall, rule_conf, False)
+ verify_rule(firewall, name, rule_conf, False)
if 'ipv6' in firewall:
for name in ['name','forward','input','output', 'prerouting']:
@@ -369,13 +409,11 @@ def verify(firewall):
raise ConfigError('default-jump-target defined, but default-action jump needed and it is not defined')
if name_conf['default_jump_target'] == name_id:
raise ConfigError(f'Loop detected on default-jump-target.')
- ## Now need to check that default-jump-target exists (other firewall chain/name)
- if target not in dict_search_args(firewall['ipv6'], 'name'):
- raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
+ verify_jump_target(firewall, name, target, True, recursive=True)
if 'rule' in name_conf:
for rule_id, rule_conf in name_conf['rule'].items():
- verify_rule(firewall, rule_conf, True)
+ verify_rule(firewall, name, rule_conf, True)
#### ZONESSSS
local_zone = False
diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py
index 320ab7b7b..a03bd5959 100755
--- a/src/conf_mode/interfaces_openvpn.py
+++ b/src/conf_mode/interfaces_openvpn.py
@@ -322,8 +322,8 @@ def verify(openvpn):
if v4addr in openvpn['local_address'] and 'subnet_mask' not in openvpn['local_address'][v4addr]:
raise ConfigError('Must specify IPv4 "subnet-mask" for local-address')
- if dict_search('encryption.ncp_ciphers', openvpn):
- raise ConfigError('NCP ciphers can only be used in client or server mode')
+ if dict_search('encryption.data_ciphers', openvpn):
+ raise ConfigError('Cipher negotiation can only be used in client or server mode')
else:
# checks for client-server or site-to-site bridged
@@ -520,7 +520,7 @@ def verify(openvpn):
if dict_search('encryption.cipher', openvpn):
raise ConfigError('"encryption cipher" option is deprecated for TLS mode. '
- 'Use "encryption ncp-ciphers" instead')
+ 'Use "encryption data-ciphers" instead')
if dict_search('encryption.cipher', openvpn) == 'none':
print('Warning: "encryption none" was specified!')
diff --git a/src/conf_mode/policy_route.py b/src/conf_mode/policy_route.py
index c58fe1bce..223175b8a 100755
--- a/src/conf_mode/policy_route.py
+++ b/src/conf_mode/policy_route.py
@@ -25,6 +25,9 @@ from vyos.template import render
from vyos.utils.dict import dict_search_args
from vyos.utils.process import cmd
from vyos.utils.process import run
+from vyos.utils.network import get_vrf_tableid
+from vyos.defaults import rt_global_table
+from vyos.defaults import rt_global_vrf
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -83,6 +86,9 @@ def verify_rule(policy, name, rule_conf, ipv6, rule_id):
if not tcp_flags or 'syn' not in tcp_flags:
raise ConfigError(f'{name} rule {rule_id}: TCP SYN flag must be set to modify TCP-MSS')
+ if 'vrf' in rule_conf['set'] and 'table' in rule_conf['set']:
+ raise ConfigError(f'{name} rule {rule_id}: Cannot set both forwarding route table and VRF')
+
tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
if tcp_flags:
if dict_search_args(rule_conf, 'protocol') != 'tcp':
@@ -152,15 +158,26 @@ def apply_table_marks(policy):
for name, pol_conf in policy[route].items():
if 'rule' in pol_conf:
for rule_id, rule_conf in pol_conf['rule'].items():
+ vrf_table_id = None
set_table = dict_search_args(rule_conf, 'set', 'table')
- if set_table:
+ set_vrf = dict_search_args(rule_conf, 'set', 'vrf')
+ if set_vrf:
+ if set_vrf == 'default':
+ vrf_table_id = rt_global_vrf
+ else:
+ vrf_table_id = get_vrf_tableid(set_vrf)
+ elif set_table:
if set_table == 'main':
- set_table = '254'
- if set_table in tables:
+ vrf_table_id = rt_global_table
+ else:
+ vrf_table_id = set_table
+ if vrf_table_id is not None:
+ vrf_table_id = int(vrf_table_id)
+ if vrf_table_id in tables:
continue
- tables.append(set_table)
- table_mark = mark_offset - int(set_table)
- cmd(f'{cmd_str} rule add pref {set_table} fwmark {table_mark} table {set_table}')
+ tables.append(vrf_table_id)
+ table_mark = mark_offset - vrf_table_id
+ cmd(f'{cmd_str} rule add pref {vrf_table_id} fwmark {table_mark} table {vrf_table_id}')
def cleanup_table_marks():
for cmd_str in ['ip', 'ip -6']:
diff --git a/src/conf_mode/system_conntrack.py b/src/conf_mode/system_conntrack.py
index aa290788c..2529445bf 100755
--- a/src/conf_mode/system_conntrack.py
+++ b/src/conf_mode/system_conntrack.py
@@ -13,7 +13,7 @@
#
# 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 json
import os
from sys import exit
@@ -24,7 +24,8 @@ from vyos.configdep import set_dependents, call_dependents
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
-from vyos.utils.process import cmd
+from vyos.utils.file import write_file
+from vyos.utils.process import cmd, call
from vyos.utils.process import rc_cmd
from vyos.template import render
from vyos import ConfigError
@@ -34,6 +35,7 @@ airbag.enable()
conntrack_config = r'/etc/modprobe.d/vyatta_nf_conntrack.conf'
sysctl_file = r'/run/sysctl/10-vyos-conntrack.conf'
nftables_ct_file = r'/run/nftables-ct.conf'
+vyos_conntrack_logger_config = r'/run/vyos-conntrack-logger.conf'
# Every ALG (Application Layer Gateway) consists of either a Kernel Object
# also called a Kernel Module/Driver or some rules present in iptables
@@ -113,6 +115,7 @@ def get_config(config=None):
return conntrack
+
def verify(conntrack):
for inet in ['ipv4', 'ipv6']:
if dict_search_args(conntrack, 'ignore', inet, 'rule') != None:
@@ -181,6 +184,11 @@ def generate(conntrack):
if not os.path.exists(nftables_ct_file):
conntrack['first_install'] = True
+ if 'log' not in conntrack:
+ # Remove old conntrack-logger config and return
+ if os.path.exists(vyos_conntrack_logger_config):
+ os.unlink(vyos_conntrack_logger_config)
+
# Determine if conntrack is needed
conntrack['ipv4_firewall_action'] = 'return'
conntrack['ipv6_firewall_action'] = 'return'
@@ -199,6 +207,11 @@ def generate(conntrack):
render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.j2', conntrack)
render(sysctl_file, 'conntrack/sysctl.conf.j2', conntrack)
render(nftables_ct_file, 'conntrack/nftables-ct.j2', conntrack)
+
+ if 'log' in conntrack:
+ log_conf_json = json.dumps(conntrack['log'], indent=4)
+ write_file(vyos_conntrack_logger_config, log_conf_json)
+
return None
def apply(conntrack):
@@ -243,8 +256,12 @@ def apply(conntrack):
# See: https://bugzilla.redhat.com/show_bug.cgi?id=1264080
cmd(f'sysctl -f {sysctl_file}')
+ if 'log' in conntrack:
+ call(f'systemctl restart vyos-conntrack-logger.service')
+
return None
+
if __name__ == '__main__':
try:
c = get_config()