Compare commits

...

2 commits

Author SHA1 Message Date
0941d89716 Include rules section 2026-04-30 08:46:46 +07:00
85b10f296d 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.
2026-04-30 08:46:34 +07:00
2 changed files with 16 additions and 59 deletions

View file

@ -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

View file

@ -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{