Skip to content
API Documentation
BastionGuard™
bsc::fw::Firewall Class Reference

#include <Firewall.hpp>

Public Member Functions

 Firewall (std::string backend="nftables")
bool reload (const std::string &config_path) const
bool install_nfqueue_rule (std::uint16_t queue_num, bool queue_bypass=true) const
void remove_nfqueue_rule () const

Private Attributes

std::string backend_

Detailed Description

Definition at line 7 of file Firewall.hpp.

Constructor & Destructor Documentation

◆ Firewall()

bsc::fw::Firewall::Firewall ( std::string backend = "nftables")
inlineexplicit

Definition at line 9 of file Firewall.hpp.

9: backend_(std::move(backend)) {}
std::string backend_
Definition Firewall.hpp:24

References backend_.

Member Function Documentation

◆ install_nfqueue_rule()

bool bsc::fw::Firewall::install_nfqueue_rule ( std::uint16_t queue_num,
bool queue_bypass = true ) const

Definition at line 472 of file Firewall.cpp.

472 {
473 if (backend_ != "nftables") return false;
474
475 const auto nft_bin = resolve_nft_binary();
476 if (!nft_bin) {
478 "nft non trovato: impossibile installare la regola NFQUEUE, "
479 "fallback su polling /proc");
480 return false;
481 }
482
483 // Catena dedicata: inet bsc_intercept output, priority mangle - 10
484 // (prima delle regole utente comuni). Usa un nome prefissato bsc_* per
485 // non collidere con regole esistenti dell'utente.
486 std::ostringstream script;
487 script << "add table inet bsc_intercept\n";
488 // Elimina eventuale chain precedente (idempotente).
489 script << "delete chain inet bsc_intercept output\n";
490 script << "add chain inet bsc_intercept output "
491 "{ type filter hook output priority mangle - 10; policy accept; }\n";
492
493 // ── Whitelist: traffico infrastrutturale che NON va mai chiesto ─────
494 // Chiedere conferma per ogni query DNS o broadcast DHCP rende il sistema
495 // inusabile (decine di popup al minuto). Questi protocolli passano sempre.
496 script << "add rule inet bsc_intercept output oif lo accept\n";
497 script << "add rule inet bsc_intercept output meta mark 0x42 accept\n";
498 // DNS (UDP e TCP porta 53)
499 script << "add rule inet bsc_intercept output udp dport 53 accept\n";
500 script << "add rule inet bsc_intercept output tcp dport 53 accept\n";
501 // DHCP client (UDP 67/68)
502 script << "add rule inet bsc_intercept output udp sport { 67, 68 } accept\n";
503 script << "add rule inet bsc_intercept output udp dport { 67, 68 } accept\n";
504 // mDNS (UDP 5353) — usato da avahi/Bonjour per service discovery locale
505 script << "add rule inet bsc_intercept output udp dport 5353 accept\n";
506 // NTP (UDP 123) — sincronizzazione orario
507 script << "add rule inet bsc_intercept output udp dport 123 accept\n";
508 // ICMP (ping, destination unreachable, ecc.) — diagnostica
509 script << "add rule inet bsc_intercept output meta l4proto icmp accept\n";
510 script << "add rule inet bsc_intercept output meta l4proto icmpv6 accept\n";
511 // IGMP (multicast management)
512 script << "add rule inet bsc_intercept output meta l4proto igmp accept\n";
513
514 // Regola principale: tutto il nuovo traffico (stato ct new) va in coda.
515 // 'bypass' permette al traffico di passare se il daemon non e' in ascolto.
516 script << "add rule inet bsc_intercept output ct state new queue num "
517 << queue_num;
518 if (queue_bypass) script << " bypass";
519 script << "\n";
520
521 // Scriviamo lo script in un file temporaneo invece di pipe, cosi' nft
522 // riporta errori leggibili nel log (se abilitato).
523 fs::path tmp_script = fs::temp_directory_path() / "bsc-nfqueue-install.nft";
524 {
525 std::ofstream out(tmp_script);
526 if (!out) {
528 "Impossibile creare lo script temporaneo nft in " + tmp_script.string());
529 return false;
530 }
531 out << script.str();
532 }
533
534 const auto cmd = *nft_bin + " -f " + shell_quote(tmp_script.string()) +
535 " 2>/dev/null";
536 // Il primo delete chain puo' fallire se la tabella non esiste ancora;
537 // nft in modalita' atomica fallisce tutto. Rifaccio un retry senza il
538 // delete se il primo tentativo fallisce (prima esecuzione).
539 int rc = std::system(cmd.c_str());
540 if (rc != 0) {
541 std::ostringstream s2;
542 s2 << "add table inet bsc_intercept\n";
543 s2 << "add chain inet bsc_intercept output "
544 "{ type filter hook output priority mangle - 10; policy accept; }\n";
545 s2 << "flush chain inet bsc_intercept output\n";
546 s2 << "add rule inet bsc_intercept output oif lo accept\n";
547 s2 << "add rule inet bsc_intercept output meta mark 0x42 accept\n";
548 s2 << "add rule inet bsc_intercept output udp dport 53 accept\n";
549 s2 << "add rule inet bsc_intercept output tcp dport 53 accept\n";
550 s2 << "add rule inet bsc_intercept output udp sport { 67, 68 } accept\n";
551 s2 << "add rule inet bsc_intercept output udp dport { 67, 68 } accept\n";
552 s2 << "add rule inet bsc_intercept output udp dport 5353 accept\n";
553 s2 << "add rule inet bsc_intercept output udp dport 123 accept\n";
554 s2 << "add rule inet bsc_intercept output meta l4proto icmp accept\n";
555 s2 << "add rule inet bsc_intercept output meta l4proto icmpv6 accept\n";
556 s2 << "add rule inet bsc_intercept output meta l4proto igmp accept\n";
557 s2 << "add rule inet bsc_intercept output ct state new queue num "
558 << queue_num;
559 if (queue_bypass) s2 << " bypass";
560 s2 << "\n";
561 std::ofstream out(tmp_script);
562 out << s2.str();
563 out.close();
564 rc = std::system(cmd.c_str());
565 }
566
567 std::error_code ec;
568 fs::remove(tmp_script, ec);
569
570 if (rc != 0) {
572 "installazione regola NFQUEUE fallita "
573 "(permessi insufficienti? manca CAP_NET_ADMIN?): fallback su /proc");
574 return false;
575 }
576
578 "regola NFQUEUE installata sulla coda " + std::to_string(queue_num) +
579 (queue_bypass ? " (bypass abilitato)" : ""));
580 return true;
581}
void warning(const std::string &msg)
Definition Logger.cpp:22
void info(const std::string &msg)
Definition Logger.cpp:21
static Logger & instance()
Definition Logger.cpp:11
std::string shell_quote(const std::string &argument)
std::optional< std::string > resolve_nft_binary()
Definition Firewall.cpp:52

References backend_, bsc::logging::Logger::info(), bsc::logging::Logger::instance(), and bsc::logging::Logger::warning().

Referenced by bsc::service::DaemonService::run().

◆ reload()

bool bsc::fw::Firewall::reload ( const std::string & config_path) const

Definition at line 394 of file Firewall.cpp.

394 {
395 if (backend_ != "nftables") return false;
396 if (config_path.empty() || !fs::exists(config_path)) return false;
397
398 const auto nft_bin = resolve_nft_binary();
399 if (!nft_bin) {
401 "nft non trovato nel sistema: reload firewall non effettuato");
402 return false;
403 }
404
405 if (fs::path(config_path).extension() == ".nft") {
406 const auto cmd = *nft_bin + " -f " + shell_quote(config_path) + " >/dev/null 2>&1";
407 return std::system(cmd.c_str()) == 0;
408 }
409
410 try {
411 std::ifstream in(config_path);
412 json j;
413 in >> j;
414
415 static const std::vector<std::string> candidate_keys{
416 "NftFile", "NftablesFile", "RulesFile", "ScriptPath"
417 };
418
419 for (const auto& key : candidate_keys) {
420 if (j.contains(key) && j[key].is_string()) {
421 const auto nft_file = j[key].get<std::string>();
422 if (!nft_file.empty() && fs::exists(nft_file)) {
423 const auto cmd = *nft_bin + " -f " + shell_quote(nft_file) + " >/dev/null 2>&1";
424 return std::system(cmd.c_str()) == 0;
425 }
426 }
427 }
428
429 const auto rendered = fs::path(config_path).parent_path() / ".bsc-rendered-system-fw.nft";
430 // Rimuovi eventuale script residuo di un run precedente, cosi' dopo
431 // possiamo verificare univocamente "il render ha prodotto regole?"
432 std::error_code rm_ec;
433 fs::remove(rendered, rm_ec);
434
435 if (!render_json_config_to_nft(j, rendered)) {
437 "firewall JSON non supportato o incompleto: reload non effettuato");
438 return false;
439 }
440
441 // Se render_json_config_to_nft ha ritornato true ma non ha scritto
442 // lo script (config valida ma nessuna regola enabled), consideriamo
443 // l'operazione riuscita silenziosamente: niente da caricare in nft.
444 if (!fs::exists(rendered)) {
445 return true;
446 }
447
448 bsc::logging::Logger::instance().info("script nft renderizzato: " + rendered.string());
449
450 const auto cmd = *nft_bin + " -f " + shell_quote(rendered.string()) + " >/dev/null 2>&1";
451 const auto rc = std::system(cmd.c_str());
452 if (rc != 0) {
454 "reload firewall fallito eseguendo script nft renderizzato da " + config_path);
455 return false;
456 }
457
459 "firewall nftables ricaricato da " + config_path + " usando " + *nft_bin);
460 return true;
461 } catch (const std::exception& e) {
463 std::string("reload firewall fallito: ") + e.what());
464 } catch (...) {
466 "reload firewall fallito: errore sconosciuto");
467 }
468
469 return false;
470}
bool render_json_config_to_nft(const json &j, const fs::path &script_path)
Definition Firewall.cpp:302
nlohmann::json json
Definition Firewall.cpp:20

References backend_, bsc::logging::Logger::info(), bsc::logging::Logger::instance(), and bsc::logging::Logger::warning().

Referenced by bsc::service::DaemonService::run().

◆ remove_nfqueue_rule()

void bsc::fw::Firewall::remove_nfqueue_rule ( ) const

Definition at line 583 of file Firewall.cpp.

583 {
584 if (backend_ != "nftables") return;
585 const auto nft_bin = resolve_nft_binary();
586 if (!nft_bin) return;
587
588 // Rimuoviamo solo la nostra tabella, non tocchiamo altro.
589 const auto cmd = *nft_bin +
590 " delete table inet bsc_intercept >/dev/null 2>&1";
591 (void)std::system(cmd.c_str());
592}

References backend_.

Referenced by bsc::service::DaemonService::run().

Member Data Documentation

◆ backend_

std::string bsc::fw::Firewall::backend_
private

Definition at line 24 of file Firewall.hpp.

Referenced by Firewall(), install_nfqueue_rule(), reload(), and remove_nfqueue_rule().


The documentation for this class was generated from the following files:
  • BastionGuard/thirdparty/bastionguard-secure-connection/daemon/include/bsc/fw/Firewall.hpp
  • BastionGuard/thirdparty/bastionguard-secure-connection/daemon/src/fw/Firewall.cpp