Rule parser: require "in" or "out" direction specifier
This commit is contained in:
parent
0dfede19e6
commit
964014b98b
|
|
@ -1,5 +1,6 @@
|
|||
rule = { SOI ~ (stateful | target) ~ EOI }
|
||||
|
||||
stateful = { direction ~ " "+ ~ target }
|
||||
direction = { "from" | "to" }
|
||||
stateful = { direction ~ " "+ ~ side ~ " "+ ~ target }
|
||||
direction = { "in" | "out" }
|
||||
side = { "from" | "to" }
|
||||
target = @{ ANY+ }
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ pub enum Rule {
|
|||
Stateless(Target),
|
||||
Stateful {
|
||||
direction: Direction,
|
||||
target: Target,
|
||||
source: Option<Target>,
|
||||
destination: Option<Target>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -32,8 +33,8 @@ pub enum Target {
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Direction {
|
||||
From,
|
||||
To,
|
||||
In,
|
||||
Out,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -66,14 +67,27 @@ impl Rule {
|
|||
.expect("a stateful rule always has a direction")
|
||||
.as_str()
|
||||
{
|
||||
"from" => Direction::From,
|
||||
"to" => Direction::To,
|
||||
"in" => Direction::In,
|
||||
"out" => Direction::Out,
|
||||
direction => unreachable!("unexpected direction: {direction}"),
|
||||
};
|
||||
let side = fields
|
||||
.next()
|
||||
.expect("a stateful rule always has a side")
|
||||
.as_str();
|
||||
let target =
|
||||
Self::parse_target(&fields.next().expect("a stateful rule always has a target"))?;
|
||||
let (source, destination) = match side {
|
||||
"from" => (Some(target), None),
|
||||
"to" => (None, Some(target)),
|
||||
side => unreachable!("unexpected side: {side}"),
|
||||
};
|
||||
|
||||
Ok(Rule::Stateful { direction, target })
|
||||
Ok(Rule::Stateful {
|
||||
direction,
|
||||
source,
|
||||
destination,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_target(pair: &Pair<'_, SyntaxRule>) -> Result<Target, ParseRuleError> {
|
||||
|
|
@ -139,18 +153,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn parses_stateful_directions() {
|
||||
let private_network = Target::Prefix(Ipv4Net::from_str("10.0.0.0/8").unwrap());
|
||||
|
||||
assert_eq!(
|
||||
"from @host".parse::<Rule>().unwrap(),
|
||||
"in from @host".parse::<Rule>().unwrap(),
|
||||
Rule::Stateful {
|
||||
direction: Direction::From,
|
||||
target: Target::Host,
|
||||
direction: Direction::In,
|
||||
source: Some(Target::Host),
|
||||
destination: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
"to 10.0.0.0/8".parse::<Rule>().unwrap(),
|
||||
"out to 10.0.0.0/8".parse::<Rule>().unwrap(),
|
||||
Rule::Stateful {
|
||||
direction: Direction::To,
|
||||
target: Target::Prefix(Ipv4Net::from_str("10.0.0.0/8").unwrap()),
|
||||
direction: Direction::Out,
|
||||
source: None,
|
||||
destination: Some(private_network),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -159,18 +177,15 @@ mod tests {
|
|||
fn rejects_invalid_rules() {
|
||||
for input in [
|
||||
"",
|
||||
"from",
|
||||
"around @host",
|
||||
"from @host tcp",
|
||||
"from @host port 8080",
|
||||
"from @host proto sctp",
|
||||
"from @host proto tcp port 8080",
|
||||
"from@host",
|
||||
"from=@host",
|
||||
" from @host",
|
||||
"from @host ",
|
||||
"from\t@host",
|
||||
"from\n@host",
|
||||
"from @host",
|
||||
"in",
|
||||
"out",
|
||||
"in @host",
|
||||
"out @host",
|
||||
"infrom @host",
|
||||
" in from @host",
|
||||
"in from @host ",
|
||||
"in\tfrom @host",
|
||||
] {
|
||||
assert!(input.parse::<Rule>().is_err(), "{input:?} should fail");
|
||||
}
|
||||
|
|
|
|||
22
src/main.rs
22
src/main.rs
|
|
@ -63,8 +63,9 @@ struct Args {
|
|||
help = "Comma-separated list of rules for allowing traffic.\n\n\
|
||||
Rule forms:\n\n\
|
||||
* TARGET: stateless rule\n\
|
||||
* from TARGET: stateful flows initiated from TARGET (not supported yet)\n\
|
||||
* to TARGET: stateful flows initiated toward TARGET (not supported yet)\n\n\
|
||||
* in|out from TARGET: stateful flows initiated from TARGET (not supported yet)\n\
|
||||
* in|out to TARGET: stateful flows initiated toward TARGET (not supported yet)\n\n\
|
||||
Stateful rules specify the initiating packet's direction: in enters the VM; out leaves it.\n\n\
|
||||
Targets are:\n\n\
|
||||
* IPv4 CIDRs\n\
|
||||
* @host, which matches the vmnet bridge gateway IP\n\n\
|
||||
|
|
@ -74,9 +75,9 @@ struct Args {
|
|||
--block=0.0.0.0/0 is specified.\n\n\
|
||||
Examples:\n\n\
|
||||
* --allow=192.168.0.0/24 — allow stateless traffic with this LAN\n\
|
||||
* --allow=\"from @host\" — allow stateful flows initiated from @host\n\
|
||||
* --allow=\"to 192.168.0.0/24\" — allow stateful flows initiated toward this LAN\n\
|
||||
* --allow=\"from @host,to 192.168.0.0/24\" — multiple rules may be comma-separated",
|
||||
* --allow=\"in from @host\" — allow stateful flows initiated from @host\n\
|
||||
* --allow=\"out to 192.168.0.0/24\" — allow stateful flows initiated toward this LAN\n\
|
||||
* --allow=\"in from @host,out to 192.168.0.0/24\" — multiple rules may be comma-separated",
|
||||
value_name = "comma-separated rules",
|
||||
use_value_delimiter = true,
|
||||
action = clap::ArgAction::Set
|
||||
|
|
@ -89,8 +90,9 @@ struct Args {
|
|||
help = "Comma-separated list of rules for blocking traffic.\n\n\
|
||||
Rule forms:\n\n\
|
||||
* TARGET: stateless rule\n\
|
||||
* from TARGET: stateful flows initiated from TARGET (not supported yet)\n\
|
||||
* to TARGET: stateful flows initiated toward TARGET (not supported yet)\n\n\
|
||||
* in|out from TARGET: stateful flows initiated from TARGET (not supported yet)\n\
|
||||
* in|out to TARGET: stateful flows initiated toward TARGET (not supported yet)\n\n\
|
||||
Stateful rules specify the initiating packet's direction: in enters the VM; out leaves it.\n\n\
|
||||
Targets are:\n\n\
|
||||
* IPv4 CIDRs\n\
|
||||
* @host, which matches the vmnet bridge gateway IP\n\n\
|
||||
|
|
@ -98,9 +100,9 @@ struct Args {
|
|||
allowed and blocked, blocking takes precedence.\n\n\
|
||||
Examples:\n\n\
|
||||
* --block=0.0.0.0/0 — establish a stateless default-deny policy\n\
|
||||
* --block=\"from @host\" — block stateful flows initiated from @host\n\
|
||||
* --block=\"to 66.66.66.0/24\" — block stateful flows initiated toward this CIDR\n\
|
||||
* --block=\"from @host,to 66.66.66.0/24\" — multiple rules may be comma-separated",
|
||||
* --block=\"in from @host\" — block stateful flows initiated from @host\n\
|
||||
* --block=\"out to 66.66.66.0/24\" — block stateful flows initiated toward this CIDR\n\
|
||||
* --block=\"in from @host,out to 66.66.66.0/24\" — multiple rules may be comma-separated",
|
||||
value_name = "comma-separated rules",
|
||||
use_value_delimiter = true,
|
||||
action = clap::ArgAction::Set
|
||||
|
|
|
|||
Loading…
Reference in New Issue