packet/tcp/
mod.rs

1//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2//                    Version 2, December 2004
3//
4// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co
5//
6// Everyone is permitted to copy and distribute verbatim or modified
7// copies of this license document, and changing it is allowed as long
8// as the name is changed.
9//
10//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11//   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12//
13//  0. You just DO WHAT THE FUCK YOU WANT TO.
14
15/// TCP flags.
16pub mod flag;
17pub use self::flag::Flags;
18
19/// TCP options.
20pub mod option;
21pub use self::option::Option;
22
23mod packet;
24pub use self::packet::Packet;
25
26mod builder;
27pub use self::builder::Builder;
28
29use crate::ip;
30use crate::ip::Protocol;
31
32/// Calculate the checksum for a TCP packet.
33///
34/// # Note
35///
36/// Since the checksum for UDP packets includes a pseudo-header based on the
37/// enclosing IP packet, one has to be given.
38pub fn checksum<B: AsRef<[u8]>>(ip: &ip::Packet<B>, buffer: &[u8]) -> u16 {
39	use std::io::Cursor;
40	use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian};
41
42	let mut prefix = [0u8; 40];
43	match *ip {
44		ip::Packet::V4(ref packet) => {
45			prefix[0 .. 4].copy_from_slice(&packet.source().octets());
46			prefix[4 .. 8].copy_from_slice(&packet.destination().octets());
47
48			prefix[9] = Protocol::Tcp.into();
49			Cursor::new(&mut prefix[10 ..])
50				.write_u16::<BigEndian>(buffer.len() as u16).unwrap();
51		}
52
53		ip::Packet::V6(ref _packet) => {
54			unimplemented!();
55		}
56	};
57
58	let mut result = 0xffffu32;
59	let mut buffer = Cursor::new(buffer);
60	let mut prefix = match *ip {
61		ip::Packet::V4(_) =>
62			Cursor::new(&prefix[0 .. 12]),
63
64		ip::Packet::V6(_) =>
65			Cursor::new(&prefix[0 .. 40]),
66	};
67
68	while let Ok(value) = prefix.read_u16::<BigEndian>() {
69		result += u32::from(value);
70
71		if result > 0xffff {
72			result -= 0xffff;
73		}
74	}
75
76	while let Ok(value) = buffer.read_u16::<BigEndian>() {
77		// Skip checksum field.
78		if buffer.position() == 18 {
79			continue;
80		}
81
82		result += u32::from(value);
83
84		if result > 0xffff {
85			result -= 0xffff;
86		}
87	}
88
89	!result as u16
90}