diff --git a/checker/collect.go b/checker/collect.go index f383b02..9a45d95 100644 --- a/checker/collect.go +++ b/checker/collect.go @@ -62,7 +62,22 @@ func (p *sshProvider) Collect(ctx context.Context, opts sdk.CheckerOptions) (any ports = append([]uint16{DefaultSSHPort}, ports...) } - host, ips := addressesFromServer(server) + // Origin is the FQDN where the service is mounted: svc.Domain holds the + // subdomain (relative to apex; "@" for apex), and the domain_name + // autofill carries the zone apex. + apex := "" + if v, ok := sdk.GetOption[string](opts, OptionDomainName); ok { + apex = strings.TrimSuffix(v, ".") + } + subdomain := "" + if svc, ok := sdk.GetOption[happydns.ServiceMessage](opts, OptionService); ok { + subdomain = strings.TrimSuffix(svc.Domain, ".") + } + origin := sdk.JoinRelative(subdomain, apex) + host, ips := addressesFromServer(server, origin) + if host == "" { + host = origin + } if len(ips) == 0 { return nil, fmt.Errorf("abstract.Server service has no A/AAAA records") } @@ -124,17 +139,16 @@ func resolveServer(opts sdk.CheckerOptions) (*abstract.Server, error) { // addressesFromServer returns the service's owner domain name (used // for SNI-like purposes in SSH banner/hostname exchange) and the list // of IPs to probe. -func addressesFromServer(server *abstract.Server) (host string, ips []string) { - // We can't know the service's owner domain from the Server payload - // alone. The host value we use here is purely informational for - // the report; the ssh handshake itself doesn't need it. +func addressesFromServer(server *abstract.Server, origin string) (host string, ips []string) { + // happyDomain encodes service-embedded record owners relative to the + // parent zone, so we must join with origin before treating as FQDN. if server.A != nil && len(server.A.A) > 0 { - host = strings.TrimSuffix(server.A.Hdr.Name, ".") + host = sdk.JoinRelative(server.A.Hdr.Name, origin) ips = append(ips, server.A.A.String()) } if server.AAAA != nil && len(server.AAAA.AAAA) > 0 { if host == "" { - host = strings.TrimSuffix(server.AAAA.Hdr.Name, ".") + host = sdk.JoinRelative(server.AAAA.Hdr.Name, origin) } ips = append(ips, server.AAAA.AAAA.String()) } diff --git a/checker/definition.go b/checker/definition.go index 3cc7548..7d26191 100644 --- a/checker/definition.go +++ b/checker/definition.go @@ -75,6 +75,12 @@ func (p *sshProvider) Definition() *sdk.CheckerDefinition { AutoFill: sdk.AutoFillService, Hide: true, }, + { + Id: OptionDomainName, + Label: "Parent domain name", + AutoFill: sdk.AutoFillDomainName, + Hide: true, + }, }, }, Rules: Rules(), diff --git a/checker/types.go b/checker/types.go index 25661f2..a927c6e 100644 --- a/checker/types.go +++ b/checker/types.go @@ -35,6 +35,7 @@ const ObservationKeySSH = "ssh" // Option ids on CheckerOptions. const ( OptionService = "service" + OptionDomainName = "domain_name" OptionPorts = "ports" OptionProbeTimeoutMs = "probeTimeoutMs" OptionIncludeAuthProbe = "includeAuthProbe"