mirror of
https://github.com/okhsunrog/vpnhide.git
synced 2026-08-19 13:33:45 +00:00
refactor(activator): model hooks as typed sets
This commit is contained in:
parent
eed9e57f2e
commit
dfd246d011
5 changed files with 158 additions and 97 deletions
|
|
@ -26,7 +26,7 @@ use vpnhide_apatch_abi::{
|
|||
parse_kernel_version_hint as parse_apatch_kernel_version_hint,
|
||||
};
|
||||
use vpnhide_protocol::Target;
|
||||
use vpnhide_protocol::hook_ids::{HOOK_NAMES, KERNEL_HOOK_MASK, ZYGISK_HOOK_MASK};
|
||||
use vpnhide_protocol::hook_ids::{Hook, KERNEL_HOOK_MASK, ZYGISK_HOOK_MASK};
|
||||
use vpnhide_protocol::{
|
||||
KPM_ARGS_LEN, Kind, MAX_TARGET_UIDS, format_config, parse_config, peek_kind,
|
||||
};
|
||||
|
|
@ -392,7 +392,7 @@ pub fn boot_wait_requested_from_env() -> Result<bool> {
|
|||
fn has_native_targets(cfg: &CanonicalConfig, family: NativeHookFamily) -> bool {
|
||||
cfg.apps
|
||||
.values()
|
||||
.any(|app| app.native.hookmask(family).is_some())
|
||||
.any(|app| app.native.hooks(family).is_some())
|
||||
}
|
||||
|
||||
fn has_ports_targets(cfg: &CanonicalConfig) -> bool {
|
||||
|
|
|
|||
|
|
@ -130,30 +130,66 @@ pub(crate) enum NativeHookFamily {
|
|||
}
|
||||
|
||||
impl NativeHookFamily {
|
||||
fn full_mask(self) -> u32 {
|
||||
fn full_set(self) -> HookSet {
|
||||
match self {
|
||||
NativeHookFamily::Kernel => KERNEL_HOOK_MASK,
|
||||
NativeHookFamily::Zygisk => ZYGISK_HOOK_MASK,
|
||||
NativeHookFamily::Kernel => HookSet::from_bits(KERNEL_HOOK_MASK),
|
||||
NativeHookFamily::Zygisk => HookSet::from_bits(ZYGISK_HOOK_MASK),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub(crate) struct HookSet(u32);
|
||||
|
||||
impl HookSet {
|
||||
const fn from_bits(bits: u32) -> Self {
|
||||
Self(bits)
|
||||
}
|
||||
|
||||
fn from_names(names: &[String]) -> Self {
|
||||
names
|
||||
.iter()
|
||||
.filter_map(|name| Hook::from_name(name))
|
||||
.fold(Self::default(), |hooks, hook| hooks.with(hook))
|
||||
}
|
||||
|
||||
const fn with(self, hook: Hook) -> Self {
|
||||
Self(self.0 | hook.bit())
|
||||
}
|
||||
|
||||
const fn restricted_to(self, owner: Self) -> Self {
|
||||
Self(self.0 & owner.0)
|
||||
}
|
||||
|
||||
fn merge(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
|
||||
const fn is_empty(self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
|
||||
const fn bits(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeSelection {
|
||||
pub(crate) fn hookmask(&self, family: NativeHookFamily) -> Option<u32> {
|
||||
pub(crate) fn hooks(&self, family: NativeHookFamily) -> Option<HookSet> {
|
||||
match self {
|
||||
NativeSelection::Enabled(false) => None,
|
||||
NativeSelection::Enabled(true) => Some(family.full_mask()),
|
||||
NativeSelection::Enabled(true) => Some(family.full_set()),
|
||||
NativeSelection::Hooks(names) => {
|
||||
if names.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mask = match family {
|
||||
let hooks = match family {
|
||||
NativeHookFamily::Kernel => {
|
||||
names.iter().fold(0u32, |acc, name| acc | hook_bit(name)) & KERNEL_HOOK_MASK
|
||||
HookSet::from_names(names).restricted_to(family.full_set())
|
||||
}
|
||||
NativeHookFamily::Zygisk => ZYGISK_HOOK_MASK,
|
||||
NativeHookFamily::Zygisk => family.full_set(),
|
||||
};
|
||||
(mask != 0).then_some(mask)
|
||||
(!hooks.is_empty()).then_some(hooks)
|
||||
}
|
||||
NativeSelection::Detailed(detail) => {
|
||||
if !detail.enabled {
|
||||
|
|
@ -164,11 +200,10 @@ impl NativeSelection {
|
|||
NativeHookFamily::Zygisk => &detail.zygisk,
|
||||
};
|
||||
let Some(names) = selected else {
|
||||
return Some(family.full_mask());
|
||||
return Some(family.full_set());
|
||||
};
|
||||
let mask =
|
||||
names.iter().fold(0u32, |acc, name| acc | hook_bit(name)) & family.full_mask();
|
||||
(mask != 0).then_some(mask)
|
||||
let hooks = HookSet::from_names(names).restricted_to(family.full_set());
|
||||
(!hooks.is_empty()).then_some(hooks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -198,14 +233,6 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
fn hook_bit(name: &str) -> u32 {
|
||||
HOOK_NAMES
|
||||
.iter()
|
||||
.position(|known| *known == name)
|
||||
.map(|id| 1u32 << id)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct PackageUidMap {
|
||||
packages: BTreeMap<String, Vec<u32>>,
|
||||
|
|
@ -350,9 +377,9 @@ pub(crate) fn project_native_with_resolver_for_family(
|
|||
resolver: &PackageUidMap,
|
||||
family: NativeHookFamily,
|
||||
) -> String {
|
||||
let mut by_uid = BTreeMap::<u32, u32>::new();
|
||||
let mut by_uid = BTreeMap::<u32, HookSet>::new();
|
||||
for (pkg, app) in &cfg.apps {
|
||||
let Some(mask) = app.native.hookmask(family) else {
|
||||
let Some(hooks) = app.native.hooks(family) else {
|
||||
continue;
|
||||
};
|
||||
// The APK is intentionally single-owner: only its main-profile copy
|
||||
|
|
@ -368,8 +395,8 @@ pub(crate) fn project_native_with_resolver_for_family(
|
|||
{
|
||||
by_uid
|
||||
.entry(uid)
|
||||
.and_modify(|existing| *existing |= mask)
|
||||
.or_insert(mask);
|
||||
.and_modify(|existing| existing.merge(hooks))
|
||||
.or_insert(hooks);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -389,8 +416,8 @@ pub(crate) fn project_native_with_resolver_for_family(
|
|||
}
|
||||
by_uid
|
||||
.entry(*uid)
|
||||
.and_modify(|existing| *existing |= mask)
|
||||
.or_insert(mask);
|
||||
.and_modify(|existing| existing.merge(hooks))
|
||||
.or_insert(hooks);
|
||||
}
|
||||
}
|
||||
// `by_uid` is a BTreeMap, so iteration is ascending by UID; truncating would
|
||||
|
|
@ -403,7 +430,10 @@ pub(crate) fn project_native_with_resolver_for_family(
|
|||
let targets = by_uid
|
||||
.into_iter()
|
||||
.take(MAX_NATIVE_TARGETS)
|
||||
.map(|(uid, hookmask)| Target { uid, hookmask })
|
||||
.map(|(uid, hooks)| Target {
|
||||
uid,
|
||||
hookmask: hooks.bits(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
format_config(cfg.debug, NO_DEFAULT_MASK, &targets)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,47 @@ pub enum Hook {
|
|||
ZygiskSetsockopt = 26,
|
||||
}
|
||||
|
||||
impl Hook {
|
||||
/// This hook's bit in the control/stats wire mask.
|
||||
pub const fn bit(self) -> u32 {
|
||||
1u32 << self as u32
|
||||
}
|
||||
|
||||
/// Resolve a canonical config hook name.
|
||||
pub fn from_name(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"fib_route_seq_show" => Some(Self::FibRouteSeqShow),
|
||||
"ipv6_route_seq_show" => Some(Self::Ipv6RouteSeqShow),
|
||||
"rtnl_fill_ifinfo" => Some(Self::RtnlFillIfinfo),
|
||||
"inet_fill_ifaddr" => Some(Self::InetFillIfaddr),
|
||||
"inet6_fill_ifaddr" => Some(Self::Inet6FillIfaddr),
|
||||
"dev_ioctl" => Some(Self::DevIoctl),
|
||||
"sock_ioctl" => Some(Self::SockIoctl),
|
||||
"fib_dump_info" => Some(Self::FibDumpInfo),
|
||||
"rt6_fill_node" => Some(Self::Rt6FillNode),
|
||||
"fib_nl_fill_rule" => Some(Self::FibNlFillRule),
|
||||
"lsposed_link_properties" => Some(Self::LsposedLinkProperties),
|
||||
"lsposed_network_capabilities" => Some(Self::LsposedNetworkCapabilities),
|
||||
"lsposed_network_info" => Some(Self::LsposedNetworkInfo),
|
||||
"lsposed_network" => Some(Self::LsposedNetwork),
|
||||
"lsposed_connectivity_result" => Some(Self::LsposedConnectivityResult),
|
||||
"lsposed_connectivity_callback" => Some(Self::LsposedConnectivityCallback),
|
||||
"lsposed_connectivity_network" => Some(Self::LsposedConnectivityNetwork),
|
||||
"lsposed_package_visibility" => Some(Self::LsposedPackageVisibility),
|
||||
"zygisk_ioctl" => Some(Self::ZygiskIoctl),
|
||||
"zygisk_getifaddrs" => Some(Self::ZygiskGetifaddrs),
|
||||
"zygisk_openat" => Some(Self::ZygiskOpenat),
|
||||
"zygisk_recvmsg" => Some(Self::ZygiskRecvmsg),
|
||||
"zygisk_recv" => Some(Self::ZygiskRecv),
|
||||
"zygisk_recvfrom" => Some(Self::ZygiskRecvfrom),
|
||||
"zygisk_recvfrom_chk" => Some(Self::ZygiskRecvfromChk),
|
||||
"socket_bind_interface" => Some(Self::SocketBindInterface),
|
||||
"zygisk_setsockopt" => Some(Self::ZygiskSetsockopt),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const HOOK_COUNT: u32 = 27;
|
||||
|
||||
/// Hooks owned by each backend: apply `mask & own`.
|
||||
|
|
@ -98,33 +139,3 @@ pub enum Backend {
|
|||
/// LSPosed Java-hook backend (system_server)
|
||||
Lsposed = 3,
|
||||
}
|
||||
|
||||
pub const HOOK_NAMES: [&str; 27] = [
|
||||
"fib_route_seq_show",
|
||||
"ipv6_route_seq_show",
|
||||
"rtnl_fill_ifinfo",
|
||||
"inet_fill_ifaddr",
|
||||
"inet6_fill_ifaddr",
|
||||
"dev_ioctl",
|
||||
"sock_ioctl",
|
||||
"fib_dump_info",
|
||||
"rt6_fill_node",
|
||||
"fib_nl_fill_rule",
|
||||
"lsposed_link_properties",
|
||||
"lsposed_network_capabilities",
|
||||
"lsposed_network_info",
|
||||
"lsposed_network",
|
||||
"lsposed_connectivity_result",
|
||||
"lsposed_connectivity_callback",
|
||||
"lsposed_connectivity_network",
|
||||
"lsposed_package_visibility",
|
||||
"zygisk_ioctl",
|
||||
"zygisk_getifaddrs",
|
||||
"zygisk_openat",
|
||||
"zygisk_recvmsg",
|
||||
"zygisk_recv",
|
||||
"zygisk_recvfrom",
|
||||
"zygisk_recvfrom_chk",
|
||||
"socket_bind_interface",
|
||||
"zygisk_setsockopt",
|
||||
];
|
||||
|
|
|
|||
|
|
@ -209,6 +209,22 @@ def emit_rust(hooks: list[Hook], errs: list[Err], backends: list[Backend]) -> st
|
|||
L.append(f" {pascal(h.name)} = {h.id},")
|
||||
L.append("}")
|
||||
L.append("")
|
||||
L.append("impl Hook {")
|
||||
L.append(" /// This hook's bit in the control/stats wire mask.")
|
||||
L.append(" pub const fn bit(self) -> u32 {")
|
||||
L.append(" 1u32 << self as u32")
|
||||
L.append(" }")
|
||||
L.append("")
|
||||
L.append(" /// Resolve a canonical config hook name.")
|
||||
L.append(" pub fn from_name(name: &str) -> Option<Self> {")
|
||||
L.append(" match name {")
|
||||
for h in hooks:
|
||||
L.append(f' "{h.name}" => Some(Self::{pascal(h.name)}),')
|
||||
L.append(" _ => None,")
|
||||
L.append(" }")
|
||||
L.append(" }")
|
||||
L.append("}")
|
||||
L.append("")
|
||||
L.append(f"pub const HOOK_COUNT: u32 = {len(hooks)};")
|
||||
L.append("")
|
||||
L.append("/// Hooks owned by each backend: apply `mask & own`.")
|
||||
|
|
@ -235,13 +251,6 @@ def emit_rust(hooks: list[Hook], errs: list[Err], backends: list[Backend]) -> st
|
|||
L.append(f" {pascal(b.name)} = {b.id},")
|
||||
L.append("}")
|
||||
L.append("")
|
||||
# One name per line so the output is rustfmt-clean (CI runs `cargo fmt
|
||||
# --check`); rustfmt wraps an over-width array into exactly this shape.
|
||||
L.append(f"pub const HOOK_NAMES: [&str; {len(hooks)}] = [")
|
||||
for h in hooks:
|
||||
L.append(f' "{h.name}",')
|
||||
L.append("];")
|
||||
L.append("")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,47 @@ pub enum Hook {
|
|||
ZygiskSetsockopt = 26,
|
||||
}
|
||||
|
||||
impl Hook {
|
||||
/// This hook's bit in the control/stats wire mask.
|
||||
pub const fn bit(self) -> u32 {
|
||||
1u32 << self as u32
|
||||
}
|
||||
|
||||
/// Resolve a canonical config hook name.
|
||||
pub fn from_name(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"fib_route_seq_show" => Some(Self::FibRouteSeqShow),
|
||||
"ipv6_route_seq_show" => Some(Self::Ipv6RouteSeqShow),
|
||||
"rtnl_fill_ifinfo" => Some(Self::RtnlFillIfinfo),
|
||||
"inet_fill_ifaddr" => Some(Self::InetFillIfaddr),
|
||||
"inet6_fill_ifaddr" => Some(Self::Inet6FillIfaddr),
|
||||
"dev_ioctl" => Some(Self::DevIoctl),
|
||||
"sock_ioctl" => Some(Self::SockIoctl),
|
||||
"fib_dump_info" => Some(Self::FibDumpInfo),
|
||||
"rt6_fill_node" => Some(Self::Rt6FillNode),
|
||||
"fib_nl_fill_rule" => Some(Self::FibNlFillRule),
|
||||
"lsposed_link_properties" => Some(Self::LsposedLinkProperties),
|
||||
"lsposed_network_capabilities" => Some(Self::LsposedNetworkCapabilities),
|
||||
"lsposed_network_info" => Some(Self::LsposedNetworkInfo),
|
||||
"lsposed_network" => Some(Self::LsposedNetwork),
|
||||
"lsposed_connectivity_result" => Some(Self::LsposedConnectivityResult),
|
||||
"lsposed_connectivity_callback" => Some(Self::LsposedConnectivityCallback),
|
||||
"lsposed_connectivity_network" => Some(Self::LsposedConnectivityNetwork),
|
||||
"lsposed_package_visibility" => Some(Self::LsposedPackageVisibility),
|
||||
"zygisk_ioctl" => Some(Self::ZygiskIoctl),
|
||||
"zygisk_getifaddrs" => Some(Self::ZygiskGetifaddrs),
|
||||
"zygisk_openat" => Some(Self::ZygiskOpenat),
|
||||
"zygisk_recvmsg" => Some(Self::ZygiskRecvmsg),
|
||||
"zygisk_recv" => Some(Self::ZygiskRecv),
|
||||
"zygisk_recvfrom" => Some(Self::ZygiskRecvfrom),
|
||||
"zygisk_recvfrom_chk" => Some(Self::ZygiskRecvfromChk),
|
||||
"socket_bind_interface" => Some(Self::SocketBindInterface),
|
||||
"zygisk_setsockopt" => Some(Self::ZygiskSetsockopt),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const HOOK_COUNT: u32 = 27;
|
||||
|
||||
/// Hooks owned by each backend: apply `mask & own`.
|
||||
|
|
@ -98,33 +139,3 @@ pub enum Backend {
|
|||
/// LSPosed Java-hook backend (system_server)
|
||||
Lsposed = 3,
|
||||
}
|
||||
|
||||
pub const HOOK_NAMES: [&str; 27] = [
|
||||
"fib_route_seq_show",
|
||||
"ipv6_route_seq_show",
|
||||
"rtnl_fill_ifinfo",
|
||||
"inet_fill_ifaddr",
|
||||
"inet6_fill_ifaddr",
|
||||
"dev_ioctl",
|
||||
"sock_ioctl",
|
||||
"fib_dump_info",
|
||||
"rt6_fill_node",
|
||||
"fib_nl_fill_rule",
|
||||
"lsposed_link_properties",
|
||||
"lsposed_network_capabilities",
|
||||
"lsposed_network_info",
|
||||
"lsposed_network",
|
||||
"lsposed_connectivity_result",
|
||||
"lsposed_connectivity_callback",
|
||||
"lsposed_connectivity_network",
|
||||
"lsposed_package_visibility",
|
||||
"zygisk_ioctl",
|
||||
"zygisk_getifaddrs",
|
||||
"zygisk_openat",
|
||||
"zygisk_recvmsg",
|
||||
"zygisk_recv",
|
||||
"zygisk_recvfrom",
|
||||
"zygisk_recvfrom_chk",
|
||||
"socket_bind_interface",
|
||||
"zygisk_setsockopt",
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue