| .clang-format | Initial version | |
| .gitignore | Initial version | |
| import_changelogs.py | Add ldns + REUSEPORT | |
| meson.build | Add ldns + REUSEPORT | |
| README.md | Add README.md | |
| secure_dns_telemetry.h | Refactored the initial code | |
| secure_dns_telemetry_client_example.c | Initial version | |
| secure_dns_telemetry_gen_key.c | Initial version | |
| secure_dns_telemetry_server.c | More hardening | |
Here is a comprehensive README.md documenting the architecture, protocol, and usage.
Secure DNS Telemetry System
A lightweight, secure, and privacy-preserving telemetry system designed to notify clients about critical security updates via DNS.
The system uses Authenticated Encryption (XSalsa20-Poly1305) to encapsulate version data inside standard DNS queries. It is designed to be fail-silent: the client only alerts if a critical security vulnerability exists; otherwise, it remains completely silent.
🚀 Key Features
- Secure by Design: All payloads are encrypted and authenticated using libsodium (XSalsa20-Poly1305).
- Privacy Preserving: Client IP and Version information are encrypted; intermediary DNS resolvers cannot see the payload.
- Fail-Silent Client: The client library generates zero output unless a High/Critical urgency update is required.
- High Performance Server: Built on libuv (async I/O) and LMDB (Memory-Mapped DB) for O(1) lookups.
- Dual Stack: Native IPv6 support with robust IPv4 fallback.
- Zero-Copy Logic: Optimized C implementation for minimal memory footprint.
🛠 Architecture
1. The Client (secure_dns_telemetry.h)
A header-only C library intended for embedding into applications (e.g., PHP extensions, agents).
- Operation:
- Generates an ephemeral keypair.
- Encrypts
Package|Version(e.g.,php8.2|8.2.14-1) using the Server's Public Key. - Encodes the ciphertext into DNS labels (Base64 URL-safe).
- Sends a UDP DNS Query (TXT Record) to
telemetry.sury.org. - Decrypts the response.
- Alerts only if the server responds with
"status":"outdated"AND"urgency":"high|critical".
2. The Server (telemetry_server)
A standalone UDP server that acts as an authoritative DNS resolver for the telemetry subdomain.
- Operation:
- Listens on UDP 53 (Dual Stack IPv6/IPv4).
- Parses DNS packets and extracts encrypted labels.
- Decrypts the payload using the Server Secret Key.
- Performs an O(1) lookup in LMDB.
- Returns a signed, encrypted JSON response (e.g.,
{"status":"ok"}or{"status":"outdated",...}).
3. The Data Pipeline
import_changelog.py: A utility that parses standarddebian/changelogfiles.- Logic: It "squashes" the version history. If version
1.0is current, but1.1fixes a critical bug, the database entry for1.0will point to1.1withurgency=critical.
🔒 The Protocol
The communication is encapsulated entirely within standard DNS TXT queries to avoid firewall blocking.
Request Structure (Client -> Server)
Query Name (QNAME) format:
<Base64_Client_PublicKey>.<Base64_Nonce>.<Base64_Ciphertext>.telemetry.sury.org- Public Key (32 bytes): Ephemeral client key for the session.
- Nonce (24 bytes): Random nonce for XSalsa20.
- Ciphertext: Encrypted payload containing
PackageName|VersionString.
Response Structure (Server -> Client)
TXT Record Answer:
<Base64_Response_Blob>- Response Blob: Contains
[Nonce (24 bytes)] || [Ciphertext]. - Payload: Encrypted JSON string.
- OK:
{"status":"ok"} - Alert:
{"status":"outdated","latest":"8.3.1-1","urgency":"critical"}
📦 Build & Installation
Prerequisites
- Build System:
meson,ninja - Libraries:
libuv1-dev,libsodium-dev,liblmdb-dev,python3-debian
1. Build Server
meson setup build
meson compile -C build
2. Generate Database
You need a debian/changelog file to populate the database.
# Install python deps
pip3 install python-debian lmdb
# Import (Source -> DB)
./import_changelog.py /path/to/debian/changelog versions.mdb
3. Generate Keys
./build/gen_key server.key
# Output:
# Secret key saved to server.key
# Public Key: <BASE64_PUBLIC_KEY>
Copy the Public Key into secure_dns_telemetry.h in your client application.
4. Run Server
# Run with verbose logging to see decrypted traffic
sudo ./build/telemetry_server -v
💻 Client Usage Example
The client is a single header file.
#define TELEMETRY_HOST "telemetry.sury.org"
#define TELEMETRY_LOG(msg) syslog(LOG_WARNING, "%s", msg) // Override logging
#include "secure_dns_telemetry.h"
int main() {
// Check specific package version
// If secure: No output.
// If critical: Logs to syslog (or stderr default).
telemetry_check("php8.2", "8.2.14-1+ubuntu22.04");
return 0;
}
🛡 Security Considerations
- Replay Attacks: The protocol uses ephemeral keys and nonces for every request, preventing replay of old telemetry data.
- Amplification: The server enforces strict packet size limits (4KB) and only responds to valid, authenticated queries, mitigating DNS amplification risks.
- Metadata Leakage: The "Question" section of the DNS packet contains only encrypted binary blobs. No version numbers or package names are visible in plaintext on the wire.
- Spoofing: Responses are authenticated with Poly1305. A client will silently discard any response that wasn't signed by the legitimate server.