diff --git a/src/etc/inc/plugins.inc.d/ipsec.inc b/src/etc/inc/plugins.inc.d/ipsec.inc index a6f409d2e..b70196b1e 100644 --- a/src/etc/inc/plugins.inc.d/ipsec.inc +++ b/src/etc/inc/plugins.inc.d/ipsec.inc @@ -1731,26 +1731,7 @@ function ipsec_configure_vti($verbose = false, $device = null) continue; } - $local_configured = null; - $remote_configured = null; - if (!empty($configured_intf[$intf])) { - if (!is_ipaddr($configured_intf[$intf]['local'])) { - $local_configured = ipsec_resolve($configured_intf[$intf]['local']); - } else { - $local_configured = $configured_intf[$intf]['local']; - } - if (!is_ipaddr($configured_intf[$intf]['remote'])) { - $remote_configured = ipsec_resolve($configured_intf[$intf]['remote']); - } else { - $remote_configured = $configured_intf[$intf]['remote']; - } - } - if ( - empty($configured_intf[$intf]) - || empty($intf_details['tunnel']) - || $local_configured != $intf_details['tunnel']['src_addr'] - || $remote_configured != $intf_details['tunnel']['dest_addr'] - ) { + if (empty($configured_intf[$intf])) { log_msg(sprintf("destroy interface %s", $intf), LOG_DEBUG); legacy_interface_destroy($intf); unset($current_interfaces[$intf]); @@ -1797,7 +1778,10 @@ function ipsec_configure_vti($verbose = false, $device = null) if (legacy_interface_create('ipsec', $intf) === null) { break; } - mwexecf('/sbin/ifconfig %s reqid %s', [$intf, $intf_details['reqid']]); + } + // [re]initialise if_ipsec + mwexecf('/sbin/ifconfig %s reqid %s', [$intf, $intf_details['reqid']]); + if (!empty($intf_details['local']) && !empty($intf_details['remote'])) { mwexecf('/sbin/ifconfig %s %s tunnel %s %s up', [ $intf, is_ipaddrv6($intf_details['local']) ? 'inet6' : 'inet', diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php b/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php index 0a85ada64..12f437a0c 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php @@ -92,6 +92,18 @@ class Swanctl extends BaseModel } } + if ( + (empty((string)$node->local) && !empty((string)$node->remote)) || + (!empty((string)$node->local) && empty((string)$node->remote)) + ) { + $messages->appendMessage( + new Message( + gettext("A local and remote address should be provided or both should be left empty"), + $key . ".local" + ) + ); + } + if ($vti_inets['local'] != $vti_inets['remote']) { $messages->appendMessage(new Message(gettext("Protocol families should match"), $key . ".local")); } diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml b/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml index 9bfad40d5..4b0193d18 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml @@ -365,13 +365,11 @@ N N - Y Please specify a valid address. N N - Y Please specify a valid address. diff --git a/src/opnsense/scripts/ipsec/updown_event.py b/src/opnsense/scripts/ipsec/updown_event.py index 32cbe4021..dd3030460 100755 --- a/src/opnsense/scripts/ipsec/updown_event.py +++ b/src/opnsense/scripts/ipsec/updown_event.py @@ -29,7 +29,6 @@ handle swanctl.conf updown event """ import os -import json import subprocess import argparse import tempfile @@ -37,7 +36,7 @@ import syslog from configparser import ConfigParser from lib import list_spds -spd_filename = '/usr/local/etc/swanctl/reqid_events.conf' +events_filename = '/usr/local/etc/swanctl/reqid_events.conf' spd_add_cmd = 'spdadd -%(ipproto)s %(source)s %(destination)s any ' \ '-P out ipsec %(protocol)s/tunnel/%(local)s-%(remote)s/unique:%(reqid)s;' @@ -54,47 +53,64 @@ if __name__ == '__main__': if cmd_args.action and cmd_args.action.startswith('up'): syslog.openlog('charon', facility=syslog.LOG_LOCAL4) syslog.syslog(syslog.LOG_NOTICE, '[UPDOWN] received %s event for reqid %s' % (cmd_args.action, cmd_args.reqid)) - if os.path.exists(spd_filename): + if os.path.exists(events_filename): cnf = ConfigParser() - cnf.read(spd_filename) + cnf.read(events_filename) spds = [] + vtis = [] for section in cnf.sections(): if cnf.get(section, 'reqid') == cmd_args.reqid \ or cnf.get(section, 'connection_child') == cmd_args.connection_child: - spds.append({ - 'reqid': cmd_args.reqid, - 'local' : cmd_args.local, - 'remote' : cmd_args.remote, - 'destination': os.environ.get('PLUTO_PEER_CLIENT') - }) - for opt in cnf.options(section): - if cnf.get(section, opt).strip() != '': - spds[-1][opt] = cnf.get(section, opt).strip() + if section.startswith('spd_'): + spds.append({ + 'reqid': cmd_args.reqid, + 'local' : cmd_args.local, + 'remote' : cmd_args.remote, + 'destination': os.environ.get('PLUTO_PEER_CLIENT') + }) + for opt in cnf.options(section): + if cnf.get(section, opt).strip() != '': + spds[-1][opt] = cnf.get(section, opt).strip() + elif section.startswith('vti_'): + vtis.append({ + 'reqid': cmd_args.reqid, + 'local' : cmd_args.local, + 'remote' : cmd_args.remote + }) - # (re)apply manual policies if specified - cur_spds = list_spds(automatic=False) - set_key = [] - for spd in cur_spds: - policy_found = False - for mspd in spds: - if mspd['source'] == spd['src'] and mspd['destination'] == spd['dst']: - policy_found = True - if policy_found or spd['reqid'] == cmd_args.reqid: - set_key.append('spddelete -n %(src)s %(dst)s any -P %(direction)s;' % spd) + for vti in vtis: + if None in vti.values(): + # incomplete, skip + continue + intf = 'ipsec%s' % vti['reqid'] + proto = 'inet6' if vti['local'].find(':') > -1 else 'inet' + subprocess.run(['/sbin/ifconfig', intf, 'reqid', vti['reqid']]) + subprocess.run(['/sbin/ifconfig', intf, proto, 'tunnel', vti['local'], vti['remote']]) - for spd in spds: - if None in spd.values(): - # incomplete, skip - continue - spd['ipproto'] = '4' if spd.get('source', '').find(':') == -1 else '6' - syslog.syslog( - syslog.LOG_NOTICE, - '[UPDOWN] add manual policy : %s' % (spd_add_cmd % spd)[7:] - ) - set_key.append(spd_add_cmd % spd) - if len(set_key) > 0: - f = tempfile.NamedTemporaryFile(mode='wt', delete=False) - f.write('\n'.join(set_key)) - f.close() - subprocess.run(['/sbin/setkey', '-f', f.name], capture_output=True, text=True) - os.unlink(f.name) + # (re)apply manual policies if specified + cur_spds = list_spds(automatic=False) + set_key = [] + for spd in cur_spds: + policy_found = False + for mspd in spds: + if mspd['source'] == spd['src'] and mspd['destination'] == spd['dst']: + policy_found = True + if policy_found or spd['reqid'] == cmd_args.reqid: + set_key.append('spddelete -n %(src)s %(dst)s any -P %(direction)s;' % spd) + + for spd in spds: + if None in spd.values(): + # incomplete, skip + continue + spd['ipproto'] = '4' if spd.get('source', '').find(':') == -1 else '6' + syslog.syslog( + syslog.LOG_NOTICE, + '[UPDOWN] add manual policy : %s' % (spd_add_cmd % spd)[7:] + ) + set_key.append(spd_add_cmd % spd) + if len(set_key) > 0: + f = tempfile.NamedTemporaryFile(mode='wt', delete=False) + f.write('\n'.join(set_key)) + f.close() + subprocess.run(['/sbin/setkey', '-f', f.name], capture_output=True, text=True) + os.unlink(f.name) diff --git a/src/opnsense/service/templates/OPNsense/IPsec/reqid_events.conf b/src/opnsense/service/templates/OPNsense/IPsec/reqid_events.conf index 9c3055f60..f652c6b1a 100644 --- a/src/opnsense/service/templates/OPNsense/IPsec/reqid_events.conf +++ b/src/opnsense/service/templates/OPNsense/IPsec/reqid_events.conf @@ -16,3 +16,14 @@ description = {{spd.description}} uuid = {{spd['@uuid']}} {% endif %} {% endfor %} + +{% for vti in helpers.toList('OPNsense.Swanctl.VTIs.VTI') %} +{% if vti.enabled == '1' and vti.local|default('') == '' and vti.remote|default('') == '' %} + +[vti_{{vti['@uuid']|replace('-', '')}}] +reqid = {{vti.reqid}} +description = {{vti.description}} +uuid = {{vti['@uuid']}} +{% endif %} +{% endfor %} +