Files
vnt/switch/packet/src/tcp/tcp.rs
T

187 lines
6.4 KiB
Rust

use std::fmt;
use std::net::IpAddr;
use byteorder::{BigEndian, ReadBytesExt};
use crate::error::*;
use crate::tcp::Flags;
/// tcp
/*
https://www.rfc-editor.org/rfc/rfc793
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Source Port: 16位 源端口
Destination Port:16位 目的端口
Sequence Number:32位 序列号,如果存在syn标志,则为初始序列号
Acknowledgment Number:32位 如果设置了ack标志,这个表示确认收到的序号
Data Offset:4位 数据的开始偏移位,单位是4字节
Reserved:6位 未使用,全零
控制位:6位 从左到右
URG: 紧急指针 表示数据要优先处理
ACK: 确认位
PSH: 推送 要求把数据尽快的交给应用层,不做处理
RST: 重置连接
SYN: 同步序列号
FIN: 结束发送
Window: 16位 能接收的数据大小
Checksum:16位 校验和,需要加入伪首部
Urgent Pointer:16位 紧急指针
Options+Padding:32位整数倍,最多40个字节
*/
pub struct TcpPacket<B> {
source_ip: IpAddr,
destination_ip: IpAddr,
buffer: B,
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> TcpPacket<B> {
TcpPacket {
source_ip,
destination_ip,
buffer,
}
}
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<TcpPacket<B>> {
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
if packet.buffer.as_ref().len() < 20 {
Err(Error::SmallBuffer)?
}
if packet.buffer.as_ref().len() < packet.data_offset() as usize * 4 {
Err(Error::SmallBuffer)?
}
Ok(packet)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> TcpPacket<B> {
fn set_checksum(&mut self, value: u16) {
self.buffer.as_mut()[16..18].copy_from_slice(&value.to_be_bytes())
}
/// 更新校验和
pub fn update_checksum(&mut self) {
//先将校验和置0
self.set_checksum(0);
self.set_checksum(self.cal_checksum())
}
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
/// 源端口
pub fn source_port(&self) -> u16 {
(&self.buffer.as_ref()[0..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 目标端口
pub fn destination_port(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 序列号
pub fn sequence(&self) -> u32 {
(&self.buffer.as_ref()[4..])
.read_u32::<BigEndian>()
.unwrap()
}
/// 确认号
pub fn acknowledgment(&self) -> u32 {
(&self.buffer.as_ref()[8..])
.read_u32::<BigEndian>()
.unwrap()
}
/// 数据偏移 4字节为单位
pub fn data_offset(&self) -> u8 {
self.buffer.as_ref()[12] >> 4
}
pub fn flags(&self) -> Flags {
Flags(self.buffer.as_ref()[13])
}
pub fn window(&self) -> u16 {
(&self.buffer.as_ref()[14..])
.read_u16::<BigEndian>()
.unwrap()
}
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[16..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
/// 所以抓到发出去的包校验和可能是错误的
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || self.cal_checksum() == 0
}
fn cal_checksum(&self) -> u16 {
match self.source_ip {
IpAddr::V4(src) => {
if let IpAddr::V4(dest) = self.destination_ip {
return crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&src,
&dest,
6,
self.buffer.as_ref().len() as u16,
);
}
}
IpAddr::V6(_src) => {}
}
unimplemented!()
}
pub fn urgent_pointer(&self) -> u16 {
(&self.buffer.as_ref()[18..])
.read_u16::<BigEndian>()
.unwrap()
}
pub fn options(&self) -> &[u8] {
&self.buffer.as_ref()[20..(self.data_offset() as usize * 4)]
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[(self.data_offset() as usize * 4)..]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for TcpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("tcp::Packet")
.field("source", &self.source_port())
.field("destination", &self.destination_port())
.field("sequence", &self.sequence())
.field("acknowledgment", &self.acknowledgment())
.field("offset", &self.data_offset())
.field("flags", &self.flags())
.field("window", &self.window())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("pointer", &self.urgent_pointer())
.field("options", &self.options())
.field("payload", &self.payload())
.finish()
}
}