summaryrefslogtreecommitdiff
path: root/src/linux
diff options
context:
space:
mode:
authorAndrew Guschin <guschin@altlinux.org>2026-10-30 13:20:18 +0400
committerAndrew Guschin <guschin@altlinux.org>2026-10-30 13:20:18 +0400
commit0b898d982549eab1ba12bf743d001aee6c2e27f9 (patch)
treeca2689cd63ce7f89584e95c5ce88bbb22b817f47 /src/linux
parent3c8b130be89fbb0e58e2ee23f07ad56a3b9de2e7 (diff)
Validate real TUN forwarding and fix firewall routingmain
- Move the default-drop guard to POSTROUTING so it sees final TUN egress - Treat a missing TUN interface as absent and add acceptance coverage - Document successful real-subscription validation on ALT Xray 26.10.29
Diffstat (limited to 'src/linux')
-rw-r--r--src/linux/firewall.rs5
-rw-r--r--src/linux/routes.rs13
2 files changed, 14 insertions, 4 deletions
diff --git a/src/linux/firewall.rs b/src/linux/firewall.rs
index 8a0dd43..bbde560 100644
--- a/src/linux/firewall.rs
+++ b/src/linux/firewall.rs
@@ -126,7 +126,10 @@ fn apply_policy(enabled: bool, xray_uid: u32, allow_tun: bool) -> Result<()> {
batch.add(&mark, MsgType::Add);
let mut guard = Chain::new(c"guard", &table);
guard.set_type(ChainType::Filter);
- guard.set_hook(Hook::Out, 100);
+ // OUTPUT's hook state still names the original interface after the
+ // route chain changes skb's route. POSTROUTING sees the final egress,
+ // so the guard can allow TUN traffic without allowing direct fallback.
+ guard.set_hook(Hook::PostRouting, 100);
guard.set_policy(Policy::Drop);
batch.add(&guard, MsgType::Add);
exceptions(&mut batch, &guard, xray_uid);
diff --git a/src/linux/routes.rs b/src/linux/routes.rs
index 4212183..0380faf 100644
--- a/src/linux/routes.rs
+++ b/src/linux/routes.rs
@@ -178,12 +178,19 @@ pub async fn remove() -> Result<()> {
pub async fn tun_index() -> Result<Option<u32>> {
let handle = connection()?;
- Ok(handle
+ let result = handle
.link()
.get()
.match_name("roentgen0")
.execute()
.try_next()
- .await?
- .map(|link| link.header.index))
+ .await;
+ match result {
+ Ok(link) => Ok(link.map(|link| link.header.index)),
+ // A named RTM_GETLINK request reports ENODEV for an absent interface,
+ // including before Xray starts and while waiting for it to create TUN.
+ Err(rtnetlink::Error::NetlinkError(error))
+ if error.raw_code() == -libc::ENODEV => Ok(None),
+ Err(error) => Err(error.into()),
+ }
}