load balancer: allow IPv4 subnets up to 64 addresses in Pools and Virtual Servers (PEV-394754)

This commit is contained in:
Darren Embry 2012-04-05 13:07:20 -04:00
parent 9859b2b553
commit 0917cb214b
4 changed files with 107 additions and 40 deletions

View File

@ -1048,6 +1048,43 @@ function alias_expand_urltable($name) {
return null;
}
function subnet_size ($subnet) {
if (is_subnetv4($subnet)) {
list ($ip, $bits) = explode("/", $subnet);
return round(exp(log(2) * (32 - $bits)));
}
else if (is_subnetv6($subnet)) {
list ($ip, $bits) = explode("/", $subnet);
return round(exp(log(2) * (128 - $bits)));
}
else {
return 0;
}
}
function subnet_expand ($subnet) {
if (is_subnetv4($subnet)) {
return subnetv4_expand($subnet);
} else if (is_subnetv6($subnet)) {
return subnetv6_expand($subnet);
} else {
return $subnet;
}
}
function subnetv4_expand ($subnet) {
$result = array();
list ($ip, $bits) = explode("/", $subnet);
$net = ip2long($ip);
$mask = (0xffffffff << (32 - $bits));
$net &= $mask;
$size = round(exp(log(2) * (32 - $bits)));
for ($i = 0; $i < $size; $i += 1) {
$result[] = long2ip($net | $i);
}
return $result;
}
/* find out whether two subnets overlap */
function check_subnets_overlap($subnet1, $bits1, $subnet2, $bits2) {

View File

@ -217,11 +217,21 @@ function relayd_configure($kill_first=false) {
if(is_array($pool_a[$i]['servers'])) {
if (!empty($pool_a[$i]['retry'])) {
$retrytext = " retry {$pool_a[$i]['retry']}";
$srvtxt = implode("{$retrytext}, ", $pool_a[$i]['servers']) . "{$retrytext}";
} else {
$srvtxt = implode(", ", $pool_a[$i]['servers']);
$retrytext = "";
}
$conf .= "table <{$pool_a[$i]['name']}> { $srvtxt }\n";
$conf .= "table <{$pool_a[$i]['name']}> {\n";
foreach ($pool_a[$i]['servers'] as $server) {
if (is_subnetv4($server)) {
foreach (subnetv4_expand($server) as $ip) {
$conf .= "\t{$ip}{$retrytext}\n";
}
}
else {
$conf .= "\t{$server}{$retrytext}\n";
}
}
$conf .= "}\n";
/* Index by name for easier fetching when we loop through the virtual servers */
$pools[$pool_a[$i]['name']] = $pool_a[$i];
}
@ -244,43 +254,55 @@ function relayd_configure($kill_first=false) {
// }
$conf .= "dns protocol \"dnsproto\" {\n";
$conf .= "\ttcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
$conf .= "\t" . "tcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
$conf .= "}\n";
if(is_array($vs_a)) {
for ($i = 0; isset($vs_a[$i]); $i++) {
if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
$conf .= "relay \"{$vs_a[$i]['name']}\" {\n";
$conf .= " listen on {$vs_a[$i]['ipaddr']} port {$vs_a[$i]['port']}\n";
if (is_subnetv4($vs_a[$i]['ipaddr'])) {
$ip_list = subnetv4_expand($vs_a[$i]['ipaddr']);
$name_format = "%s_%d";
}
else {
$ip_list = array($vs_a[$i]['ipaddr']);
$name_format = "%s"; /* in which case the second arg of the sprintf call below will be silently ignored */
}
for ($j = 0; $j < count($ip_list); $j += 1) {
$ip = $ip_list[$j];
$name = sprintf($name_format, $vs_a[$i]['name'], $j);
if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
$conf .= "relay \"{$name}\" {\n";
$conf .= " listen on {$ip} port {$vs_a[$i]['port']}\n";
if ($vs_a[$i]['relay_protocol'] == "dns") {
$conf .= " protocol \"dnsproto\"\n";
} else {
$conf .= " protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
if ($vs_a[$i]['relay_protocol'] == "dns") {
$conf .= " protocol \"dnsproto\"\n";
} else {
$conf .= " protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
}
$lbmode = "";
if ( $pools[$vs_a[$i]['pool']]['mode'] == "loadbalance" ) {
$lbmode = "mode loadbalance";
}
$conf .= " forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
$conf .= " forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
$conf .= "}\n";
} else {
$conf .= "redirect \"{$name}\" {\n";
$conf .= " listen on {$ip} port {$vs_a[$i]['port']}\n";
$conf .= " forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
if (isset($config['system']['lb_use_sticky']))
$conf .= " sticky-address\n";
/* sitedown MUST use the same port as the primary pool - sucks, but it's a relayd thing */
if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
$conf .= " forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
$conf .= "}\n";
}
$lbmode = "";
if ( $pools[$vs_a[$i]['pool']]['mode'] == "loadbalance" ) {
$lbmode = "mode loadbalance";
}
$conf .= " forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
$conf .= " forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
$conf .= "}\n";
} else {
$conf .= "redirect \"{$vs_a[$i]['name']}\" {\n";
$conf .= " listen on {$vs_a[$i]['ipaddr']} port {$vs_a[$i]['port']}\n";
$conf .= " forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
if (isset($config['system']['lb_use_sticky']))
$conf .= " sticky-address\n";
/* sitedown MUST use the same port as the primary pool - sucks, but it's a relayd thing */
if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
$conf .= " forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
$conf .= "}\n";
}
}
}

View File

@ -94,15 +94,21 @@ if ($_POST) {
if (is_array($_POST['servers'])) {
foreach($pconfig['servers'] as $svrent) {
if (!is_ipaddr($svrent)) {
$input_errors[] = sprintf(gettext("%s is not a valid IP address (in \"enabled\" list)."), $svrent);
if (!is_ipaddr($svrent) && !is_subnetv4($svrent)) {
$input_errors[] = sprintf(gettext("%s is not a valid IP address or IPv4 subnet (in \"enabled\" list)."), $svrent);
}
else if (is_subnetv4($svrent) && subnet_size($svrent) > 64) {
$input_errors[] = sprintf(gettext("%s is a subnet containing more than 64 IP addresses (in \"enabled\" list)."), $svrent);
}
}
}
if (is_array($_POST['serversdisabled'])) {
foreach($pconfig['serversdisabled'] as $svrent) {
if (!is_ipaddr($svrent)) {
$input_errors[] = sprintf(gettext("%s is not a valid IP address (in \"disabled\" list)."), $svrent);
if (!is_ipaddr($svrent) && !is_subnetv4($svrent)) {
$input_errors[] = sprintf(gettext("%s is not a valid IP address or IPv4 subnet (in \"disabled\" list)."), $svrent);
}
else if (is_subnetv4($svrent) && subnet_size($svrent) > 64) {
$input_errors[] = sprintf(gettext("%s is a subnet containing more than 64 IP addresses (in \"disabled\" list)."), $svrent);
}
}
}

View File

@ -91,8 +91,10 @@ if ($_POST) {
if (!is_port($_POST['port']))
$input_errors[] = gettext("The port must be an integer between 1 and 65535.");
if(!is_ipaddr($_POST['ipaddr']))
$input_errors[] = sprintf(gettext("%s is not a valid IP address."), $_POST['ipaddr']);
if (!is_ipaddr($_POST['ipaddr']) && !is_subnetv4($_POST['ipaddr']))
$input_errors[] = sprintf(gettext("%s is not a valid IP address or IPv4 subnet."), $_POST['ipaddr']);
else if (is_subnetv4($_POST['ipaddr']) && subnet_size($_POST['ipaddr']) > 64)
$input_errors[] = sprintf(gettext("%s is a subnet containing more than 64 IP addresses."), $_POST['ipaddr']);
if (!$input_errors) {
$vsent = array();