Skip to content

Commit

Permalink
Merge branch 'main' of github.com:GyulyVGC/nullnet-firewall
Browse files Browse the repository at this point in the history
  • Loading branch information
GyulyVGC committed Jan 30, 2024
2 parents 2f7f5fb + 457b0b5 commit 86d9097
Show file tree
Hide file tree
Showing 14 changed files with 591 additions and 100 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ Cargo.lock

.DS_Store
**/*.sqlite
**/*.sqlite-journal
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All releases with the relative changes are documented in this file.

## [UNRELEASED]
### Added
- `LogLevel` enum to represent all the available logging strategies (`Off`, `Console`, `Db`, `All`).
- New option `--log-level` for user-defined firewall rules, which allows to specify the logging strategy to use for traffic matching a given rule; if this option is not set, the default firewall logging strategy will be used.
### Changed
- `Firewall::log` method (that was accepting a boolean parameter) has been renamed to `Firewall::log_level` and now accepts a `LogLevel` parameter, useful to set the default firewall logging strategy.
### Fixed
- Only spawn logger thread if a valid firewall was instantiated.
- Added `bundled` feature to `rusqlite` dependency to properly work on Windows.

## [0.2.2] - 2024-01-19
### Changed
- `FirewallError`s now also include information about the file line number responsible for the error, enabling an easier debugging activity.
Expand Down
2 changes: 1 addition & 1 deletion samples/firewall.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Firewall rules (this is a comment line)

IN REJECT --source 8.8.8.8
IN REJECT --source 8.8.8.8 --log-level off
# Rules marked with '+' have higher priority
+ IN ACCEPT --source 8.8.8.0-8.8.8.10 --sport 8
OUT ACCEPT --source 8.8.8.8,7.7.7.7 --dport 900:1000,1,2,3
Expand Down
2 changes: 1 addition & 1 deletion samples/firewall_for_tests_1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ IN ACCEPT --source 2.1.1.2 --dest 2.1.1.1 --proto 1 --icmp-type 8
IN ACCEPT --source 2.1.1.2 --dest 2.1.1.1 --proto 1 --icmp-type 9
IN ACCEPT --source 2.1.1.2 --dest 2.1.1.1 --proto 58 --icmp-type 8
OUT REJECT
IN ACCEPT
IN ACCEPT --log-level console
# IN REJECT
2 changes: 1 addition & 1 deletion samples/firewall_for_tests_2.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
OUT REJECT --source 192.168.200.135 --sport 6700:6800,8080
+ OUT DENY --source 192.168.200.135-192.168.200.140 --sport 6700:6800,8080 --dport 1,2,2000
+ OUT DENY --source 192.168.200.135-192.168.200.140 --sport 6700:6800,8080 --log-level off --dport 1,2,2000
OUT REJECT --source 192.168.200.135 --sport 6700:6800,8080 --dport 1,2,2000
OUT REJECT --source 192.168.200.135 --sport 6750:6800,8080 --dest 192.168.200.21 --dport 1,2,2000

Expand Down
2 changes: 1 addition & 1 deletion samples/firewall_for_tests_3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ OUT REJECT --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd
+ OUT ACCEPT --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --sport 545:560,43,53
OUT DENY --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --proto 17 --sport 545:560,43,53 --dport 2396
OUT REJECT --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --proto 17 --sport 545:560,43,53 --dport 2395
IN DENY --sport 40:49,53
IN DENY --log-level db --sport 40:49,53
IN REJECT --sport 40:49,53 --source 3ffe:501:4819::41,3ffe:501:4819::42
6 changes: 6 additions & 0 deletions samples/firewall_for_tests_error_invalid_log_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
OUT REJECT --log-level console --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --sport 545:560,43,53
+ OUT ACCEPT --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --sport 545:560,43,53
OUT DENY --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --proto 17 --sport 545:560,43,53 --dport 2396
OUT REJECT --dest 3ffe:507:0:1:200:86ff:fe05:800-3ffe:507:0:1:200:86ff:fe05:08dd --proto 17 --log-level DB --sport 545:560,43,53 --dport 2395
IN DENY --sport 40:49,53
IN REJECT --sport 40:49,53 --source 3ffe:501:4819::41,3ffe:501:4819::42
9 changes: 9 additions & 0 deletions src/firewall_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub enum FirewallError {
InvalidIcmpTypeValue(usize, String),
/// The value supplied for the option `--proto` is invalid.
InvalidProtocolValue(usize, String),
/// The value supplied for the option `--log-level` is invalid.
InvalidLogLevelValue(usize, String),
/// An invalid direction has been specified for a firewall rule.
InvalidDirection(usize, String),
/// An invalid action has been specified for a firewall rule.
Expand Down Expand Up @@ -78,6 +80,13 @@ impl Display for FirewallError {
FirewallOption::PROTO
),
),
FirewallError::InvalidLogLevelValue(l, val) => (
l,
format!(
"incorrect value for option '{} {val}'",
FirewallOption::LOGLEVEL
),
),
FirewallError::InvalidDirection(l, direction) => {
(l, format!("incorrect direction '{direction}'"))
}
Expand Down
76 changes: 75 additions & 1 deletion src/firewall_option.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::str::FromStr;

use crate::log_level::LogLevel;
use crate::utils::ip_collection::IpCollection;
use crate::utils::port_collection::PortCollection;
use crate::{Fields, FirewallError};
Expand All @@ -19,6 +20,8 @@ pub(crate) enum FirewallOption {
Source(IpCollection),
/// Source ports
Sport(PortCollection),
/// Log level
LogLevel(LogLevel),
}

impl FirewallOption {
Expand All @@ -28,6 +31,7 @@ impl FirewallOption {
pub(crate) const PROTO: &'static str = "--proto";
pub(crate) const SOURCE: &'static str = "--source";
pub(crate) const SPORT: &'static str = "--sport";
pub(crate) const LOGLEVEL: &'static str = "--log-level";

pub(crate) fn new(l: usize, option: &str, value: &str) -> Result<Self, FirewallError> {
Ok(match option {
Expand All @@ -49,6 +53,7 @@ impl FirewallOption {
FirewallOption::SPORT => {
Self::Sport(PortCollection::new(l, FirewallOption::SPORT, value)?)
}
FirewallOption::LOGLEVEL => Self::LogLevel(LogLevel::from_str_with_line(l, value)?),
x => return Err(FirewallError::UnknownOption(l, x.to_owned())),
})
}
Expand All @@ -73,6 +78,7 @@ impl FirewallOption {
}
FirewallOption::Source(ip_collection) => ip_collection.contains(fields.source),
FirewallOption::Sport(port_collection) => port_collection.contains(fields.sport),
FirewallOption::LogLevel(_) => true,
}
}

Expand All @@ -84,6 +90,7 @@ impl FirewallOption {
FirewallOption::Source(_) => FirewallOption::SOURCE,
FirewallOption::Sport(_) => FirewallOption::SPORT,
FirewallOption::IcmpType(_) => FirewallOption::ICMPTYPE,
FirewallOption::LogLevel(_) => FirewallOption::LOGLEVEL,
}
}
}
Expand All @@ -96,7 +103,7 @@ mod tests {
use crate::utils::raw_packets::test_packets::{
ARP_PACKET, ICMP_PACKET, TCP_PACKET, UDP_IPV6_PACKET,
};
use crate::{DataLink, Fields, FirewallError};
use crate::{DataLink, Fields, FirewallError, LogLevel};

#[test]
fn test_new_dest_option() {
Expand Down Expand Up @@ -200,6 +207,29 @@ mod tests {
);
}

#[test]
fn test_new_log_level_option() {
assert_eq!(
FirewallOption::new(3, "--log-level", "off").unwrap(),
FirewallOption::LogLevel(LogLevel::Off)
);

assert_eq!(
FirewallOption::new(3, "--log-level", "all").unwrap(),
FirewallOption::LogLevel(LogLevel::All)
);

assert_eq!(
FirewallOption::new(3, "--log-level", "console").unwrap(),
FirewallOption::LogLevel(LogLevel::Console)
);

assert_eq!(
FirewallOption::new(3, "--log-level", "db").unwrap(),
FirewallOption::LogLevel(LogLevel::Db)
);
}

#[test]
fn test_not_existing_option() {
let err = FirewallOption::new(11, "--not-exists", "8.8.8.8").unwrap_err();
Expand All @@ -211,6 +241,11 @@ mod tests {
err.to_string(),
"Firewall error at line 11 - the specified option '--not-exists' doesn't exist"
);

assert_eq!(
FirewallOption::new(14, "--log", "ciao").unwrap_err(),
FirewallError::UnknownOption(14, "--log".to_owned())
);
}

#[test]
Expand Down Expand Up @@ -282,6 +317,16 @@ mod tests {
);
}

#[test]
fn test_invalid_log_level_option() {
let err = FirewallOption::new(17, "--log-level", "3").unwrap_err();
assert_eq!(err, FirewallError::InvalidLogLevelValue(17, "3".to_owned()));
assert_eq!(
err.to_string(),
"Firewall error at line 17 - incorrect value for option '--log-level 3'"
);
}

#[test]
fn test_dest_matches_packets() {
let dest_opt = FirewallOption::new(1, "--dest", "192.168.200.21,8.8.8.8,2.1.1.2").unwrap();
Expand Down Expand Up @@ -419,6 +464,35 @@ mod tests {
assert!(!range_sport_opt_miss.matches_packet(&arp_packet_fields));
}

#[test]
fn test_log_level_matches_packets() {
let off = FirewallOption::new(6, "--log-level", "off").unwrap();
let all = FirewallOption::new(7, "--log-level", "all").unwrap();
let console = FirewallOption::new(8, "--log-level", "console").unwrap();
let db = FirewallOption::new(6, "--log-level", "db").unwrap();

// tcp packet
let tcp_packet_fields = Fields::new(&TCP_PACKET, DataLink::Ethernet);
assert!(off.matches_packet(&tcp_packet_fields));
assert!(all.matches_packet(&tcp_packet_fields));
assert!(console.matches_packet(&tcp_packet_fields));
assert!(db.matches_packet(&tcp_packet_fields));

// icmp packet
let icmp_packet_fields = Fields::new(&ICMP_PACKET, DataLink::Ethernet);
assert!(off.matches_packet(&icmp_packet_fields));
assert!(all.matches_packet(&icmp_packet_fields));
assert!(console.matches_packet(&icmp_packet_fields));
assert!(db.matches_packet(&icmp_packet_fields));

// arp packet
let arp_packet_fields = Fields::new(&ARP_PACKET, DataLink::Ethernet);
assert!(off.matches_packet(&arp_packet_fields));
assert!(all.matches_packet(&arp_packet_fields));
assert!(console.matches_packet(&arp_packet_fields));
assert!(db.matches_packet(&arp_packet_fields));
}

#[test]
fn test_dest_matches_ipv6() {
let dest_ok = FirewallOption::new(2, "--dest", "3ffe:507:0:1:200:86ff:fe05:8da").unwrap();
Expand Down
Loading

0 comments on commit 86d9097

Please sign in to comment.