# checker-srv Generic SRV records checker for [happyDomain](https://www.happydomain.org/). For every SRV record attached to a service, verifies: - DNS resolution of each target (A/AAAA) - RFC 2782 compliance: target is not `"."` (null), target is not a CNAME - TCP reachability on `target:port` (for `_tcp` SRVs) - UDP reachability on `target:port` (for `_udp` SRVs), via ICMP port-unreachable detection TLS/certificate testing is intentionally out of scope, it belongs to a dedicated TLS checker. The HTML report surfaces the most common failure scenarios at the top with actionable remediation guidance (DNS failure, CNAME-as-target, TCP unreachable, explicit null-target). ## Usage ### Standalone HTTP server ```bash # Build and run make ./checker-srv -listen :8080 ``` The server exposes: - `GET /health`, health check - `GET /definition`, checker definition (options, rules, availability) - `POST /collect`, collect SRV observations (happyDomain external checker protocol) - `POST /evaluate`, evaluate observations against the rules - `POST /report`, render the HTML report ### Docker ```bash make docker docker run -p 8080:8080 happydomain/checker-srv ``` ### happyDomain plugin ```bash make plugin # produces checker-srv.so, loadable by happyDomain as a Go plugin ``` The plugin exposes a `NewCheckerPlugin` symbol returning the checker definition and observation provider, which happyDomain registers in its global registries at load time. ### Versioning The binary, plugin, and Docker image embed a version string overridable at build time: ```bash make CHECKER_VERSION=1.2.3 make plugin CHECKER_VERSION=1.2.3 make docker CHECKER_VERSION=1.2.3 ``` ### happyDomain remote endpoint 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 ### 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 } ] } ] } } ``` ## Discovered TLS endpoints As a by-product of every `/collect`, this checker publishes `DiscoveryEntry` records of type `tls.endpoint.v1` (see [`checker-tls/contract`](https://git.happydns.org/checker-tls/tree/master/contract)) so that the TLS checker can probe the targets without re-parsing SRV data: - **Direct TLS** entries (empty `STARTTLS`) for service names that imply implicit TLS on connect: `_https`, `_ldaps`, `_sips`, `_imaps`, `_pop3s`, `_smtps`, `_submissions`, `_xmpps-client`, `_xmpps-server`, `_ftps`, `_nntps`, `_ircs`, `_telnets`, `_ipps`, `_mqtts`, `_coaps`, `_stuns`, `_turns`. - **STARTTLS** entries for service names that upgrade mid-stream: `_smtp` (opportunistic), `_submission` (required), `_imap` (required), `_pop3` (required), `_xmpp-client` (required), `_xmpp-server` (opportunistic), `_ldap`, `_nntp`, `_ftp`, `_sieve`, `_postgresql`. 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 License v3.0** (see `LICENSE`), because it still imports `happydns.ServiceMessage` from the happyDomain server module (`git.happydns.org/happyDomain/model`), which is itself distributed under AGPL-3.0 and a commercial license. The core checker types (`CheckerOptions`, `CheckerDefinition`, `ObservationProvider`, `CheckRule`, …) have already been migrated to [`checker-sdk-go`](https://git.happydns.org/checker-sdk-go); only the service-message types remain on the AGPL side. **Planned relicensing:** as soon as the remaining `ServiceMessage` dependency has been removed (moved into a dedicated permissively licensed module), this project will be relicensed under the **MIT License**, in line with the rest of the happyDomain checker ecosystem (see `checker-dummy` for the target shape). **Contributors notice:** by submitting a contribution to this repository, you accept that your contribution will be relicensed from AGPL-3.0 to MIT at the time of the relicensing described above. If you do not agree with this, please do not submit contributions until the relicensing has taken place. The third-party Apache-2.0 attributions for `checker-sdk-go` are recorded in `NOTICE` and must accompany any binary or source redistribution of this project.