From 90b49ceca34d037fd3073622d807f27e28b27d29 Mon Sep 17 00:00:00 2001 From: Monviech <79600909+Monviech@users.noreply.github.com> Date: Wed, 31 Jul 2024 11:42:40 +0200 Subject: [PATCH] www/caddy: Add remaining compatible Layer4 traffic matchers (#4133) * www/caddy: Add Layer4 SSH traffic matcher. * www/caddy: Restructure Layer4 protocol names. * www/caddy: Also change the names in the help text. * www/caddy: Generalize additional protocol handling, add remaining supported protocols for layer4 routing. --- www/caddy/pkg-descr | 1 + .../OPNsense/Caddy/forms/dialogLayer4.xml | 4 +-- .../mvc/app/models/OPNsense/Caddy/Caddy.php | 34 +++++++++++++++++++ .../mvc/app/models/OPNsense/Caddy/Caddy.xml | 13 +++++-- .../templates/OPNsense/Caddy/includeLayer4 | 15 ++++++-- 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/www/caddy/pkg-descr b/www/caddy/pkg-descr index d8a139e4c..4edfff9d1 100644 --- a/www/caddy/pkg-descr +++ b/www/caddy/pkg-descr @@ -32,6 +32,7 @@ Plugin Changelog * Add: Authentik as authentication provider (contributed by Tim-Sc) * Add: Feature Preview - Layer4 routing to proxy traffic without TLS termination. Can be enabled in advanced mode of "General Settings" +* Add: Layer4 protocols: HTTP, Postgres, Proxy Protocol, RDP, SOCKS4, SOCKS5, SSH, TLS, XMPP 1.6.1 diff --git a/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/forms/dialogLayer4.xml b/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/forms/dialogLayer4.xml index 8abb5e9fd..307937560 100644 --- a/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/forms/dialogLayer4.xml +++ b/www/caddy/src/opnsense/mvc/app/controllers/OPNsense/Caddy/forms/dialogLayer4.xml @@ -11,13 +11,13 @@ select_multiple true - + layer4.Matchers dropdown - + layer4.ToDomain diff --git a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.php b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.php index beca19c9c..c493ae9b6 100644 --- a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.php +++ b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.php @@ -266,6 +266,37 @@ class Caddy extends BaseModel } } + /** + * 6. Check that when certain Layer4 matchers are selected, only "*" is valid as FromDomain. + * This happens because they cannot be matched by host header or SNI, so they match all traffic. + * The "*" shows the user that all traffic will be matched, and that creating multiple + * matchers will not result in more routes for the same traffic type to work. + */ + private function checkLayer4Matchers($messages) + { + foreach ($this->reverseproxy->layer4->iterateItems() as $item) { + $matchers = (string) $item->Matchers; + $fromDomain = (string) $item->FromDomain; + + // Check if matchers is not in the list of specific values + $isNotInSpecificMatchers = !in_array($matchers, ['httphost', 'tlssni', 'nottlssni']); + $isInvalidFromDomain = $fromDomain !== '*'; + + if ($isNotInSpecificMatchers && $isInvalidFromDomain) { + $key = $item->__reference; + $messages->appendMessage(new Message( + sprintf( + gettext( + 'When "%s" matcher is selected, the only valid entry in Domain is "*".' + ), + $matchers + ), + $key . ".FromDomain" + )); + } + } + } + // Perform the actual validation public function performValidation($validateFullModel = false) { @@ -296,6 +327,9 @@ class Caddy extends BaseModel // 6. Check DisableSuperuser Port conflicts $this->checkSuperuserPorts($messages); + // 7. Check Layer4 matchers + $this->checkLayer4Matchers($messages); + return $messages; } } diff --git a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.xml b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.xml index 2ce870d44..b27125460 100644 --- a/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.xml +++ b/www/caddy/src/opnsense/mvc/app/models/OPNsense/Caddy/Caddy.xml @@ -405,9 +405,16 @@ Y tlssni - Host (HTTP) - SNI (TLS) - not SNI (TLS) + HTTP (Host Header) + Postgres + Proxy Protocol + RDP + SOCKSv4 + SOCKSv5 + SSH + TLS (SNI) + TLS (inverted SNI) + XMPP diff --git a/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4 b/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4 index a74eeeafd..c6a20dab4 100644 --- a/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4 +++ b/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4 @@ -23,7 +23,16 @@ {# Set up Layer4 App #} layer4 { import /usr/local/etc/caddy/caddy.d/*.layer4 - {# 1. loop to handle http host matchers #} + {# 1. loop to handle any traffic matchers that can only be added once since they match all specific protocol traffic. #} + {% for layer4 in layer4_configs %} + {% if layer4.enabled == "1" and layer4.Matchers not in ['httphost', 'tlssni', 'nottlssni'] %} + @{{ layer4['@uuid'] }} {{ layer4.Matchers }} + route @{{ layer4['@uuid'] }} { + {{ setup_proxy(layer4.ToDomain, layer4.ToPort, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }} + } + {% endif %} + {% endfor %} + {# 2. loop to handle http host matchers #} {% for layer4 in layer4_configs %} {% if layer4.enabled == "1" and layer4.Matchers == 'httphost' %} @{{ layer4['@uuid'] }} http host {{ layer4.FromDomain.replace(',', ' ') }} @@ -32,7 +41,7 @@ layer4 { } {% endif %} {% endfor %} - {# 2. loop to handle tls sni matchers #} + {# 3. loop to handle tls sni matchers #} {% for layer4 in layer4_configs %} {% if layer4.enabled == "1" and layer4.Matchers == 'tlssni' %} @{{ layer4['@uuid'] }} tls sni {{ layer4.FromDomain.replace(',', ' ') }} @@ -41,7 +50,7 @@ layer4 { } {% endif %} {% endfor %} - {# 3. loop to handle not tls sni matchers #} + {# 4. loop to handle not tls sni matchers #} {% for layer4 in layer4_configs %} {% if layer4.enabled == "1" and layer4.Matchers == 'nottlssni' %} @{{ layer4['@uuid'] }} not tls sni {{ layer4.FromDomain.replace(',', ' ') }}