1use std::fmt;
2
3use bytes::{Buf, BufMut, Bytes, BytesMut};
4
5use crate::chunk::chunk_abort::ChunkAbort;
6use crate::chunk::chunk_cookie_ack::ChunkCookieAck;
7use crate::chunk::chunk_cookie_echo::ChunkCookieEcho;
8use crate::chunk::chunk_error::ChunkError;
9use crate::chunk::chunk_forward_tsn::ChunkForwardTsn;
10use crate::chunk::chunk_header::*;
11use crate::chunk::chunk_heartbeat::ChunkHeartbeat;
12use crate::chunk::chunk_init::ChunkInit;
13use crate::chunk::chunk_payload_data::ChunkPayloadData;
14use crate::chunk::chunk_reconfig::ChunkReconfig;
15use crate::chunk::chunk_selective_ack::ChunkSelectiveAck;
16use crate::chunk::chunk_shutdown::ChunkShutdown;
17use crate::chunk::chunk_shutdown_ack::ChunkShutdownAck;
18use crate::chunk::chunk_shutdown_complete::ChunkShutdownComplete;
19use crate::chunk::chunk_type::*;
20use crate::chunk::chunk_unknown::ChunkUnknown;
21use crate::chunk::Chunk;
22use crate::error::{Error, Result};
23use crate::util::*;
24
25#[derive(Default, Debug)]
63pub(crate) struct Packet {
64 pub(crate) source_port: u16,
65 pub(crate) destination_port: u16,
66 pub(crate) verification_tag: u32,
67 pub(crate) chunks: Vec<Box<dyn Chunk + Send + Sync>>,
68}
69
70impl fmt::Display for Packet {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 let mut res = format!(
74 "Packet:
75 source_port: {}
76 destination_port: {}
77 verification_tag: {}
78 ",
79 self.source_port, self.destination_port, self.verification_tag,
80 );
81 for chunk in &self.chunks {
82 res += format!("Chunk: {chunk}").as_str();
83 }
84 write!(f, "{res}")
85 }
86}
87
88pub(crate) const PACKET_HEADER_SIZE: usize = 12;
89
90impl Packet {
91 pub(crate) fn unmarshal(raw: &Bytes) -> Result<Self> {
92 if raw.len() < PACKET_HEADER_SIZE {
93 return Err(Error::ErrPacketRawTooSmall);
94 }
95
96 let reader = &mut raw.clone();
97
98 let source_port = reader.get_u16();
99 let destination_port = reader.get_u16();
100 let verification_tag = reader.get_u32();
101
102 #[cfg(not(fuzzing))]
103 {
105 let their_checksum = reader.get_u32_le();
106 let our_checksum = generate_packet_checksum(raw);
107
108 if their_checksum != our_checksum {
109 return Err(Error::ErrChecksumMismatch);
110 }
111 }
112
113 let mut chunks = vec![];
114 let mut offset = PACKET_HEADER_SIZE;
115 loop {
116 if offset == raw.len() {
118 break;
119 } else if offset + CHUNK_HEADER_SIZE > raw.len() {
120 return Err(Error::ErrParseSctpChunkNotEnoughData);
121 }
122
123 let ct = ChunkType(raw[offset]);
124 let c: Box<dyn Chunk + Send + Sync> = match ct {
125 CT_INIT => Box::new(ChunkInit::unmarshal(&raw.slice(offset..))?),
126 CT_INIT_ACK => Box::new(ChunkInit::unmarshal(&raw.slice(offset..))?),
127 CT_ABORT => Box::new(ChunkAbort::unmarshal(&raw.slice(offset..))?),
128 CT_COOKIE_ECHO => Box::new(ChunkCookieEcho::unmarshal(&raw.slice(offset..))?),
129 CT_COOKIE_ACK => Box::new(ChunkCookieAck::unmarshal(&raw.slice(offset..))?),
130 CT_HEARTBEAT => Box::new(ChunkHeartbeat::unmarshal(&raw.slice(offset..))?),
131 CT_PAYLOAD_DATA => Box::new(ChunkPayloadData::unmarshal(&raw.slice(offset..))?),
132 CT_SACK => Box::new(ChunkSelectiveAck::unmarshal(&raw.slice(offset..))?),
133 CT_RECONFIG => Box::new(ChunkReconfig::unmarshal(&raw.slice(offset..))?),
134 CT_FORWARD_TSN => Box::new(ChunkForwardTsn::unmarshal(&raw.slice(offset..))?),
135 CT_ERROR => Box::new(ChunkError::unmarshal(&raw.slice(offset..))?),
136 CT_SHUTDOWN => Box::new(ChunkShutdown::unmarshal(&raw.slice(offset..))?),
137 CT_SHUTDOWN_ACK => Box::new(ChunkShutdownAck::unmarshal(&raw.slice(offset..))?),
138 CT_SHUTDOWN_COMPLETE => {
139 Box::new(ChunkShutdownComplete::unmarshal(&raw.slice(offset..))?)
140 }
141 _ => Box::new(ChunkUnknown::unmarshal(&raw.slice(offset..))?),
142 };
143
144 let chunk_value_padding = get_padding_size(c.value_length());
145 offset += CHUNK_HEADER_SIZE + c.value_length() + chunk_value_padding;
146 chunks.push(c);
147 }
148
149 Ok(Packet {
150 source_port,
151 destination_port,
152 verification_tag,
153 chunks,
154 })
155 }
156
157 pub(crate) fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
158 writer.put_u16(self.source_port);
161 writer.put_u16(self.destination_port);
162 writer.put_u32(self.verification_tag);
163
164 let checksum_pos = writer.len();
166 writer.extend_from_slice(&[0, 0, 0, 0]);
167
168 for c in &self.chunks {
170 c.marshal_to(writer)?;
171
172 let padding_needed = get_padding_size(writer.len());
173 if padding_needed != 0 {
174 writer.extend_from_slice(&[0u8; PADDING_MULTIPLE][..padding_needed]);
176 }
177 }
178
179 let mut digest = ISCSI_CRC.digest();
180 digest.update(writer);
181 let checksum = digest.finalize();
182
183 let checksum_place = &mut writer[checksum_pos..checksum_pos + 4];
186 checksum_place.copy_from_slice(&checksum.to_le_bytes());
187
188 Ok(writer.len())
189 }
190
191 pub(crate) fn marshal(&self) -> Result<Bytes> {
192 let mut buf = BytesMut::with_capacity(PACKET_HEADER_SIZE);
193 self.marshal_to(&mut buf)?;
194 Ok(buf.freeze())
195 }
196}
197
198impl Packet {
199 pub(crate) fn check_packet(&self) -> Result<()> {
200 if self.source_port == 0 {
208 return Err(Error::ErrSctpPacketSourcePortZero);
209 }
210
211 if self.destination_port == 0 {
216 return Err(Error::ErrSctpPacketDestinationPortZero);
217 }
218
219 for c in &self.chunks {
221 if let Some(ci) = c.as_any().downcast_ref::<ChunkInit>() {
222 if !ci.is_ack {
223 if self.chunks.len() != 1 {
227 return Err(Error::ErrInitChunkBundled);
228 }
229
230 if self.verification_tag != 0 {
233 return Err(Error::ErrInitChunkVerifyTagNotZero);
234 }
235 }
236 }
237 }
238
239 Ok(())
240 }
241}
242
243#[cfg(test)]
244mod test {
245 use super::*;
246
247 #[test]
248 fn test_packet_unmarshal() -> Result<()> {
249 let result = Packet::unmarshal(&Bytes::new());
250 assert!(
251 result.is_err(),
252 "Unmarshal should fail when a packet is too small to be SCTP"
253 );
254
255 let header_only = Bytes::from_static(&[
256 0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x06, 0xa9, 0x00, 0xe1,
257 ]);
258 let pkt = Packet::unmarshal(&header_only)?;
259 assert_eq!(
261 pkt.source_port, 5000,
262 "Unmarshal passed for SCTP packet, but got incorrect source port exp: {} act: {}",
263 5000, pkt.source_port
264 );
265 assert_eq!(
266 pkt.destination_port, 5000,
267 "Unmarshal passed for SCTP packet, but got incorrect destination port exp: {} act: {}",
268 5000, pkt.destination_port
269 );
270 assert_eq!(
271 pkt.verification_tag, 0,
272 "Unmarshal passed for SCTP packet, but got incorrect verification tag exp: {} act: {}",
273 0, pkt.verification_tag
274 );
275
276 let raw_chunk = Bytes::from_static(&[
277 0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x81, 0x46, 0x9d, 0xfc, 0x01, 0x00,
278 0x00, 0x56, 0x55, 0xb9, 0x64, 0xa5, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
279 0xe8, 0x6d, 0x10, 0x30, 0xc0, 0x00, 0x00, 0x04, 0x80, 0x08, 0x00, 0x09, 0xc0, 0x0f,
280 0xc1, 0x80, 0x82, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0x9f, 0xeb, 0xbb, 0x5c,
281 0x50, 0xc9, 0xbf, 0x75, 0x9c, 0xb1, 0x2c, 0x57, 0x4f, 0xa4, 0x5a, 0x51, 0xba, 0x60,
282 0x17, 0x78, 0x27, 0x94, 0x5c, 0x31, 0xe6, 0x5d, 0x5b, 0x09, 0x47, 0xe2, 0x22, 0x06,
283 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1,
284 0x00, 0x00,
285 ]);
286
287 Packet::unmarshal(&raw_chunk)?;
288
289 Ok(())
290 }
291
292 #[test]
293 fn test_packet_marshal() -> Result<()> {
294 let header_only = Bytes::from_static(&[
295 0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x06, 0xa9, 0x00, 0xe1,
296 ]);
297 let pkt = Packet::unmarshal(&header_only)?;
298 let header_only_marshaled = pkt.marshal()?;
299 assert_eq!(header_only, header_only_marshaled, "Unmarshal/Marshaled header only packet did not match \nheaderOnly: {header_only:?} \nheader_only_marshaled {header_only_marshaled:?}");
300
301 Ok(())
302 }
303
304 }