Skip to content
API Documentation
BastionGuard™
bsc::fw::anonymous_namespace{Firewall.cpp} Namespace Reference

Classes

struct  RenderedRuleLine

Functions

std::string trim (std::string s)
std::string lower (std::string s)
std::vector< std::string > split_csv_values (const std::string &raw)
std::optional< std::string > resolve_nft_binary ()
std::string shell_quote (const std::string &in)
std::string normalize_chain_type (const std::string &type, const std::string &hook)
std::string default_priority_for (const std::string &type)
std::string normalize_chain_name (std::string name)
std::string normalize_table_name (std::string name)
std::string render_value_set (const std::vector< std::string > &values)
std::string render_statement (const json &stmt)
std::string render_rule (const json &rule)
std::string convert_legacy_parameters (const std::string &params)
std::optional< RenderedRuleLine > render_legacy_rule (const json &legacy_rule)
void ensure_table_and_chain (std::ostringstream &script, std::set< std::string > &recreated_tables, std::set< std::string > &created_chains, const std::string &family, const std::string &table, const std::string &chain, const std::string &type, const std::string &hook, const std::string &priority, const std::string &policy)
bool render_json_config_to_nft (const json &j, const fs::path &script_path)

Function Documentation

◆ convert_legacy_parameters()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::convert_legacy_parameters ( const std::string & params)

Definition at line 206 of file Firewall.cpp.

206 {
207 std::istringstream iss(params);
208 std::vector<std::string> out;
209 std::string tok;
210 while (iss >> tok) {
211 if ((tok == "-p" || tok == "--protocol") && iss >> tok) out.push_back(lower(tok));
212 else if ((tok == "--dport" || tok == "--destination-port") && iss >> tok) out.push_back("tcp dport " + tok);
213 else if ((tok == "--sport" || tok == "--source-port") && iss >> tok) out.push_back("tcp sport " + tok);
214 else if ((tok == "-d" || tok == "--destination") && iss >> tok) out.push_back("ip daddr " + tok);
215 else if ((tok == "-s" || tok == "--source") && iss >> tok) out.push_back("ip saddr " + tok);
216 }
217 std::ostringstream oss;
218 for (std::size_t i = 0; i < out.size(); ++i) {
219 if (i) oss << ' ';
220 oss << out[i];
221 }
222 return trim(oss.str());
223}
std::string trim(std::string s)
Definition Firewall.cpp:24
std::string lower(std::string s)
Definition Firewall.cpp:31

References convert_legacy_parameters(), lower(), and trim().

Referenced by convert_legacy_parameters(), and render_legacy_rule().

◆ default_priority_for()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::default_priority_for ( const std::string & type)

Definition at line 99 of file Firewall.cpp.

99 {
100 const auto t = lower(type);
101 if (t == "natdest") return "dstnat";
102 if (t == "natsource") return "srcnat";
103 if (t == "mangle") return "mangle";
104 return "filter";
105}

References default_priority_for(), and lower().

Referenced by default_priority_for(), and render_json_config_to_nft().

◆ ensure_table_and_chain()

void bsc::fw::anonymous_namespace{Firewall.cpp}::ensure_table_and_chain ( std::ostringstream & script,
std::set< std::string > & recreated_tables,
std::set< std::string > & created_chains,
const std::string & family,
const std::string & table,
const std::string & chain,
const std::string & type,
const std::string & hook,
const std::string & priority,
const std::string & policy )

Definition at line 271 of file Firewall.cpp.

280 {
281 const auto table_key = family + ":" + table;
282 if (recreated_tables.find(table_key) == recreated_tables.end()) {
283 script << "delete table " << family << ' ' << table << "\n";
284 script << "add table " << family << ' ' << table << "\n";
285 recreated_tables.insert(table_key);
286 }
287
288 const auto chain_key = table_key + ":" + chain;
289 if (created_chains.find(chain_key) != created_chains.end()) return;
290
291 script << "add chain " << family << ' ' << table << ' ' << chain;
292 if (!hook.empty()) {
293 script << " { type " << type
294 << " hook " << hook
295 << " priority " << priority
296 << "; policy " << policy << "; }";
297 }
298 script << "\n";
299 created_chains.insert(chain_key);
300}

References ensure_table_and_chain().

Referenced by ensure_table_and_chain(), and render_json_config_to_nft().

◆ lower()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::lower ( std::string s)

Definition at line 31 of file Firewall.cpp.

31 {
32 std::transform(s.begin(), s.end(), s.begin(),
33 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
34 return s;
35}

References lower().

Referenced by convert_legacy_parameters(), default_priority_for(), lower(), normalize_chain_name(), normalize_chain_type(), normalize_table_name(), render_json_config_to_nft(), render_legacy_rule(), and render_rule().

◆ normalize_chain_name()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::normalize_chain_name ( std::string name)

Definition at line 107 of file Firewall.cpp.

107 {
108 name = lower(trim(std::move(name)));
109 if (name == "input" || name == "output" || name == "forward" || name == "prerouting" || name == "postrouting") {
110 return name;
111 }
112 return name;
113}

References lower(), normalize_chain_name(), and trim().

Referenced by normalize_chain_name(), and render_legacy_rule().

◆ normalize_chain_type()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::normalize_chain_type ( const std::string & type,
const std::string & hook )

Definition at line 90 of file Firewall.cpp.

90 {
91 const auto t = lower(type);
92 const auto h = lower(hook);
93 if (t == "natdest" || t == "natsource" || t == "nat") return "nat";
94 if (t == "route") return "route";
95 if (t == "mangle") return h == "output" ? "route" : "filter";
96 return "filter";
97}

References lower(), and normalize_chain_type().

Referenced by normalize_chain_type(), and render_json_config_to_nft().

◆ normalize_table_name()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::normalize_table_name ( std::string name)

Definition at line 115 of file Firewall.cpp.

115 {
116 name = lower(trim(std::move(name)));
117 return name.empty() ? std::string{"filter"} : name;
118}

References lower(), normalize_table_name(), and trim().

Referenced by normalize_table_name(), and render_legacy_rule().

◆ render_json_config_to_nft()

bool bsc::fw::anonymous_namespace{Firewall.cpp}::render_json_config_to_nft ( const json & j,
const fs::path & script_path )

Definition at line 302 of file Firewall.cpp.

302 {
303 if (j.contains("Enabled") && j["Enabled"].is_boolean() && !j["Enabled"].get<bool>()) {
304 bsc::logging::Logger::instance().info("firewall config caricata ma disabilitata: skip reload");
305 return true;
306 }
307
308 if (!j.contains("SystemRules") || !j["SystemRules"].is_array()) return false;
309
310 std::ostringstream script;
311 script << "#!/usr/sbin/nft -f\n";
312
313 std::set<std::string> recreated_tables;
314 std::set<std::string> created_chains;
315 std::size_t added_rules = 0; // contatore regole effettivamente emesse
316
317 for (const auto& group : j["SystemRules"]) {
318 if (!group.is_object()) continue;
319
320 if (group.contains("Rule") && group["Rule"].is_object()) {
321 if (auto legacy = render_legacy_rule(group["Rule"])) {
322 ensure_table_and_chain(script, recreated_tables, created_chains,
323 legacy->family, legacy->table, legacy->chain,
324 normalize_chain_type(legacy->table, legacy->chain),
325 legacy->chain,
326 default_priority_for(legacy->table),
327 "accept");
328 script << "add rule " << legacy->family << ' ' << legacy->table << ' ' << legacy->chain
329 << ' ' << legacy->rule << "\n";
330 ++added_rules;
331 }
332 }
333
334 if (!group.contains("Chains") || !group["Chains"].is_array()) continue;
335
336 for (const auto& chain : group["Chains"]) {
337 if (!chain.is_object()) continue;
338
339 const auto family = lower(trim(chain.value("Family", std::string{"inet"})));
340 const auto table = trim(chain.value("Table", std::string{}));
341 const auto name = trim(chain.value("Name", std::string{}));
342 const auto hook = lower(trim(chain.value("Hook", std::string{})));
343 if (table.empty() || name.empty()) continue;
344
345 // Conta quante Rules dentro questa chain sono enabled. Se zero,
346 // non creiamo neanche la chain: con `system-fw.json` legacy di
347 // OpenSnitch tutte le chain sono placeholder vuote che nft non
348 // sa gestire senza priority valida.
349 std::size_t chain_enabled_rules = 0;
350 if (chain.contains("Rules") && chain["Rules"].is_array()) {
351 for (const auto& rule : chain["Rules"]) {
352 if (rule.is_object() && rule.contains("Enabled") &&
353 rule["Enabled"].is_boolean() && !rule["Enabled"].get<bool>()) continue;
354 if (!render_rule(rule).empty()) ++chain_enabled_rules;
355 }
356 }
357 if (chain_enabled_rules == 0) continue;
358
359 const auto policy = lower(trim(chain.value("Policy", std::string{"accept"})));
360 const auto priority = trim(chain.value("Priority", std::string{}));
361 const auto type = normalize_chain_type(chain.value("Type", std::string{"filter"}), hook);
362 ensure_table_and_chain(script, recreated_tables, created_chains,
363 family, table, name, type, hook,
364 priority.empty() ? default_priority_for(chain.value("Type", std::string{"filter"})) : priority,
365 policy);
366
367 for (const auto& rule : chain["Rules"]) {
368 const auto rendered = render_rule(rule);
369 if (!rendered.empty()) {
370 script << "add rule " << family << ' ' << table << ' ' << name
371 << ' ' << rendered << "\n";
372 ++added_rules;
373 }
374 }
375 }
376 }
377
378 // Se non abbiamo emesso nessuna regola effettiva, non scriviamo neanche
379 // lo script: il chiamante interpretera' questo come "niente da fare"
380 // (ritorno true) e non generera' un warning inutile.
381 if (added_rules == 0) {
383 "system-fw.json presente ma nessuna regola abilitata: skip reload");
384 return true;
385 }
386
387 std::ofstream out(script_path);
388 out << script.str();
389 return static_cast<bool>(out);
390}
static std::string trim(const std::string &s)
Definition Backend.cpp:112
void info(const std::string &msg)
Definition Logger.cpp:21
static Logger & instance()
Definition Logger.cpp:11
std::string render_rule(const json &rule)
Definition Firewall.cpp:169
std::string normalize_chain_type(const std::string &type, const std::string &hook)
Definition Firewall.cpp:90
void ensure_table_and_chain(std::ostringstream &script, std::set< std::string > &recreated_tables, std::set< std::string > &created_chains, const std::string &family, const std::string &table, const std::string &chain, const std::string &type, const std::string &hook, const std::string &priority, const std::string &policy)
Definition Firewall.cpp:271
std::optional< RenderedRuleLine > render_legacy_rule(const json &legacy_rule)
Definition Firewall.cpp:232
std::string default_priority_for(const std::string &type)
Definition Firewall.cpp:99

References default_priority_for(), ensure_table_and_chain(), bsc::logging::Logger::info(), bsc::logging::Logger::instance(), lower(), normalize_chain_type(), render_json_config_to_nft(), render_legacy_rule(), render_rule(), and trim().

Referenced by render_json_config_to_nft().

◆ render_legacy_rule()

std::optional< RenderedRuleLine > bsc::fw::anonymous_namespace{Firewall.cpp}::render_legacy_rule ( const json & legacy_rule)

Definition at line 232 of file Firewall.cpp.

232 {
233 if (!legacy_rule.is_object()) return std::nullopt;
234 if (legacy_rule.contains("Enabled") && legacy_rule["Enabled"].is_boolean() && !legacy_rule["Enabled"].get<bool>()) return std::nullopt;
235
236 RenderedRuleLine line;
237 line.table = normalize_table_name(legacy_rule.value("Table", std::string{}));
238 line.chain = normalize_chain_name(legacy_rule.value("Chain", std::string{}));
239 std::vector<std::string> parts;
240
241 if (legacy_rule.contains("Parameters") && legacy_rule["Parameters"].is_string()) {
242 const auto converted = convert_legacy_parameters(legacy_rule["Parameters"].get<std::string>());
243 if (!converted.empty()) parts.push_back(converted);
244 }
245
246 if (legacy_rule.contains("Expressions") && legacy_rule["Expressions"].is_array()) {
247 for (const auto& expr : legacy_rule["Expressions"]) {
248 if (!expr.is_object() || !expr.contains("Statement")) continue;
249 const auto stmt = render_statement(expr["Statement"]);
250 if (!stmt.empty()) parts.push_back(stmt);
251 }
252 }
253
254 const auto target = trim(lower(legacy_rule.value("Target", std::string{})));
255 if (!target.empty()) parts.push_back(target);
256 if (legacy_rule.contains("TargetParameters") && legacy_rule["TargetParameters"].is_string()) {
257 const auto params = trim(legacy_rule["TargetParameters"].get<std::string>());
258 if (!params.empty()) parts.push_back(params);
259 }
260
261 std::ostringstream oss;
262 for (std::size_t i = 0; i < parts.size(); ++i) {
263 if (i) oss << ' ';
264 oss << parts[i];
265 }
266 line.rule = trim(oss.str());
267 if (line.table.empty() || line.chain.empty() || line.rule.empty()) return std::nullopt;
268 return line;
269}
std::string normalize_table_name(std::string name)
Definition Firewall.cpp:115
std::string normalize_chain_name(std::string name)
Definition Firewall.cpp:107
std::string convert_legacy_parameters(const std::string &params)
Definition Firewall.cpp:206
std::string render_statement(const json &stmt)
Definition Firewall.cpp:134

References convert_legacy_parameters(), lower(), normalize_chain_name(), normalize_table_name(), render_legacy_rule(), render_statement(), and trim().

Referenced by render_json_config_to_nft(), and render_legacy_rule().

◆ render_rule()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::render_rule ( const json & rule)

Definition at line 169 of file Firewall.cpp.

169 {
170 if (!rule.is_object()) return {};
171 if (rule.contains("Enabled") && rule["Enabled"].is_boolean() && !rule["Enabled"].get<bool>()) return {};
172
173 std::vector<std::string> parts;
174
175 if (rule.contains("Parameters") && rule["Parameters"].is_string()) {
176 const auto params = trim(rule["Parameters"].get<std::string>());
177 if (!params.empty()) parts.push_back(params);
178 }
179
180 if (rule.contains("Expressions") && rule["Expressions"].is_array()) {
181 for (const auto& expr : rule["Expressions"]) {
182 if (!expr.is_object()) continue;
183 if (expr.contains("Statement")) {
184 const auto stmt = render_statement(expr["Statement"]);
185 if (!stmt.empty()) parts.push_back(stmt);
186 }
187 }
188 }
189
190 const auto target = trim(lower(rule.value("Target", std::string{})));
191 if (!target.empty()) parts.push_back(target);
192
193 if (rule.contains("TargetParameters") && rule["TargetParameters"].is_string()) {
194 const auto params = trim(rule["TargetParameters"].get<std::string>());
195 if (!params.empty()) parts.push_back(params);
196 }
197
198 std::ostringstream oss;
199 for (std::size_t i = 0; i < parts.size(); ++i) {
200 if (i) oss << ' ';
201 oss << parts[i];
202 }
203 return trim(oss.str());
204}

References lower(), render_rule(), render_statement(), and trim().

Referenced by render_json_config_to_nft(), and render_rule().

◆ render_statement()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::render_statement ( const json & stmt)

Definition at line 134 of file Firewall.cpp.

134 {
135 if (!stmt.is_object()) return {};
136
137 const std::string name = trim(stmt.value("Name", std::string{}));
138 if (name.empty()) return {};
139
140 std::map<std::string, std::vector<std::string>> grouped;
141 if (stmt.contains("Values") && stmt["Values"].is_array()) {
142 for (const auto& value : stmt["Values"]) {
143 if (!value.is_object()) continue;
144 const auto key = trim(value.value("Key", std::string{}));
145 const auto raw = trim(value.value("Value", std::string{}));
146 if (raw.empty()) continue;
147 for (const auto& item : split_csv_values(raw)) grouped[key].push_back(item);
148 }
149 }
150
151 std::ostringstream oss;
152 bool first = true;
153 const auto op = trim(stmt.value("Op", std::string{}));
154
155 for (const auto& kv : grouped) {
156 if (!first) oss << ' ';
157 first = false;
158 oss << name;
159 if (!kv.first.empty()) oss << ' ' << kv.first;
160 if (!op.empty()) oss << ' ' << op;
161 oss << ' ' << render_value_set(kv.second);
162 }
163 if (!grouped.empty()) return oss.str();
164
165 if (!op.empty()) return name + " " + op;
166 return name;
167}
std::string render_value_set(const std::vector< std::string > &values)
Definition Firewall.cpp:120
std::vector< std::string > split_csv_values(const std::string &raw)
Definition Firewall.cpp:37

References render_statement(), render_value_set(), split_csv_values(), and trim().

Referenced by render_legacy_rule(), render_rule(), and render_statement().

◆ render_value_set()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::render_value_set ( const std::vector< std::string > & values)

Definition at line 120 of file Firewall.cpp.

120 {
121 if (values.empty()) return {};
122 if (values.size() == 1) return values.front();
123
124 std::ostringstream oss;
125 oss << "{ ";
126 for (std::size_t i = 0; i < values.size(); ++i) {
127 if (i) oss << ", ";
128 oss << values[i];
129 }
130 oss << " }";
131 return oss.str();
132}

References render_value_set().

Referenced by render_statement(), and render_value_set().

◆ resolve_nft_binary()

std::optional< std::string > bsc::fw::anonymous_namespace{Firewall.cpp}::resolve_nft_binary ( )

Definition at line 52 of file Firewall.cpp.

52 {
53 if (const char* env = std::getenv("NFT_BIN")) {
54 fs::path p(env);
55 if (env[0] && fs::exists(p)) return p.string();
56 }
57
58 if (const char* path_env = std::getenv("PATH")) {
59 std::stringstream ss(path_env);
60 std::string entry;
61 while (std::getline(ss, entry, ':')) {
62 if (entry.empty()) continue;
63 fs::path p = fs::path(entry) / "nft";
64 if (fs::exists(p)) return p.string();
65 }
66 }
67
68 static constexpr std::array<const char*, 4> candidates{
69 "/usr/sbin/nft", "/sbin/nft", "/usr/bin/nft", "/bin/nft"
70 };
71 for (const auto* c : candidates) {
72 if (fs::exists(c)) return std::string(c);
73 }
74 return std::nullopt;
75}

References resolve_nft_binary().

Referenced by resolve_nft_binary().

◆ shell_quote()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::shell_quote ( const std::string & in)

Definition at line 77 of file Firewall.cpp.

77 {
78 std::string out = "'";
79 for (char ch : in) {
80 if (ch == '\'') {
81 out += "'\\''";
82 } else {
83 out.push_back(ch);
84 }
85 }
86 out += "'";
87 return out;
88}

References shell_quote().

Referenced by shell_quote().

◆ split_csv_values()

std::vector< std::string > bsc::fw::anonymous_namespace{Firewall.cpp}::split_csv_values ( const std::string & raw)

Definition at line 37 of file Firewall.cpp.

37 {
38 std::vector<std::string> out;
39 std::stringstream ss(raw);
40 std::string item;
41 while (std::getline(ss, item, ',')) {
42 item = trim(item);
43 if (!item.empty()) out.push_back(item);
44 }
45 if (out.empty()) {
46 const auto v = trim(raw);
47 if (!v.empty()) out.push_back(v);
48 }
49 return out;
50}

References split_csv_values(), and trim().

Referenced by render_statement(), and split_csv_values().

◆ trim()

std::string bsc::fw::anonymous_namespace{Firewall.cpp}::trim ( std::string s)

Definition at line 24 of file Firewall.cpp.

24 {
25 auto not_space = [](unsigned char ch) { return !std::isspace(ch); };
26 s.erase(s.begin(), std::find_if(s.begin(), s.end(), not_space));
27 s.erase(std::find_if(s.rbegin(), s.rend(), not_space).base(), s.end());
28 return s;
29}

References trim().

Referenced by convert_legacy_parameters(), normalize_chain_name(), normalize_table_name(), render_json_config_to_nft(), render_legacy_rule(), render_rule(), render_statement(), split_csv_values(), and trim().