diff options
Diffstat (limited to 'config')
33 files changed, 3012 insertions, 1044 deletions
diff --git a/config/haproxy-devel/haproxy.priv.inc b/config/haproxy-devel/haproxy.priv.inc new file mode 100644 index 00000000..e4914db8 --- /dev/null +++ b/config/haproxy-devel/haproxy.priv.inc @@ -0,0 +1,50 @@ +<?php +/* + haproxy.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-service-haproxy'] = array(); +$priv_list['page-service-haproxy']['name'] = "WebCfg - Services: HAProxy package"; +$priv_list['page-service-haproxy']['descr'] = "Allow access to HAProxy package GUI"; +$priv_list['page-service-haproxy']['match'] = array(); + +$priv_list['page-service-haproxy']['match'][] = "haproxy_files.php*"; +$priv_list['page-service-haproxy']['match'][] = "haproxy_global.php*"; +$priv_list['page-service-haproxy']['match'][] = "haproxy_listeners.php*"; +$priv_list['page-service-haproxy']['match'][] = "haproxy_listeners_edit.php*"; +$priv_list['page-service-haproxy']['match'][] = "haproxy_pool_edit.php*"; +$priv_list['page-service-haproxy']['match'][] = "haproxy_pools.php*"; +$priv_list['page-service-haproxy']['match'][] = "haproxy_templates.php*"; + +$priv_list['page-service-haproxy-stats'] = array(); +$priv_list['page-service-haproxy-stats']['name'] = "WebCfg - Services: HAProxy package stats"; +$priv_list['page-service-haproxy-stats']['descr'] = "Allow access to HAProxy package GUI stats"; +$priv_list['page-service-haproxy-stats']['match'] = array(); +$priv_list['page-service-haproxy-stats']['match'][] = "haproxy_stats.php*"; + +?>
\ No newline at end of file diff --git a/config/haproxy-devel/haproxy.xml b/config/haproxy-devel/haproxy.xml index 429b6c9f..784e0034 100644 --- a/config/haproxy-devel/haproxy.xml +++ b/config/haproxy-devel/haproxy.xml @@ -42,7 +42,7 @@ ]]> </copyright> <name>haproxy</name> - <version>0.29</version> + <version>0.32</version> <title>HAProxy</title> <aftersaveredirect>/pkg_edit.php?xml=haproxy_pools.php</aftersaveredirect> <include_file>/usr/local/pkg/haproxy.inc</include_file> @@ -146,6 +146,10 @@ <prefix>/usr/local/www/javascript/</prefix> <item>https://packages.pfsense.org/packages/config/haproxy-devel/www/javascript/haproxy_geturl.js</item> </additional_files_needed> + <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/haproxy-devel/haproxy.priv.inc</item> + </additional_files_needed> <custom_php_install_command> haproxy_custom_php_install_command(); </custom_php_install_command> diff --git a/config/haproxy-devel/pkg/haproxy.inc b/config/haproxy-devel/pkg/haproxy.inc index 1bc62cb9..638ece28 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,29 @@ 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') { + $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 +795,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 +827,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 +936,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 +982,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 +1001,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 +1145,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 +1182,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 +1209,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 +1238,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 +1277,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 +1304,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 +1324,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 +1336,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 +1373,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 +1404,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 +1419,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 +1440,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 +1457,52 @@ 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']; $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 +1517,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 +1529,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 +1538,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 +1586,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 +1603,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 +1616,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 +1626,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 +1655,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 +1666,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 +1683,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 +1697,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 +1730,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 +1770,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); } - if (isset($aclkey)) { - $aclname = $acllist[$aclkey]['aclname']; + } + $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 { - $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 +2003,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 +2038,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 +2074,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 +2164,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 +2261,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 +2272,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 +2297,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 +2316,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 +2342,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 +2395,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 +2414,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 +2471,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 +2502,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 +2591,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 +2639,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 +2658,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[] = haproxy_get_cert_acl($cert); + $result = array_merge($result, haproxy_get_cert_acls($cert)); + } + if (ifset($frontend['ssloffloadacl_an']) == 'yes') { + $cert = lookup_cert($frontend['ssloffloadcert']); + $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 +2695,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 +2740,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 +2753,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 +2775,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(); diff --git a/config/haproxy-devel/pkg/haproxy_htmllist.inc b/config/haproxy-devel/pkg/haproxy_htmllist.inc index 394f3ff6..7eaad023 100644 --- a/config/haproxy-devel/pkg/haproxy_htmllist.inc +++ b/config/haproxy-devel/pkg/haproxy_htmllist.inc @@ -48,100 +48,129 @@ class HaproxyHtmlList public $fields_details = null; public $keyfield = ""; - public function HaproxyHtmlList($tablename, $fields){ + public function HaproxyHtmlList($tablename, $fields) { $this->tablename = $tablename; $this->fields = $fields; } - public function Draw($data){ + public function Draw($data) { $this->haproxy_htmllist($data, $this->fields, $this->editmode, $this->fields_details); } - function haproxy_htmllist_get_values(){ + public function outputjavascript() { + $table_def = array(); + $table_def['keyfield'] = $this->keyfield; + phparray_to_javascriptarray($table_def, "tabledefinition_".$this->tablename,Array('/*','/*/*')); + phparray_to_javascriptarray($this->fields, "fields_".$this->tablename,Array('/*','/*/name','/*/type','/*/text','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); + if (count($this->fields_details) != 0) { + phparray_to_javascriptarray($this->fields_details,"fields_details_".$this->tablename,Array('/*','/*/name','/*/columnheader','/*/description','/*/type','/*/text','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name','/*/items/*/*/name')); + } + } + + // function retrieves all posted values and returns an array + public function haproxy_htmllist_get_values() { $values = array(); - for($x=0; $x<99; $x++) { + for($x = 0; $x < 99; $x ++) { $value = array(); $add_item = false; - foreach($this->fields as $item){ + if (is_array($this->fields_details)) { + $fields = array_merge($this->fields, $this->fields_details); + } else { + $fields = $this->fields; + } + foreach($fields as $item) { $itemname = $item['name']; - $value[$itemname] = $_POST[$itemname.$x]; - if ($item['type'] == 'textarea') + $value[$itemname] = $_POST[$this->tablename.$itemname.$x]; + if ($item['type'] == 'textarea') { $value[$itemname] = base64_encode($value[$itemname]); - $add_item |= isset($_POST[$itemname.$x]); + } + $add_item |= isset($_POST[$this->tablename.$itemname.$x]); } if ($add_item) { if ($this->keyfield != "") { - if (isset($_POST[$this->tablename."_key".$x])) + if (isset($_POST[$this->tablename."_key".$x])) { $key = $_POST[$this->tablename."_key".$x]; - else - $key = $_POST[$this->keyfield.$x]; - - } else + } else { + $key = $_POST[$this->tablename.$this->keyfield.$x]; + } + } else { $key = ""; - - if (isset($values[$key])) + } + $index = $_POST[$this->tablename."_rowindex".$x]; + $value['_index'] = $index; + if (isset($values[$key])) { $values[] = $value; - else + } else { $values[$key] = $value; + } } } + usort($values, 'sort_index'); + return $values; } - - private function haproxy_htmllist_drawcell($item, $itemvalue, $editable, $itemname, $counter) { - $itemnamenr = $itemname . $counter; + + function haproxy_htmllist_drawcell($item, $itemvalue, $editable, $itemname, $counter) { + $itemnamenr = $this->tablename . $itemname . $counter; $itemtype = $item['type']; if ($editable) { $itemtype = $item['type']; - if ($itemtype == "select"){ - echo_html_select($itemnamenr, $item['items'], $itemvalue,"","html_listitem_change(\"{$this->tablename}\",\"{$itemname}\",\"{$counter}\",this);", "width:{$item['size']}"); - } else - if ($itemtype == "checkbox"){ + if ($itemtype == "select") { + echo_html_select($itemnamenr, $item['items'], $itemvalue,"-none available-","html_listitem_change(\"{$this->tablename}\",\"{$itemname}\",\"{$counter}\",this);", "width:{$item['size']}"); + } elseif ($itemtype == "checkbox") { $checked = $itemvalue=='yes' ? " checked" : ""; echo "<input onclick='html_listitem_change(\"{$this->tablename}\",\"{$itemname}\",\"{$counter}\",this);' name='$itemnamenr' id='$itemnamenr' type='checkbox'$checked value='yes' size='{$item['size']}' />"; - } else - if ($itemtype == "textarea"){ + } elseif ($itemtype == "textarea") { echo "<textarea name='$itemnamenr' id='$itemnamenr' type='text' cols='{$item['size']}' rows='10'>"; echo htmlspecialchars(base64_decode($itemvalue)); echo "</textarea>"; - } else + } elseif ($itemtype == "fixedtext") { + echo $item['text']; + } else { echo "<input name='$itemnamenr' id='$itemnamenr' type='text' value='{$itemvalue}' size='{$item['size']}' />"; + } } else { - if ($itemtype == "select"){ + if ($itemtype == "select") { echo $item['items'][$itemvalue]['name']; - } else - if ($itemtype == "checkbox"){ + } elseif ($itemtype == "checkbox") { echo $itemvalue=='yes' ? gettext('yes') : gettext('no'); - } else - if ($itemtype == "textarea"){ - echo '<div style="overlow:scroll;max-height:120px;overflow-y: scroll;">'; - echo str_replace("\n","<br/>", htmlspecialchars(base64_decode($itemvalue))); + } elseif ($itemtype == "textarea") { + echo "<div style='overlow:scroll;max-height:120px;max-width:{$item['colwidth']};overflow-y: scroll;'>"; + echo str_replace(" "," ", str_replace("\n","<br/>", htmlspecialchars(base64_decode($itemvalue)))); echo '</div>'; - } else + } elseif ($itemtype == "fixedtext") { + echo $item['text']; + } else { echo htmlspecialchars($itemvalue); + } } } function haproxy_htmllist($rowvalues,$items,$editstate=false,$itemdetails=null){ $tablename = $this->tablename; global $g, $counter; - echo "<table class='' width='100%' cellpadding='0' cellspacing='0' id='$tablename'> + echo "<table class='' width='100%' cellpadding='0' cellspacing='0' id='{$tablename}'> + <thead> <tr>"; foreach($items as $item){ echo "<td width='{$item['colwidth']}' class='listhdrr'>{$item['columnheader']}</td>"; } echo "<td width='5%' class=''></td> - </tr>"; - if (is_array($rowvalues)){ - foreach($rowvalues as $keyid => $value){ - if ($this->keyfield != "") { - if (preg_match("/[^0-9]/", $keyid)) + </tr> + </thead> + <tbody>"; + if (is_array($rowvalues)) { + foreach($rowvalues as $keyid => $value) { + if (!empty($this->keyfield)) { + if (preg_match("/[^0-9]/", $keyid)) { $itemvalue = $keyid; - else + } else { $itemvalue = $value[$this->keyfield]; + } $key = "<input name='{$tablename}_key{$counter}' id='{$tablename}_key{$counter}' type='hidden' value='{$itemvalue}'>"; - } else + } else { $key = ""; + } if (!$editstate) { echo "<tr id='tr_view_$counter' ondblclick='editRow($counter); return false;' >"; @@ -152,26 +181,36 @@ class HaproxyHtmlList $itemname = $item['name']; $itemvalue = $value[$itemname]; if (isset($item['customdrawcell'])) { - $item['customdrawcell']($item, $itemvalue, false); - } else + $item['customdrawcell']($this, $item, $itemvalue, false, $itemname, $counter); + } else { $this->haproxy_htmllist_drawcell($item, $itemvalue, false, $itemname, $counter); + } echo "</td>"; $leftitem = false; } echo " - <td class='list'> - <table border='0' cellspacing='0' cellpadding='1'><tr> - <td valign='middle'> - <img src='/themes/{$g['theme']}/images/icons/icon_e.gif' title='edit entry' width='17' height='17' border='0' onclick='editRow($counter); return false;' /> - </td> - <td valign='middle'> - <img src='/themes/{$g['theme']}/images/icons/icon_x.gif' title='delete entry' width='17' height='17' border='0' onclick='deleteRow($counter, \"$tablename\"); return false;' /> - </td> - <td valign='middle'> - <img src='/themes/{$g['theme']}/images/icons/icon_plus.gif' title='duplicate entry' width='17' height='17' border='0' onclick='dupRow($counter, \"$tablename\"); return false;' /> - </td></tr></table> - </td>"; + <td class='list'> + <table border='0' cellspacing='0' cellpadding='1'><tr> + <td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_e.gif' title='edit entry' width='17' height='17' border='0' onclick='editRow({$counter}); return false;' /> + </td> + <td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_x.gif' title='delete entry' width='17' height='17' border='0' onclick='deleteRow({$counter}, \"{$tablename}\"); return false;' /> + </td> + <td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_plus.gif' title='duplicate entry' width='17' height='17' border='0' onclick='dupRow({$counter}, \"{$tablename}\"); return false;' /> + </td>"; + if (empty($this->noindex)) { + echo "<td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_up.gif' title='move row up' width='17' height='17' border='0' onclick='moveRowUp({$counter}, \"{$tablename}\"); return false;' /> + </td> + <td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_down.gif' title='move row down' width='17' height='17' border='0' onclick='moveRowDown({$counter}, \"{$tablename}\"); return false;' /> + </td>"; + } + echo "</tr></table> + </td>"; echo "</tr>"; } $displaystyle = $editstate ? "" : "display: none;"; @@ -181,9 +220,10 @@ class HaproxyHtmlList $itemvalue = $value[$itemname]; echo "<td class='vtable'>".$key; if (isset($item['customdrawcell'])) { - $item['customdrawcell']($item, $itemvalue, true, $item['name'].$counter); - } else + $item['customdrawcell']($this, $item, $itemvalue, true, $itemname, $counter); + } else { $this->haproxy_htmllist_drawcell($item, $itemvalue, true, $itemname, $counter); + } echo "</td>"; $key = ""; } @@ -191,11 +231,21 @@ class HaproxyHtmlList <td class='list'> <table border='0' cellspacing='0' cellpadding='1'><tr> <td valign='middle'> - <img src='/themes/{$g['theme']}/images/icons/icon_x.gif' title='delete entry' width='17' height='17' border='0' onclick='removeRow(this); return false;' /> + <input name='{$tablename}_rowindex{$counter}' id='{$tablename}_rowindex{$counter}' type='hidden' value='{$counter}' /> + <img src='/themes/{$g['theme']}/images/icons/icon_x.gif' title='delete entry' width='17' height='17' border='0' onclick='deleteRow({$counter}, \"{$tablename}\"); return false;' /> </td> <td valign='middle'> - <img src='/themes/{$g['theme']}/images/icons/icon_plus.gif' title='duplicate entry' width='17' height='17' border='0' onclick='dupRow($counter, \"$tablename\"); return false;' /> - </td></tr></table> + <img src='/themes/{$g['theme']}/images/icons/icon_plus.gif' title='duplicate entry' width='17' height='17' border='0' onclick='dupRow({$counter}, \"{$tablename}\"); return false;' /> + </td>"; + if (empty($this->noindex)) { + echo "<td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_up.gif' title='move row up' width='17' height='17' border='0' onclick='moveRowUp({$counter}, \"{$tablename}\"); return false;' /> + </td> + <td valign='middle'> + <img src='/themes/{$g['theme']}/images/icons/icon_down.gif' title='move row down' width='17' height='17' border='0' onclick='moveRowDown({$counter}, \"{$tablename}\"); return false;' /> + </td>"; + } + echo "</tr></table> </td>"; echo "</tr>"; if (isset($itemdetails)) { @@ -204,7 +254,7 @@ class HaproxyHtmlList ?> <td class='vtable listlr' style='border-bottom-width: medium;vertical-align:top;'> <div style="position:relative;float:right;width:11px;height:11px;"> - <a onclick="htmltable_toggle_details('<?="htmltable_{$tablename}_{$counter}_details"?>')"> + <a onclick="htmltable_toggle_details('<?=$tablename?>','<?=$counter?>','<?="htmltable_{$tablename}_{$counter}_details"?>')"> <img id="htmltable_<?="{$tablename}_{$counter}"?>_details_off" alt="Expand advanced server settings" src="tree/plus.gif" style="clip:rect(19px 13px 30px 2px); top:-19px;position:absolute;"/> </a> @@ -215,80 +265,92 @@ class HaproxyHtmlList $itemnr = 0; echo "<div id='htmltable_{$tablename}_{$counter}_details_view'>"; $itemcount = count($itemdetails); + $leftitem = true; foreach($itemdetails as $item) { - echo "<div style='float: left;padding-right: 2px;'>"; - $tdclass = "";//$leftitem ? "vtable listlr" : "vtable listr"; - echo $item['columnheader'] . ": "; $itemname = $item['name']; $itemvalue = $value[$itemname]; + //TODO don't filter empty items, filter context un-related items through customizable function.. + if (empty($itemvalue)) { + continue; + } + echo "<div style='float: left;padding-right: 2px;'>"; + $tdclass = ""; + if (!$leftitem) { + echo ", "; + } + $leftitem = false; + echo $item['columnheader'] . ": "; if (isset($item['customdrawcell'])) { - $item['customdrawcell']($item, $itemvalue, false); - } else + $item['customdrawcell']($this, $item, $itemvalue, false, $itemname, $counter); + } else { $this->haproxy_htmllist_drawcell($item, $itemvalue, false, $itemname, $counter); - $leftitem = false; + } $itemnr++; - if ($itemcount != $itemnr) - echo ", "; echo "</div>"; } echo "</div>"; echo "<div id='htmltable_{$tablename}_{$counter}_details_edit' style='display:none;'>"; echo "<table class='tabcont' style='border-collapse:collapse' border='1' cellspacing='0' >"; - $leftitem = true; foreach($itemdetails as $item) { - echo "<tr id='tr_edititemdetails_$counter' ondblclick='editRow($counter); return false;'>"; - $tdclass = "";//$leftitem ? "vtable listlr" : "vtable listr"; - echo "<td style='border-right:0' class='$tdclass'>"; + $itemname = $item['name']; + echo "<tr id='tr_edititemdetails_{$counter}_{$itemname}'>"; + echo "<td style='border-right:0'>"; echo "{$item['columnheader']}: "; echo "</td>"; - echo "<td style='border-left:0' class='$tdclass'>"; - $itemname = $item['name']; + echo "<td style='border-left:0'>"; $itemvalue = $value[$itemname]; - echo "{$item['description']}<br/>"; + + if (!empty($item['description'])) { + echo "{$item['description']}<br/>"; + } if (isset($item['customdrawcell'])) { - $item['customdrawcell']($item, $itemvalue, true, $itemname . $counter); - } else + $item['customdrawcell']($this, $item, $itemvalue, true, $itemname, $counter); + } else { $this->haproxy_htmllist_drawcell($item, $itemvalue, true, $itemname, $counter); + } echo "</td>"; - $leftitem = false; - echo "</tr>"; + echo "</tr>"; } echo "</table>"; echo "</div>"; echo "</td>"; echo "</tr>"; } - if (isset($itemdetails)) { - $colspan = count($items)-1; - echo "<tr id='htmltable_{$tablename}_{$counter}_details' style='$displaystyle' >"; - echo "<td class='vtable listlr' style='border-bottom-width: medium;'> </td>"; - echo "<td class='vtable listr' colspan='$colspan' style='border-bottom-width: medium;'>"; - echo "</td>"; - echo "</tr>"; - } - $counter++; } } - echo "</table> - <a onclick='javascript:addRowTo(\"$tablename\"); return false;' href='#'> + echo "</tbody> + </table> + <a onclick='javascript:addRowTo(\"{$tablename}\"); return false;' href='#'> <img border='0' src='/themes/{$g['theme']}/images/icons/icon_plus.gif' alt='' title='add another entry' /> </a>"; } } +function sort_index(&$a, &$b) { + // sort callback function, cannot be inside the object. + if ($a['_index'] != $b['_index']) { + return $a['_index'] > $b['_index'] ? 1 : -1; + } + return 0; +} + function haproxy_htmllist($tablename,$rowvalues,$items,$editstate=false,$itemdetails=null){ $list = new HaproxyHtmlList($tablename, $items); $list->haproxy_htmllist($rowvalues, $items, $editstate, $itemdetails); } -function haproxy_htmllist_get_values($html_list){ - $list = new HaproxyHtmlList("-", $html_list); +function haproxy_htmllist_get_values($tablename, $html_list){ + $list = new HaproxyHtmlList($tablename, $html_list); return $list->haproxy_htmllist_get_values(); } function haproxy_htmllist_js(){ + global $g; ?><script type="text/javascript"> + + var theme = "<?=$g['theme']?>"; + function html_listitem_change(tableId, fieldId, rowNr, field) { javascript_event = tableId + "_listitem_change"; var fn = window[javascript_event]; @@ -297,61 +359,73 @@ function haproxy_htmllist_js(){ } } - function htmllist_get_select_items(prefix,tableId) { + function htmllist_get_select_items(prefix, tableId) { var items; - var i = tableId.lastIndexOf('_'); - var items_name = prefix+"_"+tableId.substr(i+1); - items = eval("typeof "+items_name+" !== 'undefined' ? "+items_name+" : {}"); + var items_name = prefix+"_"+tableId; + items = eval("typeof "+items_name+" !== 'undefined' ? "+items_name+" : null"); return items; } + function createFieldHtml(tableId, field, rowId) { + var result = ""; + if(field['type'] == 'textbox') { + result="<input size='" + field['size'] + "' name='" + tableId + field['name'] + rowId + + "' id='" + tableId + field['name'] + rowId + + "'><\/input> "; + } else if(field['type'] == 'textarea') { + result="<textarea cols='" + field['size'] + "' rows='30' name='" + tableId + field['name'] + rowId + + "' id='" + tableId + field['name'] + rowId + + "'><\/textarea> "; + } else if(field['type'] == 'select') { + var seltext = ""; + var fieldid = field['name']; + var fn = window["htmllist_get_select_options"]; + fielditems = field['items']; + if (typeof fn === 'function'){ + fielditems = htmllist_get_select_options(tableId, field['name'], fielditems); + } + for (var fieldvalueid in fielditems) { + var fieldvalue = fielditems[fieldvalueid] + seltext += "<option value='"+fieldvalueid+"'>"+fieldvalue['name']+"<\/option>"; + } + + result="<select style='width:" + field['size'] + "' name='" + tableId + field['name'] + rowId + + "' id='" + tableId + field['name'] + rowId + "' "+ + "onchange='html_listitem_change(\""+tableId+"\",\""+field['name']+"\",\""+rowId+"\",this);' " + + ">" + seltext + "<\/select> "; + } else if(field['type'] == 'fixedtext') { + result=field['text']; + } else { + result="<input type='checkbox' name='" + tableId + field['name'] + rowId +"'"+ + "id='" + tableId + field['name'] + rowId + "' "+ + "onclick='html_listitem_change(\""+tableId+"\",\""+field['name']+"\",\""+rowId+"\",this);' " + + "value='yes'><\/input> "; + } + return result; + } + var addRowTo = (function() { return (function (tableId) { var d, tbody, tr, td, bgc, i, ii, j, type, seltext, items; var btable, btbody, btr, btd; d = document; - items = htmllist_get_select_items('fields',tableId); - tbody = d.getElementById(tableId).getElementsByTagName("tbody").item(0); - tr = d.createElement("tr"); totalrows++; - tr.setAttribute("id","aclrow" + totalrows); - + + // create edit row fields + items = htmllist_get_select_items('fields',tableId); + tr = d.createElement("tr"); + tr.setAttribute("id","tr_edit_" + totalrows); for (var i in items) { + fieldhtml = createFieldHtml(tableId, items[i], totalrows); td = d.createElement("td"); - if(items[i]['type'] == 'textbox') { - td.innerHTML="<input size='" + items[i]['size'] + "' name='" + items[i]['name'] + totalrows + - "' id='" + items[i]['name'] + totalrows + - "'><\/input> "; - } else if(items[i]['type'] == 'textarea') { - td.innerHTML="<textarea cols='" + items[i]['size'] + "' rows='30' name='" + items[i]['name'] + totalrows + - "' id='" + items[i]['name'] + totalrows + - "'><\/textarea> "; - } else if(items[i]['type'] == 'select') { - seltext = htmllist_get_select_options(tableId, items[i]['name']); - td.innerHTML="<select style='width:" + items[i]['size'] + "' name='" + items[i]['name'] + totalrows + - "' id='" + items[i]['name'] + totalrows + "' "+ - "onchange='html_listitem_change(\""+tableId+"\",\""+items[i]['name']+"\",\""+totalrows+"\",this);' " + - ">" + seltext + "<\/select> "; - } else { - td.innerHTML="<input type='checkbox' name='" + items[i]['name'] + totalrows +"'"+ - "id='" + items[i]['name'] + totalrows + "' "+ - "onclick='html_listitem_change(\""+tableId+"\",\""+items[i]['name']+"\",\""+totalrows+"\",this);' " + - "value='yes'><\/input> "; - } + td.innerHTML = fieldhtml; tr.appendChild(td); } td = d.createElement("td"); td.rowSpan = "1"; td.setAttribute("class","list"); - - items = htmllist_get_select_items('fields_details',tableId); - for (var i in items) { - td.innerHTML=td.innerHTML+"<input type='hidden' name='" + items[i]['name'] + totalrows + - "' id='" + items[i]['name'] + totalrows + - "'><\/input> "; - } // Recreate the button table. btable = document.createElement("table"); @@ -360,20 +434,75 @@ function haproxy_htmllist_js(){ btable.setAttribute("cellpadding", "1"); btbody = document.createElement("tbody"); btr = document.createElement("tr"); + btd = document.createElement("td"); btd.setAttribute("valign", "middle"); - btd.innerHTML = '<img src="/themes/' + theme + '/images/icons/icon_x.gif" title="delete entry" width="17" height="17" border="0" onclick="removeRow(this); return false;" />'; + btd.innerHTML = + '<input name="'+tableId+'_rowindex'+totalrows+'" id="'+tableId+'_rowindex'+totalrows+'" type="hidden" value="'+totalrows+'" />' + + '<img src="/themes/' + theme + '/images/icons/icon_x.gif" title="delete entry" width="17" height="17" border="0" onclick="deleteRow(' + totalrows + ", '" + tableId + "'); return false;\" />"; btr.appendChild(btd); + btd = document.createElement("td"); btd.setAttribute("valign", "middle"); btd.innerHTML = '<img src="/themes/' + theme + "/images/icons/icon_plus.gif\" title=\"duplicate entry\" width=\"17\" height=\"17\" border=\"0\" onclick=\"dupRow(" + totalrows + ", '" + tableId + "'); return false;\" />"; btr.appendChild(btd); + + + var tabledefinition = htmllist_get_select_items("tabledefinition", tableId); + if (tabledefinition && tabledefinition['keyfield'] == "") { + btd = document.createElement("td"); + btd.setAttribute("valign", "middle"); + btd.innerHTML = '<img src="/themes/' + theme + "/images/icons/icon_up.gif\" title=\"move entry up\" width=\"17\" height=\"17\" border=\"0\" onclick=\"moveRowUp(" + totalrows + ", '" + tableId + "'); return false;\" />"; + btr.appendChild(btd); + + btd = document.createElement("td"); + btd.setAttribute("valign", "middle"); + btd.innerHTML = '<img src="/themes/' + theme + "/images/icons/icon_down.gif\" title=\"move entry down\" width=\"17\" height=\"17\" border=\"0\" onclick=\"moveRowDown(" + totalrows + ", '" + tableId + "'); return false;\" />"; + btr.appendChild(btd); + } + btbody.appendChild(btr); btable.appendChild(btbody); td.appendChild(btable); tr.appendChild(td); - tbody.appendChild(tr); - + tbody.appendChild(tr); // add the edit row to the table + + // create viewdetail row + items = htmllist_get_select_items('fields_details',tableId); + if (items) { + tr = d.createElement("tr"); + tr.setAttribute("id","tr_viewdetail_" + totalrows); + td = d.createElement("td"); + tr.appendChild(td); + td = d.createElement("td"); + table = d.createElement("table"); + table.setAttribute("cellspacing","0"); + for (var i in items) { + field = items[i]; + fieldhtml = createFieldHtml(tableId, field, totalrows); + subtr = d.createElement("tr"); + subtr.setAttribute("id","tr_edititemdetails_" + totalrows + "_" + field['name']); + subtd = d.createElement("td"); + subtd.setAttribute("class","vncell"); + subtd.innerHTML = field['columnheader'] + ": "; + subtr.appendChild(subtd); + subtd = d.createElement("td"); + subtd.setAttribute("class","vncell"); + subtd.innerHTML = field['description'] + "<br/>" + fieldhtml; + subtr.appendChild(subtd); + table.appendChild(subtr); + } + td.appendChild(table); + tr.appendChild(td); + tbody.appendChild(tr); // add the viewdetail row to the table + } + // show/hide conditional fields if applicable using a custom function. + javascript_event = tableId + "_listitem_change"; + var fn = window[javascript_event]; + if (typeof fn === 'function'){ + fn(tableId, "toggle_details", totalrows, null); + } + javascript_row_added = tableId + "_row_added"; var fn = window[javascript_row_added]; if (typeof fn === 'function'){ @@ -387,18 +516,18 @@ function haproxy_htmllist_js(){ addRowTo(tableId); items = htmllist_get_select_items('fields',tableId); for (var i in items) { - dupEl = document.getElementById(items[i]['name'] + rowId); - newEl = document.getElementById(items[i]['name'] + totalrows); + dupEl = document.getElementById(tableId + items[i]['name'] + rowId); + newEl = document.getElementById(tableId + items[i]['name'] + totalrows); if (dupEl && newEl) if(items[i]['type'] == 'checkbox') newEl.checked = dupEl.checked; else newEl.value = dupEl.value; } - items = htmllist_get_select_items('fields_details',tableId); + items = htmllist_get_select_items('fields_details', tableId); for (var i in items) { - dupEl = document.getElementById(items[i]['name'] + rowId); - newEl = document.getElementById(items[i]['name'] + totalrows); + dupEl = document.getElementById(tableId + items[i]['name'] + rowId); + newEl = document.getElementById(tableId + items[i]['name'] + totalrows); if (dupEl && newEl) if(items[i]['type'] == 'checkbox') newEl.value = dupEl.checked ? 'yes' : ''; @@ -428,21 +557,89 @@ function haproxy_htmllist_js(){ if (edit) edit.parentNode.removeChild(edit); } - function removeRow(el) { - var cel; - // Break out of one table first - while (el && el.nodeName.toLowerCase() != "table") - el = el.parentNode; - while (el && el.nodeName.toLowerCase() != "tr") - el = el.parentNode; - if (el && el.parentNode) { - cel = el.getElementsByTagName("td").item(0); - el.parentNode.removeChild(el); + function moveRowUp(rowId, tableId) { + moveRow(rowId, tableId, true); + } + function moveRowDown(rowId, tableId) { + moveRow(rowId, tableId, false); + } + function moveRow(rowId, tableId, up) { + var rowview = document.getElementById("tr_view_" + rowId); + var rowedit = document.getElementById("tr_edit_" + rowId); + var rowviewdetail = document.getElementById("tr_viewdetail_" + rowId); + + var parent = rowedit.parentNode; + var swapid; + var swaprowedit; + if (up){ + //move current rows before the previous row + var prevtr; + if (rowview) { + prevtr = rowview.previousElementSibling; + } else { + prevtr = rowedit.previousElementSibling; + } + if (!prevtr) + return; // was already top element. + var swapid = prevtr['id']; + var i = swapid.lastIndexOf('_'); + swapid = swapid.substr(i+1); + var prevrowview = document.getElementById("tr_view_" + swapid); + swaprowedit = document.getElementById("tr_edit_" + swapid); + if (prevrowview){ + firstprevrow = prevrowview; + } else { + firstprevrow = swaprowedit; + } + // move the 3 rows + if (rowview) { + parent.insertBefore(rowview, firstprevrow); + } + parent.insertBefore(rowedit, firstprevrow); + if (rowviewdetail) { + parent.insertBefore(rowviewdetail, firstprevrow); + } + } else { + //move next row before the current row + var nexttr; + if (rowviewdetail) { + nexttr = rowviewdetail.nextElementSibling; + } else { + nexttr = rowedit.nextElementSibling; + } + if (!nexttr) { + return; // was already bottom element. + } + var swapid = nexttr['id']; + var i = swapid.lastIndexOf('_'); + swapid = swapid.substr(i+1); + var prevrowview = document.getElementById("tr_view_" + swapid); + swaprowedit = document.getElementById("tr_edit_" + swapid); + var prevrowviewdetail = document.getElementById("tr_viewdetail_" + swapid); + if (rowview){ + firstrow = rowview; + } else { + firstrow = rowedit; + } + // move the 3 rows + if (prevrowview) { + parent.insertBefore(prevrowview, firstrow); + } + parent.insertBefore(swaprowedit, firstrow); + if (prevrowviewdetail) { + parent.insertBefore(prevrowviewdetail, firstrow); + } } + + var id_a = document.getElementById(tableId+'_rowindex' + swapid); + var id_b = document.getElementById(tableId+'_rowindex' + rowId); + temp = id_a.value; + id_a.value = id_b.value; + id_b.value = temp; } - function htmltable_toggle_details(table_row_detail_id) { + function htmltable_toggle_details(tableId, rowNr, table_row_detail_id) { tredit = document.getElementById(table_row_detail_id+'_off'); trviewdetail = document.getElementById(table_row_detail_id+'_edit'); treditdetail = document.getElementById(table_row_detail_id+'_view'); @@ -450,6 +647,13 @@ function haproxy_htmllist_js(){ tredit.style.display=current_on ? '' : 'none'; trviewdetail.style.display=current_on ? 'none' : ''; treditdetail.style.display=current_on ? '' : 'none'; + + // show/hide conditional fields if applicable using a custom function. + javascript_event = tableId + "_listitem_change"; + var fn = window[javascript_event]; + if (typeof fn === 'function'){ + fn(tableId, "toggle_details", rowNr, null); + } } </script><? } diff --git a/config/haproxy-devel/pkg/haproxy_upgrade_config.inc b/config/haproxy-devel/pkg/haproxy_upgrade_config.inc index c1c951df..052f7c77 100644 --- a/config/haproxy-devel/pkg/haproxy_upgrade_config.inc +++ b/config/haproxy-devel/pkg/haproxy_upgrade_config.inc @@ -1,6 +1,6 @@ <?php /* - haproxy.inc + haproxy_upgrade_config.inc Copyright (C) 2015 PiBa-NL All rights reserved. @@ -26,7 +26,9 @@ POSSIBILITY OF SUCH DAMAGE. */ +require_once("haproxy_utils.inc"); require_once("pkg-utils.inc"); +require_once("haproxy.inc"); function haproxy_upgrade_config() { global $config, $static_output; @@ -143,16 +145,18 @@ function haproxy_upgrade_config() { } if ($configversion < "00.13") { // update config to "haproxy-devel 1.5-dev19 pkg v0.13" - foreach ($config['installedpackages']['haproxy']['ha_backends']['item'] as &$bind) { - if (isset($bind['extaddr'])) { - $new['extaddr'] = $bind['extaddr']; - $new['extaddr_port'] = $bind['port']; - $new['extaddr_ssl'] = $bind['ssloffload']; - $bind['a_extaddr']['item'][] = $new; + if (is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { + foreach ($config['installedpackages']['haproxy']['ha_backends']['item'] as &$bind) { + if (isset($bind['extaddr'])) { + $new['extaddr'] = $bind['extaddr']; + $new['extaddr_port'] = $bind['port']; + $new['extaddr_ssl'] = $bind['ssloffload']; + $bind['a_extaddr']['item'][] = $new; + } + unset($bind['extaddr']); + unset($bind['port']); + //unset($bind['ssloffload']); } - unset($bind['extaddr']); - unset($bind['port']); - //unset($bind['ssloffload']); } $configversion = "00.13"; } @@ -167,15 +171,17 @@ function haproxy_upgrade_config() { $static_output .= "HAProxy, 00.17\n"; update_output_window($static_output); // remove 'none' ca-cert, and set checkbox to allow for no certificate instead. - foreach ($config['installedpackages']['haproxy']['ha_backends']['item'] as &$bind) { - $list = array(); - foreach ($bind['clientcert_ca']['item'] as $ca){ - if (empty($ca['cert_ca'])) - $bind['sslclientcert-none'] = 'yes'; - else - $list[] = $ca; + if (is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { + foreach ($config['installedpackages']['haproxy']['ha_backends']['item'] as &$bind) { + $list = array(); + foreach ($bind['clientcert_ca']['item'] as $ca){ + if (empty($ca['cert_ca'])) + $bind['sslclientcert-none'] = 'yes'; + else + $list[] = $ca; + } + $bind['clientcert_ca']['item'] = $list; } - $bind['clientcert_ca']['item'] = $list; } $configversion = "00.17"; } @@ -193,6 +199,71 @@ function haproxy_upgrade_config() { } $configversion = "00.19"; } + if ($configversion < "00.32") { + $frontends = array(); + if (is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { + foreach ($config['installedpackages']['haproxy']['ha_backends']['item'] as &$frontend) { + $primaryfrontend = get_primaryfrontend($frontend); + $fe_name = $primaryfrontend['name']; + $frontends[$fe_name][] = &$frontend; + } + + foreach ($frontends as $primary) { + $acl_count = array(); + foreach ($primary as &$frontend){ + $acl_use = array(); + $a_actions = &$frontend['a_actionitems']['item']; + if (!is_array($a_actions)) { + $a_actions = array(); + } + + $primaryfrontend = get_primaryfrontend($frontend); + $frontendtype = $primaryfrontend['type']; + $is_default = true; + if (is_array($frontend['ha_acls']['item'])) { + $a_acl = &$frontend['ha_acls']['item']; + + foreach ($a_acl as &$aclitem) { + $aclname = $aclitem['name']; + $acltype = haproxy_find_acl($aclitem['expression']); + if ($aclitem['expression'] == "backendservercount") { + $aclitem['backendservercountbackend'] = $frontend['backend_serverpool']; + } + if (!isset($acl_count[$aclname])) { + $acl_count[$aclname] = 1; + } else { + $acl_count[$aclname] += 1; + $aclitem['name'] .= "_{$acl_count[$aclname]}"; + } + if (!isset($acltype)) + continue; + if ($acltype['mode'] != '' && $acltype['mode'] != strtolower($frontendtype)) { + continue; + } + $acl_use[$aclname][] = $aclitem['name']; + } + foreach ($acl_use as $key => $acl_x) { + $aclx = $acl_count[$key]; + $aclnames = ""; + foreach($acl_x as $aclname) { + $aclnames .= " $aclname"; + } + $aclnames = trim($aclnames); + $action['action'] = 'use_backend'; + $action['use_backendbackend'] = $frontend['backend_serverpool']; + $action['acl'] = $aclnames; + $a_actions[] = $action; + $is_default = false; + } + } + if (!$is_default) { + $frontend['backend_serverpool'] = ""; + } + } + } + } + $configversion = "00.32"; + } $writeconfigupdate = $config['installedpackages']['haproxy']['configversion'] <> $configversion; if ($writeconfigupdate) { diff --git a/config/haproxy-devel/pkg/haproxy_utils.inc b/config/haproxy-devel/pkg/haproxy_utils.inc index ec72b986..04cacb30 100644 --- a/config/haproxy-devel/pkg/haproxy_utils.inc +++ b/config/haproxy-devel/pkg/haproxy_utils.inc @@ -122,11 +122,11 @@ function haproxy_get_bindable_interfaces($ipv="ipv4,ipv6", $interfacetype="any,l // $bindable[key]['description'] can be shown to user in a selection box global $config; - $ipverions = split(',',$ipv); + $ipversions = split(',',$ipv); $interfacetypes= split(',',$interfacetype); $bindable = array(); - if (in_array("ipv4",$ipverions)){ + if (in_array("ipv4",$ipversions)){ if (in_array('any',$interfacetypes)){ $item = array(); $item[ip] = '0.0.0.0'; @@ -187,7 +187,7 @@ function haproxy_get_bindable_interfaces($ipv="ipv4,ipv6", $interfacetype="any,l if (!isset($config['system']['ipv6allow'])) return $bindable;// skip adding the IPv6 addresses if those are not 'allowed' - if (in_array("ipv6",$ipverions)){ + if (in_array("ipv6",$ipversions)){ if (in_array('any',$interfacetypes)){ $item = array(); $item[ip] = '::'; @@ -386,6 +386,27 @@ function haproxy_get_certificates($type = 'server,user', $get_includeWebCert=fal return $certificates; } +function haproxy_get_certificate_subjectAltNames($str_crt, $decode = true) { + if ($decode) { + $str_crt = base64_decode($str_crt); + } + $result = array(); + $ext = openssl_x509_parse($str_crt, false); + $subjectAltName = $ext['extensions']['subjectAltName']; + $lines = explode('\n', $subjectAltName); + foreach($lines as $line) { + $items = explode(',', $line); + foreach($items as $item) { + $item = trim($item); + if (strpos($item, "DNS:") === 0) { + $DNSitem = substr($item, 4); + $result[] = $DNSitem; + } + } + } + return $result; +} + function haproxy_get_crls() { global $config; $certificates=array(); @@ -406,7 +427,8 @@ function haproxy_get_crls() { function phparray_to_javascriptarray_recursive($nestID, $path, $items, $nodeName, $includeitems) { $offset = str_repeat(' ',$nestID); $itemName = "item$nestID"; - echo "{$offset}$nodeName = {};\n"; + //echo "{$offset}$nodeName = {};\n"; + echo "{$offset}$nodeName = Object.create(null);\n"; if (is_array($items)) foreach ($items as $key => $item) { diff --git a/config/haproxy-devel/www/haproxy_files.php b/config/haproxy-devel/www/haproxy_files.php index 12ab5a88..4fe6bf45 100644 --- a/config/haproxy-devel/www/haproxy_files.php +++ b/config/haproxy-devel/www/haproxy_files.php @@ -42,15 +42,20 @@ if (!is_array($a_pools)) $a_pools = array(); $fields_files = array(); $fields_files[0]['name']="name"; $fields_files[0]['columnheader']="Name"; -$fields_files[0]['colwidth']="30%"; +$fields_files[0]['colwidth']="20%"; $fields_files[0]['type']="textbox"; $fields_files[0]['size']="20"; - -$fields_files[1]['name']="content"; -$fields_files[1]['columnheader']="content"; -$fields_files[1]['colwidth']="70%"; -$fields_files[1]['type']="textarea"; -$fields_files[1]['size']="70"; +$fields_files[1]['name']="type"; +$fields_files[1]['columnheader']="Type"; +$fields_files[1]['colwidth']="10%"; +$fields_files[1]['type']="select"; +$fields_files[1]['size']="10"; +$fields_files[1]['items']=$a_filestype; +$fields_files[2]['name']="content"; +$fields_files[2]['columnheader']="content"; +$fields_files[2]['colwidth']="70%"; +$fields_files[2]['type']="textarea"; +$fields_files[2]['size']="70"; $fileslist = new HaproxyHtmlList("table_files", $fields_files); $fileslist->keyfield = "name"; @@ -63,7 +68,7 @@ if ($_POST) { if ($result) unlink_if_exists($d_haproxyconfdirty_path); } else { - $a_files = $fileslist->haproxy_htmllist_get_values($fields_files); + $a_files = $fileslist->haproxy_htmllist_get_values(); $filedupcheck = array(); foreach($a_files as $key => $file) { @@ -77,7 +82,7 @@ if ($_POST) { // replace references in backends to renamed 'files' foreach($a_pools as &$backend) { - if (is_arrayset($backend,'errorfiles','item')) + if (is_arrayset($backend,'errorfiles','item')) { foreach($backend['errorfiles']['item'] as &$errorfile) { $found = false; foreach($a_files as $key => $file) { @@ -86,9 +91,11 @@ if ($_POST) { $found = true; } } - if (!$found) + if (!$found) { $input_errors[] = "Errorfile marked for deletion: " . $errorfile['errorfile'] . " which is used in backend " . $backend['name']; + } } + } } if (!$input_errors) { // save config when no errors found @@ -100,10 +107,9 @@ if ($_POST) { } } -$pf_version=substr(trim(file_get_contents("/etc/version")),0,3); - $pgtitle = "Services: HAProxy: Files"; include("head.inc"); +haproxy_css(); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> @@ -165,7 +171,7 @@ include("head.inc"); <script type="text/javascript"> totalrows = <?php echo $counter; ?>; <? - phparray_to_javascriptarray($fields_files,"fields_files",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); + $fileslist->outputjavascript(); ?> </script> diff --git a/config/haproxy-devel/www/haproxy_global.php b/config/haproxy-devel/www/haproxy_global.php index 2ae92256..4902b966 100644 --- a/config/haproxy-devel/www/haproxy_global.php +++ b/config/haproxy-devel/www/haproxy_global.php @@ -38,12 +38,13 @@ require_once("pkg_haproxy_tabs.inc"); require_once("haproxy_htmllist.inc"); $simplefields = array('localstats_refreshtime', 'localstats_sticktable_refreshtime', 'log-send-hostname', 'ssldefaultdhparam', - 'email_level', 'email_myhostname', 'email_from', 'email_to'); + 'email_level', 'email_myhostname', 'email_from', 'email_to', + 'resolver_retries', 'resolver_timeoutretry', 'resolver_holdvalid'); $none = array(); $none['']['name'] = "Dont log"; $a_sysloglevel = $none + $a_sysloglevel; - + $fields_mailers = array(); $fields_mailers[0]['name'] = "name"; $fields_mailers[0]['columnheader'] = "Name"; @@ -61,8 +62,27 @@ $fields_mailers[2]['colwidth'] = "10%"; $fields_mailers[2]['type'] = "textbox"; $fields_mailers[2]['size'] = "10"; +$fields_resolvers = array(); +$fields_resolvers[0]['name'] = "name"; +$fields_resolvers[0]['columnheader'] = "Name"; +$fields_resolvers[0]['colwidth'] = "30%"; +$fields_resolvers[0]['type'] = "textbox"; +$fields_resolvers[0]['size'] = "20"; +$fields_resolvers[1]['name'] = "server"; +$fields_resolvers[1]['columnheader'] = "DNSserver"; +$fields_resolvers[1]['colwidth'] = "60%"; +$fields_resolvers[1]['type'] = "textbox"; +$fields_resolvers[1]['size'] = "60"; +$fields_resolvers[2]['name'] = "port"; +$fields_resolvers[2]['columnheader'] = "DNSport"; +$fields_resolvers[2]['colwidth'] = "10%"; +$fields_resolvers[2]['type'] = "textbox"; +$fields_resolvers[2]['size'] = "10"; + $mailerslist = new HaproxyHtmlList("table_mailers", $fields_mailers); $mailerslist->keyfield = "name"; +$resolverslist = new HaproxyHtmlList("table_resolvers", $fields_resolvers); +$resolverslist->keyfield = "name"; if (!is_array($config['installedpackages']['haproxy'])) $config['installedpackages']['haproxy'] = array(); @@ -82,7 +102,7 @@ if ($_POST) { unlink_if_exists($d_haproxyconfdirty_path); } else { $a_mailers = $mailerslist->haproxy_htmllist_get_values(); - $pool['ha_servers']['item'] = $a_servers; + $a_resolvers = $resolverslist->haproxy_htmllist_get_values(); if ($_POST['carpdev'] == "disabled") unset($_POST['carpdev']); @@ -99,28 +119,18 @@ if ($_POST) { if ($_POST['localstats_sticktable_refreshtime'] && (!is_numeric($_POST['localstats_sticktable_refreshtime']))) $input_errors[] = "The local stats sticktable refresh time should be numeric or empty."; - /*if($_POST['synchost1'] && !is_ipaddr($_POST['synchost1'])) - $input_errors[] = "Synchost1 needs to be an IPAddress."; - if($_POST['synchost2'] && !is_ipaddr($_POST['synchost2'])) - $input_errors[] = "Synchost2 needs to be an IPAddress."; - if($_POST['synchost3'] && !is_ipaddr($_POST['synchost3'])) - $input_errors[] = "Synchost3 needs to be an IPAddress.";*/ - if (!$input_errors) { - $config['installedpackages']['haproxy']['email_mailers']['items'] = $a_mailers; + $config['installedpackages']['haproxy']['email_mailers']['item'] = $a_mailers; + $config['installedpackages']['haproxy']['dns_resolvers']['item'] = $a_resolvers; $config['installedpackages']['haproxy']['enable'] = $_POST['enable'] ? true : false; $config['installedpackages']['haproxy']['terminate_on_reload'] = $_POST['terminate_on_reload'] ? true : false; $config['installedpackages']['haproxy']['maxconn'] = $_POST['maxconn'] ? $_POST['maxconn'] : false; $config['installedpackages']['haproxy']['enablesync'] = $_POST['enablesync'] ? true : false; - //$config['installedpackages']['haproxy']['synchost1'] = $_POST['synchost1'] ? $_POST['synchost1'] : false; - //$config['installedpackages']['haproxy']['synchost2'] = $_POST['synchost2'] ? $_POST['synchost2'] : false; - //$config['installedpackages']['haproxy']['synchost2'] = $_POST['synchost3'] ? $_POST['synchost3'] : false; $config['installedpackages']['haproxy']['remotesyslog'] = $_POST['remotesyslog'] ? $_POST['remotesyslog'] : false; $config['installedpackages']['haproxy']['logfacility'] = $_POST['logfacility'] ? $_POST['logfacility'] : false; $config['installedpackages']['haproxy']['loglevel'] = $_POST['loglevel'] ? $_POST['loglevel'] : false; $config['installedpackages']['haproxy']['carpdev'] = $_POST['carpdev'] ? $_POST['carpdev'] : false; - //$config['installedpackages']['haproxy']['syncpassword'] = $_POST['syncpassword'] ? $_POST['syncpassword'] : false; $config['installedpackages']['haproxy']['localstatsport'] = $_POST['localstatsport'] ? $_POST['localstatsport'] : false; $config['installedpackages']['haproxy']['advanced'] = $_POST['advanced'] ? base64_encode($_POST['advanced']) : false; $config['installedpackages']['haproxy']['nbproc'] = $_POST['nbproc'] ? $_POST['nbproc'] : false; @@ -132,16 +142,19 @@ if ($_POST) { } } -$a_mailers = $config['installedpackages']['haproxy']['email_mailers']['items']; +$a_mailers = $config['installedpackages']['haproxy']['email_mailers']['item']; +if (!is_array($a_mailers)) { + $a_mailers = array(); +} +$a_resolvers = $config['installedpackages']['haproxy']['dns_resolvers']['item']; +if (!is_array($a_resolvers)) { + $a_resolvers = array(); +} $pconfig['enable'] = isset($config['installedpackages']['haproxy']['enable']); $pconfig['terminate_on_reload'] = isset($config['installedpackages']['haproxy']['terminate_on_reload']); $pconfig['maxconn'] = $config['installedpackages']['haproxy']['maxconn']; $pconfig['enablesync'] = isset($config['installedpackages']['haproxy']['enablesync']); -//$pconfig['syncpassword'] = $config['installedpackages']['haproxy']['syncpassword']; -//$pconfig['synchost1'] = $config['installedpackages']['haproxy']['synchost1']; -//$pconfig['synchost2'] = $config['installedpackages']['haproxy']['synchost2']; -//$pconfig['synchost3'] = $config['installedpackages']['haproxy']['synchost3']; $pconfig['remotesyslog'] = $config['installedpackages']['haproxy']['remotesyslog']; $pconfig['logfacility'] = $config['installedpackages']['haproxy']['logfacility']; $pconfig['loglevel'] = $config['installedpackages']['haproxy']['loglevel']; @@ -158,13 +171,9 @@ if (!$pconfig['logfacility']) if (!$pconfig['loglevel']) $pconfig['loglevel'] = 'info'; -$pf_version=substr(trim(file_get_contents("/etc/version")),0,3); -if ($pf_version < 2.0) - $one_two = true; - $pgtitle = "Services: HAProxy: Settings"; include("head.inc"); - +haproxy_css(); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <script type="text/javascript" src="javascript/scriptaculous/prototype.js"></script> @@ -179,9 +188,6 @@ function enable_change(enable_change) { } //--> </script> -<?php if($one_two): ?> -<p class="pgtitle"><?=$pgtitle?></p> -<?php endif; ?> <form action="haproxy_global.php" method="post" name="iform"> <?php if ($input_errors) print_input_errors($input_errors); ?> <?php if ($savemsg) print_info_box($savemsg); ?> @@ -210,7 +216,7 @@ function enable_change(enable_change) { <tr> <td width="22%" valign="top" class="vncell">Installed version:</td> <td width="78%" class="vtable"> - <strong><?=haproxy_verion()?></strong> + <strong><?=haproxy_version()?></strong> </td> </tr> <tr> @@ -400,9 +406,55 @@ function enable_change(enable_change) { </td> </tr> <tr><td> </td></tr> - <? if (haproxy_verion() >= '1.6' ) { ?> + <? if (haproxy_version() >= '1.6-dev4' ) { ?> <tr> - <td colspan="2" valign="top" class="listtopic">Email notifications</td> + <td colspan="2" valign="top" class="listtopic">Global DNS resolvers for haproxy</td> + </tr> + <tr> + <td valign="top" class="vncell"> + DNS servers + </td> + <td class="vtable"> + Configuring DNS servers will allow haproxy to detect when a servers IP changes to a different one in 'elastic' environments without needing to be restarted. + <br/> + <? + $counter=0; + $resolverslist->Draw($a_resolvers); + ?> + </td> + </tr> + <tr> + <td valign="top" class="vncell"> + 'resolver_retries' + </td> + <td class="vtable"> + <input name="resolver_retries" type="text" <?if(isset($pconfig['resolver_retries'])) echo "value=\"{$pconfig['resolver_retries']}\"";?> size="50"/><br/> + Email address to be used as the sender of the emails. + </td> + </tr> + <tr> + <td valign="top" class="vncell"> + 'resolver_timeoutretry' + </td> + <td class="vtable"> + <input name="resolver_timeoutretry" type="text" <?if(isset($pconfig['resolver_timeoutretry'])) echo "value=\"{$pconfig['resolver_timeoutretry']}\"";?> size="50"/><br/> + Email address to be used as the sender of the emails. + </td> + </tr> + <tr> + <td valign="top" class="vncell"> + 'resolver_holdvalid' + </td> + <td class="vtable"> + <input name="resolver_holdvalid" type="text" <?if(isset($pconfig['resolver_holdvalid'])) echo "value=\"{$pconfig['resolver_holdvalid']}\"";?> size="50"/><br/> + Email address to be used as the sender of the emails. + </td> + </tr> + <tr><td> </td></tr> + <? } + if (haproxy_version() >= '1.6' ) { ?> + <tr> + <td colspan="2" valign="top" class="listtopic">Global email notifications</td> </tr> <tr> <td valign="top" class="vncell"> @@ -412,7 +464,6 @@ function enable_change(enable_change) { It is possible to send email alerts when the state of servers changes. If configured email alerts are sent to each mailer that is configured in a mailers section. Email is sent to mailers using SMTP. <br/> <? - $counter=0; $mailerslist->Draw($a_mailers); ?> </td> @@ -582,7 +633,8 @@ haproxy_htmllist_js(); <script type="text/javascript"> totalrows = <?php echo $counter; ?>; <? - phparray_to_javascriptarray($fields_mailers,"fields_mailers",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); + $mailerslist->outputjavascript(); + $resolverslist->outputjavascript(); ?> function scroll_after_fade() { diff --git a/config/haproxy-devel/www/haproxy_listeners.php b/config/haproxy-devel/www/haproxy_listeners.php index db1f3ff2..c7288e7d 100644 --- a/config/haproxy-devel/www/haproxy_listeners.php +++ b/config/haproxy-devel/www/haproxy_listeners.php @@ -93,9 +93,31 @@ if ($_GET['act'] == "del") { } } +function haproxy_userlist_backend_servers($backendname) { + //used for hint title text when hovering mouse over a backend name + global $a_servermodes; + $backend_servers = ""; + $backend = get_backend($backendname); + if ($backend && is_array($backend['ha_servers']) && is_array($backend['ha_servers']['item'])){ + $servers = $backend['ha_servers']['item']; + $backend_servers = sprintf(gettext("Servers in \"%s\" pool:"), $backendname); + if (is_array($servers)){ + foreach($servers as $server){ + $srvstatus = $server['status']; + $status = $a_servermodes[$srvstatus]['sign']; + if (isset($server['forwardto']) && $server['forwardto'] != "") + $backend_servers .= "\n{$status}[{$server['forwardto']}]"; + else + $backend_servers .= "\n{$status}{$server['address']}:{$server['port']}"; + } + } + } + return $backend_servers; +} + $pgtitle = "Services: HAProxy: Frontends"; include("head.inc"); - +haproxy_css(); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> @@ -182,7 +204,7 @@ function js_callback(req) { $first = true; $last_frontend_shared = false; foreach ($a_frontend_grouped as $a_frontend) { - usort($a_frontend,'sort_sharedfrontends'); + usort($a_frontend, 'sort_sharedfrontends'); if ((count($a_frontend) > 1 || $last_frontend_shared) && !$first) { ?> <tr class="<?=$textgray?>"><td colspan="7"> </td></tr> <? } @@ -238,24 +260,6 @@ function js_callback(req) { if ($frontend['advanced']) $isadvset .= "Advanced pass thru setting used\r\n"; if ($isadvset) echo "<img src=\"$img_adv\" title=\"" . gettext("Advanced settings set") . ": {$isadvset}\" border=\"0\" />"; - - $backend_serverpool_hint = ""; - $backend_serverpool = $frontend['backend_serverpool']; - $backend = get_backend($backend_serverpool); - if ($backend && is_array($backend['ha_servers']) && is_array($backend['ha_servers']['item'])){ - $servers = $backend['ha_servers']['item']; - $backend_serverpool_hint = gettext("Servers in pool:"); - if (is_array($servers)){ - foreach($servers as $server){ - $srvstatus = $server['status']; - $status = $a_servermodes[$srvstatus]['sign']; - if (isset($server['forwardto']) && $server['forwardto'] != "") - $backend_serverpool_hint .= "\n{$status}[{$server['forwardto']}]"; - else - $backend_serverpool_hint .= "\n{$status}{$server['address']}:{$server['port']}"; - } - } - } ?> </td> <td class="listr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$frontendname;?>';"> @@ -296,15 +300,30 @@ function js_callback(req) { ?> </td> <td class="listr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$frontendname;?>';"> - <div title='<?=$backend_serverpool_hint;?>'> - <a href="haproxy_pool_edit.php?id=<?=$frontend['backend_serverpool']?>"> - <?=$frontend['backend_serverpool']?> - </a> - </div> + <? + if (is_array($frontend['a_actionitems']['item'])) { + foreach ($frontend['a_actionitems']['item'] as $actionitem) { + if ($actionitem['action'] == "use_backend") { + $backend = $actionitem['use_backendbackend']; + $hint = haproxy_userlist_backend_servers($backend); + echo "<div title='{$hint}'>"; + echo "<a href='haproxy_pool_edit.php?id={$backend}'>{$backend}</a>"; + if (!empty($actionitem['acl'])) { + echo " if({$actionitem['acl']})"; + } + echo "<br/></div>"; + } + } + } + $hint = haproxy_userlist_backend_servers($frontend['backend_serverpool']); + $backend = $frontend['backend_serverpool']; + if (!empty($backend)) { + echo "<div title='{$hint}'>"; + echo "<a href='haproxy_pool_edit.php?id={$backend}'>{$backend}</a> (default)"; + echo "<br/></div>"; + } + ?> </td> - <!--td class="listlr" ondblclick="document.location='haproxy_listeners_edit.php?id=<?=$frontendname;?>';"> - <?=$frontend['secondary'] == 'yes' ? $frontend['primary_frontend'] : "";?> - </td--> <td class="list" nowrap> <table border="0" cellspacing="0" cellpadding="1"> <tr> diff --git a/config/haproxy-devel/www/haproxy_listeners_edit.php b/config/haproxy-devel/www/haproxy_listeners_edit.php index 6998e099..9d2b0b05 100644 --- a/config/haproxy-devel/www/haproxy_listeners_edit.php +++ b/config/haproxy-devel/www/haproxy_listeners_edit.php @@ -47,17 +47,6 @@ if (!function_exists("cert_get_purpose")) { } /**/ -function haproxy_js_acl_select($mode) { - global $a_acltypes; - - $seltext = ''; - foreach ($a_acltypes as $key => $expr) { - if ($expr['mode'] == '' || $expr['mode'] == $mode) - $seltext .= "<option value='" . $key . "'>" . $expr['name'] ."<\/option>"; - } - return $seltext; -} - if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { $config['installedpackages']['haproxy']['ha_backends']['item'] = array(); } @@ -71,7 +60,8 @@ uasort($a_pools, haproxy_compareByName); global $simplefields; $simplefields = array('name','desc','status','secondary','primary_frontend','type','forwardfor','httpclose','extaddr','backend_serverpool', 'max_connections','client_timeout','port','advanced_bind', - 'ssloffloadcert','dcertadv','ssloffload','ssloffloadacl','ssloffloadacladditional','sslclientcert-none','sslclientcert-invalid','sslocsp', + 'ssloffloadcert','dcertadv','ssloffload','ssloffloadacl','ssloffloadacl_an','ssloffloadacladditional','ssloffloadacladditional_an', + 'sslclientcert-none','sslclientcert-invalid','sslocsp', 'socket-stats', 'dontlognull','dontlog-normal','log-separate-errors','log-detailed'); @@ -88,7 +78,7 @@ $id = get_frontend_id($id); if (!is_numeric($id)) { //default value for new items. - $pconfig['ssloffloadacl'] = "yes"; + $pconfig['ssloffloadacl_an'] = "yes"; $new_item = array(); $new_item['extaddr'] = "wan_ipv4"; $new_item['extaddr_port'] = "80"; @@ -182,12 +172,110 @@ $fields_externalAddress[4]['colwidth']="20%"; $fields_externalAddress[4]['type']="textbox"; $fields_externalAddress[4]['size']="30"; +$fields_actions=array(); +$fields_actions[0]['name']="action"; +$fields_actions[0]['columnheader']="Action"; +$fields_actions[0]['colwidth']="30%"; +$fields_actions[0]['type']="select"; +$fields_actions[0]['size']="200px"; +$fields_actions[0]['items']=&$a_action; +$fields_actions[1]['name']="parameters"; +$fields_actions[1]['columnheader']="Parameters"; +$fields_actions[1]['colwidth']="30%"; +$fields_actions[1]['type']="fixedtext"; +$fields_actions[1]['size']="200px"; +$fields_actions[1]['text']="See below"; +$fields_actions[2]['name']="acl"; +$fields_actions[2]['columnheader']="Condition acl names"; +$fields_actions[2]['colwidth']="15%"; +$fields_actions[2]['type']="textbox"; +$fields_actions[2]['size']="40"; + +$a_files = haproxy_get_fileslist(); +$fields_errorfile = array(); +$fields_errorfile[0]['name']="errorcode"; +$fields_errorfile[0]['columnheader']="errorcode(s)"; +$fields_errorfile[0]['colwidth']="15%"; +$fields_errorfile[0]['type']="textbox"; +$fields_errorfile[0]['size']="70px"; +$fields_errorfile[1]['name']="errorfile"; +$fields_errorfile[1]['columnheader']="Error Page"; +$fields_errorfile[1]['colwidth']="30%"; +$fields_errorfile[1]['type']="select"; +$fields_errorfile[1]['size']="170px"; +$fields_errorfile[1]['items']=&$a_files; + +$backends = get_haproxy_backends(); +$a_action['use_backend']['fields']['backend']['items'] = &$backends; +//$a_action['http-request_lua']['fields']['lua-script']['items'] = &$a_files; +//$a_action['tcp-request_content_lua']['fields']['lua-script']['items'] = &$a_files; + +$fields_actions_details=array(); +foreach($a_action as $key => $action) { + if (is_array($action['fields'])) { + foreach($action['fields'] as $field) { + $item = $field; + $name = $key . $item['name']; + $item['name'] = $name; + $item['columnheader'] = $field['name']; + $item['customdrawcell'] = customdrawcell_actions; + $fields_actions_details[$name] = $item; + } + } +} + +$a_acltypes["backendservercount"]['fields']['backend']['items'] = &$backends; +$fields_acl_details=array(); +foreach($a_acltypes as $key => $action) { + if (is_array($action['fields'])) { + foreach($action['fields'] as $field) { + $item = $field; + $name = $key . $item['name']; + $item['name'] = $name; + $item['columnheader'] = $field['name']; + $item['customdrawcell'] = customdrawcell_actions; + $fields_acl_details[$name] = $item; + } + } +} + +function customdrawcell_actions($object, $item, $itemvalue, $editable, $itemname, $counter) { + if ($editable) { + $object->haproxy_htmllist_drawcell($item, $itemvalue, $editable, $itemname, $counter); + } else { + //TODO hide fields not applicable.?. + echo $itemvalue; + } +} + +$htmllist_extaddr = new HaproxyHtmlList("table_extaddr", $fields_externalAddress); +$htmllist_extaddr->editmode = true; + +$htmllist_acls = new HaproxyHtmlList("table_acls", $fields_aclSelectionList); +$htmllist_acls->fields_details = $fields_acl_details; +//$htmllist_acls->editmode = true; + +$htmllist_actions = new HaproxyHtmlList("table_actions", $fields_actions); +$htmllist_actions->fields_details = $fields_actions_details; +//$htmllist_actions->keyfield = "name"; +//$htmllist_actions->editmode = true; + +$htmllist_sslCertificates = new HaproxyHtmlList("tbl_sslCerts", $fields_sslCertificates); +$htmllist_caCertificates = new HaproxyHtmlList("tbl_caCerts", $fields_caCertificates ); +$htmllist_crlCertificates = new HaproxyHtmlList("tbl_crlCerts", $fields_crlCertificates); + +$errorfileslist = new HaproxyHtmlList("table_errorfile", $fields_errorfile); +$errorfileslist->keyfield = "errorcode"; + if (isset($id) && $a_backend[$id]) { $pconfig['a_acl']=&$a_backend[$id]['ha_acls']['item']; $pconfig['a_certificates']=&$a_backend[$id]['ha_certificates']['item']; $pconfig['clientcert_ca']=&$a_backend[$id]['clientcert_ca']['item']; $pconfig['clientcert_crl']=&$a_backend[$id]['clientcert_crl']['item']; $pconfig['a_extaddr']=&$a_backend[$id]['a_extaddr']['item']; + $pconfig['a_actionitems']=&$a_backend[$id]['a_actionitems']['item']; + $pconfig['a_errorfiles']=&$a_backend[$id]['a_errorfiles']['item']; + $pconfig['advanced'] = base64_decode($a_backend[$id]['advanced']); foreach($simplefields as $stat) $pconfig[$stat] = $a_backend[$id][$stat]; @@ -243,20 +331,23 @@ if ($_POST) { if (($_POST['name'] == $config['installedpackages']['haproxy']['ha_backends']['item'][$i]['name']) && ($i != $id)) $input_errors[] = "This frontend name has already been used. Frontend names must be unique. $i != $id"; - $a_certificates = haproxy_htmllist_get_values($fields_sslCertificates); + $a_actionitems = $htmllist_actions->haproxy_htmllist_get_values(); + $pconfig['a_actionitems'] = $a_actionitems; + $a_errorfiles = $errorfileslist->haproxy_htmllist_get_values(); + $pconfig['a_errorfiles'] = $a_errorfiles; + $a_certificates = $htmllist_sslCertificates->haproxy_htmllist_get_values(); $pconfig['a_certificates'] = $a_certificates; - $a_clientcert_ca = haproxy_htmllist_get_values($fields_caCertificates); + $a_clientcert_ca = $htmllist_caCertificates->haproxy_htmllist_get_values(); $pconfig['clientcert_ca'] = $a_clientcert_ca; - $a_clientcert_crl = haproxy_htmllist_get_values($fields_crlCertificates); + $a_clientcert_crl = $htmllist_crlCertificates->haproxy_htmllist_get_values(); $pconfig['clientcert_crl'] = $a_clientcert_crl; - $a_acl = haproxy_htmllist_get_values($fields_aclSelectionList); + $a_acl = $htmllist_acls->haproxy_htmllist_get_values(); $pconfig['a_acl'] = $a_acl; - $a_extaddr = haproxy_htmllist_get_values($fields_externalAddress); + $a_extaddr = $htmllist_extaddr->haproxy_htmllist_get_values(); $pconfig['a_extaddr'] = $a_extaddr; - foreach($a_acl as $acl) { $acl_name = $acl['name']; $acl_value = $acl['value']; @@ -311,6 +402,8 @@ if ($_POST) { $backend['clientcert_ca']['item'] = $a_clientcert_ca; $backend['clientcert_crl']['item'] = $a_clientcert_crl; $backend['a_extaddr']['item'] = $a_extaddr; + $backend['a_actionitems']['item'] = $a_actionitems; + $backend['a_errorfiles']['item'] = $a_errorfiles; if (isset($id) && $a_backend[$id]) { $a_backend[$id] = $backend; @@ -328,13 +421,10 @@ if ($_POST) { } } -$pf_version=substr(trim(file_get_contents("/etc/version")),0,3); -if ($pf_version < 2.0) - $one_two = true; - $closehead = false; $pgtitle = "HAProxy: Frontend: Edit"; include("head.inc"); +haproxy_css(); if (!isset($_GET['dup'])) $excludefrontend = $pconfig['name']; @@ -353,50 +443,28 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); </head> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> -<?php if($one_two): ?> -<script type="text/javascript" src="/javascript/scriptaculous/prototype.js"></script> -<script type="text/javascript" src="/javascript/scriptaculous/scriptaculous.js"></script> -<?php endif; ?> - <script type="text/javascript"> - function htmllist_get_select_options(tableId, fieldname) { - var seltext; - seltext = ""; - var type; - var secondary = d.getElementById("secondary"); - var primary_frontend = d.getElementById("primary_frontend"); - if ((secondary !== null) && (secondary.checked)) - type = primaryfrontends[primary_frontend.value]['ref']['type']; - else - type = d.getElementById("type").value; - - if (tableId == 'tableA_acltable'){ - if (type == 'health') - seltext = "<?php echo haproxy_js_acl_select('health');?>"; - else if (type == 'tcp') - seltext = "<?php echo haproxy_js_acl_select('tcp');?>"; - else if (type == 'https') - seltext = "<?php echo haproxy_js_acl_select('https');?>"; + function htmllist_get_select_options(tableId, fieldname, itemstable) { + if (tableId == 'table_acls' && fieldname == 'expression') { + var type; + var secondary = d.getElementById("secondary"); + var primary_frontend = d.getElementById("primary_frontend"); + if ((secondary !== null) && (secondary.checked)) + type = primaryfrontends[primary_frontend.value]['ref']['type']; else - seltext = "<?php echo haproxy_js_acl_select('http');?>"; - if (seltext == '') { - alert("No ACL types available in current frontend type"); - return; + type = d.getElementById("type").value; + + result = Object.create(null); + for (var key in itemstable) { + newitem = itemstable[key]; + if (newitem['mode'] == type || newitem['mode'] == "") { + result[key] = newitem; + result[key]['name'] = result[key]['name']; + } } + return result; } - if (tableId == 'tableA_sslCertificates'){ - seltext = "<?=haproxy_js_select_options($servercerts);?>"; - } - if (tableId == 'table_clientcert_ca'){ - seltext = "<?=haproxy_js_select_options($certs_ca);?>"; - } - if (tableId == 'table_clientcert_crl'){ - seltext = "<?=haproxy_js_select_options($certs_crl);?>"; - } - if (tableId == 'table_extaddr'){ - seltext = "<?=haproxy_js_select_options($interfaces);?>"; - } - return seltext; + return itemstable; } function setCSSdisplay(cssID, display) { @@ -430,7 +498,7 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); } else { type = d.getElementById("type").value; for (i = 0; i < 99; i++) { - customEdit = document.getElementById("extaddr_ssl"+i); + customEdit = document.getElementById("table_extaddr"+"extaddr_ssl"+i); if (customEdit && customEdit.checked) sslshow = true; } @@ -462,47 +530,31 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); d = document; for (i = 0; i < 99; i++) { - el = d.getElementById("acl_expression" + i); - row = d.getElementById("aclrow" + i); - if (!el) - continue; - for (j = 0; j < count; j++) { - if (acl[j] == el.value) { - if (mode[j] != '' && mode[j] != type) { - Effect.Fade(row,{ duration: 1.0 }); - } else { - Effect.Appear(row,{ duration: 1.0 }); - } - } - } - } - - for (i = 0; i < 99; i++) { - el = d.getElementById("expression" + i); - //row_v = d.getElementById("tr_view_" + i); + el = d.getElementById("table_acls" + "expression" + i); row_e = d.getElementById("tr_edit_" + i); - if (!el) + row_v = d.getElementById("tr_viewdetail_" + i); + if (!el || !row_e) continue; for (j = 0; j < count; j++) { if (acl[j] == el.value) { if (mode[j] != '' && mode[j] != type) { - //Effect.Fade(row_v,{ duration: 1.0 }); Effect.Fade(row_e,{ duration: 1.0 }); + if (row_v) { + Effect.Fade(row_v,{ duration: 1.0 }); + } } else { - //Effect.Appear(row_v,{ duration: 1.0 }); Effect.Appear(row_e,{ duration: 1.0 }); + if (row_v) { + Effect.Appear(row_v,{ duration: 1.0 }); + } } } } } - } </script> <?php include("fbegin.inc"); ?> <?php if ($input_errors) print_input_errors($input_errors); ?> -<?php if($one_two): ?> -<p class="pgtitle"><?=$pgtitle?></p> -<?php endif; ?> <form action="haproxy_listeners_edit.php" method="post" name="iform" id="iform"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr><td class="tabnavtbl"> @@ -566,21 +618,19 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); <? $counter=0; $a_extaddr = $pconfig['a_extaddr']; - $htmllist_extadd = new HaproxyHtmlList("table_extaddr", $fields_externalAddress); - $htmllist_extadd->editmode = true; - $htmllist_extadd->Draw($a_extaddr); + $htmllist_extaddr->Draw($a_extaddr); ?> <script type="text/javascript"> - function table_extaddr_row_added(tableid, rowid){ - new AutoSuggestControl(document.getElementById("extaddr_custom"+rowid), new StateSuggestions(address_array)); - new AutoSuggestControl(document.getElementById("extaddr_port"+rowid), new StateSuggestions(port_array)); - table_extaddr_listitem_change(tableid,"",rowid, null);//disables address when not set to custom. + function table_extaddr_row_added(tableId, rowId){ + new AutoSuggestControl(document.getElementById(tableId+"extaddr_custom"+rowId), new StateSuggestions(address_array)); + new AutoSuggestControl(document.getElementById(tableId+"extaddr_port"+rowId), new StateSuggestions(port_array)); + table_extaddr_listitem_change(tableId,"",rowId, null);//disables address when not set to custom. } function table_extaddr_listitem_change(tableId, fieldId, rowNr, field) { if (fieldId == "extaddr" || fieldId == "") { - field = field || document.getElementById("extaddr"+rowNr); - customEdit = document.getElementById("extaddr_custom"+rowNr); + field = field || document.getElementById(tableId+"extaddr"+rowNr); + customEdit = document.getElementById(tableId+"extaddr_custom"+rowNr); customdisabled = field.value == "custom" ? 0 : 1; customEdit.disabled = customdisabled; } @@ -607,23 +657,6 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); <input name="max_connections" type="text" <?if(isset($pconfig['max_connections'])) echo "value=\"{$pconfig['max_connections']}\"";?> size="10" maxlength="10" /> </td> </tr> - <tr> - <td width="22%" valign="top" class="vncellreq">Backend server pool</td> - <td width="78%" class="vtable"> - - <select id="backend_serverpool" name="backend_serverpool" class="formfld"> - <?php - if (is_array($a_pools)) { - foreach ($a_pools as $p) { - $selected = $p['name'] == $pconfig['backend_serverpool'] ? 'selected' : ''; - $name = htmlspecialchars("{$p['name']}"); - echo "<option value=\"{$p['name']}\" $selected>$name</option>"; - } - } else { - echo "<option value=\"-\">-</option>"; - } - ?> - </select> <tr class="haproxy_primary" align="left"> <td width="22%" valign="top" class="vncellreq">Type</td> <td width="78%" class="vtable" colspan="2"> @@ -644,11 +677,74 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); <td width="78%" class="vtable" colspan="2" valign="top"> <? $a_acl = $pconfig['a_acl']; - haproxy_htmllist("tableA_acltable", $a_acl, $fields_aclSelectionList, true); + $htmllist_acls->Draw($a_acl); ?> <br/> - acl's with the same name wil be 'combined', acl's with different names will be evaluated seperately.<br/> - For more information about ACL's please see <a href='http://haproxy.1wt.eu/download/1.5/doc/configuration.txt' target='_blank'>HAProxy Documentation</a> Section 7 - Using ACL's + Example: + <table border='1' style='border-collapse:collapse'> + <tr> + <td><b>Name</b></td> + <td><b>Expression</b></td> + <td><b>Not</b></td> + <td><b>Value</b></td> + </tr> + <tr> + <td>Backend1acl</td> + <td>Host matches</td> + <td></td> + <td>www.yourdomain.tld</td> + </tr> + <tr> + <td>addHeaderAcl</td> + <td>SSL Client certificate valid</td> + <td></td> + <td></td> + </tr> + </table> + <br/> + acl's with the same name will be 'combined' using OR criteria.<br/> + For more information about ACL's please see <a href='http://haproxy.1wt.eu/download/1.5/doc/configuration.txt' target='_blank'>HAProxy Documentation</a> Section 7 - Using ACL's<br/><br/> + <strong>NOTE Important change in behaviour, since package version 0.32</strong><br/> + -acl's are no longer combined with logical AND operators, list multiple acl's below where needed.<br/> + -acl's alone no longer implicitly generate use_backend configuration. Add 'actions' below to accomplish this behaviour. + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncellreq">Actions</td> + <td width="78%" class="vtable" colspan="2" valign="top"> + <? + $a_actionitems = $pconfig['a_actionitems']; + $htmllist_actions->Draw($a_actionitems); + ?> + <br/> + Example: + <table border='1' style='border-collapse:collapse'> + <tr> + <td><b>Action</b></td> + <td><b>Parameters</b></td> + <td><b>Condition</b></td> + </tr> + <tr> + <td>Use Backend</td> + <td>Website1Backend</td> + <td>Backend1acl</td> + </tr> + <tr> + <td>http-request header set</td> + <td>Headername: X-HEADER-ClientCertValid<br/>New logformat value: YES</td> + <td>addHeaderAcl</td> + </tr> + </table> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncellreq">Default Backend</td> + <td width="78%" class="vtable"> + <?php + $listitem_none['']['name']="None"; + $backends = $listitem_none + $backends; + echo_html_select("backend_serverpool", $backends, $pconfig['backend_serverpool'] ? $pconfig['backend_serverpool'] : "none", "", "updatevisibility();"); + ?> </td> </tr> <tr class="haproxy_primary"><td> </td></tr> @@ -704,6 +800,23 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); address and ports. In http mode also the HTTP request and captured headers and cookies will be logged.</div> </td> </tr> + <tr><td> </td></tr> + <tr> + <td colspan="2" valign="top" class="listtopic">Error files</td> + </tr> + <tr class="" align="left" id='errorfiles'> + <td colspan="2" valign="top" class="vtable"> + Use these to replace the error pages that haproxy can generate by custom pages created on the files tab. + For example haproxy will generate a 503 error page when no backend is available, you can replace that page here. + <br/> + <br/> + <? + $a_errorfiles = $pconfig['a_errorfiles']; + $errorfileslist->Draw($a_errorfiles); + ?> + </td> + </tr> + <tr><td> </td></tr> </table> <br/> <br/> <table class="haproxy_primary" width="100%" border="0" cellpadding="6" cellspacing="0"> @@ -785,6 +898,7 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); Choose the cert to use on this frontend. <br/> <input id="ssloffloadacl" name="ssloffloadacl" type="checkbox" value="yes" <?php if ($pconfig['ssloffloadacl']=='yes') echo "checked";?> onclick="updatevisibility();" />Add ACL for certificate CommonName. (host header matches the 'CN' of the certificate)<br/> + <input id="ssloffloadacl_an" name="ssloffloadacl_an" type="checkbox" value="yes" <?php if ($pconfig['ssloffloadacl_an']=='yes') echo "checked";?> onclick="updatevisibility();" />Add ACL for certificate Subject Alternative Names.<br/> </td> </tr> <tr class="haproxy_ssloffloading_enabled" align="left"> @@ -799,10 +913,12 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); Which of these certificate will be send will be determined by haproxys SNI recognition. If the browser does not send SNI this will not work properly. (IE on XP is one example, possibly also older browsers or mobile devices) <? $a_certificates = $pconfig['a_certificates']; - haproxy_htmllist("tableA_sslCertificates", $a_certificates, $fields_sslCertificates); + //haproxy_htmllist("tableA_sslCertificates", $a_certificates, $fields_sslCertificates); + $htmllist_sslCertificates->Draw($a_certificates); ?> <br/> <input id="ssloffloadacladditional" name="ssloffloadacladditional" type="checkbox" value="yes" <?php if ($pconfig['ssloffloadacladditional']=='yes') echo "checked";?> onclick="updatevisibility();" />Add ACL for certificate CommonName. (host header matches the 'CN' of the certificate)<br/> + <input id="ssloffloadacladditional_an" name="ssloffloadacladditional_an" type="checkbox" value="yes" <?php if ($pconfig['ssloffloadacladditional_an']=='yes') echo "checked";?> onclick="updatevisibility();" />Add ACL for certificate Subject Alternative Names.<br/> </td> </tr> <tr class="haproxy_ssloffloading_enabled haproxy_primary" align="left"> @@ -843,7 +959,7 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); Client certificate will be verified against these CA certificates. <? $a_certificates = $pconfig['clientcert_ca']; - haproxy_htmllist("table_clientcert_ca", $a_certificates, $fields_caCertificates); + $htmllist_caCertificates->Draw($a_certificates); ?> </td> </tr> @@ -853,7 +969,7 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); Client certificate will be verified against these CRL revocation lists. <? $a_certificates = $pconfig['clientcert_crl']; - haproxy_htmllist("table_clientcert_crl", $a_certificates, $fields_crlCertificates); + $htmllist_crlCertificates->Draw($a_certificates); ?> </td> </tr> @@ -883,15 +999,26 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); <br/> <script type="text/javascript"> <? + // On gui descriptions when a closetype has been selected.. + phparray_to_javascriptarray($a_closetypes, "closetypes", Array('/*', '/*/name', '/*/descr')); + + // To find 'type' of frontend to show proper acl's ?? phparray_to_javascriptarray($primaryfrontends,"primaryfrontends",Array('/*', - '/*/name','/*/ref','/*/ref/type','/*/ref/a_extaddr','/*/ref/a_extaddr/item','/*/ref/a_extaddr/item/*', + '/*/name', '/*/ref', '/*/ref/type', '/*/ref/a_extaddr', '/*/ref/a_extaddr/item', '/*/ref/a_extaddr/item/*', '/*/ref/a_extaddr/item/*/extaddr_ssl')); - phparray_to_javascriptarray($a_closetypes,"closetypes",Array('/*','/*/name','/*/descr')); - phparray_to_javascriptarray($fields_sslCertificates,"fields_sslCertificates",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); - phparray_to_javascriptarray($fields_caCertificates,"fields_ca",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); - phparray_to_javascriptarray($fields_crlCertificates,"fields_crl",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); - phparray_to_javascriptarray($fields_aclSelectionList,"fields_acltable",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); - phparray_to_javascriptarray($fields_externalAddress,"fields_extaddr",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); + + phparray_to_javascriptarray($a_action, "showhide_actionfields", + Array('/*', '/*/fields', '/*/fields/*', '/*/fields/*/name')); + phparray_to_javascriptarray($a_acltypes, "showhide_aclfields", + Array('/*', '/*/fields', '/*/fields/*', '/*/fields/*/name')); + + $htmllist_extaddr->outputjavascript(); + $htmllist_acls->outputjavascript(); + $htmllist_actions->outputjavascript(); + $errorfileslist->outputjavascript(); + $htmllist_sslCertificates->outputjavascript(); + $htmllist_caCertificates->outputjavascript(); + $htmllist_crlCertificates->outputjavascript(); ?> </script> <script type="text/javascript"> @@ -902,12 +1029,64 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend); for(i=0;i < <?=count($a_extaddr)?>;i++){ - new AutoSuggestControl(document.getElementById('extaddr_custom'+i), new StateSuggestions(address_array)); - new AutoSuggestControl(document.getElementById('extaddr_port'+i), new StateSuggestions(port_array)); + new AutoSuggestControl(document.getElementById('table_extaddrextaddr_custom'+i), new StateSuggestions(address_array)); + new AutoSuggestControl(document.getElementById('table_extaddrextaddr_port'+i), new StateSuggestions(port_array)); // Initially set fields disabled where needed table_extaddr_listitem_change('table_extaddr','',i,null); } + function table_acls_listitem_change(tableId, fieldId, rowNr, field) { + if (fieldId = "toggle_details") { + fieldId = "expression"; + field = d.getElementById(tableId+"expression"+rowNr); + } + if (fieldId = "expression") { + var actiontype = field.value; + + var table = d.getElementById(tableId); + + for(var actionkey in showhide_aclfields) { + var fields = showhide_aclfields[actionkey]['fields']; + for(var fieldkey in fields){ + var fieldname = fields[fieldkey]['name']; + var rowid = "tr_edititemdetails_"+rowNr+"_"+actionkey+fieldname; + var element = d.getElementById(rowid); + + if (actionkey == actiontype) + element.style.display = ''; + else + element.style.display = 'none'; + } + } + } + } + + function table_actions_listitem_change(tableId, fieldId, rowNr, field) { + if (fieldId = "toggle_details") { + fieldId = "action"; + field = d.getElementById(tableId+"action"+rowNr); + } + if (fieldId = "action") { + var actiontype = field.value; + + var table = d.getElementById(tableId); + + for(var actionkey in showhide_actionfields) { + var fields = showhide_actionfields[actionkey]['fields']; + for(var fieldkey in fields){ + var fieldname = fields[fieldkey]['name']; + var rowid = "tr_edititemdetails_"+rowNr+"_"+actionkey+fieldname; + var element = d.getElementById(rowid); + + if (actionkey == actiontype) + element.style.display = ''; + else + element.style.display = 'none'; + } + } + } + } + updatevisibility(); </script> <?php diff --git a/config/haproxy-devel/www/haproxy_pool_edit.php b/config/haproxy-devel/www/haproxy_pool_edit.php index 6cd78741..71da9732 100644 --- a/config/haproxy-devel/www/haproxy_pool_edit.php +++ b/config/haproxy-devel/www/haproxy_pool_edit.php @@ -48,7 +48,7 @@ if (isset($_POST['id'])) $id = $_POST['id']; else $id = $_GET['id']; - + $tmp = get_backend_id($id); if (is_numeric($tmp)) $id = $tmp; @@ -58,7 +58,9 @@ if (isset($_GET['dup'])) global $simplefields; $simplefields = array( -"name","balance","transparent_clientip","transparent_interface", +"name", +"balance","balance_urilen","balance_uridepth","balance_uriwhole", +"transparent_clientip","transparent_interface", "check_type","checkinter","log-health-checks","httpcheck_method","monitor_uri","monitor_httpversion","monitor_username","monitor_domain","monitor_agentport", "agent_check","agent_port","agent_inter", "connection_timeout","server_timeout","retries", @@ -194,16 +196,131 @@ $fields_errorfile[1]['type']="select"; $fields_errorfile[1]['size']="170px"; $fields_errorfile[1]['items']=&$a_files; +$serverslist = new HaproxyHtmlList("tableA_servers", $fields_servers); +$serverslist->keyfield = "name"; +$serverslist->fields_details = $fields_servers_details; + +$errorfileslist = new HaproxyHtmlList("table_errorfile", $fields_errorfile); +$errorfileslist->keyfield = "errorcode"; + + + +$fields_aclSelectionList=array(); +$fields_aclSelectionList[0]['name']="name"; +$fields_aclSelectionList[0]['columnheader']="Name"; +$fields_aclSelectionList[0]['colwidth']="30%"; +$fields_aclSelectionList[0]['type']="textbox"; +$fields_aclSelectionList[0]['size']="20"; + +$fields_aclSelectionList[1]['name']="expression"; +$fields_aclSelectionList[1]['columnheader']="Expression"; +$fields_aclSelectionList[1]['colwidth']="30%"; +$fields_aclSelectionList[1]['type']="select"; +$fields_aclSelectionList[1]['size']="10"; +$fields_aclSelectionList[1]['items']=&$a_acltypes; + +$fields_aclSelectionList[2]['name']="not"; +$fields_aclSelectionList[2]['columnheader']="Not"; +$fields_aclSelectionList[2]['colwidth']="5%"; +$fields_aclSelectionList[2]['type']="checkbox"; +$fields_aclSelectionList[2]['size']="5"; + +$fields_aclSelectionList[3]['name']="value"; +$fields_aclSelectionList[3]['columnheader']="Value"; +$fields_aclSelectionList[3]['colwidth']="35%"; +$fields_aclSelectionList[3]['type']="textbox"; +$fields_aclSelectionList[3]['size']="35"; + +$fields_actions=array(); +$fields_actions[0]['name']="action"; +$fields_actions[0]['columnheader']="Action"; +$fields_actions[0]['colwidth']="30%"; +$fields_actions[0]['type']="select"; +$fields_actions[0]['size']="200px"; +$fields_actions[0]['items']=&$a_action; +$fields_actions[1]['name']="parameters"; +$fields_actions[1]['columnheader']="Parameters"; +$fields_actions[1]['colwidth']="30%"; +$fields_actions[1]['type']="fixedtext"; +$fields_actions[1]['size']="200px"; +$fields_actions[1]['text']="See below"; +$fields_actions[2]['name']="acl"; +$fields_actions[2]['columnheader']="Condition acl names"; +$fields_actions[2]['colwidth']="15%"; +$fields_actions[2]['type']="textbox"; +$fields_actions[2]['size']="40"; + + +$fields_actions_details=array(); +foreach($a_action as $key => $action) { + if (is_array($action['fields'])) { + foreach($action['fields'] as $field) { + $item = $field; + $name = $key . $item['name']; + $item['name'] = $name; + $item['columnheader'] = $field['name']; + $item['customdrawcell'] = customdrawcell_actions; + $fields_actions_details[$name] = $item; + } + } +} + +$a_acltypes["backendservercount"]['fields']['backend']['items'] = &$backends; +$fields_acl_details=array(); +foreach($a_acltypes as $key => $action) { + if (is_array($action['fields'])) { + foreach($action['fields'] as $field) { + $item = $field; + $name = $key . $item['name']; + $item['name'] = $name; + $item['columnheader'] = $field['name']; + $item['customdrawcell'] = customdrawcell_actions; + $fields_acl_details[$name] = $item; + } + } +} + +function customdrawcell_actions($object, $item, $itemvalue, $editable, $itemname, $counter) { + if ($editable) { + $object->haproxy_htmllist_drawcell($item, $itemvalue, $editable, $itemname, $counter); + } else { + //TODO hide fields not applicable.?. + echo $itemvalue; + } +} + +$htmllist_acls = new HaproxyHtmlList("table_acls", $fields_aclSelectionList); +$htmllist_acls->fields_details = $fields_acl_details; +$htmllist_acls->editmode = true; + +$htmllist_actions = new HaproxyHtmlList("table_actions", $fields_actions); +$htmllist_actions->fields_details = $fields_actions_details; +$htmllist_actions->keyfield = "name"; + + if (isset($id) && $a_pools[$id]) { + $pconfig['a_acl'] = &$a_pools[$id]['a_acl']['item']; + if (!is_array($pconfig['a_acl'])) { + $pconfig['a_acl'] = array(); + } + $pconfig['a_actionitems'] = &$a_pools[$id]['a_actionitems']['item']; + if (!is_array($pconfig['a_actionitems'])) { + $pconfig['a_actionitems'] = array(); + } $pconfig['advanced'] = base64_decode($a_pools[$id]['advanced']); $pconfig['advanced_backend'] = base64_decode($a_pools[$id]['advanced_backend']); - $pconfig['a_servers']=&$a_pools[$id]['ha_servers']['item']; + + + $a_servers = &$a_pools[$id]['ha_servers']['item']; foreach($simplefields as $stat) $pconfig[$stat] = $a_pools[$id][$stat]; + $a_errorfiles = &$a_pools[$id]['errorfiles']['item']; - if (!is_array($a_errorfiles)) $a_errorfiles = array(); + if (!is_array($a_errorfiles)) { + $a_errorfiles = array(); + } } if (isset($_GET['dup'])) @@ -265,7 +382,9 @@ if ($_POST) { if (($_POST['name'] == $config['installedpackages']['haproxy']['ha_pools']['item'][$i]['name']) && ($i != $id)) $input_errors[] = "This pool name has already been used. Pool names must be unique."; - $a_servers = haproxy_htmllist_get_values(array_merge($fields_servers,$fields_servers_details)); + $pconfig['a_acl'] = $htmllist_acls->haproxy_htmllist_get_values(); + $pconfig['a_actionitems'] = $htmllist_actions->haproxy_htmllist_get_values(); + $a_servers = $serverslist->haproxy_htmllist_get_values(); foreach($a_servers as $server){ $server_name = $server['name']; $server_address = $server['address']; @@ -294,66 +413,75 @@ if ($_POST) { $input_errors[] = "The field 'Port' value is not a number."; } - $a_errorfiles = haproxy_htmllist_get_values($fields_errorfile); + $a_errorfiles = $errorfileslist->haproxy_htmllist_get_values(); if ($_POST['strict_transport_security'] !== "" && !is_numeric($_POST['strict_transport_security'])) $input_errors[] = "The field 'Strict-Transport-Security' is not empty or a number."; -// if (!$input_errors) { - $pool = array(); - if(isset($id) && $a_pools[$id]) - $pool = $a_pools[$id]; - - if ($pool['name'] != $_POST['name']) { - // name changed: - if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) { - $config['installedpackages']['haproxy']['ha_backends']['item'] = array(); - } - $a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item']; + $pool = array(); + if(isset($id) && $a_pools[$id]) + $pool = $a_pools[$id]; + + if (!empty($pool['name']) && ($pool['name'] != $_POST['name'])) { + //old $pool['name'] can be empty if a new or cloned item is saved, nothing should be renamed then + // name changed: + $oldvalue = $pool['name']; + $newvalue = $_POST['name']; + + $a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item']; + if (!is_array($a_backend)) { + $a_backend = array(); + } - for ( $i = 0; $i < count($a_backend); $i++) { - if ($a_backend[$i]['backend_serverpool'] == $pool['name']) - $a_backend[$i]['backend_serverpool'] = $_POST['name']; + for ( $i = 0; $i < count($a_backend); $i++) { + $backend = &$a_backend[$i]; + if ($a_backend[$i]['backend_serverpool'] == $oldvalue) { + $a_backend[$i]['backend_serverpool'] = $newvalue; + } + if (is_array($backend['a_actionitems']['item'])) { + foreach($backend['a_actionitems']['item'] as &$item) { + if ($item['action'] == "use_backend") { + if ($item['use_backendbackend'] == $oldvalue) { + $item['use_backendbackend'] = $newvalue; + } + } + } } } + } - if($pool['name'] != "") - $changedesc .= " modified pool: '{$pool['name']}'"; + if($pool['name'] != "") + $changedesc .= " modified pool: '{$pool['name']}'"; + $pool['ha_servers']['item'] = $a_servers; + $pool['a_acl']['item'] = $pconfig['a_acl']; + $pool['a_actionitems']['item'] = $pconfig['a_actionitems']; - $pool['ha_servers']['item']=$a_servers; + update_if_changed("advanced", $pool['advanced'], base64_encode($_POST['advanced'])); + update_if_changed("advanced_backend", $pool['advanced_backend'], base64_encode($_POST['advanced_backend'])); - update_if_changed("advanced", $pool['advanced'], base64_encode($_POST['advanced'])); - update_if_changed("advanced_backend", $pool['advanced_backend'], base64_encode($_POST['advanced_backend'])); + global $simplefields; + foreach($simplefields as $stat) + update_if_changed($stat, $pool[$stat], $_POST[$stat]); - global $simplefields; - foreach($simplefields as $stat) - update_if_changed($stat, $pool[$stat], $_POST[$stat]); - - if (isset($id) && $a_pools[$id]) { - $a_pools[$id] = $pool; - } else { - $a_pools[] = $pool; - } + if (isset($id) && $a_pools[$id]) { + $a_pools[$id] = $pool; + } else { + $a_pools[] = $pool; + } if (!isset($input_errors)) { if ($changecount > 0) { touch($d_haproxyconfdirty_path); - write_config($changedesc); - /* - echo "<PRE>"; - print_r($config); - echo "</PRE>"; - */ + write_config($changedesc); } - header("Location: haproxy_pools.php"); exit; } - $pconfig['a_servers']=&$a_pools[$id]['ha_servers']['item']; } $closehead = false; $pgtitle = "HAProxy: Backend server pool: Edit"; include("head.inc"); +haproxy_css(); // 'processing' done, make all simple fields usable in html. foreach($simplefields as $field){ @@ -379,16 +507,6 @@ foreach($simplefields as $field){ </head> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <script type="text/javascript"> - function htmllist_get_select_options(tableId, fieldname) { - if (fieldname == 'forwardto') - return "<?=haproxy_js_select_options($primaryfrontends);?>"; - else - if (fieldname == 'errorfile') - return "<?=haproxy_js_select_options($a_files);?>"; - else - return "<?=haproxy_js_select_options($a_servermodes);?>"; - } - function clearcombo(){ for (var i=document.iform.serversSelect.options.length-1; i>=0; i--){ document.iform.serversSelect.options[i] = null; @@ -498,8 +616,7 @@ foreach($simplefields as $field){ </span> <? $counter=0; - $a_servers = $pconfig['a_servers']; - haproxy_htmllist("tableA_servers", $a_servers, $fields_servers, null, $fields_servers_details); + $serverslist->Draw($a_servers); ?> <table class="haproxy_help_serverlist" style="border:1px dashed green" cellspacing="0"> <tr><td class="vncell"> @@ -528,66 +645,104 @@ foreach($simplefields as $field){ <tr align="left"> <td width="22%" valign="top" class="vncellreq">Balance</td> <td width="78%" class="vtable" colspan="1"> - <table width="100%"> + <table width="100%" cellspacing="0"> <tr> - <td width="25%" valign="top"> + <td class="vncell" width="25%" valign="top"> + <input type="radio" name="balance" value=""<?php if(empty($pconfig['balance'])) echo " CHECKED"; ?> />None + </td> + <td class="vncell"> + This allows writing your own custom balance settings into the advanced section. + Or when you have no need for balancing with only 1 server. + </td> + </tr> + <tr> + <td class="vncell" width="25%" valign="top"> <input type="radio" name="balance" value="roundrobin"<?php if($pconfig['balance'] == "roundrobin") echo " CHECKED"; ?> />Round robin </td> - <td> - Each server is used in turns, according to their weights. - This is the smoothest and fairest algorithm when the server's - processing time remains equally distributed. This algorithm - is dynamic, which means that server weights may be adjusted - on the fly for slow starts for instance. + <td class="vncell"> + Each server is used in turns, according to their weights. + This is the smoothest and fairest algorithm when the server's + processing time remains equally distributed. This algorithm + is dynamic, which means that server weights may be adjusted + on the fly for slow starts for instance. </td> </tr> <tr> - <td width="25%" valign="top"> + <td class="vncell" width="25%" valign="top"> <input type="radio" name="balance" value="static-rr"<?php if($pconfig['balance'] == "static-rr") echo " CHECKED"; ?> />Static Round Robin </td> - <td> + <td class="vncell"> Each server is used in turns, according to their weights. - This algorithm is as similar to roundrobin except that it is - static, which means that changing a server's weight on the - fly will have no effect. On the other hand, it has no design - limitation on the number of servers, and when a server goes - up, it is always immediately reintroduced into the farm, once - the full map is recomputed. It also uses slightly less CPU to - run (around -1%). + This algorithm is as similar to roundrobin except that it is + static, which means that changing a server's weight on the + fly will have no effect. On the other hand, it has no design + limitation on the number of servers, and when a server goes + up, it is always immediately reintroduced into the farm, once + the full map is recomputed. It also uses slightly less CPU to + run (around -1%). </td> </tr> <tr> - <td width="25%" valign="top"> + <td class="vncell" width="25%" valign="top"> <input type="radio" name="balance" value="leastconn"<?php if($pconfig['balance'] == "leastconn") echo " CHECKED"; ?> />Least Connections </td> - <td> - The server with the lowest number of connections receives the - connection. Round-robin is performed within groups of servers - of the same load to ensure that all servers will be used. Use - of this algorithm is recommended where very long sessions are - expected, such as LDAP, SQL, TSE, etc... but is not very well - suited for protocols using short sessions such as HTTP. This - algorithm is dynamic, which means that server weights may be - adjusted on the fly for slow starts for instance. + <td class="vncell"> + The server with the lowest number of connections receives the + connection. Round-robin is performed within groups of servers + of the same load to ensure that all servers will be used. Use + of this algorithm is recommended where very long sessions are + expected, such as LDAP, SQL, TSE, etc... but is not very well + suited for protocols using short sessions such as HTTP. This + algorithm is dynamic, which means that server weights may be + adjusted on the fly for slow starts for instance. + </td> + </tr> + <tr> + <td class="vncell" valign="top"> + <input type="radio" name="balance" value="source"<?php if($pconfig['balance'] == "source") echo " CHECKED"; ?> />Source + </td> + <td class="vncell"> + The source IP address is hashed and divided by the total + weight of the running servers to designate which server will + receive the request. This ensures that the same client IP + address will always reach the same server as long as no + server goes down or up. If the hash result changes due to the + number of running servers changing, many clients will be + directed to a different server. This algorithm is generally + used in TCP mode where no cookie may be inserted. It may also + be used on the Internet to provide a best-effort stickyness + to clients which refuse session cookies. This algorithm is + static, which means that changing a server's weight on the + fly will have no effect. </td> </tr> - <tr><td valign="top"><input type="radio" name="balance" value="source"<?php if($pconfig['balance'] == "source") echo " CHECKED"; ?> />Source - </td> - <td> - The source IP address is hashed and divided by the total - weight of the running servers to designate which server will - receive the request. This ensures that the same client IP - address will always reach the same server as long as no - server goes down or up. If the hash result changes due to the - number of running servers changing, many clients will be - directed to a different server. This algorithm is generally - used in TCP mode where no cookie may be inserted. It may also - be used on the Internet to provide a best-effort stickyness - to clients which refuse session cookies. This algorithm is - static, which means that changing a server's weight on the - fly will have no effect. + <tr> + <td class="vncell" valign="top"> + <input type="radio" name="balance" value="uri"<?php if($pconfig['balance'] == "uri") echo " CHECKED"; ?> />Uri (HTTP backends only) + </td> + <td class="vncell"> + This algorithm hashes either the left part of the URI (before + the question mark) or the whole URI (if the "whole" parameter + is present) and divides the hash value by the total weight of + the running servers. The result designates which server will + receive the request. This ensures that the same URI will + always be directed to the same server as long as no server + goes up or down. This is used with proxy caches and + anti-virus proxies in order to maximize the cache hit rate. + Note that this algorithm may only be used in an HTTP backend.<br/> + <input name="balance_urilen" size="10" value="<?=$pconfig['balance_urilen']?>" />Len (optional) <br/> + The "len" parameter + indicates that the algorithm should only consider that many + characters at the beginning of the URI to compute the hash.<br/> + <input name="balance_uridepth" size="10" value="<?=$pconfig['balance_uridepth']?>" />Depth (optional) <br/> + The "depth" parameter indicates the maximum directory depth + to be used to compute the hash. One level is counted for each + slash in the request.<br/> + <input id="balance_uriwhole" name="balance_uriwhole" type="checkbox" value="yes" <?php if ($pconfig['balance_uriwhole']=='yes') echo "checked"; ?> /> + Allow using whole URI including url parameters behind a question mark. </td> </tr> + <!-- TODO add some other balance methods --> </table> </td> </tr> @@ -636,6 +791,71 @@ foreach($simplefields as $field){ <br/> NOTE: paste text into this box that you would like to pass thru. Applied to the backend section. </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell">Access Control lists</td> + <td width="78%" class="vtable" colspan="2" valign="top"> + <? + $a_acl = $pconfig['a_acl']; + $htmllist_acls->Draw($a_acl); + ?> + <br/> + Example: + <table border='1' style='border-collapse:collapse'> + <tr> + <td><b>Name</b></td> + <td><b>Expression</b></td> + <td><b>Not</b></td> + <td><b>Value</b></td> + </tr> + <tr> + <td>Backend1acl</td> + <td>Host matches</td> + <td></td> + <td>www.yourdomain.tld</td> + </tr> + <tr> + <td>addHeaderAcl</td> + <td>SSL Client certificate valid</td> + <td></td> + <td></td> + </tr> + </table> + <br/> + acl's with the same name will be 'combined' using OR criteria.<br/> + For more information about ACL's please see <a href='http://haproxy.1wt.eu/download/1.5/doc/configuration.txt' target='_blank'>HAProxy Documentation</a> Section 7 - Using ACL's<br/><br/> + <strong>NOTE Important change in behaviour, since package version 0.32</strong><br/> + -acl's are no longer combined with logical AND operators, list multiple acl's below where needed.<br/> + -acl's alone no longer implicitly generate use_backend configuration. Add 'actions' below to accomplish this behaviour. + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncellreq">Actions</td> + <td width="78%" class="vtable" colspan="2" valign="top"> + <? + $a_actionitems = $pconfig['a_actionitems']; + $htmllist_actions->Draw($a_actionitems); + ?> + <br/> + Example: + <table border='1' style='border-collapse:collapse'> + <tr> + <td><b>Action</b></td> + <td><b>Parameters</b></td> + <td><b>Condition</b></td> + </tr> + <tr> + <td>Use Backend</td> + <td>Website1Backend</td> + <td>Backend1acl</td> + </tr> + <tr> + <td>http-request header set</td> + <td>Headername: X-HEADER-ClientCertValid<br/>New logformat value: YES</td> + <td>addHeaderAcl</td> + </tr> + </table> + </td> </tr> <tr><td> </td></tr> <tr> @@ -868,7 +1088,7 @@ set by the 'retries' parameter.</div> </td> </tr> <tr><td> </td></tr> - <? if (haproxy_verion() >= '1.6' ) { ?> + <? if (haproxy_version() >= '1.6' ) { ?> <tr> <td colspan="2" valign="top" class="listtopic">Email notifications</td> </tr> @@ -985,7 +1205,7 @@ set by the 'retries' parameter.</div> <br/> <br/> <? - haproxy_htmllist("table_errorfile", $a_errorfiles, $fields_errorfile); + $errorfileslist->Draw($a_errorfiles); ?> </td> </tr> @@ -1030,17 +1250,78 @@ set by the 'retries' parameter.</div> <br/> <script type="text/javascript"> <? - phparray_to_javascriptarray($fields_servers,"fields_servers",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); phparray_to_javascriptarray($fields_servers_details,"fields_details_servers",Array('/*','/*/name','/*/type')); - phparray_to_javascriptarray($fields_errorfile,"fields_errorfile",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name')); phparray_to_javascriptarray($a_checktypes,"checktypes",Array('/*','/*/name','/*/descr')); phparray_to_javascriptarray($a_cookiemode,"cookiemode",Array('/*','/*/name','/*/descr')); phparray_to_javascriptarray($a_sticky_type,"sticky_type",Array('/*','/*/descr','/*/cookiedescr')); - phparray_to_javascriptarray($a_files,"a_files",Array('/*','/*/name','/*/descr')); + //phparray_to_javascriptarray($a_files,"a_files",Array('/*','/*/name','/*/descr')); + + phparray_to_javascriptarray($a_action, "showhide_actionfields", + Array('/*', '/*/fields', '/*/fields/*', '/*/fields/*/name')); + phparray_to_javascriptarray($a_acltypes, "showhide_aclfields", + Array('/*', '/*/fields', '/*/fields/*', '/*/fields/*/name')); + + $serverslist->outputjavascript(); + $errorfileslist->outputjavascript(); + $htmllist_acls->outputjavascript(); + $htmllist_actions->outputjavascript(); ?> browser_InnerText_support = (document.getElementsByTagName("body")[0].innerText != undefined) ? true : false; - + totalrows = <?php echo $counter; ?>; + + function table_acls_listitem_change(tableId, fieldId, rowNr, field) { + if (fieldId = "toggle_details") { + fieldId = "expression"; + field = d.getElementById(tableId+"expression"+rowNr); + } + if (fieldId = "expression") { + var actiontype = field.value; + + var table = d.getElementById(tableId); + + for(var actionkey in showhide_aclfields) { + var fields = showhide_aclfields[actionkey]['fields']; + for(var fieldkey in fields){ + var fieldname = fields[fieldkey]['name']; + var rowid = "tr_edititemdetails_"+rowNr+"_"+actionkey+fieldname; + var element = d.getElementById(rowid); + + if (actionkey == actiontype) + element.style.display = ''; + else + element.style.display = 'none'; + } + } + } + } + + function table_actions_listitem_change(tableId, fieldId, rowNr, field) { + if (fieldId = "toggle_details") { + fieldId = "action"; + field = d.getElementById(tableId+"action"+rowNr); + } + if (fieldId = "action") { + var actiontype = field.value; + + var table = d.getElementById(tableId); + + for(var actionkey in showhide_actionfields) { + var fields = showhide_actionfields[actionkey]['fields']; + for(var fieldkey in fields){ + var fieldname = fields[fieldkey]['name']; + var rowid = "tr_edititemdetails_"+rowNr+"_"+actionkey+fieldname; + var element = d.getElementById(rowid); + + if (actionkey == actiontype) + element.style.display = ''; + else + element.style.display = 'none'; + } + } + } + } + updatevisibility(); </script> <?php diff --git a/config/haproxy-devel/www/haproxy_pools.php b/config/haproxy-devel/www/haproxy_pools.php index 92235933..d98c7f41 100644 --- a/config/haproxy-devel/www/haproxy_pools.php +++ b/config/haproxy-devel/www/haproxy_pools.php @@ -65,19 +65,13 @@ if ($_GET['act'] == "del") { exit; } -$pf_version=substr(trim(file_get_contents("/etc/version")),0,3); -if ($pf_version < 2.0) - $one_two = true; - $pgtitle = "Services: HAProxy: Backend server pools"; include("head.inc"); +haproxy_css(); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> -<?php if($one_two): ?> -<p class="pgtitle"><?=$pgtitle?></p> -<?php endif; ?> <form action="haproxy_pools.php" method="post"> <?php if ($input_errors) print_input_errors($input_errors); ?> <?php if ($savemsg) print_info_box($savemsg); ?> @@ -108,18 +102,31 @@ include("head.inc"); foreach ($a_pools as $pool){ $fe_list = ""; $sep = ""; - foreach ($a_backends as $backend) { - if($backend['backend_serverpool'] == $pool['name']) { - $fe_list .= $sep . $backend['name']; - $sep = ", "; - } + foreach ($a_backends as $frontend) { + $used = false; + if($frontend['backend_serverpool'] == $pool['name']) { + $used = true; + } + $actions = $frontend['a_actionitems']['item']; + if (is_array($actions)) { + foreach($actions as $action) { + if ($action["action"] == "use_backend" && $action['use_backendbackend'] == $pool['name']) { + $used = true; + } + } + } + if ($used) { + $fe_list .= $sep . $frontend['name']; + $sep = ", "; + } } $textgray = $fe_list == "" ? " gray" : ""; - if (is_array($pool['ha_servers'])) + if (is_array($pool['ha_servers'])) { $count = count($pool['ha_servers']['item']); - else - $count = 0; + } else { + $count = 0; + } ?> <tr class="<?=$textgray?>"> <td class="listlr" ondblclick="document.location='haproxy_pool_edit.php?id=<?=$i;?>';"> diff --git a/config/haproxy-devel/www/haproxy_stats.php b/config/haproxy-devel/www/haproxy_stats.php index 302793b6..628d0e5a 100644 --- a/config/haproxy-devel/www/haproxy_stats.php +++ b/config/haproxy-devel/www/haproxy_stats.php @@ -68,7 +68,7 @@ if (isset($_GET['haproxystats']) || isset($_GET['scope']) || (isset($_POST) && i exit(0); } require_once("guiconfig.inc"); -if (isset($_GET['showsticktablecontent'])){ +if (isset($_GET['showsticktablecontent']) || isset($_GET['showstatresolvers'])) { if (is_numeric($pconfig['localstats_sticktable_refreshtime'])) header("Refresh: {$pconfig['localstats_sticktable_refreshtime']}"); } @@ -91,10 +91,6 @@ if ($_POST) { } } -$pf_version=substr(trim(file_get_contents("/etc/version")),0,3); -if ($pf_version < 2.0) - $one_two = true; - $pgtitle = "Services: HAProxy: Stats"; include("head.inc"); @@ -102,9 +98,6 @@ include("head.inc"); <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> <form action="haproxy_stats.php" method="post"> -<?php if($one_two): ?> -<p class="pgtitle"><?=$pgtitle?></p> -<?php endif; ?> <?php if ($input_errors) print_input_errors($input_errors); ?> <?php if ($savemsg) print_info_box($savemsg); ?> <?php if (file_exists($d_haproxyconfdirty_path)): ?> @@ -123,15 +116,25 @@ include("head.inc"); <table class="tabcont" width="100%" height="100%" cellspacing="0"> <tr> <? -if (isset($_GET['showsticktablecontent'])){ + +if (isset($_GET['showstatresolvers'])){ + $showstatresolversname = $_GET['showstatresolvers']; + echo "<td colspan='2'>"; + echo "Contents of the sticktable: $sticktablename<br/>"; + $res = haproxy_socket_command("show stat resolvers $showstatresolversname"); + foreach($res as $line){ + echo "<br/>".print_r($line,true); + } + echo "</td>"; +} elseif (isset($_GET['showsticktablecontent'])){ $sticktablename = $_GET['showsticktablecontent']; -echo "<td colspan='2'>"; + echo "<td colspan='2'>"; echo "Contents of the sticktable: $sticktablename<br/>"; $res = haproxy_socket_command("show table $sticktablename"); foreach($res as $line){ echo "<br/>".print_r($line,true); } -echo "</td>"; + echo "</td>"; } else { ?> <td colspan="2"> @@ -177,6 +180,15 @@ echo "</td>"; <td> </td> </tr> <tr> + <td colspan="2" valign="top" class="listtopic">HAProxy DNS</td> + </tr> + <tr> + <td colspan="2" valign="top" class="vncell"><a href="/haproxy_stats.php?showstatresolvers=globalresolvers" target="_blank">DNS statistics</a></td> + </tr> + <tr> + <td> </td> + </tr> + <tr> <td colspan="2" valign="top" class="listtopic">HAProxy stats</td> </tr> <tr> diff --git a/config/haproxy-devel/www/haproxy_templates.php b/config/haproxy-devel/www/haproxy_templates.php index 478c83a3..072df508 100644 --- a/config/haproxy-devel/www/haproxy_templates.php +++ b/config/haproxy-devel/www/haproxy_templates.php @@ -114,6 +114,7 @@ EOD; $savemsg = "File 'ExampleErrorfile' is already configured on the Files tab."; } + $changedesc = "haproxy, add template errorfile"; if ($changecount > 0) { header("Location: haproxy_files.php"); echo "touching: $d_haproxyconfdirty_path"; @@ -122,7 +123,83 @@ EOD; exit; } } + +function haproxy_template_multipledomains() { + global $config, $d_haproxyconfdirty_path; + $a_backends = &$config['installedpackages']['haproxy']['ha_pools']['item']; + $a_frontends = &$config['installedpackages']['haproxy']['ha_backends']['item']; + + $backend = array(); + $backend["name"] = "example_backend1"; + $backend["stats_enabled"] = "yes"; + $backend["stats_uri"] = "/"; + $backend["stats_refresh"] = "10"; + $backend["stats_scope"] = "."; + $backend["stats_node"] = "NODE1"; + $a_backends[] = $backend; + + $backend = array(); + $backend["name"] = "example_backend2"; + $backend["stats_enabled"] = "yes"; + $backend["stats_uri"] = "/"; + $backend["stats_refresh"] = "10"; + $backend["stats_scope"] = "."; + $backend["stats_node"] = "NODE2"; + $a_backends[] = $backend; + + $backend = array(); + $backend["name"] = "example_backend3"; + $backend["stats_enabled"] = "yes"; + $backend["stats_uri"] = "/"; + $backend["stats_refresh"] = "10"; + $backend["stats_scope"] = "."; + $backend["stats_node"] = "NODE3"; + $a_backends[] = $backend; + + $frontend = array(); + $frontend["name"] = "example_multipledomains"; + $frontend["status"] = "active"; + $frontend["type"] = "http"; + $frontend["a_extaddr"]["item"]["stats_name"]["extaddr"] = "wan_ipv4"; + $frontend["a_extaddr"]["item"]["stats_name"]["extaddr_port"] = "80"; + $frontend["backend_serverpool"] = "example_backend1"; + $acl = array(); + $acl["name"] = "mail_acl"; + $acl["expression"] = "host_matches"; + $acl["value"] = "mail.domain.tld"; + $frontend["ha_acls"]["item"][] = $acl; + $action = array(); + $action["action"] = "use_backend"; + $action["use_backendbackend"] = "example_backend2"; + $action["acl"] = "mail_acl"; + $frontend["a_actionitems"]["item"][] = $action; + $a_frontends[] = $frontend; + + $frontend = array(); + $frontend["name"] = "example_multipledomains_forum"; + $frontend["status"] = "active"; + $frontend["secondary"] = "yes"; + $frontend["primary_frontend"] = "example_multipledomains"; + $acl = array(); + $acl["name"] = "forum_acl"; + $acl["expression"] = "host_matches"; + $acl["value"] = "forum.domain.tld"; + $frontend["ha_acls"]["item"][] = $acl; + $action = array(); + $action["action"] = "use_backend"; + $action["use_backendbackend"] = "example_backend3"; + $action["acl"] = "forum_acl"; + $frontend["a_actionitems"]["item"][] = $action; + $a_frontends[] = $frontend; + $changedesc = "haproxy, add multi domain example"; + header("Location: haproxy_listeners.php"); + echo "touching: $d_haproxyconfdirty_path"; + touch($d_haproxyconfdirty_path); + write_config($changedesc); + exit; +} + if (isset($_GET['add_stats_example'])) { $templateid = $_GET['add_stats_example']; switch ($templateid) { @@ -132,6 +209,9 @@ if (isset($_GET['add_stats_example'])) { case "2": template_errorfile(); break; + case "3": + haproxy_template_multipledomains(); + break; } } @@ -145,14 +225,12 @@ if ($_POST) { $pgtitle = "Services: HAProxy: Templates"; include("head.inc"); +haproxy_css(); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> <form action="haproxy_templates.php" method="post"> -<?php if($one_two): ?> -<p class="pgtitle"><?=$pgtitle?></p> -<?php endif; ?> <?php if ($input_errors) print_input_errors($input_errors); ?> <?php if ($savemsg) print_info_box($savemsg); ?> <?php if (file_exists($d_haproxyconfdirty_path)): ?> @@ -179,6 +257,20 @@ include("head.inc"); <td> </td> </tr> <tr> + <td colspan="2" valign="top" class="listtopic">Serving multiple domains from 1 frontend.</td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"> + <a href="haproxy_templates.php?add_stats_example=3">Create configuration</a> + </td> + <td class="vtable"> + As an basic example of how to serve multiple domains on 1 listening ip:port. + </td> + </tr> + <tr> + <td> </td> + </tr> + <tr> <td colspan="2" valign="top" class="listtopic">Stats SSL frontent+backend</td> </tr> <tr> diff --git a/config/squid3/34/squid.inc b/config/squid3/34/squid.inc index 267305ce..973bbf05 100755 --- a/config/squid3/34/squid.inc +++ b/config/squid3/34/squid.inc @@ -452,9 +452,6 @@ function squid_restart_services() { function squid_install_command() { global $config, $g; - update_output_window("This operation may take quite some time, please be patient. Do not press stop or attempt to navigate away from this page during this process."); - update_output_window("Checking if there is configuration to migrate... One moment please..."); - /* Set storage system for nanobsd */ if (!is_array($config['installedpackages']['squidcache'])) { $config['installedpackages']['squidcache'] = array(); @@ -515,7 +512,6 @@ function squid_deinstall_command() { squid_install_cron(false); /* kill all running services */ - update_output_window("Stopping and removing services..."); mwexec('/usr/local/etc/rc.d/sqp_monitor.sh stop'); mwexec("/bin/ps awux | /usr/bin/egrep -i '[s]quid -f|\([s]quid\)' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); mwexec("/bin/ps awux | /usr/bin/grep '[d]iskd' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); @@ -542,8 +538,6 @@ function squid_deinstall_command() { $keep = ($squidsettings['keep_squid_data'] ? true : false); if (!$keep) { - update_output_window("Removing cache and logs ... One moment please..."); - update_output_window("This operation may take quite some time, please be patient. Do not press stop or attempt to navigate away from this page during this process."); if (is_dir("{$cachedir}")) { if (substr($cachedir, 0, 11) === "/var/squid/") { mwexec_bg("/bin/rm -rf {$cachedir}"); @@ -558,7 +552,6 @@ function squid_deinstall_command() { log_error("[squid] Will NOT delete Squid log dir '{$logdir}' since it is not located under /var/squid. Delete manually if required."); } } - update_output_window("Removing remaining Squid directories ... One moment please..."); $dirs = array("/var/run/squid", "/var/squid"); foreach ($dirs as $dir) { if (is_dir("{$dir}")) { @@ -570,7 +563,6 @@ function squid_deinstall_command() { // remove antivirus integration features squid_antivirus_deinstall_command(); - update_output_window("Reloading filter..."); filter_configure(); /* Remove package settings from config if 'Keep Settings/Data' is disabled */ @@ -619,7 +611,6 @@ function squid_deinstall_command() { unset($config['installedpackages']['squidusers']); } } - update_output_window("Squid3 has been uninstalled."); } /* Migrate configuration from god knows which Squid package versions */ @@ -704,7 +695,6 @@ function squid_upgrade_config() { /* unset broken antivirus settings */ squid_antivirus_upgrade_config(); - update_output_window("Writing configuration... One moment please..."); write_config(); } diff --git a/config/squid3/34/squid_antivirus.inc b/config/squid3/34/squid_antivirus.inc index 4dc2c89a..fe8406e7 100644 --- a/config/squid3/34/squid_antivirus.inc +++ b/config/squid3/34/squid_antivirus.inc @@ -169,7 +169,6 @@ function squid_antivirus_deinstall_command() { mwexec("/bin/ps awux | /usr/bin/grep '[f]reshclam' | /usr/bin/awk '{ print $2 }' | /usr/bin/xargs kill"); /* clean up created PBI symlinks */ - update_output_window("Finishing package cleanup."); if (SQUID_LOCALBASE != '/usr/local') { $ln_icap = array('bin/c-icap', 'bin/c-icap-client', 'c-icap-config', 'c-icap-libicapapi-config', 'c-icap-stretch', 'lib/c_icap', 'share/c_icap', 'etc/c-icap'); foreach ($ln_icap as $ln) { @@ -191,7 +190,6 @@ function squid_antivirus_deinstall_command() { $keep = ($squidsettings['keep_squid_data'] ? true : false); if (!$keep) { - update_output_window("Removing antivirus definitions and logs ... One moment please..."); $dirs = array("/var/run/c-icap", "/var/log/c-icap", "/var/log/clamav", "/var/run/clamav", "/var/db/clamav"); foreach ($dirs as $dir) { if (is_dir("{$dir}")) { @@ -218,7 +216,6 @@ function squid_antivirus_deinstall_command() { /* check if clamav/c_icap is enabled in rc.conf.local */ // XXX: This hasn't been used since 0.3.7; to be removed in future if (file_exists("/etc/rc.conf.local")) { - update_output_window("Removing antivirus services from /etc/rc.conf.local..."); $sample_file = file_get_contents("/etc/rc.conf.local"); $rcconf_local_m[0] = "@c_icap_enable(.*)\n@"; $rcconf_local_m[1] = "@clamav_clamd_enable(.*)\n@"; diff --git a/config/sshdcond/sshdcond.inc b/config/sshdcond/sshdcond.inc index 9c3a8bb9..7c1be614 100644 --- a/config/sshdcond/sshdcond.inc +++ b/config/sshdcond/sshdcond.inc @@ -37,8 +37,6 @@ function restart_sshd() { } function sshdcond_custom_php_install_command() { - global $g, $config; - /* We need to generate an outfile for our extra commands. The patched g_szSSHDFileGenerate php file then reads and appends that config. */ @@ -48,8 +46,6 @@ function sshdcond_custom_php_install_command() { } function sshdcond_custom_php_deinstall_command() { - global $g, $config; - /* Delete our config file. */ unlink_if_exists("/etc/ssh/sshd_extra"); @@ -59,7 +55,7 @@ function sshdcond_custom_php_deinstall_command() { } function sshdcond_custom_php_write_config() { - global $g, $config, $pkg_interface; + global $g, $config; /* Detect boot process, do nothing during boot. */ if (function_exists("platform_booting")) { @@ -113,71 +109,113 @@ function sshdcond_custom_php_write_config() { /* Uses XMLRPC to synchronize the changes to a remote node. */ function sshdcond_sync_on_changes() { - global $config, $g; - - /* Basically, this package was never configured */ - if (!is_array($config['installedpackages']['sshdcondsync'])) { - return; - } - /* Package is configured but XMLRPC sync is disabled */ - if (!isset($config['installedpackages']['sshdcondsync']['config'][0]['synconchanges'])) { - return; - } - /* Do XMLRPC sync */ - log_error("[sshdcond] xmlrpc sync is starting."); - foreach ($config['installedpackages']['sshdcondsync']['config'] as $rs) { - foreach($rs['row'] as $sh) { - $sync_to_ip = $sh['ipaddress']; - $password = $sh['password']; - if ($password && $sync_to_ip) { - sshdcond_do_xmlrpc_sync($sync_to_ip, $password); + global $config; + + if (is_array($config['installedpackages']['sshdcondsync']['config'])) { + $sshdcond_sync = $config['installedpackages']['sshdcondsync']['config'][0]; + $synconchanges = $sshdcond_sync['synconchanges']; + $synctimeout = $sshdcond_sync['synctimeout'] ?: '150'; + switch ($synconchanges) { + case "manual": + if (is_array($sshdcond_sync['row'])) { + $rs = $sshdcond_sync['row']; + } else { + log_error("[sshdcond] XMLRPC sync is enabled but there are no hosts configured as replication targets."); + return; + } + break; + case "auto": + if (is_array($config['hasync'])) { + $system_carp = $config['hasync']; + $rs[0]['ipaddress'] = $system_carp['synchronizetoip']; + $rs[0]['username'] = $system_carp['username']; + $rs[0]['password'] = $system_carp['password']; + $rs[0]['syncdestinenable'] = FALSE; + + // XMLRPC sync is currently only supported over connections using the same protocol and port as this system + if ($config['system']['webgui']['protocol'] == "http") { + $rs[0]['syncprotocol'] = "http"; + $rs[0]['syncport'] = $config['system']['webgui']['port'] ?: '80'; + } else { + $rs[0]['syncprotocol'] = "https"; + $rs[0]['syncport'] = $config['system']['webgui']['port'] ?: '443'; + } + if ($system_carp['synchronizetoip'] == "") { + log_error("[sshdcond] XMLRPC CARP/HA sync is enabled but there are no system backup hosts configured as replication targets."); + return; + } else { + $rs[0]['syncdestinenable'] = TRUE; + } + } else { + log_error("[sshdcond] XMLRPC CARP/HA sync is enabled but there are no system backup hosts configured as replication targets."); + return; + } + break; + default: + return; + break; + } + if (is_array($rs)) { + log_error("[sshdcond] XMLRPC sync is starting."); + foreach ($rs as $sh) { + // Only sync enabled replication targets + if ($sh['syncdestinenable']) { + $sync_to_ip = $sh['ipaddress']; + $port = $sh['syncport']; + $username = $sh['username'] ?: 'admin'; + $password = $sh['password']; + $protocol = $sh['syncprotocol']; + + $error = ''; + $valid = TRUE; + + if ($password == "") { + $error = "Password parameter is empty. "; + $valid = FALSE; + } + if (!is_ipaddr($sync_to_ip) && !is_hostname($sync_to_ip) && !is_domain($sync_to_ip)) { + $error .= "Misconfigured Replication Target IP Address or Hostname. "; + $valid = FALSE; + } + if (!is_port($port)) { + $error .= "Misconfigured Replication Target Port. "; + $valid = FALSE; + } + if ($valid) { + sshdcond_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout); + } else { + log_error("[sshdcond] XMLRPC sync with '{$sync_to_ip}' aborted due to the following error(s): {$error}"); + } + } } + log_error("[sshdcond] XMLRPC sync completed."); } - } - log_error("[sshdcond] xmlrpc sync is ending."); + } } /* Do the actual XMLRPC sync. */ -function sshdcond_do_xmlrpc_sync($sync_to_ip, $password) { +function sshdcond_do_xmlrpc_sync($sync_to_ip, $port, $protocol, $username, $password, $synctimeout) { global $config, $g; - if (!$password) { + if ($username == "" || $password == "" || $sync_to_ip == "" || $port == "" || $protocol == "") { + log_error("[sshdcond] A required XMLRPC sync parameter (username, password, replication target, port or protocol) is empty ... aborting pkg sync"); return; } - if (!$sync_to_ip) { - return; + // Take care of IPv6 literal address + if (is_ipaddrv6($sync_to_ip)) { + $sync_to_ip = "[{$sync_to_ip}]"; } - $username='admin'; - $xmlrpc_sync_neighbor = $sync_to_ip; - if ($config['system']['webgui']['protocol'] != "") { - $synchronizetoip = $config['system']['webgui']['protocol']; - $synchronizetoip .= "://"; - } - $port = $config['system']['webgui']['port']; - /* If port is empty, let's rely on the protocol selection. */ - if ($port == "") { - if ($config['system']['webgui']['protocol'] == "http") { - $port = "80"; - } else { - $port = "443"; - } - } - $synchronizetoip .= $sync_to_ip; + $url = "{$protocol}://{$sync_to_ip}"; - /* xml will hold the sections to sync. */ + /* XML will hold the sections to sync. */ $xml = array(); $xml['sshdcond'] = $config['installedpackages']['sshdcond']; /* Assemble XMLRPC payload. */ - $params = array( - XML_RPC_encode($password), - XML_RPC_encode($xml) - ); - - /* Set a few variables needed for sync code; borrowed from filter.inc. */ - $url = $synchronizetoip; - log_error("Beginning sshdcond XMLRPC sync to {$url}:{$port}."); + $params = array(XML_RPC_encode($password), XML_RPC_encode($xml)); + + /* Set a few variables needed for sync code */ $method = 'pfsense.merge_installedpackages_section_xmlrpc'; $msg = new XML_RPC_Message($method, $params); $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); @@ -185,20 +223,20 @@ function sshdcond_do_xmlrpc_sync($sync_to_ip, $password) { if ($g['debug']) { $cli->setDebug(1); } - /* Send our XMLRPC message and timeout after 250 seconds. */ - $resp = $cli->send($msg, "250"); + /* Send our XMLRPC message and timeout after defined sync timeout value */ + $resp = $cli->send($msg, $synctimeout); if (!$resp) { - $error = "A communications error occurred while attempting sshdcond XMLRPC sync with {$url}:{$port}."; - log_error($error); + $error = "A communications error occurred while attempting XMLRPC sync with {$url}:{$port}."; + log_error("[sshdcond] {$error}"); file_notice("sync_settings", $error, "sshdcond Settings Sync", ""); } elseif ($resp->faultCode()) { $cli->setDebug(1); - $resp = $cli->send($msg, "250"); + $resp = $cli->send($msg, $synctimeout); $error = "An error code was received while attempting sshdcond XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); - log_error($error); + log_error("[sshdcond] {$error}"); file_notice("sync_settings", $error, "sshdcond Settings Sync", ""); } else { - log_error("sshdcond XMLRPC sync successfully completed with {$url}:{$port}."); + log_error("[sshdcond] XMLRPC sync successfully completed with {$url}:{$port}."); } /* Tell sshdcond to reload our settings on the destination sync host. */ @@ -206,28 +244,24 @@ function sshdcond_do_xmlrpc_sync($sync_to_ip, $password) { $execcmd = "require_once('/usr/local/pkg/sshdcond.inc');\n"; $execcmd .= "sshdcond_custom_php_write_config();"; /* Assemble XMLRPC payload. */ - $params = array( - XML_RPC_encode($password), - XML_RPC_encode($execcmd) - ); + $params = array(XML_RPC_encode($password), XML_RPC_encode($execcmd)); - log_error("sshdcond XMLRPC reload data {$url}:{$port}."); $msg = new XML_RPC_Message($method, $params); $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); $cli->setCredentials($username, $password); - $resp = $cli->send($msg, "250"); + $resp = $cli->send($msg, $synctimeout); if (!$resp) { $error = "A communications error occurred while attempting sshdcond XMLRPC sync with {$url}:{$port} (pfsense.exec_php)."; - log_error($error); + log_error("[sshdcond] {$error}"); file_notice("sync_settings", $error, "sshdcond Settings Sync", ""); } elseif ($resp->faultCode()) { $cli->setDebug(1); - $resp = $cli->send($msg, "250"); + $resp = $cli->send($msg, $synctimeout); $error = "An error code was received while attempting sshdcond XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); - log_error($error); + log_error("[sshdcond] {$error}"); file_notice("sync_settings", $error, "sshdcond Settings Sync", ""); } else { - log_error("sshdcond XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php)."); + log_error("[sshdcond] XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php)."); } } ?> diff --git a/config/sshdcond/sshdcond.priv.inc b/config/sshdcond/sshdcond.priv.inc new file mode 100644 index 00000000..fddb86c1 --- /dev/null +++ b/config/sshdcond/sshdcond.priv.inc @@ -0,0 +1,42 @@ +<?php +/* + sshdcond.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-services-sshdcond'] = array(); +$priv_list['page-services-sshdcond']['name'] = "WebCfg - Services: SSHDCond package"; +$priv_list['page-services-sshdcond']['descr'] = "Allow access to SSHDCond package GUI"; +$priv_list['page-services-sshdcond']['match'] = array(); + +$priv_list['page-services-sshdcond']['match'][] = "pkg.php?xml=sshdcond.xml*"; +$priv_list['page-services-sshdcond']['match'][] = "pkg.php?xml=sshdcond_sync.xml*"; + +$priv_list['page-services-sshdcond']['match'][] = "pkg_edit.php?xml=sshdcond.xml*"; +$priv_list['page-services-sshdcond']['match'][] = "pkg_edit.php?xml=sshdcond_sync.xml*"; + +?> diff --git a/config/sshdcond/sshdcond.xml b/config/sshdcond/sshdcond.xml index 11104e1d..f0e27c80 100644 --- a/config/sshdcond/sshdcond.xml +++ b/config/sshdcond/sshdcond.xml @@ -43,12 +43,10 @@ ]]> </copyright> <name>sshdcond</name> - <version>1.0.2</version> - <title>SSH Conditional</title> - <description>SSH Conditional blocks</description> + <version>1.0.6</version> + <title>Services: SSH Conditional Options</title> <savetext>Save</savetext> <include_file>/usr/local/pkg/sshdcond.inc</include_file> - <menu> <name>SSH Conditions</name> <tooltiptext>Configure SSH conditional exceptions</tooltiptext> @@ -61,6 +59,10 @@ <item>https://packages.pfsense.org/packages/config/sshdcond/sshdcond.inc</item> </additional_files_needed> <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/sshdcond/sshdcond.priv.inc</item> + </additional_files_needed> + <additional_files_needed> <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/sshdcond/sshdcond_sync.xml</item> </additional_files_needed> @@ -93,7 +95,6 @@ <field> <type>listtopic</type> <name>Conditional SSH Options</name> - <fieldname>temp</fieldname> </field> <field> <fielddescr>Enable</fielddescr> @@ -187,7 +188,4 @@ <custom_php_resync_config_command> sshdcond_custom_php_write_config(); </custom_php_resync_config_command> - <custom_php_command_before_form> - unset($_POST['temp']); - </custom_php_command_before_form> </packagegui> diff --git a/config/sshdcond/sshdcond_sync.xml b/config/sshdcond/sshdcond_sync.xml index 511df25b..f81f36b0 100755 --- a/config/sshdcond/sshdcond_sync.xml +++ b/config/sshdcond/sshdcond_sync.xml @@ -42,8 +42,8 @@ ]]> </copyright> <name>sshdcondsync</name> - <version>1.0.2</version> - <title>SSH Conditional - Sync</title> + <version>1.0.6</version> + <title>Services: SSH Conditional Options - Sync</title> <include_file>/usr/local/pkg/sshdcond.inc</include_file> <tabs> <tab> @@ -62,30 +62,74 @@ <type>listtopic</type> </field> <field> - <fielddescr>Automatically sync configuration changes</fielddescr> + <fielddescr>Enable Sync</fielddescr> <fieldname>synconchanges</fieldname> - <description>Automatically sync changes to the hosts defined below.</description> - <type>checkbox</type> + <description> + <![CDATA[ + When enabled, this will sync all configuration settings to the Replication Targets.<br/><br/> + <b>Important:</b> While using "Sync to host(s) defined below", only sync from host A to B, A to C but <strong>do not</strong> enable XMLRPC sync <b>to</b> A. This will result in a loop! + ]]> + </description> + <type>select</type> + <required/> + <default_value>disabled</default_value> + <options> + <option><name>Sync to configured system backup server</name><value>auto</value></option> + <option><name>Sync to host(s) defined below</name><value>manual</value></option> + <option><name>Do not sync this package configuration</name><value>disabled</value></option> + </options> </field> <field> - <fielddescr>Remote Server</fielddescr> + <fielddescr>XMLRPC Timeout</fielddescr> + <fieldname>synctimeout</fieldname> + <description><![CDATA[XMLRPC timeout in seconds. Default: 150]]></description> + <type>input</type> + <default_value>150</default_value> + <size>5</size> + </field> + <field> + <fielddescr>Replication Targets</fielddescr> <fieldname>none</fieldname> <type>rowhelper</type> <rowhelper> - <rowhelperfield> - <fielddescr>IP Address</fielddescr> - <fieldname>ipaddress</fieldname> - <description>IP Address of remote server.</description> - <type>input</type> - <size>20</size> - </rowhelperfield> - <rowhelperfield> - <fielddescr>Password</fielddescr> - <fieldname>password</fieldname> - <description>Password for remote server.</description> - <type>password</type> - <size>20</size> - </rowhelperfield> + <rowhelperfield> + <fielddescr>Enable</fielddescr> + <fieldname>syncdestinenable</fieldname> + <description><![CDATA[Enable this host as a replication target]]></description> + <type>checkbox</type> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Protocol</fielddescr> + <fieldname>syncprotocol</fieldname> + <description><![CDATA[Choose the protocol used to sync with the destination host (HTTP or HTTPS).]]></description> + <type>select</type> + <default_value>HTTP</default_value> + <options> + <option><name>HTTP</name><value>http</value></option> + <option><name>HTTPS</name><value>https</value></option> + </options> + </rowhelperfield> + <rowhelperfield> + <fielddescr>IP Address/Hostname</fielddescr> + <fieldname>ipaddress</fieldname> + <description><![CDATA[IP address or hostname of the destination host.]]></description> + <type>input</type> + <size>40</size> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Port</fielddescr> + <fieldname>syncport</fieldname> + <description><![CDATA[Choose the sync port of the destination host.]]></description> + <type>input</type> + <size>3</size> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Admin Password</fielddescr> + <fieldname>password</fieldname> + <description><![CDATA[Password of the user "admin" on the destination host.]]></description> + <type>password</type> + <size>20</size> + </rowhelperfield> </rowhelper> </field> </fields> diff --git a/config/stunnel/stunnel.priv.inc b/config/stunnel/stunnel.priv.inc new file mode 100644 index 00000000..f9857583 --- /dev/null +++ b/config/stunnel/stunnel.priv.inc @@ -0,0 +1,42 @@ +<?php +/* + stunnel.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-services-stunnel'] = array(); +$priv_list['page-services-stunnel']['name'] = "WebCfg - Services: stunnel package"; +$priv_list['page-services-stunnel']['descr'] = "Allow access to stunnel package GUI"; +$priv_list['page-services-stunnel']['match'] = array(); + +$priv_list['page-services-stunnel']['match'][] = "pkg.php?xml=stunnel.xml*"; +$priv_list['page-services-stunnel']['match'][] = "pkg.php?xml=stunnel_certs.xml*"; + +$priv_list['page-services-stunnel']['match'][] = "pkg_edit.php?xml=stunnel.xml*"; +$priv_list['page-services-stunnel']['match'][] = "pkg_edit.php?xml=stunnel_certs.xml*"; + +?> diff --git a/config/stunnel/stunnel.xml b/config/stunnel/stunnel.xml index c8957ba8..b5dfd6bd 100644 --- a/config/stunnel/stunnel.xml +++ b/config/stunnel/stunnel.xml @@ -42,14 +42,10 @@ ]]> </copyright> <name>stunnel</name> - <version>5.20.2</version> + <version>5.20.3</version> <title>Services: Secure Tunnel</title> <menu> <name>STunnel</name> - <tooltiptext>The stunnel program is designed to work as an SSL encryption wrapper between remote client and local (inetd-startable) or remote server. - It can be used to add SSL functionality to commonly used inetd daemons like POP2, POP3, and IMAP servers without any changes in the programs' code. - It will negotiate an SSL connection using the OpenSSL or SSLeay libraries. - It calls the underlying crypto libraries, so stunnel supports whatever cryptographic algorithms you compiled into your crypto package.</tooltiptext> <section>Services</section> <configfile>stunnel.xml</configfile> </menu> @@ -59,6 +55,10 @@ <item>https://packages.pfsense.org/packages/config/stunnel/stunnel.inc</item> </additional_files_needed> <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/stunnel/stunnel.priv.inc</item> + </additional_files_needed> + <additional_files_needed> <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/stunnel/stunnel_certs.xml</item> </additional_files_needed> diff --git a/config/sudo/sudo.priv.inc b/config/sudo/sudo.priv.inc new file mode 100644 index 00000000..01cb2224 --- /dev/null +++ b/config/sudo/sudo.priv.inc @@ -0,0 +1,38 @@ +<?php +/* + sudo.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-system-sudo'] = array(); +$priv_list['page-system-sudo']['name'] = "WebCfg - System: sudo package"; +$priv_list['page-system-sudo']['descr'] = "Allow access to sudo package GUI"; +$priv_list['page-system-sudo']['match'] = array(); + +$priv_list['page-system-sudo']['match'][] = "pkg_edit.php?xml=sudo.xml*"; + +?> diff --git a/config/sudo/sudo.xml b/config/sudo/sudo.xml index 6124a641..e2b92cf1 100644 --- a/config/sudo/sudo.xml +++ b/config/sudo/sudo.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?> <packagegui> <copyright> <![CDATA[ @@ -42,7 +44,7 @@ <description>Sudo Command Control</description> <requirements>None</requirements> <name>sudo</name> - <version>0.2.7</version> + <version>0.2.8</version> <title>Sudo - Shell Command Privilege Delegation Utility</title> <include_file>/usr/local/pkg/sudo.inc</include_file> <menu> @@ -56,6 +58,10 @@ <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/sudo/sudo.inc</item> </additional_files_needed> + <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/sudo/sudo.priv.inc</item> + </additional_files_needed> <fields> <field> <type>listtopic</type> @@ -63,11 +69,14 @@ </field> <field> <type>info</type> - <description><![CDATA[ -User permission definitions for allowing the use of sudo by shell users to run commands as other users, such as root. -<br /><br />More information on the full command options may be found in the <a href="http://www.sudo.ws/sudoers.man.html">sudoers manual</a>. -<br /><br />By default the command is "ALL" meaning the user can run any commands. Leaving the commands field blank assumes "ALL". A comma-separated list of commands can be supplied to limit the user to individual binaries. Full paths to binaries must be used. - ]]></description> + <description> + <![CDATA[ + User permission definitions for allowing the use of sudo by shell users to run commands as other users, such as root.<br /><br /> + More information on the full command options may be found in the <a href="http://www.sudo.ws/sudoers.man.html">sudoers manual</a>.<br /><br /> + By default the command is "ALL" meaning the user can run any commands. Leaving the commands field blank assumes "ALL".<br /><br /> + A comma-separated list of commands can be supplied to limit the user to individual binaries. <strong>Full paths to binaries must be used.</strong> + ]]> + </description> </field> <field> <fielddescr>User Permissions</fielddescr> @@ -100,7 +109,7 @@ User permission definitions for allowing the use of sudo by shell users to run c <rowhelperfield> <fielddescr>Command List</fielddescr> <fieldname>cmdlist</fieldname> - <description>Commands the user may run. Comma-separated list, full paths preferred. Default: ALL</description> + <description>Commands the user may run. Comma-separated list, full paths required. Default: ALL</description> <type>input</type> <size>30</size> <value>ALL</value> diff --git a/config/syslog-ng/syslog-ng.priv.inc b/config/syslog-ng/syslog-ng.priv.inc new file mode 100644 index 00000000..96722a7b --- /dev/null +++ b/config/syslog-ng/syslog-ng.priv.inc @@ -0,0 +1,44 @@ +<?php +/* + syslog-ng.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-services-syslogng'] = array(); +$priv_list['page-services-syslogng']['name'] = "WebCfg - Services: syslog-ng package"; +$priv_list['page-services-syslogng']['descr'] = "Allow access to syslog-ng package GUI"; +$priv_list['page-services-syslogng']['match'] = array(); + +$priv_list['page-services-syslogng']['match'][] = "pkg.php?xml=syslog-ng.xml*"; +$priv_list['page-services-syslogng']['match'][] = "pkg.php?xml=syslog-ng_advanced.xml*"; + +$priv_list['page-services-syslogng']['match'][] = "pkg_edit.php?xml=syslog-ng.xml*"; +$priv_list['page-services-syslogng']['match'][] = "pkg_edit.php?xml=syslog-ng_advanced.xml*"; + +$priv_list['page-services-syslogng']['match'][] = "syslog-ng_log_viewer.php*"; + +?> diff --git a/config/syslog-ng/syslog-ng.xml b/config/syslog-ng/syslog-ng.xml index 9b0ccffc..81942926 100644 --- a/config/syslog-ng/syslog-ng.xml +++ b/config/syslog-ng/syslog-ng.xml @@ -42,7 +42,7 @@ ]]> </copyright> <name>Syslog-ng</name> - <version>1.0.8</version> + <version>1.1.1</version> <title>Services: Syslog-ng</title> <include_file>/usr/local/pkg/syslog-ng.inc</include_file> <menu> @@ -76,6 +76,10 @@ <item>https://packages.pfsense.org/packages/config/syslog-ng/syslog-ng.inc</item> </additional_files_needed> <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/syslog-ng/syslog-ng.priv.inc</item> + </additional_files_needed> + <additional_files_needed> <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/syslog-ng/syslog-ng_advanced.xml</item> </additional_files_needed> diff --git a/config/tftp2/tftp.inc b/config/tftp2/tftp.inc index 67054619..75ddaac8 100644 --- a/config/tftp2/tftp.inc +++ b/config/tftp2/tftp.inc @@ -50,10 +50,10 @@ function tftp_install_command() { // Restore backup if it exists if (file_exists($tftpbackup)) { - system("/usr/bin/tar xvpfz {$tftpbackup} -C /"); - system("/bin/chmod -R 0744 {$tftpdir}/*"); - unset($tftpbackup); + mwexec("/usr/bin/tar xvpfz {$tftpbackup} -C /"); + mwexec("/bin/chmod -R 0744 {$tftpdir}/*"); } + unset($tftpdir, $tftpbackup); } function tftp_deinstall_command() { @@ -68,11 +68,9 @@ function tftp_generate_rules($type) { return; } - // Open inetd.conf write handle + // Add tftpd daemon to inetd $inetd_fd = fopen("/var/etc/inetd.conf", "a+"); - // Add tftp daemon fwrite($inetd_fd, "tftp\t\tdgram\tudp\twait\t\troot\t/usr/libexec/tftpd\ttftpd /tftpboot\n"); - // Close file handle fclose($inetd_fd); if (!empty($config['installedpackages']['tftpd']['config'][0]['tftpdinterface'])) { diff --git a/config/tftp2/tftp.priv.inc b/config/tftp2/tftp.priv.inc new file mode 100644 index 00000000..14691924 --- /dev/null +++ b/config/tftp2/tftp.priv.inc @@ -0,0 +1,38 @@ +<?php +/* + tftp.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-services-tftp'] = array(); +$priv_list['page-services-tftp']['name'] = "WebCfg - Services: TFTP package"; +$priv_list['page-services-tftp']['descr'] = "Allow access to TFTP package GUI"; +$priv_list['page-services-tftp']['match'] = array(); + +$priv_list['page-services-tftp']['match'][] = "tftp_files.php*"; + +?> diff --git a/config/tftp2/tftp.xml b/config/tftp2/tftp.xml index 2a526a4c..33fb9c3d 100644 --- a/config/tftp2/tftp.xml +++ b/config/tftp2/tftp.xml @@ -43,7 +43,7 @@ ]]> </copyright> <name>tftp Settings</name> - <version>2.0</version> + <version>2.2.2</version> <title>TFTP: Settings</title> <include_file>/usr/local/pkg/tftp.inc</include_file> <menu> @@ -56,23 +56,21 @@ <service> <name>tftp</name> <executable>inetd</executable> - <description>TFTP daemon</description> + <description>TFTP Daemon</description> </service> - <tabs> - <tab> - <text>Files</text> - <url>tftp_files.php</url> - </tab> - </tabs> <configpath>installedpackages->$packagename</configpath> <additional_files_needed> <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/tftp2/tftp.inc</item> - </additional_files_needed> + </additional_files_needed> + <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/tftp2/tftp.priv.inc</item> + </additional_files_needed> <additional_files_needed> <prefix>/usr/local/www/</prefix> <item>https://packages.pfsense.org/packages/config/tftp2/tftp_files.php</item> - </additional_files_needed> + </additional_files_needed> <custom_php_install_command> tftp_install_command(); </custom_php_install_command> diff --git a/config/tftp2/tftp_files.php b/config/tftp2/tftp_files.php index eebe4c5e..0352f4a0 100644 --- a/config/tftp2/tftp_files.php +++ b/config/tftp2/tftp_files.php @@ -29,6 +29,7 @@ POSSIBILITY OF SUCH DAMAGE. */ require_once("guiconfig.inc"); +require_once("util.inc"); require_once("/usr/local/pkg/tftp.inc"); $pconfig['tftpdinterface'] = explode(",", $config['installedpackages']['tftpd']['config'][0]['tftpdinterface']); @@ -43,7 +44,7 @@ if (($_GET['a'] == "download") && $_GET['t'] == "backup") { conf_mount_rw(); $filename = $backup_filename; $download_dir = $backup_dir; - system("tar -czC / -f {$backup_path} tftpboot"); + mwexec("/usr/bin/tar -czC / -f {$backup_path} tftpboot"); conf_mount_ro(); } @@ -73,8 +74,8 @@ if ($_GET['a'] == "other") { if (file_exists($backup_path)) { //echo "The file $filename exists"; conf_mount_rw(); - system("tar -xpzC / -f {$backup_path}"); - system("chmod -R 744 {$files_dir}/*"); + mwexec("/usr/bin/tar -xpzC / -f {$backup_path}"); + mwexec("/bin/chmod -R 744 {$files_dir}/*"); header( 'Location: tftp_files.php?savemsg=Backup+has+been+restored.' ) ; conf_mount_ro(); } else { @@ -100,7 +101,7 @@ if (($_POST['submit'] == "Upload") && is_uploaded_file($_FILES['ulfile']['tmp_na conf_mount_rw(); move_uploaded_file($_FILES['ulfile']['tmp_name'], "{$files_dir}/{$_FILES['ulfile']['name']}"); $savemsg = "Uploaded file to {$files_dir}/" . htmlentities($_FILES['ulfile']['name']); - system('chmod -R 744 {$files_dir}/*'); + mwexec('/bin/chmod -R 744 {$files_dir}/*'); unset($_POST['txtCommand']); conf_mount_ro(); } @@ -122,7 +123,7 @@ include("head.inc"); <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> -<p class="pgtitle">TFTP: Files</p> +<p class="pgtitle">TFTP: Settings/Files</p> <?php $savemsg = $_GET["savemsg"]; @@ -137,7 +138,7 @@ if ($savemsg) { <?php $tab_array = array(); - $tab_array[] = array(gettext("Files"), false, "tftp_files.php"); + $tab_array[] = array(gettext("TFTP"), false, "tftp_files.php"); display_top_tabs($tab_array); ?> @@ -145,14 +146,16 @@ if ($savemsg) { </table> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tr><td> +<div id="mainarea"> + <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> <tr> - <td class="tabcont"> - <table width="100%" border="0" cellpadding="6" cellspacing="0"> + <td colspan="2" class="listtopic">TFTP Daemon Interfaces</td> + </tr> <tr> + <td width="22%" class="vncell">Select TFTP Daemon Interface(s).</td> <td width="78%" class="vtable"> <form action="tftp_files.php" method="post" enctype="multipart/form-data" name="frmInterfaces" onsubmit=""> - <p><span class="vexpl"><strong>TFTP Daemon Interfaces</strong></span></p> - <?=gettext("Choose the interfaces where you want the TFTP daemon to accept connections.");?><br/><br/> <select name="tftpdinterface[]" multiple="multiple" class="formselect" size="3"> <?php $ifdescs = get_configured_interface_with_descr(); @@ -164,70 +167,46 @@ if ($savemsg) { echo "\t\t\t<option value=\"{$ifent}\"{$selected}>" . $ifdesc . "</option>\n"; } ?> - </select><br /> - <input name="submit" type="submit" class="button" id="save" value="Save" /> + </select><br /><br /> + <span class="vexpl"> + Choose the interfaces where you want the TFTP Daemon to accept connections.<br/> + <strong>Hint:</strong> If you simply need to (re)start tftpd/inetd, just use the Save button without making any changes here.<br /><br /> + </span> + <input name="submit" type="submit" class="formbtns" id="save" value="Save" title="Save settings" /> </form> </td> </tr> <tr> - <td> - <p><span class="vexpl"><span class="red"><strong>TFTP files</strong></span><br /> - Trivial File Transport Protocol is a very simple file transfer protocol.<br /> - Use the file upload to add files to the /tftpboot directory.<br /> - Click on the file from the file list below to download it.<br /> - </span></p> - </td> + <td colspan="2" class="listtopic">TFTP Files Upload</td> </tr> - </table> - <br /> - <div id="niftyOutter"> - <form action="tftp_files.php" method="post" enctype="multipart/form-data" name="frmUpload" onsubmit=""> - <table> - <tr> - <td align="right">File to upload:</td> - <td valign="top" class="label"> - <input name="ulfile" type="file" class="button" id="ulfile" /> - </td> - </tr> - <tr> - <td valign="top"> </td> - <td valign="top" class="label"> - <input name="submit" type="submit" class="button" id="upload" value="Upload" /> - </td> - </tr> - </table> - </form> - </div> - <br /><br /> - - <table width='690' cellpadding='0' cellspacing='0' border='0'> <tr> - <td width='80%'> - <strong>Backup / Restore</strong><br /> - The 'Backup' button compresses /tftpboot/ to /root/backup/tftp.bak.tgz; after that it presents the backup for download.<br /> - If the backup file does not exist in /root/backup/tftp.bak.tgz then the 'Restore' button will be hidden.<br /> - Use Diagnostics -> Command -> File to upload: to browse to the file and then click on upload.<br /> - After that, backup will be ready to be restored.<br /><br /> - </td> - <td width='20%' valign='middle' align='right'> - <input type="button" value="Backup" onclick="document.location.href='tftp_files.php?a=download&t=backup'" /> - <?php - if (file_exists('/root/backup/tftp.bak.tgz')) { - echo "<input type='button' value='Restore' onclick=\"document.location.href='tftp_files.php?a=other&t=restore';\" />\n"; - } - ?> + <td width="22%" class="vncell">Use the file upload to add files to the /tftpboot directory.</td> + <td width="78%" class="vtable"> + <form action="tftp_files.php" method="post" enctype="multipart/form-data" name="frmUpload" onsubmit=""> + <span class="vexpl">1. Select file to upload: </span> + <input name="ulfile" type="file" class="formbtns" id="ulfile" title="Select file to upload" /> + <br /> + <span class="vexpl">2. Upload the selected file: </span> + <input name="submit" type="submit" class="formbtns" id="upload" value="Upload" title="Upload file" /> + </form> </td> </tr> - </table> - <br /><br /> - <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> - <td width="25%" class="listhdrr">File Name (download)</td> - <td width="50%" class="listhdr">Last Modified</td> - <td width="50%" class="listhdr">Size</td> + <td colspan="3" class="listtopic">TFTP Files Download</td> </tr> + <tr> + <td colspan="3" class="vexpl">Click on the file from the file list below to download it.</td> + </tr> + <tr> + <td colspan="3"> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tr> + <td width="25%" class="listhdrr">File Name (download)</td> + <td width="50%" class="listhdr">Last Modified</td> + <td width="50%" class="listhdr">Size</td> + </tr> <?php if ($handle = opendir('/tftpboot')) { @@ -267,13 +246,37 @@ if ($handle = opendir('/tftpboot')) { } ?> + <tr> + <td class="list" colspan="3"></td> + <td class="list"></td> + </tr> + </table> + </td> + </tr> + <tr> - <td class="list" colspan="3"></td> - <td class="list"></td> + <td colspan="2" class="listtopic">TFTP Backup / Restore</td> </tr> - </table> - </td> + <tr> + <td width="22%" class="vncell">Use the file upload to add files to the /tftpboot directory.</td> + <td width="78%" class="vtable"> + <span class="vexpl"><strong>Backup:</strong> 'Backup' button compresses /tftpboot/ to /root/backup/tftp.bak.tgz; after that it presents the backup for download.<br /> + <strong>Restore:</strong> If the backup file does not exist in /root/backup/tftp.bak.tgz then the 'Restore' button will be hidden. + To 'Restore' a previously downloaded backup, use <a href="diag_backup.php" title="Upload file">Diagnostics -> Command Prompt -> File to upload</a> to browse to the file and then click on upload.<br /> + After that, backup will be ready to be restored.<br /><br /> + </span> + <input type="button" value="Backup" title="Create backup" onclick="document.location.href='tftp_files.php?a=download&t=backup'" /> + <?php + if (file_exists('/root/backup/tftp.bak.tgz')) { + echo "<input type='button' value='Restore' title='Restore backup' onclick=\"document.location.href='tftp_files.php?a=other&t=restore';\" />\n"; + } + ?> + </td> </tr> + </table> + +</div> +</td></tr> </table> </div> diff --git a/config/tinc/tinc.priv.inc b/config/tinc/tinc.priv.inc new file mode 100644 index 00000000..d8b45c5b --- /dev/null +++ b/config/tinc/tinc.priv.inc @@ -0,0 +1,44 @@ +<?php +/* + tinc.priv.inc + part of pfSense (http://www.pfSense.org/) + Copyright (C) 2015 ESF, LLC + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +global $priv_list; + +$priv_list['page-vpn-tinc'] = array(); +$priv_list['page-vpn-tinc']['name'] = "WebCfg - VPN: tinc package"; +$priv_list['page-vpn-tinc']['descr'] = "Allow access to tinc package GUI"; +$priv_list['page-vpn-tinc']['match'] = array(); + +$priv_list['page-vpn-tinc']['match'][] = "pkg.php?xml=tinc.xml*"; +$priv_list['page-vpn-tinc']['match'][] = "pkg.php?xml=tinc_hosts.xml*"; + +$priv_list['page-vpn-tinc']['match'][] = "pkg_edit.php?xml=tinc.xml*"; +$priv_list['page-vpn-tinc']['match'][] = "pkg_edit.php?xml=tinc_hosts.xml*"; + +$priv_list['page-vpn-tinc']['match'][] = "status_tinc.php*"; + +?> diff --git a/config/tinc/tinc.xml b/config/tinc/tinc.xml index 89d1e8ce..0f71e03d 100644 --- a/config/tinc/tinc.xml +++ b/config/tinc/tinc.xml @@ -42,8 +42,8 @@ </copyright> <description>A self-contained VPN solution designed to connect multiple sites together in a secure way.</description> <name>tinc</name> - <version>1.2.2</version> - <title>VPN: tinc - Config</title> + <version>1.2.4</version> + <title>VPN: Tinc: Settings</title> <include_file>/usr/local/pkg/tinc.inc</include_file> <configpath>['installedpackages']['package']['$packagename']['config']</configpath> <menu> @@ -53,7 +53,7 @@ <url>/pkg_edit.php?xml=tinc.xml</url> </menu> <menu> - <name>tinc VPN</name> + <name>Tinc VPN</name> <section>Status</section> <url>/status_tinc.php</url> </menu> @@ -65,7 +65,7 @@ </service> <tabs> <tab> - <text>Config</text> + <text>Settings</text> <url>/pkg_edit.php?xml=tinc.xml</url> <active/> </tab> @@ -79,6 +79,10 @@ <item>https://packages.pfsense.org/packages/config/tinc/tinc.inc</item> </additional_files_needed> <additional_files_needed> + <prefix>/etc/inc/priv/</prefix> + <item>https://packages.pfsense.org/packages/config/tinc/tinc.priv.inc</item> + </additional_files_needed> + <additional_files_needed> <prefix>/usr/local/pkg/</prefix> <item>https://packages.pfsense.org/packages/config/tinc/tinc_hosts.xml</item> </additional_files_needed> @@ -119,7 +123,7 @@ <fieldname>localip</fieldname> <description> <![CDATA[ - IP Address of local tunnel interface.<br /> + IP address of local tunnel interface.<br /> This is often the same IP as your routers LAN address. (Example: 192.168.2.1) ]]> </description> @@ -143,7 +147,7 @@ <fieldname>vpnnetmask</fieldname> <description> <![CDATA[ - This is the Netmask that defines what traffic is routed to the VPNs tunnel interface.<br /> + This is the netmask that defines what traffic is routed to the VPNs tunnel interface.<br /> It is usually broader then your local netmask. (Example: 255.255.0.0) ]]> </description> diff --git a/config/tinc/tinc_hosts.xml b/config/tinc/tinc_hosts.xml index b521d4a2..a10c1a9e 100644 --- a/config/tinc/tinc_hosts.xml +++ b/config/tinc/tinc_hosts.xml @@ -41,13 +41,13 @@ ]]> </copyright> <name>tinchosts</name> - <version>1.2.2</version> - <title>VPN: tinc - Hosts</title> + <version>1.2.4</version> + <title>VPN: Tinc: Hosts</title> <include_file>/usr/local/pkg/tinc.inc</include_file> <configpath>['installedpackages']['package']['$packagename']['config']</configpath> <tabs> <tab> - <text>Config</text> + <text>Settings</text> <url>/pkg_edit.php?xml=tinc.xml</url> </tab> <tab> @@ -75,7 +75,6 @@ <fieldname>connect</fieldname> <type>checkbox</type> </columnitem> - </adddeleteeditpagefields> <fields> <field> @@ -107,7 +106,7 @@ <type>checkbox</type> </field> <field> - <fielddescr>RSA public key</fielddescr> + <fielddescr>RSA Public Key</fielddescr> <fieldname>cert_pub</fieldname> <description> <![CDATA[ |