#pragma once #include "server/hooks/hook.h" #include #include #include #include #include #include #include #include #include // ───────────────────────────────────────────────────────────────────────────── // DnsUpdaterHook // // Fires whenever a server's *name* changes. Updates Technitium DNS by: // 1. Logging in → GET /api/user/login?user=…&pass=… → token // 2. Deleting the old A record (404 errors are silently ignored) // 3. Adding the new A record // // The server's IP is derived from the first NIC ip_address that belongs to the // server record. This hook receives the old and new Server structs; to look up // IP addresses it needs access to the Database – pass a const ref in the ctor. // // Config is supplied via environment variables so no secrets land in source: // TECHNITIUM_HOST (default: 192.168.2.193) // TECHNITIUM_PORT (default: 5380) // TECHNITIUM_USER (default: admin) // TECHNITIUM_PASS (required – hook logs an error and skips if unset) // TECHNITIUM_ZONE (default: homelab) // DNS_TTL (default: 300) // ───────────────────────────────────────────────────────────────────────────── class Database; // forward declaration – full header included in .cpp class DnsUpdaterHook : public Hook { public: explicit DnsUpdaterHook(const Database& db) : db_(db) {} // Trigger only when the server name changes. bool filter(const Server& old_server, const Server& new_server) override { return old_server.name != new_server.name; } void execute(const Server& old_server, const Server& new_server) override; private: const Database& db_; // Resolve config from environment, falling back to defaults. struct Config { std::string host; int port; std::string user; std::string pass; std::string zone; int ttl; }; static Config load_config(); // Percent-encode a string for use in a URL query parameter. static std::string url_encode(const std::string& s); // Open a TCP connection; throws on failure. static int connect_to(const std::string& host, int port); // Send an HTTP/1.0 GET request and return the full response body. static std::string http_get(const std::string& host, int port, const std::string& path); // Send an HTTP/1.0 POST request (application/x-www-form-urlencoded body) // and return the full response body. static std::string http_post(const std::string& host, int port, const std::string& path, const std::string& body); // Minimal JSON value extractor – finds "key":"value" or "key":value. static std::string json_get(const std::string& json, const std::string& key); };