package checker import ( "context" "net" "strconv" "strings" "time" "git.happydns.org/checker-tls/contract" "git.happydns.org/checker-tls/tlsenum" ) // enumerationProbeTimeout caps each individual sub-probe. It is intentionally // shorter than the main probe timeout: a sweep does dozens of handshakes and // most rejections come back in tens of ms, so 3s is enough to absorb a slow // network without dragging the total cost. const enumerationProbeTimeout = 3 * time.Second // enumerateEndpoint runs a (version × cipher) sweep against an endpoint — // direct TLS or STARTTLS — and returns the result in the wire-format consumed // by rules. It returns (nil, "") to signal the sweep was deliberately // skipped. func enumerateEndpoint(ctx context.Context, ep contract.TLSEndpoint, totalBudget time.Duration) (*TLSEnumeration, string) { host := strings.TrimSuffix(ep.Host, ".") addr := net.JoinHostPort(host, strconv.Itoa(int(ep.Port))) sni := ep.SNI if sni == "" { sni = host } upgrader, ok := upgraderFor(ep.STARTTLS, sni) if !ok { return nil, "unsupported starttls dialect: " + ep.STARTTLS } sweepCtx := ctx if totalBudget > 0 { var cancel context.CancelFunc sweepCtx, cancel = context.WithTimeout(ctx, totalBudget) defer cancel() } start := time.Now() res, err := tlsenum.Enumerate(sweepCtx, addr, sni, tlsenum.EnumerateOptions{ ProbeTimeout: enumerationProbeTimeout, Upgrader: upgrader, }) elapsed := time.Since(start).Milliseconds() if err != nil { return &TLSEnumeration{Skipped: "enumeration error: " + err.Error(), DurationMS: elapsed}, "" } out := &TLSEnumeration{DurationMS: elapsed} for _, v := range res.SupportedVersions { ev := EnumVersion{Version: v, Name: tlsenum.VersionName(v)} for _, c := range res.CiphersByVersion[v] { ev.Ciphers = append(ev.Ciphers, EnumCipher{ID: c.ID, Name: c.Name}) } out.Versions = append(out.Versions, ev) } return out, "" } // enumerationBudget is the upper bound we give one endpoint's sweep. ~50 // handshakes × enumerationProbeTimeout would be 2-3 minutes worst case; we // cap at 60s so a black-holing target can't stall the whole collect run. const enumerationBudget = 60 * time.Second