9 Commits

Author SHA1 Message Date
dependabot[bot]
850de2febe chore(deps): bump socket2 from 0.6.0 to 0.6.1
Bumps [socket2](https://github.com/rust-lang/socket2) from 0.6.0 to 0.6.1.
- [Release notes](https://github.com/rust-lang/socket2/releases)
- [Changelog](https://github.com/rust-lang/socket2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/socket2/compare/v0.6.0...v0.6.1)

---
updated-dependencies:
- dependency-name: socket2
  dependency-version: 0.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 08:19:18 +00:00
Heng lu
7f7da10b1b fix(docker): fix parameter parsing and signal handling in phantun.sh (#235)
All checks were successful
Docker image build / build (push) Successful in 5m48s
Rust / build (push) Successful in 4m6s
- Fix awk delimiter parsing for --tun, --tun-peer, --tun-peer6 arguments
- Change shebang from sh to bash to fix signal trap handling
- Add missing dependencies (iproute2, iptables, procps) to Dockerfile
2025-10-06 09:29:18 -07:00
WGH
9d74a6bfeb style(phantun): calculate cmsg buffer size statically
Closes #178 and supersedes #225.
2025-10-06 09:25:21 -07:00
dependabot[bot]
9bdfd76819 chore(deps): bump actions/checkout from 4 to 5
Some checks failed
Docker image build / build (push) Has been cancelled
Rust / build (push) Has been cancelled
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 22:39:04 +08:00
Datong Sun
d1c18c64f3 docs(readme): bump latest release to 0.8.1
Some checks failed
Docker image build / build (push) Has been cancelled
Rust / build (push) Has been cancelled
2025-08-22 21:02:30 -07:00
Datong Sun
b42ed82147 docs(readme): bump copyright year 2025-08-22 20:55:13 -07:00
Datong Sun
7c3864a3ed chore(cargo): bump fake-tcp to 0.7.1 and phantun to 0.8.1 2025-08-22 20:54:22 -07:00
Datong Sun
6a39e9e9d0 perf(phantun): avoid heap allocation with udp_recv_from_pktinfo() 2025-08-23 11:53:41 +08:00
Datong Sun
cedee0c699 docs(readme): release 0.8.0 and add note about MIPS build
Some checks are pending
Docker image build / build (push) Waiting to run
Rust / build (push) Waiting to run
2025-08-23 01:20:53 +08:00
10 changed files with 47 additions and 28 deletions

View File

@@ -64,7 +64,7 @@ jobs:
- mipsel-unknown-linux-musl - mipsel-unknown-linux-musl
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: nightly toolchain: nightly

10
Cargo.lock generated
View File

@@ -253,7 +253,7 @@ dependencies = [
[[package]] [[package]]
name = "fake-tcp" name = "fake-tcp"
version = "0.7.0" version = "0.7.1"
dependencies = [ dependencies = [
"bytes", "bytes",
"flume", "flume",
@@ -585,7 +585,7 @@ dependencies = [
[[package]] [[package]]
name = "phantun" name = "phantun"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"clap", "clap",
"fake-tcp", "fake-tcp",
@@ -884,12 +884,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.6.0" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.59.0", "windows-sys 0.60.2",
] ]
[[package]] [[package]]

View File

@@ -5,8 +5,7 @@ A lightweight and fast UDP to TCP obfuscator.
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dndx/phantun/rust.yml) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/dndx/phantun/rust.yml)
![docs.rs](https://img.shields.io/docsrs/fake-tcp) ![docs.rs](https://img.shields.io/docsrs/fake-tcp)
Table of Contents # Table of Contents
=================
* [Phantun](#phantun) * [Phantun](#phantun)
* [Latest release](#latest-release) * [Latest release](#latest-release)
@@ -35,7 +34,14 @@ Table of Contents
# Latest release # Latest release
[v0.7.0](https://github.com/dndx/phantun/releases/tag/v0.7.0) [v0.8.1](https://github.com/dndx/phantun/releases/tag/v0.8.1)
<details>
<summary>MIPS architecture support for Phantun</summary>
[Rust only provides Tier 3 supports for MIPS based platforms](https://github.com/rust-lang/compiler-team/issues/648)
since 2023. Phantun's MIPS build are therefore built using nightly Rust toolchain and provided on a best effort basis only.
</details>
# Overview # Overview

View File

@@ -25,6 +25,10 @@ FROM debian:latest
COPY --from=builder /usr/local/bin/phantun-server /usr/local/bin/ COPY --from=builder /usr/local/bin/phantun-server /usr/local/bin/
COPY --from=builder /usr/local/bin/phantun-client /usr/local/bin/ COPY --from=builder /usr/local/bin/phantun-client /usr/local/bin/
COPY docker/phantun.sh /usr/local/bin/ COPY docker/phantun.sh /usr/local/bin/
RUN apt-get update && apt-get install -y \
iproute2 \
iptables \
procps
ENV USE_IPTABLES_NFT_BACKEND=0 ENV USE_IPTABLES_NFT_BACKEND=0
ENV RUST_LOG=INFO ENV RUST_LOG=INFO

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# alias settings must be global, and must be defined before the function being called with the alias # alias settings must be global, and must be defined before the function being called with the alias
if [ "$USE_IPTABLES_NFT_BACKEND" = 1 ]; then if [ "$USE_IPTABLES_NFT_BACKEND" = 1 ]; then
@@ -70,17 +70,17 @@ _is_ipv4_only() {
} }
_get_tun_from_args() { _get_tun_from_args() {
local tun=$(echo "$@" | awk -F '--tun' '{print $2}' | awk '{print $1}') local tun=$(echo "$@" | awk -F '--tun ' '{print $2}' | awk '{print $1}')
echo ${tun:=tun0} echo ${tun:=tun0}
} }
_get_peer_from_args() { _get_peer_from_args() {
local peer=$(echo "$@" | awk -F '--tun-peer' '{print $2}' | awk '{print $1}') local peer=$(echo "$@" | awk -F '--tun-peer ' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo ${peer:=192.168.201.2} || echo ${peer:=192.168.200.2} _is_server_mode "$1" && echo ${peer:=192.168.201.2} || echo ${peer:=192.168.200.2}
} }
_get_peer6_from_args() { _get_peer6_from_args() {
local peer=$(echo "$@" | awk -F '--tun-peer6' '{print $2}' | awk '{print $1}') local peer=$(echo "$@" | awk -F '--tun-peer6 ' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo ${peer:=fcc9::2} || echo ${peer:=fcc8::2} _is_server_mode "$1" && echo ${peer:=fcc9::2} || echo ${peer:=fcc8::2}
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "fake-tcp" name = "fake-tcp"
version = "0.7.0" version = "0.7.1"
edition = "2024" edition = "2024"
authors = ["Datong Sun <dndx@idndx.com>"] authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View File

@@ -5,7 +5,7 @@ packet oriented tunneling with minimum overhead.
## License ## License
Copyright 2021 Datong Sun <dndx@idndx.com> Copyright 2021-2025 Datong Sun <dndx@idndx.com>
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "phantun" name = "phantun"
version = "0.8.0" version = "0.8.1"
edition = "2024" edition = "2024"
authors = ["Datong Sun <dndx@idndx.com>"] authors = ["Datong Sun <dndx@idndx.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View File

@@ -4,7 +4,7 @@ Client/Server crate, see [Phantun Project README.md](https://github.com/dndx/pha
## License ## License
Copyright 2021 Datong Sun <dndx@idndx.com> Copyright 2021-2025 Datong Sun <dndx@idndx.com>
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license

View File

@@ -10,8 +10,12 @@ use neli::{
types::RtBuffer, types::RtBuffer,
utils::Groups, utils::Groups,
}; };
use nix::sys::socket::{CmsgIterator, ControlMessageOwned, SockaddrLike as _}; use nix::sys::socket::{
CmsgIterator, ControlMessageOwned, MsgFlags, SockaddrLike, SockaddrStorage, cmsg_space,
};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::os::unix::io::AsRawFd;
use tokio::io::Interest;
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
pub fn new_udp_reuseport(local_addr: SocketAddr) -> UdpSocket { pub fn new_udp_reuseport(local_addr: SocketAddr) -> UdpSocket {
@@ -49,26 +53,26 @@ pub fn new_udp_reuseport(local_addr: SocketAddr) -> UdpSocket {
udp_sock.try_into().unwrap() udp_sock.try_into().unwrap()
} }
/// Similiar to `UdpSocket::recv_from()`, but returns a 3rd value `IPAddr`
/// which corresponds to where the UDP datagram was destined to, this is useful
/// for disambigous when socket can receive on multiple IP address
/// or interfaces.
pub async fn udp_recv_pktinfo( pub async fn udp_recv_pktinfo(
sock: &UdpSocket, sock: &UdpSocket,
buf: &mut [u8], buf: &mut [u8],
) -> std::io::Result<(usize, std::net::SocketAddr, std::net::IpAddr)> { ) -> std::io::Result<(usize, SocketAddr, IpAddr)> {
use std::os::unix::io::AsRawFd;
use tokio::io::Interest;
use nix::sys::socket::cmsg_space;
sock.async_io(Interest::READABLE, || { sock.async_io(Interest::READABLE, || {
let control_buffer_size = std::cmp::max( const CONTROL_MESSAGE_BUFFER_SIZE: usize = max_usize(
cmsg_space::<nix::libc::in_pktinfo>(), cmsg_space::<nix::libc::in_pktinfo>(),
cmsg_space::<nix::libc::in6_pktinfo>(), cmsg_space::<nix::libc::in6_pktinfo>(),
); );
let mut control_buffer = vec![0u8; control_buffer_size]; let mut control_message_buffer = [0u8; CONTROL_MESSAGE_BUFFER_SIZE];
let iov = &mut [std::io::IoSliceMut::new(buf)]; let iov = &mut [std::io::IoSliceMut::new(buf)];
let res = nix::sys::socket::recvmsg::<nix::sys::socket::SockaddrStorage>( let res = nix::sys::socket::recvmsg::<SockaddrStorage>(
sock.as_raw_fd(), sock.as_raw_fd(),
iov, iov,
Some(&mut control_buffer), Some(&mut control_message_buffer),
nix::sys::socket::MsgFlags::empty(), MsgFlags::empty(),
)?; )?;
let src_addr = res.address.expect("missing source address"); let src_addr = res.address.expect("missing source address");
@@ -104,6 +108,7 @@ fn dst_addr_from_cmsgs(cmsgs: CmsgIterator) -> Option<IpAddr> {
return Some(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr).into()); return Some(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr).into());
} }
} }
None None
} }
@@ -144,3 +149,7 @@ pub fn assign_ipv6_address(device_name: &str, local: Ipv6Addr, peer: Ipv6Addr) {
.unwrap(); .unwrap();
rtnl.send(&nl_header).unwrap(); rtnl.send(&nl_header).unwrap();
} }
const fn max_usize(a: usize, b: usize) -> usize {
if a > b { a } else { b }
}