创建项目
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
||||
[package]
|
||||
name = "virtual_network"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
packet = { path = "./packet" }
|
||||
bytes = "1.3.0"
|
||||
|
||||
libc = "0.2.137"
|
||||
|
||||
dashmap = "5.4.0"
|
||||
crossbeam = "0.8.2"
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
rsa = "0.7.2"
|
||||
rand = "0.8.5"
|
||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||
colored = "2.0.0"
|
||||
|
||||
thiserror = "1.0.37"
|
||||
chrono = "0.4.23"
|
||||
lazy_static = "1.4.0"
|
||||
moka = "0.9.6"
|
||||
protobuf = "3.2.0"
|
||||
|
||||
console = "0.15.2"
|
||||
mac_address = "1.1.4"
|
||||
clap = { version = "4.0.32", features = ["derive"] }
|
||||
#clap_derive = "4.0.21"
|
||||
[target.'cfg(any(unix))'.dependencies]
|
||||
tun = { version = "0.5" }
|
||||
sudo = "0.6.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||
wintun = "0.2.1"
|
||||
libloading = "0.7.4"
|
||||
runas = "0.2.1"
|
||||
|
||||
#[dependencies.windows]
|
||||
#
|
||||
#libloading = "0.7.4"
|
||||
#
|
||||
#version = "0.37.0"
|
||||
#features = [
|
||||
# "alloc",
|
||||
# "Win32_Foundation",
|
||||
# "Win32_NetworkManagement_IpHelper",
|
||||
# "Win32_Networking_WinSock",
|
||||
# "Win32_UI_WindowsAndMessaging",
|
||||
# "Win32_System_IO"
|
||||
#]
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.2.0"
|
||||
protoc-bin-vendored = "3.0.0"
|
||||
@@ -0,0 +1,14 @@
|
||||
fn main() {
|
||||
std::fs::create_dir_all("src/proto").unwrap();
|
||||
protobuf_codegen::Codegen::new()
|
||||
.pure()
|
||||
.out_dir("src/proto")
|
||||
.inputs(&["proto/message.proto"])
|
||||
.include("proto")
|
||||
// .customize(
|
||||
// protobuf_codegen::Customize::default()
|
||||
// .tokio_bytes(true)
|
||||
// )
|
||||
.run()
|
||||
.expect("Codegen failed.");
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "packet"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.37"
|
||||
@@ -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>;
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod packet;
|
||||
pub mod protocol;
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod udp;
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
syntax = "proto3";
|
||||
message RegistrationRequest{
|
||||
string token = 1;
|
||||
string mac_address = 2;
|
||||
}
|
||||
|
||||
message RegistrationResponse{
|
||||
fixed32 virtual_ip = 1;
|
||||
fixed32 virtual_gateway = 2;
|
||||
fixed32 virtual_netmask = 3;
|
||||
uint32 epoch = 4;
|
||||
repeated fixed32 virtual_ip_list = 5;
|
||||
fixed32 public_ip = 6;
|
||||
uint32 public_port = 7;
|
||||
}
|
||||
|
||||
message DeviceList{
|
||||
uint32 epoch = 1;
|
||||
repeated fixed32 virtual_ip_list = 2;
|
||||
}
|
||||
|
||||
message Punch{
|
||||
fixed32 virtual_ip = 1;
|
||||
repeated fixed32 public_ip_list = 2;
|
||||
uint32 public_port = 3;
|
||||
uint32 public_port_range = 4;
|
||||
NatType nat_type = 5;
|
||||
bool reply = 6;
|
||||
Step step = 7;
|
||||
}
|
||||
enum NatType{
|
||||
Symmetric = 0;
|
||||
Cone = 1;
|
||||
}
|
||||
enum Step{
|
||||
Step1 = 0;
|
||||
Step2 = 1;
|
||||
Step3 = 2;
|
||||
Step4 = 3;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/// 使用 https://github.com/spa5k/is_sudo/blob/main/src/window.rs
|
||||
use std::io::Error;
|
||||
use std::ptr;
|
||||
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
|
||||
use winapi::um::securitybaseapi::GetTokenInformation;
|
||||
use winapi::um::winnt::{HANDLE, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation};
|
||||
|
||||
// Use std::io::Error::last_os_error for errors.
|
||||
// NOTE: For this example I'm simple passing on the OS error.
|
||||
// However, customising the error could provide more context
|
||||
|
||||
/// Returns true if the current process has admin rights, otherwise false.
|
||||
pub fn is_app_elevated() -> bool {
|
||||
_is_app_elevated().unwrap_or(false)
|
||||
}
|
||||
|
||||
/// On success returns a bool indicating if the current process has admin rights.
|
||||
/// Otherwise returns an OS error.
|
||||
///
|
||||
/// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway.
|
||||
/// Therefore the public function above simply eats the error and returns a bool.
|
||||
fn _is_app_elevated() -> Result<bool, Error> {
|
||||
let token = QueryAccessToken::from_current_process()?;
|
||||
token.is_elevated()
|
||||
}
|
||||
|
||||
/// A safe wrapper around querying Windows access tokens.
|
||||
pub struct QueryAccessToken(HANDLE);
|
||||
|
||||
impl QueryAccessToken {
|
||||
pub fn from_current_process() -> Result<Self, Error> {
|
||||
unsafe {
|
||||
let mut handle: HANDLE = ptr::null_mut();
|
||||
let result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle);
|
||||
|
||||
if result != 0 {
|
||||
Ok(Self(handle))
|
||||
} else {
|
||||
Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// On success returns a bool indicating if the access token has elevated privilidges.
|
||||
/// Otherwise returns an OS error.
|
||||
pub fn is_elevated(&self) -> Result<bool, Error> {
|
||||
unsafe {
|
||||
let mut elevation = TOKEN_ELEVATION::default();
|
||||
let size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||
let mut ret_size = size;
|
||||
// The weird looking repetition of `as *mut _` is casting the reference to a c_void pointer.
|
||||
if GetTokenInformation(
|
||||
self.0,
|
||||
TokenElevation,
|
||||
&mut elevation as *mut _ as *mut _,
|
||||
size,
|
||||
&mut ret_size,
|
||||
) != 0
|
||||
{
|
||||
Ok(elevation.TokenIsElevated != 0)
|
||||
} else {
|
||||
Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for QueryAccessToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { CloseHandle(self.0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use std::io;
|
||||
|
||||
use crossbeam::channel::RecvError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("packet error")]
|
||||
PacketError(#[from] packet::error::Error),
|
||||
#[error("Io error")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Channel error")]
|
||||
Channel(#[from] RecvError),
|
||||
#[error("Protobuf error")]
|
||||
Protobuf(#[from] protobuf::Error),
|
||||
#[error("Invalid packet")]
|
||||
InvalidPacket,
|
||||
#[error("Not support")]
|
||||
NotSupport,
|
||||
#[error("Stop")]
|
||||
Stop(String),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -0,0 +1,45 @@
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::handle::DIRECT_ROUTE_TABLE;
|
||||
use crate::protocol::control_packet::PingPacket;
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, Version};
|
||||
use crate::DEVICE_LIST;
|
||||
|
||||
pub fn handle_loop(udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
|
||||
const INTERVAL: u64 = 3000;
|
||||
const MAX_INTERVAL: i64 = 3000 * 5;
|
||||
let mut buf = [0u8; (4 + 8 + 4)];
|
||||
let mut net_packet = NetPacket::new(&mut buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Control);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
||||
net_packet.set_ttl(255);
|
||||
loop {
|
||||
let current_time = Local::now().timestamp();
|
||||
{
|
||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||
ping.set_time(current_time);
|
||||
let epoch = { DEVICE_LIST.lock().0 };
|
||||
ping.set_epoch(epoch);
|
||||
}
|
||||
udp.send_to(net_packet.buffer(), server_addr)?;
|
||||
for x in DIRECT_ROUTE_TABLE.iter() {
|
||||
let virtual_ip = x.key().clone();
|
||||
let route = x.value().clone();
|
||||
drop(x);
|
||||
if current_time - route.recv_time <= MAX_INTERVAL {
|
||||
udp.send_to(net_packet.buffer(), route.address)?;
|
||||
} else {
|
||||
DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| {
|
||||
current_time - route.recv_time > MAX_INTERVAL
|
||||
});
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(INTERVAL));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
use std::net::{ Ipv4Addr, SocketAddr};
|
||||
use std::sync::atomic::AtomicI64;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
use dashmap::DashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use moka::sync::Cache;
|
||||
use parking_lot::{const_mutex, Mutex};
|
||||
|
||||
use crate::proto::message::NatType;
|
||||
|
||||
pub mod heartbeat_handler;
|
||||
pub mod punch_handler;
|
||||
pub mod registration_handler;
|
||||
pub mod tun_handler;
|
||||
pub mod udp_recv_handler;
|
||||
lazy_static! {
|
||||
/// 0. 机器纪元,每一次上线或者下线都会增1,由服务端维护,用于感知网络中机器变化
|
||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||
/// 1. 网络中的虚拟ip列表
|
||||
pub static ref DEVICE_LIST:Mutex<(u32,Vec<Ipv4Addr>)> = const_mutex((0,Vec::new()));
|
||||
/// 服务器延迟
|
||||
pub static ref SERVER_RT:AtomicI64 = AtomicI64::new(-1);
|
||||
/// id
|
||||
pub static ref ID:AtomicI64 = AtomicI64::new(0);
|
||||
/// 直连路由表
|
||||
pub static ref DIRECT_ROUTE_TABLE:DashMap<Ipv4Addr,Route> = DashMap::new();
|
||||
/// 地址映射
|
||||
pub static ref ADDR_TABLE:Cache<SocketAddr,Ipv4Addr> = Cache::builder()
|
||||
.time_to_idle(Duration::from_secs(60*5)).build();
|
||||
/// 当前设备的nat信息
|
||||
pub static ref NAT_INFO:Mutex<Option<NatInfo>> = const_mutex(None);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NatInfo {
|
||||
public_ips: Vec<u32>,
|
||||
public_port: u16,
|
||||
public_port_range: u16,
|
||||
nat_type: NatType,
|
||||
}
|
||||
|
||||
impl NatInfo {
|
||||
pub fn new(public_ips: Vec<u32>,
|
||||
public_port: u16,
|
||||
public_port_range: u16,
|
||||
nat_type: NatType, ) -> Self {
|
||||
Self {
|
||||
public_ips,
|
||||
public_port,
|
||||
public_port_range,
|
||||
nat_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化nat信息
|
||||
pub fn init_nat_info(public_ip: u32, public_port: u16) {
|
||||
match crate::nat::check::public_ip_list() {
|
||||
Ok((nat_type, ips, port_range)) => {
|
||||
let mut public_ips = Vec::new();
|
||||
public_ips.push(public_ip);
|
||||
for ip in ips {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
if ip != public_ip {
|
||||
public_ips.push(ip);
|
||||
}
|
||||
}
|
||||
let nat_info = NatInfo::new(public_ips,
|
||||
public_port,
|
||||
port_range, nat_type);
|
||||
// println!("nat信息:{:?}",nat_info);
|
||||
let mut nat_info_lock = NAT_INFO.lock();
|
||||
nat_info_lock.replace(nat_info);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("获取nat数据失败,将无法进行udp打洞:{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CurrentDeviceInfo {
|
||||
virtual_ip: Ipv4Addr,
|
||||
virtual_gateway: Ipv4Addr,
|
||||
virtual_netmask: Ipv4Addr,
|
||||
//网络地址
|
||||
virtual_network: Ipv4Addr,
|
||||
//直接广播地址
|
||||
broadcast_address: Ipv4Addr,
|
||||
//链接的服务器地址
|
||||
connect_server: SocketAddr,
|
||||
}
|
||||
|
||||
impl CurrentDeviceInfo {
|
||||
pub fn new(virtual_ip: Ipv4Addr, virtual_gateway: Ipv4Addr, virtual_netmask: Ipv4Addr, connect_server: SocketAddr) -> Self {
|
||||
let broadcast_address = (!u32::from_be_bytes(virtual_netmask.octets()))
|
||||
| u32::from_be_bytes(virtual_gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
let virtual_network = u32::from_be_bytes(virtual_netmask.octets())
|
||||
& u32::from_be_bytes(virtual_gateway.octets());
|
||||
let virtual_network = Ipv4Addr::from(virtual_network);
|
||||
Self {
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
virtual_network,
|
||||
broadcast_address,
|
||||
connect_server,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct Route {
|
||||
address: SocketAddr,
|
||||
//用心跳探测延迟,收包时更新
|
||||
delay: i64,
|
||||
//收包时更新,如果太久没有收到消息则剔除
|
||||
recv_time: i64,
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn new(address: SocketAddr) -> Self {
|
||||
Self {
|
||||
address,
|
||||
delay: -1,
|
||||
recv_time: Local::now().timestamp(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam::channel::{Receiver, RecvTimeoutError, Sender, SendError, TrySendError};
|
||||
use dashmap::DashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::{CurrentDeviceInfo, DEVICE_LIST, NAT_INFO, NatInfo};
|
||||
use crate::error::*;
|
||||
use crate::handle::DIRECT_ROUTE_TABLE;
|
||||
use crate::proto::message::{NatType, Punch, Step};
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, turn_packet, Version};
|
||||
use crate::protocol::control_packet::PunchRequestPacket;
|
||||
use crate::protocol::turn_packet::TurnPacket;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref STEP_MAP:DashMap<Ipv4Addr,Step> = DashMap::new();
|
||||
}
|
||||
/// 每一种类型一个通道,减少相互干扰
|
||||
pub fn bounded() -> (PunchSender, ConeReceiver, ReqSymmetricReceiver, ResSymmetricReceiver) {
|
||||
let (cone_sender, cone_receiver) = crossbeam::channel::bounded(3);
|
||||
let (req_symmetric_sender, req_symmetric_receiver) = crossbeam::channel::bounded(1);
|
||||
let (res_symmetric_sender, res_symmetric_receiver) = crossbeam::channel::bounded(1);
|
||||
(PunchSender::new(cone_sender, req_symmetric_sender, res_symmetric_sender),
|
||||
ConeReceiver(cone_receiver), ReqSymmetricReceiver(req_symmetric_receiver),
|
||||
ResSymmetricReceiver(res_symmetric_receiver))
|
||||
}
|
||||
|
||||
pub struct ConeReceiver(Receiver<Punch>);
|
||||
|
||||
pub struct ReqSymmetricReceiver(Receiver<Punch>);
|
||||
|
||||
pub struct ResSymmetricReceiver(Receiver<Punch>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PunchSender {
|
||||
cone_sender: Sender<Punch>,
|
||||
req_symmetric_sender: Sender<Punch>,
|
||||
res_symmetric_sender: Sender<Punch>,
|
||||
}
|
||||
|
||||
impl PunchSender {
|
||||
pub fn new(cone_sender: Sender<Punch>,
|
||||
req_symmetric_sender: Sender<Punch>,
|
||||
res_symmetric_sender: Sender<Punch>, ) -> Self {
|
||||
Self {
|
||||
cone_sender,
|
||||
req_symmetric_sender,
|
||||
res_symmetric_sender,
|
||||
}
|
||||
}
|
||||
pub fn send(&self, punch: Punch) -> std::result::Result<(), SendError<Punch>> {
|
||||
match punch.nat_type.enum_value_or_default() {
|
||||
NatType::Symmetric => {
|
||||
if punch.reply {
|
||||
// 为true表示回应,也就是主动发起的打洞操作
|
||||
self.res_symmetric_sender.send(punch)
|
||||
} else {
|
||||
self.req_symmetric_sender.send(punch)
|
||||
}
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.cone_sender.send(punch)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn try_send(&self, punch: Punch) -> std::result::Result<(), TrySendError<Punch>> {
|
||||
match punch.nat_type.enum_value_or_default() {
|
||||
NatType::Symmetric => {
|
||||
if punch.reply {
|
||||
// 为true表示回应,也就是主动发起的打洞操作
|
||||
self.res_symmetric_sender.try_send(punch)
|
||||
} else {
|
||||
self.req_symmetric_sender.try_send(punch)
|
||||
}
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.cone_sender.try_send(punch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(udp: &UdpSocket, punch_list: Vec<Punch>, buf: &[u8]) -> Result<()> {
|
||||
let mut counter = 0u64;
|
||||
for punch in punch_list {
|
||||
let dest = Ipv4Addr::from(punch.virtual_ip);
|
||||
if DIRECT_ROUTE_TABLE.contains_key(&dest) {
|
||||
continue;
|
||||
}
|
||||
// println!("punch {:?}", punch);
|
||||
match punch.nat_type.enum_value_or_default() {
|
||||
NatType::Symmetric => {
|
||||
match punch.step.enum_value_or_default() {
|
||||
Step::Step1 | Step::Step2 | Step::Step3 => {
|
||||
//预测范围发送
|
||||
for pub_ip in punch.public_ip_list {
|
||||
let pub_ip = Ipv4Addr::from(pub_ip);
|
||||
for range in 0..punch.public_port_range + 1 {
|
||||
let right_port = ((punch.public_port + range) & 0xFFFF) as u16;
|
||||
let left_port = ((0xFFFF + punch.public_port - range) & 0xFFFF) as u16;
|
||||
if right_port != 0 {
|
||||
// println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)));
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
if left_port != 0 && range != 0 {
|
||||
// println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)));
|
||||
if left_port == right_port {
|
||||
break;
|
||||
}
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(pub_ip, left_port)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Step::Step4 => {
|
||||
//全范围发送
|
||||
for pub_ip in punch.public_ip_list {
|
||||
let pub_ip = Ipv4Addr::from(pub_ip);
|
||||
for port in 1..0xFFFF {
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(pub_ip, port)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NatType::Cone => {
|
||||
for pub_ip in punch.public_ip_list {
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::from(pub_ip),
|
||||
punch.public_port as u16,
|
||||
)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 给对称nat发送打洞数据包
|
||||
pub fn req_symmetric_handle_loop(
|
||||
receiver: ReqSymmetricReceiver,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let receiver = receiver.0;
|
||||
handle_loop(receiver, udp, cur_info)
|
||||
}
|
||||
|
||||
/// 给对称nat发送打洞数据包,处理主动发起的打洞操作
|
||||
pub fn res_symmetric_handle_loop(
|
||||
receiver: ResSymmetricReceiver,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let receiver = receiver.0;
|
||||
let mut buf = [0u8; 12];
|
||||
let mut packet = NetPacket::new(&mut buf)?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_ttl(255);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
{
|
||||
let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?;
|
||||
punch_packet.set_source(cur_info.virtual_ip);
|
||||
}
|
||||
loop {
|
||||
match receiver.recv_timeout(Duration::from_secs(30)) {
|
||||
Ok(punch) => {
|
||||
let mut list = Vec::new();
|
||||
list.push(punch);
|
||||
loop {
|
||||
match receiver.try_recv() {
|
||||
Ok(punch) => {
|
||||
list.push(punch);
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for punch in &list {
|
||||
let dest = Ipv4Addr::from(punch.virtual_ip);
|
||||
match punch.step.enum_value_or_default() {
|
||||
Step::Step1 => {
|
||||
STEP_MAP.insert(dest, Step::Step2);
|
||||
}
|
||||
Step::Step2 => {
|
||||
STEP_MAP.insert(dest, Step::Step3);
|
||||
}
|
||||
Step::Step3 => {
|
||||
STEP_MAP.insert(dest, Step::Step4);
|
||||
}
|
||||
Step::Step4 => {
|
||||
STEP_MAP.insert(dest, Step::Step1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(e) = handle(&udp, list, packet.buffer()) {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
Err(RecvTimeoutError::Timeout) => {
|
||||
punch_request_handle(&udp, &cur_info)?;
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(Error::Stop("打洞线程通道关闭".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 给锥形nat发送打洞数据包
|
||||
pub fn cone_handle_loop(
|
||||
receiver: ConeReceiver,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let receiver = receiver.0;
|
||||
handle_loop(receiver, udp, cur_info)
|
||||
}
|
||||
|
||||
pub fn handle_loop(
|
||||
receiver: Receiver<Punch>,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut buf = [0u8; 12];
|
||||
let mut packet = NetPacket::new(&mut buf)?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_ttl(255);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
{
|
||||
let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?;
|
||||
punch_packet.set_source(cur_info.virtual_ip);
|
||||
}
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(punch) => {
|
||||
let mut list = Vec::new();
|
||||
list.push(punch);
|
||||
loop {
|
||||
match receiver.try_recv() {
|
||||
Ok(punch) => {
|
||||
list.push(punch);
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(e) = handle(&udp, list, packet.buffer()) {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(Error::Stop("打洞线程通道关闭".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn select_sleep(counter: &mut u64) {
|
||||
*counter += 1;
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
// if *counter > 1 {
|
||||
// if cone_nat {
|
||||
// thread::sleep(Duration::from_millis(2));
|
||||
// } else {
|
||||
// if (*counter) & 10 == 10 {
|
||||
// thread::sleep(Duration::from_millis(1));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
fn punch_request_handle(udp: &UdpSocket, cur_info: &CurrentDeviceInfo) -> Result<()> {
|
||||
let nat_info_lock = NAT_INFO.lock();
|
||||
let nat_info = nat_info_lock.clone();
|
||||
drop(nat_info_lock);
|
||||
if let Some(nat_info) = nat_info {
|
||||
if let Err(e) = send_punch(&udp,
|
||||
&cur_info,
|
||||
nat_info) {
|
||||
println!("发送打洞数据失败 :{:?}", e);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Stop("未初始化nat信息".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn send_punch(udp: &UdpSocket, cur_info: &CurrentDeviceInfo, nat_info: NatInfo) -> Result<()> {
|
||||
let lock = DEVICE_LIST.lock();
|
||||
let list = lock.1.clone();
|
||||
drop(lock);
|
||||
for ip in list {
|
||||
//只向ip比自己大的发起打洞,避免双方同时发起打洞浪费流量
|
||||
if ip > cur_info.virtual_ip && !DIRECT_ROUTE_TABLE.contains_key(&ip) {
|
||||
let step = if let Some(step) = STEP_MAP.get(&ip) {
|
||||
*step
|
||||
} else {
|
||||
Step::Step1
|
||||
};
|
||||
let bytes = punch_packet(cur_info.virtual_ip,
|
||||
nat_info.clone(), ip, step)?;
|
||||
udp.send_to(&bytes, cur_info.connect_server)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn punch_packet(virtual_ip: Ipv4Addr, nat_info: NatInfo, dest: Ipv4Addr, step: Step) -> Result<Vec<u8>> {
|
||||
let mut punch_reply = Punch::new();
|
||||
punch_reply.reply = false;
|
||||
punch_reply.virtual_ip = u32::from_be_bytes(virtual_ip.octets());
|
||||
punch_reply.step = protobuf::EnumOrUnknown::new(step);
|
||||
punch_reply.public_ip_list = nat_info.public_ips;
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(nat_info.nat_type);
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
|
||||
net_packet.set_ttl(255);
|
||||
let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
turn_packet.set_source(virtual_ip);
|
||||
turn_packet.set_destination(dest);
|
||||
turn_packet.set_payload(&bytes);
|
||||
Ok(net_packet.into_buffer())
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
use parking_lot::RwLock;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||
use crate::protocol::{error_packet, NetPacket, Protocol, service_packet, Version};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref REQUEST:RwLock<Option<(String,String)>> = parking_lot::const_rwlock(None);
|
||||
static ref REGISTRATION_TIME:AtomicI64=AtomicI64::new(0);
|
||||
}
|
||||
|
||||
///向中继服务器注册,token标识一个虚拟网关,mac_address防止多次注册时得到的ip不一致
|
||||
pub fn registration(
|
||||
udp: &UdpSocket,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
mac_address: String,
|
||||
) -> Result<RegistrationResponse> {
|
||||
// todo 和服务器通信加密
|
||||
let request_packet = registration_request_packet(token.clone(), mac_address.clone())?;
|
||||
let buf = request_packet.buffer();
|
||||
let mut counter = 0;
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
|
||||
loop {
|
||||
counter += 1;
|
||||
if counter & 10 == 10 {
|
||||
return Err(Error::Stop("注册请求超时".to_string()));
|
||||
}
|
||||
udp.send_to(buf, server_address)?;
|
||||
let (len, addr) = match udp.recv_from(&mut recv_buf) {
|
||||
Ok(ok) => ok,
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut {
|
||||
continue;
|
||||
}
|
||||
return Err(Error::Io(e));
|
||||
}
|
||||
};
|
||||
if server_address != addr {
|
||||
continue;
|
||||
}
|
||||
let net_packet = NetPacket::new(&recv_buf[..len])?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response =
|
||||
RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
let _ = REQUEST.write().replace((token, mac_address));
|
||||
udp.set_read_timeout(None)?;
|
||||
return Ok(response);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match error_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
error_packet::Protocol::TokenError => {
|
||||
return Err(Error::Stop("token错误".to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn registration_request_packet(token: String, mac_address: String) -> Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = RegistrationRequest::new();
|
||||
request.token = token;
|
||||
request.mac_address = mac_address;
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 4 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
|
||||
net_packet.set_ttl(255);
|
||||
net_packet.set_payload(&bytes);
|
||||
Ok(net_packet)
|
||||
}
|
||||
|
||||
pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<()> {
|
||||
let last = REGISTRATION_TIME.load(Ordering::Relaxed);
|
||||
let new = Local::now().timestamp();
|
||||
if new - last < 2000
|
||||
|| REGISTRATION_TIME
|
||||
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
//短时间不重复注册
|
||||
return Ok(());
|
||||
}
|
||||
let lock = REQUEST.read();
|
||||
let option = lock.clone();
|
||||
drop(lock);
|
||||
if let Some((token, mac_address)) = option {
|
||||
let request_packet = registration_request_packet(token, mac_address)?;
|
||||
udp.send_to(request_packet.buffer(), server_address)?;
|
||||
REGISTRATION_TIME.store(Local::now().timestamp(), Ordering::Relaxed);
|
||||
return Ok(());
|
||||
}
|
||||
return Err(Error::Stop("注册信息不存在".to_string()));
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/// 接收tun数据,并且转发到udp上
|
||||
use std::net::{IpAddr, Ipv4Addr, UdpSocket};
|
||||
|
||||
use chrono::Local;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::icmp::Kind;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::handle::{CurrentDeviceInfo, DIRECT_ROUTE_TABLE};
|
||||
use crate::protocol::{NetPacket, Protocol, Version};
|
||||
use crate::protocol::turn_packet::TurnPacket;
|
||||
use crate::tun_device::TunReader;
|
||||
|
||||
/// 是否在一个网段
|
||||
fn check_dest(dest: Ipv4Addr, cur_info: &CurrentDeviceInfo) -> bool {
|
||||
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(cur_info.virtual_netmask.octets())
|
||||
== u32::from_be_bytes(cur_info.virtual_network.octets())
|
||||
}
|
||||
|
||||
fn icmp(udp: &UdpSocket, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
let src = ipv4_packet.source_ip();
|
||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||
ipv4_packet.set_destination_ip(src);
|
||||
ipv4_packet.update_checksum();
|
||||
let mut addr = udp.local_addr()?;
|
||||
addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
udp.send_to(ipv4_packet.buffer, addr)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn handle(
|
||||
udp: &UdpSocket,
|
||||
data: &mut [u8],
|
||||
cur_info: &CurrentDeviceInfo,
|
||||
net_packet: &mut NetPacket<Vec<u8>>,
|
||||
) -> Result<()> {
|
||||
let data_len = data.len();
|
||||
let ipv4_packet = match IpV4Packet::new(data) {
|
||||
Ok(ipv4_packet) => ipv4_packet,
|
||||
Err(packet::error::Error::Unimplemented) => {
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let dest_ip = ipv4_packet.destination_ip();
|
||||
// if dest_ip == cur_info.broadcast_address {
|
||||
// // 启动服务后会收到对137端口的广播
|
||||
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
|
||||
// return Ok(());
|
||||
// }
|
||||
if src_ip != cur_info.virtual_ip || !check_dest(dest_ip, &cur_info) {
|
||||
return Ok(());
|
||||
}
|
||||
if src_ip == dest_ip {
|
||||
return icmp(&udp, ipv4_packet);
|
||||
}
|
||||
let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
ipv4_turn_packet.set_source(src_ip);
|
||||
ipv4_turn_packet.set_destination(dest_ip);
|
||||
ipv4_turn_packet.set_payload(ipv4_packet.buffer);
|
||||
//优先发到直连到地址
|
||||
if let Some(route) = DIRECT_ROUTE_TABLE.get(&dest_ip) {
|
||||
let current_time = Local::now().timestamp();
|
||||
if current_time - route.recv_time < 3_000 {
|
||||
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], cur_info.connect_server)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn handle_loop(
|
||||
udp: UdpSocket,
|
||||
tun_reader: TunReader,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||
net_packet.set_ttl(255);
|
||||
loop {
|
||||
let mut data = tun_reader.next()?;
|
||||
match handle(&udp, data.bytes_mut(), &cur_info, &mut net_packet) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub fn handle_loop(
|
||||
udp: UdpSocket,
|
||||
mut tun_reader: TunReader,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(0);
|
||||
net_packet.set_ttl(255);
|
||||
let mut buf = [0u8; 1500];
|
||||
loop {
|
||||
let data = tun_reader.read(&mut buf)?;
|
||||
match handle(&udp, data, &cur_info, &mut net_packet) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use chrono::Local;
|
||||
use crossbeam::channel::{Receiver, Sender, TrySendError};
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::CurrentDeviceInfo;
|
||||
use crate::error::*;
|
||||
use crate::handle::{ADDR_TABLE, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, Route, SERVER_RT};
|
||||
use crate::handle::punch_handler::PunchSender;
|
||||
use crate::handle::registration_handler::fast_registration;
|
||||
use crate::proto::message::{DeviceList, Punch, RegistrationResponse};
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, service_packet, turn_packet, Version};
|
||||
use crate::protocol::control_packet::{ControlPacket, PunchResponsePacket};
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::protocol::turn_packet::TurnPacket;
|
||||
use crate::tun_device::TunWriter;
|
||||
|
||||
pub fn recv_loop(
|
||||
udp: UdpSocket,
|
||||
server_addr: SocketAddr,
|
||||
other_sender: Sender<(SocketAddr, Vec<u8>)>,
|
||||
mut tun_writer: TunWriter,
|
||||
current_device: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut buf = [0u8; 65536];
|
||||
let mut local_addr = udp.local_addr()?;
|
||||
local_addr.set_ip(std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
loop {
|
||||
match udp.recv_from(&mut buf) {
|
||||
Ok((len, addr)) => {
|
||||
if addr == local_addr {
|
||||
//本地的包直接再发到网卡,这个主要用于处理当前虚拟ip的icmp ping
|
||||
if let Ok(ip) = IpV4Packet::new(&buf[..len]) {
|
||||
if ip.destination_ip() == current_device.virtual_ip {
|
||||
let _ = tun_writer.write(&buf[..len]);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
match recv_handle(
|
||||
&udp,
|
||||
addr,
|
||||
&mut buf[..len],
|
||||
&server_addr,
|
||||
&other_sender,
|
||||
&mut tun_writer,
|
||||
¤t_device,
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(Error::Stop(str)) => {
|
||||
return Err(Error::Stop(str));
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn recv_handle(
|
||||
udp: &UdpSocket,
|
||||
recv_addr: SocketAddr,
|
||||
buf: &mut [u8],
|
||||
_server_addr: &SocketAddr,
|
||||
other_sender: &Sender<(SocketAddr, Vec<u8>)>,
|
||||
tun_writer: &mut TunWriter,
|
||||
current_device: &CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::Ipv4Turn => {
|
||||
let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
let source = ipv4_turn_packet.source();
|
||||
let destination = ipv4_turn_packet.destination();
|
||||
let mut ipv4 = IpV4Packet::new(ipv4_turn_packet.payload_mut())?;
|
||||
if ipv4.source_ip() == source
|
||||
&& ipv4.destination_ip() == destination
|
||||
&& current_device.virtual_ip == ipv4.destination_ip()
|
||||
{
|
||||
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
||||
if icmp_packet.kind() == Kind::EchoRequest {
|
||||
//开启ping
|
||||
icmp_packet.set_kind(Kind::EchoReply);
|
||||
icmp_packet.update_checksum();
|
||||
ipv4.set_source_ip(destination);
|
||||
ipv4.set_destination_ip(source);
|
||||
ipv4.update_checksum();
|
||||
ipv4_turn_packet.set_source(destination);
|
||||
ipv4_turn_packet.set_destination(source);
|
||||
udp.send_to(net_packet.buffer(), recv_addr)?;
|
||||
} else {
|
||||
tun_writer.write(ipv4_turn_packet.payload())?;
|
||||
}
|
||||
} else {
|
||||
tun_writer.write(ipv4_turn_packet.payload())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::UnKnow(_) => {}
|
||||
_ => {
|
||||
//发送到子线程处理
|
||||
let v = net_packet.buffer().to_vec();
|
||||
match other_sender.try_send((recv_addr, v)) {
|
||||
Ok(_) => {}
|
||||
Err(TrySendError::Disconnected(_)) => {
|
||||
return Err(Error::Stop("处理线程停止".to_string()));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("子线程处理 :{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn other_loop(
|
||||
udp: UdpSocket,
|
||||
receiver: Receiver<(SocketAddr, Vec<u8>)>,
|
||||
current_device: CurrentDeviceInfo,
|
||||
sender: PunchSender,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let (peer_addr, buf) = receiver.recv()?;
|
||||
match other_handle(&udp, buf, peer_addr, ¤t_device, &sender) {
|
||||
Ok(_) => {}
|
||||
Err(Error::Stop(str)) => {
|
||||
return Err(Error::Stop(str));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn other_handle(
|
||||
udp: &UdpSocket,
|
||||
buf: Vec<u8>,
|
||||
peer_addr: SocketAddr,
|
||||
current_device: &CurrentDeviceInfo,
|
||||
sender: &PunchSender,
|
||||
) -> Result<()> {
|
||||
let server_addr = current_device.connect_server;
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
if peer_addr != current_device.connect_server {
|
||||
return Ok(());
|
||||
}
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationRequest => {}
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
crate::handle::init_nat_info(response.public_ip, response.public_port as u16);
|
||||
//todo 重连之后ip可能会发生改变(目前2分钟内未重连则会释放ip),需要更新本地ip(或者保证重连ip不变)
|
||||
}
|
||||
service_packet::Protocol::UpdateDeviceList => {
|
||||
let device_list = DeviceList::parse_from_bytes(net_packet.payload())?;
|
||||
let ip_list: Vec<Ipv4Addr> = device_list
|
||||
.virtual_ip_list
|
||||
.iter()
|
||||
.map(|ip| Ipv4Addr::from(*ip))
|
||||
.collect();
|
||||
let mut dev = DEVICE_LIST.lock();
|
||||
if dev.0 < device_list.epoch || device_list.epoch - dev.0 > u32::MAX >> 2 {
|
||||
dev.0 = device_list.epoch;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
}
|
||||
service_packet::Protocol::UnKnow(_) => {}
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
InErrorPacket::TokenError => {
|
||||
if server_addr == peer_addr {
|
||||
//停止整个应用
|
||||
return Err(Error::Stop("token无效".to_string()));
|
||||
}
|
||||
}
|
||||
InErrorPacket::Disconnect => {
|
||||
if server_addr == peer_addr {
|
||||
fast_registration(&udp, server_addr)?;
|
||||
}
|
||||
}
|
||||
InErrorPacket::OtherError(e) => {
|
||||
println!("{:?}", e.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Control => {
|
||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
ControlPacket::PingPacket(_) => {
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||
udp.send_to(&net_packet.buffer()[..12], peer_addr)?;
|
||||
}
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
let current_time = Local::now().timestamp();
|
||||
let rt = current_time - pong_packet.time();
|
||||
if rt >= 0 {
|
||||
if peer_addr == server_addr {
|
||||
SERVER_RT.store(rt, Ordering::Relaxed)
|
||||
} else {
|
||||
//其他设备
|
||||
if let Some(virtual_ip) = ADDR_TABLE.get(&peer_addr) {
|
||||
if let Some(mut info) = DIRECT_ROUTE_TABLE.get_mut(&virtual_ip) {
|
||||
info.delay = rt;
|
||||
info.recv_time = current_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlPacket::PunchRequest(punch_request) => {
|
||||
// println!("打洞请求:{:?}", punch_request);
|
||||
let src = punch_request.source();
|
||||
drop(punch_request);
|
||||
//回应
|
||||
let mut punch_response = PunchResponsePacket::new(net_packet.payload_mut())?;
|
||||
punch_response.set_source(current_device.virtual_ip);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
|
||||
udp.send_to(net_packet.buffer(), peer_addr)?;
|
||||
let route = Route::new(peer_addr);
|
||||
DIRECT_ROUTE_TABLE.insert(src, route);
|
||||
ADDR_TABLE.insert(peer_addr, src);
|
||||
}
|
||||
ControlPacket::PunchResponse(punch_response) => {
|
||||
// println!("打洞响应:{:?}", punch_response);
|
||||
let route = Route::new(peer_addr);
|
||||
DIRECT_ROUTE_TABLE.insert(punch_response.source(), route);
|
||||
ADDR_TABLE.insert(peer_addr, punch_response.source());
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Ipv4Turn => {}
|
||||
Protocol::OtherTurn => {
|
||||
let turn_packet = TurnPacket::new(net_packet.payload())?;
|
||||
// println!("{:?}",turn_packet);
|
||||
let src = turn_packet.source();
|
||||
let dest = turn_packet.destination();
|
||||
if dest == current_device.virtual_ip {
|
||||
match turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
turn_packet::Protocol::Punch => {
|
||||
let punch = Punch::parse_from_bytes(turn_packet.payload())?;
|
||||
if punch.virtual_ip.to_be_bytes() == src.octets() {
|
||||
if !punch.reply {
|
||||
let mut punch_reply = Punch::new();
|
||||
punch_reply.reply = true;
|
||||
punch_reply.virtual_ip = u32::from_be_bytes(current_device.virtual_ip.octets());
|
||||
punch_reply.step = punch.step;
|
||||
if let Err(_) = sender.try_send(punch) {
|
||||
return Ok(());
|
||||
}
|
||||
let nat_info = NAT_INFO.lock();
|
||||
if let Some(info) = nat_info.as_ref() {
|
||||
punch_reply.public_ip_list = info.public_ips.clone();
|
||||
punch_reply.public_port = info.public_port as u32;
|
||||
punch_reply.public_port_range = info.public_port_range as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(info.nat_type);
|
||||
drop(nat_info);
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
|
||||
net_packet.set_ttl(255);
|
||||
let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
turn_packet.set_source(current_device.virtual_ip);
|
||||
turn_packet.set_destination(src);
|
||||
turn_packet.set_payload(&bytes);
|
||||
udp.send_to(net_packet.buffer(), peer_addr)?;
|
||||
}
|
||||
} else {
|
||||
let _ = sender.try_send(punch);
|
||||
}
|
||||
}
|
||||
}
|
||||
turn_packet::Protocol::UnKnow(_) => {}
|
||||
}
|
||||
} else {
|
||||
panic!("ip")
|
||||
}
|
||||
}
|
||||
Protocol::UnKnow(p) => {
|
||||
println!("未知协议:{}", p)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
use std::{io, thread};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
|
||||
use clap::Parser;
|
||||
use console::style;
|
||||
use crossbeam::sync::Parker;
|
||||
|
||||
use crate::handle::{CurrentDeviceInfo, DEVICE_LIST, NAT_INFO, NatInfo};
|
||||
use crate::handle::registration_handler::registration;
|
||||
use crate::tun_device::create_tun;
|
||||
|
||||
pub mod tun_device;
|
||||
pub mod nat;
|
||||
pub mod error;
|
||||
pub mod handle;
|
||||
pub mod proto;
|
||||
pub mod protocol;
|
||||
#[cfg(windows)]
|
||||
pub mod admin_check;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author = "Lu Beilin", version, about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信")]
|
||||
struct Args {
|
||||
/// 32位字符
|
||||
/// 相同token的设备之间才能通信。
|
||||
/// 建议使用uuid保证唯一性。
|
||||
/// 32-bit characters.
|
||||
/// Only devices with the same token can communicate with each other.
|
||||
/// It is recommended to use uuid to ensure uniqueness
|
||||
#[arg(short, long)]
|
||||
token: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
#[cfg(windows)]
|
||||
if !admin_check::is_app_elevated() {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
println!("{}", style("正在启动管理员权限执行...").red());
|
||||
if let Some(absolute_path) = std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|p| p.to_str().map(|p| p.to_string()))
|
||||
{
|
||||
let _ = runas::Command::new(&absolute_path).args(&args[1..]).status()
|
||||
.expect("failed to execute");
|
||||
} else {
|
||||
panic!("failed to execute")
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(any(unix))]
|
||||
if sudo::RunningAs::Root != sudo::check() {
|
||||
println!("{}", style("需要使用root权限执行...").red());
|
||||
sudo::escalate_if_needed().unwrap();
|
||||
}
|
||||
|
||||
println!("{}", style("启动服务...").green());
|
||||
|
||||
let token = args.token;
|
||||
// let d = Local::now().timestamp().to_string();
|
||||
let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string();
|
||||
let server_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(43, 139, 56, 10)), 29876);
|
||||
// let server_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), 29876);
|
||||
let mut port = 101 as u16;
|
||||
let udp = loop {
|
||||
match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(0), port))) {
|
||||
Ok(udp) => {
|
||||
break udp;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::AddrInUse {
|
||||
port += 1;
|
||||
} else {
|
||||
println!("创建udp失败:{:?}", e);
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//注册
|
||||
let response = registration(&udp, server_address, token, mac_address).unwrap();
|
||||
{
|
||||
let ip_list = response
|
||||
.virtual_ip_list
|
||||
.iter()
|
||||
.map(|ip| Ipv4Addr::from(*ip))
|
||||
.collect();
|
||||
let mut dev = DEVICE_LIST.lock();
|
||||
dev.0 = response.epoch;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||
println!("virtual_gateway:{:?}", virtual_gateway);
|
||||
println!("virtual_netmask:{:?}", virtual_netmask);
|
||||
println!("当前设备ip(virtual_ip):{}", style(virtual_ip).green());
|
||||
let parker = Parker::new();
|
||||
//心跳线程
|
||||
{
|
||||
let un_parker = parker.unparker().clone();
|
||||
let udp = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
if let Err(e) = handle::heartbeat_handler::handle_loop(udp, server_address) {
|
||||
println!("心跳线程停止:{:?}", e);
|
||||
}
|
||||
un_parker.unpark();
|
||||
});
|
||||
}
|
||||
//初始化nat数据
|
||||
handle::init_nat_info(response.public_ip, response.public_port as u16);
|
||||
// tun服务
|
||||
let (tun_writer, tun_reader) =
|
||||
create_tun(virtual_ip, virtual_netmask, virtual_gateway).unwrap();
|
||||
// 打洞数据通道
|
||||
let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = handle::punch_handler::bounded();
|
||||
//udp数据处理
|
||||
{
|
||||
let un_parker = parker.unparker().clone();
|
||||
// 低优先级的udp数据通道
|
||||
let (sender, receiver) = crossbeam::channel::bounded(100);
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::udp_recv_handler::recv_loop(
|
||||
udp1,
|
||||
server_address,
|
||||
sender,
|
||||
tun_writer,
|
||||
current_device,
|
||||
) {
|
||||
println!("udp数据处理线程停止:{:?}", e);
|
||||
}
|
||||
un_parker.unpark();
|
||||
});
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let un_parker = parker.unparker().clone();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::udp_recv_handler::other_loop(udp1, receiver, current_device, punch_sender) {
|
||||
println!("udp数据处理线程停止:{:?}", e);
|
||||
}
|
||||
un_parker.unpark();
|
||||
});
|
||||
}
|
||||
//打洞处理
|
||||
{
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::punch_handler::cone_handle_loop(cone_receiver, udp1, current_device) {
|
||||
println!("打洞响应线程停止:{:?}", e);
|
||||
}
|
||||
});
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::punch_handler::req_symmetric_handle_loop(req_symmetric_receiver, udp1, current_device) {
|
||||
println!("打洞触发线程停止:{:?}", e);
|
||||
}
|
||||
});
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::punch_handler::res_symmetric_handle_loop(res_symmetric_receiver, udp1, current_device) {
|
||||
println!("打洞触发线程停止:{:?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
//tun数据处理
|
||||
{
|
||||
let udp = udp.try_clone().unwrap();
|
||||
let un_parker = parker.unparker().clone();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::tun_handler::handle_loop(udp, tun_reader, current_device) {
|
||||
println!("tun数据处理线程停止:{:?}", e);
|
||||
}
|
||||
un_parker.unpark();
|
||||
});
|
||||
}
|
||||
parker.park();
|
||||
std::process::exit(1);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
use std::{io, thread};
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::proto::message::NatType;
|
||||
|
||||
// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||
// pub enum NatType {
|
||||
// Symmetric,
|
||||
// Cone,
|
||||
// }
|
||||
//
|
||||
// impl Into<u8> for NatType {
|
||||
// fn into(self) -> u8 {
|
||||
// match self {
|
||||
// NatType::Symmetric => 0,
|
||||
// NatType::Cone => 1,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// 返回所有公网ip和端口变化范围
|
||||
pub fn public_ip_list() -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let mut hash_set = HashSet::new();
|
||||
let mut max_port_range = 0;
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port = 88;
|
||||
for _ in 0..3 {
|
||||
let udp = loop {
|
||||
match UdpSocket::bind(SocketAddr::new(IpAddr::from(Ipv4Addr::from(0)), port)) {
|
||||
Ok(udp) => {
|
||||
break udp;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::AddrInUse {
|
||||
port += 1;
|
||||
continue;
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
let (set, min_port, max_port) = public_ip_list_(&udp)?;
|
||||
drop(udp);
|
||||
let port_range = max_port - min_port;
|
||||
//有多个ip或者端口有变化,说明是对称nat
|
||||
if nat_type == NatType::Cone && (set.len() > 1 || port_range != 0) {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
if max_port_range < port_range {
|
||||
max_port_range = port_range;
|
||||
}
|
||||
for x in set {
|
||||
hash_set.insert(x);
|
||||
}
|
||||
thread::sleep(Duration::from_micros(5));
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), max_port_range))
|
||||
}
|
||||
|
||||
/// 测试样本较少,可能不对
|
||||
///
|
||||
/// - 移动宽带:锥形网络、一个ip、端口和局域网端口不相同
|
||||
/// - 电信宽带:锥形网络、一个ip,端口和局域网端口不相同
|
||||
/// - 联调宽带:对称网络、端口不变ip轮流用
|
||||
/// - 移动4g:对称网络、ip端口都变 使用小的端口变化量小
|
||||
/// - 联通4g:对称网络、只有一个ip 端口变化大
|
||||
/// - 电信4g:对称网络只有一个ip 公网端口比较连续
|
||||
/// - 综上:客户端使用小端口,针对对称网络 尝试所有ip 公网端口+-变化量的范围
|
||||
/// - 打通概率 移动宽带=电信宽带>联调宽带>电信4g>移动4g>>联调4g
|
||||
pub fn public_ip_list_(udp: &UdpSocket) -> io::Result<(HashSet<Ipv4Addr>, u16, u16)> {
|
||||
// println!("local port {:?}", udp.local_addr().unwrap().port());
|
||||
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
|
||||
let mut buf = [0u8; 128];
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?;
|
||||
let mut hash_set = HashSet::new();
|
||||
let mut count = 0;
|
||||
let mut min_port = 65535;
|
||||
let mut max_port = 0;
|
||||
for _ in 0..4 {
|
||||
if let Ok(len) = udp.recv(&mut buf) {
|
||||
if len != 16 || &buf[..10] != &b"NatType213"[..] {
|
||||
continue;
|
||||
}
|
||||
let port = u16::from_be_bytes([buf[14], buf[15]]);
|
||||
if min_port > port {
|
||||
min_port = port;
|
||||
}
|
||||
if max_port < port {
|
||||
max_port = port;
|
||||
}
|
||||
let ip = Ipv4Addr::new(buf[10], buf[11], buf[12], buf[13]);
|
||||
// println!("pub {:?}:{}", ip, port);
|
||||
hash_set.insert(ip);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
if count <= 1 {
|
||||
return Err(io::Error::from(io::ErrorKind::TimedOut));
|
||||
}
|
||||
Ok((hash_set, min_port, max_port))
|
||||
}
|
||||
|
||||
/// 返回nat类型
|
||||
pub fn nat_test() -> io::Result<NatType> {
|
||||
for _ in 0..3 {
|
||||
if NatType::Symmetric == nat_test_()? {
|
||||
return Ok(NatType::Symmetric);
|
||||
}
|
||||
thread::sleep(Duration::from_micros(5));
|
||||
}
|
||||
Ok(NatType::Cone)
|
||||
}
|
||||
|
||||
pub fn nat_test_() -> io::Result<NatType> {
|
||||
let udp = UdpSocket::bind("0.0.0.0:0")?;
|
||||
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
|
||||
let mut buf = [0u8; 128];
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?;
|
||||
let mut tmp_ip_port: Option<[u8; 6]> = None;
|
||||
let mut count = 0;
|
||||
for _ in 0..4 {
|
||||
if let Ok(len) = udp.recv(&mut buf) {
|
||||
if len != 16 || &buf[..10] != &b"NatType213"[..] {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
let mut ip_port = [0u8; 6];
|
||||
ip_port.copy_from_slice(&buf[10..16]);
|
||||
if let Some(tmp_ip_port) = &tmp_ip_port {
|
||||
if tmp_ip_port != &ip_port {
|
||||
return Ok(NatType::Symmetric);
|
||||
}
|
||||
} else {
|
||||
tmp_ip_port = Some(ip_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if count <= 1 {
|
||||
return Err(io::Error::from(io::ErrorKind::TimedOut));
|
||||
}
|
||||
Ok(NatType::Cone)
|
||||
}
|
||||
#[test]
|
||||
fn nat_test_run(){
|
||||
let udp = UdpSocket::bind("0.0.0.0:101").unwrap();
|
||||
let print = public_ip_list_(&udp).unwrap();
|
||||
println!("{:?}",print);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod check;
|
||||
@@ -0,0 +1,941 @@
|
||||
// This file is generated by rust-protobuf 3.2.0. Do not edit
|
||||
// .proto file is parsed by pure
|
||||
// @generated
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/702
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
#![allow(unused_attributes)]
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
|
||||
#![allow(box_pointers)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(unused_results)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
//! Generated file from `message.proto`
|
||||
|
||||
/// Generated files are compatible only with the same version
|
||||
/// of protobuf runtime.
|
||||
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:RegistrationRequest)
|
||||
pub struct RegistrationRequest {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.token)
|
||||
pub token: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.mac_address)
|
||||
pub mac_address: ::std::string::String,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationRequest.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RegistrationRequest {
|
||||
fn default() -> &'a RegistrationRequest {
|
||||
<RegistrationRequest as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationRequest {
|
||||
pub fn new() -> RegistrationRequest {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"token",
|
||||
|m: &RegistrationRequest| { &m.token },
|
||||
|m: &mut RegistrationRequest| { &mut m.token },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"mac_address",
|
||||
|m: &RegistrationRequest| { &m.mac_address },
|
||||
|m: &mut RegistrationRequest| { &mut m.mac_address },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationRequest>(
|
||||
"RegistrationRequest",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RegistrationRequest {
|
||||
const NAME: &'static str = "RegistrationRequest";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.token = is.read_string()?;
|
||||
},
|
||||
18 => {
|
||||
self.mac_address = is.read_string()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.token.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.token);
|
||||
}
|
||||
if !self.mac_address.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(2, &self.mac_address);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.token.is_empty() {
|
||||
os.write_string(1, &self.token)?;
|
||||
}
|
||||
if !self.mac_address.is_empty() {
|
||||
os.write_string(2, &self.mac_address)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> RegistrationRequest {
|
||||
RegistrationRequest::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.token.clear();
|
||||
self.mac_address.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RegistrationRequest {
|
||||
static instance: RegistrationRequest = RegistrationRequest {
|
||||
token: ::std::string::String::new(),
|
||||
mac_address: ::std::string::String::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for RegistrationRequest {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationRequest").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for RegistrationRequest {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RegistrationRequest {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:RegistrationResponse)
|
||||
pub struct RegistrationResponse {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_gateway)
|
||||
pub virtual_gateway: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_netmask)
|
||||
pub virtual_netmask: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.epoch)
|
||||
pub epoch: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip_list)
|
||||
pub virtual_ip_list: ::std::vec::Vec<u32>,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_ip)
|
||||
pub public_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_port)
|
||||
pub public_port: u32,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationResponse.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RegistrationResponse {
|
||||
fn default() -> &'a RegistrationResponse {
|
||||
<RegistrationResponse as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationResponse {
|
||||
pub fn new() -> RegistrationResponse {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &RegistrationResponse| { &m.virtual_ip },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_gateway",
|
||||
|m: &RegistrationResponse| { &m.virtual_gateway },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_gateway },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_netmask",
|
||||
|m: &RegistrationResponse| { &m.virtual_netmask },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_netmask },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"epoch",
|
||||
|m: &RegistrationResponse| { &m.epoch },
|
||||
|m: &mut RegistrationResponse| { &mut m.epoch },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"virtual_ip_list",
|
||||
|m: &RegistrationResponse| { &m.virtual_ip_list },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_ip_list },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_ip",
|
||||
|m: &RegistrationResponse| { &m.public_ip },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port",
|
||||
|m: &RegistrationResponse| { &m.public_port },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_port },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationResponse>(
|
||||
"RegistrationResponse",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RegistrationResponse {
|
||||
const NAME: &'static str = "RegistrationResponse";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
13 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
21 => {
|
||||
self.virtual_gateway = is.read_fixed32()?;
|
||||
},
|
||||
29 => {
|
||||
self.virtual_netmask = is.read_fixed32()?;
|
||||
},
|
||||
32 => {
|
||||
self.epoch = is.read_uint32()?;
|
||||
},
|
||||
42 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.virtual_ip_list)?;
|
||||
},
|
||||
45 => {
|
||||
self.virtual_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
53 => {
|
||||
self.public_ip = is.read_fixed32()?;
|
||||
},
|
||||
56 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.virtual_gateway != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.virtual_netmask != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.epoch != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(4, self.epoch);
|
||||
}
|
||||
my_size += 5 * self.virtual_ip_list.len() as u64;
|
||||
if self.public_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(7, self.public_port);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(1, self.virtual_ip)?;
|
||||
}
|
||||
if self.virtual_gateway != 0 {
|
||||
os.write_fixed32(2, self.virtual_gateway)?;
|
||||
}
|
||||
if self.virtual_netmask != 0 {
|
||||
os.write_fixed32(3, self.virtual_netmask)?;
|
||||
}
|
||||
if self.epoch != 0 {
|
||||
os.write_uint32(4, self.epoch)?;
|
||||
}
|
||||
for v in &self.virtual_ip_list {
|
||||
os.write_fixed32(5, *v)?;
|
||||
};
|
||||
if self.public_ip != 0 {
|
||||
os.write_fixed32(6, self.public_ip)?;
|
||||
}
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(7, self.public_port)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> RegistrationResponse {
|
||||
RegistrationResponse::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.virtual_ip = 0;
|
||||
self.virtual_gateway = 0;
|
||||
self.virtual_netmask = 0;
|
||||
self.epoch = 0;
|
||||
self.virtual_ip_list.clear();
|
||||
self.public_ip = 0;
|
||||
self.public_port = 0;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RegistrationResponse {
|
||||
static instance: RegistrationResponse = RegistrationResponse {
|
||||
virtual_ip: 0,
|
||||
virtual_gateway: 0,
|
||||
virtual_netmask: 0,
|
||||
epoch: 0,
|
||||
virtual_ip_list: ::std::vec::Vec::new(),
|
||||
public_ip: 0,
|
||||
public_port: 0,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for RegistrationResponse {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationResponse").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for RegistrationResponse {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RegistrationResponse {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:DeviceList)
|
||||
pub struct DeviceList {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:DeviceList.epoch)
|
||||
pub epoch: u32,
|
||||
// @@protoc_insertion_point(field:DeviceList.virtual_ip_list)
|
||||
pub virtual_ip_list: ::std::vec::Vec<u32>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:DeviceList.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a DeviceList {
|
||||
fn default() -> &'a DeviceList {
|
||||
<DeviceList as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceList {
|
||||
pub fn new() -> DeviceList {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"epoch",
|
||||
|m: &DeviceList| { &m.epoch },
|
||||
|m: &mut DeviceList| { &mut m.epoch },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"virtual_ip_list",
|
||||
|m: &DeviceList| { &m.virtual_ip_list },
|
||||
|m: &mut DeviceList| { &mut m.virtual_ip_list },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DeviceList>(
|
||||
"DeviceList",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for DeviceList {
|
||||
const NAME: &'static str = "DeviceList";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
8 => {
|
||||
self.epoch = is.read_uint32()?;
|
||||
},
|
||||
18 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.virtual_ip_list)?;
|
||||
},
|
||||
21 => {
|
||||
self.virtual_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.epoch != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(1, self.epoch);
|
||||
}
|
||||
my_size += 5 * self.virtual_ip_list.len() as u64;
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.epoch != 0 {
|
||||
os.write_uint32(1, self.epoch)?;
|
||||
}
|
||||
for v in &self.virtual_ip_list {
|
||||
os.write_fixed32(2, *v)?;
|
||||
};
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> DeviceList {
|
||||
DeviceList::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.epoch = 0;
|
||||
self.virtual_ip_list.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static DeviceList {
|
||||
static instance: DeviceList = DeviceList {
|
||||
epoch: 0,
|
||||
virtual_ip_list: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for DeviceList {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("DeviceList").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for DeviceList {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for DeviceList {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:Punch)
|
||||
pub struct Punch {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:Punch.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:Punch.public_ip_list)
|
||||
pub public_ip_list: ::std::vec::Vec<u32>,
|
||||
// @@protoc_insertion_point(field:Punch.public_port)
|
||||
pub public_port: u32,
|
||||
// @@protoc_insertion_point(field:Punch.public_port_range)
|
||||
pub public_port_range: u32,
|
||||
// @@protoc_insertion_point(field:Punch.nat_type)
|
||||
pub nat_type: ::protobuf::EnumOrUnknown<NatType>,
|
||||
// @@protoc_insertion_point(field:Punch.reply)
|
||||
pub reply: bool,
|
||||
// @@protoc_insertion_point(field:Punch.step)
|
||||
pub step: ::protobuf::EnumOrUnknown<Step>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:Punch.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a Punch {
|
||||
fn default() -> &'a Punch {
|
||||
<Punch as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
pub fn new() -> Punch {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &Punch| { &m.virtual_ip },
|
||||
|m: &mut Punch| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"public_ip_list",
|
||||
|m: &Punch| { &m.public_ip_list },
|
||||
|m: &mut Punch| { &mut m.public_ip_list },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port",
|
||||
|m: &Punch| { &m.public_port },
|
||||
|m: &mut Punch| { &mut m.public_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port_range",
|
||||
|m: &Punch| { &m.public_port_range },
|
||||
|m: &mut Punch| { &mut m.public_port_range },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"nat_type",
|
||||
|m: &Punch| { &m.nat_type },
|
||||
|m: &mut Punch| { &mut m.nat_type },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"reply",
|
||||
|m: &Punch| { &m.reply },
|
||||
|m: &mut Punch| { &mut m.reply },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"step",
|
||||
|m: &Punch| { &m.step },
|
||||
|m: &mut Punch| { &mut m.step },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Punch>(
|
||||
"Punch",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for Punch {
|
||||
const NAME: &'static str = "Punch";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
13 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
18 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.public_ip_list)?;
|
||||
},
|
||||
21 => {
|
||||
self.public_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
24 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
32 => {
|
||||
self.public_port_range = is.read_uint32()?;
|
||||
},
|
||||
40 => {
|
||||
self.nat_type = is.read_enum_or_unknown()?;
|
||||
},
|
||||
48 => {
|
||||
self.reply = is.read_bool()?;
|
||||
},
|
||||
56 => {
|
||||
self.step = is.read_enum_or_unknown()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
my_size += 5 * self.public_ip_list.len() as u64;
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(3, self.public_port);
|
||||
}
|
||||
if self.public_port_range != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(4, self.public_port_range);
|
||||
}
|
||||
if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) {
|
||||
my_size += ::protobuf::rt::int32_size(5, self.nat_type.value());
|
||||
}
|
||||
if self.reply != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) {
|
||||
my_size += ::protobuf::rt::int32_size(7, self.step.value());
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(1, self.virtual_ip)?;
|
||||
}
|
||||
for v in &self.public_ip_list {
|
||||
os.write_fixed32(2, *v)?;
|
||||
};
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(3, self.public_port)?;
|
||||
}
|
||||
if self.public_port_range != 0 {
|
||||
os.write_uint32(4, self.public_port_range)?;
|
||||
}
|
||||
if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) {
|
||||
os.write_enum(5, ::protobuf::EnumOrUnknown::value(&self.nat_type))?;
|
||||
}
|
||||
if self.reply != false {
|
||||
os.write_bool(6, self.reply)?;
|
||||
}
|
||||
if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) {
|
||||
os.write_enum(7, ::protobuf::EnumOrUnknown::value(&self.step))?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> Punch {
|
||||
Punch::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.virtual_ip = 0;
|
||||
self.public_ip_list.clear();
|
||||
self.public_port = 0;
|
||||
self.public_port_range = 0;
|
||||
self.nat_type = ::protobuf::EnumOrUnknown::new(NatType::Symmetric);
|
||||
self.reply = false;
|
||||
self.step = ::protobuf::EnumOrUnknown::new(Step::Step1);
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static Punch {
|
||||
static instance: Punch = Punch {
|
||||
virtual_ip: 0,
|
||||
public_ip_list: ::std::vec::Vec::new(),
|
||||
public_port: 0,
|
||||
public_port_range: 0,
|
||||
nat_type: ::protobuf::EnumOrUnknown::from_i32(0),
|
||||
reply: false,
|
||||
step: ::protobuf::EnumOrUnknown::from_i32(0),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for Punch {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("Punch").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Punch {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for Punch {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
|
||||
// @@protoc_insertion_point(enum:NatType)
|
||||
pub enum NatType {
|
||||
// @@protoc_insertion_point(enum_value:NatType.Symmetric)
|
||||
Symmetric = 0,
|
||||
// @@protoc_insertion_point(enum_value:NatType.Cone)
|
||||
Cone = 1,
|
||||
}
|
||||
|
||||
impl ::protobuf::Enum for NatType {
|
||||
const NAME: &'static str = "NatType";
|
||||
|
||||
fn value(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
|
||||
fn from_i32(value: i32) -> ::std::option::Option<NatType> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(NatType::Symmetric),
|
||||
1 => ::std::option::Option::Some(NatType::Cone),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
|
||||
const VALUES: &'static [NatType] = &[
|
||||
NatType::Symmetric,
|
||||
NatType::Cone,
|
||||
];
|
||||
}
|
||||
|
||||
impl ::protobuf::EnumFull for NatType {
|
||||
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().enum_by_package_relative_name("NatType").unwrap()).clone()
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
|
||||
let index = *self as usize;
|
||||
Self::enum_descriptor().value_by_index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::default::Default for NatType {
|
||||
fn default() -> Self {
|
||||
NatType::Symmetric
|
||||
}
|
||||
}
|
||||
|
||||
impl NatType {
|
||||
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
|
||||
::protobuf::reflect::GeneratedEnumDescriptorData::new::<NatType>("NatType")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
|
||||
// @@protoc_insertion_point(enum:Step)
|
||||
pub enum Step {
|
||||
// @@protoc_insertion_point(enum_value:Step.Step1)
|
||||
Step1 = 0,
|
||||
// @@protoc_insertion_point(enum_value:Step.Step2)
|
||||
Step2 = 1,
|
||||
// @@protoc_insertion_point(enum_value:Step.Step3)
|
||||
Step3 = 2,
|
||||
// @@protoc_insertion_point(enum_value:Step.Step4)
|
||||
Step4 = 3,
|
||||
}
|
||||
|
||||
impl ::protobuf::Enum for Step {
|
||||
const NAME: &'static str = "Step";
|
||||
|
||||
fn value(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
|
||||
fn from_i32(value: i32) -> ::std::option::Option<Step> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(Step::Step1),
|
||||
1 => ::std::option::Option::Some(Step::Step2),
|
||||
2 => ::std::option::Option::Some(Step::Step3),
|
||||
3 => ::std::option::Option::Some(Step::Step4),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
|
||||
const VALUES: &'static [Step] = &[
|
||||
Step::Step1,
|
||||
Step::Step2,
|
||||
Step::Step3,
|
||||
Step::Step4,
|
||||
];
|
||||
}
|
||||
|
||||
impl ::protobuf::EnumFull for Step {
|
||||
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().enum_by_package_relative_name("Step").unwrap()).clone()
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
|
||||
let index = *self as usize;
|
||||
Self::enum_descriptor().value_by_index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::default::Default for Step {
|
||||
fn default() -> Self {
|
||||
Step::Step1
|
||||
}
|
||||
}
|
||||
|
||||
impl Step {
|
||||
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
|
||||
::protobuf::reflect::GeneratedEnumDescriptorData::new::<Step>("Step")
|
||||
}
|
||||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\rmessage.proto\"L\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\
|
||||
\x20\x01(\tR\x05token\x12\x1f\n\x0bmac_address\x18\x02\x20\x01(\tR\nmacA\
|
||||
ddress\"\x83\x02\n\x14RegistrationResponse\x12\x1d\n\nvirtual_ip\x18\x01\
|
||||
\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtual_gateway\x18\x02\x20\x01(\x07\
|
||||
R\x0evirtualGateway\x12'\n\x0fvirtual_netmask\x18\x03\x20\x01(\x07R\x0ev\
|
||||
irtualNetmask\x12\x14\n\x05epoch\x18\x04\x20\x01(\rR\x05epoch\x12&\n\x0f\
|
||||
virtual_ip_list\x18\x05\x20\x03(\x07R\rvirtualIpList\x12\x1b\n\tpublic_i\
|
||||
p\x18\x06\x20\x01(\x07R\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\
|
||||
\x01(\rR\npublicPort\"J\n\nDeviceList\x12\x14\n\x05epoch\x18\x01\x20\x01\
|
||||
(\rR\x05epoch\x12&\n\x0fvirtual_ip_list\x18\x02\x20\x03(\x07R\rvirtualIp\
|
||||
List\"\xef\x01\n\x05Punch\x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tv\
|
||||
irtualIp\x12$\n\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\
|
||||
\x12\x1f\n\x0bpublic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11publ\
|
||||
ic_port_range\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12#\n\x08nat_type\
|
||||
\x18\x05\x20\x01(\x0e2\x08.NatTypeR\x07natType\x12\x14\n\x05reply\x18\
|
||||
\x06\x20\x01(\x08R\x05reply\x12\x19\n\x04step\x18\x07\x20\x01(\x0e2\x05.\
|
||||
StepR\x04step*\"\n\x07NatType\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\
|
||||
\x10\x01*2\n\x04Step\x12\t\n\x05Step1\x10\0\x12\t\n\x05Step2\x10\x01\x12\
|
||||
\t\n\x05Step3\x10\x02\x12\t\n\x05Step4\x10\x03b\x06proto3\
|
||||
";
|
||||
|
||||
/// `FileDescriptorProto` object which was a source for this generated file
|
||||
fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new();
|
||||
file_descriptor_proto_lazy.get(|| {
|
||||
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
/// `FileDescriptor` object which allows dynamic access to files
|
||||
pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
|
||||
static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
file_descriptor.get(|| {
|
||||
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
|
||||
let mut deps = ::std::vec::Vec::with_capacity(0);
|
||||
let mut messages = ::std::vec::Vec::with_capacity(4);
|
||||
messages.push(RegistrationRequest::generated_message_descriptor_data());
|
||||
messages.push(RegistrationResponse::generated_message_descriptor_data());
|
||||
messages.push(DeviceList::generated_message_descriptor_data());
|
||||
messages.push(Punch::generated_message_descriptor_data());
|
||||
let mut enums = ::std::vec::Vec::with_capacity(2);
|
||||
enums.push(NatType::generated_enum_descriptor_data());
|
||||
enums.push(Step::generated_enum_descriptor_data());
|
||||
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
|
||||
file_descriptor_proto(),
|
||||
deps,
|
||||
messages,
|
||||
enums,
|
||||
)
|
||||
});
|
||||
::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// @generated
|
||||
|
||||
pub mod message;
|
||||
@@ -0,0 +1,205 @@
|
||||
use std::fmt;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
Ping,
|
||||
Pong,
|
||||
PunchRequest,
|
||||
PunchResponse,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Ping,
|
||||
2 => Protocol::Pong,
|
||||
3 => Protocol::PunchRequest,
|
||||
4 => Protocol::PunchResponse,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Ping => 1,
|
||||
Protocol::Pong => 2,
|
||||
Protocol::PunchRequest => 3,
|
||||
Protocol::PunchResponse => 4,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ControlPacket<B> {
|
||||
PingPacket(PingPacket<B>),
|
||||
PongPacket(PongPacket<B>),
|
||||
PunchRequest(PunchRequestPacket<B>),
|
||||
PunchResponse(PunchResponsePacket<B>),
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ControlPacket<B> {
|
||||
pub fn new(protocol: u8, buffer: B) -> Result<ControlPacket<B>> {
|
||||
match Protocol::from(protocol) {
|
||||
Protocol::Ping => Ok(ControlPacket::PingPacket(PingPacket::new(buffer)?)),
|
||||
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
|
||||
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest(PunchRequestPacket::new(
|
||||
buffer,
|
||||
)?)),
|
||||
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse(PunchResponsePacket::new(
|
||||
buffer,
|
||||
)?)),
|
||||
Protocol::UnKnow(_) => Err(Error::NotSupport),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 网络探针
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PingPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PongPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<PingPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 8 + 4 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(PingPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn time(&self) -> i64 {
|
||||
i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap())
|
||||
}
|
||||
pub fn epoch(&self) -> u32 {
|
||||
u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PingPacket<B> {
|
||||
pub fn set_time(&mut self, time: i64) {
|
||||
self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
pub fn set_epoch(&mut self, epoch: u32) {
|
||||
self.buffer.as_mut()[8..12].copy_from_slice(&epoch.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PongPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<PongPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(PongPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PongPacket<B> {
|
||||
pub fn time(&self) -> i64 {
|
||||
i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PongPacket<B> {
|
||||
pub fn set_time(&mut self, time: i64) {
|
||||
self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
pub type TurnPongPacket<B> = TurnPingPacket<B>;
|
||||
|
||||
/// 探测目标延迟
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TurnPingPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPingPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<TurnPingPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 16 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(TurnPingPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPingPacket<B> {
|
||||
// pub fn source(&self) -> Ipv4Addr {
|
||||
// let tmp:[u8;4] = self.buffer.as_ref()[..4].try_into().unwrap();
|
||||
// Ipv4Addr::from(tmp)
|
||||
// }
|
||||
// pub fn destination(&self) -> Ipv4Addr {
|
||||
// let tmp:[u8;4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
// Ipv4Addr::from(tmp)
|
||||
// }
|
||||
pub fn time(&self) -> i64 {
|
||||
i64::from_be_bytes(self.buffer.as_ref()[8..].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> TurnPingPacket<B> {
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
|
||||
}
|
||||
pub fn set_destination(&mut self, destination: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets());
|
||||
}
|
||||
pub fn set_time(&mut self, time: i64) {
|
||||
self.buffer.as_mut()[8..].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
pub type PunchResponsePacket<B> = PunchPacket<B>;
|
||||
pub type PunchRequestPacket<B> = PunchPacket<B>;
|
||||
|
||||
/// nat穿透
|
||||
#[derive(Clone)]
|
||||
pub struct PunchPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PunchPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<PunchPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(Self { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PunchPacket<B> {
|
||||
pub fn source(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PunchPacket<B> {
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for PunchPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PunchPacket")
|
||||
.field("source", &self.source())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Self::TokenError,
|
||||
2 => Self::Disconnect,
|
||||
val => Self::Other(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::TokenError => 1,
|
||||
Protocol::Disconnect => 2,
|
||||
Protocol::Other(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum InErrorPacket<B> {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
OtherError(ErrorPacket<B>),
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> InErrorPacket<B> {
|
||||
pub fn new(protocol: u8, buffer: B) -> Result<InErrorPacket<B>> {
|
||||
match Protocol::from(protocol) {
|
||||
Protocol::TokenError => Ok(InErrorPacket::TokenError),
|
||||
Protocol::Disconnect => Ok(InErrorPacket::Disconnect),
|
||||
Protocol::Other(_) => Ok(InErrorPacket::OtherError(ErrorPacket::new(buffer)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ErrorPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ErrorPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<ErrorPacket<B>> {
|
||||
Ok(Self { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ErrorPacket<B> {
|
||||
pub fn message(&self) -> Result<String> {
|
||||
match String::from_utf8(self.buffer.as_ref().to_vec()) {
|
||||
Ok(str) => Ok(str),
|
||||
Err(_) => Err(Error::InvalidPacket),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> ErrorPacket<B> {
|
||||
pub fn set_message(&mut self, message: &str) {
|
||||
self.buffer.as_mut().copy_from_slice(message.as_bytes())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
pub mod control_packet;
|
||||
pub mod error_packet;
|
||||
pub mod service_packet;
|
||||
pub mod turn_packet;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Version {
|
||||
V1,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Version {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Version::V1,
|
||||
val => Version::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Version {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Version::V1 => 1,
|
||||
Version::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// 服务包 用于和服务端交互
|
||||
Service,
|
||||
/// 响应异常
|
||||
Error,
|
||||
/// 控制协议
|
||||
Control,
|
||||
/// 转发ipv4数据
|
||||
Ipv4Turn,
|
||||
OtherTurn,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Service,
|
||||
2 => Protocol::Error,
|
||||
3 => Protocol::Control,
|
||||
4 => Protocol::Ipv4Turn,
|
||||
5 => Protocol::OtherTurn,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Service => 1,
|
||||
Protocol::Error => 2,
|
||||
Protocol::Control => 3,
|
||||
Protocol::Ipv4Turn => 4,
|
||||
Protocol::OtherTurn => 5,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NetPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<NetPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
// 不能大于udp最大载荷长度
|
||||
if len < 4 || len > 65535 - 20 - 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(NetPacket { buffer })
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
self.buffer.as_ref()
|
||||
}
|
||||
pub fn into_buffer(self) -> B {
|
||||
self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn version(&self) -> Version {
|
||||
Version::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn protocol(&self) -> Protocol {
|
||||
Protocol::from(self.buffer.as_ref()[1])
|
||||
}
|
||||
pub fn transport_protocol(&self) -> u8 {
|
||||
self.buffer.as_ref()[2]
|
||||
}
|
||||
pub fn ttl(&self) -> u8 {
|
||||
self.buffer.as_ref()[3]
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[4..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
||||
pub fn set_version(&mut self, version: Version) {
|
||||
self.buffer.as_mut()[0] = version.into();
|
||||
}
|
||||
pub fn set_protocol(&mut self, protocol: Protocol) {
|
||||
self.buffer.as_mut()[1] = protocol.into();
|
||||
}
|
||||
pub fn set_transport_protocol(&mut self, transport_protocol: u8) {
|
||||
self.buffer.as_mut()[2] = transport_protocol;
|
||||
}
|
||||
pub fn set_ttl(&mut self, ttl: u8) {
|
||||
self.buffer.as_mut()[3] = ttl;
|
||||
}
|
||||
pub fn set_payload(&mut self, payload: &[u8]) {
|
||||
self.buffer.as_mut()[4..payload.len() + 4].copy_from_slice(payload);
|
||||
}
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[4..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for NetPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("NetPacket")
|
||||
.field("version", &self.version())
|
||||
.field("protocol", &self.protocol())
|
||||
.field("transport_protocol", &self.transport_protocol())
|
||||
.field("ttl", &self.ttl())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// 注册请求
|
||||
RegistrationRequest,
|
||||
/// 注册响应
|
||||
RegistrationResponse,
|
||||
/// 更新设备列表
|
||||
UpdateDeviceList,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Self::RegistrationRequest,
|
||||
2 => Self::RegistrationResponse,
|
||||
3 => Self::UpdateDeviceList,
|
||||
val => Self::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Self::RegistrationRequest => 1,
|
||||
Self::RegistrationResponse => 2,
|
||||
Self::UpdateDeviceList => 3,
|
||||
Self::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
use std::fmt;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Protocol {
|
||||
Punch,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Punch,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Punch => 1,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TurnPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<TurnPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len <= 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(Self { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPacket<B> {
|
||||
pub fn source(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn destination(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[8..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> TurnPacket<B> {
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[8..]
|
||||
}
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
|
||||
}
|
||||
pub fn set_destination(&mut self, destination: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets());
|
||||
}
|
||||
pub fn set_payload(&mut self, payload: &[u8]) {
|
||||
self.buffer.as_mut()[8..payload.len() + 8].copy_from_slice(payload)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for TurnPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TurnPacket")
|
||||
.field("source", &self.source())
|
||||
.field("destination", &self.destination())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub use unix::create_tun;
|
||||
#[cfg(any(unix))]
|
||||
pub use unix::{TunReader, TunWriter};
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub mod unix;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::create_tun;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{TunReader, TunWriter};
|
||||
@@ -0,0 +1,155 @@
|
||||
use std::io;
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
|
||||
use bytes::BufMut;
|
||||
use tun::platform::posix::{Reader, Writer};
|
||||
use tun::Device;
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> crate::error::Result<(TunWriter, TunReader)> {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(1420)
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
|
||||
let up_eth_str: String = format!("ifconfig utun3 {:?} {:?} up ", address, gateway);
|
||||
let route_add_str: String = format!(
|
||||
"sudo route -n add -net {:?} -netmask {:?} {:?}",
|
||||
address, netmask, gateway
|
||||
);
|
||||
|
||||
let up_eth_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(up_eth_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !up_eth_out.status.success(){
|
||||
return Err(crate::error::Error::Stop(format!("设置地址失败:{:?}", up_eth_out)));
|
||||
}
|
||||
// println!("{:?}", up_eth_out);
|
||||
let if_config_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !if_config_out.status.success(){
|
||||
return Err(crate::error::Error::Stop(format!("设置路由失败:{:?}", if_config_out)));
|
||||
}
|
||||
// println!("{:?}", if_config_out);
|
||||
// let cmd_str: String = " ifconfig|grep flags=8051|awk -F ':' '{print $1}'|tail -1".to_string();
|
||||
//
|
||||
// let cmd_str_out = Command::new("sh")
|
||||
// .arg("-c")
|
||||
// .arg(cmd_str)
|
||||
// .output()
|
||||
// .expect("sh exec error!");
|
||||
// if !cmd_str_out.status.success(){
|
||||
// return Err(Error::Stop(format!("设置路由失败:{:?}", cmd_str_out)));
|
||||
// }
|
||||
// println!("{:?}", cmd_str_out);
|
||||
let packet_information = dev.has_packet_information();
|
||||
let (reader, writer) = dev.split();
|
||||
Ok((
|
||||
TunWriter(writer, packet_information),
|
||||
TunReader(reader, packet_information),
|
||||
))
|
||||
}
|
||||
|
||||
pub struct TunReader(Reader, bool);
|
||||
|
||||
impl TunReader {
|
||||
pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> {
|
||||
let len = self.0.read(buf)?;
|
||||
if self.1 {
|
||||
Ok(&mut buf[4..len])
|
||||
} else {
|
||||
Ok(&mut buf[..len])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunWriter(Writer, bool);
|
||||
|
||||
impl TunWriter {
|
||||
pub fn write(&mut self, packet: &[u8]) -> io::Result<()> {
|
||||
if self.1 {
|
||||
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
|
||||
buf.put_u16(0);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
buf.put_u16(libc::PF_INET as u16);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
buf.put_u16(libc::ETH_P_IP as u16);
|
||||
buf.extend_from_slice(packet);
|
||||
self.0.write_all(&buf)
|
||||
} else {
|
||||
self.0.write_all(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn main1() {
|
||||
// loop {
|
||||
// let len = reader.read(&mut buffer).unwrap();
|
||||
// println!("{:?}", &buffer[..len]);
|
||||
// match ip::Packet::new(&buffer[4..len]) {
|
||||
// Ok(ip::Packet::V4(pkt)) => {
|
||||
// match icmp::Packet::new(pkt.payload()) {
|
||||
// Ok(icmp) => {
|
||||
// match icmp.echo() {
|
||||
// Ok(icmp) => {
|
||||
// println!("{:?}", icmp);
|
||||
// let reply = ip::v4::Builder::default()
|
||||
// .id(0x42)
|
||||
// .unwrap()
|
||||
// .ttl(64)
|
||||
// .unwrap()
|
||||
// .source(pkt.destination())
|
||||
// .unwrap()
|
||||
// .destination(pkt.source())
|
||||
// .unwrap()
|
||||
// .icmp()
|
||||
// .unwrap()
|
||||
// .echo()
|
||||
// .unwrap()
|
||||
// .reply()
|
||||
// .unwrap()
|
||||
// .identifier(icmp.identifier())
|
||||
// .unwrap()
|
||||
// .sequence(icmp.sequence())
|
||||
// .unwrap()
|
||||
// .payload(icmp.payload())
|
||||
// .unwrap()
|
||||
// .build()
|
||||
// .unwrap();
|
||||
// let l = reply.len();
|
||||
// &mut buffer[4..(l + 4)].copy_from_slice(&reply);
|
||||
// // writer.write_all(&buffer[..4]).unwrap();
|
||||
// writer.write_all(&buffer[..(l + 4)]).unwrap();
|
||||
// }
|
||||
// Err(_) => {}
|
||||
// }
|
||||
// }
|
||||
// Err(_) => {}
|
||||
// }
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,131 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use libloading::Library;
|
||||
use wintun::{Adapter, Packet, Session};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
pub struct TunWriter(Arc<Session>);
|
||||
|
||||
impl TunWriter {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.0.allocate_send_packet(buf.len() as u16) {
|
||||
Ok(mut packet) => {
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
self.0.send_packet(packet);
|
||||
return Ok(());
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "send err"));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunReader(Arc<Session>);
|
||||
|
||||
impl TunReader {
|
||||
pub fn next(&self) -> io::Result<Packet> {
|
||||
match self.0.receive_blocking() {
|
||||
Ok(packet) => {
|
||||
return Ok(packet);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "read err"));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> Result<(TunWriter, TunReader)> {
|
||||
let win_tun = unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(library) => match wintun::load_from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
Err(e) => {
|
||||
return Err(Error::Stop(format!("{:?}", e)));
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(Error::Stop(format!("{:?}", e)));
|
||||
}
|
||||
}
|
||||
};
|
||||
let adapter = match Adapter::open(&win_tun, "Demo") {
|
||||
Ok(a) => a,
|
||||
Err(_) => match Adapter::create(&win_tun, "Example", "Demo", None) {
|
||||
Ok(adapter) => adapter,
|
||||
|
||||
Err(e) => return Err(Error::Stop(format!("{:?}", e))),
|
||||
},
|
||||
};
|
||||
let index = adapter.get_adapter_index().unwrap();
|
||||
let set_mtu = format!(
|
||||
"netsh interface ipv4 set subinterface {} mtu=1420 store=persistent",
|
||||
index
|
||||
);
|
||||
let set_metric = format!("netsh interface ip set interface {} metric=1", index);
|
||||
let set_address = format!(
|
||||
"netsh interface ip set address {} static {:?} {:?} ", // gateway={:?}
|
||||
index, address, netmask,
|
||||
);
|
||||
// println!("{}", set_mtu);
|
||||
// println!("{}", set_metric);
|
||||
// println!("{}", set_address);
|
||||
// 执行网卡初始化命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_mtu)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("设置mtu失败:{:?}", out)));
|
||||
}
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_metric)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("设置接口跃点失败:{:?}", out)));
|
||||
}
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_address)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("设置网络地址失败:{:?}", out)));
|
||||
}
|
||||
let dest = {
|
||||
let ip = address.octets();
|
||||
let mask = netmask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
};
|
||||
let set_route = format!(
|
||||
"route add {:?} mask {:?} {:?} if {}",
|
||||
dest, netmask, gateway, index
|
||||
);
|
||||
// println!("{}", set_route);
|
||||
// 执行添加路由命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_route)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("添加路由失败:{:?}", out)));
|
||||
}
|
||||
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
|
||||
let reader_session = session.clone();
|
||||
Ok((TunWriter(session), TunReader(reader_session)))
|
||||
}
|
||||
Reference in New Issue
Block a user