Enable SSH and TLS handshake on prober for TCP22 and TCP443 ports

This commit is contained in:
ayurishchev committed 2026-08-26 23:52:31 +03:00
1 parent af3453f19f
commit 550ce3fec4
11 files changed
+308 -20

No files matched your search

+35
View File
@@ -0,0 +1,35 @@
package checkrunner
import (
"context"
"crypto/tls"
"net"
"strconv"
"time"
)
// TLSHandshake performs a real TLS handshake (not just a TCP connect)
// against host:port and reports success if it completes within timeout.
// Certificate validation is intentionally skipped: the target is a bare
// candidate IP under test before any DNS/hostname is attached to it, so
// there's neither a hostname to validate the cert against nor any reason
// to expect a signed cert yet. This checks "is there a real TLS listener
// here", not "is its certificate valid" — same scope-limiting principle
// SSHBanner already applies (banner only, no auth handshake).
func TLSHandshake(host string, port int, timeout time.Duration) func(ctx context.Context) Result {
target := net.JoinHostPort(host, strconv.Itoa(port))
checkType := "tls-" + strconv.Itoa(port)
return run(checkType, target, func(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
d := tls.Dialer{
NetDialer: &net.Dialer{Timeout: timeout},
Config: &tls.Config{InsecureSkipVerify: true},
}
conn, err := d.DialContext(ctx, "tcp", target)
if err != nil {
return err
}
return conn.Close()
})
}
+70
View File
@@ -0,0 +1,70 @@
package checkrunner
import (
"context"
"net"
"net/http/httptest"
"strconv"
"testing"
"time"
)
func splitHostPortInt(t *testing.T, addr string) (string, int) {
t.Helper()
host, portStr, err := net.SplitHostPort(addr)
if err != nil {
t.Fatalf("split host port %q: %v", addr, err)
}
port, err := strconv.Atoi(portStr)
if err != nil {
t.Fatalf("parse port %q: %v", portStr, err)
}
return host, port
}
// TestTLSHandshakeSucceedsAgainstTLSServer confirms a real TLS listener
// (self-signed cert, InsecureSkipVerify accepts it) passes the handshake.
func TestTLSHandshakeSucceedsAgainstTLSServer(t *testing.T) {
ts := httptest.NewTLSServer(nil)
defer ts.Close()
host, port := splitHostPortInt(t, ts.Listener.Addr().String())
res := TLSHandshake(host, port, time.Second)(context.Background())
if !res.Success {
t.Fatalf("expected success, got failure: %s", res.Detail)
}
wantType := "tls-" + strconv.Itoa(port)
if res.CheckType != wantType {
t.Fatalf("expected check type %q, got %q", wantType, res.CheckType)
}
}
// TestTLSHandshakeFailsAgainstPlainTCP confirms a bare TCP listener (no TLS
// on top) fails the handshake rather than being mistaken for success —
// this is exactly the gap a plain TCPConnect check can't catch.
func TestTLSHandshakeFailsAgainstPlainTCP(t *testing.T) {
ts := httptest.NewServer(nil)
defer ts.Close()
host, port := splitHostPortInt(t, ts.Listener.Addr().String())
res := TLSHandshake(host, port, time.Second)(context.Background())
if res.Success {
t.Fatalf("expected failure against a plain TCP listener, got success")
}
}
// TestTLSHandshakeFailsOnConnectionRefused confirms a closed port reports
// failure rather than hanging or panicking.
func TestTLSHandshakeFailsOnConnectionRefused(t *testing.T) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen: %v", err)
}
_, port := splitHostPortInt(t, l.Addr().String())
l.Close() // close immediately so the port refuses connections
res := TLSHandshake("127.0.0.1", port, time.Second)(context.Background())
if res.Success {
t.Fatalf("expected failure against a closed port, got success")
}
}