Initial commit
Generic SRV records checker for happyDomain.
For each SRV record attached to an svcs.UnknownSRV service, the checker
resolves every target and probes reachability:
- DNS resolution (A/AAAA), CNAME detection (RFC 2782 violation),
null-target detection (RFC 2782 "service explicitly unavailable")
- TCP connect to target:port for _tcp SRVs
- UDP probe for _udp SRVs, using ICMP port-unreachable detection
The checker also publishes TLS endpoints (host, port, SNI) for every
SRV target hitting a well-known direct-TLS port (443, 465, 636, 853,
993, 995, 5061, 5223, …) via the EndpointDiscoverer SDK interface, so
a downstream TLS checker can pick them up.
The HTML report groups records as cards and surfaces the most common
failure scenarios (DNS failure, CNAME target, TCP unreachable,
null-target) at the top with remediation guidance.
This commit is contained in:
commit
90f1b4943f
27 changed files with 2809 additions and 0 deletions
174
README.md
Normal file
174
README.md
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue