falco_event/types/net/
socktuple.rs

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