Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(event)!: use typed-path for filesystem paths #26

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions falco_event/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ bitflags = { version = "2.4.2" }
anyhow = "1.0.81"
chrono = "0.4.38"
serde = { version = "1.0.210", features = ["derive"], optional = true }
typed-path = "0.9.3"

[target.'cfg(target_os = "linux")'.dependencies]
nix = { version = "0.29.0", features = ["signal"] }
Expand Down
4 changes: 2 additions & 2 deletions falco_event/src/fields/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ use std::ffi::CStr;
pub use std::net::IpAddr as PT_IPADDR;
pub use std::net::Ipv4Addr as PT_IPV4ADDR;
pub use std::net::Ipv6Addr as PT_IPV6ADDR;
pub use std::path::Path as PT_FSPATH;
pub use std::time::Duration as PT_RELTIME;
pub use std::time::SystemTime as PT_ABSTIME;
pub use typed_path::UnixPath as PT_FSPATH;

/// Signed 8-bit value ([i8])
pub type PT_INT8 = i8;
Expand Down Expand Up @@ -97,7 +97,7 @@ pub mod owned {
pub use crate::types::OwnedSockTuple as PT_SOCKTUPLE;
pub use std::ffi::CString as PT_CHARBUF;
use std::ffi::CString;
pub use std::path::PathBuf as PT_FSPATH;
pub use typed_path::UnixPathBuf as PT_FSPATH;

/// Arbitrary (owned) byte buffer (`Vec<u8>`)
pub type PT_BYTEBUF = Vec<u8>;
Expand Down
1 change: 1 addition & 0 deletions falco_event/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod utf_chunked;
#[cfg(feature = "serde")]
pub mod serde {
pub use super::bytebuf::serde::*;
pub use super::path::serde::*;
pub use super::string::serde::*;
}

Expand Down
24 changes: 13 additions & 11 deletions falco_event/src/types/net/sockaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL, PPM_AF_UNSPEC};
use crate::types::format::Format;
use crate::types::{Borrow, Borrowed, EndpointV4, EndpointV6};
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::ffi::OsStr;
use std::fmt::Formatter;
use std::io::Write;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
use typed_path::{UnixPath, UnixPathBuf};

/// A socket address
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[derive(Debug)]
pub enum SockAddr<'a> {
/// Unix sockets
Unix(&'a Path),
Unix(
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))] &'a UnixPath,
),

/// IPv4 sockets
V4(EndpointV4),
Expand Down Expand Up @@ -71,9 +71,9 @@ impl<'a> FromBytes<'a> for SockAddr<'a> {
let variant = buf.read_u8()?;
match variant as u32 {
PPM_AF_LOCAL => {
let path = <OsStr as OsStrExt>::from_bytes(buf);
*buf = &[];
Ok(Self::Unix(Path::new(path)))
// TODO embedded NULs
let path = std::mem::take(buf);
Ok(Self::Unix(UnixPath::new(path)))
}
PPM_AF_INET => {
let addr = EndpointV4::from_bytes(buf)?;
Expand All @@ -97,7 +97,7 @@ where
fn format(&self, fmt: &mut Formatter) -> std::fmt::Result {
match self {
SockAddr::Unix(u) => {
let bytes = u.as_os_str().as_bytes();
let bytes = u.as_bytes();
fmt.write_str("unix://")?;
bytes.format(fmt)
}
Expand All @@ -114,7 +114,9 @@ where
#[derive(Debug)]
pub enum OwnedSockAddr {
/// Unix sockets
Unix(PathBuf),
Unix(
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))] UnixPathBuf,
),

/// IPv4 sockets
V4(EndpointV4),
Expand Down Expand Up @@ -150,11 +152,11 @@ impl Borrow for OwnedSockAddr {
mod tests {
use crate::types::{OwnedSockAddr, Port, SockAddr};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::Path;
use typed_path::UnixPath;

#[test]
fn test_serde_sockaddr_unix() {
let path = Path::new("/path/to/unix");
let path = UnixPath::new("/path/to/unix");
let sockaddr = SockAddr::Unix(path);

let json = serde_json::to_string(&sockaddr).unwrap();
Expand Down
20 changes: 9 additions & 11 deletions falco_event/src/types/net/socktuple.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::fmt::{Debug, Display, Formatter};
use std::io::Write;
use std::path::{Path, PathBuf};

use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL};
use crate::fields::{FromBytes, FromBytesResult, ToBytes};
use crate::types::format::Format;
use crate::types::net::endpoint::{EndpointV4, EndpointV6};
use crate::types::{Borrow, Borrowed};
use byteorder::{ReadBytesExt, WriteBytesExt};
use typed_path::{UnixPath, UnixPathBuf};

/// Socket tuple: describing both endpoints of a connection
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
Expand All @@ -21,7 +21,8 @@ pub enum SockTuple<'a> {
/// destination socket kernel pointer
dest_ptr: u64,
/// filesystem path to the socket
path: &'a Path,
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))]
path: &'a UnixPath,
},

/// IPv4 connection
Expand Down Expand Up @@ -146,7 +147,7 @@ impl<'a> FromBytes<'a> for SockTuple<'a> {

impl<F> Format<F> for SockTuple<'_>
where
for<'a> &'a Path: Format<F>,
for<'a> &'a UnixPath: Format<F>,
EndpointV4: Format<F>,
EndpointV6: Format<F>,
{
Expand Down Expand Up @@ -187,7 +188,8 @@ pub enum OwnedSockTuple {
/// destination socket kernel pointer
dest_ptr: u64,
/// filesystem path to the socket
path: PathBuf,
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))]
path: UnixPathBuf,
},

/// IPv4 connection
Expand Down Expand Up @@ -249,7 +251,6 @@ mod tests {
use super::*;
use crate::types::Port;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::ffi::OsStrExt;
use std::str::FromStr;

#[test]
Expand Down Expand Up @@ -324,10 +325,7 @@ mod tests {

assert_eq!(source_addr, 0);
assert_eq!(dest_addr, 0xffff98bc4ecf2000);
assert_eq!(
path.as_os_str().as_bytes(),
b"/var/run/nscd/socket".as_slice()
);
assert_eq!(path.as_bytes(), b"/var/run/nscd/socket".as_slice());

assert_eq!(binary, binary2.as_slice(),);
}
Expand All @@ -337,12 +335,12 @@ mod tests {
mod serde_tests {
use crate::types::{OwnedSockTuple, Port, SockTuple};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::Path;
use std::str::FromStr;
use typed_path::UnixPath;

#[test]
fn test_serde_socktuple_unix() {
let path = Path::new("/path/to/unix");
let path = UnixPath::new("/path/to/unix");
let sockaddr = SockTuple::Unix {
source_ptr: 1,
dest_ptr: 2,
Expand Down
117 changes: 91 additions & 26 deletions falco_event/src/types/path/absolute_path.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
use std::ffi::{CStr, OsStr};
use std::fmt::Formatter;
use std::io::Write;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

use crate::event_derive::{FromBytes, FromBytesResult, ToBytes};
use crate::types::format::Format;
use crate::types::{Borrow, Borrowed};
use std::ffi::CStr;
use std::fmt::Formatter;
use std::io::Write;
use typed_path::{UnixPath, UnixPathBuf};

impl<'a> FromBytes<'a> for &'a Path {
impl<'a> FromBytes<'a> for &'a UnixPath {
fn from_bytes(buf: &mut &'a [u8]) -> FromBytesResult<Self> {
let buf = <&CStr>::from_bytes(buf)?;
let osstr = OsStr::from_bytes(buf.to_bytes());
Ok(Path::new(osstr))
Ok(UnixPath::new(buf.to_bytes()))
}
}

impl ToBytes for &Path {
impl ToBytes for &UnixPath {
fn binary_size(&self) -> usize {
self.as_os_str().len()
self.as_bytes().len() + 1
}

fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
self.as_os_str().as_bytes().write(&mut writer)?;
self.as_bytes().write(&mut writer)?;
0u8.write(writer)
}

Expand All @@ -31,59 +28,127 @@ impl ToBytes for &Path {
}
}

impl<F> Format<F> for &Path
impl<F> Format<F> for &UnixPath
where
for<'a> &'a [u8]: Format<F>,
{
fn format(&self, fmt: &mut Formatter) -> std::fmt::Result {
let bytes = self.as_os_str().as_bytes();
let bytes = self.as_bytes();
bytes.format(fmt)
}
}

impl Borrowed for Path {
type Owned = PathBuf;
impl Borrowed for UnixPath {
type Owned = UnixPathBuf;
}

impl Borrow for PathBuf {
type Borrowed<'a> = &'a Path;
impl Borrow for UnixPathBuf {
type Borrowed<'a> = &'a UnixPath;

fn borrow(&self) -> Self::Borrowed<'_> {
self.as_path()
}
}

#[cfg(feature = "serde")]
pub mod serde {
pub mod unix_path {
use crate::types::utf_chunked::{OwnedUtfChunked, UtfChunked};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use typed_path::{UnixPath, UnixPathBuf};

pub fn serialize<S: Serializer>(path: &UnixPath, ser: S) -> Result<S::Ok, S::Error> {
if ser.is_human_readable() {
let chunks = UtfChunked::from(path.as_bytes());
chunks.serialize(ser)
} else {
path.as_bytes().serialize(ser)
}
}

pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<UnixPathBuf, D::Error> {
let chunks: OwnedUtfChunked = Deserialize::deserialize(de)?;
Ok(UnixPathBuf::from(chunks.into_vec()))
}
}

pub mod unix_path_option {
use crate::types::utf_chunked::UtfChunked;
use serde::{Serialize, Serializer};
use typed_path::UnixPath;

pub fn serialize<S: Serializer>(
path: &Option<&UnixPath>,
ser: S,
) -> Result<S::Ok, S::Error> {
if ser.is_human_readable() {
let chunks = path.as_ref().map(|path| UtfChunked::from(path.as_bytes()));
chunks.serialize(ser)
} else {
path.map(|p| p.as_bytes()).serialize(ser)
}
}
}

pub mod unix_path_option_owned {
use crate::types::utf_chunked::{OwnedUtfChunked, UtfChunked};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use typed_path::UnixPathBuf;

pub fn serialize<S: Serializer>(
path: &Option<UnixPathBuf>,
ser: S,
) -> Result<S::Ok, S::Error> {
let chunks = path.as_ref().map(|path| UtfChunked::from(path.as_bytes()));
chunks.serialize(ser)
}

pub fn deserialize<'de, D: Deserializer<'de>>(
de: D,
) -> Result<Option<UnixPathBuf>, D::Error> {
let chunks: Option<OwnedUtfChunked> = Deserialize::deserialize(de)?;
Ok(chunks.map(|c| UnixPathBuf::from(c.into_vec())))
}
}
}

#[cfg(test)]
mod tests {
use std::path::{Path, PathBuf};
use std::str::FromStr;

use crate::event_derive::{FromBytes, ToBytes};
use std::str::FromStr;
use typed_path::{UnixPath, UnixPathBuf};

#[test]
fn test_absolute_path() {
let path = PathBuf::from_str("/foo").unwrap();
let path = UnixPathBuf::from_str("/foo").unwrap();
let mut binary = Vec::new();

assert_eq!(path.as_path().binary_size(), 5);

path.as_path().write(&mut binary).unwrap();
hexdump::hexdump(binary.as_slice());

assert_eq!(binary.as_slice(), "/foo\0".as_bytes());

let mut buf = binary.as_slice();
let path = <&Path>::from_bytes(&mut buf).unwrap();
let path = <&UnixPath>::from_bytes(&mut buf).unwrap();
assert_eq!(path.to_str().unwrap(), "/foo");
}

#[cfg(feature = "serde")]
#[test]
fn test_serde_absolute_path() {
let path = Path::new("/foo");
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
struct SerPathBuf(#[serde(with = "super::serde::unix_path")] UnixPathBuf);

let path = SerPathBuf(UnixPathBuf::from("/foo"));

let json = serde_json::to_string(&path).unwrap();
assert_eq!(json, "\"/foo\"");

let path2: PathBuf = serde_json::from_str(&json).unwrap();
assert_eq!(path2, path);
let path2: SerPathBuf = serde_json::from_str(&json).unwrap();
assert_eq!(path2.0, path.0);

let json2 = serde_json::to_string(&path2).unwrap();
assert_eq!(json, json2);
Expand Down
Loading
Loading