调整项目结构、尝试支持安卓

This commit is contained in:
lubeilin
2023-01-08 15:38:45 +08:00
parent d956e493af
commit 292893e9dd
76 changed files with 1132 additions and 588 deletions
+25
View File
@@ -0,0 +1,25 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("the buffer is too small")]
SmallBuffer,
#[error("the packet is invalid")]
InvalidPacket,
#[error("Unimplemented")]
Unimplemented,
// #[error("the vaue is invalid for the field")]
// InvalidValue,
//
// #[error("the value has already been defined")]
// AlreadyDefined,
//
// #[error(transparent)]
// Io(#[from] io::Error),
//
// #[error(transparent)]
// Nul(#[from] ffi::NulError),
}
pub type Result<T> = ::std::result::Result<T, Error>;
+174
View File
@@ -0,0 +1,174 @@
use std::fmt;
use byteorder::{BigEndian, ReadBytesExt};
use crate::cal_checksum;
use crate::error::*;
/// icmp 协议
/* https://www.rfc-editor.org/rfc/rfc792
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 不同Type和Code有不同含义 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据体 不同Type和Code有不同含义 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
use crate::icmp::{Code, Kind};
use crate::ip::ipv4::packet::IpV4Packet;
pub struct IcmpPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> IcmpPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> Result<Self> {
if buffer.as_ref().len() < 8 {
Err(Error::SmallBuffer)?
}
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IcmpPacket<B> {
pub fn set_kind(&mut self, kind: Kind) {
self.buffer.as_mut()[0] = kind.into();
}
pub fn update_checksum(&mut self) {
self.buffer.as_mut()[2..4].copy_from_slice(&[0, 0]);
let checksum = cal_checksum(self.buffer.as_ref());
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
}
}
impl<B: AsRef<[u8]>> IcmpPacket<B> {
pub fn kind(&self) -> Kind {
Kind::from(self.buffer.as_ref()[0])
}
pub fn code(&self) -> Code {
Code::from(self.kind(), self.buffer.as_ref()[1])
}
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
}
pub fn header_other(&self) -> HeaderOther {
match self.kind() {
Kind::EchoReply
| Kind::EchoRequest
| Kind::TimestampRequest
| Kind::TimestampReply
| Kind::InformationRequest
| Kind::InformationReply => {
let ide = (&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap();
let seq = (&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap();
HeaderOther::Identifier(ide, seq)
}
Kind::DestinationUnreachable | Kind::TimeExceeded | Kind::SourceQuench => {
let bytes = self.buffer.as_ref();
HeaderOther::Unused(bytes[4], bytes[5], bytes[6], bytes[7])
}
Kind::Redirect => {
let bytes = self.buffer.as_ref();
HeaderOther::Address(bytes[4], bytes[5], bytes[6], bytes[7])
}
Kind::ParameterProblem => HeaderOther::Pointer(self.buffer.as_ref()[4]),
_ => {
let bytes = self.buffer.as_ref();
HeaderOther::UnKnown(bytes[4], bytes[5], bytes[6], bytes[7])
}
}
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[8..]
}
pub fn description(&self) -> Description<&[u8]> {
use std::io::Cursor;
match self.kind() {
Kind::DestinationUnreachable
| Kind::TimeExceeded
| Kind::ParameterProblem
| Kind::SourceQuench
| Kind::Redirect => match IpV4Packet::new(self.payload()) {
Ok(d) => Description::Ip(d),
Err(_) => Description::Other(self.payload()),
},
Kind::TimestampRequest | Kind::TimestampReply => {
let mut buffer = Cursor::new(self.payload());
Description::Timestamp(
buffer.read_u32::<BigEndian>().unwrap(),
buffer.read_u32::<BigEndian>().unwrap(),
buffer.read_u32::<BigEndian>().unwrap(),
)
}
_ => Description::Other(self.payload()),
}
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IcmpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct(if self.is_valid() {
"icmp::Packet"
} else {
"icmp::Packet!"
})
.field("kind", &self.kind())
.field("code", &self.code())
.field("checksum", &self.checksum())
.field("payload", &self.payload())
.finish()
}
}
#[derive(Debug)]
pub enum HeaderOther {
/// 全零
Unused(u8, u8, u8, u8),
/// If code = 0, identifies the octet where an error was detected.
Pointer(u8),
/// Address of the gateway to which traffic for the network specified
/// in the internet destination network field of the original
/// datagram's data should be sent.
Address(u8, u8, u8, u8),
/// Identifier | Sequence Number
Identifier(u16, u16),
UnKnown(u8, u8, u8, u8),
}
pub enum Description<B> {
Ip(IpV4Packet<B>),
///时间戳 Originate Timestamp,Receive Timestamp,Transmit Timestamp
Timestamp(u32, u32, u32),
Other(B),
}
impl<B: AsRef<[u8]> + std::fmt::Debug> fmt::Debug for Description<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Description::Ip(packet) => f.debug_struct(&format!("{:?}", packet)).finish(),
Description::Timestamp(originate, receive, transmit) => f
.debug_struct("")
.field("originate", originate)
.field("receive", receive)
.field("transmit", transmit)
.finish(),
Description::Other(bytes) => f.debug_struct(&format!("{:?}", bytes)).finish(),
}
}
}
+414
View File
@@ -0,0 +1,414 @@
pub mod icmp;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Kind {
/// ping应答,type=0
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ...
+-+-+-+-+-
*/
EchoReply,
/// 目的地不可达,差错报文的一种,路由器收到一个不能转发的数据报,会向源地址返回这个报文,type=3
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
DestinationUnreachable,
/// 源抑制报文,用于防止接收端缓存溢出,接收设备发送这个来请求源设备降低发送速度,type=4
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
SourceQuench,
/// 重定向报文,当路由器接收包的接口正好是去往目的地的出口时,会向源地址发送重定向报文,告知源直接将数据发往自己的下一跳,type=5
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Gateway Internet Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
Redirect,
/// ping请求,type=8
EchoRequest,
/// 路由器通告,type=9,
RouterAdvertisement,
/// 路由器请求,type=10
RouterSolicitation,
/// 报文ttl为0后,路由器会向源发送此报文,type=11
/// Tracert工作原理:
/// 首先向目的地发送ttl=1的包,下一跳路由器收到后ttl-1,此时ttl=0,将向源发送 ICMP time exceeded
/// 再发送ttl=2的包,以此类推,直到目标主机接收到改包,此时不会回复ICMP time exceeded,代表已经探测到目的地
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
TimeExceeded,
/// 参数错误,数据有误、校验和不对等,type=12
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Pointer | unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
注:Pointer指示错误的位置
*/
ParameterProblem,
/// 时间戳请求,type=13
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Originate Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Receive Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Transmit Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
TimestampRequest,
/// 时间戳响应,type=14
TimestampReply,
/// 信息请求,type=15
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
InformationRequest,
/// 信息响应,type=16
InformationReply,
/// 地址掩码请求,type=17
AddressMaskRequest,
/// 地址掩码应答,type=18
AddressMaskReply,
///
TraceRoute,
///
Unknown(u8),
}
impl From<u8> for Kind {
fn from(value: u8) -> Kind {
use self::Kind::*;
match value {
0 => EchoReply,
3 => DestinationUnreachable,
4 => SourceQuench,
5 => Redirect,
8 => EchoRequest,
9 => RouterAdvertisement,
10 => RouterSolicitation,
11 => TimeExceeded,
12 => ParameterProblem,
13 => TimestampRequest,
14 => TimestampReply,
15 => InformationRequest,
16 => InformationReply,
17 => AddressMaskRequest,
18 => AddressMaskReply,
30 => TraceRoute,
v => Unknown(v),
}
}
}
impl Into<u8> for Kind {
fn into(self) -> u8 {
use self::Kind::*;
match self {
EchoReply => 0,
DestinationUnreachable => 3,
SourceQuench => 4,
Redirect => 5,
EchoRequest => 8,
RouterAdvertisement => 9,
RouterSolicitation => 10,
TimeExceeded => 11,
ParameterProblem => 12,
TimestampRequest => 13,
TimestampReply => 14,
InformationRequest => 15,
InformationReply => 16,
AddressMaskRequest => 17,
AddressMaskReply => 18,
TraceRoute => 30,
Unknown(v) => v,
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Code {
DestinationUnreachable(DestinationUnreachable),
Redirect(Redirect),
ParameterProblem(ParameterProblem),
Other(u8),
}
impl Code {
pub fn from(kind: Kind, code: u8) -> Code {
match kind {
Kind::DestinationUnreachable => {
Code::DestinationUnreachable(DestinationUnreachable::from(code))
}
Kind::Redirect => Code::Redirect(Redirect::from(code)),
Kind::ParameterProblem => Code::ParameterProblem(ParameterProblem::from(code)),
_ => Code::Other(code),
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum DestinationUnreachable {
/// 网络不可达
DestinationNetworkUnreachable,
/// 主机不可达
DestinationHostUnreachable,
/// 协议不可达
DestinationProtocolUnreachable,
/// 端口不可达
DestinationPortUnreachable,
/// 需要进行分片但设置不分片比特
FragmentationRequired,
/// 源站选路失败
SourceRouteFailed,
/// 目的网络未知
DestinationNetworkUnknown,
/// 目的主机未知
DestinationHostUnknown,
/// 源主机被隔离(作废不用)
SourceHostIsolated,
/// 目的网络被强制禁止
NetworkAdministrativelyProhibited,
/// 目的主机被强制禁止
HostAdministrativelyProhibited,
/// 由于服务类型TOS,网络不可达
NetworkUnreachableForTos,
/// 由于服务类型TOS,主机不可达
HostUnreachableForTos,
/// 由于过滤,通信被强制禁止
CommunicationAdministrativelyProhibited,
/// 主机越权
HostPrecedenceViolation,
/// 优先中止生效
PrecedentCutoffInEffect,
///
Unknown(u8),
}
/// Codes for Redirect Message packets.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Redirect {
/// 对网络重定向
RedirectDatagramForNetwork,
/// 对主机重定向
RedirectDatagramForHost,
/// 对服务类型和网络重定向
RedirectDatagramForTosAndNetwork,
/// 对服务类型和主机重定向
RedirectDatagramForTosAndHost,
///
Unknown(u8),
}
/// Codes for TimeExceeded Message packets.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum TimeExceeded {
/// TTL超时报文
Transit,
/// 分片重组超时报文
Reassembly,
///
Unknown(u8),
}
/// Codes for Parameter Problem packets.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum ParameterProblem {
/// 坏的IP首部(包括各种差错)
PointerIndicatesError,
/// 缺少必需的选项
MissingRequiredData,
/// 长度错误
BadLength,
///
Unknown(u8),
}
impl From<u8> for DestinationUnreachable {
fn from(value: u8) -> Self {
use self::DestinationUnreachable::*;
match value {
0 => DestinationNetworkUnreachable,
1 => DestinationHostUnreachable,
2 => DestinationProtocolUnreachable,
3 => DestinationPortUnreachable,
4 => FragmentationRequired,
5 => SourceRouteFailed,
6 => DestinationNetworkUnknown,
7 => DestinationHostUnknown,
8 => SourceHostIsolated,
9 => NetworkAdministrativelyProhibited,
10 => HostAdministrativelyProhibited,
11 => NetworkUnreachableForTos,
12 => HostUnreachableForTos,
13 => CommunicationAdministrativelyProhibited,
14 => HostPrecedenceViolation,
15 => PrecedentCutoffInEffect,
v => Unknown(v),
}
}
}
impl Into<u8> for DestinationUnreachable {
fn into(self) -> u8 {
use self::DestinationUnreachable::*;
match self {
DestinationNetworkUnreachable => 0,
DestinationHostUnreachable => 1,
DestinationProtocolUnreachable => 2,
DestinationPortUnreachable => 3,
FragmentationRequired => 4,
SourceRouteFailed => 5,
DestinationNetworkUnknown => 6,
DestinationHostUnknown => 7,
SourceHostIsolated => 8,
NetworkAdministrativelyProhibited => 9,
HostAdministrativelyProhibited => 10,
NetworkUnreachableForTos => 11,
HostUnreachableForTos => 12,
CommunicationAdministrativelyProhibited => 13,
HostPrecedenceViolation => 14,
PrecedentCutoffInEffect => 15,
Unknown(v) => v,
}
}
}
impl From<u8> for Redirect {
fn from(value: u8) -> Self {
use self::Redirect::*;
match value {
0 => RedirectDatagramForNetwork,
1 => RedirectDatagramForHost,
2 => RedirectDatagramForTosAndNetwork,
3 => RedirectDatagramForTosAndHost,
v => Unknown(v),
}
}
}
impl Into<u8> for Redirect {
fn into(self) -> u8 {
use self::Redirect::*;
match self {
RedirectDatagramForNetwork => 0,
RedirectDatagramForHost => 1,
RedirectDatagramForTosAndNetwork => 2,
RedirectDatagramForTosAndHost => 3,
Unknown(v) => v,
}
}
}
impl From<u8> for TimeExceeded {
fn from(value: u8) -> Self {
use self::TimeExceeded::*;
match value {
0 => Transit,
1 => Reassembly,
v => Unknown(v),
}
}
}
impl Into<u8> for TimeExceeded {
fn into(self) -> u8 {
use self::TimeExceeded::*;
match self {
Transit => 0,
Reassembly => 1,
Unknown(v) => v,
}
}
}
impl From<u8> for ParameterProblem {
fn from(value: u8) -> Self {
use self::ParameterProblem::*;
match value {
0 => PointerIndicatesError,
1 => MissingRequiredData,
2 => BadLength,
v => Unknown(v),
}
}
}
impl Into<u8> for ParameterProblem {
fn into(self) -> u8 {
use self::ParameterProblem::*;
match self {
PointerIndicatesError => 0,
MissingRequiredData => 1,
BadLength => 2,
Unknown(v) => v,
}
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod packet;
pub mod protocol;
+250
View File
@@ -0,0 +1,250 @@
use std::fmt;
use std::net::Ipv4Addr;
use byteorder::{BigEndian, ReadBytesExt};
use crate::cal_checksum;
use crate::error::*;
use crate::ip::ipv4::protocol::Protocol;
/// ip协议
/*
RFC: 791 https://www.ietf.org/rfc/rfc791.txt
0 15 31
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 版本(4) | 头部长度(4) | 服务类型(8) | 总字节数(16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 标识(16) | 标志(3) | 片偏移(13) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 生存时间(8) | 协议(8) | 头部校验和(16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 选项 + 填充 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
数据体
注:头部长度单位是4字节,所以ip头最长60字节,选项最长40字节,选项填充按4字节对齐
*/
pub struct IpV4Packet<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> IpV4Packet<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> Result<Self> {
if buffer.as_ref()[0] >> 4 != 4 {
Err(Error::Unimplemented)?
}
if buffer.as_ref().len() < 20 {
Err(Error::SmallBuffer)?
}
let packet = Self::unchecked(buffer);
if packet.buffer.as_ref().len() < packet.header_len() as usize * 4 {
Err(Error::SmallBuffer)?
}
Ok(packet)
}
}
impl<B: AsRef<[u8]>> IpV4Packet<B> {
pub fn header(&self) -> &[u8] {
&self.buffer.as_ref()[..(self.header_len() as usize * 4)]
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[(self.header_len() as usize * 4)..]
// match self.protocol() {
// Protocol::Udp => {
// let udp = UdpPacket::new(IpAddr::V4(self.source_ip()),
// IpAddr::V4(self.destination_ip()),
// &self.buffer.as_ref()[(self.header_len() as usize * 4)..])?;
// Ok(crate::IpUpperLayer::UDP(udp))
// }
// _ => {
// Ok(crate::IpUpperLayer::Unknown(self.buffer.as_ref()));
// }
// }
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
pub fn header_mut(&mut self) -> &mut [u8] {
let len = self.header_len() as usize * 4;
&mut self.buffer.as_mut()[..len]
}
pub fn payload_mut(&mut self) -> &mut [u8] {
let len = self.header_len() as usize * 4;
&mut self.buffer.as_mut()[len..]
}
pub fn set_source_ip(&mut self, value: Ipv4Addr) {
self.header_mut()[12..16].copy_from_slice(&value.octets());
}
pub fn set_destination_ip(&mut self, value: Ipv4Addr) {
self.header_mut()[16..20].copy_from_slice(&value.octets());
}
fn set_checksum(&mut self, value: u16) {
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
}
/// 更新校验和
pub fn update_checksum(&mut self) {
//先将校验和置0
self.set_checksum(0);
self.set_checksum(cal_checksum(self.header()))
}
}
impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// 版本号,ipv4的为4
pub fn version(&self) -> u8 {
self.buffer.as_ref()[0] >> 4
}
/// 头部长度,以4字节为单位
pub fn header_len(&self) -> u8 {
self.buffer.as_ref()[0] & 0b1111
}
/// 差异化服务编码点
///
/// 类别(3)+丢失概率(2)+用途(1)
///
///
/// 类别子字段值 | 名称
/// ---|:---
/// 000 | 常规(Routine)
/// 001 | 优先(Priority)
/// 010 | 立即(Immediate)
/// 011 | 瞬间(Flash)
/// 100 | 瞬间覆盖(Flash Override)
/// 101 | 严重(CRITIC/ECP)
/// 110 | 网间控制(Internetwork Control)
/// 111 | 网络控制(Network Control)
///
///
/// 参考:https://www.modb.pro/db/477116
pub fn dscp(&self) -> u8 {
self.buffer.as_ref()[1] >> 2
}
/// 显示拥塞 00:发送主机不支持ECN 01或者10:发送主机支持ECN 11:路由器正在经历拥塞
pub fn ecn(&self) -> u8 {
self.buffer.as_ref()[1] & 0b11
}
/// ip报总字节数
pub fn length(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
pub fn id(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 标志 3位.
/// 第1位没有使用
/// 第2位表示不分段位(DF
/// 0:允许数据报分段
/// 1:数据报不能分段
/// 置1之后路由器不能对其分段处理,如果超过MTU值则路由器不能对其转发将其丢弃,并向源点发送错误消息
/// 第3位表示更多段位
/// 0:数据包后面没有包,该包为最后的包
/// 1:数据包后面有更多的包
pub fn flags(&self) -> u8 {
self.buffer.as_ref()[6] >> 5
}
/// 片偏移 13位.
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
pub fn offset(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
& 0x1fff
}
/// 生存时间.
/// 每一跳 减1 到0了则会被丢弃
pub fn ttl(&self) -> u8 {
self.buffer.as_ref()[8]
}
/// 协议.
pub fn protocol(&self) -> Protocol {
self.buffer.as_ref()[9].into()
}
/// 首部校验和
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[10..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 验证校验和
///
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
/// 所以抓到发出去的包校验和可能是错误的
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.header()) == 0
}
/// 源ip.
pub fn source_ip(&self) -> Ipv4Addr {
Ipv4Addr::new(
self.buffer.as_ref()[12],
self.buffer.as_ref()[13],
self.buffer.as_ref()[14],
self.buffer.as_ref()[15],
)
}
/// 目标ip.
pub fn destination_ip(&self) -> Ipv4Addr {
Ipv4Addr::new(
self.buffer.as_ref()[16],
self.buffer.as_ref()[17],
self.buffer.as_ref()[18],
self.buffer.as_ref()[19],
)
}
/// 选项.
pub fn options(&self) -> &[u8] {
&self.buffer.as_ref()[20..(self.header_len() as usize * 4)]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IpV4Packet<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ip::v4::Packet")
.field("version", &self.version())
.field("header_len", &self.header_len())
.field("dscp", &self.dscp())
.field("ecn", &self.ecn())
.field("length", &self.length())
.field("id", &self.id())
.field("flags", &self.flags())
.field("offset", &self.offset())
.field("ttl", &self.ttl())
.field("protocol", &self.protocol())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("source", &self.source_ip())
.field("destination", &self.destination_ip())
.field("options", &self.options())
.field("payload", &self.payload())
.finish()
}
}
+742
View File
@@ -0,0 +1,742 @@
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
///
Hopopt,
///
Icmp,
///
Igmp,
///
Ggp,
///
Ipv4,
///
St,
///
Tcp,
///
Cbt,
///
Egp,
///
Igp,
///
BbnRccMon,
///
NvpII,
///
Pup,
///
Argus,
///
Emcon,
///
Xnet,
///
Chaos,
///
Udp,
///
Mux,
///
DcnMeas,
///
Hmp,
///
Prm,
///
XnsIdp,
///
Trunk1,
///
Trunk2,
///
Leaf1,
///
Leaf2,
///
Rdp,
///
Irtp,
///
IsoTp4,
///
Netblt,
///
MfeNsp,
///
MeritInp,
///
Dccp,
///
ThreePc,
///
Idpr,
///
Xtp,
///
Ddp,
///
IdprCmtp,
///
TpPlusPlus,
///
Il,
///
Ipv6,
///
Sdrp,
///
Ipv6Route,
///
Ipv6Frag,
///
Idrp,
///
Rsvp,
///
Gre,
///
Dsr,
///
Bna,
///
Esp,
///
Ah,
///
INlsp,
///
Swipe,
///
Narp,
///
Mobile,
///
Tlsp,
///
Skip,
///
Ipv6Icmp,
///
Ipv6NoNxt,
///
Ipv6Opts,
///
HostInternal,
///
Cftp,
///
LocalNetwork,
///
SatExpak,
///
Kryptolan,
///
Rvd,
///
Ippc,
///
DistributedFs,
///
SatMon,
///
Visa,
///
Ipcv,
///
Cpnx,
///
Cphb,
///
Wsn,
///
Pvp,
///
BrSatMon,
///
SunNd,
///
WbMon,
///
WbExpak,
///
IsoIp,
///
Vmtp,
///
SecureVmtp,
///
Vines,
///
TtpOrIptm,
///
NsfnetIgp,
///
Dgp,
///
Tcf,
///
Eigrp,
///
OspfigP,
///
SpriteRpc,
///
Larp,
///
Mtp,
///
Ax25,
///
IpIp,
///
Micp,
///
SccSp,
///
Etherip,
///
Encap,
///
PrivEncryption,
///
Gmtp,
///
Ifmp,
///
Pnni,
///
Pim,
///
Aris,
///
Scps,
///
Qnx,
///
AN,
///
IpComp,
///
Snp,
///
CompaqPeer,
///
IpxInIp,
///
Vrrp,
///
Pgm,
///
ZeroHop,
///
L2tp,
///
Ddx,
///
Iatp,
///
Stp,
///
Srp,
///
Uti,
///
Smp,
///
Sm,
///
Ptp,
///
IsisOverIpv4,
///
Fire,
///
Crtp,
///
Crudp,
///
Sscopmce,
///
Iplt,
///
Sps,
///
Pipe,
///
Sctp,
///
Fc,
///
RsvpE2eIgnore,
///
MobilityHeader,
///
UdpLite,
///
MplsInIp,
///
Manet,
///
Hip,
///
Shim6,
///
Wesp,
Rohc,
Test1,
Test2,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Protocol {
use self::Protocol::*;
match value {
0 => Hopopt,
1 => Icmp,
2 => Igmp,
3 => Ggp,
4 => Ipv4,
5 => St,
6 => Tcp,
7 => Cbt,
8 => Egp,
9 => Igp,
10 => BbnRccMon,
11 => NvpII,
12 => Pup,
13 => Argus,
14 => Emcon,
15 => Xnet,
16 => Chaos,
17 => Udp,
18 => Mux,
19 => DcnMeas,
20 => Hmp,
21 => Prm,
22 => XnsIdp,
23 => Trunk1,
24 => Trunk2,
25 => Leaf1,
26 => Leaf2,
27 => Rdp,
28 => Irtp,
29 => IsoTp4,
30 => Netblt,
31 => MfeNsp,
32 => MeritInp,
33 => Dccp,
34 => ThreePc,
35 => Idpr,
36 => Xtp,
37 => Ddp,
38 => IdprCmtp,
39 => TpPlusPlus,
40 => Il,
41 => Ipv6,
42 => Sdrp,
43 => Ipv6Route,
44 => Ipv6Frag,
45 => Idrp,
46 => Rsvp,
47 => Gre,
48 => Dsr,
49 => Bna,
50 => Esp,
51 => Ah,
52 => INlsp,
53 => Swipe,
54 => Narp,
55 => Mobile,
56 => Tlsp,
57 => Skip,
58 => Ipv6Icmp,
59 => Ipv6NoNxt,
60 => Ipv6Opts,
61 => HostInternal,
62 => Cftp,
63 => LocalNetwork,
64 => SatExpak,
65 => Kryptolan,
66 => Rvd,
67 => Ippc,
68 => DistributedFs,
69 => SatMon,
70 => Visa,
71 => Ipcv,
72 => Cpnx,
73 => Cphb,
74 => Wsn,
75 => Pvp,
76 => BrSatMon,
77 => SunNd,
78 => WbMon,
79 => WbExpak,
80 => IsoIp,
81 => Vmtp,
82 => SecureVmtp,
83 => Vines,
84 => TtpOrIptm,
85 => NsfnetIgp,
86 => Dgp,
87 => Tcf,
88 => Eigrp,
89 => OspfigP,
90 => SpriteRpc,
91 => Larp,
92 => Mtp,
93 => Ax25,
94 => IpIp,
95 => Micp,
96 => SccSp,
97 => Etherip,
98 => Encap,
99 => PrivEncryption,
100 => Gmtp,
101 => Ifmp,
102 => Pnni,
103 => Pim,
104 => Aris,
105 => Scps,
106 => Qnx,
107 => AN,
108 => IpComp,
109 => Snp,
110 => CompaqPeer,
111 => IpxInIp,
112 => Vrrp,
113 => Pgm,
114 => ZeroHop,
115 => L2tp,
116 => Ddx,
117 => Iatp,
118 => Stp,
119 => Srp,
120 => Uti,
121 => Smp,
122 => Sm,
123 => Ptp,
124 => IsisOverIpv4,
125 => Fire,
126 => Crtp,
127 => Crudp,
128 => Sscopmce,
129 => Iplt,
130 => Sps,
131 => Pipe,
132 => Sctp,
133 => Fc,
134 => RsvpE2eIgnore,
135 => MobilityHeader,
136 => UdpLite,
137 => MplsInIp,
138 => Manet,
139 => Hip,
140 => Shim6,
141 => Wesp,
142 => Rohc,
253 => Test1,
254 => Test2,
p => Unknown(p),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
use self::Protocol::*;
match self {
Hopopt => 0,
Icmp => 1,
Igmp => 2,
Ggp => 3,
Ipv4 => 4,
St => 5,
Tcp => 6,
Cbt => 7,
Egp => 8,
Igp => 9,
BbnRccMon => 10,
NvpII => 11,
Pup => 12,
Argus => 13,
Emcon => 14,
Xnet => 15,
Chaos => 16,
Udp => 17,
Mux => 18,
DcnMeas => 19,
Hmp => 20,
Prm => 21,
XnsIdp => 22,
Trunk1 => 23,
Trunk2 => 24,
Leaf1 => 25,
Leaf2 => 26,
Rdp => 27,
Irtp => 28,
IsoTp4 => 29,
Netblt => 30,
MfeNsp => 31,
MeritInp => 32,
Dccp => 33,
ThreePc => 34,
Idpr => 35,
Xtp => 36,
Ddp => 37,
IdprCmtp => 38,
TpPlusPlus => 39,
Il => 40,
Ipv6 => 41,
Sdrp => 42,
Ipv6Route => 43,
Ipv6Frag => 44,
Idrp => 45,
Rsvp => 46,
Gre => 47,
Dsr => 48,
Bna => 49,
Esp => 50,
Ah => 51,
INlsp => 52,
Swipe => 53,
Narp => 54,
Mobile => 55,
Tlsp => 56,
Skip => 57,
Ipv6Icmp => 58,
Ipv6NoNxt => 59,
Ipv6Opts => 60,
HostInternal => 61,
Cftp => 62,
LocalNetwork => 63,
SatExpak => 64,
Kryptolan => 65,
Rvd => 66,
Ippc => 67,
DistributedFs => 68,
SatMon => 69,
Visa => 70,
Ipcv => 71,
Cpnx => 72,
Cphb => 73,
Wsn => 74,
Pvp => 75,
BrSatMon => 76,
SunNd => 77,
WbMon => 78,
WbExpak => 79,
IsoIp => 80,
Vmtp => 81,
SecureVmtp => 82,
Vines => 83,
TtpOrIptm => 84,
NsfnetIgp => 85,
Dgp => 86,
Tcf => 87,
Eigrp => 88,
OspfigP => 89,
SpriteRpc => 90,
Larp => 91,
Mtp => 92,
Ax25 => 93,
IpIp => 94,
Micp => 95,
SccSp => 96,
Etherip => 97,
Encap => 98,
PrivEncryption => 99,
Gmtp => 100,
Ifmp => 101,
Pnni => 102,
Pim => 103,
Aris => 104,
Scps => 105,
Qnx => 106,
AN => 107,
IpComp => 108,
Snp => 109,
CompaqPeer => 110,
IpxInIp => 111,
Vrrp => 112,
Pgm => 113,
ZeroHop => 114,
L2tp => 115,
Ddx => 116,
Iatp => 117,
Stp => 118,
Srp => 119,
Uti => 120,
Smp => 121,
Sm => 122,
Ptp => 123,
IsisOverIpv4 => 124,
Fire => 125,
Crtp => 126,
Crudp => 127,
Sscopmce => 128,
Iplt => 129,
Sps => 130,
Pipe => 131,
Sctp => 132,
Fc => 133,
RsvpE2eIgnore => 134,
MobilityHeader => 135,
UdpLite => 136,
MplsInIp => 137,
Manet => 138,
Hip => 139,
Shim6 => 140,
Wesp => 141,
Rohc => 142,
Test1 => 253,
Test2 => 254,
Unknown(p) => p,
}
}
}
+18
View File
@@ -0,0 +1,18 @@
use ipv4::packet::IpV4Packet;
use crate::error::*;
pub mod ipv4;
pub enum IpPacket<B> {
V4(IpV4Packet<B>),
}
impl<B: AsRef<[u8]>> IpPacket<B> {
pub fn new(buffer: B) -> Result<Self> {
match buffer.as_ref()[0] >> 4 {
4 => Ok(IpPacket::V4(IpV4Packet::new(buffer)?)),
_ => Err(Error::InvalidPacket),
}
}
}
+146
View File
@@ -0,0 +1,146 @@
use std::net::Ipv4Addr;
use byteorder::BigEndian;
use byteorder::ReadBytesExt;
pub mod error;
pub mod icmp;
pub mod ip;
pub mod tcp;
pub mod udp;
// pub enum IpUpperLayer<B> {
// UDP(UdpPacket<B>),
// Unknown(B),
// }
//
// impl<B: AsRef<[u8]>> fmt::Debug for IpUpperLayer<B> {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// match self {
// IpUpperLayer::UDP(p) => {
// f.debug_struct("udp::Packet")
// .field("data", p).finish()
// }
// IpUpperLayer::Unknown(p) => {
// f.debug_struct("Unknown")
// .field("data", &p.as_ref()).finish()
// }
// }
// }
// }
/// https://datatracker.ietf.org/doc/html/rfc1071 4.1节
///
/// 计算校验和,各协议都是通用的
/// 计算:
/// 首先将校验和置0,然后对首部每个16位数进行二进制反码求和,
/// 得到校验和之后,持续取高16位加到低16位,直到高16位全为0
/// 最后取反
///
/// 校验:
/// 在已有校验和的情况下,再计算校验和,正确的数据计算得到的值为0
/*
unsigned short getChecksum(unsigned short * iphead, int count)
{
unsigned long int sum = 0;
unsigned short checksum = 0;
printf("\nStarting adress: %p\n", iphead);
while(count > 1) {
sum += * (unsigned short *) (iphead);
count -=2;
printf("a: %p, content is: %d, new sum: %ld\n", iphead, (unsigned short) *(iphead), sum);
iphead++;
}
if(count > 0) {
sum += * (unsigned short *) (iphead);
}
while(sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
checksum = ~sum;
return checksum;
}
*/
pub fn cal_checksum(buffer: &[u8]) -> u16 {
use std::io::Cursor;
let mut sum = 0;
let length = buffer.len();
let mut buffer = Cursor::new(buffer);
while let Ok(value) = buffer.read_u16::<BigEndian>() {
sum += u32::from(value);
}
if length & 1 == 1 {
//奇数,说明还有一位,不足的补0
sum += u32c(buffer.read_u8().unwrap(), 0);
}
while sum >> 16 != 0 {
sum = (sum & 0xffff) + (sum >> 16);
}
!sum as u16
}
/// ipv4上层协议校验和计算方式
/// ipv4 udp伪首部 用于参与计算首部校验和
/*
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| source address |
+--------+--------+--------+--------+
| destination address |
+--------+--------+--------+--------+
| zero |protocol| length |
+--------+--------+--------+--------+
*/
pub fn ipv4_cal_checksum(
buffer: &[u8],
src_ip: &Ipv4Addr,
dest_ip: &Ipv4Addr,
protocol: u8,
length: u16,
) -> u16 {
use std::io::Cursor;
let mut sum = 0;
let src_ip = src_ip.octets();
sum += u32c(src_ip[0], src_ip[1]);
sum += u32c(src_ip[2], src_ip[3]);
let dest_ip = dest_ip.octets();
sum += u32c(dest_ip[0], dest_ip[1]);
sum += u32c(dest_ip[2], dest_ip[3]);
sum += u32c(0, protocol);
sum += length as u32;
let mut buffer = Cursor::new(buffer);
while let Ok(value) = buffer.read_u16::<BigEndian>() {
sum += u32::from(value);
}
if length & 1 == 1 {
//奇数,说明还有一位
sum += u32c(buffer.read_u8().unwrap(), 0);
}
while sum >> 16 != 0 {
sum = (sum & 0xffff) + (sum >> 16);
}
!sum as u16
}
#[inline]
fn u32c(x: u8, y: u8) -> u32 {
((x as u32) << 8) | y as u32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let sum = cal_checksum(&[255, 255]);
println!("{:?}", sum);
}
}
+42
View File
@@ -0,0 +1,42 @@
use std::fmt;
pub mod tcp;
pub struct Flags(u8);
pub const FIN: u8 = 0b0000_0001;
pub const SYN: u8 = 0b0000_0010;
pub const RST: u8 = 0b0000_0100;
pub const PSH: u8 = 0b0000_1000;
pub const ACK: u8 = 0b0001_0000;
pub const URG: u8 = 0b0010_0000;
impl fmt::Debug for Flags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut str = String::with_capacity(22);
if self.0 & URG != 0 {
str.push_str("URG|");
}
if self.0 & ACK != 0 {
str.push_str("ACK|");
}
if self.0 & PSH != 0 {
str.push_str("PSH|");
}
if self.0 & RST != 0 {
str.push_str("RST|");
}
if self.0 & SYN != 0 {
str.push_str("SYN|");
}
if self.0 & FIN != 0 {
str.push_str("FIN|");
}
if str.is_empty() {
f.debug_struct("NULL").finish()
} else {
let len = str.len() - 1;
f.debug_struct(&str[..len]).finish()
}
}
}
+175
View File
@@ -0,0 +1,175 @@
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]>> 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()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod udp;
+177
View File
@@ -0,0 +1,177 @@
use std::fmt;
use std::io::Cursor;
use std::net::IpAddr;
use byteorder::WriteBytesExt;
use byteorder::{BigEndian, ReadBytesExt};
use crate::error::*;
/// udp协议
///
/*
RFC 768 https://www.ietf.org/rfc/rfc768.txt
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| 源端口(16) | 目的端口(16) |
+--------+--------+--------+--------+
| 长度(16) | 校验和(16) |
+--------+--------+--------+--------+
|
| 载荷 ...
+---------------- ...
注:1.长度包含标头和数据体,以字节为单位
2.伪首部和载荷参与校验和的计算,位数不够则补0
*/
/// ipv6 udp伪首部
/* https://datatracker.ietf.org/doc/html/rfc2460
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Upper-Layer Packet Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| zero | Next Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
pub struct UdpPacket<B> {
source_ip: IpAddr,
destination_ip: IpAddr,
buffer: B,
}
impl<B: AsRef<[u8]>> UdpPacket<B> {
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> UdpPacket<B> {
UdpPacket {
source_ip,
destination_ip,
buffer,
}
}
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<UdpPacket<B>> {
if buffer.as_ref().len() < 8 {
Err(Error::SmallBuffer)?
}
let packet = Self::unchecked(source_ip, destination_ip, buffer);
Ok(packet)
}
}
impl<B: AsRef<[u8]>> UdpPacket<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 length(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
}
/// Checksum of the packet.
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || self.cal_checksum() == 0
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[8..]
}
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,
17,
self.length(),
);
}
}
IpAddr::V6(_src) => {}
}
unimplemented!()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
fn header_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..8]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
/// 设置源端口
pub fn set_source_port(&mut self, value: u16) -> &mut Self {
Cursor::new(&mut self.header_mut()[0..])
.write_u16::<BigEndian>(value)
.unwrap();
self
}
/// 设置目的端口
pub fn set_destination_port(&mut self, value: u16) -> &mut Self {
Cursor::new(&mut self.header_mut()[2..])
.write_u16::<BigEndian>(value)
.unwrap();
self
}
fn set_checknum(&mut self, value: u16) {
Cursor::new(&mut self.header_mut()[6..])
.write_u16::<BigEndian>(value)
.unwrap();
}
pub fn update_checknum(&mut self) {
//先写0
self.set_checknum(0);
self.set_checknum(self.cal_checksum());
}
}
impl<B: AsRef<[u8]>> fmt::Debug for UdpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("udp::Packet")
.field("source", &self.source_port())
.field("destination", &self.destination_port())
.field("length", &self.length())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("payload", &self.payload())
.finish()
}
}