diff --git a/CHANGELOG.md b/CHANGELOG.md index 387c06b1c..586a674ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ #### 2.652 (July, 2026) * Fix to recognize hex numeric HTML entities to work in various elements * Fix `patch` sub-command to reload Webmin instead of restarting +* Fix SSL certificate and TCP monitors to report connection, timeout and DNS failures as down or timed out rather than uninstalled #### 2.651 (June 28, 2026) * Fix Certbot-backed certificate requests and renewals to correctly parse PEM paths after issuance diff --git a/status/lang/en b/status/lang/en index 5aba641ad..9576fb4de 100644 --- a/status/lang/en +++ b/status/lang/en @@ -102,6 +102,7 @@ mon_down=Down mon_webmin=Webmin Down mon_timeout=Timed out mon_not=Not installed +mon_eload=Monitor program $1 failed to load : $2 mon_ondown=If monitor goes down, run command mon_onup=If monitor comes up, run command mon_ontimeout=If monitor times out, run command @@ -222,6 +223,8 @@ tcp_alarm=Connection timeout tcp_ehost=Missing or invalid hostname tcp_eport=Missing or invalid port number tcp_ealarm=Missing or invalid connection timeout +tcp_esocket=Failed to create TCP socket : $1 +tcp_eresolve=Failed to resolve host name $1 http_url=URL to request http_alarm=Connection timeout @@ -558,6 +561,7 @@ sslcert_eurl=Missing, invalid or non-SSL URL sslcert_efile=Missing or invalid certificate file sslcert_ecert=Could not get certificate sslcert_edown=Web server is down +sslcert_etimeout=Timed out connecting to web server sslcert_days=Days before expiry to fail sslcert_when=When expired sslcert_mismatch=Also detect hostname mismatch? diff --git a/status/sslcert-monitor.pl b/status/sslcert-monitor.pl index 7b8c9c9a3..c0f8baf74 100755 --- a/status/sslcert-monitor.pl +++ b/status/sslcert-monitor.pl @@ -2,6 +2,8 @@ sub get_sslcert_status { +# The openssl command is needed for all checks +&has_command("openssl") || return { 'up' => -1 }; local $up = 0; local $desc; local $certfile; @@ -21,12 +23,15 @@ if ($_[0]->{'url'}) { # don't support it $cmd = "openssl s_client -host ".quotemeta($host). " -port ".quotemeta($port)." &1"; - $out = &backquote_with_timeout($cmd, 10); + ($out, $timed) = &backquote_with_timeout($cmd, 10); } if ($?) { - # Connection failed - return { 'up' => -1, - 'desc' => $text{'sslcert_edown'} }; + # Connection failed or timed out, meaning the web server + # is down rather than the monitor being uninstalled + return $timed ? { 'up' => -3, + 'desc' => $text{'sslcert_etimeout'} } + : { 'up' => 0, + 'desc' => $text{'sslcert_edown'} }; } # Extract the cert part and save @@ -62,6 +67,11 @@ if ($info =~ /Not\s*Before\s*:\s*(.*)/i) { if ($info =~ /Not\s+After\s*:\s*(.*)/i) { $end = &mailboxes::parse_mail_date("$1"); } +if (!$end) { + # Certificate could not be parsed, so it cannot be considered OK + return { 'up' => 0, + 'desc' => $text{'sslcert_ecert'} }; + } local $now = time(); if ($start && $now < $start) { # Too new?! diff --git a/status/status-lib.pl b/status/status-lib.pl index 6a11ef597..a00d1e9de 100755 --- a/status/status-lib.pl +++ b/status/status-lib.pl @@ -168,7 +168,7 @@ foreach $r (&expand_remotes($serv)) { $remote_error_msg = undef; &remote_foreign_require($r, 'status', 'status-lib.pl') if (!$done_remote_status{$r}++); - my $webmindown = $s->{'type'} eq 'alive' ? 0 : -2; + my $webmindown = $serv->{'type'} eq 'alive' ? 0 : -2; if ($remote_error_msg) { $rv = { 'up' => $webmindown, 'desc' => "$text{'mon_webmin'} : $remote_error_msg" }; @@ -195,7 +195,11 @@ foreach $r (&expand_remotes($serv)) { } else { # Just include and use the local monitor library - do "${t}-monitor.pl" if (!$done_monitor{$t}++); + my $mfile = "$module_root_directory/${t}-monitor.pl"; + if (-r $mfile && !$done_monitor{$t}++) { + do $mfile; + $done_monitor_err{$t} = "$@" if ($@); + } my $func = "get_${t}_status"; if (defined(&$func)) { $rv = &$func($serv, @@ -203,7 +207,12 @@ foreach $r (&expand_remotes($serv)) { $fromcgi); } else { + # Monitor type is unknown, or its program + # failed to load $rv = { 'up' => -1 }; + $rv->{'desc'} = &text('mon_eload', $mfile, + $done_monitor_err{$t}) + if ($done_monitor_err{$t}); } } alarm(0); diff --git a/status/tcp-monitor.pl b/status/tcp-monitor.pl index 479b0c935..d4e3bf740 100755 --- a/status/tcp-monitor.pl +++ b/status/tcp-monitor.pl @@ -5,9 +5,11 @@ sub get_tcp_status { # Connect to the server socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname("tcp")) || - return { 'up' => -1 }; + return { 'up' => -3, + 'desc' => &text('tcp_esocket', $!) }; local $addr = inet_aton($_[0]->{'host'}); -return { 'up' => -1 } if (!$addr); +return { 'up' => 0, + 'desc' => &text('tcp_eresolve', $_[0]->{'host'}) } if (!$addr); local $st = time(); local $rv; eval { @@ -18,7 +20,7 @@ eval { alarm(0); }; return { 'up' => 0 } if ($@); -return { 'up' => $rv, +return { 'up' => $rv ? 1 : 0, 'time' => time() - $st }; }