/* * BastionGuard™ Secure Connection * Copyright (C) 2025–2026 Calogero Scarnà * GPL-3.0 * * Protocollo wire daemon ↔ UI. * * Trasporto: Unix domain socket (SOCK_STREAM). * Framing: 4 byte little-endian length (uint32) + payload JSON UTF-8. * Nessun terminatore, nessun escape: la lunghezza e' l'unico marker. * * La UI e' sempre il server. Il daemon si connette come client. * * Ogni messaggio ha due campi obbligatori: * "type": stringa, identifica il tipo di messaggio * "id": uint64, correlazione per richieste/risposte * * Direzione daemon → UI: * hello -> primo messaggio, { type, id, daemon_version } * ping -> heartbeat, { type, id, stats: {...} } * ask_rule -> richiede decisione utente, { type, id, connection: {...} } * La UI risponde con ask_rule_reply con stesso id. * alert -> notifica informativa, { type, id, level, what, text, connection? } * * Direzione UI → daemon: * pong -> risposta a ping, { type, id } * ask_rule_reply -> risposta a ask_rule, { type, id, action, duration, rule_name? } * notification -> notifica runtime, { type, id, kind, data? } * kind ∈ { stop, reload_rules, change_config, enable_interception, * disable_interception, log_level, ... } */ #pragma once #include #include #include #include #include #include namespace bsc::proto { // Path di default del socket Unix della UI. inline constexpr const char* kDefaultSocketPath = "/tmp/bsd-daemon.sock"; // Tipi di messaggi. namespace msg { inline constexpr std::string_view kHello = "hello"; inline constexpr std::string_view kPing = "ping"; inline constexpr std::string_view kPong = "pong"; inline constexpr std::string_view kAskRule = "ask_rule"; inline constexpr std::string_view kAskRuleReply = "ask_rule_reply"; inline constexpr std::string_view kAlert = "alert"; inline constexpr std::string_view kNotification = "notification"; } // namespace msg // Risoluzione socketPath: accetta sia "/tmp/foo.sock" sia "unix:///tmp/foo.sock". inline std::string resolve_socket_path(std::string uri) { static const std::string prefix = "unix://"; if (uri.rfind(prefix, 0) == 0) uri = uri.substr(prefix.size()); return uri; } // Codifica un payload JSON in un frame [uint32 LE length][payload]. Inserisce // nel vettore `out` senza allocare di piu'. inline void frame_encode(std::string_view payload, std::vector& out) { const std::uint32_t len = static_cast(payload.size()); out.resize(4 + payload.size()); out[0] = static_cast(len & 0xff); out[1] = static_cast((len >> 8) & 0xff); out[2] = static_cast((len >> 16) & 0xff); out[3] = static_cast((len >> 24) & 0xff); std::memcpy(out.data() + 4, payload.data(), payload.size()); } // Legge 4 byte di lunghezza dal buffer. Restituisce -1 se il buffer non ha // almeno 4 byte. inline std::int64_t frame_peek_length(const std::uint8_t* buf, std::size_t len) { if (len < 4) return -1; return static_cast(buf[0]) | (static_cast(buf[1]) << 8) | (static_cast(buf[2]) << 16) | (static_cast(buf[3]) << 24); } // Dimensione massima accettabile di un frame (DoS guard). 4 MiB e' ampiamente // sufficiente per i messaggi del protocollo: AskRule col process tree piu' // grande mai visto sta sotto i 64 KiB. inline constexpr std::size_t kMaxFrameSize = 4u * 1024u * 1024u; } // namespace bsc::proto