RFC 3263 NAPTR/SRV/A walk + sips TLS cert diagnostic for a SIP target
dns_diagnose_sip_target[cost: external_io (DNS via Cloudflare + Google; TLS handshake + a SIP OPTIONS keepalive to public targets when applicable) | read-only | rate-limited per IP: 10/min, 200/day]
Walk DNS the same way a SIP UA does (RFC 3263 §4.1): NAPTR → SRV → A/AAAA. Given a SIP URI ("sip:example.com"), bare hostname ("example.com"), or "host:port" string, return the records that exist and the resolution ladder a UA would try.
When the queried target uses TLS (sips: URI, transport=tls/wss, or any _sips._tcp SRV record), the tool also performs a TLS handshake against each resolved sips target and reports the negotiated TLS version + cipher, the leaf certificate's subject / issuer / SANs / validity, the chain length and whether it validates against Node's default trust store, plus two cert-domain checks: RFC 5922 §7.2 strict (cert must cover the original SIP domain) and a lenient SAN match against the SRV target hostname.
SIP liveness: DNS resolving and a TLS handshake succeeding do NOT prove the endpoint actually speaks SIP - a load-balanced node can accept TCP/TLS yet black-hole SIP. So the tool ALSO sends a real SIP OPTIONS keepalive to each resolved public IP across the relevant transports (UDP/TCP on 5060, TLS on 5061 / SRV port) and reports per-IP answered / timeout / refused. Any SIP response (even 405/403/404) proves the stack is alive on that IP. When a name resolves to multiple IPs it is treated as a load-balancer fan-out and each IP is probed individually, with a warning about the known failure modes of fronting stateful SIP/RTP with a cloud L4 LB (AWS NLB/ALB etc.): cross-zone-off targets that black-hole, the ~120s UDP idle timeout, and per-5-tuple hashing splitting signaling from media.
Egress safety:
Per-IP rate limited.
Hostnames that resolve only to RFC 1918 / loopback / link-local / documentation / multicast space are refused (SSRF guard).
Walk depth capped to prevent runaway NAPTR / CNAME chains.
TLS probes capped at 6 (host, port, ip) tuples per call, 5 s handshake timeout each, public-IP only (we connect to the resolved IP, not the hostname, so the system resolver cannot redirect us into private space).
SIP OPTIONS probes capped at 6 (ip, transport) tuples per call, 3 s timeout each, public-IP only; the request carries no SDP/body and an unroutable Via, and only the response status line is captured.
Use to diagnose:
"carrier doesn't answer" / "wrong port" / "TLS instead of UDP" routing puzzles
"DNS looks healthy but calls fail" - per-IP SIP OPTIONS surfaces nodes that resolve and accept the transport but never answer SIP (the decisive step for load-balanced / multi-IP targets)
"carrier rejects our target because no SRV is published" - when A/AAAA resolves but SRV is missing the tool synthesises a copy-pasteable suggested zone-record block pointing at the resolved canonical hostname
"TLS handshake works but cert isn't valid for the SIP domain" - RFC 5922 §7.2 compliance is checked separately from generic chain validation, since the SAN must cover the original SIP domain (not the SRV-redirected target)
ACL caveat: a SIP OPTIONS timeout can also mean the target authorizes inbound SIP by source IP whitelist on the trunk (Twilio, Telnyx, Bandwidth, …; see https://www.twilio.com/docs/sip-trunking/api/ipaccesscontrollist-resource) and is dropping our probe because our egress IP is not on the ACL. An answered result is conclusive (the node speaks SIP); a timeout is suggestive, not proof of a dead node - confirm reachability from the SBC itself.
Pair with: troubleshoot_response_code when 503 / 408 / 480 are involved; search_sip_docs(vendor=...) for carrier-specific routing docs.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| target | Yes | SIP URI ("sip:example.com"), "example.com:5060", or bare hostname ("example.com"). Userinfo is stripped before lookup. | |
| transport | No | Transport hint. "any" surfaces all NAPTR services; specific transports filter the SRV walk to that service. | any |