falco_event_schema/types/net/
socktuple.rs1use 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#[derive(Clone, Copy, Eq, PartialEq, Hash)]
10pub enum SockTuple<'a> {
11 Unix {
13 source_ptr: u64,
15 dest_ptr: u64,
17 path: &'a UnixPath,
19 },
20
21 V4 {
23 source: SocketAddrV4,
25 dest: SocketAddrV4,
27 },
28
29 V6 {
31 source: SocketAddrV6,
33 dest: SocketAddrV6,
35 },
36
37 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}