diff options
Diffstat (limited to 'config/haproxy-devel/pkg/haproxy.inc')
-rw-r--r-- | config/haproxy-devel/pkg/haproxy.inc | 1296 |
1 files changed, 976 insertions, 320 deletions
diff --git a/config/haproxy-devel/pkg/haproxy.inc b/config/haproxy-devel/pkg/haproxy.inc index 1bc62cb9..3d614fe0 100644 --- a/config/haproxy-devel/pkg/haproxy.inc +++ b/config/haproxy-devel/pkg/haproxy.inc @@ -37,7 +37,7 @@ require_once("haproxy_utils.inc"); require_once("haproxy_xmlrpcsyncclient.inc"); $d_haproxyconfdirty_path = $g['varrun_path'] . "/haproxy.conf.dirty"; - +#region Global haproxy array item definitions.. global $a_frontendmode; $a_frontendmode = array(); $a_frontendmode['http'] = array('name' => "http / https(offloading)", 'shortname' => "http/https"); @@ -66,7 +66,12 @@ $a_acltypes["path_matches"] = array('name' => 'Path matches:', $a_acltypes["path_regex"] = array('name' => 'Path regex:', 'mode' => 'http', 'syntax' => 'path_reg -i %1$s'); $a_acltypes["path_contains"] = array('name' => 'Path contains:', - 'mode' => 'http', 'syntax' => 'path_dir -i %1$s'); + 'mode' => 'http', 'syntax' => 'path_sub -i %1$s'); +$a_acltypes["url_parameter"] = array('name' => 'Url parameter contains:', + 'mode' => 'http', 'syntax' => 'url_param({parameter}) -i %1$s', + 'fields' => array( + array('name'=>"parameter",'columnheader'=>"Parameter name",'type'=>"textbox",'size'=>"50",'mask'=>'urlparameter') + )); $a_acltypes["ssl_c_verify_code"] = array('name' => 'SSL Client certificate verify error result:', 'mode' => 'http', 'syntax' => 'ssl_c_verify %1$s', 'require_client_cert' => '1'); // ssl_c_verify result codes: https://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS @@ -77,7 +82,10 @@ $a_acltypes["ssl_c_ca_commonname"] = array('name' => 'SSL Client issued by CA co $a_acltypes["source_ip"] = array('name' => 'Source IP matches IP or Alias:', 'mode' => '', 'syntax' => 'src %1$s'); $a_acltypes["backendservercount"] = array('name' => 'Minimum count usable servers:', - 'mode' => '', 'syntax' => 'nbsrv(%2$s) ge %1$d', 'parameters' => 'value,backendname'); + 'mode' => '', 'syntax' => 'nbsrv({backend}) ge %1$d', 'parameters' => 'value,backendname', + 'fields' => array( + 'backend' => array('name'=>"backend",'columnheader'=>"Backend",'type'=>"select",'size'=>"50",'mask'=>'backend') + )); $a_acltypes["traffic_is_http"] = array('name' => 'Traffic is http (no value needed):', 'inspect-delay' => '5', 'mode' => 'tcp', 'syntax' => 'req.proto_http', 'advancedoptions' => "tcp-request content accept if { req.proto_http }"); $a_acltypes["traffic_is_ssl"] = array('name' => 'Traffic is ssl (no value needed):', 'inspect-delay' => '5', @@ -224,7 +232,144 @@ $a_sysloglevel['notice'] = array('name' => "Notice"); $a_sysloglevel['info'] = array('name' => "Informational"); $a_sysloglevel['debug'] = array('name' => "Debugging"); -if(!function_exists('group_ports')){ +global $a_filestype; +$a_filestype = array(); +$a_filestype[''] = array('name' => "Errorfile"); +$a_filestype['luascript'] = array('name' => "Lua script"); +$a_filestype['writetodisk'] = array('name' => "Write to disk"); + +global $a_action; +$a_action = array(); +// +$a_action["use_backend"] = array('name' => "Use Backend", 'mode' => '', 'syntax' => 'use_backend {backend}', 'usage' => 'frontend', + 'fields' => array( + 'backend' => array('name'=>"backend",'columnheader'=>"Backend",'type'=>"select",'size'=>"50",'mask'=>'backend') + )); +$a_action["use_server"] = array('name' => "Use Server", 'mode' => '', 'syntax' => 'use-server {server}', 'usage' => 'backend', + 'fields' => array( + 'server' => array('name'=>"server",'columnheader'=>"Server",'type'=>"select",'size'=>"50",'mask'=>'server') + )); +// +$a_action["custom"] = array('name' => "Custom", 'mode' => '', + 'fields' => array( + array('name'=>"customaction",'columnheader'=>"Custom action",'type'=>"textbox",'size'=>"50",'mask'=>'freetext') + )); +// +$a_action["http-request_allow"] = array('name' => "http-request allow", 'mode'=> 'http', 'syntax' => 'http-request allow'); +$a_action["http-request_deny"] = array('name' => "http-request deny", 'mode'=> 'http', 'syntax' => 'http-request deny'); +$a_action["http-request_tarpit"] = array('name' => "http-request tarpit", 'mode'=> 'http', 'syntax' => 'http-request tarpit'); +$a_action["http-request_auth"] = array('name' => "http-request auth", 'mode'=> 'http', 'syntax' => 'http-request auth {realm}', + 'fields' => array( + array('name'=>"realm",'columnheader'=>"Realm",'type'=>"textbox",'size'=>"50",'mask'=>'freetext') + ) +); +$a_action["http-request_redirect"] = array('name' => "http-request redirect", 'mode'=> 'http', 'syntax' => 'http-request redirect {rule}', + 'fields' => array( + array('name'=>"rule",'columnheader'=>"Rule",'type'=>"textbox",'size'=>"50",'mask'=>'logformat') + ) +); +if (haproxy_version() >= '1.6') { + $a_action["http-request_lua"] = array('name' => "http-request lua action", 'mode'=> 'http', 'syntax' => 'http-request lua.{lua-function}', + 'fields' => array( + 'lua-function' => array('name'=>"lua-function",'columnheader'=>"lua function",'type'=>"textbox",'size'=>"50",'mask'=>'lua-function') + )); + $a_action["http-request_use-service"] = array('name' => "http-request lua service", 'mode'=> 'http', 'syntax' => 'http-request use-service lua.{lua-function}', + 'fields' => array( + 'lua-function' => array('name'=>"lua-function",'columnheader'=>"lua function",'type'=>"textbox",'size'=>"50",'mask'=>'lua-function') + )); +} +$a_action["http-request_add-header"] = array('name' => "http-request header add", 'mode'=> 'http', 'syntax' => 'http-request add-header {name} {fmt}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"fmt",'columnheader'=>"New logformat value",'type'=>"textbox",'size'=>"50",'mask'=>'logformat') + )); +$a_action["http-request_set-header"] = array('name' => "http-request header set", 'mode'=> 'http', 'syntax' => 'http-request set-header {name} {fmt}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"fmt",'columnheader'=>"New logformat value",'type'=>"textbox",'size'=>"50",'mask'=>'logformat') + )); +$a_action["http-request_del-header"] = array('name' => "http-request header delete", 'mode'=> 'http', 'syntax' => 'http-request del-header {name}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername') + )); +$a_action["http-request_replace-header"] = array('name' => "http-request header replace", 'mode'=> 'http', 'syntax' => 'http-request replace-header {name} {find} {replace}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"find",'columnheader'=>"Find regex",'type'=>"textbox",'size'=>"50",'mask'=>'match-regex'), + array('name'=>"replace",'columnheader'=>"Replace by",'type'=>"textbox",'size'=>"50",'mask'=>'replace-fmt') + )); +$a_action["http-request_replace-value"] = array('name' => "http-request header replace value", 'mode'=> 'http', 'syntax' => 'http-request replace-value {name} {find} {replace}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"find",'columnheader'=>"Find regex",'type'=>"textbox",'size'=>"50",'mask'=>'match-regex'), + array('name'=>"replace",'columnheader'=>"Replace by",'type'=>"textbox",'size'=>"50",'mask'=>'replace-fmt') + )); +// +$a_action["http-response_allow"] = array('name' => "http-response allow", 'mode'=> 'http', 'syntax' => 'http-response allow'); +$a_action["http-response_deny"] = array('name' => "http-response deny", 'mode'=> 'http', 'syntax' => 'http-response deny'); +if (haproxy_version() >= '1.6') { + $a_action["http-response_lua"] = array('name' => "http-response lua script", 'mode'=> 'http', 'syntax' => 'http-response lua.{lua-function}', + 'fields' => array( + 'lua-function' => array('name'=>"lua-function",'columnheader'=>"lua function",'type'=>"textbox",'size'=>"50",'mask'=>'lua-function') + )); +} +$a_action["http-response_add-header"] = array('name' => "http-response header add", 'mode'=> 'http', 'syntax' => 'http-response add-header {name} {fmt}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"fmt",'columnheader'=>"New logformat value",'type'=>"textbox",'size'=>"50",'mask'=>'logformat') + )); +$a_action["http-response_set-header"] = array('name' => "http-response header set", 'mode'=> 'http', 'syntax' => 'http-response set-header {name} {fmt}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"fmt",'columnheader'=>"New logformat value",'type'=>"textbox",'size'=>"50",'mask'=>'logformat') + )); +$a_action["http-response_del-header"] = array('name' => "http-response header delete", 'mode'=> 'http', 'syntax' => 'http-response del-header {name}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername') + )); +$a_action["http-response_replace-header"] = array('name' => "http-response header replace", 'mode'=> 'http', 'syntax' => 'http-response replace-header {name} {find} {replace}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"find",'columnheader'=>"Find regex",'type'=>"textbox",'size'=>"50",'mask'=>'match-regex'), + array('name'=>"replace",'columnheader'=>"Replace by",'type'=>"textbox",'size'=>"50",'mask'=>'replace-fmt') + )); +$a_action["http-response_replace-value"] = array('name' => "http-response header replace value", 'mode'=> 'http', 'syntax' => 'http-response replace-value {name} {find} {replace}', + 'fields' => array( + array('name'=>"name",'columnheader'=>"Headername",'type'=>"textbox",'size'=>"50",'mask'=>'headername'), + array('name'=>"find",'columnheader'=>"Find regex",'type'=>"textbox",'size'=>"50",'mask'=>'match-regex'), + array('name'=>"replace",'columnheader'=>"Replace by",'type'=>"textbox",'size'=>"50",'mask'=>'replace-fmt') + )); +// +$a_action["tcp-request_connection_accept"] = array('name' => "tcp-request connection accept", 'mode'=> '', 'syntax' => 'tcp-request connection accept'); +$a_action["tcp-request_connection_reject"] = array('name' => "tcp-request connection reject", 'mode'=> '', 'syntax' => 'tcp-request connection reject'); +// +$a_action["tcp-request_content_accept"] = array('name' => "tcp-request content accept", 'mode'=> '', 'syntax' => 'tcp-request content accept'); +$a_action["tcp-request_content_reject"] = array('name' => "tcp-request content reject", 'mode'=> '', 'syntax' => 'tcp-request content reject'); +if (haproxy_version() >= '1.6') { + $a_action["tcp-request_content_lua"] = array('name' => "tcp-request content lua script", 'mode'=> '', 'syntax' => 'tcp-request content lua.{lua-function}', + 'fields' => array( + 'lua-function' => array('name'=>"lua-function",'columnheader'=>"lua function",'type'=>"textbox",'size'=>"50",'mask'=>'lua-function') + )); + $a_action["tcp-request_content_use-service"] = array('name' => "tcp-request content use-service", 'mode'=> '', 'syntax' => 'tcp-request content use-service lua.{lua-function}', + 'fields' => array( + 'lua-function' => array('name'=>"lua-function",'columnheader'=>"lua function",'type'=>"textbox",'size'=>"50",'mask'=>'lua-function') + )); +} +// +$a_action["tcp-response_content_accept"] = array('name' => "tcp-response content accept", 'mode'=> '', 'syntax' => 'tcp-response content accept'); +$a_action["tcp-response_content_close"] = array('name' => "tcp-response content close", 'mode'=> '', 'syntax' => 'tcp-response content close'); +$a_action["tcp-response_content_reject"] = array('name' => "tcp-response content reject", 'mode'=> '', 'syntax' => 'tcp-response content reject'); +if (haproxy_version() >= '1.6') { + $a_action["tcp-response_content_lua"] = array('name' => "tcp-response content lua script", 'mode'=> '', 'syntax' => 'tcp-response content lua.{lua-function}', 'usage' => 'backend', + 'fields' => array( + 'lua-function' => array('name'=>"lua-function",'columnheader'=>"lua function",'type'=>"textbox",'size'=>"50",'mask'=>'lua-function') + )); +} + +#end + + +if (!function_exists('group_ports')) { // function group_ports() is present in pfSense 2.2 in util.inc /* create ranges of sequential port numbers (200:215) and remove duplicates */ function group_ports($ports) { @@ -243,7 +388,7 @@ function group_ports($ports) { for ($i = $begin; $i <= $end; $i++) if (!in_array($i, $uniq)) $uniq[] = $i; - } else if (is_port($port)) { + } elseif (is_port($port)) { if (!in_array($port, $uniq)) $uniq[] = $port; } @@ -276,7 +421,7 @@ function group_ports($ports) { } global $haproxy_version; -function haproxy_verion() { +function haproxy_version() { global $haproxy_version; if (empty($haproxy_version)) { $haproxy_version = shell_exec("haproxy -v | head -n 1 | awk '{ print $3 }'"); @@ -284,6 +429,89 @@ function haproxy_verion() { return $haproxy_version; } +function haproxy_css() { + if (!file_exists("/usr/local/www/bootstrap")) + return; + // quick fix to look a bit decent on bootstrapped pfSense.. + echo <<<EOD +<style type="text/css"> +.listtopic { + border-right: 1px solid #999999; + font-size: 11px; + background-color: #990000; + padding-right: 16px; + padding-left: 6px; + color: #FFFFFF; + font-weight: bold; + padding-top: 5px; + padding-bottom: 5px; +} +.tabcont { + background-color: #DDDDDD; + padding-right: 12px; + padding-left: 12px; + padding-top: 12px; + padding-bottom: 12px; +} +.vtable { + border-bottom: 1px solid #999999; +} +.vncell { + background-color: #DDDDDD; + padding-right: 20px; + padding-left: 8px; + border-bottom: 1px solid #999999; +} +.vncellreq { + background-color: #DDDDDD; + padding-right: 20px; + padding-left: 8px; + font-weight: bold; + border-bottom: 1px solid #999999; +} +.listhdrr { + background-color: #BBBBBB; + padding-right: 6px; + padding-left: 6px; + font-weight: bold; + border-right: 1px solid #999999; + border-bottom: 1px solid #999999; + font-size: 11px; + padding-top: 5px; + padding-bottom: 5px; +} +.listr { + background-color: #FFFFFF; + border-right: 1px solid #999999; + border-bottom: 1px solid #999999; + font-size: 11px; + padding-right: 6px; + padding-left: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +.listlr { + background-color: #FFFFFF; + border-right: 1px solid #999999; + border-bottom: 1px solid #999999; + border-left: 1px solid #999999; + font-size: 11px; + padding-right: 6px; + padding-left: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +.tabcont { + background-color: #DDDDDD; + padding-right: 12px; + padding-left: 12px; + padding-top: 12px; + padding-bottom: 12px; +} +</style> +EOD; +} + function haproxy_portoralias_to_list($port_or_alias) { // input: a port or aliasname: 80 https MyPortAlias // returns: a array of ports and portranges 80 443 8000:8010 @@ -298,7 +526,7 @@ function haproxy_portoralias_to_list($port_or_alias) { $portresult = array_merge($portresult, $portresults); } return $portresult; - } else if (is_portrange($port_or_alias)) { + } elseif (is_portrange($port_or_alias)) { return (array)$port_or_alias; } else { $ports = explode(",", $port_or_alias); @@ -420,7 +648,7 @@ haproxy_start () { require_once("haproxy.inc"); haproxy_configure(); ?> -ENDOFF +ENDOFF } haproxy_check () { @@ -504,10 +732,11 @@ function haproxy_find_backend($backendname) { function haproxy_find_acl($name) { global $a_acltypes; - if($a_acltypes) { + if ($a_acltypes) { foreach ($a_acltypes as $key => $acl) { - if ($key == $name) + if ($key == $name) { return $acl; + } } } } @@ -517,25 +746,30 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { $frontend = $backendsettings['frontend']; $ipversion = $backendsettings['ipversion']; $a_global = &$config['installedpackages']['haproxy']; - $a_mailers = &$config['installedpackages']['haproxy']['email_mailers']['items']; + $a_mailers = &$config['installedpackages']['haproxy']['email_mailers']['item']; + $a_resolvers = $config['installedpackages']['haproxy']['dns_resolvers']['item']; - if(!is_array($pool['ha_servers']['item']) && !$pool['stats_enabled']=='yes') + if (!is_array($pool['ha_servers']['item']) && !$pool['stats_enabled']=='yes') { return; + } global $a_checktypes, $a_cookiemode, $a_files_cache, $a_error; - + + $server_options = ""; $a_servers = &$pool['ha_servers']['item']; $frontendtype = $frontend['type']; fwrite ($fd, "backend " . $name . "\n"); // https is an alias for tcp for clarity purposes - if($frontendtype == "https") { + if ($frontendtype == "https") { $backend_mode = "tcp"; } else { $backend_mode = $frontendtype; } fwrite ($fd, "\tmode\t\t\t" . $backend_mode . "\n"); - - if (haproxy_verion() >= '1.6') { + fwrite ($fd, "\tlog\t\t\tglobal\n"); + + $use_haproxyresolvers = false; + if (haproxy_version() >= '1.6') { $use_mailers = is_array($a_mailers) && count($a_mailers) > 0; if ($use_mailers) { fwrite ($fd, "\t# use mailers\n"); @@ -562,6 +796,14 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { } } } + + $use_resolvers = is_array($a_resolvers) && count($a_resolvers) > 0; + if ($use_resolvers) { + $use_haproxyresolvers = true; + //server s1 app1.domain.com:80 resolvers mydns resolve-prefer ipv6 + $resolverprefer = ($ipversion == "ipv4" || $ipversion == "ipv6") ? $resolverprefer = " resolve-prefer {$ipversion}" : ""; + $server_options .= " resolvers globalresolvers" . $resolverprefer; + } } if ($pool['log-health-checks'] == 'yes') @@ -586,39 +828,46 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { fwrite ($fd, "\trspirep ^(Set-Cookie:((?!;\\ secure).)*)$ \\1;\ secure if { ssl_fc }\n"); } - if($pool['stats_enabled']=='yes') { + if ($pool['stats_enabled'] == 'yes') { fwrite ($fd, "\tstats\t\t\tenable\n"); - if($pool['stats_uri']) + if ($pool['stats_uri']) { fwrite ($fd, "\tstats\t\t\turi ".$pool['stats_uri']."\n"); - if($pool['stats_realm']) + } + if ($pool['stats_realm']) { fwrite ($fd, "\tstats\t\t\trealm " . haproxy_escapestring($pool['stats_realm']) . "\n"); - else + } else { fwrite ($fd, "\tstats\t\t\trealm .\n"); + } - if ($pool['stats_username'] && $pool['stats_password']) + if ($pool['stats_username'] && $pool['stats_password']) { fwrite ($fd, "\tstats\t\t\tauth " . haproxy_escapestring($pool['stats_username']).":". haproxy_escapestring($pool['stats_password'])."\n"); - - if($pool['stats_admin']=='yes') + } + if ($pool['stats_admin'] == 'yes') { fwrite ($fd, "\tstats\t\t\tadmin if TRUE" . "\n"); - - if($pool['stats_node']) + } + if ($pool['stats_node']) { fwrite ($fd, "\tstats\t\t\tshow-node " . $pool['stats_node'] . "\n"); - if($pool['stats_desc']) + } + if ($pool['stats_desc']) { fwrite ($fd, "\tstats\t\t\tshow-desc " . haproxy_escapestring($pool['stats_desc']) . "\n"); - if($pool['stats_refresh']) + } + if ($pool['stats_refresh']) { fwrite ($fd, "\tstats\t\t\trefresh " . $pool['stats_refresh'] . "\n"); + } if ($pool['stats_scope']) { $scope_items = explode(",", $pool['stats_scope']); - foreach($scope_items as $scope_item) + foreach($scope_items as $scope_item) { fwrite ($fd, "\tstats\t\t\tscope " . $scope_item . "\n"); + } } } if (is_arrayset($pool,'errorfiles','item')) { foreach($pool['errorfiles']['item'] as $errorfile) { - if (!is_array($a_files_cache))// load only once + if (!is_array($a_files_cache)) {// load only once $a_files_cache = haproxy_get_fileslist(); + } $file = $errorfile['errorfile']; $errorcodes = explode(",",$errorfile['errorcode']); foreach($errorcodes as $errorcode) { @@ -688,19 +937,35 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { } } - if($pool['balance']) - fwrite ($fd, "\tbalance\t\t\t" . $pool['balance'] . "\n"); - - if(!$pool['connection_timeout']) + if ($pool['balance']) { + $parameters = ""; + if ($pool['balance'] == 'uri') { + if (!empty($pool['balance_urilen'])) { + $parameters .= " len {$pool['balance_urilen']}"; + } + if (!empty($pool['balance_uridepth'])) { + $parameters .= " depth {$pool['balance_uridepth']}"; + } + if ($pool['balance_uriwhole'] == 'yes') { + $parameters .= " whole"; + } + + } + fwrite ($fd, "\tbalance\t\t\t{$pool['balance']}{$parameters}\n"); + } + if (!$pool['connection_timeout']) { $pool['connection_timeout'] = 30000; + } fwrite ($fd, "\ttimeout connect\t\t" . $pool['connection_timeout'] . "\n"); - if(!$pool['server_timeout']) + if (!$pool['server_timeout']) { $pool['server_timeout'] = 30000; + } fwrite ($fd, "\ttimeout server\t\t" . $pool['server_timeout'] . "\n"); - if(!$pool['retries']) + if (!$pool['retries']) { $pool['retries'] = 3; + } fwrite ($fd, "\tretries\t\t\t" . $pool['retries'] . "\n"); $addrprefix = ""; @@ -718,13 +983,15 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { } $uri = $pool['monitor_uri']; - if ($pool['monitor_uri']) + if ($pool['monitor_uri']) { $uri = $pool['monitor_uri']; - else + } else { $uri = "/"; - - if ($optioncheck) + } + + if ($optioncheck) { fwrite ($fd, "\toption\t\t\t{$optioncheck}\n"); + } if ($pool['advanced_backend']) { $adv_be = explode("\n", base64_decode($pool['advanced_backend'])); @@ -735,7 +1002,143 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { } } - if($pool['advanced']) { + global $a_action; + $config_acls = array(); + + $cert_acls = ""; + $aclcrt_name = ""; + $a_acl = get_backend_acls($pool, $frontendtype); + if (!is_array($a_acl)) { + $a_acl = array(); + } + // ACL's + foreach ($a_acl as $entry) { + $aclitem = $entry['ref']; + $expression = $aclitem['expression']; + + $aclname = $aclitem['name']; + $acltype = haproxy_find_acl($expression); + if (!isset($acltype)) + continue; + + // Filter out acls for different modes + if ($acltype['mode'] != '' && $acltype['mode'] != strtolower($frontendtype)) { + continue; + } + if ($acltype['inspect-delay'] != '') { + $inspectdelay = $acltype['inspect-delay']; + } + if ($acltype['advancedoptions'] != '') { + $advancedextra[$acltype['syntax']] = $acltype['advancedoptions']."\n"; + } + if ($acltype['require_client_cert']) { + $needs_clientcert[$aclname] = true; + } + if ($aclitem['certacl']) { + $aclname = "aclcrt_{$frontend['name']}"; + $aclcrt_name = $aclname; + } + + if (($expression == "source_ip") && is_alias($aclitem['value'])) { + $filename = "$configpath/ipalias_{$aclitem['value']}.lst"; + $listitems = haproxy_hostoralias_to_list($aclitem['value']); + $fd_alias = fopen("$filename", "w"); + foreach($listitems as $item) { + fwrite($fd_alias, $item."\r\n"); + } + fclose($fd_alias); + $expr = "src -f $filename"; + } else { + $expr = sprintf($acltype['syntax'], $aclitem['value']); + if (is_array($acltype['fields'])) { + foreach ($acltype['fields'] as $field) { + $fieldname = $field['name']; + $parameter = $aclitem[$expression . $fieldname]; + if ($fieldname == "backend") { + $backendname = $parameter . "_" . strtolower($bind['type'])."_".$ipversion; + $parameter = $backendname; + } + $expr = str_replace("{{$fieldname}}", $parameter, $expr); + } + } + } + $config_acls ["\tacl\t\t\t" . $aclname . "\t" . $expr . "\n"] = 1; + } + // Write acl's first, so they may be used by advanced text options written by user. + foreach($config_acls as $acl => $dummy) { + fwrite ($fd, $acl); + } + + $a_actionitems = $pool['a_actionitems']['item']; + if (!is_array($a_actionitems)) { + $a_actionitems = array(); + } + foreach ($a_actionitems as $actionitem) { + $actionid = $actionitem['action']; + $action = $a_action[$actionid]; + + $action_cfg = $action['syntax']; + + if (is_array($action['fields'])) { + foreach ($action['fields'] as $field) { + $fieldname = $field['name']; + $parameter = $actionitem[$actionid . $field['name']]; + + if ($fieldname == "backend") { + $backend = $parameter; + $backendname = $parameter . "_" . strtolower($bind['type'])."_".$ipversion; + if (!isset($a_pendingpl[$backendname])) { + $a_pendingpl[$backendname] = array(); + $a_pendingpl[$backendname]['name'] = $backendname; + $a_pendingpl[$backendname]['backend'] = $backend; + $a_pendingpl[$backendname]['frontend'] = $bind; + $a_pendingpl[$backendname]['ipversion'] = $ipversion; + } + $parameter = $backendname; + } + $action_cfg = str_replace("{{$fieldname}}", $parameter, $action_cfg); + } + } + $condition = ""; + if (!empty($actionitem['acl']) || !empty($systemacl)) { + $useclientcert = ""; + $useracls = ""; + $aclnames = explode(' ', $actionitem['acl']); + foreach($aclnames as $aclname) { + if ($needs_clientcert[$aclname]) { + $useclientcert = " aclsystem_ssl_c_used"; + } + $not = ""; + foreach ($a_acl as $entry) { + if ($entry['ref']['name'] == $aclname && $entry['ref']['not'] == 'yes') { + $not = "!"; + } + } + $useracls .= " {$not}{$aclname}"; + } + $condition = " if {$useracls}{$useclientcert} {$systemacl}"; + } + + $action = "\t{$action_cfg} {$condition}\n"; + + if ($actionid == "use_backend") { + if (empty($condition)) { + $config_usedefaultbackends .= "\tdefault_backend {$parameter}{$condition}\n"; + } else { + if (!empty($actionitem['acl'])){ + $config_usebackends .= $action; + } else { + // add use_backend if ipv4/6 before default_backend if any exists.. + $config_usedefaultbackends .= $action; + } + } + } else { + $config_actions .= $action; + } + } + fwrite ($fd, $config_actions); + + if ($pool['advanced']) { $advanced = base64_decode($pool['advanced']); $advanced_txt = " " . $advanced; } else { @@ -743,28 +1146,33 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { } if ($check_type != 'none') { - if($pool['checkinter']) + if ($pool['checkinter']) { $checkinter = " check inter {$pool['checkinter']}"; - else + } else { $checkinter = " check inter 1000"; + } } //agent-check requires at least haproxy v1.5dev20 - if ($pool['agent_check']) + if ($pool['agent_check']) { $agentcheck = " agent-check agent-inter {$pool['agent_inter']} agent-port {$pool['agent_port']}"; + } if (is_array($a_servers)) { foreach($a_servers as $be) { - if ($be['status'] == "inactive") + if ($be['status'] == "inactive") { continue; - if($be['cookie'] && $frontendtype == "http") + } + if ($be['cookie'] && $frontendtype == "http") { $cookie = " cookie {$be['cookie']}"; - else + } else { $cookie = ""; + } - if (!$be['name']) + if (!$be['name']) { $be['name'] = $be['address']; - if(!$be['status'] || $be['status'] != 'active') { + } + if (!$be['status'] || $be['status'] != 'active') { $isbackup = $be['status']; } else { $isbackup = ""; @@ -775,8 +1183,7 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { $crtfile = ""; $verifynone = ""; $verifyhost = ""; - if ($be['ssl'] == 'yes') - { + if ($be['ssl'] == 'yes') { $ssl = $frontendtype == "http" ? ' ssl' : ' check-ssl'; if ($be['sslserververify'] != 'yes') { @@ -803,24 +1210,25 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { haproxy_write_certificate_crt($filename, $server_clientcert, true); $crtfile = " crt $filename"; } - } $weight = ""; - if (is_numeric($be['weight'])){ + if (is_numeric($be['weight'])) { $weight = " weight " . $be['weight']; } $maxconn = ""; - if (is_numeric($be['maxconn'])){ + if (is_numeric($be['maxconn'])) { $maxconn = " maxconn " . $be['maxconn']; } + $unix_socket = false; $servers = array(); if ($be['forwardto'] && $be['forwardto'] != "") { + $unix_socket = true; $servers[] = "/{$be['forwardto']}.socket send-proxy-v2-ssl-cn"; } else { - if (is_ipaddr($be['address'])) { + if (is_ipaddr($be['address']) || $use_haproxyresolvers) { $servers[] = $be['address']; - } else if (is_hostname($be['address'])) { + } elseif (is_hostname($be['address'])) { $dnsresult_servers = haproxy_utils::query_dns($be['address'], $dnsquerytype); foreach($dnsresult_servers as $dnsresult_server){ $servers[] = $dnsresult_server['data']; @@ -831,18 +1239,26 @@ function write_backend($configpath, $fd, $name, $pool, $backendsettings) { foreach($servers as $server) { if (is_ipaddr($server)) { // skip ipv4 servers when using transparent client ip with ipv6 backend servers, and vice versa - if ($ipversion == "ipv4" && !is_ipaddrv4($server)) + if ($ipversion == "ipv4" && !is_ipaddrv4($server)) { continue; - if ($ipversion == "ipv6" && !is_ipaddrv6($server)) + } + if ($ipversion == "ipv6" && !is_ipaddrv6($server)) { continue; - if (isset($be['port'])) - $server = $server . ":" . $be['port']; + } + } else { + if (!$unix_socket) { + // place the ipv4@ or ipv6@ before the address, but not when using a unix socket + $server = $addrprefix . $server; + } + } + if (!empty($be['port'])) { + $server = $server . ":" . $be['port']; } $servername = $be['name']; if (count($servers) > 1) { $servername .= "_" . $counter; } - fwrite ($fd, "\tserver\t\t\t" . $servername . " " . $server . "$ssl$cookie$checkinter$checkport$agentcheck $isbackup$weight$maxconn$cafile$crlfile$verifynone$verifyhost$crtfile{$advanced_txt} {$be['advanced']}\n"); + fwrite ($fd, "\tserver\t\t\t" . $servername . " " . $server . "$ssl$cookie$checkinter$checkport$agentcheck $isbackup$weight$maxconn$cafile$crlfile$verifynone$verifyhost$crtfile$server_options{$advanced_txt} {$be['advanced']}\n"); $counter++; } } @@ -862,15 +1278,20 @@ function haproxy_check_and_run(&$messages, $reload) { haproxy_writeconf($testpath); $retval = exec("haproxy -c -V -f $testpath/haproxy.cfg 2>&1", $output, $err); $messages = ""; - if ($err > 1) + if ($err > 1) { $messages = "<h2><strong>FATAL ERROR CODE: $err while starting haproxy</strong></h2>"; - elseif ($err == 1) + } elseif ($err == 1) { $messages = "Errors found while starting haproxy"; + } if ((count($output) > 1) && $output[0] != "Configuration file is valid") { - foreach($output as $line) + $syslogmessage = ""; + foreach($output as $line) { $messages .= "<br/>" . htmlspecialchars($line) . "\n"; + $syslogmessage .= str_replace("\n"," ", $line) . " "; + } + syslog(LOG_NOTICE, "haproxy: check error output: {$syslogmessage}"); } $ok = strstr($retval, "Configuration file is valid"); if ($ok && $reload) { @@ -884,16 +1305,18 @@ function haproxy_check_and_run(&$messages, $reload) { function haproxy_lookup_cert($certid) { $res = lookup_ca($certid); - if (!$res) + if (!$res) { $res = lookup_cert($certid); + } return $res; } function haproxy_write_certificate_crt($filename, $certid, $include_psk = false, $append = false) { $cert = haproxy_lookup_cert($certid); $certcontent = base64_decode($cert['crt']); - if ($include_psk && isset($cert['prv'])) + if ($include_psk && isset($cert['prv'])) { $certcontent .= "\r\n".base64_decode($cert['prv']); + } $flags = $append ? FILE_APPEND : 0; file_put_contents($filename, $certcontent, $flags); unset($certcontent); @@ -902,6 +1325,7 @@ function haproxy_write_certificate_crt($filename, $certid, $include_psk = false, function haproxy_write_certificate_crl($filename, $crlid, $append = false) { $crl = lookup_crl($crlid); + crl_update($crl); $content = base64_decode($crl['text']); $flags = $append ? FILE_APPEND : 0; file_put_contents($filename, $content, $flags); @@ -913,18 +1337,21 @@ function haproxy_write_certificate_fullchain($filename, $certid, $append = false $cert = haproxy_lookup_cert($certid); $certcontent = base64_decode($cert['crt']); - if (isset($cert['prv'])) + if (isset($cert['prv'])) { $certcontent .= "\r\n".base64_decode($cert['prv']); + } $ca = $cert; while(!empty($ca['caref'])) { $ca = lookup_ca($ca['caref']); if ($ca) { - if ($skiproot && (cert_get_subject($ca['crt']) == cert_get_issuer($ca['crt']))) + if ($skiproot && (cert_get_subject($ca['crt']) == cert_get_issuer($ca['crt']))) { break; + } $certcontent .= "\r\n" . base64_decode($ca['crt']); - } else + } else { break; + } } $flags = $append ? FILE_APPEND : 0; file_put_contents($filename, $certcontent, $flags); @@ -947,8 +1374,9 @@ function haproxy_write_certificate_issuer($filename, $certid) { function haproxy_uses_ocsp() { global $config; $a_frontends = &$config['installedpackages']['haproxy']['ha_backends']['item']; - if (!is_array($a_frontends)) + if (!is_array($a_frontends)) { return false; + } $configpath = "{$g['varetc_path']}/haproxy"; foreach ($a_frontends as $frontend) { @@ -977,9 +1405,9 @@ function haproxy_updateocsp_one($socketupdate, $filename, $name) { if ($socketupdate) { $ocspresponse = base64_encode(file_get_contents("{$filename}.ocsp")); $r = haproxy_socket_command("set ssl ocsp-response $ocspresponse"); - if ($r[0] == "OCSP Response updated!\n") + if ($r[0] == "OCSP Response updated!\n") { syslog(LOG_NOTICE, "HAProxy OCSP socket update successful for frontend {$name}..result: ".$retval); - else { + } else { syslog(LOG_ERR, "HAProxy OCSP ERROR while performing haproxy socket update OCSP response for: {$name}"); } } else { @@ -992,8 +1420,9 @@ function haproxy_updateocsp_one($socketupdate, $filename, $name) { function haproxy_updateocsp($socketupdate = true) { global $config, $g; $a_frontends = &$config['installedpackages']['haproxy']['ha_backends']['item']; - if (!is_array($a_frontends)) + if (!is_array($a_frontends)) { return true; + } $configpath = "{$g['varetc_path']}/haproxy"; foreach ($a_frontends as $frontend) { @@ -1012,10 +1441,12 @@ function haproxy_updateocsp($socketupdate = true) { } function haproxy_writeconf($configpath) { - global $config; + global $config, $a_files_cache; global $aliastable; - if (!isset($aliastable)) + global $a_action; + if (!isset($aliastable)) { alias_make_table($config); + } $chroot_dir = "/tmp/haproxy_chroot"; // can contain socket to forward connection from backend to frontend. "/var/empty" @mkdir($chroot_dir, 0755, true); @@ -1027,38 +1458,64 @@ function haproxy_writeconf($configpath) { $a_global = &$config['installedpackages']['haproxy']; $a_frontends = &$config['installedpackages']['haproxy']['ha_backends']['item']; $a_backends = &$config['installedpackages']['haproxy']['ha_pools']['item']; - $a_mailers = &$config['installedpackages']['haproxy']['email_mailers']['items']; + $a_mailers = &$config['installedpackages']['haproxy']['email_mailers']['item']; + $a_resolvers = &$config['installedpackages']['haproxy']['dns_resolvers']['item']; + $a_files = &$config['installedpackages']['haproxy']['files']['item']; + if (!is_array($a_frontends)) { + $a_frontends = array(); + } + if (!is_array($a_backends)) { + $a_backends = array(); + } + if (!is_array($a_mailers)) { + $a_mailers = array(); + } + if (!is_array($a_resolvers)) { + $a_resolvers = array(); + } $fd = fopen($configfile, "w"); - if(is_array($a_global)) { + if (is_array($a_global)) { fwrite ($fd, "global\n"); - if ($a_global['maxconn']) + if ($a_global['maxconn']) { fwrite ($fd, "\tmaxconn\t\t\t".$a_global['maxconn']."\n"); - if($a_global['remotesyslog']) + } + if ($a_global['remotesyslog']) { fwrite ($fd, "\tlog\t\t\t{$a_global['remotesyslog']}\t{$a_global['logfacility']}\t{$a_global['loglevel']}\n"); + } fwrite ($fd, "\tstats socket /tmp/haproxy.socket level admin\n"); - if(!use_transparent_clientip_proxying()) + if(!use_transparent_clientip_proxying()) { fwrite ($fd, "\tuid\t\t\t80\n"); - + } + fwrite ($fd, "\tgid\t\t\t80\n"); // Set numprocs if defined or use system default (#cores) - if($a_global['nbproc']) - $numprocs = $a_global['nbproc']; - else - $numprocs ="1"; + $numprocs = $a_global['nbproc'] ? $a_global['nbproc'] : "1"; fwrite ($fd, "\tnbproc\t\t\t$numprocs\n"); fwrite ($fd, "\tchroot\t\t\t$chroot_dir\n"); fwrite ($fd, "\tdaemon\n"); - //fwrite ($fd, "\tssl-server-verify none\n"); - if($a_global['ssldefaultdhparam']) + if ($a_global['ssldefaultdhparam']) { fwrite ($fd, "\ttune.ssl.default-dh-param\t{$a_global['ssldefaultdhparam']}\n"); - if($a_global['log-send-hostname']) + } + if ($a_global['log-send-hostname']) { fwrite ($fd, "\tlog-send-hostname\t\t{$a_global['log-send-hostname']}\n"); + } + + // lua-load + if (is_array($a_files)) { + foreach($a_files as $file) { + if ($file['type'] == "luascript") { + $luafile = $configpath . "/luascript_" . $file['name']; + file_put_contents($luafile, base64_decode($file['content']), 0); + fwrite ($fd, "\tlua-load\t\t{$luafile}\n"); + } + } + } // Keep the advanced options on the bottom of the global settings, to allow additional sections to be easely added - if($a_global['advanced']) { + if ($a_global['advanced']) { $adv = explode("\n", base64_decode($a_global['advanced'])); foreach($adv as $adv_line) { fwrite($fd, "\t" . str_replace("\r", "", $adv_line) . "\n"); @@ -1073,8 +1530,9 @@ function haproxy_writeconf($configpath) { fwrite ($fd, "\tbind 127.0.0.1:$localstatsport name localstats\n"); fwrite ($fd, "\tmode http\n"); fwrite ($fd, "\tstats enable\n"); - if (is_numeric($a_global['localstats_refreshtime'])) + if (is_numeric($a_global['localstats_refreshtime'])) { fwrite ($fd, "\tstats refresh {$a_global['localstats_refreshtime']}\n"); + } fwrite ($fd, "\tstats admin if TRUE\n"); fwrite ($fd, "\tstats uri /haproxy_stats.php?haproxystats=1\n"); fwrite ($fd, "\ttimeout client 5000\n"); @@ -1084,7 +1542,7 @@ function haproxy_writeconf($configpath) { } } - if (haproxy_verion() >= '1.6') { + if (haproxy_version() >= '1.6') { $use_mailers = is_array($a_mailers) && count($a_mailers) > 0; if ($use_mailers) { fwrite ($fd, "mailers globalmailers\n"); @@ -1093,16 +1551,26 @@ function haproxy_writeconf($configpath) { } fwrite ($fd, "\n"); } + $use_resolvers = is_array($a_resolvers) && count($a_resolvers) > 0; + if ($use_resolvers) { + fwrite ($fd, "resolvers globalresolvers\n"); + foreach($a_resolvers as $resolver) { + fwrite ($fd, "\tnameserver {$resolver['name']} {$resolver['server']}:{$resolver['port']}\n"); + } + fwrite ($fd, "\tresolve_retries {$a_global['resolver_retries']}\n"); + fwrite ($fd, "\ttimeout retry {$a_global['resolver_timeoutretry']}\n"); + fwrite ($fd, "\thold valid {$a_global['resolver_holdvalid']}\n"); + fwrite ($fd, "\n"); + } } // Try and get a unique array for address:port as frontends can duplicate $a_bind = array(); - if(is_array($a_frontends)) { + if (is_array($a_frontends)) { foreach ($a_frontends as $frontend) { - if($frontend['status'] != 'active') - continue; - if(!$frontend['backend_serverpool']) + if ($frontend['status'] != 'active') { continue; + } $primaryfrontend = get_primaryfrontend($frontend); $bname = $primaryfrontend['name']; @@ -1131,8 +1599,8 @@ function haproxy_writeconf($configpath) { $subfolder = "$configpath/{$frontend['name']}"; $certs = $frontend['ha_certificates']['item']; - if (is_array($certs)){ - if (count($certs) > 0){ + if (is_array($certs)) { + if (count($certs) > 0) { @mkdir($subfolder, 0755, true); foreach($certs as $cert){ $filenamefoldercert = "$subfolder/{$cert['ssl_certificate']}.pem"; @@ -1148,7 +1616,7 @@ function haproxy_writeconf($configpath) { $ssl_crt .= " crt $subfolder"; } } - }else{ + } else { $ssl_crt=""; unlink_if_exists("var/etc/{$frontend['name']}.{$frontend['port']}.crt");//cleanup for possible old haproxy package version } @@ -1161,8 +1629,9 @@ function haproxy_writeconf($configpath) { } if ($ssl_crt != "") { - if ($b['ssl_info'] == "") + if ($b['ssl_info'] == "") { $b['ssl_info'] = "ssl {$frontend['dcertadv']}"; + } $b['ssl_info'] .= $ssl_crt; } @@ -1170,26 +1639,26 @@ function haproxy_writeconf($configpath) { $b['config'][] = $frontend; } } - $a_pendingpl = array(); // Construct and write out configuration for each "frontend" - if(is_array($a_bind)) { + if (is_array($a_bind)) { foreach ($a_bind as $bind) { - if (count($bind['config']) > 1) + if (count($bind['config']) > 1) { $frontendinfo = "frontend {$bind['name']}-merged\n"; - else + } else { $frontendinfo = "frontend {$bind['name']}\n"; + } fwrite ($fd, "{$frontendinfo}"); $advancedextra = array(); $ca_file = ""; $first = true; - if (is_array($bind['clientcert_ca']['item'])){ + if (is_array($bind['clientcert_ca']['item'])) { $filename = "$configpath/clientca_{$bind['name']}.pem"; - foreach($bind['clientcert_ca']['item'] as $ca){ - if (!empty($ca['cert_ca'])){ + foreach($bind['clientcert_ca']['item'] as $ca) { + if (!empty($ca['cert_ca'])) { haproxy_write_certificate_crt($filename, $ca['cert_ca'], false, !$first); $first = false; } @@ -1199,9 +1668,9 @@ function haproxy_writeconf($configpath) { } $crl_file = ""; $first = true; - if (is_array($bind['clientcert_crl']['item'])){ + if (is_array($bind['clientcert_crl']['item'])) { $filename = "$configpath/clientcrl_{$bind['name']}.pem"; - foreach($bind['clientcert_crl']['item'] as $ca){ + foreach($bind['clientcert_crl']['item'] as $ca) { haproxy_write_certificate_crl($filename, $ca['cert_crl'], !$first); $first = false; } @@ -1210,8 +1679,9 @@ function haproxy_writeconf($configpath) { $advanced_bind = $bind['advanced_bind']; $ssl_info = $bind['ssl_info']; $ssl_info .= $ca_file . $crl_file; - if ($bind['sslclientcert-invalid']) + if ($bind['sslclientcert-invalid']) { $ssl_info .= " crt-ignore-err all"; + } $useipv4 = false; $useipv6 = false; @@ -1226,12 +1696,12 @@ function haproxy_writeconf($configpath) { } fwrite ($fd, "{$listenip}"); - if (use_frontend_as_unixsocket($bind['name'])){ + if (use_frontend_as_unixsocket($bind['name'])) { fwrite ($fd, "\tbind /tmp/haproxy_chroot/{$bind['name']}.socket name unixsocket accept-proxy {$ssl_info} {$advanced_bind}\n"); } // https is an alias for tcp for clarity purposes - if($bind['type'] == "https") { + if ($bind['type'] == "https") { $backend_type = "tcp"; } else { $backend_type = $bind['type']; @@ -1240,26 +1710,32 @@ function haproxy_writeconf($configpath) { fwrite ($fd, "\tmode\t\t\t" . $backend_type . "\n"); fwrite ($fd, "\tlog\t\t\tglobal\n"); - if ($bind['socket-stats'] == 'yes') + if ($bind['socket-stats'] == 'yes') { fwrite ($fd, "\toption\t\t\tsocket-stats\n"); - if ($bind['dontlognull'] == 'yes') + } + if ($bind['dontlognull'] == 'yes') { fwrite ($fd, "\toption\t\t\tdontlognull\n"); - if ($bind['dontlog-normal'] == 'yes') + } + if ($bind['dontlog-normal'] == 'yes') { fwrite ($fd, "\toption\t\t\tdontlog-normal\n"); - if ($bind['log-separate-errors'] == 'yes') + } + if ($bind['log-separate-errors'] == 'yes') { fwrite ($fd, "\toption\t\t\tlog-separate-errors\n"); - if ($bind['log-detailed'] == 'yes'){ - if ($backend_type == 'http') + } + if ($bind['log-detailed'] == 'yes') { + if ($backend_type == 'http') { fwrite ($fd, "\toption\t\t\thttplog\n"); - else + } else { fwrite ($fd, "\toption\t\t\ttcplog\n"); + } } if ($backend_type == 'http') { - if($bind['httpclose'] && $bind['httpclose'] != "none" ) + if ($bind['httpclose'] && $bind['httpclose'] != "none") { fwrite ($fd, "\toption\t\t\t{$bind['httpclose']}\n"); + } - if($bind['forwardfor']) { + if ($bind['forwardfor']) { fwrite ($fd, "\toption\t\t\tforwardfor\n"); fwrite ($fd, "\tacl https ssl_fc\n"); fwrite ($fd, "\treqadd X-Forwarded-Proto:\ http if !https\n"); @@ -1267,19 +1743,38 @@ function haproxy_writeconf($configpath) { } } - if($bind['max_connections']) - fwrite ($fd, "\tmaxconn\t\t\t" . $bind['max_connections'] . "\n"); + if ($bind['max_connections']) { + fwrite ($fd, "\tmaxconn\t\t\t{$bind['max_connections']}\n"); + } - if(!$bind['client_timeout']) + if (!$bind['client_timeout']) { $bind['client_timeout'] = 30000; + } - fwrite ($fd, "\ttimeout client\t\t" . $bind['client_timeout'] . "\n"); + fwrite ($fd, "\ttimeout client\t\t{$bind['client_timeout']}\n"); + + if (is_arrayset($bind,'a_errorfiles','item')) { + foreach($bind['a_errorfiles']['item'] as $errorfile) { + if (!is_array($a_files_cache)) {// load only once + $a_files_cache = haproxy_get_fileslist(); + } + $file = $errorfile['errorfile']; + $errorcodes = explode(",",$errorfile['errorcode']); + foreach($errorcodes as $errorcode) { + $filename = "$configpath/errorfile_{$name}_{$errorcode}_{$file}"; + $content = base64_decode($a_files_cache[$file]['content']); + $content = str_replace('{errormsg}', $a_error[$errorcode]['descr'], $content); + $content = str_replace('{errorcode}', $errorcode, $content); + file_put_contents($filename, $content); + fwrite ($fd, "\terrorfile\t\t\t" . $errorcode ." " . $filename . "\n"); + } + } + } - // Advanced pass thru - if($bind['advanced']) { - $advanced = explode("\n", base64_decode($bind['advanced'])); - foreach($advanced as $adv_line) { + if ($bind['advanced']) { + $advanced = explode("\n", base64_decode($bind['advanced'])); + foreach ($advanced as $adv_line) { if ($adv_line != "") { fwrite($fd, "\t" . str_replace("\r", "", $adv_line) . "\n"); } @@ -1288,176 +1783,220 @@ function haproxy_writeconf($configpath) { // Combine the rest of the frontend configs $default_backend = ""; - $config_acls = ""; + $config_acls = array(); + $config_actions = ""; $config_usebackends = ""; $config_usedefaultbackends = ""; $transparent_clientip = false; foreach ($bind['config'] as $frontend) { - $backend = haproxy_find_backend($frontend['backend_serverpool']); - if ($backend["transparent_clientip"] == 'yes') { + //todo: check also use_backend actions + if (frontend_usetransparentbackend($frontend)) { $transparent_clientip = true; break; } } if ($transparent_clientip && $useipv4 && $useipv6) { // set the src_is_ipv4 acl if needed. - $config_acls .= "\tacl\t\t\tsrc_is_ipv4\tsrc 0.0.0.0/0\n"; + $acl = "\tacl\t\t\tsrc_is_ipv4\tsrc 0.0.0.0/0\n"; + $config_acls[$acl] = 1; } $inspectdelay = 0; $i = 0; $acllist = array(); + $needs_clientcert = array(); $acl_newid = 0; foreach ($bind['config'] as $frontend) { + // loop through 'shared frontends' within one primary. + $a_acl = get_frontend_acls($frontend); - - $backend = haproxy_find_backend($frontend['backend_serverpool']); - $transparent_clientip = $backend["transparent_clientip"] == 'yes'; + + $a_actionitems = $frontend['a_actionitems']['item']; + if (!is_array($a_actionitems)) { + $a_actionitems = array(); + } + if (!empty($frontend['backend_serverpool'])) { + // insert extra use_backend action without a user-condition + $item = array(); + $item['action'] = "use_backend"; + $item['use_backendbackend'] = $frontend['backend_serverpool']; + $a_actionitems[] = $item; + } + $transparent_clientip = frontend_usetransparentbackend($frontend); $allowfordefaultbackend = true; $ipv = array(); if ($transparent_clientip) { if ($useipv4 && $useipv6) { $ipv["ipv4"]['acl'] = " src_is_ipv4 "; + $ipv["ipv4"]['aclnameadd'] = "_ipv4"; $ipv["ipv6"]['acl'] = " !src_is_ipv4 "; + $ipv["ipv6"]['aclnameadd'] = "_ipv6"; $allowfordefaultbackend = false; // transparent backend must always match client-ip which is ipv4 v.s. ipv6 specific so there cannot be a default. - } else if ($useipv6) + } elseif ($useipv6) { $ipv["ipv6"]['acl'] = " "; - else + $ipv["ipv6"]['aclnameadd'] = ""; + } else { $ipv["ipv4"]['acl'] = " "; - } else - $ipv["ipvANY"]['acl'] = " "; - - // combine acl's with same name to allow for 'combined checks' to check for example hostname and fileextension together.. - $a_acl_combine = array(); - foreach ($a_acl as $entry) { - $name = $entry['ref']['name']; - - $acl = array(); - $acl['ref'] = $entry['ref']; - $acltype = haproxy_find_acl($entry['ref']['expression']); - $acl['acltype'] = $acltype; - if (!isset($acltype)) - continue; - $a_acl_combine[$name][] = $acl; - - if (isset($acltype['require_client_cert'])){ - $acl = array(); - $acl['ref']['expression'] = "ssl_c_used"; - $acl['acltype']['syntax'] = "ssl_c_used"; - $acl['acltype']['novalue'] = 1; - $a_acl_combine[$name][] = $acl; + $ipv["ipv4"]['aclnameadd'] = ""; } + } else { + $ipv["ipvANY"]['acl'] = " "; + $ipv["ipvANY"]['aclnameadd'] = ""; } - + $certacl = ""; $y = 0; foreach($ipv as $ipversion => $ipversionoptions) { - $useracls = array(); - $poolname = $frontend['backend_serverpool'] . "_" . strtolower($bind['type'])."_".$ipversion; - if (!isset($a_pendingpl[$poolname])) { - $a_pendingpl[$poolname] = array(); - $a_pendingpl[$poolname]['name'] = $poolname; - $a_pendingpl[$poolname]['backend'] = $frontend['backend_serverpool']; - $a_pendingpl[$poolname]['frontend'] = $bind; - $a_pendingpl[$poolname]['ipversion'] = $ipversion; - } - $canbedefaultbackend = false; - // Write this out once, and must be before any backend config text - if (($default_backend == "" || $frontend['secondary'] != 'yes') && count($a_acl) == 0 ) { - $canbedefaultbackend = true; - if ($allowfordefaultbackend) - $default_backend = $poolname; + $cert_acls = ""; + $aclcrt_name = ""; + + // ACL's + foreach ($a_acl as $entry) { + $aclitem = $entry['ref']; + $expression = $aclitem['expression']; + + $aclname = $aclitem['name']; + $acltype = haproxy_find_acl($expression); + if (!isset($acltype)) + continue; + + // Filter out acls for different modes + if ($acltype['mode'] != '' && $acltype['mode'] != strtolower($bind['type'])) { + continue; + } + if ($acltype['inspect-delay'] != '') { + $inspectdelay = $acltype['inspect-delay']; + } + if ($acltype['advancedoptions'] != '') { + $advancedextra[$acltype['syntax']] = $acltype['advancedoptions']."\n"; + } + if ($acltype['require_client_cert']) { + $needs_clientcert[$aclname] = true; + } + if ($aclitem['certacl']) { + $aclname = "aclcrt_{$frontend['name']}"; + $aclcrt_name = $aclname; + } + + if (($expression == "source_ip") && is_alias($aclitem['value'])) { + $filename = "$configpath/ipalias_{$aclitem['value']}.lst"; + $listitems = haproxy_hostoralias_to_list($aclitem['value']); + $fd_alias = fopen("$filename", "w"); + foreach($listitems as $item) { + fwrite($fd_alias, $item."\r\n"); + } + fclose($fd_alias); + $expr = "src -f $filename"; + } else { + $expr = sprintf($acltype['syntax'], $aclitem['value']); + if (is_array($acltype['fields'])) { + foreach ($acltype['fields'] as $field) { + $fieldname = $field['name']; + $parameter = $aclitem[$expression . $fieldname]; + if ($fieldname == "backend") { + $backendname = $parameter . "_" . strtolower($bind['type'])."_".$ipversion; + $parameter = $backendname; + } + $expr = str_replace("{{$fieldname}}", $parameter, $expr); + } + } + } + $config_acls ["\tacl\t\t\t" . $aclname . "\t" . $expr . "\n"] = 1; } - - foreach ($a_acl_combine as $a_usebackend) { - $aclnames = ""; - foreach ($a_usebackend as $entry2) { - $entry = $entry2['ref']; - $acl = $entry2['acltype']; - - // Filter out acls for different modes - if ($acl['mode'] != '' && $acl['mode'] != strtolower($bind['type'])) - continue; - if (($entry['expression'] == "source_ip") && is_alias($entry['value'])) { - $filename = "$configpath/ipalias_{$entry['value']}.lst"; - $listitems = haproxy_hostoralias_to_list($entry['value']); - $fd_alias = fopen("$filename", "w"); - foreach($listitems as $item) - fwrite($fd_alias, $item."\r\n"); - fclose($fd_alias); - $expr = "src -f $filename"; - } else - $expr = sprintf($acl['syntax'],$entry['value'],$poolname); - - $not = $entry['not'] == "yes" ? "!" : ""; - - unset($aclkey); - foreach($acllist as $aclid => $aclitem) { - if ($aclitem['expr'] == $expr) { - $aclkey = $aclid; + + $systemacl = trim("{$aclcrt_name}{$ipversionoptions['acl']}"); + + foreach ($a_actionitems as $actionitem) { + $actionid = $actionitem['action']; + $action = $a_action[$actionid]; + + $action_cfg = $action['syntax']; + + if (is_array($action['fields'])) { + foreach ($action['fields'] as $field) { + $fieldname = $field['name']; + $parameter = $actionitem[$actionid . $field['name']]; + + if ($fieldname == "backend") { + $backend = $parameter; + $backendname = $parameter . "_" . strtolower($bind['type'])."_".$ipversion; + if (!isset($a_pendingpl[$backendname])) { + $a_pendingpl[$backendname] = array(); + $a_pendingpl[$backendname]['name'] = $backendname; + $a_pendingpl[$backendname]['backend'] = $backend; + $a_pendingpl[$backendname]['frontend'] = $bind; + $a_pendingpl[$backendname]['ipversion'] = $ipversion; + } + $parameter = $backendname; + } + $action_cfg = str_replace("{{$fieldname}}", $parameter, $action_cfg); + } + } + $condition = ""; + if (!empty($actionitem['acl']) || !empty($systemacl)) { + $useclientcert = ""; + $useracls = ""; + $aclnames = explode(' ', $actionitem['acl']); + foreach($aclnames as $aclname) { + if ($needs_clientcert[$aclname]) { + $useclientcert = " aclsystem_ssl_c_used"; } + $not = ""; + foreach ($a_acl as $entry) { + if ($entry['ref']['name'] == $aclname && $entry['ref']['not'] == 'yes') { + $not = "!"; + } + } + $useracls .= " {$not}{$aclname}"; } - if (isset($aclkey)) { - $aclname = $acllist[$aclkey]['aclname']; + $condition = " if {$useracls}{$useclientcert} {$systemacl}"; + } + + $action = "\t{$action_cfg} {$condition}\n"; + + if ($actionid == "use_backend") { + if (empty($condition)) { + $config_usedefaultbackends .= "\tdefault_backend {$parameter}{$condition}\n"; } else { - $aclkey = $acl_newid++; - if ($entry['certacl']) { - $aclname = "aclcrt_".$frontend['name']; - $certacl = $aclname; + if (!empty($actionitem['acl'])){ + $config_usebackends .= $action; } else { - $aclname = "aclusr_{$entry['expression']}"; - if (!isset($acl['novalue'])) - $aclname .= "_{$entry['value']}"; - $aclname = haproxy_escape_acl_name($aclname); - $i++; + // add use_backend if ipv4/6 before default_backend if any exists.. + $config_usedefaultbackends .= $action; } - $acllist[$aclkey]['aclname'] = $aclname; - $acllist[$aclkey]['expr'] = $expr; - $config_acls .= "\tacl\t\t\t" . $aclname . "\t" . $expr . "\n"; } - if (!isset($entry['certacl'])) - $useracls[$y] .= $not . $aclname . " "; - - if ($acl['inspect-delay'] != '') - $inspectdelay = $acl['inspect-delay']; - - if ($acl['advancedoptions'] != '') - $advancedextra[$acl['syntax']] = $acl['advancedoptions']."\n"; + } else { + $config_actions .= $action; } - $y++; - } - - $systemacl = trim("{$certacl}{$ipversionoptions['acl']}"); - if (!empty($systemacl) && count($useracls) == 0) $useracls[] = ""; // add empty item to enter foreach loop at least once when a system acl is pressent. - foreach($useracls as $useracl) { - $backendacl = ""; - $backendacl .= "|| {$useracl}{$systemacl}"; - $backendacl = substr($backendacl, 3); - if ($canbedefaultbackend) { - // makes sure these come last even though systemacl's might have been added. - $config_usedefaultbackends .= "\tuse_backend\t\t" . $poolname . " if " . $backendacl . "\n"; - } else - $config_usebackends .= "\tuse_backend\t\t" . $poolname . " if " . $backendacl . "\n"; } } } - if ($inspectdelay > 0) + if ($inspectdelay > 0) { fwrite ($fd, "\ttcp-request inspect-delay\t" . $inspectdelay . "s\n"); + } + if (count($needs_clientcert) > 0) { + fwrite ($fd, "\tacl\t\t\taclsystem_ssl_c_used\tssl_c_used\n"); + } // Write acl's first, so they may be used by advanced text options written by user. - fwrite ($fd, $config_acls); + foreach($config_acls as $acl => $dummy) { + fwrite ($fd, $acl); + } - foreach($advancedextra as $extra) + foreach($advancedextra as $extra) { fwrite ($fd, "\t".$extra."\n"); + } + fwrite ($fd, $config_actions); // Write backends after advanced options so custom use_backend rules can be applied first. fwrite ($fd, $config_usebackends); fwrite ($fd, $config_usedefaultbackends); - if ($default_backend) + if ($default_backend) { fwrite ($fd, "\tdefault_backend\t\t" . $default_backend . "\n"); + } fwrite ($fd, "\n"); } @@ -1477,21 +2016,20 @@ function haproxy_writeconf($configpath) { // close config file fclose($fd); - if ($input_errors) - { + if ($input_errors) { require_once("guiconfig.inc"); print_input_errors($input_errors); } else { // Only sync to xmlrpc backup machine if no errors are found in config - if(isset($config['installedpackages']['haproxy']['enablesync'])) { + if (isset($config['installedpackages']['haproxy']['enablesync'])) { haproxy_do_xmlrpc_sync(); } } } function haproxy_is_running() { - $running = (shell_exec("/bin/pgrep -x haproxy") != ''); - return $running; + $running = (shell_exec("/bin/pgrep -x haproxy") != ''); + return $running; } function haproxy_load_modules() { @@ -1513,6 +2051,24 @@ function haproxy_load_modules() { unmute_kernel_msgs(); } +function frontend_usetransparentbackend($frontend) { + $backend = haproxy_find_backend($frontend['backend_serverpool']); + if ($backend["transparent_clientip"] == 'yes') { + return true; + } + if (is_array($frontend['a_actionitems']['item'])) { + foreach($frontend['a_actionitems']['item'] as $action) { + if ($action['action'] == "use_backend") { + $backend = haproxy_find_backend($action['use_backendbackend']); + if ($backend["transparent_clientip"] == 'yes') { + return true; + } + } + } + } + return false; +} + function use_transparent_clientip_proxying() { global $config; $a_backends = &$config['installedpackages']['haproxy']['ha_pools']['item']; @@ -1531,17 +2087,20 @@ function haproxy_get_transparent_backends(){ global $config; $a_backends = &$config['installedpackages']['haproxy']['ha_pools']['item']; $transparent_backends = array(); + if (!is_array($a_backends)) { + return $transparent_backends; + } foreach ($a_backends as $backend) { - if ($backend["transparent_clientip"] != 'yes') + if ($backend["transparent_clientip"] != 'yes') { continue; + } $real_if = get_real_interface($backend["transparent_interface"]); $a_servers = &$backend['ha_servers']['item']; if (is_array($a_servers)) { foreach($a_servers as $be) { - if (!$be['status'] == "inactive") - continue; - if (!is_ipaddr($be['address'])) + if (!$be['status'] == "inactive" || !is_ipaddr($be['address'])){ continue; + } $item = array(); $item['name'] = $be['name']; $item['interface'] = $real_if; @@ -1618,9 +2177,9 @@ function load_ipfw_rules() { $rulenum = 64000; // why that high? captiveportal.inc also does it... $rules = "flush\n"; foreach($transparent_backends as $transparent_be) { - if (is_ipaddrv4($transparent_be["address"])) + if (is_ipaddrv4($transparent_be["address"])) { $rules .= "add $rulenum fwd localhost tcp from {$transparent_be["address"]} {$transparent_be["port"]} to any in recv {$transparent_be["interface"]}\n"; - else if (is_ipaddrv6($transparent_be["address"])) { + } elseif (is_ipaddrv6($transparent_be["address"])) { list ($addr, $scope) = explode("%", $transparent_be['address']); $rules .= "add $rulenum fwd ::1 tcp from {$addr} {$transparent_be["port"]} to any in recv {$transparent_be["interface"]}\n"; } @@ -1715,7 +2274,7 @@ function haproxy_check_run($reload) { } } - if(isset($a_global['enable'])) { + if (isset($a_global['enable'])) { if (isset($a_global['carpdev'])) { $status = haproxy_carpipismaster($a_global['carpdev']); if (!$status) { @@ -1726,18 +2285,18 @@ function haproxy_check_run($reload) { } unlock($haproxylock); return (0); - } else if (haproxy_is_running() && $reload == 0) { + } elseif (haproxy_is_running() && $reload == 0) { unlock($haproxylock); return (0); } log_error("Starting haproxy on CARP master."); /* fallthrough */ - } else if ($reload == 0){ + } elseif ($reload == 0) { unlock($haproxylock); return (0); } - if(use_transparent_clientip_proxying()) { + if (use_transparent_clientip_proxying()) { filter_configure(); load_ipfw_rules(); } else { @@ -1751,14 +2310,16 @@ function haproxy_check_run($reload) { if (file_exists('/var/run/haproxy.pid')){ $old_pid = file_get_contents('/var/run/haproxy.pid'); - } else + } else { $old_pid = 'none'; + } if (haproxy_is_running()) { - if (isset($a_global['terminate_on_reload'])) + if (isset($a_global['terminate_on_reload'])) { $sf_st = "-st";//terminate old process as soon as the new process is listening - else + } else { $sf_st = "-sf";//finish serving existing connections exit when done, and the new process is listening + } syslog(LOG_NOTICE, "haproxy: reload old pid:$old_pid"); exec("/usr/local/sbin/haproxy -f {$configpath}/haproxy.cfg -p /var/run/haproxy.pid $sf_st `cat /var/run/haproxy.pid` 2>&1", $output, $errcode); @@ -1768,12 +2329,20 @@ function haproxy_check_run($reload) { } if (file_exists('/var/run/haproxy.pid')){ $new_pid = file_get_contents('/var/run/haproxy.pid'); - } else + } else { $new_pid = 'none'; + } syslog(LOG_NOTICE, "haproxy: started new pid:$new_pid"); - foreach($output as $line) + $syslogmessage = ""; + foreach($output as $line) { $haproxy_run_message .= "<br/>" . htmlspecialchars($line) . "\n"; + $syslogmessage .= str_replace("\n"," ",$line); + } + if (!empty($syslogmessage)) { + syslog(LOG_NOTICE, "haproxy: startup error output!: {$syslogmessage}"); + } + } else { if ($reload && haproxy_is_running()) { //exec("/bin/pkill -F /var/run/haproxy.pid haproxy");//doesnt work for multiple pid's in a pidfile @@ -1786,10 +2355,11 @@ function haproxy_check_run($reload) { } function haproxy_kill($killimmediately = true) { - if ($killimmediately) + if ($killimmediately) { $signal = "KILL"; // stop now - else + } else { $signal = "USR1"; // stop when all connections are closed + } killprocesses("haproxy", "/var/run/haproxy.pid", $signal); } @@ -1838,7 +2408,7 @@ function haproxy_xmlrpc_sync_configure() { haproxy_configure(); // Configure HAProxy config files to use the new configuration. // sync 2nd and further nodes in the chain if applicable. - if(isset($config['installedpackages']['haproxy']['enablesync'])) { + if (isset($config['installedpackages']['haproxy']['enablesync'])) { haproxy_do_xmlrpc_sync(); } } @@ -1857,34 +2427,38 @@ function get_frontend_id($name) { } function haproxy_is_frontendname($name) { - if ($name[0] == '!') + if ($name[0] == '!') { $name = substr($name, 1); + } return get_frontend_id($name) != null; } function get_primaryfrontend($frontend) { global $config; $a_frontend = &$config['installedpackages']['haproxy']['ha_backends']['item']; - if ($frontend['secondary'] == 'yes') + if ($frontend['secondary'] == 'yes') { $mainfrontend = $a_frontend[get_frontend_id($frontend['primary_frontend'])]; - else + } else { $mainfrontend = $frontend; + } return $mainfrontend; } function get_frontend_ipport($frontend, $userfriendly=false) { $mainfrontend = get_primaryfrontend($frontend); $result = array(); - if (!is_arrayset($mainfrontend,"a_extaddr","item")) + if (!is_arrayset($mainfrontend,"a_extaddr","item")) { return $result; + } foreach($mainfrontend['a_extaddr']['item'] as $extaddr) { if ($extaddr['extaddr'] == 'custom'){ $addr = $extaddr['extaddr_custom']; } else { $addr = haproxy_interface_ip($extaddr['extaddr'], $userfriendly); } - if ($userfriendly and is_ipaddrv6($addr)) + if ($userfriendly and is_ipaddrv6($addr)) { $addr = "[{$addr}]"; + } $port = $extaddr['extaddr_port']; $newitem = array(); @@ -1910,10 +2484,11 @@ function get_frontend_bindips($frontend) { $iporalias = $extaddr['extaddr_custom']; $a_ip = haproxy_addressoralias_to_list($iporalias); } - if ($extaddr['extaddr_ssl'] == 'yes') + if ($extaddr['extaddr_ssl'] == 'yes') { $ssl = $ssl_info; - else + } else { $ssl = ""; + } foreach($a_ip as $ip) { $portsnumeric = group_ports(haproxy_portoralias_to_list($extaddr['extaddr_port'])); @@ -1940,46 +2515,66 @@ function haproxy_check_config() { $activefrontends = array(); $issues = array(); - foreach($a_backends as $frontend) { - if (($frontend['status'] != 'active') || ($frontend['secondary'] == 'yes')) + foreach ($a_backends as $frontend) { + if (($frontend['status'] != 'active') || ($frontend['secondary'] == 'yes')) { continue; + } $ipports = get_frontend_ipport($frontend); foreach($ipports as $ipport) { $id = "{$ipport['addr']}:{$ipport['port']}"; - if (isset($activefrontends[$id])) - $issues['P_'.$id] = "Multiple primary frontends with IP:Port \"$id\", use Shared-Frontends instead."; - else - $activefrontends[$id] = true; + if (isset($activefrontends[$id])) { + $activefrontends[$id] = $activefrontends[$id].", ".$frontend['name']; + $issues['P_'.$id] = "Multiple primary frontends ({$activefrontends[$id]}) with IP:Port \"$id\", use Shared-Frontends instead."; + } else { + $activefrontends[$id] = $frontend['name']; + } } } - foreach($a_backends as $frontend) { - if (($frontend['status'] != 'active') || ($frontend['secondary'] != 'yes')) + foreach ($a_backends as $frontend) { + if (($frontend['status'] != 'active') || ($frontend['secondary'] != 'yes')) { continue; + } $mainfrontend = get_primaryfrontend($frontend); - if (!isset($mainfrontend)) + if (!isset($mainfrontend)) { $issues['S_'.$frontend['name']] = "Secondary frontend \"{$frontend['name']}\" without active primary frontend."; + } } - foreach ($issues as $item) + foreach ($issues as $item) { $result .= ($result == false ? "" : "<br/>") . $item; + } return $result; } -function get_haproxy_frontends($excludeitem="") { +function get_haproxy_backends() { + global $config; + $a_backend = &$config['installedpackages']['haproxy']['ha_pools']['item']; + $result = array(); + if (!is_array($a_backend)) { + return $result; + } + foreach ($a_backend as &$backend) { + $result[$backend['name']]['name'] = "{$backend['name']}"; + $result[$backend['name']]['ref'] = &$backend; + } + uasort($result, haproxy_compareByName); + return $result; +} + +function get_haproxy_frontends($excludeitem = "") { global $config; $a_frontend = &$config['installedpackages']['haproxy']['ha_backends']['item']; $result = array(); - if(!is_array($a_frontend)) + if (!is_array($a_frontend)) { return $result; - foreach($a_frontend as &$frontend) - { - if ($frontend['secondary']) - continue; - if ($frontend['name'] == $excludeitem) + } + foreach ($a_frontend as &$frontend) { + if ($frontend['secondary'] || $frontend['name'] == $excludeitem) { continue; + } $serveraddress = get_frontend_ipport($frontend, true); $serveradresstext = null; - foreach($serveraddress as $addr) { + foreach ($serveraddress as $addr) { $serveradresstext .=($serveradresstext == null ? "" : ", ") . "{$addr['addr']}:{$addr['port']}"; } $result[$frontend['name']]['name'] = "{$frontend['name']} - {$frontend['type']} ({$serveradresstext})"; @@ -2009,30 +2604,44 @@ function get_frontend_uses_ssl_only($frontend) { $mainfrontend = get_primaryfrontend($frontend); if (is_arrayset($mainfrontend,'a_extaddr','item')) { foreach($mainfrontend['a_extaddr']['item'] as $extaddr) { - if ($extaddr['extaddr_ssl'] != 'yes') + if ($extaddr['extaddr_ssl'] != 'yes') { return false; + } } } return true; } -function haproxy_get_cert_acl($cert) { - $acl_item = array(); +function haproxy_get_cert_acls($cert, $usealternativenames = false) { + $result = array(); - $cert_cn = cert_get_cn($cert['crt']); + if (!$usealternativenames) { + $cert_cns = array(); + $cert_cns[] = cert_get_cn($cert['crt']); + } else { + $cert_cns = haproxy_get_certificate_subjectAltNames($cert['crt']); + } $descr = haproxy_escape_acl_name($cert['descr']); unset($cert); - $is_wildcard = substr($cert_cn, 0, 2) == "*."; - $cert_cn_regex = str_replace(".", "\.", $cert_cn); // escape '.' in regex. - $wild_regex = ""; - if ($is_wildcard) { - $cert_cn_regex = "([^\.]*)" . substr($cert_cn_regex, 1);// match only subdomains directly under the wildcard + //$i = 1; + foreach ($cert_cns as $cert_cn) { + $acl_item = array(); + $is_wildcard = substr($cert_cn, 0, 2) == "*."; + $cert_cn_regex = str_replace(".", "\.", $cert_cn); // escape '.' in regex. + $wild_regex = ""; + if ($is_wildcard) { + $cert_cn_regex = "([^\.]*)" . substr($cert_cn_regex, 1);// match only subdomains directly under the wildcard + } + $cert_cn_regex = "^{$cert_cn_regex}(:([0-9]){1,5})?$";// match both with and without port. + + $acl_item['descr'] = "Certificate ACL matches: {$cert_cn}"; + //$aclname_add = $usealternativenames ? "_{$i}" : ""; + $acl_item['ref'] = array('name' => "{$aclname}_{$descr}{$aclname_add}",'expression' => 'host_regex', 'value' => $cert_cn_regex, 'certacl' => true); + + //$i++; + $result[] = $acl_item; } - $cert_cn_regex = "^{$cert_cn_regex}(:([0-9]){1,5})?$";// match both with and without port. - - $acl_item['descr'] = "Certificate ACL matches: {$cert_cn}"; - $acl_item['ref'] = array('name' => "{$aclname}_{$descr}",'expression' => 'host_regex', 'value' => $cert_cn_regex, 'certacl' => true); - return $acl_item; + return $result; } function get_frontend_acls($frontend) { @@ -2043,12 +2652,14 @@ function get_frontend_acls($frontend) { { foreach ($a_acl as $entry) { $acl = haproxy_find_acl($entry['expression']); - if (!$acl) + if (!$acl) { continue; + } // Filter out acls for different modes - if ($acl['mode'] != '' && $acl['mode'] != strtolower($mainfrontend['type'])) + if ($acl['mode'] != '' && $acl['mode'] != strtolower($mainfrontend['type'])) { continue; + } $not = $entry['not'] == "yes" ? "not: " : ""; $acl_item = array(); $acl_item['descr'] = $acl['name'] . " " . (isset($acl['novalue']) ? "" : $not . $entry['value']); @@ -2060,22 +2671,36 @@ function get_frontend_acls($frontend) { if (get_frontend_uses_ssl($frontend)) { $a_acl = &$frontend['ha_acls']['item']; - if(!is_array($a_acl)) - $a_acl=array(); + if (!is_array($a_acl)) { + $a_acl = array(); + } - $poolname = $frontend['backend_serverpool'] . "_" . strtolower($frontend['type']); - $aclname = "SNI_" . $poolname; + //$poolname = $frontend['backend_serverpool'] . "_" . strtolower($frontend['type']); + //$aclname = "SNI_" . $poolname; - if (ifset($frontend['ssloffloadacl']) == 'yes' || ifset($frontend['ssloffloadaclnondefault']) == 'yes') { + if (ifset($frontend['ssloffloadacl']) == 'yes') { + $cert = lookup_cert($frontend['ssloffloadcert']); + $result = array_merge($result, haproxy_get_cert_acls($cert)); + } + if (ifset($frontend['ssloffloadacl_an']) == 'yes') { $cert = lookup_cert($frontend['ssloffloadcert']); - $result[] = haproxy_get_cert_acl($cert); + $result = array_merge($result, haproxy_get_cert_acls($cert, true)); } if (ifset($frontend['ssloffloadacladditional']) == 'yes') { $certs = $frontend['ha_certificates']['item']; - if (is_array($certs)){ - foreach($certs as $certref){ + if (is_array($certs)) { + foreach ($certs as $certref) { + $cert = lookup_cert($certref['ssl_certificate']); + $result = array_merge($result, haproxy_get_cert_acls($cert)); + } + } + } + if (ifset($frontend['ssloffloadacladditional_an']) == 'yes') { + $certs = $frontend['ha_certificates']['item']; + if (is_array($certs)) { + foreach ($certs as $certref) { $cert = lookup_cert($certref['ssl_certificate']); - $result[] = haproxy_get_cert_acl($cert); + $result = array_merge($result, haproxy_get_cert_acls($cert, true)); } } } @@ -2083,16 +2708,44 @@ function get_frontend_acls($frontend) { return $result; } +function get_backend_acls($backend, $type) { + $result = array(); + $a_acl = &$backend['a_acl']['item']; + if (is_array($a_acl)) + { + foreach ($a_acl as $entry) { + $acl = haproxy_find_acl($entry['expression']); + if (!$acl) { + continue; + } + + // Filter out acls for different modes + if ($acl['mode'] != '' && $acl['mode'] != $type) { + continue; + } + $not = $entry['not'] == "yes" ? "not: " : ""; + $acl_item = array(); + $acl_item['descr'] = $acl['name'] . " " . (isset($acl['novalue']) ? "" : $not . $entry['value']); + $acl_item['ref'] = $entry; + + $result[] = $acl_item; + } + } + return $result; +} + function get_backend_id($name) { global $config; $a_backend = &$config['installedpackages']['haproxy']['ha_pools']['item']; $i = 0; - if(is_array($a_backend)) - foreach($a_backend as $key => $backend) { - if ($backend['name'] == $name) + if (is_array($a_backend)) { + foreach ($a_backend as $key => $backend) { + if ($backend['name'] == $name) { return $i; + } $i++; } + } return null; } @@ -2100,8 +2753,9 @@ function get_backend($name) { global $config; $a_backend = &$config['installedpackages']['haproxy']['ha_pools']['item']; $id = get_backend_id($name); - if (is_numeric($id)) + if (is_numeric($id)) { return $a_backend[$id]; + } return null; } @@ -2112,8 +2766,9 @@ function use_frontend_as_unixsocket($name) { $a_servers = &$backend['ha_servers']['item']; if (is_array($a_servers)) { foreach($a_servers as $server) { - if ($server['forwardto'] && $server['forwardto'] == $name) + if ($server['forwardto'] && $server['forwardto'] == $name) { return true; + } } } } @@ -2133,8 +2788,9 @@ function haproxy_escape_acl_name($aclname) { function haproxy_find_create_certificate($certificatename) { global $g; $cert = lookup_cert_by_name($certificatename); - if (is_array($cert)) + if (is_array($cert)) { return $cert; + } global $config; $a_cert =& $config['cert']; $cert = array(); |