vpnhide/kmod/generated/iface_lists.h
Danila Gornushko daa98f3138
refactor: drive VPN-iface matching from a single TOML source of truth (#90)
The kernel module, zygisk, lsposed-native, and the LSPosed Kotlin module
each had their own hand-written list of VPN interface name prefixes,
and the four had drifted: kmod/zygisk/HookEntry knew utun/l2tp/gre
while lsposed-native and DiagnosticsScreen only knew tun/wg/ppp/tap/
ipsec/xfrm. So the self-test could PASS while the hooks were actually
hiding more interfaces.

Move the rules to data/interfaces.toml and render four matchers from it
via scripts/codegen-interfaces.py — one per language target. A new lint
job re-runs the codegen and fails if anything drifts.

The match grammar is intentionally tiny so each codegen target
implements it without depending on regex (kernel C can't):
  exact / prefix / prefix+digits / contains.

Side effect: native diagnostics now agree with the hooks, so the
self-test in DiagnosticsScreen will recognize utun*, l2tp*, gre* and
*vpn* substrings as VPN tunnels (previously it would silently PASS on
those). The /proc/net/route check also moved from raw substring to
whitespace-tokenized matching, which avoids matching VPN-prefix
substrings that show up by chance inside hex-encoded IP addresses.

Existing zygisk filter unit tests still pass unchanged — public API of
is_vpn_iface_bytes / is_vpn_iface_cstr is preserved, only the body now
delegates to the generated matches_vpn().

Cargo.lock files updated incidentally (synced with Cargo.toml versions
that were already 0.7.1 in the manifests).
2026-04-25 20:53:11 +03:00

110 lines
2.7 KiB
C

/* AUTO-GENERATED from data/interfaces.toml — do not edit by hand. Regenerate with: python3 scripts/codegen-interfaces.py */
#ifndef VPNHIDE_GENERATED_IFACE_LISTS_H
#define VPNHIDE_GENERATED_IFACE_LISTS_H
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/types.h>
static inline bool vpnhide_iface_starts_with_ci(
const char *name, const char *prefix)
{
size_t i;
for (i = 0; prefix[i]; i++) {
if (!name[i])
return false;
if (tolower((unsigned char)name[i]) !=
(unsigned char)prefix[i])
return false;
}
return true;
}
static inline bool vpnhide_iface_starts_with_then_digits_ci(
const char *name, const char *prefix)
{
size_t i;
if (!vpnhide_iface_starts_with_ci(name, prefix))
return false;
i = strlen(prefix);
if (!name[i])
return false;
for (; name[i]; i++)
if (name[i] < '0' || name[i] > '9')
return false;
return true;
}
static inline bool vpnhide_iface_equals_ci(
const char *name, const char *other)
{
size_t i;
for (i = 0; other[i]; i++) {
if (!name[i])
return false;
if (tolower((unsigned char)name[i]) !=
(unsigned char)other[i])
return false;
}
return name[i] == '\0';
}
static inline bool vpnhide_iface_contains_ci(
const char *name, const char *needle)
{
size_t nlen = strlen(needle);
size_t i, j;
if (nlen == 0)
return true;
for (i = 0; name[i]; i++) {
for (j = 0; j < nlen; j++) {
if (!name[i + j])
return false;
if (tolower((unsigned char)name[i + j]) !=
(unsigned char)needle[j])
break;
}
if (j == nlen)
return true;
}
return false;
}
static inline bool vpnhide_iface_is_vpn(const char *name)
{
if (!name || !name[0])
return false;
/* OpenVPN, WireGuard userspace, Tailscale, generic tunneling */
if (vpnhide_iface_starts_with_ci(name, "tun"))
return true;
/* OpenVPN bridged */
if (vpnhide_iface_starts_with_ci(name, "tap"))
return true;
/* WireGuard kernel */
if (vpnhide_iface_starts_with_ci(name, "wg"))
return true;
/* PPTP / L2TP PPP tunnels */
if (vpnhide_iface_starts_with_ci(name, "ppp"))
return true;
/* Android built-in IPsec VPN */
if (vpnhide_iface_starts_with_ci(name, "ipsec"))
return true;
/* kernel IPsec XFRM framework */
if (vpnhide_iface_starts_with_ci(name, "xfrm"))
return true;
/* Apple-style, rare on Android */
if (vpnhide_iface_starts_with_ci(name, "utun"))
return true;
/* L2TP */
if (vpnhide_iface_starts_with_ci(name, "l2tp"))
return true;
/* GRE tunnels */
if (vpnhide_iface_starts_with_ci(name, "gre"))
return true;
/* catch-all for renamed clients (myvpn0, vpn-client, xvpn1, ...) */
if (vpnhide_iface_contains_ci(name, "vpn"))
return true;
return false;
}
#endif /* VPNHIDE_GENERATED_IFACE_LISTS_H */