From e0bcb7bd230a64adf09801ef12c84623afe221cb Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Wed, 29 Sep 2021 10:48:41 +0200 Subject: [PATCH] interfaces: support disabling bind to IP aliases; closes #5086 --- src/etc/inc/interfaces.inc | 15 ++-- src/etc/inc/plugins.inc.d/dnsmasq.inc | 4 ++ src/etc/inc/plugins.inc.d/openssh.inc | 4 ++ src/etc/inc/plugins.inc.d/unbound.inc | 8 +++ src/etc/inc/plugins.inc.d/webgui.inc | 4 ++ .../app/library/OPNsense/Routing/Gateways.php | 4 +- src/www/firewall_virtual_ip_edit.php | 68 +++++++++++++------ 7 files changed, 80 insertions(+), 27 deletions(-) diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index 1d7486fa4..c6545b386 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -4535,13 +4535,16 @@ function interfaces_addresses($interfaces, $as_subnet = false, $ifconfig_details $suffix = "/{$address['subnetbits']}"; $scope = ''; } - $result["{$address['ipaddr']}{$scope}{$suffix}"] = [ + $key = "{$address['ipaddr']}{$scope}{$suffix}"; + $result[$key] = [ 'address' => $address['ipaddr'], 'alias' => false, + 'bind' => true, 'bits' => $address['subnetbits'], 'deprecated' => !empty($address['deprecated']), 'family' => $proto == 'ipv4' ? 'inet' : 'inet6', 'interface' => !empty($ifcache[$realif]) ? $ifcache[$realif] : null, + 'key' => $key, 'name' => $realif, 'scope' => !empty($address['link-local']), ]; @@ -4549,21 +4552,25 @@ function interfaces_addresses($interfaces, $as_subnet = false, $ifconfig_details } } - foreach ($result as $addr => $info) { + foreach ($result as &$info) { foreach (config_read_array('virtualip', 'vip') as $vip) { if (empty($info['interface']) || $info['interface'] != $vip['interface'] || $vip['mode'] != 'ipalias') { continue; } if ($info['family'] == 'inet' && strpos($vip['subnet'], ':') === false) { - $result[$addr]['alias'] = $vip['subnet'] == $info['address']; + $info['alias'] = $vip['subnet'] == $info['address']; } elseif ($info['family'] == 'inet6' && strpos($vip['subnet'], ':') !== false) { /* * Since we do not know what subnet value was given by user * uncompress/compress to match correctly compressed system * value. */ - $result[$addr]['alias'] = Net_IPv6::compress(Net_IPv6::uncompress($vip['subnet'])) == $info['address']; + $info['alias'] = Net_IPv6::compress(Net_IPv6::uncompress($vip['subnet'])) == $info['address']; + } + + if ($info['alias'] && !empty($vip['nobind'])) { + $info['bind'] = false; } } } diff --git a/src/etc/inc/plugins.inc.d/dnsmasq.inc b/src/etc/inc/plugins.inc.d/dnsmasq.inc index 6d50e2cd6..c9d15e503 100644 --- a/src/etc/inc/plugins.inc.d/dnsmasq.inc +++ b/src/etc/inc/plugins.inc.d/dnsmasq.inc @@ -132,6 +132,10 @@ function dnsmasq_configure_do($verbose = false) continue; } + if (!$info['bind']) { + continue; + } + $addresses[] = $tmpaddr; } diff --git a/src/etc/inc/plugins.inc.d/openssh.inc b/src/etc/inc/plugins.inc.d/openssh.inc index 1d448e668..9dfa453a4 100644 --- a/src/etc/inc/plugins.inc.d/openssh.inc +++ b/src/etc/inc/plugins.inc.d/openssh.inc @@ -219,6 +219,10 @@ function openssh_configure_do($verbose = false, $interface = '') continue; } + if (!$info['bind']) { + continue; + } + if (count($listeners) >= 16) { log_error("The SSH listening address $tmpaddr cannot be added due to MAX_LISTEN_SOCKS limit reached."); continue; diff --git a/src/etc/inc/plugins.inc.d/unbound.inc b/src/etc/inc/plugins.inc.d/unbound.inc index 04dabd2c4..c274bc9a5 100644 --- a/src/etc/inc/plugins.inc.d/unbound.inc +++ b/src/etc/inc/plugins.inc.d/unbound.inc @@ -186,6 +186,10 @@ EOF; continue; } + if (!$info['bind']) { + continue; + } + $addresses[] = $tmpaddr; } @@ -681,6 +685,10 @@ function unbound_acls_subnets() $subnets = array('127.0.0.1/8', '::1/64'); foreach (interfaces_addresses(array_keys($active_interfaces), true) as $subnet => $info) { + if (!$info['bind']) { + continue; + } + if (!empty($active_interfaces[$info['name']]['net4']) && is_subnetv4($subnet)) { $subnet = explode('/', $subnet)[0] . '/' . $active_interfaces[$info['name']]['net4']; } elseif (!empty($active_interfaces[$info['name']]['net6']) && is_subnetv6($subnet) && !$info['scope']) { diff --git a/src/etc/inc/plugins.inc.d/webgui.inc b/src/etc/inc/plugins.inc.d/webgui.inc index 87be03e2b..09d1f7f5b 100644 --- a/src/etc/inc/plugins.inc.d/webgui.inc +++ b/src/etc/inc/plugins.inc.d/webgui.inc @@ -77,6 +77,10 @@ function webgui_configure_do($verbose = false, $interface = '') continue; } + if (!$info['bind']) { + continue; + } + $listeners[] = $tmpaddr; } diff --git a/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php b/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php index 64a2dc481..c28f19f32 100644 --- a/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php +++ b/src/opnsense/mvc/app/library/OPNsense/Routing/Gateways.php @@ -403,7 +403,7 @@ class Gateways * @param boolean $only_configured only return configured in interface or dynamic gateways * @return string|null gateway address */ - public function getInterfaceGateway($interface, $ipproto = "inet", $only_configured = false, $property='gateway') + public function getInterfaceGateway($interface, $ipproto = "inet", $only_configured = false, $property = 'gateway') { foreach ($this->getGateways() as $gateway) { if (!empty($gateway['disabled']) || $gateway['ipprotocol'] != $ipproto) { @@ -424,7 +424,7 @@ class Gateways // are not returned as valid gateway address (automatic outbound nat rules). // An alternative setup option would be practical here, less fuzzy. if (!$only_configured || $intf_gateway == $gateway['name'] || !empty($gateway['dynamic'])) { - return isset($gateway[$property]) ? $gateway[$property] : null ; + return isset($gateway[$property]) ? $gateway[$property] : null; } } } diff --git a/src/www/firewall_virtual_ip_edit.php b/src/www/firewall_virtual_ip_edit.php index 297b4a166..d47216687 100644 --- a/src/www/firewall_virtual_ip_edit.php +++ b/src/www/firewall_virtual_ip_edit.php @@ -1,7 +1,7 @@ * Copyright (C) 2003-2005 Manuel Kasper * Copyright (C) 2004-2005 Scott Ullrich @@ -48,13 +48,9 @@ function find_last_used_vhid() { return $vhid; } - -// create new vip array if none existent $a_vip = &config_read_array('virtualip', 'vip'); - if ($_SERVER['REQUEST_METHOD'] === 'GET') { - // input record id, if valid if (isset($_GET['dup']) && isset($a_vip[$_GET['dup']])) { $configId = $_GET['dup']; $after = $configId; @@ -62,23 +58,38 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $id = $_GET['id']; $configId = $id; } - $pconfig = array(); - $form_fields = array('mode', 'vhid', 'advskew', 'advbase', 'password', 'subnet', 'subnet_bits' - , 'descr' ,'type', 'interface', 'gateway' ); + + $pconfig = []; + $form_fields = [ + 'advbase', + 'advskew', + 'descr', + 'gateway', + 'interface', + 'mode', + 'noexpand', + 'password', + 'subnet', + 'subnet_bits', + 'type', + 'vhid', + ]; + + // initialize empty form fields + foreach ($form_fields as $fieldname) { + $pconfig[$fieldname] = null; + } + $pconfig['bind'] = null; if (isset($configId)) { // 1-on-1 copy of config data foreach ($form_fields as $fieldname) { if (isset($a_vip[$configId][$fieldname])) { - $pconfig[$fieldname] = $a_vip[$configId][$fieldname] ; + $pconfig[$fieldname] = $a_vip[$configId][$fieldname]; } } - } - - // initialize empty form fields - foreach ($form_fields as $fieldname) { - if (!isset($pconfig[$fieldname])) { - $pconfig[$fieldname] = null ; + if (empty($a_vip[$configId]['nobind'])) { + $pconfig['bind'] = 'yes'; } } } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { @@ -165,13 +176,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } if (count($input_errors) == 0) { - $vipent = array(); + $vipent = []; // defaults $vipent['type'] = "single"; $vipent['subnet_bits'] = "32"; // 1-on-1 copy attributes - foreach (array('mode', 'interface', 'descr', 'type', 'subnet_bits', 'subnet', 'vhid' - ,'advskew','advbase','password', 'gateway') as $fieldname) { + foreach (['mode', 'interface', 'descr', 'type', 'subnet_bits', 'subnet', 'vhid', + 'advskew','advbase','password', 'gateway'] as $fieldname) { if (isset($pconfig[$fieldname]) && $pconfig[$fieldname] != "") { $vipent[$fieldname] = $pconfig[$fieldname]; } @@ -181,6 +192,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { // noexpand, only used for proxyarp $vipent['noexpand'] = true; } + if (empty($pconfig['bind'])) { + // noexpand, only used for proxyarp + $vipent['nobind'] = true; + } // virtual ip UI keeps track of its changes in a separate file // (which is only use on apply in firewall_virtual_ip) @@ -239,7 +254,8 @@ $( document ).ready(function() { $("#type").attr('disabled', true); $("#gateway").attr('disabled', true); $("#subnet_bits").attr('disabled', true); - $("#noexpand").attr('disabled', true); + $("#bind").attr('disabled', true); + $("#bindrow").addClass("hidden"); $("#password").attr('disabled', true); $("#vhid").attr('disabled', true); $("#advskew").attr('disabled', true); @@ -254,6 +270,8 @@ $( document ).ready(function() { $("#gateway").attr('disabled', false); $("#vhid").attr('disabled', false); $("#subnet_bits").attr('disabled', false); + $("#bind").attr('disabled', false); + $("#bindrow").removeClass("hidden"); $("#typenote").html(""); break; case "carp": @@ -388,6 +406,14 @@ $( document ).ready(function() { + + + + /> + + @@ -400,7 +426,7 @@ $( document ).ready(function() { - /> + /> @@ -462,7 +488,7 @@ $( document ).ready(function() { - +