mirror of
https://github.com/dndx/phantun.git
synced 2025-09-16 12:14:29 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b40ca10cc1 | ||
|
30f0a1118b | ||
|
fd607bc72a | ||
|
939e4aa94e | ||
|
7bcfada87b | ||
|
fe18a49d40 | ||
|
b707c5bd12 | ||
|
6af7757456 | ||
|
f374ac8081 | ||
|
50346c1ba0 | ||
|
f649c79656 | ||
|
c91bda7e6a | ||
|
00a308a005 |
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -26,9 +26,9 @@ jobs:
|
|||||||
- aarch64-unknown-linux-gnu
|
- aarch64-unknown-linux-gnu
|
||||||
- aarch64-unknown-linux-musl
|
- aarch64-unknown-linux-musl
|
||||||
- mips-unknown-linux-gnu
|
- mips-unknown-linux-gnu
|
||||||
#- mips-unknown-linux-musl # currently does not build due to libc::sock_txtime not found, need a newer release of libc
|
- mips-unknown-linux-musl
|
||||||
- mipsel-unknown-linux-gnu
|
- mipsel-unknown-linux-gnu
|
||||||
#- mipsel-unknown-linux-musl
|
- mipsel-unknown-linux-musl
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
@@ -35,7 +35,7 @@ Table of Contents
|
|||||||
|
|
||||||
# Latest release
|
# Latest release
|
||||||
|
|
||||||
[v0.4.2](https://github.com/dndx/phantun/releases/tag/v0.4.2)
|
[v0.5.0](https://github.com/dndx/phantun/releases/tag/v0.5.0)
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
@@ -329,6 +329,8 @@ Test command: `iperf3 -c <IP> -p <PORT> -R -u -l 1400 -b 1000m -t 30 -P 5`
|
|||||||
| Phantun (5 streams) | 5.00 Gbits/sec | 2.38 Gbits/sec | 95% (all cores utilized) |
|
| Phantun (5 streams) | 5.00 Gbits/sec | 2.38 Gbits/sec | 95% (all cores utilized) |
|
||||||
| udp2raw (`cipher-mode=none` `auth-mode=none` `disable-anti-replay`) (5 streams) | 5.00 Gbits/sec | 770 Mbits/sec | 50% (2 cores at 100%) |
|
| udp2raw (`cipher-mode=none` `auth-mode=none` `disable-anti-replay`) (5 streams) | 5.00 Gbits/sec | 770 Mbits/sec | 50% (2 cores at 100%) |
|
||||||
|
|
||||||
|
Writeup on some of the techniques used in Phantun to achieve this performance result: [Writing Highly Efficient UDP Server in Rust](https://idndx.com/writing-highly-efficient-udp-server-in-rust/).
|
||||||
|
|
||||||
[Back to TOC](#table-of-contents)
|
[Back to TOC](#table-of-contents)
|
||||||
|
|
||||||
# Future plans
|
# Future plans
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fake-tcp"
|
name = "fake-tcp"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
edition = "2021"
|
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"
|
||||||
@@ -16,10 +16,10 @@ benchmark = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
pnet = "0.30"
|
pnet = "0.31"
|
||||||
tokio = { version = "1.14", features = ["full"] }
|
tokio = { version = "1.14", features = ["full"] }
|
||||||
rand = { version = "0.8", features = ["small_rng"] }
|
rand = { version = "0.8", features = ["small_rng"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
internet-checksum = "0.2"
|
internet-checksum = "0.2"
|
||||||
tokio-tun = "0.5"
|
tokio-tun = "0.7"
|
||||||
flume = "0.10"
|
flume = "0.10"
|
||||||
|
@@ -436,8 +436,7 @@ impl Stack {
|
|||||||
let mut tuples: HashMap<AddrTuple, flume::Sender<Bytes>> = HashMap::new();
|
let mut tuples: HashMap<AddrTuple, flume::Sender<Bytes>> = HashMap::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut buf = BytesMut::with_capacity(MAX_PACKET_LEN);
|
let mut buf = BytesMut::zeroed(MAX_PACKET_LEN);
|
||||||
buf.resize(MAX_PACKET_LEN, 0);
|
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
size = tun.recv(&mut buf) => {
|
size = tun.recv(&mut buf) => {
|
||||||
|
@@ -47,8 +47,7 @@ pub fn build_tcp_packet(
|
|||||||
let tcp_header_len = TCP_HEADER_LEN + if wscale { 4 } else { 0 }; // nop + wscale
|
let tcp_header_len = TCP_HEADER_LEN + if wscale { 4 } else { 0 }; // nop + wscale
|
||||||
let tcp_total_len = tcp_header_len + payload.map_or(0, |payload| payload.len());
|
let tcp_total_len = tcp_header_len + payload.map_or(0, |payload| payload.len());
|
||||||
let total_len = ip_header_len + tcp_total_len;
|
let total_len = ip_header_len + tcp_total_len;
|
||||||
let mut buf = BytesMut::with_capacity(total_len);
|
let mut buf = BytesMut::zeroed(total_len);
|
||||||
buf.resize(total_len, 0);
|
|
||||||
|
|
||||||
let mut ip_buf = buf.split_to(ip_header_len);
|
let mut ip_buf = buf.split_to(ip_header_len);
|
||||||
let mut tcp_buf = buf.split_to(tcp_total_len);
|
let mut tcp_buf = buf.split_to(tcp_total_len);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "phantun"
|
name = "phantun"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
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"
|
||||||
@@ -11,14 +11,14 @@ Transforms UDP stream into (fake) TCP streams that can go through
|
|||||||
Layer 3 & Layer 4 (NAPT) firewalls/NATs.
|
Layer 3 & Layer 4 (NAPT) firewalls/NATs.
|
||||||
"""
|
"""
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.0", features = ["cargo"] }
|
clap = { version = "4.0", features = ["cargo"] }
|
||||||
socket2 = { version = "0.4", features = ["all"] }
|
socket2 = { version = "0.4", features = ["all"] }
|
||||||
fake-tcp = { path = "../fake-tcp", version = "0.4" }
|
fake-tcp = { path = "../fake-tcp", version = "0.5" }
|
||||||
tokio = { version = "1.14", features = ["full"] }
|
tokio = { version = "1.14", features = ["full"] }
|
||||||
tokio-util = "0.7"
|
tokio-util = "0.7"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
tokio-tun = "0.5"
|
tokio-tun = "0.7"
|
||||||
num_cpus = "1.13"
|
num_cpus = "1.13"
|
||||||
neli = "0.6"
|
neli = "0.6"
|
||||||
nix = "0.24"
|
nix = "0.25"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
use clap::{crate_version, Arg, Command};
|
use clap::{crate_version, Arg, ArgAction, Command};
|
||||||
use fake_tcp::packet::MAX_PACKET_LEN;
|
use fake_tcp::packet::MAX_PACKET_LEN;
|
||||||
use fake_tcp::{Socket, Stack};
|
use fake_tcp::{Socket, Stack};
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
@@ -29,7 +29,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.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, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
|
.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),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("remote")
|
Arg::new("remote")
|
||||||
@@ -38,7 +37,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.value_name("IP or HOST NAME:PORT")
|
.value_name("IP or HOST NAME:PORT")
|
||||||
.help("Sets the address or host name and port where Phantun Client connects to Phantun Server, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
|
.help("Sets the address or host name and port where Phantun Client connects to Phantun Server, IPv6 address need to be specified as: \"[IPv6]:PORT\"")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun")
|
Arg::new("tun")
|
||||||
@@ -47,7 +45,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.value_name("tunX")
|
.value_name("tunX")
|
||||||
.help("Sets the Tun interface name, if absent, pick the next available name")
|
.help("Sets the Tun interface name, if absent, pick the next available name")
|
||||||
.default_value("")
|
.default_value("")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun_local")
|
Arg::new("tun_local")
|
||||||
@@ -56,7 +53,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.value_name("IP")
|
.value_name("IP")
|
||||||
.help("Sets the Tun interface IPv4 local address (O/S's end)")
|
.help("Sets the Tun interface IPv4 local address (O/S's end)")
|
||||||
.default_value("192.168.200.1")
|
.default_value("192.168.200.1")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun_peer")
|
Arg::new("tun_peer")
|
||||||
@@ -67,7 +63,6 @@ async fn main() -> io::Result<()> {
|
|||||||
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
|
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
|
||||||
in order for Phantun Client to connect to Phantun Server")
|
in order for Phantun Client to connect to Phantun Server")
|
||||||
.default_value("192.168.200.2")
|
.default_value("192.168.200.2")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("ipv4_only")
|
Arg::new("ipv4_only")
|
||||||
@@ -75,7 +70,7 @@ async fn main() -> io::Result<()> {
|
|||||||
.short('4')
|
.short('4')
|
||||||
.required(false)
|
.required(false)
|
||||||
.help("Only use IPv4 address when connecting to remote")
|
.help("Only use IPv4 address when connecting to remote")
|
||||||
.takes_value(false)
|
.action(ArgAction::SetTrue)
|
||||||
.conflicts_with_all(&["tun_local6", "tun_peer6"]),
|
.conflicts_with_all(&["tun_local6", "tun_peer6"]),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@@ -85,7 +80,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.value_name("IP")
|
.value_name("IP")
|
||||||
.help("Sets the Tun interface IPv6 local address (O/S's end)")
|
.help("Sets the Tun interface IPv6 local address (O/S's end)")
|
||||||
.default_value("fcc8::1")
|
.default_value("fcc8::1")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun_peer6")
|
Arg::new("tun_peer6")
|
||||||
@@ -96,7 +90,6 @@ async fn main() -> io::Result<()> {
|
|||||||
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
|
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
|
||||||
in order for Phantun Client to connect to Phantun Server")
|
in order for Phantun Client to connect to Phantun Server")
|
||||||
.default_value("fcc8::2")
|
.default_value("fcc8::2")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("handshake_packet")
|
Arg::new("handshake_packet")
|
||||||
@@ -107,19 +100,18 @@ async fn main() -> io::Result<()> {
|
|||||||
first data packet to the server.\n\
|
first data packet to the server.\n\
|
||||||
Note: ensure this file's size does not exceed the MTU of the outgoing interface. \
|
Note: ensure this file's size does not exceed the MTU of the outgoing interface. \
|
||||||
The content is always sent out in a single packet and will not be further segmented")
|
The content is always sent out in a single packet and will not be further segmented")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let local_addr: SocketAddr = matches
|
let local_addr: SocketAddr = matches
|
||||||
.value_of("local")
|
.get_one::<String>("local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad local address");
|
.expect("bad local address");
|
||||||
|
|
||||||
let ipv4_only = matches.is_present("ipv4_only");
|
let ipv4_only = matches.get_flag("ipv4_only");
|
||||||
|
|
||||||
let remote_addr = tokio::net::lookup_host(matches.value_of("remote").unwrap())
|
let remote_addr = tokio::net::lookup_host(matches.get_one::<String>("remote").unwrap())
|
||||||
.await
|
.await
|
||||||
.expect("bad remote address or host")
|
.expect("bad remote address or host")
|
||||||
.find(|addr| !ipv4_only || addr.is_ipv4())
|
.find(|addr| !ipv4_only || addr.is_ipv4())
|
||||||
@@ -127,32 +119,32 @@ async fn main() -> io::Result<()> {
|
|||||||
info!("Remote address is: {}", remote_addr);
|
info!("Remote address is: {}", remote_addr);
|
||||||
|
|
||||||
let tun_local: Ipv4Addr = matches
|
let tun_local: Ipv4Addr = matches
|
||||||
.value_of("tun_local")
|
.get_one::<String>("tun_local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad local address for Tun interface");
|
.expect("bad local address for Tun interface");
|
||||||
let tun_peer: Ipv4Addr = matches
|
let tun_peer: Ipv4Addr = matches
|
||||||
.value_of("tun_peer")
|
.get_one::<String>("tun_peer")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad peer address for Tun interface");
|
.expect("bad peer address for Tun interface");
|
||||||
|
|
||||||
let (tun_local6, tun_peer6) = if ipv4_only {
|
let (tun_local6, tun_peer6) = if matches.get_flag("ipv4_only") {
|
||||||
(None, None)
|
(None, None)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
matches
|
matches
|
||||||
.value_of("tun_local6")
|
.get_one::<String>("tun_local6")
|
||||||
.map(|v| v.parse().expect("bad local address for Tun interface")),
|
.map(|v| v.parse().expect("bad local address for Tun interface")),
|
||||||
matches
|
matches
|
||||||
.value_of("tun_peer6")
|
.get_one::<String>("tun_peer6")
|
||||||
.map(|v| v.parse().expect("bad peer address for Tun interface")),
|
.map(|v| v.parse().expect("bad peer address for Tun interface")),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let tun_name = matches.value_of("tun").unwrap();
|
let tun_name = matches.get_one::<String>("tun").unwrap();
|
||||||
let handshake_packet: Option<Vec<u8>> = matches
|
let handshake_packet: Option<Vec<u8>> = matches
|
||||||
.value_of("handshake_packet")
|
.get_one::<String>("handshake_packet")
|
||||||
.map(fs::read)
|
.map(fs::read)
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
use clap::{crate_version, Arg, Command};
|
use clap::{crate_version, Arg, ArgAction, Command};
|
||||||
use fake_tcp::packet::MAX_PACKET_LEN;
|
use fake_tcp::packet::MAX_PACKET_LEN;
|
||||||
use fake_tcp::Stack;
|
use fake_tcp::Stack;
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
@@ -29,7 +29,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.value_name("PORT")
|
.value_name("PORT")
|
||||||
.help("Sets the port where Phantun Server listens for incoming Phantun Client TCP connections")
|
.help("Sets the port where Phantun Server listens for incoming Phantun Client TCP connections")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("remote")
|
Arg::new("remote")
|
||||||
@@ -38,7 +37,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.required(true)
|
.required(true)
|
||||||
.value_name("IP or HOST NAME:PORT")
|
.value_name("IP or HOST NAME:PORT")
|
||||||
.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\"")
|
.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),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun")
|
Arg::new("tun")
|
||||||
@@ -47,7 +45,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.value_name("tunX")
|
.value_name("tunX")
|
||||||
.help("Sets the Tun interface name, if absent, pick the next available name")
|
.help("Sets the Tun interface name, if absent, pick the next available name")
|
||||||
.default_value("")
|
.default_value("")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun_local")
|
Arg::new("tun_local")
|
||||||
@@ -56,7 +53,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.value_name("IP")
|
.value_name("IP")
|
||||||
.help("Sets the Tun interface local address (O/S's end)")
|
.help("Sets the Tun interface local address (O/S's end)")
|
||||||
.default_value("192.168.201.1")
|
.default_value("192.168.201.1")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun_peer")
|
Arg::new("tun_peer")
|
||||||
@@ -67,7 +63,6 @@ async fn main() -> io::Result<()> {
|
|||||||
You will need to setup DNAT rules to this address in order for Phantun Server \
|
You will need to setup DNAT rules to this address in order for Phantun Server \
|
||||||
to accept TCP traffic from Phantun Client")
|
to accept TCP traffic from Phantun Client")
|
||||||
.default_value("192.168.201.2")
|
.default_value("192.168.201.2")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("ipv4_only")
|
Arg::new("ipv4_only")
|
||||||
@@ -75,7 +70,7 @@ async fn main() -> io::Result<()> {
|
|||||||
.short('4')
|
.short('4')
|
||||||
.required(false)
|
.required(false)
|
||||||
.help("Do not assign IPv6 addresses to Tun interface")
|
.help("Do not assign IPv6 addresses to Tun interface")
|
||||||
.takes_value(false)
|
.action(ArgAction::SetTrue)
|
||||||
.conflicts_with_all(&["tun_local6", "tun_peer6"]),
|
.conflicts_with_all(&["tun_local6", "tun_peer6"]),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@@ -85,7 +80,6 @@ async fn main() -> io::Result<()> {
|
|||||||
.value_name("IP")
|
.value_name("IP")
|
||||||
.help("Sets the Tun interface IPv6 local address (O/S's end)")
|
.help("Sets the Tun interface IPv6 local address (O/S's end)")
|
||||||
.default_value("fcc9::1")
|
.default_value("fcc9::1")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("tun_peer6")
|
Arg::new("tun_peer6")
|
||||||
@@ -96,7 +90,6 @@ async fn main() -> io::Result<()> {
|
|||||||
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
|
You will need to setup SNAT/MASQUERADE rules on your Internet facing interface \
|
||||||
in order for Phantun Client to connect to Phantun Server")
|
in order for Phantun Client to connect to Phantun Server")
|
||||||
.default_value("fcc9::2")
|
.default_value("fcc9::2")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("handshake_packet")
|
Arg::new("handshake_packet")
|
||||||
@@ -107,50 +100,50 @@ async fn main() -> io::Result<()> {
|
|||||||
first data packet to the client.\n\
|
first data packet to the client.\n\
|
||||||
Note: ensure this file's size does not exceed the MTU of the outgoing interface. \
|
Note: ensure this file's size does not exceed the MTU of the outgoing interface. \
|
||||||
The content is always sent out in a single packet and will not be further segmented")
|
The content is always sent out in a single packet and will not be further segmented")
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let local_port: u16 = matches
|
let local_port: u16 = matches
|
||||||
.value_of("local")
|
.get_one::<String>("local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad local port");
|
.expect("bad local port");
|
||||||
|
|
||||||
let remote_addr = tokio::net::lookup_host(matches.value_of("remote").unwrap())
|
let remote_addr = tokio::net::lookup_host(matches.get_one::<String>("remote").unwrap())
|
||||||
.await
|
.await
|
||||||
.expect("bad remote address or host")
|
.expect("bad remote address or host")
|
||||||
.next()
|
.next()
|
||||||
.expect("unable to resolve remote host name");
|
.expect("unable to resolve remote host name");
|
||||||
|
|
||||||
info!("Remote address is: {}", remote_addr);
|
info!("Remote address is: {}", remote_addr);
|
||||||
|
|
||||||
let tun_local: Ipv4Addr = matches
|
let tun_local: Ipv4Addr = matches
|
||||||
.value_of("tun_local")
|
.get_one::<String>("tun_local")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad local address for Tun interface");
|
.expect("bad local address for Tun interface");
|
||||||
let tun_peer: Ipv4Addr = matches
|
let tun_peer: Ipv4Addr = matches
|
||||||
.value_of("tun_peer")
|
.get_one::<String>("tun_peer")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
.expect("bad peer address for Tun interface");
|
.expect("bad peer address for Tun interface");
|
||||||
|
|
||||||
let (tun_local6, tun_peer6) = if matches.is_present("ipv4_only") {
|
let (tun_local6, tun_peer6) = if matches.get_flag("ipv4_only") {
|
||||||
(None, None)
|
(None, None)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
matches
|
matches
|
||||||
.value_of("tun_local6")
|
.get_one::<String>("tun_local6")
|
||||||
.map(|v| v.parse().expect("bad local address for Tun interface")),
|
.map(|v| v.parse().expect("bad local address for Tun interface")),
|
||||||
matches
|
matches
|
||||||
.value_of("tun_peer6")
|
.get_one::<String>("tun_peer6")
|
||||||
.map(|v| v.parse().expect("bad peer address for Tun interface")),
|
.map(|v| v.parse().expect("bad peer address for Tun interface")),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let tun_name = matches.value_of("tun").unwrap();
|
let tun_name = matches.get_one::<String>("tun").unwrap();
|
||||||
let handshake_packet: Option<Vec<u8>> = matches
|
let handshake_packet: Option<Vec<u8>> = matches
|
||||||
.value_of("handshake_packet")
|
.get_one::<String>("handshake_packet")
|
||||||
.map(fs::read)
|
.map(fs::read)
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user