diff --git a/firewall.json b/firewall.json index ea7d087..9deb137 100644 --- a/firewall.json +++ b/firewall.json @@ -1,6 +1,7 @@ { "timeout": 1000, "default_policy": "allow", + "cache": true, "expressions": [ { "policy": "deny", diff --git a/libappguard/Cargo.lock b/libappguard/Cargo.lock index 85f6e78..5194140 100644 --- a/libappguard/Cargo.lock +++ b/libappguard/Cargo.lock @@ -430,7 +430,7 @@ dependencies = [ [[package]] name = "nullnet-libappguard" -version = "0.1.10" +version = "0.1.11" dependencies = [ "prost", "serde", diff --git a/libappguard/Cargo.toml b/libappguard/Cargo.toml index 7395c6c..80667ee 100644 --- a/libappguard/Cargo.toml +++ b/libappguard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nullnet-libappguard" -version = "0.1.10" +version = "0.1.11" edition = "2024" authors = ["Giuliano Bellini ", "Anton Liashkevich "] description = "An application-level firewall designed to secure and control network traffic" diff --git a/libappguard/src/proto/appguard_commands.rs b/libappguard/src/proto/appguard_commands.rs index 930cb73..8741afc 100644 --- a/libappguard/src/proto/appguard_commands.rs +++ b/libappguard/src/proto/appguard_commands.rs @@ -71,6 +71,8 @@ pub struct FirewallDefaults { pub timeout: u32, #[prost(enumeration = "FirewallPolicy", tag = "2")] pub policy: i32, + #[prost(bool, tag = "3")] + pub cache: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/proto/commands.proto b/proto/commands.proto index df84cdb..ca02120 100644 --- a/proto/commands.proto +++ b/proto/commands.proto @@ -46,6 +46,7 @@ message ServerMessage { message FirewallDefaults { uint32 timeout = 1; FirewallPolicy policy = 2; + bool cache = 3; } enum FirewallPolicy { diff --git a/src/app_guard_impl.rs b/src/app_guard_impl.rs index 2f5ee52..d70acb0 100644 --- a/src/app_guard_impl.rs +++ b/src/app_guard_impl.rs @@ -427,6 +427,7 @@ impl AppGuardImpl { Ok(FirewallDefaults { timeout: fw.timeout, policy: fw.default_policy.into(), + cache: fw.cache, }) } } diff --git a/src/db/datastore_wrapper.rs b/src/db/datastore_wrapper.rs index f7a21e1..321d449 100644 --- a/src/db/datastore_wrapper.rs +++ b/src/db/datastore_wrapper.rs @@ -1328,10 +1328,10 @@ mod tests { #[test] fn test_internal_firewall_parse_response_data() { - let data = r#"[{"app_id": "app1", "firewall": "{\"timeout\" : 1000, \"default_policy\": \"allow\", \"expressions\": []}"}, {"app_id": "app2", "firewall": "{\"timeout\" : 2000, \"default_policy\": \"deny\", \"expressions\": [{\"policy\": \"deny\", \"postfix_tokens\": [{\"type\": \"predicate\", \"condition\": \"equal\", \"protocol\": [\"HTTPS\"]}]}]}"}]"#; + let data = r#"[{"app_id": "app1", "firewall": "{\"timeout\" : 1000, \"default_policy\": \"allow\", \"cache\" : true, \"expressions\": []}"}, {"app_id": "app2", "firewall": "{\"timeout\" : 2000, \"default_policy\": \"deny\", \"cache\" : false, \"expressions\": [{\"policy\": \"deny\", \"postfix_tokens\": [{\"type\": \"predicate\", \"condition\": \"equal\", \"protocol\": [\"HTTPS\"]}]}]}"}]"#; let result = DatastoreWrapper::internal_firewall_parse_response_data(data).unwrap(); assert_eq!(result.len(), 2); assert_eq!(*result.get("app1").unwrap(), Firewall::default()); - assert_eq!(*result.get("app2").unwrap(), Firewall::from_postfix(r#"{"timeout" : 2000, "default_policy": "deny", "expressions": [{"policy": "deny", "postfix_tokens": [{"type": "predicate", "condition": "equal", "protocol": ["HTTPS"]}]}]}"#).unwrap()); + assert_eq!(*result.get("app2").unwrap(), Firewall::from_postfix(r#"{"timeout" : 2000, "default_policy": "deny", "cache" : false, "expressions": [{"policy": "deny", "postfix_tokens": [{"type": "predicate", "condition": "equal", "protocol": ["HTTPS"]}]}]}"#).unwrap()); } } diff --git a/src/firewall/firewall.rs b/src/firewall/firewall.rs index 7c6f39c..27fb09d 100644 --- a/src/firewall/firewall.rs +++ b/src/firewall/firewall.rs @@ -12,6 +12,7 @@ use nullnet_liberror::{location, Error, ErrorHandler, Location}; pub struct Firewall { pub(crate) timeout: u32, pub(crate) default_policy: FirewallPolicy, + pub(crate) cache: bool, pub(super) expressions: Vec, } @@ -68,6 +69,7 @@ impl Default for Firewall { Self { timeout: 1000, // default timeout in milliseconds default_policy: FirewallPolicy::Allow, + cache: true, expressions: Vec::new(), } } @@ -110,6 +112,7 @@ mod tests { std::sync::LazyLock::new(|| Firewall { timeout: 1000, default_policy: FirewallPolicy::Allow, + cache: true, expressions: Vec::from([ FirewallExpression { policy: FirewallPolicy::Deny, @@ -228,7 +231,7 @@ mod tests { ]), }); - const SERIALIZED_SAMPLE_FIREWALL: &str = r#"{"timeout":1000,"default_policy":"allow","expressions":[{"policy":"deny","postfix_tokens":[{"type":"predicate","condition":"equal","protocol":["HTTP","HTTPS"],"direction":"in"},{"type":"predicate","condition":"contains","http_request_url":[".php"]},{"type":"operator","value":"or"},{"type":"predicate","condition":"equal","country":["US"]},{"type":"operator","value":"and"}]},{"policy":"allow","postfix_tokens":[{"type":"predicate","condition":"contains","http_request_body":["Hello"]},{"type":"predicate","condition":"greater_equal","http_request_header":{"From":["foo@bar.com","bar@foo.com","foo@baz.com"]}},{"type":"operator","value":"or"},{"type":"predicate","condition":"equal","http_request_rate_limit":{"limit":5,"period":30,"urls":["/account","/some/other/path"]}},{"type":"operator","value":"or"}]},{"policy":"deny","postfix_tokens":[{"type":"predicate","condition":"lower_than","http_response_code":[205,206]},{"type":"predicate","condition":"not_starts_with","http_request_query":{"Name":["giuliano","giacomo"]}},{"type":"operator","value":"or"},{"type":"predicate","condition":"ends_with","http_response_size":[100,200,300]},{"type":"operator","value":"or"},{"type":"predicate","condition":"contains","source_ip":["alias_name"]},{"type":"operator","value":"or"}]}]}"#; + const SERIALIZED_SAMPLE_FIREWALL: &str = r#"{"timeout":1000,"default_policy":"allow","cache":true,"expressions":[{"policy":"deny","postfix_tokens":[{"type":"predicate","condition":"equal","protocol":["HTTP","HTTPS"],"direction":"in"},{"type":"predicate","condition":"contains","http_request_url":[".php"]},{"type":"operator","value":"or"},{"type":"predicate","condition":"equal","country":["US"]},{"type":"operator","value":"and"}]},{"policy":"allow","postfix_tokens":[{"type":"predicate","condition":"contains","http_request_body":["Hello"]},{"type":"predicate","condition":"greater_equal","http_request_header":{"From":["foo@bar.com","bar@foo.com","foo@baz.com"]}},{"type":"operator","value":"or"},{"type":"predicate","condition":"equal","http_request_rate_limit":{"limit":5,"period":30,"urls":["/account","/some/other/path"]}},{"type":"operator","value":"or"}]},{"policy":"deny","postfix_tokens":[{"type":"predicate","condition":"lower_than","http_response_code":[205,206]},{"type":"predicate","condition":"not_starts_with","http_request_query":{"Name":["giuliano","giacomo"]}},{"type":"operator","value":"or"},{"type":"predicate","condition":"ends_with","http_response_size":[100,200,300]},{"type":"operator","value":"or"},{"type":"predicate","condition":"contains","source_ip":["alias_name"]},{"type":"operator","value":"or"}]}]}"#; #[test] fn test_firewall_load_from_infix_json() { diff --git a/src/firewall/infix_firewall.rs b/src/firewall/infix_firewall.rs index 0f092d6..b85be6e 100644 --- a/src/firewall/infix_firewall.rs +++ b/src/firewall/infix_firewall.rs @@ -10,6 +10,7 @@ use crate::proto::appguard_commands::FirewallPolicy; pub struct InfixFirewall { timeout: u32, default_policy: FirewallPolicy, + cache: bool, expressions: Vec, } @@ -18,7 +19,8 @@ impl InfixFirewall { let mut firewall = Firewall { timeout: self.timeout, default_policy: self.default_policy, - ..Firewall::default() + cache: self.cache, + expressions: Vec::new(), }; for expr in self.expressions { firewall.expressions.push(FirewallExpression { @@ -41,6 +43,7 @@ impl Default for InfixFirewall { Self { timeout: 1000, // default timeout in milliseconds default_policy: FirewallPolicy::Allow, + cache: true, expressions: Vec::new(), } } diff --git a/src/http_proxy/api/update_client_firewall.rs b/src/http_proxy/api/update_client_firewall.rs index 3900037..a48b442 100644 --- a/src/http_proxy/api/update_client_firewall.rs +++ b/src/http_proxy/api/update_client_firewall.rs @@ -56,6 +56,7 @@ pub async fn update_client_firewall( log::info!("Updating firewall for '{device_id}': {firewall:?}",); let default_policy = firewall.default_policy; let timeout = firewall.timeout; + let cache = firewall.cache; if deactivate_old_firewalls(&context, device_id, &jwt) .await @@ -84,6 +85,7 @@ pub async fn update_client_firewall( let defaults = FirewallDefaults { timeout, policy: default_policy.into(), + cache, }; let Some(instances) = context diff --git a/src/proto/appguard_commands.rs b/src/proto/appguard_commands.rs index 930cb73..8741afc 100644 --- a/src/proto/appguard_commands.rs +++ b/src/proto/appguard_commands.rs @@ -71,6 +71,8 @@ pub struct FirewallDefaults { pub timeout: u32, #[prost(enumeration = "FirewallPolicy", tag = "2")] pub policy: i32, + #[prost(bool, tag = "3")] + pub cache: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/test_material/firewall/firewall.json b/test_material/firewall/firewall.json index a4ec9b4..bb5ad8c 100644 --- a/test_material/firewall/firewall.json +++ b/test_material/firewall/firewall.json @@ -1 +1 @@ -{"timeout": 1000, "default_policy": "allow", "expressions": [{"policy": "deny", "infix_tokens": [{"type": "parenthesis", "value": "open"}, {"type": "predicate", "condition": "equal", "protocol": ["HTTP", "HTTPS"], "direction": "in"}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "contains", "http_request_url": [".php"]}, {"type": "parenthesis", "value": "close"}, {"type": "operator", "value": "and"}, {"type": "predicate", "condition": "equal", "country": ["US"]}]}, {"policy": "allow", "infix_tokens": [{"type": "predicate", "condition": "contains", "smtp_request_body": ["Hello"]}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "greater_equal", "smtp_request_header": {"From": ["foo@bar.com", "bar@foo.com", "foo@baz.com"]}}]}, {"policy": "deny", "infix_tokens": [{"type": "predicate", "condition": "lower_than", "smtp_response_code": [205, 206]}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "not_starts_with", "http_request_query": {"Name": ["giuliano", "giacomo"]}}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "ends_with", "http_response_size": [100, 200, 300]}]}]} \ No newline at end of file +{"timeout": 1000, "default_policy": "allow", "cache": true, "expressions": [{"policy": "deny", "infix_tokens": [{"type": "parenthesis", "value": "open"}, {"type": "predicate", "condition": "equal", "protocol": ["HTTP", "HTTPS"], "direction": "in"}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "contains", "http_request_url": [".php"]}, {"type": "parenthesis", "value": "close"}, {"type": "operator", "value": "and"}, {"type": "predicate", "condition": "equal", "country": ["US"]}]}, {"policy": "allow", "infix_tokens": [{"type": "predicate", "condition": "contains", "smtp_request_body": ["Hello"]}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "greater_equal", "smtp_request_header": {"From": ["foo@bar.com", "bar@foo.com", "foo@baz.com"]}}]}, {"policy": "deny", "infix_tokens": [{"type": "predicate", "condition": "lower_than", "smtp_response_code": [205, 206]}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "not_starts_with", "http_request_query": {"Name": ["giuliano", "giacomo"]}}, {"type": "operator", "value": "or"}, {"type": "predicate", "condition": "ends_with", "http_response_size": [100, 200, 300]}]}]} \ No newline at end of file diff --git a/test_material/firewall_test_1.json b/test_material/firewall_test_1.json index 823fe5c..998df8f 100644 --- a/test_material/firewall_test_1.json +++ b/test_material/firewall_test_1.json @@ -1,6 +1,7 @@ { "timeout": 1000, "default_policy": "allow", + "cache": true, "expressions": [ { "policy": "deny", diff --git a/test_material/firewall_test_2.json b/test_material/firewall_test_2.json index 6045020..95334f0 100644 --- a/test_material/firewall_test_2.json +++ b/test_material/firewall_test_2.json @@ -1,6 +1,7 @@ { "timeout": 1000, "default_policy": "deny", + "cache": true, "expressions": [ { "policy": "allow",