diff --git a/www/caddy/pkg-descr b/www/caddy/pkg-descr
index 4edfff9d1..df004fa8c 100644
--- a/www/caddy/pkg-descr
+++ b/www/caddy/pkg-descr
@@ -33,6 +33,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
+* Add: Layer4 Remote IP matcher to restrict access to proxied services
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 307937560..bbc7d6b30 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
@@ -61,4 +61,17 @@
dropdown
+
+ header
+
+ true
+
+
+ layer4.RemoteIp
+
+ select_multiple
+
+ true
+
+
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 b27125460..d3c0d2ed2 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
@@ -438,6 +438,12 @@
v2
+
+ ,
+ Y
+ Y
+ Please enter one or multiple valid IP addresses or networks.
+
diff --git a/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/reverse_proxy.volt b/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/reverse_proxy.volt
index 4df185cc7..f16163beb 100644
--- a/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/reverse_proxy.volt
+++ b/www/caddy/src/opnsense/mvc/app/views/OPNsense/Caddy/reverse_proxy.volt
@@ -561,6 +561,7 @@
{{ lang._('Matcher') }} |
{{ lang._('Upstream Domain') }} |
{{ lang._('Upstream Port') }} |
+ {{ lang._('Remote IP') }} |
{{ lang._('Fail Duration') }} |
{{ lang._('Proxy Protocol') }} |
{{ lang._('Description') }} |
diff --git a/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4 b/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4
index c6a20dab4..7eb367b6b 100644
--- a/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4
+++ b/www/caddy/src/opnsense/service/templates/OPNsense/Caddy/includeLayer4
@@ -5,8 +5,8 @@
#}
{% set layer4_configs = helpers.toList('Pischem.caddy.reverseproxy.layer4') %}
-{# Define a macro for setting up the proxy #}
-{% macro setup_proxy(to_domains, to_port, fail_duration, proxy_protocol) %}
+{# Nested Macro for proxy definition #}
+{% macro define_proxy(to_domains, to_port, fail_duration, proxy_protocol) %}
proxy {% for domain in to_domains.split(',') %}
{% set is_ipv6 = (':' in domain) %} {# Check if the domain contains a colon, typical in IPv6 addresses #}
{{ '[' if is_ipv6 }}{{ domain }}{{ ']' if is_ipv6 }}:{{ to_port }}{% if not loop.last %} {% endif %}
@@ -20,6 +20,23 @@
}
{% endmacro %}
+{# Macro for configuring the proxy with additional remote IP access list #}
+{% macro configure_proxy(to_domains, to_port, remote_ips, fail_duration, proxy_protocol) %}
+ {% if remote_ips %}
+ {% set ip_list = remote_ips.split(',') %}
+ subroute {
+ @allowed_ips remote_ip {{ ip_list|join(' ') }}
+ route @allowed_ips {
+ {# Call Nested Macro #}
+ {{ define_proxy(to_domains, to_port, fail_duration, proxy_protocol) }}
+ }
+ }
+ {% else %}
+ {# Call Nested Macro #}
+ {{ define_proxy(to_domains, to_port, fail_duration, proxy_protocol) }}
+ {% endif %}
+{% endmacro %}
+
{# Set up Layer4 App #}
layer4 {
import /usr/local/etc/caddy/caddy.d/*.layer4
@@ -28,7 +45,7 @@ layer4 {
{% 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) }}
+ {{ configure_proxy(layer4.ToDomain, layer4.ToPort, layer4.RemoteIp, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
}
{% endif %}
{% endfor %}
@@ -37,7 +54,7 @@ layer4 {
{% if layer4.enabled == "1" and layer4.Matchers == 'httphost' %}
@{{ layer4['@uuid'] }} http host {{ layer4.FromDomain.replace(',', ' ') }}
route @{{ layer4['@uuid'] }} {
- {{ setup_proxy(layer4.ToDomain, layer4.ToPort, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
+ {{ configure_proxy(layer4.ToDomain, layer4.ToPort, layer4.RemoteIp, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
}
{% endif %}
{% endfor %}
@@ -46,7 +63,7 @@ layer4 {
{% if layer4.enabled == "1" and layer4.Matchers == 'tlssni' %}
@{{ layer4['@uuid'] }} tls sni {{ layer4.FromDomain.replace(',', ' ') }}
route @{{ layer4['@uuid'] }} {
- {{ setup_proxy(layer4.ToDomain, layer4.ToPort, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
+ {{ configure_proxy(layer4.ToDomain, layer4.ToPort, layer4.RemoteIp, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
}
{% endif %}
{% endfor %}
@@ -55,7 +72,7 @@ layer4 {
{% if layer4.enabled == "1" and layer4.Matchers == 'nottlssni' %}
@{{ layer4['@uuid'] }} not tls sni {{ layer4.FromDomain.replace(',', ' ') }}
route @{{ layer4['@uuid'] }} {
- {{ setup_proxy(layer4.ToDomain, layer4.ToPort, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
+ {{ configure_proxy(layer4.ToDomain, layer4.ToPort, layer4.RemoteIp, layer4.PassiveHealthFailDuration, layer4.ProxyProtocol) }}
}
{% endif %}
{% endfor %}