falco_event_schema/types/net/
socktuple.rs

1use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL};
2use falco_event::fields::{FromBytes, FromBytesError, ToBytes};
3use std::fmt::{Debug, Formatter};
4use std::io::Write;
5use std::net::{SocketAddrV4, SocketAddrV6};
6use typed_path::UnixPath;
7
8/// Socket tuple: describing both endpoints of a connection
9#[derive(Clone, Copy, Eq, PartialEq, Hash)]
10pub enum SockTuple<'a> {
11    /// Unix socket connection
12    Unix {
13        /// source socket kernel pointer
14        source_ptr: u64,
15        /// destination socket kernel pointer
16        dest_ptr: u64,
17        /// filesystem path to the socket
18        path: &'a UnixPath,
19    },
20
21    /// IPv4 connection
22    V4 {
23        /// source address and port
24        source: SocketAddrV4,
25        /// destination address and port
26        dest: SocketAddrV4,
27    },
28
29    /// IPv6 connection
30    V6 {
31        /// source address and port
32        source: SocketAddrV6,
33        /// destination address and port
34        dest: SocketAddrV6,
35    },
36
37    /// Unknown/other socket family: `PPM_AF_*` id and a raw byte buffer
38    Other(u8, &'a [u8]),
39}
40
41impl Debug for SockTuple<'_> {
42    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43        match self {
44            Self::Unix {
45                source_ptr,
46                dest_ptr,
47                path,
48            } => write!(f, "{:x}->{:x} {}", source_ptr, dest_ptr, path.display()),
49            Self::V4 { source, dest } => {
50                write!(f, "{source} -> {dest}")
51            }
52            Self::V6 { source, dest } => {
53                write!(f, "{source} -> {dest}")
54            }
55            Self::Other(af, buf) => f
56                .debug_struct("SockTuple")
57                .field("af", &af)
58                .field("addr", buf)
59                .finish(),
60        }
61    }
62}
63
64impl ToBytes for SockTuple<'_> {
65    fn binary_size(&self) -> usize {
66        match self {
67            Self::Unix {
68                source_ptr: source_addr,
69                dest_ptr: dest_addr,
70                path,
71            } => 1 + source_addr.binary_size() + dest_addr.binary_size() + path.binary_size(),
72            Self::V4 { source, dest } => 1 + source.binary_size() + dest.binary_size(),
73            Self::V6 { source, dest } => 1 + source.binary_size() + dest.binary_size(),
74            Self::Other(_, buf) => 1 + buf.len(),
75        }
76    }
77
78    fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
79        match self {
80            Self::Unix {
81                source_ptr: source_addr,
82                dest_ptr: dest_addr,
83                path,
84            } => {
85                writer.write_all(&[PPM_AF_LOCAL as u8])?;
86                source_addr.write(&mut writer)?;
87                dest_addr.write(&mut writer)?;
88                path.write(writer)
89            }
90            Self::V4 { source, dest } => {
91                writer.write_all(&[PPM_AF_INET as u8])?;
92                source.write(&mut writer)?;
93                dest.write(writer)
94            }
95            Self::V6 { source, dest } => {
96                writer.write_all(&[PPM_AF_INET6 as u8])?;
97                source.write(&mut writer)?;
98                dest.write(writer)
99            }
100            Self::Other(af, buf) => {
101                writer.write_all(&[*af])?;
102                ToBytes::write(buf, writer)
103            }
104        }
105    }
106
107    fn default_repr() -> impl ToBytes {
108        [].as_slice()
109    }
110}
111
112impl<'a> FromBytes<'a> for SockTuple<'a> {
113    fn from_bytes(buf: &mut &'a [u8]) -> Result<Self, FromBytesError> {
114        let variant = buf.split_off_first().ok_or(FromBytesError::InvalidLength)?;
115
116        match *variant as u32 {
117            PPM_AF_LOCAL => Ok(Self::Unix {
118                source_ptr: FromBytes::from_bytes(buf)?,
119                dest_ptr: FromBytes::from_bytes(buf)?,
120                path: FromBytes::from_bytes(buf)?,
121            }),
122            PPM_AF_INET => Ok(Self::V4 {
123                source: FromBytes::from_bytes(buf)?,
124                dest: FromBytes::from_bytes(buf)?,
125            }),
126            PPM_AF_INET6 => Ok(Self::V6 {
127                source: FromBytes::from_bytes(buf)?,
128                dest: FromBytes::from_bytes(buf)?,
129            }),
130            _ => Ok(Self::Other(*variant, std::mem::take(buf))),
131        }
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138    use std::net::{Ipv4Addr, Ipv6Addr};
139    use std::str::FromStr;
140
141    #[test]
142    fn test_socktuple_ipv4() {
143        let socktuple = SockTuple::V4 {
144            source: SocketAddrV4::new(Ipv4Addr::from_str("172.31.33.48").unwrap(), 47263),
145            dest: SocketAddrV4::new(Ipv4Addr::from_str("172.31.0.2").unwrap(), 53),
146        };
147
148        dbg!(&socktuple);
149
150        let mut binary = Vec::new();
151        socktuple.write(&mut binary).unwrap();
152
153        assert_eq!(
154            binary.as_slice(),
155            b"\x02\xac\x1f!0\x9f\xb8\xac\x1f\x00\x025\x00".as_slice()
156        );
157
158        let mut buf = binary.as_slice();
159        let socktuple2 = <SockTuple>::from_bytes(&mut buf).unwrap();
160        assert_eq!(socktuple, socktuple2)
161    }
162
163    #[test]
164    fn test_socktuple_ipv6() {
165        let socktuple = SockTuple::V6 {
166            source: SocketAddrV6::new(
167                Ipv6Addr::from_str("2001:4860:4860::8844").unwrap(),
168                47263,
169                0,
170                0,
171            ),
172            dest: SocketAddrV6::new(
173                Ipv6Addr::from_str("2001:4860:4860::8800").unwrap(),
174                53,
175                0,
176                0,
177            ),
178        };
179
180        dbg!(&socktuple);
181
182        let mut binary = Vec::new();
183        socktuple.write(&mut binary).unwrap();
184
185        assert_eq!(
186            binary.as_slice(),
187            b"\x0a\x20\x01\x48\x60\x48\x60\0\0\0\0\0\0\0\0\x88\x44\x9f\xb8\x20\x01\x48\x60\x48\x60\0\0\0\0\0\0\0\0\x88\x00\x35\x00".as_slice()
188        );
189
190        let mut buf = binary.as_slice();
191        let socktuple2 = <SockTuple>::from_bytes(&mut buf).unwrap();
192        assert_eq!(socktuple, socktuple2)
193    }
194
195    #[test]
196    fn test_socktuple_unix() {
197        let binary = b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00 \xcfN\xbc\x98\xff\xff/var/run/nscd/socket\x00".as_slice();
198        let mut buf = binary;
199
200        let socktuple = <SockTuple>::from_bytes(&mut buf).unwrap();
201        dbg!(&socktuple);
202
203        let mut binary2 = Vec::new();
204        socktuple.write(&mut binary2).unwrap();
205
206        let SockTuple::Unix {
207            source_ptr: source_addr,
208            dest_ptr: dest_addr,
209            path,
210        } = socktuple
211        else {
212            panic!("not a unix sock tuple: {socktuple:?}")
213        };
214
215        assert_eq!(source_addr, 0);
216        assert_eq!(dest_addr, 0xffff98bc4ecf2000);
217        assert_eq!(path.as_bytes(), b"/var/run/nscd/socket".as_slice());
218
219        assert_eq!(binary, binary2.as_slice(),);
220    }
221}