diff --git a/net/haproxy/pkg-descr b/net/haproxy/pkg-descr
index 2bb68861a..d675ec264 100644
--- a/net/haproxy/pkg-descr
+++ b/net/haproxy/pkg-descr
@@ -11,6 +11,8 @@ Plugin Changelog
Added:
* add support for req.ssl_hello_type (#2311)
* add support for Prometheus exporter (#2764)
+* add support for FastCGI applications (#2769)
+* add server option to override the multiplexer protocol
Fixed:
* fix unix sockets in chrooted environment (#3093)
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php
index 44ccd006c..4e0006f39 100644
--- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php
+++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php
@@ -1,7 +1,7 @@
searchBase('luas.lua', array('enabled', 'name', 'description'), 'name');
}
+ public function getFcgiAction($uuid = null)
+ {
+ return $this->getBase('fcgi', 'fcgis.fcgi', $uuid);
+ }
+
+ public function setFcgiAction($uuid)
+ {
+ return $this->setBase('fcgi', 'fcgis.fcgi', $uuid);
+ }
+
+ public function addFcgiAction()
+ {
+ return $this->addBase('fcgi', 'fcgis.fcgi');
+ }
+
+ public function delFcgiAction($uuid)
+ {
+ return $this->delBase('fcgis.fcgi', $uuid);
+ }
+
+ public function searchFcgisAction()
+ {
+ return $this->searchBase('fcgis.fcgi', array('name', 'description'), 'name');
+ }
+
public function getErrorfileAction($uuid = null)
{
return $this->getBase('errorfile', 'errorfiles.errorfile', $uuid);
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php
index 8e2b52f65..791f6bfe6 100644
--- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php
+++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php
@@ -1,7 +1,7 @@
view->formDialogBackend = $this->getForm("dialogBackend");
$this->view->formDialogCpu = $this->getForm("dialogCpu");
$this->view->formDialogErrorfile = $this->getForm("dialogErrorfile");
+ $this->view->formDialogFcgi = $this->getForm("dialogFcgi");
$this->view->formDialogFrontend = $this->getForm("dialogFrontend");
$this->view->formDialogGroup = $this->getForm("dialogGroup");
$this->view->formDialogHealthcheck = $this->getForm("dialogHealthcheck");
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml
index f0a663f16..7a499dab8 100644
--- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml
+++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml
@@ -448,4 +448,26 @@
dropdown
+
+
+ header
+
+
+
+ action.fcgi_pass_header
+
+ text
+
+
+
+
+ header
+
+
+
+ action.fcgi_set_param
+
+ text
+ Custom Log format rules. With this directive, it is possible to overwrite the value of default FastCGI parameters.]]>
+
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogBackend.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogBackend.xml
index cd1aec54e..7615ceb09 100644
--- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogBackend.xml
+++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogBackend.xml
@@ -54,6 +54,12 @@
Type server name or choose from list.
+
+ backend.linkedFcgi
+
+ dropdown
+
+ backend.linkedResolver
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogFcgi.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogFcgi.xml
new file mode 100644
index 000000000..ffaec1d91
--- /dev/null
+++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogFcgi.xml
@@ -0,0 +1,77 @@
+
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogServer.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogServer.xml
index 53190b12c..99db8ffab 100644
--- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogServer.xml
+++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogServer.xml
@@ -95,6 +95,13 @@
dropdown
+
+ server.multiplexer_protocol
+
+ dropdown
+
+ true
+ server.resolvePrefer
diff --git a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml
index 8a81ffce3..8289391d5 100644
--- a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml
+++ b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml
@@ -911,6 +911,18 @@
YN
+
+
+
+ OPNsense.HAProxy.HAProxy
+ fcgis.fcgi
+ name
+
+
+ Related fcgi item not found
+ N
+ N
+
@@ -1282,6 +1294,16 @@
disabled
+
+ N
+ unspecified
+
+ auto-selection [recommended]
+ FastCGI
+
HTTP/2
+
HTTP/1.1
+
+ Ystatic
@@ -2138,6 +2160,8 @@
Use specified Backend PoolOverride server in Backend PoolMap domains to backend pools using a map file
+ FastCGI pass-header
+ FastCGI set-paramhttp-request allowhttp-request denyhttp-request tarpit
@@ -2202,6 +2226,16 @@
NN
+
+ /^.{1,1024}$/u
+ Should be a string between 1 and 1024 characters.
+ N
+
+
+ /^.{1,1024}$/u
+ Should be a string between 1 and 1024 characters.
+ N
+ /^.{1,4096}$/uN
@@ -2471,6 +2505,80 @@
+
+
+
+ Y
+
+
+ 1
+ Y
+
+
+ /^[^\t^,^;^\.^\[^\]^\{^\}]{1,255}$/u
+ Should be a string between 1 and 255 characters.
+ Y
+
+
+ /^.{1,255}$/u
+ Should be a string between 1 and 255 characters.
+ N
+
+
+ /^.{1,4096}$/u
+ Should be a string between 1 and 4096 characters.
+ Y
+
+
+ /^.{1,4096}$/u
+ Should be a string between 1 and 4096 characters.
+ N
+
+
+ /^.{1,4096}$/u
+ Should be a string between 1 and 4096 characters.
+ N
+
+
+ 0
+ N
+
+
+ 1
+ N
+
+
+ 0
+ N
+
+
+ 0
+ N
+
+
+ 1
+ 100000
+ Please specify a value between 1 and 100000.
+ N
+
+
+
+
+ OPNsense.HAProxy.HAProxy
+ actions.action
+ name
+
+ /fcgi/
+
+
+
+ Related action item not found
+ Y
+ Y
+ N
+
+
+
diff --git a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml
index 0d78bf3eb..d95844a34 100644
--- a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml
+++ b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml
@@ -18,6 +18,7 @@
+
diff --git a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt
index 7510ca1ed..796dd5e0c 100644
--- a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt
+++ b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt
@@ -162,6 +162,18 @@ POSSIBILITY OF SUCH DAMAGE.
}
);
+ $("#grid-fcgis").UIBootgrid(
+ { search:'/api/haproxy/settings/searchFcgis',
+ get:'/api/haproxy/settings/getFcgi/',
+ set:'/api/haproxy/settings/setFcgi/',
+ add:'/api/haproxy/settings/addFcgi/',
+ del:'/api/haproxy/settings/delFcgi/',
+ options: {
+ rowCount:[10,25,50,100,500,1000]
+ }
+ }
+ );
+
$("#grid-errorfiles").UIBootgrid(
{ search:'/api/haproxy/settings/searchErrorfiles',
get:'/api/haproxy/settings/getErrorfile/',
@@ -676,6 +688,7 @@ POSSIBILITY OF SUCH DAMAGE.
{{ lang._("Most of the time these features are not required, but in certain situations they will be handy:") }}
{{ lang._("%sError Messages:%s Return a custom message instead of errors generated by HAProxy. Useful to overwrite HAProxy's internal error messages. The message must represent the full HTTP response and include required HTTP headers.") | format('', '') }}
+
{{ lang._("%sFastCGI Applications:%s HAProxy can be configured to send requests to FastCGI applications. After configuring a FastCGI application, it needs to be enabled in a %sBackend Pool%s.") | format('', '', '', '') }}
{{ lang._("%sLua scripts:%s Include your own Lua code/scripts to extend HAProxy's functionality. The Lua code can be used in certain %sRules%s, for example.") | format('', '', '', '') }}
{{ lang._("%sMap Files:%s A map allows to map a data in input to an other one on output. For example, this makes it possible to map a large number of domains to backend pools without using the GUI. Map files need to be used in %sRules%s, otherwise they are ignored.") | format('', '', '', '') }}
{{ lang._("%sCPU Affinity Rules:%s This feature makes it possible to bind HAProxy's processes/threads to a specific CPU (or a CPU set). Furthermore it is possible to select CPU Affinity Rules in %sPublic Services%s to restrict them to a certain set of processes/threads/CPUs.") | format('', '', '', '') }}
@@ -1029,6 +1043,31 @@ POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+
{{ lang._('FastCGI ID') }}
+
{{ lang._('FastCGI Application Name') }}
+
{{ lang._('Description') }}
+
{{ lang._('Commands') }}
+
{{ lang._('ID') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1264,6 +1303,7 @@ POSSIBILITY OF SUCH DAMAGE.
{{ partial("layout_partials/base_dialog",['fields':formDialogGroup,'id':'DialogGroup','label':lang._('Edit Group')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogLua,'id':'DialogLua','label':lang._('Edit Lua Script')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogErrorfile,'id':'DialogErrorfile','label':lang._('Edit Error Message')])}}
+{{ partial("layout_partials/base_dialog",['fields':formDialogFcgi,'id':'DialogFcgi','label':lang._('Edit FastCGI Application')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogMapfile,'id':'DialogMapfile','label':lang._('Edit Map File')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogCpu,'id':'DialogCpu','label':lang._('Edit CPU Affinity Rule')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogResolver,'id':'DialogResolver','label':lang._('Edit Resolver')])}}
diff --git a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf
index d7d910beb..e0fb1fd7a 100644
--- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf
+++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf
@@ -465,6 +465,20 @@
{% set action_enabled = '0' %}
# ERROR: missing parameters
{% endif %}
+{% elif action_data.type == 'fcgi_pass_header' %}
+{% if action_data.fcgi_pass_header|default('') != '' %}
+{% do action_options.append('pass-header ' ~ action_data.fcgi_pass_header) %}
+{% else %}
+{% set action_enabled = '0' %}
+ # ERROR: missing parameters
+{% endif %}
+{% elif action_data.type == 'fcgi_set_param' %}
+{% if action_data.fcgi_set_param|default('') != '' %}
+{% do action_options.append('set-param ' ~ action_data.fcgi_set_param) %}
+{% else %}
+{% set action_enabled = '0' %}
+ # ERROR: missing parameters
+{% endif %}
{% elif action_data.type == 'http-request_allow' %}
{% do action_options.append('http-request allow') %}
{% elif action_data.type == 'http-request_deny' %}
@@ -696,7 +710,7 @@
{% set comment_lines = comment_lines + [' # NOTE: actions with no ACLs/conditions will always match'] %}
{% endif %}
{% if action_options|length > 0 %}
-{% do global_action_options.append(comment_lines|join('\n')) %}
+{% do global_action_options.append(comment_lines|join('\n')) -%}
{% do global_action_options.append(([action_options|join(' '), acl_line]|join(' '))) %}
{% endif %}
{% else %}
@@ -1626,6 +1640,17 @@ backend {{backend.name}}
{% else %}
balance {{backend.algorithm}}
{% endif %}
+{# # FastCGI application #}
+{% if backend.linkedFcgi|default("") != "" %}
+{% set fcgi_data = helpers.getUUID(backend.linkedFcgi) %}
+{% if fcgi_data == {} %}
+# ERROR: FastCGI data not found ({{backend.linkedFcgi}})
+{% elif fcgi_data.enabled == '0' %}
+# NOTE: specified FastCGI application is disabled ({{fcgi_data.name}})
+{% else %}
+ use-fcgi-app {{fcgi_data.name}}
+{% endif %}
+{% endif %}
{# # call macro to evaluate stickiness config #}
{{ StickTableConfig(backend,true) }}
# tuning options
@@ -1771,6 +1796,12 @@ backend {{backend.name}}
{% if server_data.mode|default("") != 'active' %}
{% do server_options.append(server_data.mode) %}
{% endif %}
+{# # force multiplexer protocol if FastCGI is configured for this backend #}
+{% if backend.linkedFcgi|default("") != "" and fcgi_data.enabled == '1' %}
+{% do server_options.append('proto fcgi') %}
+{% elif server_data.multiplexer_protocol|default('') != '' and server_data.multiplexer_protocol|default('') != 'unspecified' %}
+{% do server_options.append('proto ' ~ server_data.multiplexer_protocol) %}
+{% endif %}
{# # server ssl communication #}
{% if server_data.ssl|default("") == '1' %}
{% do server_options.append('ssl') %}
@@ -1785,7 +1816,8 @@ backend {{backend.name}}
{% do server_options.append('alpn ' ~ alpn_options) %}
{% endif %}
{# # HTTP/2 without TLS #}
-{% elif backend.http2Enabled|default("") == '1' and backend.http2Enabled_nontls|default("") == '1' %}
+{# # Must be ignored when a FastCGI application is configured #}
+{% elif backend.http2Enabled|default("") == '1' and backend.http2Enabled_nontls|default("") == '1' and (server_data.multiplexer_protocol|default('') == '' or server_data.multiplexer_protocol|default('') == 'unspecified') and (backend.linkedFcgi|default('') == '' or fcgi_data.enabled == '0') %}
{% do server_options.append('proto h2') %}
{% endif %}
{# # ssl verification can be enabled for two reasons: #}
@@ -1895,6 +1927,50 @@ backend {{backend.name}}
{% endfor %}
{%- endif -%}
+{# ############################### #}
+{# FASTCGI #}
+{# ############################### #}
+
+{%- if helpers.exists('OPNsense.HAProxy.fcgis') %}
+{% for fcgi in helpers.toList('OPNsense.HAProxy.fcgis.fcgi') %}
+{# # ignore disabled fcgis #}
+{% if fcgi.enabled == '1' %}
+# FastCGI: {{fcgi.name}} ({{fcgi.description}})
+fcgi-app {{fcgi.name}}
+ docroot {{fcgi.docroot}}
+{% if fcgi.log_stderr|default('') == '1' %}
+ log-stderr global
+{% endif -%}
+{% if fcgi.index|default('') != '' %}
+ index {{fcgi.index}}
+{% endif -%}
+{% if fcgi.path_info|default('') != '' %}
+ path-info {{fcgi.path_info}}
+{% endif -%}
+{% if fcgi.keep_conn|default('') == '1' %}
+ option keep-conn
+{% endif -%}
+{% if fcgi.get_values|default('') == '1' %}
+ option get-values
+{% endif -%}
+{% if fcgi.mpxs_conns|default('') == '1' %}
+ option mpxs-conns
+{% endif -%}
+{% if fcgi.max_reqs|default('') != '' %}
+ option max-reqs {{fcgi.max_reqs}}
+{% endif -%}
+{# # action and ACL configuration #}
+{% if fcgi.linkedActions|default("") != "" -%}
+{# # call macro to evaluate ACLs and actions #}
+{{ AclsAndActions(fcgi.linkedActions) }}
+{%- endif %}
+
+{% else %}
+# FastCGI (DISABLED): {{fcgi.name}} ({{fcgi.description}})
+{% endif %}
+{% endfor %}
+{%- endif %}
+
{# ############################### #}
{# PEERS #}
{# ############################### #}