From 85b10f296dc967f78034c24a43cf0b34a54f2160 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Wed, 29 Apr 2026 17:35:47 +0700 Subject: [PATCH 1/2] checker: join SRV record Hdr.Name to service domain before parsing SRV record owners inside the service body are relative to the service location (subdomain.domain). Using Hdr.Name directly produced relative owners in the report and broke grouping/dedup. Join via sdk.JoinRelative against the already-computed serviceDomain. --- checker/collect.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/checker/collect.go b/checker/collect.go index 4a410fb..83f37df 100644 --- a/checker/collect.go +++ b/checker/collect.go @@ -86,7 +86,10 @@ func (p *srvProvider) Collect(ctx context.Context, opts sdk.CheckerOptions) (any } for _, r := range payload.Records { - owner := strings.TrimSuffix(r.Hdr.Name, ".") + // Hdr.Name is relative to the service location (serviceDomain = + // subdomain.domain), so we join it with serviceDomain before + // treating as FQDN. + owner := sdk.JoinRelative(r.Hdr.Name, serviceDomain) svc, proto := parseOwner(owner, serviceDomain) rec := SRVRecord{ From 0941d89716a5123d21767106e40471935c932820 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 30 Apr 2026 08:46:46 +0700 Subject: [PATCH 2/2] Include rules section --- README.md | 70 ++++++++++--------------------------------------------- 1 file changed, 12 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 38e3ede..c5b791c 100644 --- a/README.md +++ b/README.md @@ -64,53 +64,19 @@ make docker CHECKER_VERSION=1.2.3 Set the `endpoint` admin option for the SRV checker to the URL of the running checker-srv server (e.g., `http://checker-srv:8080`). happyDomain will delegate observation collection to this endpoint. -## Protocol +## Rules -### POST /collect - -Request: -```json -{ - "key": "srv_records", - "target": {"userId": "...", "domainId": "...", "serviceId": "..."}, - "options": { - "service": {"_svctype": "svcs.UnknownSRV", "Service": {"srv": [ /* dns.SRV records */ ]}}, - "subdomain": "_sip._tcp", - "domain": "example.com", - "tcpTimeout": 3000, - "udpTimeout": 2000 - } -} -``` - -Response: -```json -{ - "data": { - "serviceDomain": "_sip._tcp.example.com", - "records": [ - { - "service": "sip", - "proto": "tcp", - "owner": "_sip._tcp.example.com", - "target": "sip1.example.com", - "port": 5061, - "priority": 10, - "weight": 20, - "addresses": ["203.0.113.5"], - "probes": [ - { - "address": "203.0.113.5:5061", - "proto": "tcp", - "connected": true, - "latencyMs": 12.4 - } - ] - } - ] - } -} -``` +| Code | Description | Severity | +|-------------------------------|---------------------------------------------------------------------------------------------------|---------------------| +| `srv_records_present` | At least one SRV record is published for this service. | CRITICAL | +| `srv_null_target` | Detects SRV records with target `.`, signaling the service is intentionally not available. | WARNING | +| `srv_target_not_cname` | RFC 2782: SRV targets must resolve directly to A/AAAA, not through a CNAME. | WARNING | +| `srv_targets_resolve` | Every SRV target resolves to at least one A/AAAA address. | CRITICAL | +| `srv_port_valid` | SRV records advertise a non-zero port that clients can actually connect to. | CRITICAL | +| `srv_priority_weight_sanity` | Priority/weight values follow RFC 2782 conventions (failover present, weights meaningful). | WARNING | +| `srv_tcp_reachable` | Every TCP SRV `target:port` accepts a TCP connection. | CRITICAL | +| `srv_udp_reachable` | UDP SRV targets do not return ICMP port-unreachable. | WARNING | +| `srv_redundancy` | At least two distinct SRV targets exist (avoids single point of failure). | INFO | ## Discovered TLS endpoints @@ -132,18 +98,6 @@ so that the TLS checker can probe the targets without re-parsing SRV data: Null targets (`.`) and unknown service names are skipped. SNI is set to the SRV target hostname. -## Rules - -| Name | Description | -|---|---| -| `srv_records_present` | At least one SRV record is published. | -| `srv_null_target` | Detects `"."` targets (RFC 2782, service intentionally unavailable). | -| `srv_target_not_cname` | Warns when an SRV target is a CNAME (RFC 2782 violation). | -| `srv_targets_resolve` | Every target resolves to at least one A/AAAA. | -| `srv_tcp_reachable` | Every `_tcp` SRV `target:port` accepts a TCP connection. | -| `srv_udp_reachable` | UDP targets do not return ICMP port-unreachable. | -| `srv_redundancy` | At least two distinct targets exist (no single point of failure). | - ## License & licensing roadmap This project is currently licensed under the **GNU Affero General Public