ptrclassify; A QUIC Hello; dnstt
I wanted to talk about the first resource today, so I made the whole Drop about DNS-based resources.
This one is a tad on the DNS “nerd” side, and I tried to put in ’splainer links for all the funky new terms.
ptrclassify

Reading 86-45-50-202-dynamic.agg1.cab.bdt-fng.eircom.net and concluding “that’s a dynamic residential IP in Ireland!!” takes a moderately skilled analyst a few seconds. Except…that particular skill does not survive contact with a honeypot log holding several million distinct source addresses.
ptrclassify, from the always-generous Alexandre Dulaunoy, solves the scale end of that problem by turning reverse-DNS PTR strings into structured MISP machine-tag labels at machine speed – and, more usefully, in the very same way every time.
This consistent output lets us count things like what share of a scanning campaign came from cloud versus residential, whether a botnet has shifted from broadband to mobile infrastructure, or whether a given ASN’s traffic profile looks like customer devices or datacenter capacity. You can’t do any of that aggregation if the classification is produced by analysts who remember naming conventions unevenly (which is all of us, by the way).
The guts of the classification logic lives in ptrclassify/data/rules.json – a set of regular-expression rules, each carrying an ID, a category, a label, a confidence value, and one or more patterns. The classifier applies every pattern to the hostname and collects everything that fires, which gives you multi-label output: a mobile address behind CGNAT is tagged across the allocation, access, and translation namespaces simultaneously rather than being forced into a single bucket. Provider rules are separated from generic token rules to prevent bleed-through inference (i.e., so that a softbank hostname isn’t reflexively labeled mobile just because that company also runs a mobile network).
Location extraction is in a separate output object with a deliberately different structure. Since place data is open-ended rather than taxonomic, candidates come back with raw codes, decoded city/region/country, and per-candidate confidence – scoped to operator suffix so false matches don’t fire. Built-in operator templates cover AWS EC2 regions, Azure cloudapp.azure.com regions, CloudFront POP codes, and router codes for Hurricane Electric and Cogent. You can extend both classification and location at runtime through extra_rules, which keeps proprietary naming schemes out of the packaged data.
The access options are a library (classify() function or PTRClassifier object), a CLI that takes a hostname, a record, or a file and emits JSONL, and an optional FastAPI service with a POST /lookup for batch work. If you’re running serious volume, there’s a Hyperscan backend that compiles all expressions into a single database – same output as the default Python-stdlib engine, with meaningfully higher throughput.
The very real limitation is the same one it’s always been with reverse DNS: operators name things for their own reasons and update inconsistently, so ptrclassify produces hypotheses, not facts. Dulaunoy’s own documentation says to corroborate with ASN, RDAP, BGP prefix data, geofeeds, forward-confirmed reverse DNS (FCrDNS), and service observation.
This is def a welcome addition to an enrichment pipeline.
A QUIC Hello

Before your browser opens a single connection, it can already know whether the server speaks HTTP/3 and where its IP addresses are, but only if the server’s operator has published an HTTPS DNS record. Without it, the browser connects over HTTP/2, waits for an Alt-Svc response header advertising HTTP/3 support, and only upgrades on a subsequent visit. The HTTPS record collapses that into the DNS lookup itself.
The record is type 65 in the DNS spec (RFC 9460 defines it, along with the closely related SVCB record at type 64). It has three fields: priority, a target name, and a parameters list. dig +short HTTPS google.com returns 1 . alpn="h2,h3" – priority 1, the dot indicating “same name you queried,” and alpn listing the supported application-layer protocols. A browser reading h3 in that list can start with HTTP/3 immediately rather than negotiating up to it later. dig +short HTTPS censys.io goes further: 1 . alpn="h2" ipv4hint=104.18.10.85,104.18.11.85 plus an ipv6hint list. Those address hints let the client start the TCP or QUIC handshake before its parallel A and AAAA queries come back – shaving legity latency off the connection setup.
Priority zero produces a different record shape entirely: an alias that carries no parameters and just points to another name. dig +short HTTPS akamai.com returns 0 www.akamai.com.edgekey.net. and nothing else. This actually solves a decades-old DNS annoyance: CNAME records are illegal at the zone apex, so akamai.com can’t use a traditional CNAME to hand off to its CDN. An alias-mode HTTPS record does precisely the same thing without breaking zone-file rules. www.apple.com also uses the same pattern.
NOTE: If dig HTTPS returns an error, your dig is older than BIND 9.16 and doesn’t know the query type yet. dig -t TYPE65 example.com gets you the same data in raw hex, and I made a small golang CLI to parse (incompletely) the output — https://git.sr.ht/~hrbrmstr/gists/tree/main/item/2026/2026-08-23-https-record/README.md. PRs welcome if you want to add more field support.
The ech parameter is the record’s privacy-critical field. It carries the public key for Encrypted Client Hello, which hides the server name indicator during the TLS handshake – the thing that otherwise lets anyone watching the network see which hostname you’re connecting to even when the payload’s encrypted. A client can’t use ECH until it reads that key from DNS, so publishing it in the HTTPS record gives it a home. defo.ie and tls-ech.dev both publish ech values; defo.ie pairs it with DNSSEC signing (dig +dnssec HTTPS defo.ie shows the RRSIG — Resource Record Signature), which is the right setup since an attacker who can tamper with the DNS response can strip the ECH key. To decode a raw ech value you find in the wild: pipe the base64 blob through base64 -d and check the first two bytes. fe0d is draft-13 format.
ECH adoption is thin enough right now that you still have time to set up a regular measurement cadence (if you are so inclined), but you can also help speed up the curve by both running an HTTP server that supports HTTP/3 (like Caddy) and publishing these records yourself.
dnstt

Most DNS tunnel documentation avoids the awkward bits about how easy it is to detect DNS tunnels. David Fifield’s dnstt page doesn’t bother with that evasion. The tool itself is deliberately stripped down – no TUN device, no bundled proxy layer, just a Noise-encrypted pipe (that uses a pinned server public key and kcp-go+smux for sequencing) that connects a local TCP port to a remote one through whatever public DoH or DoT (DNS-over-HTTPS/TLS) resolver the client points at, with an NS (nameserver) delegation on the server side handling the authoritative hop. The “tt” is Turbo Tunnel, the architecture that gives you reliable sequencing on top of a transport that’s inherently lossy and slow.
Fifield documents the detection surface plainly. No traffic shaping, no padding, and he says outright that timing and volume metadata will likely identify tunnel use even through an encrypted resolver. The -udp mode collapses against a static pattern match. Cure53 put fifteen days into auditing the codebase in early 2021, and the page links to published research on fingerprinting dnstt traffic against ordinary browser DNS.
Whether you’re interested in how basic covert channels work or would like some new kit to profile and write detections for, David’s very accessible post should have everything you’re looking for.
FIN
Remember, you can follow and interact with the full text of The Daily Drop’s free posts on:
- 🐘 Mastodon via
@dailydrop.hrbrmstr.dev@dailydrop.hrbrmstr.dev - 🦋 Bluesky via
https://bsky.app/profile/dailydrop.hrbrmstr.dev.web.brid.gy
☮️
Leave a Reply