+
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 1083b8780..91921fc35 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
@@ -472,7 +472,7 @@ POSSIBILITY OF SUCH DAMAGE.
{{ lang._('Lastly, enable HAProxy using the %sService Settings%s.') | format('', '') }}
{{ lang._('Please be aware that you need to %smanually%s add the required firewall rules for all configured services.') | format('', '') }}
- {{ lang._('Further information is available in our %sHAProxy plugin documentation%s and of course in the %sofficial HAProxy documentation%s. Be sure to report bugs and request features on our %sGitHub issue page%s. Code contributions are also very welcome!') | format('', '', '', '', '', '') }}
+ {{ lang._('Further information is available in our %sHAProxy plugin documentation%s and of course in the %sofficial HAProxy documentation%s. Be sure to report bugs and request features on our %sGitHub issue page%s. Code contributions are also very welcome!') | format('', '', '', '', '', '') }}
@@ -514,7 +514,7 @@ POSSIBILITY OF SUCH DAMAGE.
{{ lang._('%sConditions:%s HAProxy is capable of extracting data from requests, responses and other connection data and match it against predefined patterns. Use these powerful patterns to compose a condition that may be used in multiple Rules.') | format('', '') }}
{{ lang._('%sRules:%s Perform a large set of actions if one or more %sConditions%s match. These Rules may be used in %sBackend Pools%s as well as %sPublic Services%s.') | format('', '', '', '', '', '', '', '') }}
- {{ lang._("For more information on HAProxy's %sACL feature%s see the %sofficial documentation%s.") | format('', '', '', '') }}
+ {{ lang._("For more information on HAProxy's %sACL feature%s see the %sofficial documentation%s.") | format('', '', '', '') }}
{{ lang._('Note that it is possible to directly add options to the HAProxy configuration by using the "option pass-through", a setting that is available for several configuration items. It allows you to implement configurations that are currently not officially supported by this plugin. It is strongly discouraged to rely on this feature. Please report missing features on our GitHub page!') | format('', '') }}
@@ -528,7 +528,7 @@ POSSIBILITY OF SUCH DAMAGE.
{{ 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._("%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._("For more details visit HAProxy's official documentation regarding the %sError Messages%s and the %sLua Script%s features.") | format('', '', '', '') }}
+ {{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s and the %sLua Script%s features.") | format('', '', '', '') }}
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 dd8db755c..a4b193405 100644
--- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf
+++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf
@@ -3,6 +3,15 @@
# Do not edit this file manually.
{% if helpers.exists('OPNsense.HAProxy') %}
+{# ############################### #}
+{# GLOBAL VARIABLES #}
+{# ############################### #}
+
+{%- if helpers.exists('OPNsense.HAProxy.general.peers') and OPNsense.HAProxy.general.peers.enabled|default("") == "1" -%}
+{% set peers_enabled = True %}
+{% set peers_name = 'opnsense-haproxy-peers' %}
+{%- endif -%}
+
{# ############################### #}
{# MACROS #}
{# ############################### #}
@@ -172,6 +181,36 @@
{% set acl_enabled = '0' %}
# ERROR: missing parameters
{% endif %}
+{% elif acl_data.expression == 'src_is_local' %}
+{% do acl_options.append('src_is_local') %}
+{% elif acl_data.expression == 'src_bytes_in_rate' %}
+{% do acl_options.append('src_bytes_in_rate ' ~ acl_data.src_bytes_in_rate_comparison ~ ' ' ~ acl_data.src_bytes_in_rate) %}
+{% elif acl_data.expression == 'src_bytes_out_rate' %}
+{% do acl_options.append('src_bytes_out_rate ' ~ acl_data.src_bytes_out_rate_comparison ~ ' ' ~ acl_data.src_bytes_out_rate) %}
+{% elif acl_data.expression == 'src_conn_cnt' %}
+{% do acl_options.append('src_conn_cnt ' ~ acl_data.src_conn_cnt_comparison ~ ' ' ~ acl_data.src_conn_cnt) %}
+{% elif acl_data.expression == 'src_conn_cur' %}
+{% do acl_options.append('src_conn_cur ' ~ acl_data.src_conn_cur_comparison ~ ' ' ~ acl_data.src_conn_cur) %}
+{% elif acl_data.expression == 'src_conn_rate' %}
+{% do acl_options.append('src_conn_rate ' ~ acl_data.src_conn_rate_comparison ~ ' ' ~ acl_data.src_conn_rate) %}
+{% elif acl_data.expression == 'src_http_err_cnt' %}
+{% do acl_options.append('src_http_err_cnt ' ~ acl_data.src_http_err_cnt_comparison ~ ' ' ~ acl_data.src_http_err_cnt) %}
+{% elif acl_data.expression == 'src_http_err_rate' %}
+{% do acl_options.append('src_http_err_rate ' ~ acl_data.src_http_err_rate_comparison ~ ' ' ~ acl_data.src_http_err_rate) %}
+{% elif acl_data.expression == 'src_http_req_cnt' %}
+{% do acl_options.append('src_http_req_cnt ' ~ acl_data.src_http_req_cnt_comparison ~ ' ' ~ acl_data.src_http_req_cnt) %}
+{% elif acl_data.expression == 'src_http_req_rate' %}
+{% do acl_options.append('src_http_req_rate ' ~ acl_data.src_http_req_rate_comparison ~ ' ' ~ acl_data.src_http_req_rate) %}
+{% elif acl_data.expression == 'src_kbytes_in' %}
+{% do acl_options.append('src_kbytes_in ' ~ acl_data.src_kbytes_in_comparison ~ ' ' ~ acl_data.src_kbytes_in) %}
+{% elif acl_data.expression == 'src_kbytes_out' %}
+{% do acl_options.append('src_kbytes_out ' ~ acl_data.src_kbytes_out_comparison ~ ' ' ~ acl_data.src_kbytes_out) %}
+{% elif acl_data.expression == 'src_port' %}
+{% do acl_options.append('src_port ' ~ acl_data.src_port_comparison ~ ' ' ~ acl_data.src_port) %}
+{% elif acl_data.expression == 'src_sess_cnt' %}
+{% do acl_options.append('src_sess_cnt' ~ acl_data.src_sess_cnt_comparison ~ ' ' ~ acl_data.src_sess_cnt) %}
+{% elif acl_data.expression == 'src_sess_rate' %}
+{% do acl_options.append('src_sess_rate ' ~ acl_data.src_sess_rate_comparison ~ ' ' ~ acl_data.src_sess_rate) %}
{% elif acl_data.expression == 'nbsrv' %}
{% do acl_options.append('') %}
{% if acl_data.nbsrv|default("") != "" %}
@@ -455,6 +494,87 @@
{% endif %}
{%- endmacro %}
+{# Macro expects a backend or frontend object. #}
+{% macro StickTableConfig(proxy, backend=False) -%}
+{% if proxy is defined %}
+{# # check if stickiness is disabled (set to "None") #}
+{% if proxy.stickiness_pattern|default("") != "" %}
+ # stickiness
+{# # check if additional data types are configured #}
+{% if proxy.stickiness_dataTypes|default("") != "" %}
+{% set stickiness_datatypes = [] %}
+{% for datatype in proxy.stickiness_dataTypes.split(",") %}
+{# # add time period to all types where this is required #}
+{% if datatype == 'conn_rate' %}
+{% do stickiness_datatypes.append(datatype ~ '(' ~ proxy.stickiness_connRatePeriod ~ ')') %}
+{% elif datatype == 'sess_rate' %}
+{% do stickiness_datatypes.append(datatype ~ '(' ~ proxy.stickiness_sessRatePeriod ~ ')') %}
+{% elif datatype == 'http_req_rate' %}
+{% do stickiness_datatypes.append(datatype ~ '(' ~ proxy.stickiness_httpReqRatePeriod ~ ')') %}
+{% elif datatype == 'http_err_rate' %}
+{% do stickiness_datatypes.append(datatype ~ '(' ~ proxy.stickiness_httpErrRatePeriod ~ ')') %}
+{% elif datatype == 'bytes_in_rate' %}
+{% do stickiness_datatypes.append(datatype ~ '(' ~ proxy.stickiness_bytesInRatePeriod ~ ')') %}
+{% elif datatype == 'bytes_out_rate' %}
+{% do stickiness_datatypes.append(datatype ~ '(' ~ proxy.stickiness_bytesOutRatePeriod ~ ')') %}
+{% else %}
+{% do stickiness_datatypes.append(datatype) %}
+{% endif %}
+{% endfor %}
+{% set stickiness_store = 'store ' ~ stickiness_datatypes|join(',') %}
+{% endif %}
+{# # check stick-table type #}
+{% if proxy.stickiness_pattern == "sourceipv4" or proxy.stickiness_pattern == "ipv4" %}
+{% set table_type = 'ip' %}
+{% elif proxy.stickiness_pattern == "sourceipv6" or proxy.stickiness_pattern == "ipv6" %}
+{% set table_type = 'ipv6' %}
+{% elif proxy.stickiness_pattern == "cookievalue" or proxy.stickiness_pattern == "string" %}
+{% set table_type = 'string' %}
+{% set add_length = True %}
+{% elif proxy.stickiness_pattern == "rdpcookie" or proxy.stickiness_pattern == "binary" %}
+{% set table_type = 'binary' %}
+{% set add_length = True %}
+{% elif proxy.stickiness_pattern == "integer" %}
+{% set table_type = 'integer' %}
+{% endif %}
+{# # check data length #}
+{% if add_length is defined %}
+{% if proxy.stickiness_cookielength is defined %}
+{% set data_length = proxy.stickiness_cookielength %}
+{% elif proxy.stickiness_length is defined %}
+{% set data_length = proxy.stickiness_length %}
+{% else %}
+{% set data_length = '32' %}
+{% endif %}
+{% endif %}
+{# # add stick-table #}
+{% if table_type is defined %}
+ stick-table type {{table_type}} {%if add_length is defined %}len {{data_length}} {% endif %}size {{proxy.stickiness_size}} expire {{proxy.stickiness_expire}} {{stickiness_store}} {% if peers_enabled is defined %}{{'peers ' ~ peers_name}}{% endif %}
+
+{% endif %}
+{# # sticky counters (frontends only) #}
+{%- if backend == False -%}
+{%- if proxy.stickiness_counter|default("0") == "1" and proxy.stickiness_counter_key != '' %}
+ tcp-request connection track-sc0 {{proxy.stickiness_counter_key}}
+{%- endif -%}
+{%- endif -%}
+{# # stick-table persistence (backends only) #}
+{%- if backend == True -%}
+{%- if proxy.stickiness_pattern == "cookievalue" %}
+ stick store-response res.cook({{proxy.stickiness_cookiename}})
+ stick on req.cook({{proxy.stickiness_cookiename}})
+{%- elif proxy.stickiness_pattern == "rdpcookie" %}
+ stick on req.rdp_cookie(mstshash)
+{%- elif proxy.stickiness_pattern != '' %}
+ stick on src
+{%- endif -%}
+{%- endif -%}
+{% endif %}
+{% else %}
+# ERROR: StickTableConfig called with empty data
+{% endif %}
+{%- endmacro -%}
+
{% if not (helpers.exists('OPNsense.HAProxy.general') and OPNsense.HAProxy.general.enabled|default("0") == "1") %}
#
# NOTE: HAProxy is currently DISABLED
@@ -608,7 +728,15 @@ frontend {{frontend.name}}
{% endif %}
{# # HSTS #}
{% if frontend.ssl_hstsEnabled|default("") == '1' and frontend.mode == 'http' %}
- http-response set-header Strict-Transport-Security max-age={{frontend.ssl_hstsMaxAge}}
+{% set hsts_options = [] %}
+{% do hsts_options.append('max-age=' ~ frontend.ssl_hstsMaxAge) %}
+{% if frontend.ssl_hstsIncludeSubDomains|default("") == '1' %}
+{% do hsts_options.append('; includeSubDomains') %}
+{% endif %}
+{% if frontend.ssl_hstsPreload|default("") == '1' %}
+{% do hsts_options.append('; preload') %}
+{% endif %}
+ http-response set-header Strict-Transport-Security "{{ hsts_options|join('') }}"
{% endif %}
{% endif %}
{% endif %}
@@ -644,6 +772,14 @@ frontend {{frontend.name}}
{% elif OPNsense.HAProxy.general.defaults.timeoutClient is defined %}
timeout client {{OPNsense.HAProxy.general.defaults.timeoutClient}}
{% endif %}
+{% if frontend.tuning_timeoutHttpReq|default("") != "" and frontend.mode == 'http' %}
+ timeout http-request {{frontend.tuning_timeoutHttpReq}}
+{% endif %}
+{% if frontend.tuning_timeoutHttpKeepAlive|default("") != "" and frontend.mode == 'http' %}
+ timeout http-keep-alive {{frontend.tuning_timeoutHttpKeepAlive}}
+{% endif %}
+{# # call macro to evaluate stickiness config #}
+{{ StickTableConfig(frontend) }}
# logging options
{% if frontend.logging_dontLogNull=='1' %}
option dontlognull
@@ -802,24 +938,8 @@ backend {{backend.name}}
{# # (redundant) GUI option for this. #}
mode {{backend.mode}}
balance {{backend.algorithm}}
-{# # ignore if stickiness is disabled (set to "None") #}
-{% if backend.stickiness_pattern|default("") != "" %}
- # stickiness
-{% if backend.stickiness_pattern == "sourceipv4" %}
- stick-table type ip size {{backend.stickiness_size}} expire {{backend.stickiness_expire}}
- stick on src
-{% elif backend.stickiness_pattern == "sourceipv6" %}
- stick-table type ipv6 size {{backend.stickiness_size}} expire {{backend.stickiness_expire}}
- stick on src
-{% elif backend.stickiness_pattern == "cookievalue" %}
- stick-table type string len {{backend.stickiness_cookielength}} size {{backend.stickiness_size}} expire {{backend.stickiness_expire}}
- stick store-response res.cook({{backend.stickiness_cookiename}})
- stick on req.cook({{backend.stickiness_cookiename}})
-{% elif backend.stickiness_pattern == "rdpcookie" %}
- stick-table type binary len {{backend.stickiness_cookielength}} size {{backend.stickiness_size}} expire {{backend.stickiness_expire}}
- stick on req.rdp_cookie(mstshash)
-{% endif %}
-{% endif %}
+{# # call macro to evaluate stickiness config #}
+{{ StickTableConfig(backend,true) }}
# tuning options
{% if backend.tuning_timeoutConnect|default("") != "" %}
timeout connect {{backend.tuning_timeoutConnect}}
@@ -948,6 +1068,24 @@ backend {{backend.name}}
{% endfor %}
{% endif %}
+{# ############################### #}
+{# PEERS #}
+{# ############################### #}
+
+{% if helpers.exists('OPNsense.HAProxy.general.peers') and OPNsense.HAProxy.general.peers.enabled|default("") == "1" %}
+{# # ensure that no value is missing #}
+{% if OPNsense.HAProxy.general.peers.name1|default("") != '' and
+ OPNsense.HAProxy.general.peers.listen1|default("") != '' and
+ OPNsense.HAProxy.general.peers.port1|default("") != '' and
+ OPNsense.HAProxy.general.peers.name2|default("") != '' and
+ OPNsense.HAProxy.general.peers.listen2|default("") != '' and
+ OPNsense.HAProxy.general.peers.port2|default("") != '' %}
+peers {{peers_name}}
+ peer {{OPNsense.HAProxy.general.peers.name1}} {{OPNsense.HAProxy.general.peers.listen1}}:{{OPNsense.HAProxy.general.peers.port1}}
+ peer {{OPNsense.HAProxy.general.peers.name2}} {{OPNsense.HAProxy.general.peers.listen2}}:{{OPNsense.HAProxy.general.peers.port2}}
+{% endif %}
+{% endif %}
+
{# ############################### #}
{# STATISTICS #}
{# ############################### #}