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 pub const fn new(start: usize, end: usize) -> Self {
90 Self {
91 index: LayerIndex::new(LayerKind::Tcp, start, end),
92 }
93 }
94
95 #[inline]
97 pub const fn at_start() -> Self {
98 Self::new(0, TCP_MIN_HEADER_LEN)
99 }
100
101 #[inline]
103 pub const fn at_offset(offset: usize) -> Self {
104 Self::new(offset, offset + TCP_MIN_HEADER_LEN)
105 }
106
107 pub fn at_offset_dynamic(buf: &[u8], offset: usize) -> Result<Self, FieldError> {
109 if buf.len() < offset + TCP_MIN_HEADER_LEN {
110 return Err(FieldError::BufferTooShort {
111 offset,
112 need: TCP_MIN_HEADER_LEN,
113 have: buf.len().saturating_sub(offset),
114 });
115 }
116
117 let data_offset = ((buf[offset + offsets::DATA_OFFSET] >> 4) & 0x0F) as usize;
118 let header_len = data_offset * 4;
119
120 if header_len < TCP_MIN_HEADER_LEN {
121 return Err(FieldError::InvalidValue(format!(
122 "Data offset {} is less than minimum (5)",
123 data_offset
124 )));
125 }
126
127 if buf.len() < offset + header_len {
128 return Err(FieldError::BufferTooShort {
129 offset,
130 need: header_len,
131 have: buf.len().saturating_sub(offset),
132 });
133 }
134
135 Ok(Self::new(offset, offset + header_len))
136 }
137
138 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
140 if buf.len() < offset + TCP_MIN_HEADER_LEN {
141 return Err(FieldError::BufferTooShort {
142 offset,
143 need: TCP_MIN_HEADER_LEN,
144 have: buf.len().saturating_sub(offset),
145 });
146 }
147
148 let data_offset = ((buf[offset + offsets::DATA_OFFSET] >> 4) & 0x0F) as usize;
149 if data_offset < 5 {
150 return Err(FieldError::InvalidValue(format!(
151 "Data offset {} is less than minimum (5)",
152 data_offset
153 )));
154 }
155
156 let header_len = data_offset * 4;
157 if buf.len() < offset + header_len {
158 return Err(FieldError::BufferTooShort {
159 offset,
160 need: header_len,
161 have: buf.len().saturating_sub(offset),
162 });
163 }
164
165 Ok(())
166 }
167
168 pub fn calculate_header_len(&self, buf: &[u8]) -> usize {
170 self.data_offset(buf)
171 .map(|doff| (doff as usize) * 4)
172 .unwrap_or(TCP_MIN_HEADER_LEN)
173 }
174
175 pub fn options_len(&self, buf: &[u8]) -> usize {
177 self.calculate_header_len(buf)
178 .saturating_sub(TCP_MIN_HEADER_LEN)
179 }
180
181 #[inline]
185 pub fn src_port(&self, buf: &[u8]) -> Result<u16, FieldError> {
186 u16::read(buf, self.index.start + offsets::SRC_PORT)
187 }
188
189 #[inline]
191 pub fn sport(&self, buf: &[u8]) -> Result<u16, FieldError> {
192 self.src_port(buf)
193 }
194
195 #[inline]
197 pub fn dst_port(&self, buf: &[u8]) -> Result<u16, FieldError> {
198 u16::read(buf, self.index.start + offsets::DST_PORT)
199 }
200
201 #[inline]
203 pub fn dport(&self, buf: &[u8]) -> Result<u16, FieldError> {
204 self.dst_port(buf)
205 }
206
207 #[inline]
209 pub fn seq(&self, buf: &[u8]) -> Result<u32, FieldError> {
210 u32::read(buf, self.index.start + offsets::SEQ)
211 }
212
213 #[inline]
215 pub fn ack(&self, buf: &[u8]) -> Result<u32, FieldError> {
216 u32::read(buf, self.index.start + offsets::ACK)
217 }
218
219 #[inline]
221 pub fn data_offset(&self, buf: &[u8]) -> Result<u8, FieldError> {
222 let b = u8::read(buf, self.index.start + offsets::DATA_OFFSET)?;
223 Ok((b >> 4) & 0x0F)
224 }
225
226 #[inline]
228 pub fn dataofs(&self, buf: &[u8]) -> Result<u8, FieldError> {
229 self.data_offset(buf)
230 }
231
232 #[inline]
234 pub fn reserved(&self, buf: &[u8]) -> Result<u8, FieldError> {
235 let b = u8::read(buf, self.index.start + offsets::DATA_OFFSET)?;
236 Ok((b >> 1) & 0x07)
237 }
238
239 #[inline]
241 pub fn flags_raw(&self, buf: &[u8]) -> Result<u8, FieldError> {
242 u8::read(buf, self.index.start + offsets::FLAGS)
243 }
244
245 #[inline]
247 pub fn flags(&self, buf: &[u8]) -> Result<TcpFlags, FieldError> {
248 let hi = u8::read(buf, self.index.start + offsets::DATA_OFFSET)?;
249 let lo = u8::read(buf, self.index.start + offsets::FLAGS)?;
250 Ok(TcpFlags::from_bytes(hi, lo))
251 }
252
253 #[inline]
255 pub fn window(&self, buf: &[u8]) -> Result<u16, FieldError> {
256 u16::read(buf, self.index.start + offsets::WINDOW)
257 }
258
259 #[inline]
261 pub fn checksum(&self, buf: &[u8]) -> Result<u16, FieldError> {
262 u16::read(buf, self.index.start + offsets::CHECKSUM)
263 }
264
265 #[inline]
267 pub fn chksum(&self, buf: &[u8]) -> Result<u16, FieldError> {
268 self.checksum(buf)
269 }
270
271 #[inline]
273 pub fn urgent_ptr(&self, buf: &[u8]) -> Result<u16, FieldError> {
274 u16::read(buf, self.index.start + offsets::URG_PTR)
275 }
276
277 #[inline]
279 pub fn urgptr(&self, buf: &[u8]) -> Result<u16, FieldError> {
280 self.urgent_ptr(buf)
281 }
282
283 pub fn options_bytes<'a>(&self, buf: &'a [u8]) -> Result<&'a [u8], FieldError> {
285 let header_len = self.calculate_header_len(buf);
286 let opts_start = self.index.start + TCP_MIN_HEADER_LEN;
287 let opts_end = self.index.start + header_len;
288
289 if buf.len() < opts_end {
290 return Err(FieldError::BufferTooShort {
291 offset: opts_start,
292 need: header_len - TCP_MIN_HEADER_LEN,
293 have: buf.len().saturating_sub(opts_start),
294 });
295 }
296
297 Ok(&buf[opts_start..opts_end])
298 }
299
300 pub fn options(&self, buf: &[u8]) -> Result<TcpOptions, FieldError> {
302 let opts_bytes = self.options_bytes(buf)?;
303 parse_options(opts_bytes)
304 }
305
306 #[inline]
310 pub fn set_src_port(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
311 port.write(buf, self.index.start + offsets::SRC_PORT)
312 }
313
314 #[inline]
316 pub fn set_sport(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
317 self.set_src_port(buf, port)
318 }
319
320 #[inline]
322 pub fn set_dst_port(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
323 port.write(buf, self.index.start + offsets::DST_PORT)
324 }
325
326 #[inline]
328 pub fn set_dport(&self, buf: &mut [u8], port: u16) -> Result<(), FieldError> {
329 self.set_dst_port(buf, port)
330 }
331
332 #[inline]
334 pub fn set_seq(&self, buf: &mut [u8], seq: u32) -> Result<(), FieldError> {
335 seq.write(buf, self.index.start + offsets::SEQ)
336 }
337
338 #[inline]
340 pub fn set_ack(&self, buf: &mut [u8], ack: u32) -> Result<(), FieldError> {
341 ack.write(buf, self.index.start + offsets::ACK)
342 }
343
344 #[inline]
346 pub fn set_data_offset(&self, buf: &mut [u8], offset: u8) -> Result<(), FieldError> {
347 let idx = self.index.start + offsets::DATA_OFFSET;
348 let current = u8::read(buf, idx)?;
349 let new_val = (current & 0x0F) | ((offset & 0x0F) << 4);
350 new_val.write(buf, idx)
351 }
352
353 #[inline]
355 pub fn set_dataofs(&self, buf: &mut [u8], offset: u8) -> Result<(), FieldError> {
356 self.set_data_offset(buf, offset)
357 }
358
359 #[inline]
361 pub fn set_reserved(&self, buf: &mut [u8], reserved: u8) -> Result<(), FieldError> {
362 let idx = self.index.start + offsets::DATA_OFFSET;
363 let current = u8::read(buf, idx)?;
364 let new_val = (current & 0xF1) | ((reserved & 0x07) << 1);
365 new_val.write(buf, idx)
366 }
367
368 #[inline]
370 pub fn set_flags_raw(&self, buf: &mut [u8], flags: u8) -> Result<(), FieldError> {
371 flags.write(buf, self.index.start + offsets::FLAGS)
372 }
373
374 #[inline]
376 pub fn set_flags(&self, buf: &mut [u8], flags: TcpFlags) -> Result<(), FieldError> {
377 flags
379 .to_byte()
380 .write(buf, self.index.start + offsets::FLAGS)?;
381
382 let idx = self.index.start + offsets::DATA_OFFSET;
384 let current = u8::read(buf, idx)?;
385 let new_val = (current & 0xFE) | flags.ns_bit();
386 new_val.write(buf, idx)
387 }
388
389 #[inline]
391 pub fn set_window(&self, buf: &mut [u8], window: u16) -> Result<(), FieldError> {
392 window.write(buf, self.index.start + offsets::WINDOW)
393 }
394
395 #[inline]
397 pub fn set_checksum(&self, buf: &mut [u8], checksum: u16) -> Result<(), FieldError> {
398 checksum.write(buf, self.index.start + offsets::CHECKSUM)
399 }
400
401 #[inline]
403 pub fn set_chksum(&self, buf: &mut [u8], checksum: u16) -> Result<(), FieldError> {
404 self.set_checksum(buf, checksum)
405 }
406
407 #[inline]
409 pub fn set_urgent_ptr(&self, buf: &mut [u8], urgptr: u16) -> Result<(), FieldError> {
410 urgptr.write(buf, self.index.start + offsets::URG_PTR)
411 }
412
413 #[inline]
415 pub fn set_urgptr(&self, buf: &mut [u8], urgptr: u16) -> Result<(), FieldError> {
416 self.set_urgent_ptr(buf, urgptr)
417 }
418
419 pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
423 match name {
424 "sport" | "src_port" => Some(self.src_port(buf).map(FieldValue::U16)),
425 "dport" | "dst_port" => Some(self.dst_port(buf).map(FieldValue::U16)),
426 "seq" => Some(self.seq(buf).map(FieldValue::U32)),
427 "ack" => Some(self.ack(buf).map(FieldValue::U32)),
428 "dataofs" | "data_offset" => Some(self.data_offset(buf).map(FieldValue::U8)),
429 "reserved" => Some(self.reserved(buf).map(FieldValue::U8)),
430 "flags" => Some(self.flags_raw(buf).map(FieldValue::U8)),
431 "window" => Some(self.window(buf).map(FieldValue::U16)),
432 "chksum" | "checksum" => Some(self.checksum(buf).map(FieldValue::U16)),
433 "urgptr" | "urgent_ptr" => Some(self.urgent_ptr(buf).map(FieldValue::U16)),
434 _ => None,
435 }
436 }
437
438 pub fn set_field(
440 &self,
441 buf: &mut [u8],
442 name: &str,
443 value: FieldValue,
444 ) -> Option<Result<(), FieldError>> {
445 match (name, value) {
446 ("sport" | "src_port", FieldValue::U16(v)) => Some(self.set_src_port(buf, v)),
447 ("dport" | "dst_port", FieldValue::U16(v)) => Some(self.set_dst_port(buf, v)),
448 ("seq", FieldValue::U32(v)) => Some(self.set_seq(buf, v)),
449 ("ack", FieldValue::U32(v)) => Some(self.set_ack(buf, v)),
450 ("dataofs" | "data_offset", FieldValue::U8(v)) => Some(self.set_data_offset(buf, v)),
451 ("reserved", FieldValue::U8(v)) => Some(self.set_reserved(buf, v)),
452 ("flags", FieldValue::U8(v)) => Some(self.set_flags_raw(buf, v)),
453 ("window", FieldValue::U16(v)) => Some(self.set_window(buf, v)),
454 ("chksum" | "checksum", FieldValue::U16(v)) => Some(self.set_checksum(buf, v)),
455 ("urgptr" | "urgent_ptr", FieldValue::U16(v)) => Some(self.set_urgent_ptr(buf, v)),
456 _ => None,
457 }
458 }
459
460 pub fn field_names() -> &'static [&'static str] {
462 &[
463 "sport", "dport", "seq", "ack", "dataofs", "reserved", "flags", "window", "chksum",
464 "urgptr",
465 ]
466 }
467
468 pub fn payload_len(&self, buf: &[u8], ip_payload_len: usize) -> usize {
473 let header_len = self.calculate_header_len(buf);
474 ip_payload_len.saturating_sub(header_len)
475 }
476
477 pub fn payload<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
479 let header_len = self.calculate_header_len(buf);
480 let payload_start = self.index.start + header_len;
481
482 if payload_start > buf.len() {
483 return &[];
484 }
485
486 &buf[payload_start..]
487 }
488
489 #[inline]
491 pub fn header_bytes<'a>(&self, buf: &'a [u8]) -> &'a [u8] {
492 let header_len = self.calculate_header_len(buf);
493 let end = (self.index.start + header_len).min(buf.len());
494 &buf[self.index.start..end]
495 }
496
497 pub fn src_service(&self, buf: &[u8]) -> &'static str {
499 self.src_port(buf)
500 .map(services::service_name)
501 .unwrap_or("unknown")
502 }
503
504 pub fn dst_service(&self, buf: &[u8]) -> &'static str {
506 self.dst_port(buf)
507 .map(services::service_name)
508 .unwrap_or("unknown")
509 }
510
511 pub fn hashret(&self, buf: &[u8]) -> Vec<u8> {
513 let sport = self.src_port(buf).unwrap_or(0);
514 let dport = self.dst_port(buf).unwrap_or(0);
515
516 let xored = sport ^ dport;
518
519 xored.to_be_bytes().to_vec()
521 }
522
523 pub fn answers(&self, buf: &[u8], other: &TcpLayer, other_buf: &[u8]) -> bool {
525 let self_flags = self.flags(buf).unwrap_or(TcpFlags::NONE);
526 let other_flags = other.flags(other_buf).unwrap_or(TcpFlags::NONE);
527
528 if other_flags.rst {
530 return false;
531 }
532
533 if self_flags.syn && !self_flags.ack {
535 return false;
536 }
537
538 if self_flags.syn && self_flags.ack {
540 if !other_flags.syn {
541 return false;
542 }
543 }
544
545 let self_sport = self.src_port(buf).unwrap_or(0);
547 let self_dport = self.dst_port(buf).unwrap_or(0);
548 let other_sport = other.src_port(other_buf).unwrap_or(0);
549 let other_dport = other.dst_port(other_buf).unwrap_or(0);
550
551 if self_sport != other_dport || self_dport != other_sport {
552 return false;
553 }
554
555 let self_seq = self.seq(buf).unwrap_or(0);
557 let self_ack = self.ack(buf).unwrap_or(0);
558 let other_seq = other.seq(other_buf).unwrap_or(0);
559 let other_ack = other.ack(other_buf).unwrap_or(0);
560
561 if !(other_flags.syn && !other_flags.ack) {
563 let diff = if other_ack > self_seq {
564 other_ack - self_seq
565 } else {
566 self_seq - other_ack
567 };
568 if diff > 2 {
569 return false;
570 }
571 }
572
573 if self_flags.rst && !self_flags.ack {
575 return true;
576 }
577
578 let other_payload_len = other.payload(other_buf).len() as u32;
580 let diff = if other_seq > self_ack {
581 other_seq - self_ack
582 } else {
583 self_ack - other_seq
584 };
585 if diff > 2 + other_payload_len {
586 return false;
587 }
588
589 true
590 }
591}
592
593impl Layer for TcpLayer {
594 fn kind(&self) -> LayerKind {
595 LayerKind::Tcp
596 }
597
598 fn summary(&self, buf: &[u8]) -> String {
599 let sport = self.src_port(buf).unwrap_or(0);
600 let dport = self.dst_port(buf).unwrap_or(0);
601 let flags = self.flags(buf).unwrap_or(TcpFlags::NONE);
602
603 format!("TCP {} > {} {}", sport, dport, flags)
604 }
605
606 fn header_len(&self, buf: &[u8]) -> usize {
607 self.calculate_header_len(buf)
608 }
609
610 fn hashret(&self, buf: &[u8]) -> Vec<u8> {
611 self.hashret(buf)
612 }
613
614 fn answers(&self, buf: &[u8], other: &Self, other_buf: &[u8]) -> bool {
615 self.answers(buf, other, other_buf)
616 }
617
618 fn field_names(&self) -> &'static [&'static str] {
619 Self::field_names()
620 }
621}
622
623#[cfg(test)]
624mod tests {
625 use super::*;
626
627 fn sample_tcp_header() -> Vec<u8> {
628 vec![
629 0x00, 0x50, 0x1F, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, ]
639 }
640
641 #[test]
642 fn test_field_readers() {
643 let buf = sample_tcp_header();
644 let layer = TcpLayer::at_offset(0);
645
646 assert_eq!(layer.src_port(&buf).unwrap(), 80);
647 assert_eq!(layer.dst_port(&buf).unwrap(), 8080);
648 assert_eq!(layer.seq(&buf).unwrap(), 1);
649 assert_eq!(layer.ack(&buf).unwrap(), 0);
650 assert_eq!(layer.data_offset(&buf).unwrap(), 5);
651 assert_eq!(layer.window(&buf).unwrap(), 65535);
652 assert_eq!(layer.urgent_ptr(&buf).unwrap(), 0);
653
654 let flags = layer.flags(&buf).unwrap();
655 assert!(flags.syn);
656 assert!(!flags.ack);
657 }
658
659 #[test]
660 fn test_field_writers() {
661 let mut buf = sample_tcp_header();
662 let layer = TcpLayer::at_offset(0);
663
664 layer.set_src_port(&mut buf, 12345).unwrap();
665 assert_eq!(layer.src_port(&buf).unwrap(), 12345);
666
667 layer.set_dst_port(&mut buf, 443).unwrap();
668 assert_eq!(layer.dst_port(&buf).unwrap(), 443);
669
670 layer.set_seq(&mut buf, 0x12345678).unwrap();
671 assert_eq!(layer.seq(&buf).unwrap(), 0x12345678);
672
673 layer.set_ack(&mut buf, 0xABCDEF00).unwrap();
674 assert_eq!(layer.ack(&buf).unwrap(), 0xABCDEF00);
675
676 layer.set_flags(&mut buf, TcpFlags::SA).unwrap();
677 let flags = layer.flags(&buf).unwrap();
678 assert!(flags.syn);
679 assert!(flags.ack);
680 }
681
682 #[test]
683 fn test_flags() {
684 let mut buf = sample_tcp_header();
685 let layer = TcpLayer::at_offset(0);
686
687 let mut flags = TcpFlags::SA;
689 flags.ns = true;
690 layer.set_flags(&mut buf, flags).unwrap();
691
692 let read_flags = layer.flags(&buf).unwrap();
693 assert!(read_flags.syn);
694 assert!(read_flags.ack);
695 assert!(read_flags.ns);
696 }
697
698 #[test]
699 fn test_header_len() {
700 let buf = sample_tcp_header();
701 let layer = TcpLayer::at_offset(0);
702
703 assert_eq!(layer.calculate_header_len(&buf), 20);
704
705 let mut buf_with_opts = sample_tcp_header();
707 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);
711 }
712
713 #[test]
714 fn test_validate() {
715 let buf = sample_tcp_header();
716 assert!(TcpLayer::validate(&buf, 0).is_ok());
717
718 let short = vec![0x00, 0x50];
720 assert!(TcpLayer::validate(&short, 0).is_err());
721
722 let mut bad_doff = sample_tcp_header();
724 bad_doff[12] = 0x30; assert!(TcpLayer::validate(&bad_doff, 0).is_err());
726 }
727
728 #[test]
729 fn test_summary() {
730 let buf = sample_tcp_header();
731 let layer = TcpLayer::at_offset(0);
732
733 let summary = layer.summary(&buf);
734 assert!(summary.contains("80"));
735 assert!(summary.contains("8080"));
736 assert!(summary.contains("S")); }
738
739 #[test]
740 fn test_at_offset_dynamic() {
741 let buf = sample_tcp_header();
742 let layer = TcpLayer::at_offset_dynamic(&buf, 0).unwrap();
743
744 assert_eq!(layer.index.start, 0);
745 assert_eq!(layer.index.end, 20);
746 }
747
748 #[test]
749 fn test_payload() {
750 let mut buf = sample_tcp_header();
751 buf.extend_from_slice(b"Hello, TCP!");
752
753 let layer = TcpLayer::at_offset(0);
754 let payload = layer.payload(&buf);
755
756 assert_eq!(payload, b"Hello, TCP!");
757 }
758}