diff --git a/languages/en_US/helptext.txt b/languages/en_US/helptext.txt index e2cfe5bed..91440fa6f 100644 --- a/languages/en_US/helptext.txt +++ b/languages/en_US/helptext.txt @@ -1153,6 +1153,13 @@ Select **Strict** to enable *exclusive* use of an Unraid.net SSL certificate for https access (see **Provision** below). Note that a DNS server must be reachable. +**Redirects:** When accessing `http://` or `http://.`, the +behavior will change depending on the value of the Use SSL/TLS setting: + +* If Use SSL/TLS is set to **Strict**, you will be redirected to `https://..myunraid.net` +* If Use SSL/TLS is set to **Yes**, you will be redirected to `https:// or https://.` +* If Use SSL/TLS is set to **No**, then the http url will load directly. + Important: **Strict** may not be selectable if your router or upstream DNS server has [DNS rebinding protection](https://en.wikipedia.org/wiki/DNS_rebinding) enabled. DNS rebinding protection prevents DNS from resolving a private IP network range. DNS rebinding protection is meant as @@ -1200,6 +1207,11 @@ Enter the HTTPS port, default port is 443. Enter your local Top Level Domain. May be blank. :end +:mgmt_local_access_urls_help: +The Local Access URLs shown above are based on your current settings. +To adjust URLs or redirects, see the help text for "Use SSL/TLS". +:end + :mgmt_certificate_expiration_help: **Provision** may be used to install a *free* Unraid.net SSL Certificate from [Let's Encrypt](https://letsencrypt.org/). diff --git a/plugins/dynamix/ManagementAccess.page b/plugins/dynamix/ManagementAccess.page index 87032d76a..3a047b569 100644 --- a/plugins/dynamix/ManagementAccess.page +++ b/plugins/dynamix/ManagementAccess.page @@ -38,6 +38,19 @@ function find_tasks() { sort($tasks); return $tasks; } +function acceptableCert($certFile, $hostname, $expectedURL) { + if (!file_exists($certFile)) return false; + $certURLs=null; + // get Subject URL and all SAN URLs from cert + exec("openssl x509 -noout -subject -nameopt multiline -in $certFile | sed -n 's/ *commonName *= //p' ; openssl x509 -noout -ext subjectAltName -in $certFile | grep -Eo \"DNS:[a-zA-Z 0-9.*-]*\" | sed \"s/DNS://g\"", $certURLs); + foreach($certURLs as $certURL) { + // adjust for wildcard certs + $certURL = str_replace('*', $hostname, $certURL); + // case-insensitive compare + if (strcasecmp($certURL, $expectedURL) == 0) return true; + } + return false; +} $tasks = find_tasks(); $ethX = 'eth0'; #$addr = ipaddr($ethX); @@ -45,29 +58,41 @@ $addr = $_SERVER['SERVER_ADDR']; $keyfile = @file_get_contents($var['regFILE']); if ($keyfile !== false) $keyfile = base64_encode($keyfile); -$certFile = "/boot/config/ssl/certs/certificate_bundle.pem"; -$certPresent = file_exists("$certFile"); -if ($certPresent) { - $certSubject = exec("/usr/bin/openssl x509 -in $certFile -noout -subject -nameopt multiline 2>/dev/null|sed -n 's/ *commonName *= //p'"); - $certIssuer = exec("/usr/bin/openssl x509 -in $certFile -noout -text | sed -n -e 's/^.*Issuer: //p'"); - $certExpires = exec("/usr/bin/openssl x509 -in $certFile -noout -text | sed -n -e 's/^.*Not After : //p'"); - $isLegacyCert = preg_match('/.*\.unraid\.net$/', $certSubject); - $isWildcardCert = preg_match('/.*\.myunraid\.net$/', $certSubject); +// self-signed or user-provided cert +$cert1File = "/boot/config/ssl/certs/{$var['NAME']}_unraid_bundle.pem"; +$cert1Present = file_exists("$cert1File"); +if ($cert1Present) { + $cert1URL = $var['NAME'].".".$var['LOCAL_TLD']; + // if user replaced cert without reloading nginx, the cert on the flash could be invalid + $cert1URLvalid = acceptableCert($cert1File, $var['NAME'], $cert1URL); + $cert1Issuer = exec("/usr/bin/openssl x509 -in $cert1File -noout -text | sed -n -e 's/^.*Issuer: //p'"); + $cert1Expires = exec("/usr/bin/openssl x509 -in $cert1File -noout -text | sed -n -e 's/^.*Not After : //p'"); +} + +// unraid.net, myunraid.net LE cert. could potentially be user provided as well +$cert2File = "/boot/config/ssl/certs/certificate_bundle.pem"; +$cert2Present = file_exists("$cert2File"); +if ($cert2Present) { + $cert2Subject = exec("/usr/bin/openssl x509 -in $cert2File -noout -subject -nameopt multiline 2>/dev/null|sed -n 's/ *commonName *= //p'"); + $cert2Issuer = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Issuer: //p'"); + $cert2Expires = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Not After : //p'"); + $isLegacyCert = preg_match('/.*\.unraid\.net$/', $cert2Subject); + $isWildcardCert = preg_match('/.*\.myunraid\.net$/', $cert2Subject); $isLEcert = $isLegacyCert || $isWildcardCert; - $subjectURL = $certSubject; + $subject2URL = $cert2Subject; if ($isWildcardCert) { if (strpos($addr, ":") === false) - $subjectURL = str_replace("*", str_replace(".", "-", $addr), $subjectURL); + $subject2URL = str_replace("*", str_replace(".", "-", $addr), $subject2URL); else - $subjectURL = str_replace("*", str_replace(":", "-", $addr), $subjectURL); + $subject2URL = str_replace("*", str_replace(":", "-", $addr), $subject2URL); } if ($isLEcert) { - exec("openssl x509 -checkend 2592000 -noout -in $certFile 2>/dev/null", $arrout, $retval_expired); + exec("openssl x509 -checkend 2592000 -noout -in $cert2File 2>/dev/null", $arrout, $retval_expired); if (strpos($addr, ":") === false) { $rebindtest_ip = exec("host -4 -t A rebindtest4.myunraid.net 2>/dev/null|awk '{print \$4}'"); $dnsRebindingProtection = ($rebindtest_ip != "192.168.42.42"); if (!$dnsRebindingProtection) { - $cert_ip = exec("host -4 -t A $subjectURL 2>/dev/null|awk '{print \$4}'"); + $cert_ip = exec("host -4 -t A $subject2URL 2>/dev/null|awk '{print \$4}'"); $dnsValid = $cert_ip==$addr; } } else { @@ -76,18 +101,53 @@ if ($certPresent) { // $dnsRebindingProtection = ($rebindtest_ip != "fd42::42"); $dnsRebindingProtection = ($rebindtest_ip != "fd42::42") && ($rebindtest_ip != "fd42::"); if (!$dnsRebindingProtection) { - $cert_ip = exec("host -6 -t AAAA $subjectURL 2>/dev/null|awk '{print \$4}'"); + $cert_ip = exec("host -6 -t AAAA $subject2URL 2>/dev/null|awk '{print \$4}'"); $dnsValid = $cert_ip==$addr; } } } } +$nginx = parse_ini_file('/var/local/emhttp/nginx.ini'); +$http_port = $var['PORT'] != 80 ? ":{$var['PORT']}" : ''; +$https_port = $var['PORTSSL'] != 443 ? ":{$var['PORTSSL']}" : ''; + +$http_ip_url = "http://{$nginx['NGINX_LANIP']}{$http_port}/"; +$http_url = "http://{$nginx['NGINX_LANMDNS']}{$http_port}/"; +$https_ip_url = "https://{$nginx['NGINX_LANIP']}{$https_port}/"; +$https_url = "https://{$nginx['NGINX_LANMDNS']}{$https_port}/"; +$https_2_url = "https://{$nginx['NGINX_LANFQDN']}{$https_port}/"; + +$urls = array(); +// push an array of three values into the $urls array: +// 0 - the url +// 1 - the url it redirects to, or null +// 2 - the certificate file used, or null +switch($var['USE_SSL']) { + case 'no': + $urls[] = [$http_ip_url, null, null]; + $urls[] = [$http_url, null, null]; + if ($nginx['NGINX_LANFQDN']) $urls[] = [$https_2_url, null, "certificate_bundle.pem"]; + break; + case 'yes': + $urls[] = [$http_ip_url, $https_ip_url, null]; + $urls[] = [$https_ip_url, null, "{$var['NAME']}_unraid_bundle.pem"]; + $urls[] = [$http_url, $https_url, null]; + $urls[] = [$https_url, null, "{$var['NAME']}_unraid_bundle.pem"]; + if ($nginx['NGINX_LANFQDN']) $urls[] = [$https_2_url, null, "certificate_bundle.pem"]; + break; + case 'auto': // aka strict + $urls[] = [$http_ip_url, $https_2_url, null]; + $urls[] = [$http_url, $https_2_url, null]; + $urls[] = [$https_2_url, null, "certificate_bundle.pem"]; + break; +} + $cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replace(['%M','%R'],['%M:%S','%R:%S'],$display['time']):''); $provisionlabel = $isLEcert ? _('Renew') : _('Provision'); $disabled_provision = $keyfile===false || ($isLEcert && $retval_expired===0) ? 'disabled' : ''; $disabled_updatedns = $keyfile!==false && $isLEcert ? '' : 'disabled'; -$disabled_delete = $certPresent && $var['USE_SSL']!='auto' ? '' : 'disabled'; +$disabled_delete = $cert2Present && $var['USE_SSL']!='auto' ? '' : 'disabled'; $disabled_auto = $isLEcert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled'; $upgradelabel = _('Upgrade Cert'); @@ -275,22 +335,68 @@ _(Local TLD)_: : + +
+
+ +
"._("Local Access URLs").":
\n"; +echo "

    \n"; +foreach($urls as $url) { + if ($url[1]) $msg = " ("._("redirects to")." {$url[1]})"; + if ($url[2]) $msg = " ("._("uses certificate")." {$url[2]} )"; + echo "
  • {$url[0]}{$msg}
  • \n"; +} +echo "
\n"; +?> + +:mgmt_local_access_urls_help: + +
+ +
+
+ +_(Self-signed or user-provided certificate)_: +: + + +_(Certificate URL)_: +: [](https://:) + +_(Certificate URL)_: +: Certificate not valid for + + +_(Certificate issuer)_: +: + +_(Certificate expiration)_: +: + + +_(Self-signed certificate file)_: +: _(Not present)_ + + +
+
"> - -_(CA-signed certificate file)_: -: + +_(Unraid Let's Encrypt certificate)_: +: -_(Certificate subject)_: -: [](https://:) +_(Certificate URL)_: +: [](https://:) _(Certificate issuer)_: -: +: _(Certificate expiration)_: -: +:   @@ -309,7 +415,7 @@ _(CA-signed certificate file)_:   : - +   :