From 2202b028df2e028bf966e01ea33a20f8ca700659 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Thu, 28 Oct 2021 20:13:55 +0200 Subject: [PATCH] IPsec - VTI device [re]creation. could be https://github.com/opnsense/core/issues/5263 When local or remote isn't set to an ip address every configure will start removing the current device (and thus routes), although hostnames will likely always be a bit wacky (needs resolving, might change in which case the underlaying components likely miss the event). It's probably still a good idea to resolve when no addresses are used before concluding a device has changed. In the process change ipsec_resolve() to support both IPv4 and IPv6, but to limit risk, keep callers at IPv4 (which was the old behaviour), since it's not entirely sure we can use the phase 1 protocol for the tunnel itself as well. --- src/etc/inc/plugins.inc.d/ipsec.inc | 42 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/etc/inc/plugins.inc.d/ipsec.inc b/src/etc/inc/plugins.inc.d/ipsec.inc index 3d5a9c8a5..0a7806be8 100644 --- a/src/etc/inc/plugins.inc.d/ipsec.inc +++ b/src/etc/inc/plugins.inc.d/ipsec.inc @@ -230,17 +230,7 @@ function ipsec_firewall(\OPNsense\Firewall\Plugin $fw) if (isset($ph1ent['mobile'])) { $rgip = "any"; } elseif (!is_ipaddr($ph1ent['remote-gateway'])) { - $dns_qry_type = $ph1ent['protocol'] == 'inet6' ? DNS_AAAA : DNS_A; - $dns_qry_outfield = $ph1ent['protocol'] == 'inet6' ? "ipv6" : "ip"; - $dns_records = @dns_get_record($ph1ent['remote-gateway'], $dns_qry_type); - if (is_array($dns_records)) { - foreach ($dns_records as $dns_record) { - if (!empty($dns_record[$dns_qry_outfield])) { - $rgip = $dns_record[$dns_qry_outfield]; - break; - } - } - } + $rgip = ipsec_resolve($ph1ent['remote-gateway'], $ph1ent['protocol']); } else { $rgip = $ph1ent['remote-gateway']; } @@ -773,14 +763,20 @@ function ipsec_lookup_keypair($uuid) return $node ? $node->getNodes() : null; } -function ipsec_resolve($hostname) +function ipsec_resolve($hostname, $ipproto='inet') { if (!is_ipaddr($hostname)) { - /* XXX IPv4-only */ - $ip = gethostbyname($hostname); - if ($ip && $ip != $hostname) { - $hostname = $ip; + $dns_qry_type = $ipproto == 'inet6' ? DNS_AAAA : DNS_A; + $dns_qry_outfield = $ipproto == 'inet6' ? "ipv6" : "ip"; + $dns_records = @dns_get_record($hostname, $dns_qry_type); + if (is_array($dns_records)) { + foreach ($dns_records as $dns_record) { + if (!empty($dns_record[$dns_qry_outfield])) { + return $dns_record[$dns_qry_outfield]; + } + } } + return null; } return $hostname; @@ -1921,10 +1917,20 @@ function ipsec_configure_vti($verbose = false) // drop changed or not existing interfaces and tunnel endpoints foreach ($current_interfaces as $intf => $intf_details) { + $local_configured = $configured_intf[$intf]['local']; + $remote_configured = $configured_intf[$intf]['remote']; + if (!empty($configured_intf[$intf])) { + if (!is_ipaddr($configured_intf[$intf]['local'])) { + $local_configured = ipsec_resolve($configured_intf[$intf]['local']); + } + if (!is_ipaddr($configured_intf[$intf]['remote'])) { + $remote_configured = ipsec_resolve($configured_intf[$intf]['remote']); + } + } if ( empty($configured_intf[$intf]) - || $configured_intf[$intf]['local'] != $intf_details['tunnel']['src_addr'] - || $configured_intf[$intf]['remote'] != $intf_details['tunnel']['dest_addr'] + || $local_configured != $intf_details['tunnel']['src_addr'] + || $remote_configured != $intf_details['tunnel']['dest_addr'] ) { log_error(sprintf("destroy interface %s", $intf)); legacy_interface_destroy($intf);