mirror of
https://github.com/nftables-rs/nftables-rs.git
synced 2026-10-14 08:01:26 +00:00
fix: accept fib flags as string or array
nft 1.1.4 changed the json output to return only a single string if there is only one flag set.[1,2] The same logic applies to some other types as well which I update in the following commits. [1] https://github.com/nftables-rs/nftables-rs/issues/183 [2] https://bugzilla.netfilter.org/show_bug.cgi?id=1806 Fixes #183 Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Vendored
+1
@@ -0,0 +1 @@
|
||||
These files are where either generated by a specific nftables version or by hand to test specific json parsing behavior.
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"nftables": [
|
||||
{
|
||||
"metainfo": {
|
||||
"version": "1.1.0",
|
||||
"release_name": "some name",
|
||||
"json_schema_version": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": {
|
||||
"family": "ip",
|
||||
"name": "test",
|
||||
"handle": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"chain": {
|
||||
"family": "ip",
|
||||
"table": "test",
|
||||
"name": "prerouting",
|
||||
"handle": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"rule": {
|
||||
"family": "ip",
|
||||
"table": "test",
|
||||
"chain": "prerouting",
|
||||
"handle": 2,
|
||||
"expr": [
|
||||
{
|
||||
"match": {
|
||||
"op": "==",
|
||||
"left": {
|
||||
"fib": {
|
||||
"result": "type",
|
||||
"flags": [
|
||||
"daddr"
|
||||
]
|
||||
}
|
||||
},
|
||||
"right": "local"
|
||||
}
|
||||
},
|
||||
{
|
||||
"accept": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"nftables": [
|
||||
{
|
||||
"metainfo": {
|
||||
"version": "1.1.0",
|
||||
"release_name": "some name",
|
||||
"json_schema_version": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": {
|
||||
"family": "ip",
|
||||
"name": "test",
|
||||
"handle": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"chain": {
|
||||
"family": "ip",
|
||||
"table": "test",
|
||||
"name": "prerouting",
|
||||
"handle": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"rule": {
|
||||
"family": "ip",
|
||||
"table": "test",
|
||||
"chain": "prerouting",
|
||||
"handle": 2,
|
||||
"expr": [
|
||||
{
|
||||
"match": {
|
||||
"op": "==",
|
||||
"left": {
|
||||
"fib": {
|
||||
"result": "type",
|
||||
"flags": "daddr"
|
||||
}
|
||||
},
|
||||
"right": "local"
|
||||
}
|
||||
},
|
||||
{
|
||||
"accept": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+8
-2
@@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
|
||||
use std::{borrow::Cow, collections::HashSet};
|
||||
|
||||
use crate::stmt::{Counter, JumpTarget, Statement};
|
||||
use crate::visitor::deserialize_flags;
|
||||
use strum_macros::EnumString;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
@@ -300,7 +302,7 @@ pub struct SctpChunk<'a> {
|
||||
#[serde(rename = "meta")]
|
||||
/// Create a reference to packet meta data.
|
||||
///
|
||||
/// See [this page](https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation)
|
||||
/// See [this page](https://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation)
|
||||
/// for more information.
|
||||
pub struct Meta {
|
||||
/// The packet [meta data key](MetaKey).
|
||||
@@ -589,6 +591,7 @@ impl Default for SymHash {
|
||||
pub struct Fib {
|
||||
/// The data to be queried by fib lookup.
|
||||
pub result: FibResult,
|
||||
#[serde(deserialize_with = "deserialize_flags")]
|
||||
/// The tuple of elements ([FibFlags](FibFlag)) that is used as input to the
|
||||
/// fib lookup functions.
|
||||
pub flags: HashSet<FibFlag>,
|
||||
@@ -618,8 +621,11 @@ pub enum FibResult {
|
||||
Type,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Hash, JsonSchema)]
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, EnumString, Hash, JsonSchema,
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
/// Represents flags for `fib` lookup.
|
||||
pub enum FibFlag {
|
||||
/// Consider the source address of a packet.
|
||||
|
||||
@@ -113,3 +113,49 @@ where
|
||||
None => s.serialize_some(&0_usize),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize string or array of strings into the given HashSet type.
|
||||
pub fn deserialize_flags<'de, D, T>(deserializer: D) -> Result<HashSet<T>, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
T: FromStr + Eq + core::hash::Hash + Deserialize<'de>,
|
||||
<T as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
struct FlagSet<T>(PhantomData<T>);
|
||||
impl<'de, T> de::Visitor<'de> for FlagSet<T>
|
||||
where
|
||||
T: FromStr + Eq + core::hash::Hash + Deserialize<'de>,
|
||||
<T as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
type Value = HashSet<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("single string or list of strings")
|
||||
}
|
||||
|
||||
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(HashSet::default())
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
<T as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
let mut h: HashSet<T> = HashSet::new();
|
||||
h.insert(T::from_str(value).map_err(<E>::custom)?);
|
||||
Ok(h)
|
||||
}
|
||||
|
||||
fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
|
||||
where
|
||||
S: de::SeqAccess<'de>,
|
||||
{
|
||||
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_any(FlagSet(PhantomData))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
use std::{fs::File, io::BufReader};
|
||||
|
||||
use nftables::schema::Nftables;
|
||||
|
||||
// nft 1.1.4 changed behavior where the flag is printed as single string instead of array
|
||||
// As such this lib should be able to parse both and return the same result.
|
||||
// https://bugzilla.netfilter.org/show_bug.cgi?id=1806
|
||||
#[test]
|
||||
fn test_parse_fib_flags() {
|
||||
let file1 = BufReader::new(
|
||||
File::open("resources/test/fixtures/single-fib-flag-1.json").expect("Cannot open file1"),
|
||||
);
|
||||
let json1: Nftables =
|
||||
serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_reader(file1))
|
||||
.expect("failed to parse json1");
|
||||
|
||||
let file2 = BufReader::new(
|
||||
File::open("resources/test/fixtures/single-fib-flag-2.json").expect("Cannot open file2"),
|
||||
);
|
||||
|
||||
let json2: Nftables =
|
||||
serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_reader(file2))
|
||||
.expect("failed to parse json2");
|
||||
|
||||
assert_eq!(json1, json2, "Both parsed files should be identical")
|
||||
}
|
||||
Reference in New Issue
Block a user