summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/platform/linux.rs98
1 files changed, 75 insertions, 23 deletions
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index 5b413b4..2571cb1 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -15,7 +15,6 @@
// You should have received a copy of the GNU General Public License
// along with DPIBreak. If not, see <https://www.gnu.org/licenses/>.
-use iptables::IPTables;
use std::sync::{
atomic::{AtomicBool, Ordering},
Mutex,
@@ -67,6 +66,58 @@ fn exec_process(args: &[&str], input: Option<&str>) -> Result<()> {
}
}
+pub struct IPTables {
+ cmd: &'static str,
+}
+
+impl IPTables {
+ pub fn new(is_ipv6: bool) -> Result<Self> {
+ Ok(Self {
+ cmd: if is_ipv6 { "ip6tables" } else { "iptables" },
+ })
+ }
+
+ fn run(&self, args: &[&str]) -> Result<()> {
+ let mut full_args = Vec::with_capacity(args.len() + 1);
+
+ full_args.push(self.cmd);
+ full_args.extend_from_slice(args);
+
+ exec_process(&full_args, None)
+ }
+
+ pub fn new_chain(&self, table: &str, chain: &str) -> Result<()> {
+ self.run(&["-t", table, "-N", chain])
+ }
+
+ pub fn flush_chain(&self, table: &str, chain: &str) -> Result<()> {
+ self.run(&["-t", table, "-F", chain])
+ }
+
+ pub fn delete_chain(&self, table: &str, chain: &str) -> Result<()> {
+ self.run(&["-t", table, "-X", chain])
+ }
+
+ pub fn insert(&self, table: &str, chain: &str, rule: &[&str], pos: i32) -> Result<()> {
+ let pos_str = pos.to_string();
+ let mut args = vec!["-t", table, "-I", chain, &pos_str];
+ args.extend_from_slice(rule);
+ self.run(&args)
+ }
+
+ pub fn append(&self, table: &str, chain: &str, rule: &[&str]) -> Result<()> {
+ let mut args = vec!["-t", table, "-A", chain];
+ args.extend_from_slice(rule);
+ self.run(&args)
+ }
+
+ pub fn delete(&self, table: &str, chain: &str, rule: &[&str]) -> Result<()> {
+ let mut args = vec!["-t", table, "-D", chain];
+ args.extend_from_slice(rule);
+ self.run(&args)
+ }
+}
+
/// Apply json format nft rules with `nft_command() -j -f -`.
fn apply_nft_rules(rule: &str) -> Result<()> {
exec_process(&[crate::opt::nft_command(), "-j", "-f", "-"], Some(rule))
@@ -79,7 +130,6 @@ fn is_xt_u32_loaded() -> bool {
}
fn ensure_xt_u32() -> Result<()> {
-
let before = is_xt_u32_loaded();
Command::new("modprobe").args(&["-q", "xt_u32"]).status()?;
let after = is_xt_u32_loaded();
@@ -102,10 +152,11 @@ fn is_u32_supported(ipt: &IPTables) -> bool {
log_println!(LogLevel::Info, "xt_u32 loaded");
- let rule = "-m u32 --u32 \'0x0=0x0\' -j RETURN";
- match ipt.insert("raw", "PREROUTING", rule, 1) {
+ let rule = ["-m", "u32", "--u32", "0x0=0x0", "-j", "RETURN"];
+
+ match ipt.insert("raw", "PREROUTING", &rule, 1) {
Ok(_) => {
- _ = ipt.delete("raw", "PREROUTING", rule);
+ _ = ipt.delete("raw", "PREROUTING", &rule);
IS_U32_SUPPORTED.store(true, Ordering::Relaxed);
true
}
@@ -119,41 +170,42 @@ fn iptables_err(e: impl ToString) -> Error {
}
fn install_iptables_rules(ipt: &IPTables) -> Result<()> {
- let base = format!("-p tcp --dport 443 -j NFQUEUE --queue-num {} --queue-bypass",
- crate::opt::queue_num());
+ let q_num = crate::opt::queue_num().to_string();
- let rule = if is_u32_supported(ipt) {
- const U32: &str = "-m u32 --u32 \
- \'0>>22&0x3C @ 12>>26&0x3C @ 0>>24&0xFF=0x16 && \
- 0>>22&0x3C @ 12>>26&0x3C @ 2>>24&0xFF=0x01\'";
+ let mut rule = vec![
+ "-p", "tcp", "--dport", "443",
+ "-j", "NFQUEUE", "--queue-num", &q_num, "--queue-bypass"
+ ];
- format!("{} {}", base, U32)
- } else {
- base
- };
+ if is_u32_supported(ipt) {
+ const U32: &str = "0>>22&0x3C @ 12>>26&0x3C @ 0>>24&0xFF=0x16 && \
+ 0>>22&0x3C @ 12>>26&0x3C @ 2>>24&0xFF=0x01";
+
+ rule.extend_from_slice(&["-m", "u32", "--u32", U32]);
+ }
ipt.new_chain("mangle", DPIBREAK_CHAIN).map_err(iptables_err)?;
// prevent inf loop
+ let mark = format!("{:#x}", INJECT_MARK);
ipt.insert(
"mangle",
DPIBREAK_CHAIN,
- &format!("-m mark --mark {:#x} -j RETURN", INJECT_MARK),
+ &["-m", "mark", "--mark", &mark, "-j", "RETURN"],
1
).map_err(iptables_err)?;
ipt.append("mangle", DPIBREAK_CHAIN, &rule).map_err(iptables_err)?;
log_println!(LogLevel::Info, "{}: new chain {} on table mangle", ipt.cmd, DPIBREAK_CHAIN);
- ipt.insert("mangle", "POSTROUTING",
- &format!("-j {}", DPIBREAK_CHAIN), 1).map_err(iptables_err)?;
+ ipt.insert("mangle", "POSTROUTING", &["-j", DPIBREAK_CHAIN], 1).map_err(iptables_err)?;
log_println!(LogLevel::Info, "{}: add jump to {} chain on POSTROUTING", ipt.cmd, DPIBREAK_CHAIN);
Ok(())
}
fn cleanup_iptables_rules(ipt: &IPTables) -> Result<()> {
- if ipt.delete("mangle", "POSTROUTING", &format!("-j {}", DPIBREAK_CHAIN)).is_ok() {
+ if ipt.delete("mangle", "POSTROUTING", &["-j", DPIBREAK_CHAIN]).is_ok() {
log_println!(LogLevel::Info, "{}: deleted jump from POSTROUTING", ipt.cmd);
}
@@ -289,8 +341,8 @@ fn install_rules() -> Result<()> {
log_println!(LogLevel::Warning, "nftables: {}", e.to_string());
log_println!(LogLevel::Warning, "fallback to iptables");
- let ipt = iptables::new(false).map_err(iptables_err)?;
- let ip6 = iptables::new(true).map_err(iptables_err)?;
+ let ipt = IPTables::new(false).map_err(iptables_err)?;
+ let ip6 = IPTables::new(true).map_err(iptables_err)?;
install_iptables_rules(&ipt)?;
// FIXME: using xt_u32 on ipv6 is not supported; (even if it does,
@@ -304,8 +356,8 @@ fn install_rules() -> Result<()> {
fn cleanup_rules() -> Result<()> {
if IS_NFT_NOT_SUPPORTED.load(Ordering::Relaxed) {
- let ipt = iptables::new(false).map_err(iptables_err)?;
- let ip6 = iptables::new(true).map_err(iptables_err)?;
+ let ipt = IPTables::new(false).map_err(iptables_err)?;
+ let ip6 = IPTables::new(true).map_err(iptables_err)?;
cleanup_iptables_rules(&ipt)?;
cleanup_iptables_rules(&ip6)?;