1use crate::layer::field::{Field, FieldDesc, FieldError, FieldType, FieldValue};
30use crate::layer::{Layer, LayerIndex, LayerKind};
31
32use super::flags::TcpFlags;
33use super::options::{TcpOptions, parse_options};
34use super::services;
35
36pub const TCP_MIN_HEADER_LEN: usize = 20;
38
39pub const TCP_MAX_HEADER_LEN: usize = 60;
41
42pub mod offsets {
44 pub const SRC_PORT: usize = 0;
46 pub const DST_PORT: usize = 2;
48 pub const SEQ: usize = 4;
50 pub const ACK: usize = 8;
52 pub const DATA_OFFSET: usize = 12;
54 pub const FLAGS: usize = 13;
56 pub const WINDOW: usize = 14;
58 pub const CHECKSUM: usize = 16;
60 pub const URG_PTR: usize = 18;
62 pub const OPTIONS: usize = 20;
64}
65
66pub static FIELDS: &[FieldDesc] = &[
68 FieldDesc::new("sport", offsets::SRC_PORT, 2, FieldType::U16),
69 FieldDesc::new("dport", offsets::DST_PORT, 2, FieldType::U16),
70 FieldDesc::new("seq", offsets::SEQ, 4, FieldType::U32),
71 FieldDesc::new("ack", offsets::ACK, 4, FieldType::U32),
72 FieldDesc::new("dataofs", offsets::DATA_OFFSET, 1, FieldType::U8),
73 FieldDesc::new("reserved", offsets::DATA_OFFSET, 1, FieldType::U8),
74 FieldDesc::new("flags", offsets::FLAGS, 1, FieldType::U8),
75 FieldDesc::new("window", offsets::WINDOW, 2, FieldType::U16),
76 FieldDesc::new("chksum", offsets::CHECKSUM, 2, FieldType::U16),
77 FieldDesc::new("urgptr", offsets::URG_PTR, 2, FieldType::U16),
78];
79
80#[derive(Debug, Clone)]
82pub struct TcpLayer {
83 pub index: LayerIndex,
84}
85
86impl TcpLayer {
87 #[inline]
89 #[must_use]
90 pub const fn new(start: usize, end: usize) -> Self {
91 Self {
92 index: LayerIndex::new(LayerKind::Tcp, start, end),
93 }
94 }
95
96 #[inline]
98 #[must_use]
99 pub const fn at_start() -> Self {
100 Self::new(0, TCP_MIN_HEADER_LEN)
101 }
102
103 #[inline]
105 #[must_use]
106 pub const fn at_offset(offset: usize) -> Self {
107 Self::new(offset, offset + TCP_MIN_HEADER_LEN)
108 }
109
110 pub fn at_offset_dynamic(buf: &[u8], offset: usize) -> Result<Self, FieldError> {
112 if buf.len() < offset + TCP_MIN_HEADER_LEN {
113 return Err(FieldError::BufferTooShort {
114 offset,
115 need: TCP_MIN_HEADER_LEN,
116 have: buf.len().saturating_sub(offset),
117 });
118 }
119
120 let data_offset = ((buf[offset + offsets::DATA_OFFSET] >> 4) & 0x0F) as usize;
121 let header_len = data_offset * 4;
122
123 if header_len < TCP_MIN_HEADER_LEN {
124 return Err(FieldError::InvalidValue(format!(
125 "Data offset {data_offset} is less than minimum (5)"
126 )));
127 }
128
129 if buf.len() < offset + header_len {
130 return Err(FieldError::BufferTooShort {
131 offset,
132 need: header_len,
133 have: buf.len().saturating_sub(offset),
134 });
135 }
136
137 Ok(Self::new(offset, offset + header_len))
138 }
139
140 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
142 if buf.len() < offset + TCP_MIN_HEADER_LEN {
143 return Err(FieldError::BufferTooShort {
144 offset,
145 need: TCP_MIN_HEADER_LEN,
146 have: buf.len().saturating_sub(offset),
147 });
148 }
149
150 let data_offset = ((buf[offset + offsets::DATA_OFFSET] >> 4) & 0x0F) as usize;
151 if data_offset < 5 {
152 return Err(FieldError::InvalidValue(format!(
153 "Data offset {data_offset} is less than minimum (5)"
154 )));
155 }
156
157 let header_len = data_offset * 4;
158 if buf.len() < offset + header_len {
159 return Err(FieldError::BufferTooShort {
160 offset,
161 need: header_len,
162 have: buf.len().saturating_sub(offset),
163 });
164 }
165
166 Ok(())
167 }
168
169 #[must_use]
171 pub fn calculate_header_len(&self, buf: &[u8]) -> usize {
172 self.data_offset(buf)
173 .map(|doff| (doff as usize) * 4)
174 .unwrap_or(TCP_MIN_HEADER_LEN)
175 }
176
177 #[must_use]
179 pub fn options_len(&self, buf: &[u8]) -> usize {
180 self.calculate_header_len(buf)
181 .saturating_sub(TCP_MIN_HEADER_LEN)
182 }
183
184 #[inline]
188 pub fn src_port(&self, buf: &[u8]) -> Result<u16, FieldError> {
189 u16::read(buf, self.index.start + offsets::SRC_PORT)
190 }
191
192 #[inline]
194 pub fn sport(&self, buf: &[u8]) -> Result<u16, FieldError> {
195 self.src_port(buf)
196 }
197
198 #[inline]
200 pub fn dst_port(&self, buf: &[u8]) -> Result<u16, FieldError> {
201 u16::read(buf, self.index.start + offsets::DST_PORT)
202 }
203
204 #[inline]
206 pub fn dport(&self, buf: &[u8]) -> Result<u16, FieldError> {
207 self.dst_port(buf)
208 }
209
210 #[inline]
212 pub fn seq(&self, buf: &[u8]) -> Result<u32, FieldError> {
213 u32::read(buf, self.index.start + offsets::SEQ)
214 }
215
216 #[inline]
218 pub fn ack(&self, buf: &[u8]) -> Result<u32, FieldError> {
219 u32::read(buf, self.index.start + offsets::ACK)
220 }
221
222 #[inline]
224 pub fn data_offset(&self, buf: &[u8]) -> Result<u8, FieldError> {
225 let b = u8::read(buf, self.index.start + offsets::DATA_OFFSET)?;
226 Ok((b >> 4) & 0x0F)
227 }
228
229 #[inline]
231 pub fn dataofs(&self, buf: &[u8]) -> Result<u8, FieldError> {
232 self.data_offset(buf)
233 }
234
235 #[inline]
237 pub fn reserved(&self, buf: &[u8]) -> Result<u8, FieldError> {
238 let b = u8::read(buf, self.index.start + offsets::DATA_OFFSET)?;
239 Ok((b >> 1) & 0x07)
240 }
241
242 #[inline]
244 pub fn flags_raw(&self, buf: &[u8]) -> Result<u8, FieldError> {
245 u8::read(buf, self.index.start + offsets::FLAGS)
246 }
247
248 #[inline]
250 pub fn flags(&self, buf: &[u8]) -> Result<TcpFlags, FieldError> {
251 let hi = u8::read(buf, self.index.start + offsets::DATA_OFFSET)?;
252 let lo = u8::read(buf, self.index.start + offsets::FLAGS)?;
253 Ok(TcpFlags::from_bytes(hi, lo))
254 }
255
256 #[inline]
258 pub fn window(&self, buf: &[u8]) -> Result<u16, FieldError> {
259 u16::read(buf, self.index.start + offsets::WINDOW)
260 }
261
262 #[inline]
264 pub fn checksum(&self, buf: &[u8]) -> Result<u16, FieldError> {
265 u16::read(buf, self.index.start + offsets::CHECKSUM)
266 }
267
268 #[inline]
270 pub fn chksum(&self, buf: &[u8]) -> Result<u16, FieldError> {
271 self.checksum(buf)
272 }
273
274 #[inline]
276 pub fn urgent_ptr(&self, buf: &[u8]) -> Result<u16, FieldError> {
277 u16::read(buf, self.index.start + offsets::URG_PTR)
278 }
279
280 #[inline]
282 pub fn urgptr(&self, buf: &[u8]) -> Result<u16, FieldError> {
283 self.urgent_ptr(buf)
284 }
285
286 pub fn options_bytes<'a>(&self, buf: &'a [u8]) -> Result<&'a [u8], FieldError> {
288 let header_len = self.calculate_header_len(buf);
289 let opts_start = self.index.start + TCP_MIN_HEADER_LEN;
290 let opts_end = self.index.start + header_len;
291
292 if buf.len() < opts_end {
293 return Err(FieldError::BufferTooShort {
294 offset: opts_start,
295 need: header_len - TCP_MIN_HEADER_LEN,
296 have: buf.len().saturating_sub(opts_start),
297 });
298 }
299
300 Ok(&buf[opts_start..opts_end])
301 }
302
303 pub fn options(&self, buf: &[u8]) -> Result<TcpOptions, FieldError> {
305 let opts_bytes = self.options_bytes(buf)?;
306 parse_options(opts_bytes)
307 }
308
309 #[inline]
313 pub fn set_src_port(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
314 port.write(buf, self.index.start + offsets::SRC_PORT)
315 }
316
317 #[inline]
319 pub fn set_sport(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
320 self.set_src_port(buf, port)
321 }
322
323 #[inline]
325 pub fn set_dst_port(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
326 port.write(buf, self.index.start + offsets::DST_PORT)
327 }
328
329 #[inline]
331 pub fn set_dport(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
332 self.set_dst_port(buf, port)
333 }
334
335 #[inline]
337 pub fn set_seq(&self, buf: &mut [u8], seq: u32) -> Result<(), FieldError> {
338 seq.write(buf, self.index.start + offsets::SEQ)
339 }
340
341 #[inline]
343 pub fn set_ack(&self, buf: &mut [u8], ack: u32) -> Result<(), FieldError> {
344 ack.write(buf, self.index.start + offsets::ACK)
345 }
346
347 #[inline]
349 pub fn set_data_offset(&self, buf: &mut [u8], offset: u8) -> Result<(), FieldError> {
350 let idx = self.index.start + offsets::DATA_OFFSET;
351 let current = u8::read(buf, idx)?;
352 let new_val = (current & 0x0F) | ((offset & 0x0F) << 4);
353 new_val.write(buf, idx)
354 }
355
356 #[inline]
358 pub fn set_dataofs(&self, buf: &mut [u8], offset: u8) -> Result<(), FieldError> {
359 self.set_data_offset(buf, offset)
360 }
361
362 #[inline]
364 pub fn set_reserved(&self, buf: &mut [u8], reserved: u8) -> Result<(), FieldError> {
365 let idx = self.index.start + offsets::DATA_OFFSET;
366 let current = u8::read(buf, idx)?;
367 let new_val = (current & 0xF1) | ((reserved & 0x07) << 1);
368 new_val.write(buf, idx)
369 }
370
371 #[inline]
373 pub fn set_flags_raw(&self, buf: &mut [u8], flags: u8) -> Result<(), FieldError> {
374 flags.write(buf, self.index.start + offsets::FLAGS)
375 }
376
377 #[inline]
379 pub fn set_flags(&self, buf: &mut [u8], flags: TcpFlags) -> Result<(), FieldError> {
380 flags
382 .to_byte()
383 .write(buf, self.index.start + offsets::FLAGS)?;
384
385 let idx = self.index.start + offsets::DATA_OFFSET;
387 let current = u8::read(buf, idx)?;
388 let new_val = (current & 0xFE) | flags.ns_bit();
389 new_val.write(buf, idx)
390 }
391
392 #[inline]
394 pub fn set_window(&self, buf: &mut [u8], window: u16) -> Result<(), FieldError> {
395 window.write(buf, self.index.start + offsets::WINDOW)
396 }
397
398 #[inline]
400 pub fn set_checksum(&self, buf: &mut [u8], checksum: u16) -> Result<(), FieldError> {
401 checksum.write(buf, self.index.start + offsets::CHECKSUM)
402 }
403
404 #[inline]
406 pub fn set_chksum(&self, buf: &mut [u8], checksum: u16) -> Result<(), FieldError> {
407 self.set_checksum(buf, checksum)
408 }
409
410 #[inline]
412 pub fn set_urgent_ptr(&self, buf: &mut [u8], urgptr: u16) -> Result<(), FieldError> {
413 urgptr.write(buf, self.index.start + offsets::URG_PTR)
414 }
415
416 #[inline]
418 pub fn set_urgptr(&self, buf: &mut [u8], urgptr: u16) -> Result<(), FieldError> {
419 self.set_urgent_ptr(buf, urgptr)
420 }
421
422 pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
426 match name {
427 "sport" | "src_port" => Some(self.src_port(buf).map(FieldValue::U16)),
428 "dport" | "dst_port" => Some(self.dst_port(buf).map(FieldValue::U16)),
429 "seq" => Some(self.seq(buf).map(FieldValue::U32)),
430 "ack" => Some(self.ack(buf).map(FieldValue::U32)),
431 "dataofs" | "data_offset" => Some(self.data_offset(buf).map(FieldValue::U8)),
432 "reserved" => Some(self.reserved(buf).map(FieldValue::U8)),
433 "flags" => Some(self.flags_raw(buf).map(FieldValue::U8)),
434 "window" => Some(self.window(buf).map(FieldValue::U16)),
435 "chksum" | "checksum" => Some(self.checksum(buf).map(FieldValue::U16)),
436 "urgptr" | "urgent_ptr" => Some(self.urgent_ptr(buf).map(FieldValue::U16)),
437 _ => None,
438 }
439 }
440
441 pub fn set_field(
443 &self,
444 buf: &mut [u8],
445 name: &str,
446 value: FieldValue,
447 ) -> Option<Result<(), FieldError>> {
448 match (name, value) {
449 ("sport" | "src_port", FieldValue::U16(v)) => Some(self.set_src_port(buf, v)),
450 ("dport" | "dst_port", FieldValue::U16(v)) => Some(self.set_dst_port(buf, v)),
451 ("seq", FieldValue::U32(v)) => Some(self.set_seq(buf, v)),
452 ("ack", FieldValue::U32(v)) => Some(self.set_ack(buf, v)),
453 ("dataofs" | "data_offset", FieldValue::U8(v)) => Some(self.set_data_offset(buf, v)),
454 ("reserved", FieldValue::U8(v)) => Some(self.set_reserved(buf, v)),
455 ("flags", FieldValue::U8(v)) => Some(self.set_flags_raw(buf, v)),
456 ("window", FieldValue::U16(v)) => Some(self.set_window(buf, v)),
457 ("chksum" | "checksum", FieldValue::U16(v)) => Some(self.set_checksum(buf, v)),
458 ("urgptr" | "urgent_ptr", FieldValue::U16(v)) => Some(self.set_urgent_ptr(buf, v)),
459 _ => None,
460 }
461 }
462
463 #[must_use]
465 pub fn field_names() -> &'static [&'static str] {
466 &[
467 "sport", "dport", "seq", "ack", "dataofs", "reserved", "flags", "window", "chksum",
468 "urgptr",
469 ]
470 }
471
472 #[must_use]
477 pub fn payload_len(&self, buf: &[u8], ip_payload_len: usize) -> usize {
478 let header_len = self.calculate_header_len(buf);
479 ip_payload_len.saturating_sub(header_len)
480 }
481
482 #[must_use]
484 pub fn payload<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
485 let header_len = self.calculate_header_len(buf);
486 let payload_start = self.index.start + header_len;
487
488 if payload_start > buf.len() {
489 return &[];
490 }
491
492 &buf[payload_start..]
493 }
494
495 #[inline]
497 #[must_use]
498 pub fn header_bytes<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
499 let header_len = self.calculate_header_len(buf);
500 let end = (self.index.start + header_len).min(buf.len());
501 &buf[self.index.start..end]
502 }
503
504 pub fn src_service(&self, buf: &[u8]) -> &'static str {
506 self.src_port(buf)
507 .map(services::service_name)
508 .unwrap_or("unknown")
509 }
510
511 pub fn dst_service(&self, buf: &[u8]) -> &'static str {
513 self.dst_port(buf)
514 .map(services::service_name)
515 .unwrap_or("unknown")
516 }
517
518 #[must_use]
520 pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
521 let sport = self.src_port(buf).unwrap_or(0);
522 let dport = self.dst_port(buf).unwrap_or(0);
523
524 let xored = sport ^ dport;
526
527 xored.to_be_bytes().to_vec()
529 }
530
531 #[must_use]
533 pub fn answers(&self, buf: &[u8], other: &TcpLayer, other_buf: &[u8]) -> bool {
534 let self_flags = self.flags(buf).unwrap_or(TcpFlags::NONE);
535 let other_flags = other.flags(other_buf).unwrap_or(TcpFlags::NONE);
536
537 if other_flags.rst {
539 return false;
540 }
541
542 if self_flags.syn && !self_flags.ack {
544 return false;
545 }
546
547 if self_flags.syn && self_flags.ack && !other_flags.syn {
549 return false;
550 }
551
552 let self_sport = self.src_port(buf).unwrap_or(0);
554 let self_dport = self.dst_port(buf).unwrap_or(0);
555 let other_sport = other.src_port(other_buf).unwrap_or(0);
556 let other_dport = other.dst_port(other_buf).unwrap_or(0);
557
558 if self_sport != other_dport || self_dport != other_sport {
559 return false;
560 }
561
562 let self_seq = self.seq(buf).unwrap_or(0);
564 let self_ack = self.ack(buf).unwrap_or(0);
565 let other_seq = other.seq(other_buf).unwrap_or(0);
566 let other_ack = other.ack(other_buf).unwrap_or(0);
567
568 if !(other_flags.syn && !other_flags.ack) {
570 let diff = other_ack.abs_diff(self_seq);
571 if diff > 2 {
572 return false;
573 }
574 }
575
576 if self_flags.rst && !self_flags.ack {
578 return true;
579 }
580
581 let other_payload_len = other.payload(other_buf).len() as u32;
583 let diff = other_seq.abs_diff(self_ack);
584 if diff > 2 + other_payload_len {
585 return false;
586 }
587
588 true
589 }
590}
591
592impl Layer for TcpLayer {
593 fn kind(&self) -> LayerKind {
594 LayerKind::Tcp
595 }
596
597 fn summary(&self, buf: &[u8]) -> String {
598 let sport = self.src_port(buf).unwrap_or(0);
599 let dport = self.dst_port(buf).unwrap_or(0);
600 let flags = self.flags(buf).unwrap_or(TcpFlags::NONE);
601
602 format!("TCP {sport} > {dport} {flags}")
603 }
604
605 fn header_len(&self, buf: &[u8]) -> usize {
606 self.calculate_header_len(buf)
607 }
608
609 fn hashret(&self, buf: &[u8]) -> Vec<u8> {
610 self.hashret(buf)
611 }
612
613 fn answers(&self, buf: &[u8], other: &Self, other_buf: &[u8]) -> bool {
614 self.answers(buf, other, other_buf)
615 }
616
617 fn field_names(&self) -> &'static [&'static str] {
618 Self::field_names()
619 }
620}
621
622#[cfg(test)]
623mod tests {
624 use super::*;
625
626 fn sample_tcp_header() -> Vec<u8> {
627 vec![
628 0x00, 0x50, 0x1F, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, ]
638 }
639
640 #[test]
641 fn test_field_readers() {
642 let buf = sample_tcp_header();
643 let layer = TcpLayer::at_offset(0);
644
645 assert_eq!(layer.src_port(&buf).unwrap(), 80);
646 assert_eq!(layer.dst_port(&buf).unwrap(), 8080);
647 assert_eq!(layer.seq(&buf).unwrap(), 1);
648 assert_eq!(layer.ack(&buf).unwrap(), 0);
649 assert_eq!(layer.data_offset(&buf).unwrap(), 5);
650 assert_eq!(layer.window(&buf).unwrap(), 65535);
651 assert_eq!(layer.urgent_ptr(&buf).unwrap(), 0);
652
653 let flags = layer.flags(&buf).unwrap();
654 assert!(flags.syn);
655 assert!(!flags.ack);
656 }
657
658 #[test]
659 fn test_field_writers() {
660 let mut buf = sample_tcp_header();
661 let layer = TcpLayer::at_offset(0);
662
663 layer.set_src_port(&mut buf, 12345).unwrap();
664 assert_eq!(layer.src_port(&buf).unwrap(), 12345);
665
666 layer.set_dst_port(&mut buf, 443).unwrap();
667 assert_eq!(layer.dst_port(&buf).unwrap(), 443);
668
669 layer.set_seq(&mut buf, 0x12345678).unwrap();
670 assert_eq!(layer.seq(&buf).unwrap(), 0x12345678);
671
672 layer.set_ack(&mut buf, 0xABCDEF00).unwrap();
673 assert_eq!(layer.ack(&buf).unwrap(), 0xABCDEF00);
674
675 layer.set_flags(&mut buf, TcpFlags::SA).unwrap();
676 let flags = layer.flags(&buf).unwrap();
677 assert!(flags.syn);
678 assert!(flags.ack);
679 }
680
681 #[test]
682 fn test_flags() {
683 let mut buf = sample_tcp_header();
684 let layer = TcpLayer::at_offset(0);
685
686 let mut flags = TcpFlags::SA;
688 flags.ns = true;
689 layer.set_flags(&mut buf, flags).unwrap();
690
691 let read_flags = layer.flags(&buf).unwrap();
692 assert!(read_flags.syn);
693 assert!(read_flags.ack);
694 assert!(read_flags.ns);
695 }
696
697 #[test]
698 fn test_header_len() {
699 let buf = sample_tcp_header();
700 let layer = TcpLayer::at_offset(0);
701
702 assert_eq!(layer.calculate_header_len(&buf), 20);
703
704 let mut buf_with_opts = sample_tcp_header();
706 buf_with_opts[12] = 0x60; buf_with_opts.extend_from_slice(&[0, 0, 0, 0]); assert_eq!(layer.calculate_header_len(&buf_with_opts), 24);
710 }
711
712 #[test]
713 fn test_validate() {
714 let buf = sample_tcp_header();
715 assert!(TcpLayer::validate(&buf, 0).is_ok());
716
717 let short = vec![0x00, 0x50];
719 assert!(TcpLayer::validate(&short, 0).is_err());
720
721 let mut bad_doff = sample_tcp_header();
723 bad_doff[12] = 0x30; assert!(TcpLayer::validate(&bad_doff, 0).is_err());
725 }
726
727 #[test]
728 fn test_summary() {
729 let buf = sample_tcp_header();
730 let layer = TcpLayer::at_offset(0);
731
732 let summary = layer.summary(&buf);
733 assert!(summary.contains("80"));
734 assert!(summary.contains("8080"));
735 assert!(summary.contains("S")); }
737
738 #[test]
739 fn test_at_offset_dynamic() {
740 let buf = sample_tcp_header();
741 let layer = TcpLayer::at_offset_dynamic(&buf, 0).unwrap();
742
743 assert_eq!(layer.index.start, 0);
744 assert_eq!(layer.index.end, 20);
745 }
746
747 #[test]
748 fn test_payload() {
749 let mut buf = sample_tcp_header();
750 buf.extend_from_slice(b"Hello, TCP!");
751
752 let layer = TcpLayer::at_offset(0);
753 let payload = layer.payload(&buf);
754
755 assert_eq!(payload, b"Hello, TCP!");
756 }
757}