mirror of
https://github.com/dndx/phantun.git
synced 2025-09-16 20:24:29 +08:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c5a5116808 | ||
|
e8f2457cb5 | ||
|
583cdbe300 | ||
|
91988520e5 | ||
|
49cc6a6865 | ||
|
7390d4bf27 | ||
|
95e762f5fd | ||
|
c9043015f2 | ||
|
494abf37c5 | ||
|
cab87bd75b | ||
|
042f5af49f | ||
|
f667f56747 | ||
|
49665b906f | ||
|
e9cde27923 | ||
|
cf588db042 | ||
|
0e27822995 | ||
|
eeca1d0108 | ||
|
35541df7e2 | ||
|
3219cb9f38 | ||
|
41e86521b7 | ||
|
427fb7c19a |
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
|
||||||
|
- package-ecosystem: "cargo"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -16,12 +16,19 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target:
|
target:
|
||||||
- x86_64-unknown-linux-gnu
|
- x86_64-unknown-linux-gnu
|
||||||
|
- x86_64-unknown-linux-musl
|
||||||
- i686-unknown-linux-gnu
|
- i686-unknown-linux-gnu
|
||||||
|
- i686-unknown-linux-musl
|
||||||
- armv7-unknown-linux-gnueabihf
|
- armv7-unknown-linux-gnueabihf
|
||||||
|
- armv7-unknown-linux-musleabihf
|
||||||
- arm-unknown-linux-gnueabihf
|
- arm-unknown-linux-gnueabihf
|
||||||
|
- arm-unknown-linux-musleabihf
|
||||||
- aarch64-unknown-linux-gnu
|
- aarch64-unknown-linux-gnu
|
||||||
|
- aarch64-unknown-linux-musl
|
||||||
- mips-unknown-linux-gnu
|
- mips-unknown-linux-gnu
|
||||||
|
- mips-unknown-linux-musl
|
||||||
- mipsel-unknown-linux-gnu
|
- mipsel-unknown-linux-gnu
|
||||||
|
- mipsel-unknown-linux-musl
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
3
.github/workflows/rust.yml
vendored
3
.github/workflows/rust.yml
vendored
@@ -12,6 +12,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
- name: Run lint
|
- name: Run lint
|
||||||
run: cargo clippy --verbose
|
run: cargo clippy --verbose
|
||||||
- name: Build
|
- name: Build
|
||||||
|
21
README.md
21
README.md
@@ -31,7 +31,7 @@ Table of Contents
|
|||||||
|
|
||||||
# Latest release
|
# Latest release
|
||||||
|
|
||||||
[v0.1.1](https://github.com/dndx/phantun/releases/tag/v0.1.1)
|
[v0.2.2](https://github.com/dndx/phantun/releases/tag/v0.2.2)
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
@@ -84,6 +84,10 @@ and change the destination IP address to where the server is listening for incom
|
|||||||
In those cases, the machine/iptables running Phantun acts as the "router" that allows Phantun
|
In those cases, the machine/iptables running Phantun acts as the "router" that allows Phantun
|
||||||
to communicate with outside using it's private IP addresses.
|
to communicate with outside using it's private IP addresses.
|
||||||
|
|
||||||
|
As of Phantun v0.2.2, IPv6 support for UDP endpoints has been added, however Fake TCP IPv6 support
|
||||||
|
has not been finished yet. To specify an IPv6 address, use the following format: `[::1]:1234` with
|
||||||
|
the command line options.
|
||||||
|
|
||||||
[Back to TOC](#table-of-contents)
|
[Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
## 1. Enable Kernel IP forwarding
|
## 1. Enable Kernel IP forwarding
|
||||||
@@ -218,18 +222,13 @@ of obfuscation.
|
|||||||
For people who use Phantun to tunnel [WireGuard®](https://www.wireguard.com) UDP packets, here are some guidelines on figuring
|
For people who use Phantun to tunnel [WireGuard®](https://www.wireguard.com) UDP packets, here are some guidelines on figuring
|
||||||
out the correct MTU to use for your WireGuard interface.
|
out the correct MTU to use for your WireGuard interface.
|
||||||
|
|
||||||
WireGuard MTU = `MAX_OF_16`(Interface MTU - IP header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes))
|
WireGuard MTU = Interface MTU - IP header (20 bytes) - TCP header (20 bytes) - WireGuard overhead (32 bytes)
|
||||||
|
|
||||||
Where:
|
|
||||||
|
|
||||||
`MAX_OF_16` takes an input integer and calculates the maximum multiple of 16 not exceeding the input. This
|
|
||||||
is needed because WireGuard will always pad it's payloads to multiple of 16 bytes.
|
|
||||||
|
|
||||||
For example, for a Ethernet interface with 1500 bytes MTU, the WireGuard interface MTU should be set as:
|
For example, for a Ethernet interface with 1500 bytes MTU, the WireGuard interface MTU should be set as:
|
||||||
|
|
||||||
`MAX_OF_16`(1500 - 20 - 20 - 32) = 1424 bytes
|
1500 - 20 - 20 - 32 = 1428 bytes
|
||||||
|
|
||||||
The resulted Phantun TCP data packet will be 1424 + 20 + 20 + 32 = 1496 bytes which does not exceed the
|
The resulted Phantun TCP data packet will be 1500 bytes which does not exceed the
|
||||||
interface MTU of 1500.
|
interface MTU of 1500.
|
||||||
|
|
||||||
[Back to TOC](#table-of-contents)
|
[Back to TOC](#table-of-contents)
|
||||||
@@ -255,7 +254,7 @@ for tunneling TCP/UDP traffic between two test instances and MTU has been tuned
|
|||||||
|
|
||||||
# Future plans
|
# Future plans
|
||||||
|
|
||||||
* IPv6 support
|
* IPv6 support for fake-tcp
|
||||||
* Load balancing a single UDP stream into multiple TCP streams
|
* Load balancing a single UDP stream into multiple TCP streams
|
||||||
* Integration tests
|
* Integration tests
|
||||||
* Auto insertion/removal of required firewall rules
|
* Auto insertion/removal of required firewall rules
|
||||||
@@ -283,7 +282,7 @@ Here is a quick overview of comparison between those two to help you choose:
|
|||||||
| Tunneling MTU overhead | 12 bytes | 44 bytes |
|
| Tunneling MTU overhead | 12 bytes | 44 bytes |
|
||||||
| Seprate TCP connections for each UDP connection | Client/Server | Server only |
|
| Seprate TCP connections for each UDP connection | Client/Server | Server only |
|
||||||
| Anti-replay, encryption | ❌ | ✅ |
|
| Anti-replay, encryption | ❌ | ✅ |
|
||||||
| IPv6 | Planned | ✅ |
|
| IPv6 | UDP only | ✅ |
|
||||||
|
|
||||||
[Back to TOC](#table-of-contents)
|
[Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fake-tcp"
|
name = "fake-tcp"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Datong Sun <dndx@idndx.com>"]
|
authors = ["Datong Sun <dndx@idndx.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/dndx/phantun"
|
repository = "https://github.com/dndx/phantun"
|
||||||
@@ -21,4 +21,4 @@ tokio = { version = "1.12.0", features = ["full"] }
|
|||||||
rand = { version = "0.8.4", features = ["small_rng"] }
|
rand = { version = "0.8.4", features = ["small_rng"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
internet-checksum = "0.2.0"
|
internet-checksum = "0.2.0"
|
||||||
dndx-fork-tokio-tun = "0.3.16"
|
dndx-fork-tokio-tun = "0.4.0"
|
||||||
|
@@ -15,7 +15,6 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
use tokio::sync::mpsc::{self, Receiver, Sender};
|
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||||
use tokio::sync::watch;
|
|
||||||
use tokio::sync::Mutex as AsyncMutex;
|
use tokio::sync::Mutex as AsyncMutex;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
use tokio_tun::Tun;
|
use tokio_tun::Tun;
|
||||||
@@ -58,6 +57,7 @@ pub enum State {
|
|||||||
SynSent,
|
SynSent,
|
||||||
SynReceived,
|
SynReceived,
|
||||||
Established,
|
Established,
|
||||||
|
Closed,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
@@ -69,8 +69,6 @@ pub struct Socket {
|
|||||||
seq: AtomicU32,
|
seq: AtomicU32,
|
||||||
ack: AtomicU32,
|
ack: AtomicU32,
|
||||||
state: State,
|
state: State,
|
||||||
closing_tx: watch::Sender<()>,
|
|
||||||
closing_rx: watch::Receiver<()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Socket {
|
impl Socket {
|
||||||
@@ -83,7 +81,6 @@ impl Socket {
|
|||||||
state: State,
|
state: State,
|
||||||
) -> (Socket, Sender<Bytes>) {
|
) -> (Socket, Sender<Bytes>) {
|
||||||
let (incoming_tx, incoming_rx) = mpsc::channel(MPSC_BUFFER_LEN);
|
let (incoming_tx, incoming_rx) = mpsc::channel(MPSC_BUFFER_LEN);
|
||||||
let (closing_tx, closing_rx) = watch::channel(());
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Socket {
|
Socket {
|
||||||
@@ -95,8 +92,6 @@ impl Socket {
|
|||||||
seq: AtomicU32::new(0),
|
seq: AtomicU32::new(0),
|
||||||
ack: AtomicU32::new(ack.unwrap_or(0)),
|
ack: AtomicU32::new(ack.unwrap_or(0)),
|
||||||
state,
|
state,
|
||||||
closing_tx,
|
|
||||||
closing_rx,
|
|
||||||
},
|
},
|
||||||
incoming_tx,
|
incoming_tx,
|
||||||
)
|
)
|
||||||
@@ -114,8 +109,6 @@ impl Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send(&self, payload: &[u8]) -> Option<()> {
|
pub async fn send(&self, payload: &[u8]) -> Option<()> {
|
||||||
let mut closing = self.closing_rx.clone();
|
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Established => {
|
State::Established => {
|
||||||
let buf = self.build_tcp_packet(tcp::TcpFlags::ACK, Some(payload));
|
let buf = self.build_tcp_packet(tcp::TcpFlags::ACK, Some(payload));
|
||||||
@@ -126,28 +119,22 @@ impl Socket {
|
|||||||
res.unwrap();
|
res.unwrap();
|
||||||
Some(())
|
Some(())
|
||||||
},
|
},
|
||||||
_ = closing.changed() => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
State::Closed => None,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv(&self, buf: &mut [u8]) -> Option<usize> {
|
pub async fn recv(&self, buf: &mut [u8]) -> Option<usize> {
|
||||||
let mut closing = self.closing_rx.clone();
|
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
State::Established => {
|
State::Established => {
|
||||||
let mut incoming = self.incoming.lock().await;
|
let mut incoming = self.incoming.lock().await;
|
||||||
tokio::select! {
|
incoming.recv().await.and_then(|raw_buf| {
|
||||||
Some(raw_buf) = incoming.recv() => {
|
|
||||||
let (_v4_packet, tcp_packet) = parse_ipv4_packet(&raw_buf);
|
let (_v4_packet, tcp_packet) = parse_ipv4_packet(&raw_buf);
|
||||||
|
|
||||||
if (tcp_packet.get_flags() & tcp::TcpFlags::RST) != 0 {
|
if (tcp_packet.get_flags() & tcp::TcpFlags::RST) != 0 {
|
||||||
info!("Connection {} reset by peer", self);
|
info!("Connection {} reset by peer", self);
|
||||||
self.close();
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,20 +146,13 @@ impl Socket {
|
|||||||
buf[..payload.len()].copy_from_slice(payload);
|
buf[..payload.len()].copy_from_slice(payload);
|
||||||
|
|
||||||
Some(payload.len())
|
Some(payload.len())
|
||||||
},
|
})
|
||||||
_ = closing.changed() => {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
State::Closed => None,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&self) {
|
|
||||||
self.closing_tx.send(()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn accept(mut self) {
|
async fn accept(mut self) {
|
||||||
for _ in 0..RETRIES {
|
for _ in 0..RETRIES {
|
||||||
match self.state {
|
match self.state {
|
||||||
@@ -272,6 +252,8 @@ impl Socket {
|
|||||||
|
|
||||||
impl Drop for Socket {
|
impl Drop for Socket {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
self.state = State::Closed;
|
||||||
|
|
||||||
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
|
||||||
assert!(self.shared.tuples.write().unwrap().remove(&tuple).is_some());
|
assert!(self.shared.tuples.write().unwrap().remove(&tuple).is_some());
|
||||||
@@ -282,7 +264,7 @@ impl Drop for Socket {
|
|||||||
if let Err(e) = self.tun.try_send(&buf) {
|
if let Err(e) = self.tun.try_send(&buf) {
|
||||||
warn!("Unable to send RST to remote end: {}", e);
|
warn!("Unable to send RST to remote end: {}", e);
|
||||||
}
|
}
|
||||||
self.close();
|
|
||||||
info!("Fake TCP connection to {} closed", self);
|
info!("Fake TCP connection to {} closed", self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,16 +367,21 @@ impl Stack {
|
|||||||
|
|
||||||
let tuple = AddrTuple::new(local_addr, remote_addr);
|
let tuple = AddrTuple::new(local_addr, remote_addr);
|
||||||
if let Some(c) = tuples.get(&tuple) {
|
if let Some(c) = tuples.get(&tuple) {
|
||||||
c.send(buf).await.unwrap();
|
if c.send(buf).await.is_err() {
|
||||||
|
trace!("Cache hit, but receiver already closed, dropping packet");
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// If not Ok, receiver has been closed and just fall through to the slow
|
||||||
|
// path below
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
trace!("Cache miss, checking the shared tuples table for connection");
|
trace!("Cache miss, checking the shared tuples table for connection");
|
||||||
let sender;
|
let sender = {
|
||||||
{
|
|
||||||
let tuples = shared.tuples.read().unwrap();
|
let tuples = shared.tuples.read().unwrap();
|
||||||
sender = tuples.get(&tuple).cloned();
|
tuples.get(&tuple).cloned()
|
||||||
}
|
};
|
||||||
|
|
||||||
if let Some(c) = sender {
|
if let Some(c) = sender {
|
||||||
trace!("Storing connection information into local tuples");
|
trace!("Storing connection information into local tuples");
|
||||||
|
@@ -32,7 +32,7 @@ pub fn build_tcp_packet(
|
|||||||
v4.set_version(4);
|
v4.set_version(4);
|
||||||
v4.set_header_length(IPV4_HEADER_LEN as u8 / 4);
|
v4.set_header_length(IPV4_HEADER_LEN as u8 / 4);
|
||||||
v4.set_next_level_protocol(ip::IpNextHeaderProtocols::Tcp);
|
v4.set_next_level_protocol(ip::IpNextHeaderProtocols::Tcp);
|
||||||
v4.set_ttl(32);
|
v4.set_ttl(64);
|
||||||
v4.set_source(*local_addr.ip());
|
v4.set_source(*local_addr.ip());
|
||||||
v4.set_destination(*remote_addr.ip());
|
v4.set_destination(*remote_addr.ip());
|
||||||
v4.set_total_length(total_len.try_into().unwrap());
|
v4.set_total_length(total_len.try_into().unwrap());
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "phantun"
|
name = "phantun"
|
||||||
version = "0.2.0"
|
version = "0.2.3"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Datong Sun <dndx@idndx.com>"]
|
authors = ["Datong Sun <dndx@idndx.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/dndx/phantun"
|
repository = "https://github.com/dndx/phantun"
|
||||||
@@ -13,9 +13,9 @@ Layer 3 & Layer 4 (NAPT) firewalls/NATs.
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
socket2 = { version = "0.4.2", features = ["all"] }
|
socket2 = { version = "0.4.2", features = ["all"] }
|
||||||
fake-tcp = "0.1.1"
|
fake-tcp = "0.2.0"
|
||||||
tokio = { version = "1.12.0", features = ["full"] }
|
tokio = { version = "1.12.0", features = ["full"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
dndx-fork-tokio-tun = "0.3.16"
|
dndx-fork-tokio-tun = "0.4.0"
|
||||||
num_cpus = "1.13.0"
|
num_cpus = "1.13.0"
|
||||||
|
@@ -6,7 +6,7 @@ use fake_tcp::{Socket, Stack};
|
|||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
@@ -16,8 +16,17 @@ use tokio_tun::TunBuilder;
|
|||||||
|
|
||||||
const UDP_TTL: Duration = Duration::from_secs(180);
|
const UDP_TTL: Duration = Duration::from_secs(180);
|
||||||
|
|
||||||
fn new_udp_reuseport(addr: SocketAddrV4) -> UdpSocket {
|
fn new_udp_reuseport(addr: SocketAddr) -> UdpSocket {
|
||||||
let udp_sock = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::DGRAM, None).unwrap();
|
let udp_sock = socket2::Socket::new(
|
||||||
|
if addr.is_ipv4() {
|
||||||
|
socket2::Domain::IPV4
|
||||||
|
} else {
|
||||||
|
socket2::Domain::IPV6
|
||||||
|
},
|
||||||
|
socket2::Type::DGRAM,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
udp_sock.set_reuse_port(true).unwrap();
|
udp_sock.set_reuse_port(true).unwrap();
|
||||||
// from tokio-rs/mio/blob/master/src/sys/unix/net.rs
|
// from tokio-rs/mio/blob/master/src/sys/unix/net.rs
|
||||||
udp_sock.set_cloexec(true).unwrap();
|
udp_sock.set_cloexec(true).unwrap();
|
||||||
@@ -40,7 +49,7 @@ async fn main() {
|
|||||||
.long("local")
|
.long("local")
|
||||||
.required(true)
|
.required(true)
|
||||||
.value_name("IP:PORT")
|
.value_name("IP:PORT")
|
||||||
.help("Sets the IP and port where Phantun Client listens for incoming UDP datagrams")
|
.help("Sets the IP and port where Phantun Client listens for incoming UDP datagrams, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@@ -48,8 +57,8 @@ async fn main() {
|
|||||||
.short("r")
|
.short("r")
|
||||||
.long("remote")
|
.long("remote")
|
||||||
.required(true)
|
.required(true)
|
||||||
.value_name("IP:PORT")
|
.value_name("IP or HOST NAME:PORT")
|
||||||
.help("Sets the address and port where Phantun Client connects to Phantun Server")
|
.help("Sets the address or host name and port where Phantun Client connects to Phantun Server")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@@ -83,16 +92,24 @@ async fn main() {
|
|||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let local_addr: SocketAddrV4 = matches
|
let local_addr: SocketAddr = matches
|
||||||
.value_of("local")
|
.value_of("local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad local address");
|
.expect("bad local address");
|
||||||
let remote_addr: SocketAddrV4 = matches
|
|
||||||
.value_of("remote")
|
let remote_addr = tokio::net::lookup_host(matches.value_of("remote").unwrap())
|
||||||
.unwrap()
|
.await
|
||||||
.parse()
|
.expect("bad remote address or host")
|
||||||
.expect("bad remote address");
|
.next()
|
||||||
|
.expect("unable to resolve remote host name");
|
||||||
|
let remote_addr = if let SocketAddr::V4(addr) = remote_addr {
|
||||||
|
addr
|
||||||
|
} else {
|
||||||
|
panic!("only IPv4 remote address is supported");
|
||||||
|
};
|
||||||
|
info!("Remote address is: {}", remote_addr);
|
||||||
|
|
||||||
let tun_local: Ipv4Addr = matches
|
let tun_local: Ipv4Addr = matches
|
||||||
.value_of("tun_local")
|
.value_of("tun_local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -117,7 +134,7 @@ async fn main() {
|
|||||||
info!("Created TUN device {}", tun[0].name());
|
info!("Created TUN device {}", tun[0].name());
|
||||||
|
|
||||||
let udp_sock = Arc::new(new_udp_reuseport(local_addr));
|
let udp_sock = Arc::new(new_udp_reuseport(local_addr));
|
||||||
let connections = Arc::new(RwLock::new(HashMap::<SocketAddrV4, Arc<Socket>>::new()));
|
let connections = Arc::new(RwLock::new(HashMap::<SocketAddr, Arc<Socket>>::new()));
|
||||||
|
|
||||||
let mut stack = Stack::new(tun);
|
let mut stack = Stack::new(tun);
|
||||||
|
|
||||||
@@ -126,7 +143,7 @@ async fn main() {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Ok((size, SocketAddr::V4(addr))) = udp_sock.recv_from(&mut buf_r) => {
|
Ok((size, addr)) = udp_sock.recv_from(&mut buf_r) => {
|
||||||
// seen UDP packet to listening socket, this means:
|
// seen UDP packet to listening socket, this means:
|
||||||
// 1. It is a new UDP connection, or
|
// 1. It is a new UDP connection, or
|
||||||
// 2. It is some extra packets not filtered by more specific
|
// 2. It is some extra packets not filtered by more specific
|
||||||
|
@@ -4,7 +4,7 @@ use clap::{crate_version, App, Arg};
|
|||||||
use fake_tcp::packet::MAX_PACKET_LEN;
|
use fake_tcp::packet::MAX_PACKET_LEN;
|
||||||
use fake_tcp::Stack;
|
use fake_tcp::Stack;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
use std::net::Ipv4Addr;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use tokio::time::{self, Duration};
|
use tokio::time::{self, Duration};
|
||||||
use tokio_tun::TunBuilder;
|
use tokio_tun::TunBuilder;
|
||||||
@@ -31,8 +31,8 @@ async fn main() {
|
|||||||
.short("r")
|
.short("r")
|
||||||
.long("remote")
|
.long("remote")
|
||||||
.required(true)
|
.required(true)
|
||||||
.value_name("IP:PORT")
|
.value_name("IP or HOST NAME:PORT")
|
||||||
.help("Sets the address and port where Phantun Server forwards UDP packets to")
|
.help("Sets the address or host name and port where Phantun Server forwards UDP packets to, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@@ -71,11 +71,14 @@ async fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad local port");
|
.expect("bad local port");
|
||||||
let remote_addr: SocketAddrV4 = matches
|
|
||||||
.value_of("remote")
|
let remote_addr = tokio::net::lookup_host(matches.value_of("remote").unwrap())
|
||||||
.unwrap()
|
.await
|
||||||
.parse()
|
.expect("bad remote address or host")
|
||||||
.expect("bad remote address");
|
.next()
|
||||||
|
.expect("unable to resolve remote host name");
|
||||||
|
info!("Remote address is: {}", remote_addr);
|
||||||
|
|
||||||
let tun_local: Ipv4Addr = matches
|
let tun_local: Ipv4Addr = matches
|
||||||
.value_of("tun_local")
|
.value_of("tun_local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -113,7 +116,13 @@ async fn main() {
|
|||||||
info!("New connection: {}", sock);
|
info!("New connection: {}", sock);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let udp_sock = UdpSocket::bind("0.0.0.0:0").await.unwrap();
|
let udp_sock = UdpSocket::bind(if remote_addr.is_ipv4() {
|
||||||
|
"0.0.0.0:0"
|
||||||
|
} else {
|
||||||
|
"[::]:0"
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
udp_sock.connect(remote_addr).await.unwrap();
|
udp_sock.connect(remote_addr).await.unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
Reference in New Issue
Block a user