Skip to content

Commit 1d2b56e

Browse files
committed
security/acme-client: fix IPv6 support HTTP-01 and TLS-ALPN-01 challenges
Underlying issue: IPv6 features multiple scopes restricting where the IP address is valid [1]. ::1 belongs to link-local scope which is not allowed to be routed. As result FreeBSD will reject the connection after rewriting, as it will come from global scope (the internet) and going to ::1 [2]. This isn't allowed. The fix / workaround: Instead of redirecting to ::1, the following is tried: * If there is a WAN interface with an IPv6 address defined, redirect to this address. I expect most setup with IPv6 to have a WAN interface with a suitable (=allowed scope) IPv6 address. * Else, only redirect the port and leave the address unchanged. This will only work if we are issuing a certificate for ourselves (rather than a host behind the firewall). A better solution would be to pick an arbitrary IPv6 address of the host with a suitable scope. However, I believe this would be considerably more complex to implement and test. I propose we use this simplified approach, at least for now, which should already work for the vast majority of users. [1]: https://en.wikipedia.org/wiki/IPv6_address#Address_scopes [2]: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568
1 parent e46a70e commit 1d2b56e

3 files changed

Lines changed: 59 additions & 10 deletions

File tree

security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeValidation/HttpOpnsense.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,34 @@ public function prepare()
9191
$_ipv6_enabled = false;
9292
}
9393

94+
// Find redirect target for IPv6
95+
//
96+
// Needed because redirecting to ::1 isn't allowed [1].
97+
//
98+
// [1]: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568
99+
$ipv6_redirect_addr = null;
100+
if ($_ipv6_enabled == true) {
101+
$backend = new \OPNsense\Core\Backend();
102+
$interface = "wan";
103+
$response = json_decode($backend->configdpRun('interface address', [$interface]));
104+
105+
$ipv6_redirect_addr = null;
106+
if (isset($response->$interface)) {
107+
foreach ($response->$interface as $if) {
108+
if (!empty($if->address) && $if->family == "inet6") {
109+
$ipv6_redirect_addr = $if->address;
110+
break;
111+
}
112+
}
113+
}
114+
115+
if ($ipv6_redirect_addr != null) {
116+
LeUtils::log("found IPv6 on WAN interface, will redirect traffic there ({$ipv6_redirect_addr})");
117+
} else {
118+
LeUtils::log("failed to find IPv6 on WAN interface ($interface), will not rewrite target address");
119+
}
120+
}
121+
94122
// Generate rules for all IP addresses
95123
$anchor_rules = "";
96124
if (!empty($iplist)) {
@@ -104,7 +132,7 @@ public function prepare()
104132
LeUtils::log("using IPv4 address: {$ip}");
105133
} elseif (($_ipv6_enabled == true) && (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))) {
106134
// IPv6
107-
$_dst = '::1';
135+
$_dst = $ipv6_redirect_addr != null ? $ipv6_redirect_addr : $ip;
108136
$_family = 'inet6';
109137
LeUtils::log("using IPv6 address: {$ip}");
110138
} else {

security/acme-client/src/opnsense/mvc/app/library/OPNsense/AcmeClient/LeValidation/TlsalpnAcme.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,34 @@ public function prepare()
9292
$_ipv6_enabled = false;
9393
}
9494

95+
// Find redirect target for IPv6
96+
//
97+
// Needed because redirecting to ::1 isn't allowed [1].
98+
//
99+
// [1]: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193568
100+
$ipv6_redirect_addr = null;
101+
if ($_ipv6_enabled == true) {
102+
$backend = new \OPNsense\Core\Backend();
103+
$interface = "wan";
104+
$response = json_decode($backend->configdpRun('interface address', [$interface]));
105+
106+
$ipv6_redirect_addr = null;
107+
if (isset($response->$interface)) {
108+
foreach ($response->$interface as $if) {
109+
if (!empty($if->address) && $if->family == "inet6") {
110+
$ipv6_redirect_addr = $if->address;
111+
break;
112+
}
113+
}
114+
}
115+
116+
if ($ipv6_redirect_addr != null) {
117+
LeUtils::log("found IPv6 on WAN interface, will redirect traffic there ({$ipv6_redirect_addr})");
118+
} else {
119+
LeUtils::log("failed to find IPv6 on WAN interface ($interface), will not rewrite target address");
120+
}
121+
}
122+
95123
// Generate rules for all IP addresses
96124
$anchor_rules = "";
97125
if (!empty($iplist)) {
@@ -105,7 +133,7 @@ public function prepare()
105133
LeUtils::log("using IPv4 address: {$ip}");
106134
} elseif (($_ipv6_enabled == true) && (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))) {
107135
// IPv6
108-
$_dst = '::1';
136+
$_dst = $ipv6_redirect_addr != null ? $ipv6_redirect_addr : $ip;
109137
$_family = 'inet6';
110138
LeUtils::log("using IPv6 address: {$ip}");
111139
} else {

security/acme-client/src/opnsense/service/templates/OPNsense/AcmeClient/lighttpd-acme-challenge.conf

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# FreeBSD!
88
server.event-handler = "freebsd-kqueue"
99
server.network-backend = "writev"
10-
#server.use-ipv6 = "enable"
10+
server.use-ipv6 = "{{ 'enable' if helpers.exists('system.ipv6allow') or system.ipv6allow|default("1") == "1" else 'disable' }}"
1111

1212
# modules to load
1313
server.modules = ( "mod_access", "mod_expire", "mod_deflate", "mod_redirect",
@@ -60,14 +60,7 @@ mimetype.assign = (
6060
url.access-deny = ( "~", ".inc" )
6161

6262
# bind to port
63-
server.bind = "127.0.0.1"
6463
server.port = {{OPNsense.AcmeClient.settings.challengePort}}
65-
$SERVER["socket"] == "127.0.0.1:{{OPNsense.AcmeClient.settings.challengePort}}" { }
66-
67-
{% if not helpers.exists('system.ipv6allow') or system.ipv6allow|default("1") == "1" %}
68-
# IPv6
69-
$SERVER["socket"] == "[::1]:{{OPNsense.AcmeClient.settings.challengePort}}" { }
70-
{% endif %}
7164

7265
# to help the rc.scripts
7366
server.pid-file = "/var/run/lighttpd-acme-challenge.pid"

0 commit comments

Comments
 (0)