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#[derive(Clone, Copy, Eq, PartialEq, Hash)]
11pub enum SockTuple<'a> {
12 Unix {
14 source_ptr: u64,
16 dest_ptr: u64,
18 path: &'a UnixPath,
20 },
21
22 V4 {
24 source: EndpointV4,
26 dest: EndpointV4,
28 },
29
30 V6 {
32 source: EndpointV6,
34 dest: EndpointV6,
36 },
37
38 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}