No description
  • Go 98.1%
  • Makefile 1.1%
  • Dockerfile 0.8%
Find a file
Pierre-Olivier Mercier 90f1b4943f 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.
2026-04-26 18:17:38 +07:00
checker Initial commit 2026-04-26 18:17:38 +07:00
plugin Initial commit 2026-04-26 18:17:38 +07:00
.gitignore Initial commit 2026-04-26 18:17:38 +07:00
Dockerfile Initial commit 2026-04-26 18:17:38 +07:00
go.mod Initial commit 2026-04-26 18:17:38 +07:00
go.sum Initial commit 2026-04-26 18:17:38 +07:00
LICENSE Initial commit 2026-04-26 18:17:38 +07:00
main.go Initial commit 2026-04-26 18:17:38 +07:00
Makefile Initial commit 2026-04-26 18:17:38 +07:00
README.md Initial commit 2026-04-26 18:17:38 +07:00

checker-srv

Generic SRV records checker for happyDomain.

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

# 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

make docker
docker run -p 8080:8080 happydomain/checker-srv

happyDomain plugin

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:

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:

{
  "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:

{
  "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) 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; 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.