summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock153
-rw-r--r--Cargo.toml3
-rw-r--r--src/platform/linux.rs57
-rw-r--r--src/platform/linux/libc_s.rs95
-rw-r--r--src/platform/linux/rxring.rs111
5 files changed, 246 insertions, 173 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 31feccf..e52bffb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -34,39 +34,33 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anyhow"
-version = "1.0.102"
+version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]]
name = "arrayvec"
-version = "0.7.6"
+version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "autocfg"
-version = "1.5.0"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "bitflags"
-version = "2.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "bumpalo"
-version = "3.20.2"
+version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytes"
-version = "1.11.1"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
[[package]]
name = "cast"
@@ -76,9 +70,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
-version = "1.2.60"
+version = "1.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20"
+checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -227,7 +221,6 @@ dependencies = [
"etherparse 0.18.2",
"libc",
"nfq-updated",
- "nix",
"socket2",
"windivert",
"windows-services",
@@ -236,9 +229,9 @@ dependencies = [
[[package]]
name = "either"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]]
name = "etherparse"
@@ -265,6 +258,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
name = "half"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -292,25 +309,26 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
-version = "0.3.95"
+version = "0.3.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
+checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
dependencies = [
- "once_cell",
+ "cfg-if",
+ "futures-util",
"wasm-bindgen",
]
[[package]]
name = "libc"
-version = "0.2.185"
+version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "memchr"
-version = "2.8.0"
+version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "nfq-updated"
@@ -324,17 +342,6 @@ dependencies = [
]
[[package]]
-name = "nix"
-version = "0.27.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
-dependencies = [
- "bitflags",
- "cfg-if",
- "libc",
-]
-
-[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -366,6 +373,12 @@ dependencies = [
]
[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -404,9 +417,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.45"
+version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [
"proc-macro2",
]
@@ -433,9 +446,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.12.3"
+version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
dependencies = [
"aho-corasick",
"memchr",
@@ -456,9 +469,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.10"
+version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "rustversion"
@@ -507,9 +520,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.149"
+version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
@@ -520,15 +533,21 @@ dependencies = [
[[package]]
name = "shlex"
-version = "1.3.0"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "socket2"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
+checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [
"libc",
"windows-sys",
@@ -536,9 +555,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.117"
+version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
@@ -602,9 +621,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
-version = "0.2.118"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
+checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
dependencies = [
"cfg-if",
"once_cell",
@@ -615,9 +634,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.118"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
+checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -625,9 +644,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.118"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
+checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -638,18 +657,18 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.118"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
+checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
-version = "0.3.95"
+version = "0.3.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d"
+checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -810,18 +829,18 @@ dependencies = [
[[package]]
name = "zerocopy"
-version = "0.8.48"
+version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
+checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.48"
+version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
+checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 44a4542..bf875d3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,7 @@
[package]
name = "dpibreak"
version = "0.6.1"
-authors = ["Dilluti0n <[email protected]>"]
+authors = ["Dilluti0n <[email protected]>"]
edition = "2024"
rust-version = "1.88"
build = "build.rs"
@@ -36,7 +36,6 @@ etherparse = "0.18"
[target.'cfg(target_os = "linux")'.dependencies]
nfq = { package = "nfq-updated", version = "0.2.6" } # nfq-updated: to use as_raw_fd
socket2 = { version = "0.6", features = ["all"] }
-nix = { version = "0.27.1", features = ["fs", "user"] }
daemonize = "0.5.0"
libc = "0.2"
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index bebc6f4..096451a 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -17,10 +17,10 @@ use crate::opt;
mod iptables;
mod nftables;
mod rxring;
+mod libc_s;
use iptables::*;
use nftables::*;
-use libc::sock_filter;
use crate::pkt;
pub static IS_U32_SUPPORTED: AtomicBool = AtomicBool::new(false);
@@ -99,7 +99,7 @@ fn cleanup_rules() -> Result<()> {
}
fn lock_pid_file() -> Result<()> {
- use nix::fcntl::{flock, FlockArg};
+ use libc_s::flock;
let pid_file = OpenOptions::new()
.write(true)
@@ -107,7 +107,7 @@ fn lock_pid_file() -> Result<()> {
.truncate(false)
.open(PID_FILE)?;
- if flock(pid_file.as_raw_fd(), FlockArg::LockExclusiveNonblock).is_err() {
+ if flock(pid_file.as_raw_fd(), libc::LOCK_NB | libc::LOCK_EX).is_err() {
let existing_pid = std::fs::read_to_string(PID_FILE)?;
anyhow::bail!("Fail to lock {PID_FILE}: {PKG_NAME} already running with PID {}", existing_pid.trim());
}
@@ -122,7 +122,7 @@ fn lock_pid_file() -> Result<()> {
}
fn exit_if_not_root() {
- if !nix::unistd::geteuid().is_root() {
+ if libc_s::geteuid() != 0 {
crate::error!("{PKG_NAME} must be run as root. Try sudo.");
std::process::exit(3);
}
@@ -154,7 +154,10 @@ static RAW6: LazyLock<Socket> = LazyLock::new(|| {
let sock = Socket::new(Domain::IPV6, Type::RAW, Some(Protocol::TCP))
.expect("create raw6");
- sock.set_header_included_v6(true).expect("IP_HDRINCL");
+ if let Err(e) = sock.set_header_included_v6(true) {
+ crate::warn!("Failed to set IPV6_HDRINCL. Maybe old kernel version? IPv6 header manipulation disabled.");
+ crate::warn!("Cause: {e}");
+ }
sock.set_mark(INJECT_MARK).expect("SO_MARK");
sock
@@ -181,26 +184,29 @@ pub fn send_to_raw(pkt: &[u8], dst: std::net::IpAddr) -> Result<()> {
fn open_nfqueue() -> Result<nfq::Queue> {
use std::os::fd::AsRawFd;
- use nix::fcntl::{fcntl, FcntlArg, OFlag};
+ use libc_s::{fcntl, FcntlArg};
let mut q = nfq::Queue::open()?;
- q.bind(crate::opt::queue_num())?;
- crate::info!("nfqueue: bound to queue number {}", crate::opt::queue_num());
+ q.bind(opt::queue_num())?;
+ crate::info!("nfqueue: bound to queue number {}", opt::queue_num());
// to check inturrupts
- let raw_fd = q.as_raw_fd();
- let flags = fcntl(raw_fd, FcntlArg::F_GETFL)?;
- let new_flags = OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK;
- fcntl(raw_fd, FcntlArg::F_SETFL(new_flags))?;
+ let fd = q.as_raw_fd();
+ let fl = fcntl(fd, FcntlArg::F_GETFL)?;
+ fcntl(fd, FcntlArg::F_SETFL(fl | libc::O_NONBLOCK))?;
Ok(q)
}
+/// Open AF_PACKET RX ring for syn/ack packets
fn open_rxring() -> Result<rxring::RxRing> {
+ use libc::sock_filter;
+
/// cBPF filter for TCP and sport=443 and SYN,ACK packets
///
/// Produced by
- /// tcpdump -dd '(ip and tcp src port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)) or (ip6 and tcp src port 443 and ip6[53] & 0x12 == 0x12)'
+ /// tcpdump -dd '(ip and tcp src port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack)
+ /// == (tcp-syn|tcp-ack)) or (ip6 and tcp src port 443 and ip6[53] & 0x12 == 0x12)'
const SYNACK_443_CBPF: &[sock_filter] = &[
sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
sock_filter { code: 0x15, jt: 0, jf: 10, k: 0x00000800 },
@@ -225,12 +231,14 @@ fn open_rxring() -> Result<rxring::RxRing> {
sock_filter { code: 0x6, jt: 0, jf: 0, k: 0x00040000 },
sock_filter { code: 0x6, jt: 0, jf: 0, k: 0x00000000 },
];
+ const BLOCK_SIZE: u32 = 4096 * 4; // 16 KB
+ const BLOCK_NR: u32 = 4;
+
+ /// tpacket_hdr (~66) + eth(14) + ipv6(40) + tcp with options(60) = ~180
+ const FRAME_SIZE: u32 = 256;
- let rx = rxring::RxRing::new(SYNACK_443_CBPF)?;
+ let rx = rxring::RxRing::new(SYNACK_443_CBPF, BLOCK_SIZE, BLOCK_NR, FRAME_SIZE)?;
crate::info!("rxring: initialized");
- crate::debug!(
- "rxring: tcp src port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)"
- );
Ok(rx)
}
@@ -258,18 +266,6 @@ fn open_signalfd() -> Result<OwnedFd> {
}
}
-// Note: Invalid FDs safely result in POLLNVAL, so this doesn't need to be unsafe
-fn poll_s(fds: &mut [libc::pollfd]) -> Result<()> {
- use std::io::Error;
-
- // SAFETY: fds.len() is fds's length
- if unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as _, -1) } == -1 {
- return Err(Error::last_os_error().into());
- }
-
- Ok(())
-}
-
pub fn run() -> Result<()> {
use crate::handle_packet;
use super::PACKET_SIZE_CAP;
@@ -295,7 +291,8 @@ pub fn run() -> Result<()> {
crate::splash!("{}", super::MESSAGE_AT_RUN);
loop {
- poll_s(&mut fds)?;
+ libc_s::poll(&mut fds, -1)?;
+
let is_intr: bool = fds[0].revents & libc::POLLIN != 0;
let q_ready: bool = fds[1].revents & libc::POLLIN != 0;
let rx_ready: bool = fds[2].revents & libc::POLLIN != 0;
diff --git a/src/platform/linux/libc_s.rs b/src/platform/linux/libc_s.rs
new file mode 100644
index 0000000..f599ed0
--- /dev/null
+++ b/src/platform/linux/libc_s.rs
@@ -0,0 +1,95 @@
+// SPDX-FileCopyrightText: 2026 Dilluti0n <[email protected]>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+use std::os::fd::{OwnedFd, RawFd, FromRawFd};
+use std::io::Error;
+
+use std::ffi::{c_int, c_void};
+use std::mem;
+
+macro_rules! syscall {
+ ($call:expr) => {
+ match $call {
+ -1 => Err(::std::io::Error::last_os_error()),
+ res => Ok(res),
+ }
+ };
+}
+
+#[allow(non_camel_case_types)]
+pub enum FcntlArg {
+ F_GETFL,
+ F_SETFL(c_int),
+}
+
+pub fn fcntl(fd: RawFd, op: FcntlArg) -> Result<c_int, Error> {
+ use libc::fcntl;
+
+ syscall!(match op {
+ FcntlArg::F_GETFL => unsafe { fcntl(fd, libc::F_GETFL) },
+ FcntlArg::F_SETFL(flags) => unsafe { fcntl(fd, libc::F_SETFL, flags) }
+ })
+}
+
+pub fn flock(fd: RawFd, op: c_int) -> Result<(), Error> {
+ syscall!(unsafe { libc::flock(fd, op) }).map(drop)
+}
+
+pub fn geteuid() -> libc::uid_t {
+ unsafe { libc::geteuid() }
+}
+
+pub fn poll(fds: &mut [libc::pollfd], timeout: c_int) -> Result<(), Error> {
+ syscall!(unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as _, timeout) }).map(drop)
+}
+
+unsafe fn setsockopt_1<T>(sockfd: RawFd, level: c_int, optname: c_int, optval: &T) -> c_int {
+ unsafe {
+ libc::setsockopt(sockfd, level, optname,
+ (optval as *const T).cast() as *const c_void,
+ mem::size_of::<T>() as libc::socklen_t)
+ }
+}
+
+#[allow(non_camel_case_types)]
+pub enum SockOpt<'a> {
+ SO_ATTACH_FILTER(&'a [libc::sock_filter]),
+ PACKET_RX_RING(&'a libc::tpacket_req),
+}
+
+pub fn setsockopt(sockfd: RawFd, opt: SockOpt) -> Result<(), Error> {
+ syscall!(match opt {
+ SockOpt::SO_ATTACH_FILTER(val) => {
+ let prog = libc::sock_fprog {
+ len: val.len() as u16,
+ filter: val.as_ptr() as *mut libc::sock_filter
+ };
+
+ unsafe {setsockopt_1(sockfd, libc::SOL_SOCKET, libc::SO_ATTACH_FILTER, &prog)}
+ },
+ SockOpt::PACKET_RX_RING(optval) => unsafe {
+ setsockopt_1(sockfd, libc::SOL_PACKET, libc::PACKET_RX_RING, optval)
+ }
+ }).map(drop)
+}
+
+pub fn socket(domain: c_int, so_type: c_int, protocol: c_int) -> Result<OwnedFd, Error> {
+ unsafe {
+ let raw = syscall!(libc::socket(domain, so_type, protocol))?;
+ Ok(OwnedFd::from_raw_fd(raw))
+ }
+}
+
+pub unsafe fn mmap(
+ addr: *mut c_void, length: usize, prot: c_int,
+ flags: c_int, fd: RawFd, offset: libc::off_t
+) -> Result<*mut c_void, Error> {
+ match unsafe {libc::mmap(addr, length, prot, flags, fd, offset)} {
+ libc::MAP_FAILED => Err(Error::last_os_error()),
+ res => Ok(res),
+ }
+}
+
+pub unsafe fn munmap(addr: *mut c_void, length: usize) -> Result<(), Error> {
+ syscall!(unsafe { libc::munmap(addr, length) }).map(drop)
+}
diff --git a/src/platform/linux/rxring.rs b/src/platform/linux/rxring.rs
index e5066dd..0249b9f 100644
--- a/src/platform/linux/rxring.rs
+++ b/src/platform/linux/rxring.rs
@@ -1,10 +1,14 @@
// SPDX-FileCopyrightText: 2026 Dilluti0n <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later
-use std::os::fd::{RawFd, BorrowedFd, AsFd, OwnedFd, FromRawFd, AsRawFd};
+use std::os::fd::{RawFd, BorrowedFd, AsFd, OwnedFd, AsRawFd};
use std::io::Error;
use libc::*;
+use super::libc_s;
+
+use libc_s::{setsockopt, SockOpt};
+
pub struct RxRing {
fd: OwnedFd,
ring: *mut u8,
@@ -17,85 +21,45 @@ pub struct RxRing {
current: usize
}
-fn attach_filter(sockfd: RawFd, filter: &[sock_filter]) -> Result<(), Error> {
- let prog = sock_fprog {
- len: filter.len() as u16,
- filter: filter.as_ptr() as *mut sock_filter,
- };
-
- let ret = unsafe {
- setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER,
- &prog as *const _ as *const _,
- std::mem::size_of::<sock_fprog>() as socklen_t)
- };
-
- if ret < 0 {
- return Err(Error::last_os_error());
- }
-
- Ok(())
-}
-
-/// Make [`sockfd`] as mmapable rxring with size of [`BLOCK_SIZE`] * [`BLOCK_NR`]
-/// and single frame [`FRAME_SIZE`] (each packet goes to frame).
-/// Since we only need to seek ip header here, 128 bytes are
-/// enough.
-fn setup_rxring(sockfd: RawFd) -> Result<tpacket_req, Error> {
- const BLOCK_SIZE: u32 = 4096 * 4; // 16 KB
- const BLOCK_NR: u32 = 4;
-
- // tpacket_hdr (~66) + eth(14) + ipv6(40) + tcp with options(60) = ~180
- const FRAME_SIZE: u32 = 256;
+/// Make [`sockfd`] as mmapable rxring with size of [`tp_block_size`] * [`tp_block_nr`]
+/// and single frame [`tp_frame_size`] (each packet goes to frame).
+fn setup_rxring(sockfd: RawFd,
+ tp_block_size: u32, tp_block_nr: u32, tp_frame_size: u32
+) -> Result<tpacket_req, Error> {
let req = tpacket_req {
- tp_block_size: BLOCK_SIZE,
- tp_block_nr: BLOCK_NR,
- tp_frame_size: FRAME_SIZE,
- tp_frame_nr: BLOCK_SIZE / FRAME_SIZE * BLOCK_NR,
+ tp_block_size,
+ tp_block_nr,
+ tp_frame_size,
+ tp_frame_nr: tp_block_size / tp_frame_size * tp_block_nr,
};
- let ret = unsafe {
- setsockopt(sockfd, SOL_PACKET, PACKET_RX_RING,
- &req as *const _ as *const _,
- std::mem::size_of::<tpacket_req>() as socklen_t)
- };
-
- if ret < 0 {
- return Err(Error::last_os_error());
- }
+ setsockopt(sockfd, SockOpt::PACKET_RX_RING(&req))?;
Ok(req)
}
impl RxRing {
- pub fn new(filter: &[libc::sock_filter]) -> Result<Self, Error> {
- let raw = unsafe {
- socket(
- AF_PACKET,
- SOCK_RAW,
- (ETH_P_ALL as u16).to_be() as i32 // big-endian
- )
- };
- if raw < 0 { return Err(Error::last_os_error()); }
-
- // SAFETY: we just opened raw.
- let fd = unsafe { OwnedFd::from_raw_fd(raw) };
-
- attach_filter(fd.as_raw_fd(), filter)?;
- let req = setup_rxring(fd.as_raw_fd())?;
+ pub fn new(
+ filter: &[libc::sock_filter],
+ tp_block_size: u32, tp_block_nr: u32, tp_frame_size: u32
+ ) -> Result<Self, Error> {
+ let fd = libc_s::socket(AF_PACKET, SOCK_RAW, (ETH_P_ALL as u16).to_be() as i32)?;
+ let raw = fd.as_raw_fd();
+
+ setsockopt(raw, SockOpt::SO_ATTACH_FILTER(&filter))?;
+ let req = setup_rxring(raw, tp_block_size, tp_block_nr, tp_frame_size)?;
let ring_size = (req.tp_block_size * req.tp_block_nr) as usize;
- let ring = unsafe {
- mmap(
- std::ptr::null_mut(),
- ring_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_LOCKED,
- fd.as_raw_fd(),
- 0
- )
- };
- if ring == MAP_FAILED { return Err(Error::last_os_error()); }
+ // SAFETY: we munmap this segment when RxRing is dropped.
+ let ring = unsafe {libc_s::mmap(
+ std::ptr::null_mut(),
+ ring_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_LOCKED,
+ raw,
+ 0
+ )}?;
Ok(RxRing {
fd,
@@ -110,7 +74,6 @@ impl RxRing {
let frame_size = self.req.tp_frame_size as usize;
// SAFETY: current < frame_nr guaranteed by modular increment on advance.
- // ring is valid mmap'd memory from new(), munmapped by Drop.
unsafe { self.ring.add(self.current * frame_size) as *mut tpacket_hdr }
}
@@ -151,12 +114,12 @@ impl AsRawFd for RxRing {
}
}
-// SAFETY: ring was mmap'd with ring_size bytes.
-// This guarantees munmap() happens before OwnedFd closes the fd.
impl Drop for RxRing {
fn drop(&mut self) {
- unsafe {
- libc::munmap(self.ring as *mut _, self.ring_size);
+ // SAFETY: ring was mmap'd with ring_size bytes.
+ match unsafe { libc_s::munmap(self.ring as *mut _, self.ring_size) } {
+ Err(e) => crate::warn!("rxring: cannot munmap: {}", e.kind()),
+ Ok(_) => {}
}
}
}