mirror of
https://github.com/dndx/phantun.git
synced 2025-01-31 12:19:30 +08:00
docs(fake-tcp) added documentations for fake-tcp
This commit is contained in:
parent
9c85b43e94
commit
5d4e3bf8c0
@ -1,3 +1,43 @@
|
|||||||
|
//! A minimum, userspace TCP based datagram stack
|
||||||
|
//!
|
||||||
|
//! # Overview
|
||||||
|
//!
|
||||||
|
//! `fake-tcp` is a reusable library that implements a minimum TCP stack in
|
||||||
|
//! user space using the Tun interface. It allows programs to send datagrams
|
||||||
|
//! as if they are part of a TCP connection. `fake-tcp` has been tested to
|
||||||
|
//! be able to pass through a variety of NAT and stateful firewalls while
|
||||||
|
//! fully preserves certain desirable behavior such as out of order delivery
|
||||||
|
//! and no congestion/flow controls.
|
||||||
|
//!
|
||||||
|
//! # Core Concepts
|
||||||
|
//!
|
||||||
|
//! The core of the `fake-tcp` crate compose of two structures. [`Stack`] and
|
||||||
|
//! [`Socket`].
|
||||||
|
//!
|
||||||
|
//! ## [`Stack`]
|
||||||
|
//!
|
||||||
|
//! [`Stack`] represents a virtual TCP stack that operates at
|
||||||
|
//! Layer 3. It is responsible for:
|
||||||
|
//!
|
||||||
|
//! * TCP active and passive open and handshake
|
||||||
|
//! * `RST` handling
|
||||||
|
//! * Interact with the Tun interface at Layer 3
|
||||||
|
//! * Distribute incoming datagrams to corresponding [`Socket`]
|
||||||
|
//!
|
||||||
|
//! ## [`Socket`]
|
||||||
|
//!
|
||||||
|
//! [`Socket`] represents a TCP connection. It registers the identifying
|
||||||
|
//! tuple `(src_ip, src_port, dest_ip, dest_port)` inside the [`Stack`] so
|
||||||
|
//! so that incoming packets can be distributed to the right [`Socket`] with
|
||||||
|
//! using a channel. It is also what the client should use for
|
||||||
|
//! sending/receiving datagrams.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! Please see [`client.rs`](https://github.com/dndx/phantun/blob/main/phantun/src/bin/client.rs)
|
||||||
|
//! and [`server.rs`](https://github.com/dndx/phantun/blob/main/phantun/src/bin/server.rs) files
|
||||||
|
//! from the `phantun` crate for how to use this library in client/server mode, respectively.
|
||||||
|
|
||||||
#![cfg_attr(feature = "benchmark", feature(test))]
|
#![cfg_attr(feature = "benchmark", feature(test))]
|
||||||
|
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
@ -23,7 +63,7 @@ const RETRIES: usize = 6;
|
|||||||
const MPSC_BUFFER_LEN: usize = 512;
|
const MPSC_BUFFER_LEN: usize = 512;
|
||||||
|
|
||||||
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
|
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
|
||||||
pub struct AddrTuple {
|
struct AddrTuple {
|
||||||
local_addr: SocketAddrV4,
|
local_addr: SocketAddrV4,
|
||||||
remote_addr: SocketAddrV4,
|
remote_addr: SocketAddrV4,
|
||||||
}
|
}
|
||||||
@ -69,6 +109,13 @@ pub struct Socket {
|
|||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A socket that represents a unique TCP connection between a server and client.
|
||||||
|
///
|
||||||
|
/// The `Socket` object itself satisfies `Sync` and `Send`, which means it can
|
||||||
|
/// be safely called within an async future.
|
||||||
|
///
|
||||||
|
/// To close a TCP connection that is no longer needed, simply drop this object
|
||||||
|
/// out of scope.
|
||||||
impl Socket {
|
impl Socket {
|
||||||
fn new(
|
fn new(
|
||||||
shared: Arc<Shared>,
|
shared: Arc<Shared>,
|
||||||
@ -106,6 +153,13 @@ impl Socket {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends a datagram to the other end.
|
||||||
|
///
|
||||||
|
/// This method takes `&self`, and it can be called safely by multiple threads
|
||||||
|
/// at the same time.
|
||||||
|
///
|
||||||
|
/// A return of `None` means the Tun socket returned an error
|
||||||
|
/// and this socket must be closed.
|
||||||
pub async fn send(&self, payload: &[u8]) -> Option<()> {
|
pub async fn send(&self, payload: &[u8]) -> Option<()> {
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Established => {
|
State::Established => {
|
||||||
@ -122,6 +176,13 @@ impl Socket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to receive a datagram from the other end.
|
||||||
|
///
|
||||||
|
/// This method takes `&self`, and it can be called safely by multiple threads
|
||||||
|
/// at the same time.
|
||||||
|
///
|
||||||
|
/// A return of `None` means the TCP connection is broken
|
||||||
|
/// and this socket must be closed.
|
||||||
pub async fn recv(&self, buf: &mut [u8]) -> Option<usize> {
|
pub async fn recv(&self, buf: &mut [u8]) -> Option<usize> {
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Established => {
|
State::Established => {
|
||||||
@ -246,6 +307,7 @@ impl Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Socket {
|
impl Drop for Socket {
|
||||||
|
/// Drop the socket and close the TCP connection
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let tuple = AddrTuple::new(self.local_addr, self.remote_addr);
|
let tuple = AddrTuple::new(self.local_addr, self.remote_addr);
|
||||||
// dissociates ourself from the dispatch map
|
// dissociates ourself from the dispatch map
|
||||||
@ -263,6 +325,7 @@ impl Drop for Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Socket {
|
impl fmt::Display for Socket {
|
||||||
|
/// User-friendly string representation of the socket
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -272,7 +335,12 @@ impl fmt::Display for Socket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A userspace TCP state machine
|
||||||
impl Stack {
|
impl Stack {
|
||||||
|
/// Create a new stack, `tun` is an array of [`Tun`](tokio_tun::Tun).
|
||||||
|
/// When more than one [`Tun`](tokio_tun::Tun) object is passed in, same amount
|
||||||
|
/// of reader will be spawned later. This allows user to utilize the performance
|
||||||
|
/// benefit of Multiqueue Tun support on machines with SMP.
|
||||||
pub fn new(tun: Vec<Tun>) -> Stack {
|
pub fn new(tun: Vec<Tun>) -> Stack {
|
||||||
let tun: Vec<Arc<Tun>> = tun.into_iter().map(Arc::new).collect();
|
let tun: Vec<Arc<Tun>> = tun.into_iter().map(Arc::new).collect();
|
||||||
let (ready_tx, ready_rx) = mpsc::channel(MPSC_BUFFER_LEN);
|
let (ready_tx, ready_rx) = mpsc::channel(MPSC_BUFFER_LEN);
|
||||||
@ -301,14 +369,18 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Listens for incoming connections on the given `port`.
|
||||||
pub fn listen(&mut self, port: u16) {
|
pub fn listen(&mut self, port: u16) {
|
||||||
assert!(self.shared.listening.write().unwrap().insert(port));
|
assert!(self.shared.listening.write().unwrap().insert(port));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Accepts an incoming connection.
|
||||||
pub async fn accept(&mut self) -> Socket {
|
pub async fn accept(&mut self) -> Socket {
|
||||||
self.ready.recv().await.unwrap()
|
self.ready.recv().await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Connects to the remote end. `None` returned means
|
||||||
|
/// the connection attempt failed.
|
||||||
pub async fn connect(&mut self, addr: SocketAddrV4) -> Option<Socket> {
|
pub async fn connect(&mut self, addr: SocketAddrV4) -> Option<Socket> {
|
||||||
let mut rng = SmallRng::from_entropy();
|
let mut rng = SmallRng::from_entropy();
|
||||||
let local_port: u16 = rng.gen_range(1024..65535);
|
let local_port: u16 = rng.gen_range(1024..65535);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user