interfaces: support disabling bind to IP aliases; closes #5086

This commit is contained in:
Franco Fichtner 2021-09-29 10:48:41 +02:00
parent 466ac29950
commit e0bcb7bd23
7 changed files with 80 additions and 27 deletions

View File

@ -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;
}
}
}

View File

@ -132,6 +132,10 @@ function dnsmasq_configure_do($verbose = false)
continue;
}
if (!$info['bind']) {
continue;
}
$addresses[] = $tmpaddr;
}

View File

@ -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;

View File

@ -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']) {

View File

@ -77,6 +77,10 @@ function webgui_configure_do($verbose = false, $interface = '')
continue;
}
if (!$info['bind']) {
continue;
}
$listeners[] = $tmpaddr;
}

View File

@ -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;
}
}
}

View File

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2014-2015 Deciso B.V.
* Copyright (C) 2014-2021 Deciso B.V.
* Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>
* Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>
* Copyright (C) 2004-2005 Scott Ullrich <sullrich@gmail.com>
@ -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("<?= html_safe(gettext('Please provide a single IP address.')) ?>");
break;
case "carp":
@ -388,6 +406,14 @@ $( document ).ready(function() {
</div>
</td>
</tr>
<tr id="bindrow">
<td><a id="help_for_bind" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?= gettext('Allow service binding') ?> </td>
<td>
<input id="bind" name="bind" type="checkbox" class="form-control" id="bind" <?= !empty($pconfig['bind']) ? 'checked="checked"' : '' ?> />
<div class="hidden" data-for="help_for_bind">
<?= gettext('Assigning services to the virtual IP\'s interface will automatically include this address. Uncheck to prevent binding to this address instead.');?>
</div>
</tr>
<tr>
<td><a id="help_for_gateway" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Gateway");?></td>
<td>
@ -400,7 +426,7 @@ $( document ).ready(function() {
<tr id="noexpandrow">
<td><a id="help_for_noexpand" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Expansion");?> </td>
<td>
<input id="noexpand" name="noexpand" type="checkbox" class="form-control unknown" id="noexpand" <?= !empty($pconfig['noexpand']) ? "checked=\"checked\"" : "" ; ?> />
<input id="noexpand" name="noexpand" type="checkbox" class="form-control" id="noexpand" <?= !empty($pconfig['noexpand']) ? "checked=\"checked\"" : "" ; ?> />
<div class="hidden" data-for="help_for_noexpand">
<?=gettext("Disable expansion of this entry into IPs on NAT lists (e.g. 192.168.1.0/24 expands to 256 entries.");?>
</div>
@ -462,7 +488,7 @@ $( document ).ready(function() {
<tr>
<td><a id="help_for_descr" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Description");?></td>
<td>
<input name="descr" type="text" class="form-control unknown" id="descr" size="40" value="<?=$pconfig['descr'];?>" />
<input name="descr" type="text" class="form-control" id="descr" size="40" value="<?=$pconfig['descr'];?>" />
<div class="hidden" data-for="help_for_adv">
<?=gettext("You may enter a description here for your reference (not parsed).");?>
</div>