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

This commit is contained in:
lubeilin
2023-01-08 15:38:45 +08:00
parent d956e493af
commit 292893e9dd
76 changed files with 1132 additions and 588 deletions
+38
View File
@@ -0,0 +1,38 @@
[package]
name = "switch"
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"
log = "0.4.17"
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"] }
thiserror = "1.0.37"
chrono = "0.4.23"
lazy_static = "1.4.0"
moka = "0.9.6"
protobuf = "3.2.0"
tokio = { version = "1.24.1", features = ["full"] }
[target.'cfg(any(unix))'.dependencies]
tun = { path = "./rust-tun" }
[target.'cfg(target_os = "windows")'.dependencies]
wintun = "0.2.1"
libloading = "0.7.4"
[build-dependencies]
protobuf-codegen = "3.2.0"
protoc-bin-vendored = "3.0.0"
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+14
View File
@@ -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.");
}
+10
View File
@@ -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"
+25
View File
@@ -0,0 +1,25 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("the buffer is too small")]
SmallBuffer,
#[error("the packet is invalid")]
InvalidPacket,
#[error("Unimplemented")]
Unimplemented,
// #[error("the vaue is invalid for the field")]
// InvalidValue,
//
// #[error("the value has already been defined")]
// AlreadyDefined,
//
// #[error(transparent)]
// Io(#[from] io::Error),
//
// #[error(transparent)]
// Nul(#[from] ffi::NulError),
}
pub type Result<T> = ::std::result::Result<T, Error>;
+174
View File
@@ -0,0 +1,174 @@
use std::fmt;
use byteorder::{BigEndian, ReadBytesExt};
use crate::cal_checksum;
use crate::error::*;
/// icmp 协议
/* https://www.rfc-editor.org/rfc/rfc792
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 不同Type和Code有不同含义 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据体 不同Type和Code有不同含义 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
use crate::icmp::{Code, Kind};
use crate::ip::ipv4::packet::IpV4Packet;
pub struct IcmpPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> IcmpPacket<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> Result<Self> {
if buffer.as_ref().len() < 8 {
Err(Error::SmallBuffer)?
}
let packet = Self::unchecked(buffer);
Ok(packet)
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IcmpPacket<B> {
pub fn set_kind(&mut self, kind: Kind) {
self.buffer.as_mut()[0] = kind.into();
}
pub fn update_checksum(&mut self) {
self.buffer.as_mut()[2..4].copy_from_slice(&[0, 0]);
let checksum = cal_checksum(self.buffer.as_ref());
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
}
}
impl<B: AsRef<[u8]>> IcmpPacket<B> {
pub fn kind(&self) -> Kind {
Kind::from(self.buffer.as_ref()[0])
}
pub fn code(&self) -> Code {
Code::from(self.kind(), self.buffer.as_ref()[1])
}
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
}
pub fn header_other(&self) -> HeaderOther {
match self.kind() {
Kind::EchoReply
| Kind::EchoRequest
| Kind::TimestampRequest
| Kind::TimestampReply
| Kind::InformationRequest
| Kind::InformationReply => {
let ide = (&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap();
let seq = (&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap();
HeaderOther::Identifier(ide, seq)
}
Kind::DestinationUnreachable | Kind::TimeExceeded | Kind::SourceQuench => {
let bytes = self.buffer.as_ref();
HeaderOther::Unused(bytes[4], bytes[5], bytes[6], bytes[7])
}
Kind::Redirect => {
let bytes = self.buffer.as_ref();
HeaderOther::Address(bytes[4], bytes[5], bytes[6], bytes[7])
}
Kind::ParameterProblem => HeaderOther::Pointer(self.buffer.as_ref()[4]),
_ => {
let bytes = self.buffer.as_ref();
HeaderOther::UnKnown(bytes[4], bytes[5], bytes[6], bytes[7])
}
}
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[8..]
}
pub fn description(&self) -> Description<&[u8]> {
use std::io::Cursor;
match self.kind() {
Kind::DestinationUnreachable
| Kind::TimeExceeded
| Kind::ParameterProblem
| Kind::SourceQuench
| Kind::Redirect => match IpV4Packet::new(self.payload()) {
Ok(d) => Description::Ip(d),
Err(_) => Description::Other(self.payload()),
},
Kind::TimestampRequest | Kind::TimestampReply => {
let mut buffer = Cursor::new(self.payload());
Description::Timestamp(
buffer.read_u32::<BigEndian>().unwrap(),
buffer.read_u32::<BigEndian>().unwrap(),
buffer.read_u32::<BigEndian>().unwrap(),
)
}
_ => Description::Other(self.payload()),
}
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IcmpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct(if self.is_valid() {
"icmp::Packet"
} else {
"icmp::Packet!"
})
.field("kind", &self.kind())
.field("code", &self.code())
.field("checksum", &self.checksum())
.field("payload", &self.payload())
.finish()
}
}
#[derive(Debug)]
pub enum HeaderOther {
/// 全零
Unused(u8, u8, u8, u8),
/// If code = 0, identifies the octet where an error was detected.
Pointer(u8),
/// Address of the gateway to which traffic for the network specified
/// in the internet destination network field of the original
/// datagram's data should be sent.
Address(u8, u8, u8, u8),
/// Identifier | Sequence Number
Identifier(u16, u16),
UnKnown(u8, u8, u8, u8),
}
pub enum Description<B> {
Ip(IpV4Packet<B>),
///时间戳 Originate Timestamp,Receive Timestamp,Transmit Timestamp
Timestamp(u32, u32, u32),
Other(B),
}
impl<B: AsRef<[u8]> + std::fmt::Debug> fmt::Debug for Description<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Description::Ip(packet) => f.debug_struct(&format!("{:?}", packet)).finish(),
Description::Timestamp(originate, receive, transmit) => f
.debug_struct("")
.field("originate", originate)
.field("receive", receive)
.field("transmit", transmit)
.finish(),
Description::Other(bytes) => f.debug_struct(&format!("{:?}", bytes)).finish(),
}
}
}
+414
View File
@@ -0,0 +1,414 @@
pub mod icmp;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Kind {
/// ping应答,type=0
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ...
+-+-+-+-+-
*/
EchoReply,
/// 目的地不可达,差错报文的一种,路由器收到一个不能转发的数据报,会向源地址返回这个报文,type=3
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
DestinationUnreachable,
/// 源抑制报文,用于防止接收端缓存溢出,接收设备发送这个来请求源设备降低发送速度,type=4
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
SourceQuench,
/// 重定向报文,当路由器接收包的接口正好是去往目的地的出口时,会向源地址发送重定向报文,告知源直接将数据发往自己的下一跳,type=5
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Gateway Internet Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
Redirect,
/// ping请求,type=8
EchoRequest,
/// 路由器通告,type=9,
RouterAdvertisement,
/// 路由器请求,type=10
RouterSolicitation,
/// 报文ttl为0后,路由器会向源发送此报文,type=11
/// Tracert工作原理:
/// 首先向目的地发送ttl=1的包,下一跳路由器收到后ttl-1,此时ttl=0,将向源发送 ICMP time exceeded
/// 再发送ttl=2的包,以此类推,直到目标主机接收到改包,此时不会回复ICMP time exceeded,代表已经探测到目的地
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
TimeExceeded,
/// 参数错误,数据有误、校验和不对等,type=12
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Pointer | unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
注:Pointer指示错误的位置
*/
ParameterProblem,
/// 时间戳请求,type=13
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Originate Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Receive Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Transmit Timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
TimestampRequest,
/// 时间戳响应,type=14
TimestampReply,
/// 信息请求,type=15
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
InformationRequest,
/// 信息响应,type=16
InformationReply,
/// 地址掩码请求,type=17
AddressMaskRequest,
/// 地址掩码应答,type=18
AddressMaskReply,
///
TraceRoute,
///
Unknown(u8),
}
impl From<u8> for Kind {
fn from(value: u8) -> Kind {
use self::Kind::*;
match value {
0 => EchoReply,
3 => DestinationUnreachable,
4 => SourceQuench,
5 => Redirect,
8 => EchoRequest,
9 => RouterAdvertisement,
10 => RouterSolicitation,
11 => TimeExceeded,
12 => ParameterProblem,
13 => TimestampRequest,
14 => TimestampReply,
15 => InformationRequest,
16 => InformationReply,
17 => AddressMaskRequest,
18 => AddressMaskReply,
30 => TraceRoute,
v => Unknown(v),
}
}
}
impl Into<u8> for Kind {
fn into(self) -> u8 {
use self::Kind::*;
match self {
EchoReply => 0,
DestinationUnreachable => 3,
SourceQuench => 4,
Redirect => 5,
EchoRequest => 8,
RouterAdvertisement => 9,
RouterSolicitation => 10,
TimeExceeded => 11,
ParameterProblem => 12,
TimestampRequest => 13,
TimestampReply => 14,
InformationRequest => 15,
InformationReply => 16,
AddressMaskRequest => 17,
AddressMaskReply => 18,
TraceRoute => 30,
Unknown(v) => v,
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Code {
DestinationUnreachable(DestinationUnreachable),
Redirect(Redirect),
ParameterProblem(ParameterProblem),
Other(u8),
}
impl Code {
pub fn from(kind: Kind, code: u8) -> Code {
match kind {
Kind::DestinationUnreachable => {
Code::DestinationUnreachable(DestinationUnreachable::from(code))
}
Kind::Redirect => Code::Redirect(Redirect::from(code)),
Kind::ParameterProblem => Code::ParameterProblem(ParameterProblem::from(code)),
_ => Code::Other(code),
}
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum DestinationUnreachable {
/// 网络不可达
DestinationNetworkUnreachable,
/// 主机不可达
DestinationHostUnreachable,
/// 协议不可达
DestinationProtocolUnreachable,
/// 端口不可达
DestinationPortUnreachable,
/// 需要进行分片但设置不分片比特
FragmentationRequired,
/// 源站选路失败
SourceRouteFailed,
/// 目的网络未知
DestinationNetworkUnknown,
/// 目的主机未知
DestinationHostUnknown,
/// 源主机被隔离(作废不用)
SourceHostIsolated,
/// 目的网络被强制禁止
NetworkAdministrativelyProhibited,
/// 目的主机被强制禁止
HostAdministrativelyProhibited,
/// 由于服务类型TOS,网络不可达
NetworkUnreachableForTos,
/// 由于服务类型TOS,主机不可达
HostUnreachableForTos,
/// 由于过滤,通信被强制禁止
CommunicationAdministrativelyProhibited,
/// 主机越权
HostPrecedenceViolation,
/// 优先中止生效
PrecedentCutoffInEffect,
///
Unknown(u8),
}
/// Codes for Redirect Message packets.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Redirect {
/// 对网络重定向
RedirectDatagramForNetwork,
/// 对主机重定向
RedirectDatagramForHost,
/// 对服务类型和网络重定向
RedirectDatagramForTosAndNetwork,
/// 对服务类型和主机重定向
RedirectDatagramForTosAndHost,
///
Unknown(u8),
}
/// Codes for TimeExceeded Message packets.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum TimeExceeded {
/// TTL超时报文
Transit,
/// 分片重组超时报文
Reassembly,
///
Unknown(u8),
}
/// Codes for Parameter Problem packets.
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum ParameterProblem {
/// 坏的IP首部(包括各种差错)
PointerIndicatesError,
/// 缺少必需的选项
MissingRequiredData,
/// 长度错误
BadLength,
///
Unknown(u8),
}
impl From<u8> for DestinationUnreachable {
fn from(value: u8) -> Self {
use self::DestinationUnreachable::*;
match value {
0 => DestinationNetworkUnreachable,
1 => DestinationHostUnreachable,
2 => DestinationProtocolUnreachable,
3 => DestinationPortUnreachable,
4 => FragmentationRequired,
5 => SourceRouteFailed,
6 => DestinationNetworkUnknown,
7 => DestinationHostUnknown,
8 => SourceHostIsolated,
9 => NetworkAdministrativelyProhibited,
10 => HostAdministrativelyProhibited,
11 => NetworkUnreachableForTos,
12 => HostUnreachableForTos,
13 => CommunicationAdministrativelyProhibited,
14 => HostPrecedenceViolation,
15 => PrecedentCutoffInEffect,
v => Unknown(v),
}
}
}
impl Into<u8> for DestinationUnreachable {
fn into(self) -> u8 {
use self::DestinationUnreachable::*;
match self {
DestinationNetworkUnreachable => 0,
DestinationHostUnreachable => 1,
DestinationProtocolUnreachable => 2,
DestinationPortUnreachable => 3,
FragmentationRequired => 4,
SourceRouteFailed => 5,
DestinationNetworkUnknown => 6,
DestinationHostUnknown => 7,
SourceHostIsolated => 8,
NetworkAdministrativelyProhibited => 9,
HostAdministrativelyProhibited => 10,
NetworkUnreachableForTos => 11,
HostUnreachableForTos => 12,
CommunicationAdministrativelyProhibited => 13,
HostPrecedenceViolation => 14,
PrecedentCutoffInEffect => 15,
Unknown(v) => v,
}
}
}
impl From<u8> for Redirect {
fn from(value: u8) -> Self {
use self::Redirect::*;
match value {
0 => RedirectDatagramForNetwork,
1 => RedirectDatagramForHost,
2 => RedirectDatagramForTosAndNetwork,
3 => RedirectDatagramForTosAndHost,
v => Unknown(v),
}
}
}
impl Into<u8> for Redirect {
fn into(self) -> u8 {
use self::Redirect::*;
match self {
RedirectDatagramForNetwork => 0,
RedirectDatagramForHost => 1,
RedirectDatagramForTosAndNetwork => 2,
RedirectDatagramForTosAndHost => 3,
Unknown(v) => v,
}
}
}
impl From<u8> for TimeExceeded {
fn from(value: u8) -> Self {
use self::TimeExceeded::*;
match value {
0 => Transit,
1 => Reassembly,
v => Unknown(v),
}
}
}
impl Into<u8> for TimeExceeded {
fn into(self) -> u8 {
use self::TimeExceeded::*;
match self {
Transit => 0,
Reassembly => 1,
Unknown(v) => v,
}
}
}
impl From<u8> for ParameterProblem {
fn from(value: u8) -> Self {
use self::ParameterProblem::*;
match value {
0 => PointerIndicatesError,
1 => MissingRequiredData,
2 => BadLength,
v => Unknown(v),
}
}
}
impl Into<u8> for ParameterProblem {
fn into(self) -> u8 {
use self::ParameterProblem::*;
match self {
PointerIndicatesError => 0,
MissingRequiredData => 1,
BadLength => 2,
Unknown(v) => v,
}
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod packet;
pub mod protocol;
+250
View File
@@ -0,0 +1,250 @@
use std::fmt;
use std::net::Ipv4Addr;
use byteorder::{BigEndian, ReadBytesExt};
use crate::cal_checksum;
use crate::error::*;
use crate::ip::ipv4::protocol::Protocol;
/// ip协议
/*
RFC: 791 https://www.ietf.org/rfc/rfc791.txt
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 版本(4) | 头部长度(4) | 服务类型(8) | 总字节数(16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 标识(16) | 标志(3) | 片偏移(13) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 生存时间(8) | 协议(8) | 头部校验和(16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 选项 + 填充 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
数据体
注:头部长度单位是4字节,所以ip头最长60字节,选项最长40字节,选项填充按4字节对齐
*/
pub struct IpV4Packet<B> {
pub buffer: B,
}
impl<B: AsRef<[u8]>> IpV4Packet<B> {
pub fn unchecked(buffer: B) -> Self {
Self { buffer }
}
pub fn new(buffer: B) -> Result<Self> {
if buffer.as_ref()[0] >> 4 != 4 {
Err(Error::Unimplemented)?
}
if buffer.as_ref().len() < 20 {
Err(Error::SmallBuffer)?
}
let packet = Self::unchecked(buffer);
if packet.buffer.as_ref().len() < packet.header_len() as usize * 4 {
Err(Error::SmallBuffer)?
}
Ok(packet)
}
}
impl<B: AsRef<[u8]>> IpV4Packet<B> {
pub fn header(&self) -> &[u8] {
&self.buffer.as_ref()[..(self.header_len() as usize * 4)]
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[(self.header_len() as usize * 4)..]
// match self.protocol() {
// Protocol::Udp => {
// let udp = UdpPacket::new(IpAddr::V4(self.source_ip()),
// IpAddr::V4(self.destination_ip()),
// &self.buffer.as_ref()[(self.header_len() as usize * 4)..])?;
// Ok(crate::IpUpperLayer::UDP(udp))
// }
// _ => {
// Ok(crate::IpUpperLayer::Unknown(self.buffer.as_ref()));
// }
// }
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
pub fn header_mut(&mut self) -> &mut [u8] {
let len = self.header_len() as usize * 4;
&mut self.buffer.as_mut()[..len]
}
pub fn payload_mut(&mut self) -> &mut [u8] {
let len = self.header_len() as usize * 4;
&mut self.buffer.as_mut()[len..]
}
pub fn set_source_ip(&mut self, value: Ipv4Addr) {
self.header_mut()[12..16].copy_from_slice(&value.octets());
}
pub fn set_destination_ip(&mut self, value: Ipv4Addr) {
self.header_mut()[16..20].copy_from_slice(&value.octets());
}
fn set_checksum(&mut self, value: u16) {
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
}
/// 更新校验和
pub fn update_checksum(&mut self) {
//先将校验和置0
self.set_checksum(0);
self.set_checksum(cal_checksum(self.header()))
}
}
impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// 版本号,ipv4的为4
pub fn version(&self) -> u8 {
self.buffer.as_ref()[0] >> 4
}
/// 头部长度,以4字节为单位
pub fn header_len(&self) -> u8 {
self.buffer.as_ref()[0] & 0b1111
}
/// 差异化服务编码点
///
/// 类别(3)+丢失概率(2)+用途(1)
///
///
/// 类别子字段值 | 名称
/// ---|:---
/// 000 | 常规(Routine)
/// 001 | 优先(Priority)
/// 010 | 立即(Immediate)
/// 011 | 瞬间(Flash)
/// 100 | 瞬间覆盖(Flash Override)
/// 101 | 严重(CRITIC/ECP)
/// 110 | 网间控制(Internetwork Control)
/// 111 | 网络控制(Network Control)
///
///
/// 参考:https://www.modb.pro/db/477116
pub fn dscp(&self) -> u8 {
self.buffer.as_ref()[1] >> 2
}
/// 显示拥塞 00:发送主机不支持ECN 01或者10:发送主机支持ECN 11:路由器正在经历拥塞
pub fn ecn(&self) -> u8 {
self.buffer.as_ref()[1] & 0b11
}
/// ip报总字节数
pub fn length(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
pub fn id(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 标志 3位.
/// 第1位没有使用
/// 第2位表示不分段位(DF
/// 0:允许数据报分段
/// 1:数据报不能分段
/// 置1之后路由器不能对其分段处理,如果超过MTU值则路由器不能对其转发将其丢弃,并向源点发送错误消息
/// 第3位表示更多段位
/// 0:数据包后面没有包,该包为最后的包
/// 1:数据包后面有更多的包
pub fn flags(&self) -> u8 {
self.buffer.as_ref()[6] >> 5
}
/// 片偏移 13位.
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
pub fn offset(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
& 0x1fff
}
/// 生存时间.
/// 每一跳 减1 到0了则会被丢弃
pub fn ttl(&self) -> u8 {
self.buffer.as_ref()[8]
}
/// 协议.
pub fn protocol(&self) -> Protocol {
self.buffer.as_ref()[9].into()
}
/// 首部校验和
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[10..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 验证校验和
///
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
/// 所以抓到发出去的包校验和可能是错误的
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || cal_checksum(self.header()) == 0
}
/// 源ip.
pub fn source_ip(&self) -> Ipv4Addr {
Ipv4Addr::new(
self.buffer.as_ref()[12],
self.buffer.as_ref()[13],
self.buffer.as_ref()[14],
self.buffer.as_ref()[15],
)
}
/// 目标ip.
pub fn destination_ip(&self) -> Ipv4Addr {
Ipv4Addr::new(
self.buffer.as_ref()[16],
self.buffer.as_ref()[17],
self.buffer.as_ref()[18],
self.buffer.as_ref()[19],
)
}
/// 选项.
pub fn options(&self) -> &[u8] {
&self.buffer.as_ref()[20..(self.header_len() as usize * 4)]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for IpV4Packet<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ip::v4::Packet")
.field("version", &self.version())
.field("header_len", &self.header_len())
.field("dscp", &self.dscp())
.field("ecn", &self.ecn())
.field("length", &self.length())
.field("id", &self.id())
.field("flags", &self.flags())
.field("offset", &self.offset())
.field("ttl", &self.ttl())
.field("protocol", &self.protocol())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("source", &self.source_ip())
.field("destination", &self.destination_ip())
.field("options", &self.options())
.field("payload", &self.payload())
.finish()
}
}
+742
View File
@@ -0,0 +1,742 @@
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
///
Hopopt,
///
Icmp,
///
Igmp,
///
Ggp,
///
Ipv4,
///
St,
///
Tcp,
///
Cbt,
///
Egp,
///
Igp,
///
BbnRccMon,
///
NvpII,
///
Pup,
///
Argus,
///
Emcon,
///
Xnet,
///
Chaos,
///
Udp,
///
Mux,
///
DcnMeas,
///
Hmp,
///
Prm,
///
XnsIdp,
///
Trunk1,
///
Trunk2,
///
Leaf1,
///
Leaf2,
///
Rdp,
///
Irtp,
///
IsoTp4,
///
Netblt,
///
MfeNsp,
///
MeritInp,
///
Dccp,
///
ThreePc,
///
Idpr,
///
Xtp,
///
Ddp,
///
IdprCmtp,
///
TpPlusPlus,
///
Il,
///
Ipv6,
///
Sdrp,
///
Ipv6Route,
///
Ipv6Frag,
///
Idrp,
///
Rsvp,
///
Gre,
///
Dsr,
///
Bna,
///
Esp,
///
Ah,
///
INlsp,
///
Swipe,
///
Narp,
///
Mobile,
///
Tlsp,
///
Skip,
///
Ipv6Icmp,
///
Ipv6NoNxt,
///
Ipv6Opts,
///
HostInternal,
///
Cftp,
///
LocalNetwork,
///
SatExpak,
///
Kryptolan,
///
Rvd,
///
Ippc,
///
DistributedFs,
///
SatMon,
///
Visa,
///
Ipcv,
///
Cpnx,
///
Cphb,
///
Wsn,
///
Pvp,
///
BrSatMon,
///
SunNd,
///
WbMon,
///
WbExpak,
///
IsoIp,
///
Vmtp,
///
SecureVmtp,
///
Vines,
///
TtpOrIptm,
///
NsfnetIgp,
///
Dgp,
///
Tcf,
///
Eigrp,
///
OspfigP,
///
SpriteRpc,
///
Larp,
///
Mtp,
///
Ax25,
///
IpIp,
///
Micp,
///
SccSp,
///
Etherip,
///
Encap,
///
PrivEncryption,
///
Gmtp,
///
Ifmp,
///
Pnni,
///
Pim,
///
Aris,
///
Scps,
///
Qnx,
///
AN,
///
IpComp,
///
Snp,
///
CompaqPeer,
///
IpxInIp,
///
Vrrp,
///
Pgm,
///
ZeroHop,
///
L2tp,
///
Ddx,
///
Iatp,
///
Stp,
///
Srp,
///
Uti,
///
Smp,
///
Sm,
///
Ptp,
///
IsisOverIpv4,
///
Fire,
///
Crtp,
///
Crudp,
///
Sscopmce,
///
Iplt,
///
Sps,
///
Pipe,
///
Sctp,
///
Fc,
///
RsvpE2eIgnore,
///
MobilityHeader,
///
UdpLite,
///
MplsInIp,
///
Manet,
///
Hip,
///
Shim6,
///
Wesp,
Rohc,
Test1,
Test2,
Unknown(u8),
}
impl From<u8> for Protocol {
fn from(value: u8) -> Protocol {
use self::Protocol::*;
match value {
0 => Hopopt,
1 => Icmp,
2 => Igmp,
3 => Ggp,
4 => Ipv4,
5 => St,
6 => Tcp,
7 => Cbt,
8 => Egp,
9 => Igp,
10 => BbnRccMon,
11 => NvpII,
12 => Pup,
13 => Argus,
14 => Emcon,
15 => Xnet,
16 => Chaos,
17 => Udp,
18 => Mux,
19 => DcnMeas,
20 => Hmp,
21 => Prm,
22 => XnsIdp,
23 => Trunk1,
24 => Trunk2,
25 => Leaf1,
26 => Leaf2,
27 => Rdp,
28 => Irtp,
29 => IsoTp4,
30 => Netblt,
31 => MfeNsp,
32 => MeritInp,
33 => Dccp,
34 => ThreePc,
35 => Idpr,
36 => Xtp,
37 => Ddp,
38 => IdprCmtp,
39 => TpPlusPlus,
40 => Il,
41 => Ipv6,
42 => Sdrp,
43 => Ipv6Route,
44 => Ipv6Frag,
45 => Idrp,
46 => Rsvp,
47 => Gre,
48 => Dsr,
49 => Bna,
50 => Esp,
51 => Ah,
52 => INlsp,
53 => Swipe,
54 => Narp,
55 => Mobile,
56 => Tlsp,
57 => Skip,
58 => Ipv6Icmp,
59 => Ipv6NoNxt,
60 => Ipv6Opts,
61 => HostInternal,
62 => Cftp,
63 => LocalNetwork,
64 => SatExpak,
65 => Kryptolan,
66 => Rvd,
67 => Ippc,
68 => DistributedFs,
69 => SatMon,
70 => Visa,
71 => Ipcv,
72 => Cpnx,
73 => Cphb,
74 => Wsn,
75 => Pvp,
76 => BrSatMon,
77 => SunNd,
78 => WbMon,
79 => WbExpak,
80 => IsoIp,
81 => Vmtp,
82 => SecureVmtp,
83 => Vines,
84 => TtpOrIptm,
85 => NsfnetIgp,
86 => Dgp,
87 => Tcf,
88 => Eigrp,
89 => OspfigP,
90 => SpriteRpc,
91 => Larp,
92 => Mtp,
93 => Ax25,
94 => IpIp,
95 => Micp,
96 => SccSp,
97 => Etherip,
98 => Encap,
99 => PrivEncryption,
100 => Gmtp,
101 => Ifmp,
102 => Pnni,
103 => Pim,
104 => Aris,
105 => Scps,
106 => Qnx,
107 => AN,
108 => IpComp,
109 => Snp,
110 => CompaqPeer,
111 => IpxInIp,
112 => Vrrp,
113 => Pgm,
114 => ZeroHop,
115 => L2tp,
116 => Ddx,
117 => Iatp,
118 => Stp,
119 => Srp,
120 => Uti,
121 => Smp,
122 => Sm,
123 => Ptp,
124 => IsisOverIpv4,
125 => Fire,
126 => Crtp,
127 => Crudp,
128 => Sscopmce,
129 => Iplt,
130 => Sps,
131 => Pipe,
132 => Sctp,
133 => Fc,
134 => RsvpE2eIgnore,
135 => MobilityHeader,
136 => UdpLite,
137 => MplsInIp,
138 => Manet,
139 => Hip,
140 => Shim6,
141 => Wesp,
142 => Rohc,
253 => Test1,
254 => Test2,
p => Unknown(p),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
use self::Protocol::*;
match self {
Hopopt => 0,
Icmp => 1,
Igmp => 2,
Ggp => 3,
Ipv4 => 4,
St => 5,
Tcp => 6,
Cbt => 7,
Egp => 8,
Igp => 9,
BbnRccMon => 10,
NvpII => 11,
Pup => 12,
Argus => 13,
Emcon => 14,
Xnet => 15,
Chaos => 16,
Udp => 17,
Mux => 18,
DcnMeas => 19,
Hmp => 20,
Prm => 21,
XnsIdp => 22,
Trunk1 => 23,
Trunk2 => 24,
Leaf1 => 25,
Leaf2 => 26,
Rdp => 27,
Irtp => 28,
IsoTp4 => 29,
Netblt => 30,
MfeNsp => 31,
MeritInp => 32,
Dccp => 33,
ThreePc => 34,
Idpr => 35,
Xtp => 36,
Ddp => 37,
IdprCmtp => 38,
TpPlusPlus => 39,
Il => 40,
Ipv6 => 41,
Sdrp => 42,
Ipv6Route => 43,
Ipv6Frag => 44,
Idrp => 45,
Rsvp => 46,
Gre => 47,
Dsr => 48,
Bna => 49,
Esp => 50,
Ah => 51,
INlsp => 52,
Swipe => 53,
Narp => 54,
Mobile => 55,
Tlsp => 56,
Skip => 57,
Ipv6Icmp => 58,
Ipv6NoNxt => 59,
Ipv6Opts => 60,
HostInternal => 61,
Cftp => 62,
LocalNetwork => 63,
SatExpak => 64,
Kryptolan => 65,
Rvd => 66,
Ippc => 67,
DistributedFs => 68,
SatMon => 69,
Visa => 70,
Ipcv => 71,
Cpnx => 72,
Cphb => 73,
Wsn => 74,
Pvp => 75,
BrSatMon => 76,
SunNd => 77,
WbMon => 78,
WbExpak => 79,
IsoIp => 80,
Vmtp => 81,
SecureVmtp => 82,
Vines => 83,
TtpOrIptm => 84,
NsfnetIgp => 85,
Dgp => 86,
Tcf => 87,
Eigrp => 88,
OspfigP => 89,
SpriteRpc => 90,
Larp => 91,
Mtp => 92,
Ax25 => 93,
IpIp => 94,
Micp => 95,
SccSp => 96,
Etherip => 97,
Encap => 98,
PrivEncryption => 99,
Gmtp => 100,
Ifmp => 101,
Pnni => 102,
Pim => 103,
Aris => 104,
Scps => 105,
Qnx => 106,
AN => 107,
IpComp => 108,
Snp => 109,
CompaqPeer => 110,
IpxInIp => 111,
Vrrp => 112,
Pgm => 113,
ZeroHop => 114,
L2tp => 115,
Ddx => 116,
Iatp => 117,
Stp => 118,
Srp => 119,
Uti => 120,
Smp => 121,
Sm => 122,
Ptp => 123,
IsisOverIpv4 => 124,
Fire => 125,
Crtp => 126,
Crudp => 127,
Sscopmce => 128,
Iplt => 129,
Sps => 130,
Pipe => 131,
Sctp => 132,
Fc => 133,
RsvpE2eIgnore => 134,
MobilityHeader => 135,
UdpLite => 136,
MplsInIp => 137,
Manet => 138,
Hip => 139,
Shim6 => 140,
Wesp => 141,
Rohc => 142,
Test1 => 253,
Test2 => 254,
Unknown(p) => p,
}
}
}
+18
View File
@@ -0,0 +1,18 @@
use ipv4::packet::IpV4Packet;
use crate::error::*;
pub mod ipv4;
pub enum IpPacket<B> {
V4(IpV4Packet<B>),
}
impl<B: AsRef<[u8]>> IpPacket<B> {
pub fn new(buffer: B) -> Result<Self> {
match buffer.as_ref()[0] >> 4 {
4 => Ok(IpPacket::V4(IpV4Packet::new(buffer)?)),
_ => Err(Error::InvalidPacket),
}
}
}
+146
View File
@@ -0,0 +1,146 @@
use std::net::Ipv4Addr;
use byteorder::BigEndian;
use byteorder::ReadBytesExt;
pub mod error;
pub mod icmp;
pub mod ip;
pub mod tcp;
pub mod udp;
// pub enum IpUpperLayer<B> {
// UDP(UdpPacket<B>),
// Unknown(B),
// }
//
// impl<B: AsRef<[u8]>> fmt::Debug for IpUpperLayer<B> {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// match self {
// IpUpperLayer::UDP(p) => {
// f.debug_struct("udp::Packet")
// .field("data", p).finish()
// }
// IpUpperLayer::Unknown(p) => {
// f.debug_struct("Unknown")
// .field("data", &p.as_ref()).finish()
// }
// }
// }
// }
/// https://datatracker.ietf.org/doc/html/rfc1071 4.1节
///
/// 计算校验和,各协议都是通用的
/// 计算:
/// 首先将校验和置0,然后对首部每个16位数进行二进制反码求和,
/// 得到校验和之后,持续取高16位加到低16位,直到高16位全为0
/// 最后取反
///
/// 校验:
/// 在已有校验和的情况下,再计算校验和,正确的数据计算得到的值为0
/*
unsigned short getChecksum(unsigned short * iphead, int count)
{
unsigned long int sum = 0;
unsigned short checksum = 0;
printf("\nStarting adress: %p\n", iphead);
while(count > 1) {
sum += * (unsigned short *) (iphead);
count -=2;
printf("a: %p, content is: %d, new sum: %ld\n", iphead, (unsigned short) *(iphead), sum);
iphead++;
}
if(count > 0) {
sum += * (unsigned short *) (iphead);
}
while(sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
checksum = ~sum;
return checksum;
}
*/
pub fn cal_checksum(buffer: &[u8]) -> u16 {
use std::io::Cursor;
let mut sum = 0;
let length = buffer.len();
let mut buffer = Cursor::new(buffer);
while let Ok(value) = buffer.read_u16::<BigEndian>() {
sum += u32::from(value);
}
if length & 1 == 1 {
//奇数,说明还有一位,不足的补0
sum += u32c(buffer.read_u8().unwrap(), 0);
}
while sum >> 16 != 0 {
sum = (sum & 0xffff) + (sum >> 16);
}
!sum as u16
}
/// ipv4上层协议校验和计算方式
/// ipv4 udp伪首部 用于参与计算首部校验和
/*
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| source address |
+--------+--------+--------+--------+
| destination address |
+--------+--------+--------+--------+
| zero |protocol| length |
+--------+--------+--------+--------+
*/
pub fn ipv4_cal_checksum(
buffer: &[u8],
src_ip: &Ipv4Addr,
dest_ip: &Ipv4Addr,
protocol: u8,
length: u16,
) -> u16 {
use std::io::Cursor;
let mut sum = 0;
let src_ip = src_ip.octets();
sum += u32c(src_ip[0], src_ip[1]);
sum += u32c(src_ip[2], src_ip[3]);
let dest_ip = dest_ip.octets();
sum += u32c(dest_ip[0], dest_ip[1]);
sum += u32c(dest_ip[2], dest_ip[3]);
sum += u32c(0, protocol);
sum += length as u32;
let mut buffer = Cursor::new(buffer);
while let Ok(value) = buffer.read_u16::<BigEndian>() {
sum += u32::from(value);
}
if length & 1 == 1 {
//奇数,说明还有一位
sum += u32c(buffer.read_u8().unwrap(), 0);
}
while sum >> 16 != 0 {
sum = (sum & 0xffff) + (sum >> 16);
}
!sum as u16
}
#[inline]
fn u32c(x: u8, y: u8) -> u32 {
((x as u32) << 8) | y as u32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let sum = cal_checksum(&[255, 255]);
println!("{:?}", sum);
}
}
+42
View File
@@ -0,0 +1,42 @@
use std::fmt;
pub mod tcp;
pub struct Flags(u8);
pub const FIN: u8 = 0b0000_0001;
pub const SYN: u8 = 0b0000_0010;
pub const RST: u8 = 0b0000_0100;
pub const PSH: u8 = 0b0000_1000;
pub const ACK: u8 = 0b0001_0000;
pub const URG: u8 = 0b0010_0000;
impl fmt::Debug for Flags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut str = String::with_capacity(22);
if self.0 & URG != 0 {
str.push_str("URG|");
}
if self.0 & ACK != 0 {
str.push_str("ACK|");
}
if self.0 & PSH != 0 {
str.push_str("PSH|");
}
if self.0 & RST != 0 {
str.push_str("RST|");
}
if self.0 & SYN != 0 {
str.push_str("SYN|");
}
if self.0 & FIN != 0 {
str.push_str("FIN|");
}
if str.is_empty() {
f.debug_struct("NULL").finish()
} else {
let len = str.len() - 1;
f.debug_struct(&str[..len]).finish()
}
}
}
+175
View File
@@ -0,0 +1,175 @@
use std::fmt;
use std::net::IpAddr;
use byteorder::{BigEndian, ReadBytesExt};
use crate::error::*;
use crate::tcp::Flags;
/// tcp
/*
https://www.rfc-editor.org/rfc/rfc793
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Source Port: 16位 源端口
Destination Port:16位 目的端口
Sequence Number:32位 序列号,如果存在syn标志,则为初始序列号
Acknowledgment Number:32位 如果设置了ack标志,这个表示确认收到的序号
Data Offset:4位 数据的开始偏移位,单位是4字节
Reserved:6位 未使用,全零
控制位:6位 从左到右
URG: 紧急指针 表示数据要优先处理
ACK: 确认位
PSH: 推送 要求把数据尽快的交给应用层,不做处理
RST: 重置连接
SYN: 同步序列号
FIN: 结束发送
Window: 16位 能接收的数据大小
Checksum:16位 校验和,需要加入伪首部
Urgent Pointer:16位 紧急指针
Options+Padding:32位整数倍,最多40个字节
*/
pub struct TcpPacket<B> {
source_ip: IpAddr,
destination_ip: IpAddr,
buffer: B,
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> TcpPacket<B> {
TcpPacket {
source_ip,
destination_ip,
buffer,
}
}
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<TcpPacket<B>> {
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
if packet.buffer.as_ref().len() < 20 {
Err(Error::SmallBuffer)?
}
if packet.buffer.as_ref().len() < packet.data_offset() as usize * 4 {
Err(Error::SmallBuffer)?
}
Ok(packet)
}
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
/// 源端口
pub fn source_port(&self) -> u16 {
(&self.buffer.as_ref()[0..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 目标端口
pub fn destination_port(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 序列号
pub fn sequence(&self) -> u32 {
(&self.buffer.as_ref()[4..])
.read_u32::<BigEndian>()
.unwrap()
}
/// 确认号
pub fn acknowledgment(&self) -> u32 {
(&self.buffer.as_ref()[8..])
.read_u32::<BigEndian>()
.unwrap()
}
/// 数据偏移 4字节为单位
pub fn data_offset(&self) -> u8 {
self.buffer.as_ref()[12] >> 4
}
pub fn flags(&self) -> Flags {
Flags(self.buffer.as_ref()[13])
}
pub fn window(&self) -> u16 {
(&self.buffer.as_ref()[14..])
.read_u16::<BigEndian>()
.unwrap()
}
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[16..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
/// 所以抓到发出去的包校验和可能是错误的
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || self.cal_checksum() == 0
}
fn cal_checksum(&self) -> u16 {
match self.source_ip {
IpAddr::V4(src) => {
if let IpAddr::V4(dest) = self.destination_ip {
return crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&src,
&dest,
6,
self.buffer.as_ref().len() as u16,
);
}
}
IpAddr::V6(_src) => {}
}
unimplemented!()
}
pub fn urgent_pointer(&self) -> u16 {
(&self.buffer.as_ref()[18..])
.read_u16::<BigEndian>()
.unwrap()
}
pub fn options(&self) -> &[u8] {
&self.buffer.as_ref()[20..(self.data_offset() as usize * 4)]
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[(self.data_offset() as usize * 4)..]
}
}
impl<B: AsRef<[u8]>> fmt::Debug for TcpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("tcp::Packet")
.field("source", &self.source_port())
.field("destination", &self.destination_port())
.field("sequence", &self.sequence())
.field("acknowledgment", &self.acknowledgment())
.field("offset", &self.data_offset())
.field("flags", &self.flags())
.field("window", &self.window())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("pointer", &self.urgent_pointer())
.field("options", &self.options())
.field("payload", &self.payload())
.finish()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod udp;
+177
View File
@@ -0,0 +1,177 @@
use std::fmt;
use std::io::Cursor;
use std::net::IpAddr;
use byteorder::WriteBytesExt;
use byteorder::{BigEndian, ReadBytesExt};
use crate::error::*;
/// udp协议
///
/*
RFC 768 https://www.ietf.org/rfc/rfc768.txt
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| 源端口(16) | 目的端口(16) |
+--------+--------+--------+--------+
| 长度(16) | 校验和(16) |
+--------+--------+--------+--------+
|
| 载荷 ...
+---------------- ...
注:1.长度包含标头和数据体,以字节为单位
2.伪首部和载荷参与校验和的计算,位数不够则补0
*/
/// ipv6 udp伪首部
/* https://datatracker.ietf.org/doc/html/rfc2460
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Upper-Layer Packet Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| zero | Next Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
pub struct UdpPacket<B> {
source_ip: IpAddr,
destination_ip: IpAddr,
buffer: B,
}
impl<B: AsRef<[u8]>> UdpPacket<B> {
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> UdpPacket<B> {
UdpPacket {
source_ip,
destination_ip,
buffer,
}
}
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<UdpPacket<B>> {
if buffer.as_ref().len() < 8 {
Err(Error::SmallBuffer)?
}
let packet = Self::unchecked(source_ip, destination_ip, buffer);
Ok(packet)
}
}
impl<B: AsRef<[u8]>> UdpPacket<B> {
/// 源端口
pub fn source_port(&self) -> u16 {
(&self.buffer.as_ref()[0..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 目标端口
pub fn destination_port(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 总字节数
pub fn length(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
}
/// Checksum of the packet.
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
}
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
pub fn is_valid(&self) -> bool {
self.checksum() == 0 || self.cal_checksum() == 0
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[8..]
}
fn cal_checksum(&self) -> u16 {
match self.source_ip {
IpAddr::V4(src) => {
if let IpAddr::V4(dest) = self.destination_ip {
return crate::ipv4_cal_checksum(
self.buffer.as_ref(),
&src,
&dest,
17,
self.length(),
);
}
}
IpAddr::V6(_src) => {}
}
unimplemented!()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
fn header_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..8]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
/// 设置源端口
pub fn set_source_port(&mut self, value: u16) -> &mut Self {
Cursor::new(&mut self.header_mut()[0..])
.write_u16::<BigEndian>(value)
.unwrap();
self
}
/// 设置目的端口
pub fn set_destination_port(&mut self, value: u16) -> &mut Self {
Cursor::new(&mut self.header_mut()[2..])
.write_u16::<BigEndian>(value)
.unwrap();
self
}
fn set_checknum(&mut self, value: u16) {
Cursor::new(&mut self.header_mut()[6..])
.write_u16::<BigEndian>(value)
.unwrap();
}
pub fn update_checknum(&mut self) {
//先写0
self.set_checknum(0);
self.set_checknum(self.cal_checksum());
}
}
impl<B: AsRef<[u8]>> fmt::Debug for UdpPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("udp::Packet")
.field("source", &self.source_port())
.field("destination", &self.destination_port())
.field("length", &self.length())
.field("checksum", &self.checksum())
.field("is_valid", &self.is_valid())
.field("payload", &self.payload())
.finish()
}
}
+40
View File
@@ -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;
}
+45
View File
@@ -0,0 +1,45 @@
[package]
name = "tun"
version = "0.5.4"
edition = "2018"
authors = ["meh. <[email protected]>"]
license = "WTFPL"
description = "TUN device creation and handling."
repository = "https://github.com/meh/rust-tun"
keywords = ["tun", "network", "tunnel", "bindings"]
[dependencies]
libc = "0.2"
thiserror = "1"
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "android"))'.dependencies]
tokio = { version = "1", features = ["net", "macros"], optional = true }
tokio-util = { version = "0.6", features = ["codec"], optional = true }
bytes = { version = "1", optional = true }
byteorder = { version = "1", optional = true }
# This is only for the `ready` macro.
futures-core = { version = "0.3", optional = true }
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.6", package = "ioctl-sys" }
[dev-dependencies]
packet = "0.1"
futures = "0.3"
[features]
async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"]
[[example]]
name = "read-async"
required-features = [ "async", "tokio/rt-multi-thread" ]
[[example]]
name = "read-async-codec"
required-features = [ "async", "tokio/rt-multi-thread" ]
[[example]]
name = "ping-tun"
required-features = [ "async", "tokio/rt-multi-thread" ]
+106
View File
@@ -0,0 +1,106 @@
TUN interfaces [![Crates.io](https://img.shields.io/crates/v/tun.svg)](https://crates.io/crates/tun) ![tun](https://docs.rs/tun/badge.svg) ![WTFPL](http://img.shields.io/badge/license-WTFPL-blue.svg)
==============
This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform.
Usage
-----
First, add the following to your `Cargo.toml`:
```toml
[dependencies]
tun = "0.5"
```
Next, add this to your crate root:
```rust
extern crate tun;
```
If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature:
```toml
[dependencies]
tun = { version = "0.5", features = ["async"] }
```
Example
-------
The following example creates and configures a TUN interface and starts reading
packets from it.
```rust
use std::io::Read;
extern crate tun;
fn main() {
let mut config = tun::Configuration::default();
config.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let mut dev = tun::create(&config).unwrap();
let mut buf = [0; 4096];
loop {
let amount = dev.read(&mut buf).unwrap();
println!("{:?}", &buf[0 .. amount]);
}
}
```
Platforms
=========
Not every platform is supported.
Linux
-----
You will need the `tun` module to be loaded and root is required to create
interfaces.
macOS
-----
It just werks, but you have to set up routing manually.
iOS
----
You can pass the file descriptor of the TUN device to `rust-tun` to create the interface.
Here is an example to create the TUN device on iOS and pass the `fd` to `rust-tun`:
```swift
// Swift
class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let tunnelNetworkSettings = createTunnelSettings() // Configure TUN address, DNS, mtu, routing...
setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in
let tunFd = self?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32
DispatchQueue.global(qos: .default).async {
start_tun(tunFd)
}
completionHandler(nil)
}
}
}
```
```rust
#[no_mangle]
pub extern "C" fn start_tun(fd: std::os::raw::c_int) {
let mut rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let mut cfg = tun::Configuration::default();
cfg.raw_fd(fd);
let mut tun = tun::create_as_async(&cfg).unwrap();
let mut framed = tun.into_framed();
while let Some(packet) = framed.next().await {
...
}
});
}
```
+78
View File
@@ -0,0 +1,78 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use futures::{SinkExt, StreamExt};
use packet::{builder::Builder, icmp, ip, Packet};
use tun::{self, Configuration, TunPacket};
#[tokio::main]
async fn main() {
let mut config = Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let dev = tun::create_as_async(&config).unwrap();
let mut framed = dev.into_framed();
while let Some(packet) = framed.next().await {
match packet {
Ok(pkt) => match ip::Packet::new(pkt.get_bytes()) {
Ok(ip::Packet::V4(pkt)) => match icmp::Packet::new(pkt.payload()) {
Ok(icmp) => match icmp.echo() {
Ok(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();
framed.send(TunPacket::new(reply)).await.unwrap();
}
_ => {}
},
_ => {}
},
Err(err) => println!("Received an invalid packet: {:?}", err),
_ => {}
},
Err(err) => panic!("Error: {:?}", err),
}
}
}
@@ -0,0 +1,61 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use bytes::BytesMut;
use futures::StreamExt;
use packet::{ip::Packet, Error};
use tokio_util::codec::{Decoder, FramedRead};
pub struct IPPacketCodec;
impl Decoder for IPPacketCodec {
type Item = Packet<BytesMut>;
type Error = Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if buf.is_empty() {
return Ok(None);
}
let buf = buf.split_to(buf.len());
Ok(match Packet::no_payload(buf) {
Ok(pkt) => Some(pkt),
Err(err) => {
println!("error {:?}", err);
None
}
})
}
}
#[tokio::main]
async fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
let dev = tun::create_as_async(&config).unwrap();
let mut stream = FramedRead::new(dev, IPPacketCodec);
while let Some(packet) = stream.next().await {
match packet {
Ok(pkt) => println!("pkt: {:#?}", pkt),
Err(err) => panic!("Error: {:?}", err),
}
}
}
+42
View File
@@ -0,0 +1,42 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use futures::StreamExt;
use packet::ip::Packet;
#[tokio::main]
async fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let dev = tun::create_as_async(&config).unwrap();
let mut stream = dev.into_framed();
while let Some(packet) = stream.next().await {
match packet {
Ok(pkt) => println!("pkt: {:#?}", Packet::unchecked(pkt.get_bytes())),
Err(err) => panic!("Error: {:?}", err),
}
}
}
+37
View File
@@ -0,0 +1,37 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::Read;
fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 1))
.netmask((255, 255, 255, 0))
.up();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
let mut dev = tun::create(&config).unwrap();
let mut buf = [0; 4096];
loop {
let amount = dev.read(&mut buf).unwrap();
println!("{:?}", &buf[0..amount]);
}
}
+128
View File
@@ -0,0 +1,128 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::net::{IpAddr, Ipv4Addr};
use std::net::{SocketAddr, SocketAddrV4};
use crate::error::*;
/// Helper trait to convert things into IPv4 addresses.
#[allow(clippy::wrong_self_convention)]
pub trait IntoAddress {
/// Convert the type to an `Ipv4Addr`.
fn into_address(&self) -> Result<Ipv4Addr>;
}
impl IntoAddress for u32 {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(Ipv4Addr::new(
((*self) & 0xff) as u8,
((*self >> 8) & 0xff) as u8,
((*self >> 16) & 0xff) as u8,
((*self >> 24) & 0xff) as u8,
))
}
}
impl IntoAddress for i32 {
fn into_address(&self) -> Result<Ipv4Addr> {
(*self as u32).into_address()
}
}
impl IntoAddress for (u8, u8, u8, u8) {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(Ipv4Addr::new(self.0, self.1, self.2, self.3))
}
}
impl IntoAddress for str {
fn into_address(&self) -> Result<Ipv4Addr> {
self.parse().map_err(|_| Error::InvalidAddress)
}
}
impl<'a> IntoAddress for &'a str {
fn into_address(&self) -> Result<Ipv4Addr> {
(*self).into_address()
}
}
impl IntoAddress for String {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl<'a> IntoAddress for &'a String {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for Ipv4Addr {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(*self)
}
}
impl<'a> IntoAddress for &'a Ipv4Addr {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for IpAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
match *self {
IpAddr::V4(ref value) => Ok(*value),
IpAddr::V6(_) => Err(Error::InvalidAddress),
}
}
}
impl<'a> IntoAddress for &'a IpAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for SocketAddrV4 {
fn into_address(&self) -> Result<Ipv4Addr> {
Ok(*self.ip())
}
}
impl<'a> IntoAddress for &'a SocketAddrV4 {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
impl IntoAddress for SocketAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
match *self {
SocketAddr::V4(ref value) => Ok(*value.ip()),
SocketAddr::V6(_) => Err(Error::InvalidAddress),
}
}
}
impl<'a> IntoAddress for &'a SocketAddr {
fn into_address(&self) -> Result<Ipv4Addr> {
(&**self).into_address()
}
}
+149
View File
@@ -0,0 +1,149 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io;
use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt};
use bytes::{BufMut, Bytes, BytesMut};
use tokio_util::codec::{Decoder, Encoder};
/// A packet protocol IP version
#[derive(Debug)]
enum PacketProtocol {
IPv4,
IPv6,
Other(u8),
}
// Note: the protocol in the packet information header is platform dependent.
impl PacketProtocol {
#[cfg(any(target_os = "linux", target_os = "android"))]
fn into_pi_field(&self) -> Result<u16, io::Error> {
match self {
PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16),
PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16),
PacketProtocol::Other(_) => Err(io::Error::new(
io::ErrorKind::Other,
"neither an IPv4 or IPv6 packet",
)),
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn into_pi_field(&self) -> Result<u16, io::Error> {
match self {
PacketProtocol::IPv4 => Ok(libc::PF_INET as u16),
PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16),
PacketProtocol::Other(_) => Err(io::Error::new(
io::ErrorKind::Other,
"neither an IPv4 or IPv6 packet",
)),
}
}
}
/// A Tun Packet to be sent or received on the TUN interface.
#[derive(Debug)]
pub struct TunPacket(PacketProtocol, Bytes);
/// Infer the protocol based on the first nibble in the packet buffer.
fn infer_proto(buf: &[u8]) -> PacketProtocol {
match buf[0] >> 4 {
4 => PacketProtocol::IPv4,
6 => PacketProtocol::IPv6,
p => PacketProtocol::Other(p),
}
}
impl TunPacket {
/// Create a new `TunPacket` based on a byte slice.
pub fn new(bytes: Vec<u8>) -> TunPacket {
let proto = infer_proto(&bytes);
TunPacket(proto, Bytes::from(bytes))
}
/// Return this packet's bytes.
pub fn get_bytes(&self) -> &[u8] {
&self.1
}
pub fn into_bytes(self) -> Bytes {
self.1
}
}
/// A TunPacket Encoder/Decoder.
pub struct TunPacketCodec(bool, i32);
impl TunPacketCodec {
/// Create a new `TunPacketCodec` specifying whether the underlying
/// tunnel Device has enabled the packet information header.
pub fn new(pi: bool, mtu: i32) -> TunPacketCodec {
TunPacketCodec(pi, mtu)
}
}
impl Decoder for TunPacketCodec {
type Item = TunPacket;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if buf.is_empty() {
return Ok(None);
}
let mut pkt = buf.split_to(buf.len());
// reserve enough space for the next packet
if self.0 {
buf.reserve(self.1 as usize + 4);
} else {
buf.reserve(self.1 as usize);
}
// if the packet information is enabled we have to ignore the first 4 bytes
if self.0 {
let _ = pkt.split_to(4);
}
let proto = infer_proto(pkt.as_ref());
Ok(Some(TunPacket(proto, pkt.freeze())))
}
}
impl Encoder<TunPacket> for TunPacketCodec {
type Error = io::Error;
fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.reserve(item.get_bytes().len() + 4);
match item {
TunPacket(proto, bytes) if self.0 => {
// build the packet information header comprising of 2 u16
// fields: flags and protocol.
let mut buf = Vec::<u8>::with_capacity(4);
// flags is always 0
buf.write_u16::<NativeEndian>(0).unwrap();
// write the protocol as network byte order
buf.write_u16::<NetworkEndian>(proto.into_pi_field()?)
.unwrap();
dst.put_slice(&buf);
dst.put(bytes);
}
TunPacket(_, bytes) => dst.put(bytes),
}
Ok(())
}
}
+201
View File
@@ -0,0 +1,201 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io;
use std::io::{IoSlice, Read, Write};
use core::pin::Pin;
use core::task::{Context, Poll};
use futures_core::ready;
use tokio::io::unix::AsyncFd;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio_util::codec::Framed;
use crate::device::Device as D;
use crate::platform::{Device, Queue};
use crate::r#async::codec::*;
/// An async TUN device wrapper around a TUN device.
pub struct AsyncDevice {
inner: AsyncFd<Device>,
}
impl AsyncDevice {
/// Create a new `AsyncDevice` wrapping around a `Device`.
pub fn new(device: Device) -> io::Result<AsyncDevice> {
device.set_nonblock()?;
Ok(AsyncDevice {
inner: AsyncFd::new(device)?,
})
}
/// Returns a shared reference to the underlying Device object
pub fn get_ref(&self) -> &Device {
self.inner.get_ref()
}
/// Returns a mutable reference to the underlying Device object
pub fn get_mut(&mut self) -> &mut Device {
self.inner.get_mut()
}
/// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface)
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
let pi = self.get_mut().has_packet_information();
let codec = TunPacketCodec::new(pi, self.inner.get_ref().mtu().unwrap_or(1504));
Framed::new(self, codec)
}
}
impl AsyncRead for AsyncDevice {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf,
) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
let rbuf = buf.initialize_unfilled();
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
Err(_wb) => continue,
}
}
}
}
impl AsyncWrite for AsyncDevice {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().write(buf)) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().flush()) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_write_vectored(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[IoSlice<'_>],
) -> Poll<Result<usize, io::Error>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().write_vectored(bufs)) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn is_write_vectored(&self) -> bool {
true
}
}
/// An async TUN device queue wrapper around a TUN device queue.
pub struct AsyncQueue {
inner: AsyncFd<Queue>,
}
impl AsyncQueue {
/// Create a new `AsyncQueue` wrapping around a `Queue`.
pub fn new(queue: Queue) -> io::Result<AsyncQueue> {
queue.set_nonblock()?;
Ok(AsyncQueue {
inner: AsyncFd::new(queue)?,
})
}
/// Returns a shared reference to the underlying Queue object
pub fn get_ref(&self) -> &Queue {
self.inner.get_ref()
}
/// Returns a mutable reference to the underlying Queue object
pub fn get_mut(&mut self) -> &mut Queue {
self.inner.get_mut()
}
/// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface)
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
let pi = self.get_mut().has_packet_information();
let codec = TunPacketCodec::new(pi, 1504);
Framed::new(self, codec)
}
}
impl AsyncRead for AsyncQueue {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf,
) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
let rbuf = buf.initialize_unfilled();
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
Err(_wb) => continue,
}
}
}
}
impl AsyncWrite for AsyncQueue {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().write(buf)) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
loop {
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().flush()) {
Ok(res) => return Poll::Ready(res),
Err(_wb) => continue,
}
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
+32
View File
@@ -0,0 +1,32 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Async specific modules.
use crate::error;
use crate::configuration::Configuration;
use crate::platform::create;
mod device;
pub use self::device::{AsyncDevice, AsyncQueue};
mod codec;
pub use self::codec::{TunPacket, TunPacketCodec};
/// Create a TUN device with the given name.
pub fn create_as_async(configuration: &Configuration) -> Result<AsyncDevice, error::Error> {
let device = create(&configuration)?;
AsyncDevice::new(device).map_err(|err| err.into())
}
+126
View File
@@ -0,0 +1,126 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::net::Ipv4Addr;
use std::os::unix::io::RawFd;
use crate::address::IntoAddress;
use crate::platform;
/// TUN interface OSI layer of operation.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Layer {
L2,
L3,
}
impl Default for Layer {
fn default() -> Self {
Layer::L3
}
}
/// Configuration builder for a TUN interface.
#[derive(Clone, Default, Debug)]
pub struct Configuration {
pub(crate) name: Option<String>,
pub(crate) platform: platform::Configuration,
pub(crate) address: Option<Ipv4Addr>,
pub(crate) destination: Option<Ipv4Addr>,
pub(crate) broadcast: Option<Ipv4Addr>,
pub(crate) netmask: Option<Ipv4Addr>,
pub(crate) mtu: Option<i32>,
pub(crate) enabled: Option<bool>,
pub(crate) layer: Option<Layer>,
pub(crate) queues: Option<usize>,
pub(crate) raw_fd: Option<RawFd>,
}
impl Configuration {
/// Access the platform dependant configuration.
pub fn platform<F>(&mut self, f: F) -> &mut Self
where
F: FnOnce(&mut platform::Configuration),
{
f(&mut self.platform);
self
}
/// Set the name.
pub fn name<S: AsRef<str>>(&mut self, name: S) -> &mut Self {
self.name = Some(name.as_ref().into());
self
}
/// Set the address.
pub fn address<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.address = Some(value.into_address().unwrap());
self
}
/// Set the destination address.
pub fn destination<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.destination = Some(value.into_address().unwrap());
self
}
/// Set the broadcast address.
pub fn broadcast<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.broadcast = Some(value.into_address().unwrap());
self
}
/// Set the netmask.
pub fn netmask<A: IntoAddress>(&mut self, value: A) -> &mut Self {
self.netmask = Some(value.into_address().unwrap());
self
}
/// Set the MTU.
pub fn mtu(&mut self, value: i32) -> &mut Self {
self.mtu = Some(value);
self
}
/// Set the interface to be enabled once created.
pub fn up(&mut self) -> &mut Self {
self.enabled = Some(true);
self
}
/// Set the interface to be disabled once created.
pub fn down(&mut self) -> &mut Self {
self.enabled = Some(false);
self
}
/// Set the OSI layer of operation.
pub fn layer(&mut self, value: Layer) -> &mut Self {
self.layer = Some(value);
self
}
/// Set the number of queues.
pub fn queues(&mut self, value: usize) -> &mut Self {
self.queues = Some(value);
self
}
/// Set the raw fd.
pub fn raw_fd(&mut self, fd: RawFd) -> &mut Self {
self.raw_fd = Some(fd);
self
}
}
+95
View File
@@ -0,0 +1,95 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::{Read, Write};
use std::net::Ipv4Addr;
use crate::configuration::Configuration;
use crate::error::*;
/// A TUN device.
pub trait Device: Read + Write {
type Queue: Read + Write;
/// Reconfigure the device.
fn configure(&mut self, config: &Configuration) -> Result<()> {
if let Some(ip) = config.address {
self.set_address(ip)?;
}
if let Some(ip) = config.destination {
self.set_destination(ip)?;
}
if let Some(ip) = config.broadcast {
self.set_broadcast(ip)?;
}
if let Some(ip) = config.netmask {
self.set_netmask(ip)?;
}
if let Some(mtu) = config.mtu {
self.set_mtu(mtu)?;
}
if let Some(enabled) = config.enabled {
self.enabled(enabled)?;
}
Ok(())
}
/// Get the device name.
fn name(&self) -> &str;
/// Set the device name.
fn set_name(&mut self, name: &str) -> Result<()>;
/// Turn on or off the interface.
fn enabled(&mut self, value: bool) -> Result<()>;
/// Get the address.
fn address(&self) -> Result<Ipv4Addr>;
/// Set the address.
fn set_address(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the destination address.
fn destination(&self) -> Result<Ipv4Addr>;
/// Set the destination address.
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the broadcast address.
fn broadcast(&self) -> Result<Ipv4Addr>;
/// Set the broadcast address.
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the netmask.
fn netmask(&self) -> Result<Ipv4Addr>;
/// Set the netmask.
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()>;
/// Get the MTU.
fn mtu(&self) -> Result<i32>;
/// Set the MTU.
fn set_mtu(&mut self, value: i32) -> Result<()>;
/// Get a device queue.
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>;
}
+54
View File
@@ -0,0 +1,54 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::{ffi, io, num};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("invalid configuration")]
InvalidConfig,
#[error("not implementated")]
NotImplemented,
#[error("device name too long")]
NameTooLong,
#[error("invalid device name")]
InvalidName,
#[error("invalid address")]
InvalidAddress,
#[error("invalid file descriptor")]
InvalidDescriptor,
#[error("unsuported network layer of operation")]
UnsupportedLayer,
#[error("invalid queues number")]
InvalidQueuesNumber,
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Nul(#[from] ffi::NulError),
#[error(transparent)]
ParseNum(#[from] num::ParseIntError),
}
pub type Result<T> = ::std::result::Result<T, Error>;
+53
View File
@@ -0,0 +1,53 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
mod error;
pub use crate::error::*;
mod address;
pub use crate::address::IntoAddress;
mod device;
pub use crate::device::Device;
mod configuration;
pub use crate::configuration::{Configuration, Layer};
pub mod platform;
pub use crate::platform::create;
#[cfg(all(
feature = "async",
any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "android"
)
))]
pub mod r#async;
#[cfg(all(
feature = "async",
any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "android"
)
))]
pub use r#async::*;
pub fn configure() -> Configuration {
Configuration::default()
}
@@ -0,0 +1,214 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![allow(unused_variables)]
use std::io::{self, Read, Write};
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::Device as D;
use crate::error::*;
use crate::platform::posix::{self, Fd};
/// A TUN device for Android.
pub struct Device {
queue: Queue,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let fd = match config.raw_fd {
Some(raw_fd) => raw_fd,
_ => return Err(Error::InvalidConfig),
};
let device = {
let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?;
Device {
queue: Queue { tun: tun },
}
};
Ok(device)
}
/// Split the interface into a `Reader` and `Writer`.
pub fn split(self) -> (posix::Reader, posix::Writer) {
let fd = Arc::new(self.queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&self) -> bool {
self.queue.has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
return "";
}
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::NotImplemented)
}
fn enabled(&mut self, value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn destination(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn broadcast(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn netmask(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn mtu(&self) -> Result<i32> {
Err(Error::NotImplemented)
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
Ok(())
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
if index > 0 {
return None;
}
Some(&mut self.queue)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queue.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on Android this is always the case
false
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
@@ -0,0 +1,30 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Android specific functionality.
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// Android-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(&configuration)
}
+214
View File
@@ -0,0 +1,214 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![allow(unused_variables)]
use std::io::{self, Read, Write};
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::sync::Arc;
use crate::configuration::Configuration;
use crate::device::Device as D;
use crate::error::*;
use crate::platform::posix::{self, Fd};
/// A TUN device for iOS.
pub struct Device {
queue: Queue,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let fd = match config.raw_fd {
Some(raw_fd) => raw_fd,
_ => return Err(Error::InvalidConfig),
};
let mut device = unsafe {
let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?;
Device {
queue: Queue { tun: tun },
}
};
Ok(device)
}
/// Split the interface into a `Reader` and `Writer`.
pub fn split(self) -> (posix::Reader, posix::Writer) {
let fd = Arc::new(self.queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&self) -> bool {
self.queue.has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
return "";
}
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::NotImplemented)
}
fn enabled(&mut self, value: bool) -> Result<()> {
Ok(())
}
fn address(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn destination(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn broadcast(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn netmask(&self) -> Result<Ipv4Addr> {
Err(Error::NotImplemented)
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
Ok(())
}
fn mtu(&self) -> Result<i32> {
Err(Error::NotImplemented)
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
Ok(())
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
if index > 0 {
return None;
}
Some(&mut self.queue)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queue.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on ios this is always the case
true
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
+30
View File
@@ -0,0 +1,30 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! iOS specific functionality.
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// iOS-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(&configuration)
}
@@ -0,0 +1,457 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::ffi::{CStr, CString};
use std::io::{self, Read, Write};
use std::mem;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::ptr;
use std::sync::Arc;
use std::vec::Vec;
use libc;
use libc::{c_char, c_short};
use libc::{AF_INET, O_RDWR, SOCK_DGRAM};
use crate::configuration::{Configuration, Layer};
use crate::device::Device as D;
use crate::error::*;
use crate::platform::linux::sys::*;
use crate::platform::posix::{self, Fd, SockAddr};
/// A TUN device using the TUN/TAP Linux driver.
pub struct Device {
name: String,
queues: Vec<Queue>,
ctl: Fd,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let mut device = unsafe {
let dev = match config.name.as_ref() {
Some(name) => {
let name = CString::new(name.clone())?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
Some(name)
}
None => None,
};
let mut queues = Vec::new();
let mut req: ifreq = mem::zeroed();
if let Some(dev) = dev.as_ref() {
ptr::copy_nonoverlapping(
dev.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
dev.as_bytes().len(),
);
}
let device_type: c_short = config.layer.unwrap_or(Layer::L3).into();
let queues_num = config.queues.unwrap_or(1);
if queues_num < 1 {
return Err(Error::InvalidQueuesNumber);
}
req.ifru.flags = device_type
| if config.platform.packet_information {
0
} else {
IFF_NO_PI
}
| if queues_num > 1 { IFF_MULTI_QUEUE } else { 0 };
for _ in 0..queues_num {
let tun = Fd::new(libc::open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR))
.map_err(|_| io::Error::last_os_error())?;
if tunsetiff(tun.0, &mut req as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error().into());
}
queues.push(Queue {
tun,
pi_enabled: config.platform.packet_information,
});
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
.map_err(|_| io::Error::last_os_error())?;
Device {
name: CStr::from_ptr(req.ifrn.name.as_ptr())
.to_string_lossy()
.into(),
queues,
ctl,
}
};
device.configure(config)?;
Ok(device)
}
/// Prepare a new request.
unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
/// Make the device persistent.
pub fn persist(&mut self) -> Result<()> {
unsafe {
if tunsetpersist(self.as_raw_fd(), &1) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
/// Set the owner of the device.
pub fn user(&mut self, value: i32) -> Result<()> {
unsafe {
if tunsetowner(self.as_raw_fd(), &value) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
/// Set the group of the device.
pub fn group(&mut self, value: i32) -> Result<()> {
unsafe {
if tunsetgroup(self.as_raw_fd(), &value) < 0 {
Err(io::Error::last_os_error().into())
} else {
Ok(())
}
}
}
pub fn split(mut self) -> (posix::Reader, posix::Writer) {
let queue = self.queues.swap_remove(0);
let fd = Arc::new(queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&mut self) -> bool {
self.queues[0].has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queues[0].set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queues[0].read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queues[0].read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queues[0].write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queues[0].flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queues[0].write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
&self.name
}
fn set_name(&mut self, value: &str) -> Result<()> {
unsafe {
let name = CString::new(value)?;
if name.as_bytes_with_nul().len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
let mut req = self.request();
ptr::copy_nonoverlapping(
name.as_ptr() as *const c_char,
req.ifru.newname.as_mut_ptr(),
value.len(),
);
if siocsifname(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
self.name = value.into();
Ok(())
}
}
fn enabled(&mut self, value: bool) -> Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
if value {
req.ifru.flags |= IFF_UP | IFF_RUNNING;
} else {
req.ifru.flags &= !IFF_UP;
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn address(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn destination(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn broadcast(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn netmask(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.netmask).map(Into::into)
}
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.netmask = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn mtu(&self) -> Result<i32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(req.ifru.mtu)
}
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
self.queues.get_mut(index)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queues[0].as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(mut self) -> RawFd {
// It is Ok to swap the first queue with the last one, because the self will be dropped afterwards
let queue = self.queues.swap_remove(0);
queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
pi_enabled: bool,
}
impl Queue {
pub fn has_packet_information(&mut self) -> bool {
self.pi_enabled
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl From<Layer> for c_short {
fn from(layer: Layer) -> Self {
match layer {
Layer::L2 => IFF_TAP,
Layer::L3 => IFF_TUN,
}
}
}
+43
View File
@@ -0,0 +1,43 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Linux specific functionality.
pub mod sys;
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// Linux-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {
pub(crate) packet_information: bool,
}
impl Configuration {
/// Enable or disable packet information, when enabled the first 4 bytes of
/// each packet is a header with flags and protocol type.
pub fn packet_information(&mut self, value: bool) -> &mut Self {
self.packet_information = value;
self
}
}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(configuration)
}
+111
View File
@@ -0,0 +1,111 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Bindings to internal Linux stuff.
use ioctl::*;
use libc::sockaddr;
use libc::{c_char, c_int, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void};
pub const IFNAMSIZ: usize = 16;
pub const IFF_UP: c_short = 0x1;
pub const IFF_RUNNING: c_short = 0x40;
pub const IFF_TUN: c_short = 0x0001;
pub const IFF_TAP: c_short = 0x0002;
pub const IFF_NO_PI: c_short = 0x1000;
pub const IFF_MULTI_QUEUE: c_short = 0x0100;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifmap {
pub mem_start: c_ulong,
pub mem_end: c_ulong,
pub base_addr: c_ushort,
pub irq: c_uchar,
pub dma: c_uchar,
pub port: c_uchar,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifsu {
pub raw_hdlc_proto: *mut c_void,
pub cisco: *mut c_void,
pub fr: *mut c_void,
pub fr_pvc: *mut c_void,
pub fr_pvc_info: *mut c_void,
pub sync: *mut c_void,
pub te1: *mut c_void,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct if_settings {
pub type_: c_uint,
pub size: c_uint,
pub ifsu: ifsu,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub netmask: sockaddr,
pub hwaddr: sockaddr,
pub flags: c_short,
pub ivalue: c_int,
pub mtu: c_int,
pub map: ifmap,
pub slave: [c_char; IFNAMSIZ],
pub newname: [c_char; IFNAMSIZ],
pub data: *mut c_void,
pub settings: if_settings,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
ioctl!(bad read siocgifflags with 0x8913; ifreq);
ioctl!(bad write siocsifflags with 0x8914; ifreq);
ioctl!(bad read siocgifaddr with 0x8915; ifreq);
ioctl!(bad write siocsifaddr with 0x8916; ifreq);
ioctl!(bad read siocgifdstaddr with 0x8917; ifreq);
ioctl!(bad write siocsifdstaddr with 0x8918; ifreq);
ioctl!(bad read siocgifbrdaddr with 0x8919; ifreq);
ioctl!(bad write siocsifbrdaddr with 0x891a; ifreq);
ioctl!(bad read siocgifnetmask with 0x891b; ifreq);
ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
ioctl!(bad read siocgifmtu with 0x8921; ifreq);
ioctl!(bad write siocsifmtu with 0x8922; ifreq);
ioctl!(bad write siocsifname with 0x8923; ifreq);
ioctl!(write tunsetiff with b'T', 202; c_int);
ioctl!(write tunsetpersist with b'T', 203; c_int);
ioctl!(write tunsetowner with b'T', 204; c_int);
ioctl!(write tunsetgroup with b'T', 206; c_int);
@@ -0,0 +1,438 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![allow(unused_variables)]
use std::ffi::CStr;
use std::io::{self, Read, Write};
use std::mem;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use std::ptr;
use std::sync::Arc;
use libc;
use libc::{c_char, c_uint, c_void, sockaddr, socklen_t, AF_INET, SOCK_DGRAM};
use crate::configuration::{Configuration, Layer};
use crate::device::Device as D;
use crate::error::*;
use crate::platform::macos::sys::*;
use crate::platform::posix::{self, Fd, SockAddr};
/// A TUN device using the TUN macOS driver.
pub struct Device {
name: String,
queue: Queue,
ctl: Fd,
}
impl Device {
/// Create a new `Device` for the given `Configuration`.
pub fn new(config: &Configuration) -> Result<Self> {
let id = if let Some(name) = config.name.as_ref() {
if name.len() > IFNAMSIZ {
return Err(Error::NameTooLong);
}
if !name.starts_with("utun") {
return Err(Error::InvalidName);
}
name[4..].parse()?
} else {
0
};
if config.layer.filter(|l| *l != Layer::L3).is_some() {
return Err(Error::UnsupportedLayer);
}
let queues_number = config.queues.unwrap_or(1);
if queues_number != 1 {
return Err(Error::InvalidQueuesNumber);
}
let mut device = unsafe {
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))
.map_err(|_| io::Error::last_os_error())?;
let mut info = ctl_info {
ctl_id: 0,
ctl_name: {
let mut buffer = [0; 96];
for (i, o) in UTUN_CONTROL_NAME.as_bytes().iter().zip(buffer.iter_mut()) {
*o = *i as _;
}
buffer
},
};
if ctliocginfo(tun.0, &mut info as *mut _ as *mut _) < 0 {
return Err(io::Error::last_os_error().into());
}
let addr = sockaddr_ctl {
sc_id: info.ctl_id,
sc_len: mem::size_of::<sockaddr_ctl>() as _,
sc_family: AF_SYSTEM,
ss_sysaddr: AF_SYS_CONTROL,
sc_unit: id as c_uint,
sc_reserved: [0; 5],
};
if libc::connect(
tun.0,
&addr as *const sockaddr_ctl as *const sockaddr,
mem::size_of_val(&addr) as socklen_t,
) < 0
{
return Err(io::Error::last_os_error().into());
}
let mut name = [0u8; 64];
let mut name_len: socklen_t = 64;
if libc::getsockopt(
tun.0,
SYSPROTO_CONTROL,
UTUN_OPT_IFNAME,
&mut name as *mut _ as *mut c_void,
&mut name_len as *mut socklen_t,
) < 0
{
return Err(io::Error::last_os_error().into());
}
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))
.map_err(|_| io::Error::last_os_error())?;
Device {
name: CStr::from_ptr(name.as_ptr() as *const c_char)
.to_string_lossy()
.into(),
queue: Queue { tun: tun },
ctl: ctl,
}
};
device.configure(&config)?;
Ok(device)
}
/// Prepare a new request.
pub unsafe fn request(&self) -> ifreq {
let mut req: ifreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifrn.name.as_mut_ptr(),
self.name.len(),
);
req
}
/// Set the IPv4 alias of the device.
pub fn set_alias(&mut self, addr: Ipv4Addr, broadaddr: Ipv4Addr, mask: Ipv4Addr) -> Result<()> {
unsafe {
let mut req: ifaliasreq = mem::zeroed();
ptr::copy_nonoverlapping(
self.name.as_ptr() as *const c_char,
req.ifran.as_mut_ptr(),
self.name.len(),
);
req.addr = SockAddr::from(addr).into();
req.broadaddr = SockAddr::from(broadaddr).into();
req.mask = SockAddr::from(mask).into();
if siocaifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
/// Split the interface into a `Reader` and `Writer`.
pub fn split(self) -> (posix::Reader, posix::Writer) {
let fd = Arc::new(self.queue.tun);
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
}
/// Return whether the device has packet information
pub fn has_packet_information(&self) -> bool {
self.queue.has_packet_information()
}
/// Set non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
self.queue.set_nonblock()
}
}
impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.queue.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.queue.tun.read_vectored(bufs)
}
}
impl Write for Device {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.queue.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.queue.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.queue.tun.write_vectored(bufs)
}
}
impl D for Device {
type Queue = Queue;
fn name(&self) -> &str {
&self.name
}
// XXX: Cannot set interface name on Darwin.
fn set_name(&mut self, value: &str) -> Result<()> {
Err(Error::InvalidName)
}
fn enabled(&mut self, value: bool) -> Result<()> {
unsafe {
let mut req = self.request();
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
if value {
req.ifru.flags |= IFF_UP | IFF_RUNNING;
} else {
req.ifru.flags &= !IFF_UP;
}
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn address(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.addr).map(Into::into)
}
}
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn destination(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
}
}
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.dstaddr = SockAddr::from(value).into();
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn broadcast(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
}
}
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.broadaddr = SockAddr::from(value).into();
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn netmask(&self) -> Result<Ipv4Addr> {
unsafe {
let mut req = self.request();
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
}
}
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.addr = SockAddr::from(value).into();
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn mtu(&self) -> Result<i32> {
unsafe {
let mut req = self.request();
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(req.ifru.mtu)
}
}
fn set_mtu(&mut self, value: i32) -> Result<()> {
unsafe {
let mut req = self.request();
req.ifru.mtu = value;
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
return Err(io::Error::last_os_error().into());
}
Ok(())
}
}
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
if index > 0 {
return None;
}
Some(&mut self.queue)
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.queue.as_raw_fd()
}
}
impl IntoRawFd for Device {
fn into_raw_fd(self) -> RawFd {
self.queue.into_raw_fd()
}
}
pub struct Queue {
tun: Fd,
}
impl Queue {
pub fn has_packet_information(&self) -> bool {
// on macos this is always the case
true
}
pub fn set_nonblock(&self) -> io::Result<()> {
self.tun.set_nonblock()
}
}
impl AsRawFd for Queue {
fn as_raw_fd(&self) -> RawFd {
self.tun.as_raw_fd()
}
}
impl IntoRawFd for Queue {
fn into_raw_fd(self) -> RawFd {
self.tun.into_raw_fd()
}
}
impl Read for Queue {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.tun.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.tun.read_vectored(bufs)
}
}
impl Write for Queue {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.tun.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.tun.flush()
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.tun.write_vectored(bufs)
}
}
+32
View File
@@ -0,0 +1,32 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! macOS specific functionality.
pub mod sys;
mod device;
pub use self::device::{Device, Queue};
use crate::configuration::Configuration as C;
use crate::error::*;
/// macOS-only interface configuration.
#[derive(Copy, Clone, Default, Debug)]
pub struct Configuration {}
/// Create a TUN device with the given name.
pub fn create(configuration: &C) -> Result<Device> {
Device::new(&configuration)
}
+138
View File
@@ -0,0 +1,138 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Bindings to internal macOS stuff.
use ioctl::*;
use libc::sockaddr;
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void};
pub const IFNAMSIZ: usize = 16;
pub const IFF_UP: c_short = 0x1;
pub const IFF_RUNNING: c_short = 0x40;
pub const AF_SYS_CONTROL: c_ushort = 2;
pub const AF_SYSTEM: c_char = 32;
pub const PF_SYSTEM: c_int = AF_SYSTEM as c_int;
pub const SYSPROTO_CONTROL: c_int = 2;
pub const UTUN_OPT_IFNAME: c_int = 2;
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ctl_info {
pub ctl_id: c_uint,
pub ctl_name: [c_char; 96],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct sockaddr_ctl {
pub sc_len: c_char,
pub sc_family: c_char,
pub ss_sysaddr: c_ushort,
pub sc_id: c_uint,
pub sc_unit: c_uint,
pub sc_reserved: [c_uint; 5],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
pub name: [c_char; IFNAMSIZ],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifdevmtu {
pub current: c_int,
pub min: c_int,
pub max: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifku {
pub ptr: *mut c_void,
pub value: c_int,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifkpi {
pub module_id: c_uint,
pub type_: c_uint,
pub ifku: ifku,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
pub addr: sockaddr,
pub dstaddr: sockaddr,
pub broadaddr: sockaddr,
pub flags: c_short,
pub metric: c_int,
pub mtu: c_int,
pub phys: c_int,
pub media: c_int,
pub intval: c_int,
pub data: *mut c_void,
pub devmtu: ifdevmtu,
pub wake_flags: c_uint,
pub route_refcnt: c_uint,
pub cap: [c_int; 2],
pub functional_type: c_uint,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
pub ifrn: ifrn,
pub ifru: ifru,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifaliasreq {
pub ifran: [c_char; IFNAMSIZ],
pub addr: sockaddr,
pub broadaddr: sockaddr,
pub mask: sockaddr,
}
ioctl!(readwrite ctliocginfo with 'N', 3; ctl_info);
ioctl!(write siocsifflags with 'i', 16; ifreq);
ioctl!(readwrite siocgifflags with 'i', 17; ifreq);
ioctl!(write siocsifaddr with 'i', 12; ifreq);
ioctl!(readwrite siocgifaddr with 'i', 33; ifreq);
ioctl!(write siocsifdstaddr with 'i', 14; ifreq);
ioctl!(readwrite siocgifdstaddr with 'i', 34; ifreq);
ioctl!(write siocsifbrdaddr with 'i', 19; ifreq);
ioctl!(readwrite siocgifbrdaddr with 'i', 35; ifreq);
ioctl!(write siocsifnetmask with 'i', 22; ifreq);
ioctl!(readwrite siocgifnetmask with 'i', 37; ifreq);
ioctl!(write siocsifmtu with 'i', 52; ifreq);
ioctl!(readwrite siocgifmtu with 'i', 51; ifreq);
ioctl!(write siocaifaddr with 'i', 26; ifaliasreq);
ioctl!(write siocdifaddr with 'i', 25; ifreq);
+70
View File
@@ -0,0 +1,70 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! Platform specific modules.
#[cfg(unix)]
pub mod posix;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::{create, Configuration, Device, Queue};
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
pub use self::macos::{create, Configuration, Device, Queue};
#[cfg(target_os = "ios")]
pub mod ios;
#[cfg(target_os = "ios")]
pub use self::ios::{create, Configuration, Device, Queue};
#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "android")]
pub use self::android::{create, Configuration, Device, Queue};
#[cfg(test)]
mod test {
use crate::configuration::Configuration;
use crate::device::Device;
use std::net::Ipv4Addr;
#[test]
fn create() {
let dev = super::create(
Configuration::default()
.name("utun6")
.address("192.168.50.1")
.netmask("255.255.0.0")
.mtu(1400)
.up(),
)
.unwrap();
assert_eq!(
"192.168.50.1".parse::<Ipv4Addr>().unwrap(),
dev.address().unwrap()
);
assert_eq!(
"255.255.0.0".parse::<Ipv4Addr>().unwrap(),
dev.netmask().unwrap()
);
assert_eq!(1400, dev.mtu().unwrap());
}
}
+124
View File
@@ -0,0 +1,124 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
use crate::error::*;
use libc::{self, fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
/// POSIX file descriptor support for `io` traits.
pub struct Fd(pub RawFd);
impl Fd {
pub fn new(value: RawFd) -> Result<Self> {
if value < 0 {
return Err(Error::InvalidDescriptor);
}
Ok(Fd(value))
}
/// Enable non-blocking mode
pub fn set_nonblock(&self) -> io::Result<()> {
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
}
impl Read for Fd {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
unsafe {
let iov = bufs.as_ptr().cast();
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::readv(self.0, iov, iovcnt);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl Write for Fd {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
unsafe {
let iov = bufs.as_ptr().cast();
let iovcnt = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::writev(self.0, iov, iovcnt);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl AsRawFd for Fd {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl IntoRawFd for Fd {
fn into_raw_fd(mut self) -> RawFd {
let fd = self.0;
self.0 = -1;
fd
}
}
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
if self.0 >= 0 {
libc::close(self.0);
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//! POSIX compliant support.
mod sockaddr;
pub use self::sockaddr::SockAddr;
mod fd;
pub use self::fd::Fd;
mod split;
pub use self::split::{Reader, Writer};
@@ -0,0 +1,96 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::mem;
use std::net::Ipv4Addr;
use std::ptr;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use libc::c_uchar;
#[cfg(any(target_os = "linux", target_os = "android"))]
use libc::c_ushort;
use libc::AF_INET as _AF_INET;
use libc::{in_addr, sockaddr, sockaddr_in};
use crate::error::*;
/// A wrapper for `sockaddr_in`.
#[derive(Copy, Clone)]
pub struct SockAddr(sockaddr_in);
#[cfg(any(target_os = "linux", target_os = "android"))]
const AF_INET: c_ushort = _AF_INET as c_ushort;
#[cfg(any(target_os = "macos", target_os = "ios"))]
const AF_INET: c_uchar = _AF_INET as c_uchar;
impl SockAddr {
/// Create a new `SockAddr` from a generic `sockaddr`.
pub fn new(value: &sockaddr) -> Result<Self> {
if value.sa_family != AF_INET {
return Err(Error::InvalidAddress);
}
unsafe { Self::unchecked(value) }
}
/// # Safety
/// Create a new `SockAddr` and not check the source.
pub unsafe fn unchecked(value: &sockaddr) -> Result<Self> {
Ok(SockAddr(ptr::read(value as *const _ as *const _)))
}
/// # Safety
/// Get a generic pointer to the `SockAddr`.
pub unsafe fn as_ptr(&self) -> *const sockaddr {
&self.0 as *const _ as *const sockaddr
}
}
impl From<Ipv4Addr> for SockAddr {
fn from(ip: Ipv4Addr) -> SockAddr {
let octets = ip.octets();
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
addr.sin_family = AF_INET;
addr.sin_port = 0;
addr.sin_addr = in_addr {
s_addr: u32::from_ne_bytes(octets),
};
SockAddr(addr)
}
}
impl From<SockAddr> for Ipv4Addr {
fn from(addr: SockAddr) -> Ipv4Addr {
let ip = addr.0.sin_addr.s_addr;
let [a, b, c, d] = ip.to_ne_bytes();
Ipv4Addr::new(a, b, c, d)
}
}
impl From<SockAddr> for sockaddr {
fn from(addr: SockAddr) -> sockaddr {
unsafe { mem::transmute(addr.0) }
}
}
impl From<SockAddr> for sockaddr_in {
fn from(addr: SockAddr) -> sockaddr_in {
addr.0
}
}
+105
View File
@@ -0,0 +1,105 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
use std::io::{self, Read, Write};
use std::mem;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::Arc;
use crate::platform::posix::Fd;
use libc;
/// Read-only end for a file descriptor.
pub struct Reader(pub(crate) Arc<Fd>);
/// Write-only end for a file descriptor.
pub struct Writer(pub(crate) Arc<Fd>);
impl Read for Reader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
let amount = libc::read(self.0.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
unsafe {
let mut msg: libc::msghdr = mem::zeroed();
// msg.msg_name: NULL
// msg.msg_namelen: 0
msg.msg_iov = bufs.as_mut_ptr().cast();
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::recvmsg(self.0.as_raw_fd(), &mut msg, 0);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len());
if amount < 0 {
return Err(io::Error::last_os_error());
}
Ok(amount as usize)
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
unsafe {
let mut msg: libc::msghdr = mem::zeroed();
// msg.msg_name = NULL
// msg.msg_namelen = 0
msg.msg_iov = bufs.as_ptr() as *mut _;
msg.msg_iovlen = bufs.len().min(libc::c_int::MAX as usize) as _;
let n = libc::sendmsg(self.0.as_raw_fd(), &msg, 0);
if n < 0 {
return Err(io::Error::last_os_error());
}
Ok(n as usize)
}
}
}
impl AsRawFd for Reader {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl AsRawFd for Writer {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
+26
View File
@@ -0,0 +1,26 @@
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("TokioWatchRecvError")]
TokioWatchRecvError(#[from] tokio::sync::watch::error::RecvError),
#[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>;
+70
View File
@@ -0,0 +1,70 @@
use std::net::{SocketAddr, UdpSocket};
use std::time::Duration;
use chrono::Local;
use tokio::sync::watch::Receiver;
use tokio::time::sleep;
use crate::{CurrentDeviceInfo, DEVICE_LIST};
use crate::error::*;
use crate::handle::{ApplicationStatus, DIRECT_ROUTE_TABLE};
use crate::protocol::{control_packet, NetPacket, Protocol, Version};
use crate::protocol::control_packet::PingPacket;
pub async fn start<F>(status_watch: Receiver<ApplicationStatus>,
udp: UdpSocket, cur_info: CurrentDeviceInfo, stop_fn: F)
where F: FnOnce() + Send + 'static {
tokio::spawn(async move {
match handle_loop(status_watch, udp, cur_info.connect_server).await {
Ok(_) => {}
Err(e) => {
log::error!("{:?}",e)
}
}
stop_fn();
});
}
async fn handle_loop(mut status_watch: Receiver<ApplicationStatus>, udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
const INTERVAL: u64 = 3000;
const MAX_INTERVAL: i64 = 3000 * 3;
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_millis();
{
let mut ping = PingPacket::new(net_packet.payload_mut())?;
ping.set_time(current_time);
let epoch = { DEVICE_LIST.lock().0 };
ping.set_epoch(epoch);
}
let _ = 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 {
let _ = udp.send_to(net_packet.buffer(), route.address);
} else {
DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| {
current_time - route.recv_time > MAX_INTERVAL
});
}
}
tokio::select! {
_ = sleep(Duration::from_millis(INTERVAL))=>{
}
status = status_watch.changed() =>{
status?;
if *status_watch.borrow() != ApplicationStatus::Starting{
return Ok(())
}
}
}
}
}
+169
View File
@@ -0,0 +1,169 @@
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(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ApplicationStatus {
Starting,
Stopping,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ConnectStatus {
Connecting,
Connected,
}
impl Into<u8> for ConnectStatus {
fn into(self) -> u8 {
match self {
ConnectStatus::Connecting => 0,
ConnectStatus::Connected => 1,
}
}
}
#[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(Copy, Clone, Debug)]
pub struct CurrentDeviceInfo {
pub virtual_ip: Ipv4Addr,
pub virtual_gateway: Ipv4Addr,
pub virtual_netmask: Ipv4Addr,
//网络地址
pub virtual_network: Ipv4Addr,
//直接广播地址
pub broadcast_address: Ipv4Addr,
//链接的服务器地址
pub 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 {
pub route_type: RouteType,
pub address: SocketAddr,
//用心跳探测延迟,收包时更新
pub rt: i64,
//收包时更新,如果太久没有收到消息则剔除
pub recv_time: i64,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum RouteType {
ServerRelay,
P2P,
}
impl Into<u8> for RouteType {
fn into(self) -> u8 {
match self {
RouteType::ServerRelay => 0,
RouteType::P2P => 1
}
}
}
impl Route {
pub fn new(address: SocketAddr) -> Self {
Self {
route_type: RouteType::P2P,
address,
rt: -1,
recv_time: Local::now().timestamp_millis(),
}
}
}
+422
View File
@@ -0,0 +1,422 @@
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::thread;
use std::time::Duration;
use dashmap::DashMap;
use lazy_static::lazy_static;
use protobuf::Message;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::sync::mpsc::error::TrySendError;
use tokio::sync::watch;
use crate::{CurrentDeviceInfo, DEVICE_LIST, handle::NAT_INFO, handle::NatInfo};
use crate::error::*;
use crate::handle::{ApplicationStatus, 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) = tokio::sync::mpsc::channel(3);
let (req_symmetric_sender, req_symmetric_receiver) = tokio::sync::mpsc::channel(1);
let (res_symmetric_sender, res_symmetric_receiver) = tokio::sync::mpsc::channel(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.blocking_send(punch)
// } else {
// self.req_symmetric_sender.blocking_send(punch)
// }
// }
// NatType::Cone => {
// self.cone_sender.blocking_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(status_watch: &watch::Receiver<ApplicationStatus>, 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 {
if counter & 10 == 10 {
if status_watch.has_changed()? {
return Ok(());
}
}
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 {
if counter & 10 == 10 {
if status_watch.has_changed()? {
return Ok(());
}
}
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 async fn req_symmetric_handler_start<F>(status_watch: watch::Receiver<ApplicationStatus>,
receiver: ReqSymmetricReceiver,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
stop_fn: F) where F: FnOnce() +Send+'static{
let receiver = receiver.0;
tokio::spawn(async move {
match handle_loop(status_watch, receiver, udp, cur_info).await {
Ok(_) => {}
Err(e) => {
log::error!("{:?}",e)
}
}
stop_fn()
});
}
// 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 async fn res_symmetric_handler_start<F>(status_watch: watch::Receiver<ApplicationStatus>,
receiver: ResSymmetricReceiver,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
stop_fn: F) where F: FnOnce() +Send+'static{
let receiver = receiver.0;
tokio::spawn(async move {
match res_symmetric_handle_loop(status_watch, receiver, udp, cur_info).await {
Ok(_) => {}
Err(e) => {
log::error!("{:?}",e)
}
}
stop_fn()
});
}
async fn res_symmetric_handle_loop(
mut status_watch: watch::Receiver<ApplicationStatus>,
mut 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);
}
match tokio::time::timeout(Duration::from_secs(30), receiver.recv()).await {
Ok(_) => {}
Err(e) => {}
}
loop {
tokio::select! {
rs = tokio::time::timeout(Duration::from_secs(30), receiver.recv()) =>{
match rs {
Ok(punch) => {
if let Some(punch) = 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(&status_watch,&udp, list, packet.buffer()) {
log::error!("{:?}",e)
}
}else {
return Err(Error::Stop("打洞线程通道关闭".to_string()));
}
}
Err(_) => {
punch_request_handle(&udp, &cur_info)?;
}
}
}
status = status_watch.changed() =>{
status?;
if *status_watch.borrow() != ApplicationStatus::Starting{
return Ok(())
}
}
}
}
}
/// 给锥形nat发送打洞数据包
pub async fn cone_handler_start<F>(status_watch: watch::Receiver<ApplicationStatus>,
receiver: ConeReceiver,
udp: UdpSocket,
cur_info: CurrentDeviceInfo,
stop_fn: F) where F: FnOnce()+Send +'static{
let receiver = receiver.0;
tokio::spawn(async move {
match handle_loop(status_watch, receiver, udp, cur_info).await {
Ok(_) => {}
Err(e) => {
log::error!("{:?}",e)
}
}
stop_fn();
});
}
async fn handle_loop(
mut status_watch: watch::Receiver<ApplicationStatus>,
mut 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 {
tokio::select! {
punch = receiver.recv() =>{
if let Some(punch) = 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(&status_watch,&udp, list, packet.buffer()) {
log::error!("{:?}",e)
}
}else {
return Err(Error::Stop("打洞线程通道关闭".to_string()));
}
}
status = status_watch.changed() =>{
status?;
if *status_watch.borrow() != ApplicationStatus::Starting{
return Ok(())
}
}
}
}
}
fn select_sleep(counter: &mut u64) {
*counter += 1;
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) {
log::error!("发送打洞数据失败 {:?}",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())
}
+118
View File
@@ -0,0 +1,118 @@
use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::sync::atomic::{AtomicI64, Ordering};
use std::time::Duration;
use chrono::Local;
use crossbeam::atomic::AtomicCell;
use parking_lot::RwLock;
use protobuf::Message;
use crate::error::*;
use crate::handle::ConnectStatus;
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);
pub(crate) static ref CONNECTION_STATUS:AtomicCell<ConnectStatus> = AtomicCell::new(ConnectStatus::Connecting);
}
///向中继服务器注册,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)?;
CONNECTION_STATUS.store(ConnectStatus::Connected);
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_millis();
if new - last < 2000
|| REGISTRATION_TIME
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
//短时间不重复注册
return Ok(());
}
CONNECTION_STATUS.store(ConnectStatus::Connecting);
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_millis(), Ordering::Relaxed);
return Ok(());
}
return Err(Error::Stop("注册信息不存在".to_string()));
}
+178
View File
@@ -0,0 +1,178 @@
/// 接收tun数据,并且转发到udp上
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::os::fd::AsRawFd;
use std::thread;
use chrono::Local;
use tokio::sync::watch;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use crate::ApplicationStatus;
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_millis();
if current_time - route.recv_time < 3_000 {
if udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address).is_ok() {
return Ok(());
}
}
}
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], cur_info.connect_server)?;
return Ok(());
}
#[cfg(target_os = "windows")]
pub async fn handler_start<F>(mut status_watch: watch::Receiver<ApplicationStatus>,
udp: UdpSocket,
tun_reader: TunReader,
cur_info: CurrentDeviceInfo, stop_fn: F)
where F: FnOnce() + Send + 'static {
let session = tun_reader.0.clone();
tokio::spawn(async move {
let _ = status_watch.changed().await;
session.shutdown();
let udp = UdpSocket::bind("0.0.0.0:0").unwrap();
let _ = udp.send_to(&[0],SocketAddr::new(IpAddr::V4(cur_info.virtual_gateway),10));
});
thread::spawn(move || {
if let Err(e) = handle_loop(udp, tun_reader, cur_info) {
log::error!("tun数据处理线程停止 {:?}",e);
}
stop_fn();
});
}
#[cfg(target_os = "windows")]
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(target_os = "macos", target_os = "linux"))]
pub async fn handler_start<F>(mut status_watch: watch::Receiver<ApplicationStatus>,
udp: UdpSocket,
tun_reader: TunReader,
cur_info: CurrentDeviceInfo, stop_fn: F)
where F: FnOnce() + Send + 'static {
let raw_fd = tun_reader.0.as_raw_fd();
tokio::spawn(async move {
let _ = status_watch.changed().await;
// 让tun接收线程关闭
unsafe {
libc::close(raw_fd);
}
let udp = UdpSocket::bind("0.0.0.0:0").unwrap();
let _ = udp.send_to(&[0],SocketAddr::new(IpAddr::V4(cur_info.virtual_gateway),10));
});
thread::spawn(move || {
if let Err(e) = handle_loop(udp, tun_reader, cur_info) {
log::error!(" tun数据处理线程停止 {:?}",e);
}
stop_fn();
});
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
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) => {
log::error!("{:?}",e)
}
}
}
}
+372
View File
@@ -0,0 +1,372 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::atomic::Ordering;
use std::thread;
use chrono::Local;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use protobuf::Message;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::sync::mpsc::error::TrySendError;
use tokio::sync::watch;
use crate::{ApplicationStatus, CurrentDeviceInfo};
use crate::error::*;
use crate::handle::{ADDR_TABLE, ConnectStatus, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, Route, SERVER_RT};
use crate::handle::punch_handler::PunchSender;
use crate::handle::registration_handler::{CONNECTION_STATUS, 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;
const UDP_STOP_BUF: [u8; 1] = [0u8];
pub async fn udp_recv_start<F>(
mut status_watch: watch::Receiver<ApplicationStatus>,
udp: UdpSocket,
server_addr: SocketAddr,
other_sender: Sender<(SocketAddr, Vec<u8>)>,
mut tun_writer: TunWriter,
current_device: CurrentDeviceInfo,
stop_fn: F)
where F: FnOnce() + Send + 'static {
{
let udp = udp.try_clone().unwrap();
tokio::spawn(async move {
let _ = status_watch.changed().await;
let mut addr = udp.local_addr().unwrap();
addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
udp.send_to(&UDP_STOP_BUF, addr).unwrap();
});
}
thread::spawn(move || {
if let Err(e) = recv_loop(
udp,
server_addr,
other_sender,
tun_writer,
current_device,
) {
log::error!("udp数据处理线程停止 {:?}",e);
}
stop_fn();
});
}
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(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
loop {
match udp.recv_from(&mut buf) {
Ok((len, addr)) => {
if addr == local_addr {
if len == 1 && &buf[..len] == &UDP_STOP_BUF {
return Ok(());
}
//本地的包直接再发到网卡,这个主要用于处理当前虚拟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,
&current_device,
) {
Ok(_) => {}
Err(Error::Stop(str)) => {
return Err(Error::Stop(str));
}
Err(e) => {
log::error!("{:?}",e);
}
}
}
Err(e) => {
log::error!("{:?}",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::Closed(_)) => {
return Err(Error::Stop("子处理线程停止".to_string()));
}
Err(e) => {
log::error!("子线程处理 {:?}",e);
}
}
}
}
Ok(())
}
pub async fn udp_other_recv_start<F>(status_watch: watch::Receiver<ApplicationStatus>,
udp: UdpSocket,
receiver: Receiver<(SocketAddr, Vec<u8>)>,
current_device: CurrentDeviceInfo,
sender: PunchSender,
stop_fn: F) where F: FnOnce() + Send + 'static {
tokio::spawn(async move {
match other_loop(status_watch, udp, receiver, current_device, sender).await {
Ok(_) => {}
Err(e) => {
log::error!("{:?}",e);
}
}
stop_fn();
});
}
async fn other_loop(
mut status_watch: watch::Receiver<ApplicationStatus>,
udp: UdpSocket,
mut receiver: Receiver<(SocketAddr, Vec<u8>)>,
current_device: CurrentDeviceInfo,
sender: PunchSender,
) -> Result<()> {
loop {
tokio::select! {
rs = receiver.recv()=>{
if let Some((peer_addr, buf)) = rs {
match other_handle(&udp, buf, peer_addr, &current_device, &sender) {
Ok(_) => {}
Err(Error::Stop(str)) => {
return Err(Error::Stop(str));
}
Err(e) => {
log::error!("other_loop {:?}",e);
}
}
}
}
status = status_watch.changed() =>{
status?;
if *status_watch.borrow() != ApplicationStatus::Starting{
return Ok(())
}
}
}
}
}
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);
CONNECTION_STATUS.store(ConnectStatus::Connected);
//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) => {
log::error!("OtherError {:?}",e.message());
}
}
}
Protocol::Control => {
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PingPacket(ping) => {
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_millis();
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.rt = 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) => {
log::error!("未知协议 {}",p);
}
}
Ok(())
}
+211
View File
@@ -0,0 +1,211 @@
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};
use std::sync::atomic::Ordering;
use crossbeam::sync::WaitGroup;
use tokio::sync::watch;
use error::*;
use crate::handle::{ApplicationStatus, ConnectStatus, CurrentDeviceInfo, DEVICE_LIST, DIRECT_ROUTE_TABLE, Route, RouteType, SERVER_RT};
use crate::handle::registration_handler::CONNECTION_STATUS;
pub mod tun_device;
pub mod nat;
pub mod error;
pub mod handle;
pub mod proto;
pub mod protocol;
#[derive(Clone, Debug)]
pub struct Config {
pub token: String,
pub mac_address: String,
}
impl Config {
pub fn new(token: String, mac_address: String) -> Self {
Self {
token,
mac_address,
}
}
}
pub struct Switch {
current_device: CurrentDeviceInfo,
status_sender: watch::Sender<ApplicationStatus>,
wait_group: WaitGroup,
runtime: Option<tokio::runtime::Runtime>,
}
impl Switch {
pub fn start(config: Config) -> Result<Self> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
return match runtime.block_on(Switch::start_(config.token, config.mac_address)) {
Ok(mut switch) => {
switch.runtime = Some(runtime);
Ok(switch)
}
Err(e) => {
Err(e)
}
};
}
pub fn stop(self) {
let _ = self.status_sender.send(ApplicationStatus::Stopping);
self.wait_group.wait();
}
pub fn current_device(&self) -> &CurrentDeviceInfo {
&self.current_device
}
pub fn server_rt(&self) -> i64 {
SERVER_RT.load(Ordering::Relaxed)
}
pub fn connection_status(&self) -> ConnectStatus {
CONNECTION_STATUS.load()
}
pub fn device_list(&self) -> Vec<Ipv4Addr> {
let device_list_lock = DEVICE_LIST.lock();
let (_epoch, device_list) = device_list_lock.clone();
drop(device_list_lock);
device_list
}
pub fn route(&self, ip: &Ipv4Addr) -> Route {
if let Some(route_ref) = DIRECT_ROUTE_TABLE.get(ip) {
route_ref.value().clone()
} else {
let mut route = Route::new(self.current_device.connect_server);
route.route_type = RouteType::ServerRelay;
route.rt = self.server_rt() * 2;
route.recv_time = -1;
route
}
}
}
impl Switch {
pub async fn start_(token: String, mac_address: String) -> Result<Self> {
let server_address = "nat1.wherewego.top:29876".to_socket_addrs().unwrap().next().unwrap();
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 {
log::error!("创建udp失败 {:?}",e);
return Err(Error::Stop("udp bind error".to_string()));
}
}
}
};
//注册
let response = handle::registration_handler::registration(&udp, server_address, token, mac_address)?;
{
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);
let (status_sender, status_receiver) = tokio::sync::watch::channel(ApplicationStatus::Starting);
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
let wait_group = WaitGroup::new();
//心跳线程
{
let udp = udp.try_clone()?;
let wait_group1 = wait_group.clone();
handle::heartbeat_handler::start(status_receiver.clone(), udp, current_device, || {
drop(wait_group1);
}).await;
}
//初始化nat数据
handle::init_nat_info(response.public_ip, response.public_port as u16);
// tun服务
let (tun_writer, tun_reader) =
tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway)?;
// 打洞数据通道
let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = handle::punch_handler::bounded();
//udp数据处理
{
// 低优先级的udp数据通道
let (sender, receiver) = tokio::sync::mpsc::channel(50);
let udp1 = udp.try_clone()?;
let wait_group1 = wait_group.clone();
handle::udp_recv_handler::udp_recv_start(
status_receiver.clone(),
udp1,
server_address,
sender,
tun_writer,
current_device,
|| {
drop(wait_group1);
},
).await;
let udp1 = udp.try_clone()?;
let wait_group1 = wait_group.clone();
handle::udp_recv_handler::udp_other_recv_start(status_receiver.clone(), udp1,
receiver, current_device, punch_sender,
|| {
drop(wait_group1);
}).await;
}
//打洞处理
{
let udp1 = udp.try_clone()?;
let wait_group1 = wait_group.clone();
handle::punch_handler::cone_handler_start(status_receiver.clone(),
cone_receiver, udp1,
current_device,
|| {
drop(wait_group1);
}).await;
let udp1 = udp.try_clone()?;
let wait_group1 = wait_group.clone();
handle::punch_handler::req_symmetric_handler_start(status_receiver.clone(),
req_symmetric_receiver, udp1,
current_device,
|| {
drop(wait_group1);
}).await;
let udp1 = udp.try_clone()?;
let wait_group1 = wait_group.clone();
handle::punch_handler::res_symmetric_handler_start(status_receiver.clone(),
res_symmetric_receiver,
udp1,
current_device,
|| {
drop(wait_group1);
}).await;
}
//tun数据处理
{
let wait_group1 = wait_group.clone();
handle::tun_handler::handler_start(status_receiver.clone(), udp,
tun_reader, current_device,
|| {
drop(wait_group1);
}).await;
}
Ok(Switch {
current_device,
status_sender,
wait_group,
runtime: None,
})
}
}
+157
View File
@@ -0,0 +1,157 @@
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);
}
+1
View File
@@ -0,0 +1 @@
pub mod check;
+941
View File
@@ -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)
})
}
+3
View File
@@ -0,0 +1,3 @@
// @generated
pub mod message;
+223
View File
@@ -0,0 +1,223 @@
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]>> fmt::Debug for PingPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PingPacket")
.field("time", &self.time())
.field("epoch", &self.epoch())
.finish()
}
}
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())
}
}
impl<B: AsRef<[u8]>> fmt::Debug for PongPacket<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PongPacket")
.field("time", &self.time())
.finish()
}
}
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()
}
}
+69
View File
@@ -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())
}
}
+145
View File
@@ -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()
}
}
+32
View File
@@ -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,
}
}
}
+81
View File
@@ -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()
}
}
+39
View File
@@ -0,0 +1,39 @@
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::Device;
use tun::platform::posix::{Reader, Writer};
use crate::tun_device::{TunReader, TunWriter};
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();
config.platform(|config| {
config.packet_information(true);
});
let mut dev = tun::create(&config).unwrap();
let packet_information = dev.has_packet_information();
let (reader, writer) = dev.split();
Ok((
TunWriter(writer, packet_information),
TunReader(reader, packet_information),
))
}
+68
View File
@@ -0,0 +1,68 @@
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::Device;
use tun::platform::posix::{Reader, Writer};
use crate::tun_device::{TunReader, TunWriter};
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();
let dev = tun::create(&config).unwrap();
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", dev.name(), 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)));
}
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),
))
}
+19
View File
@@ -0,0 +1,19 @@
#[cfg(any(target_os = "linux",target_os = "android"))]
pub use linux::create_tun;
#[cfg(target_os = "macos")]
pub use mac::create_tun;
#[cfg(any(unix))]
pub use unix::{TunReader, TunWriter};
#[cfg(target_os = "windows")]
pub use windows::{TunReader, TunWriter};
#[cfg(target_os = "windows")]
pub use windows::create_tun;
#[cfg(target_os = "macos")]
pub mod mac;
#[cfg(any(target_os = "linux",target_os = "android"))]
pub mod linux;
#[cfg(any(unix))]
pub mod unix;
#[cfg(target_os = "windows")]
pub mod windows;
+37
View File
@@ -0,0 +1,37 @@
use std::io;
use std::io::{Read, Write};
use bytes::BufMut;
use tun::platform::posix::{Reader, Writer};
pub struct TunReader(pub(crate) Reader, pub(crate) 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(pub(crate) Writer, pub(crate) 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)
}
}
}
+132
View File
@@ -0,0 +1,132 @@
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(pub(crate) 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) => {
log::error!("wintun.dll not found");
return Err(Error::Stop(format!("wintun.dll not found {:?}", e)));
}
}
};
let adapter = match Adapter::open(&win_tun, "Switch") {
Ok(a) => a,
Err(_) => match Adapter::create(&win_tun, "Switch", "Switch", 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)))
}