muslim-kh09/NexusFi-app
GitHub: muslim-kh09/NexusFi-app
一个运行在 Root Android/Termux 上的自包含微型 ISP 平台,提供热点强制门户、会话管理、带宽控制及离线本地云服务。
Stars: 1 | Forks: 0
# NexusFi (微型 ISP 与本地云生态系统)
### 面向 Root Android / Termux 的生产级热点基础设施
## 目录
1. [系统概述](#1-system-overview)
2. [架构与技术栈](#2-architecture--tech-stack)
3. [核心创新与基础设施](#3-core-innovations--infrastructure)
- [PENTA-SHIELD 设备指纹](#31-penta-shield-device-fingerprinting)
- [幽灵雷达与会话管理](#32-ghost-radar--session-management)
- [智能存储与硬件遥测](#33-smart-storage--hardware-telemetry)
4. [游戏化与忠诚度引擎](#4-the-gamification--loyalty-engine)
5. [本地云(离线内联网)](#5-the-local-cloud-offline-intranet)
6. [数据层与安全架构](#6-data-layer--security-architecture)
7. [部署与启动序列](#7-deployment--startup-sequence)
8. [截图画廊](#8-screenshots-gallery)
## 1. 系统概述
该平台构成了一个完全在 rooted Android 硬件上运行的完整**微型互联网服务提供商 (Micro-ISP)** 技术栈。它专为密集型、受控访问的 Wi-Fi 环境而设计,运营者可以在其中进行精细的会话控制、可靠的收入追踪,并拥有丰富的离线内容生态系统——所有这些都不依赖于远程服务器、VPS 或云基础设施。
该系统管理着客户端连接的整个生命周期:
1. 设备连接到 Wi-Fi 接入点,并立即被 captive portal 防火墙拦截。
2. 用户通过 voucher 代码或免费试用进行身份验证,触发实时 `iptables` 规则注入以授权该特定设备。
3. 活动会话通过心跳循环持续监控。一旦过期或超时,防火墙规则将被原子性地撤销,并且会话在数据库中关闭。
4. 在整个会话期间,使用能够在 MAC 地址随机化后依然生效的多信号方法对设备进行指纹采集。忠诚度积分随之累积,用户无需运营者干预即可兑换赚取的礼物。
5. 用户随时可以访问完全离线的内联网——媒体服务器、社交网络、应用程序库——这些服务通过本地网络从同一台 Android 设备上提供,互联网带宽消耗为零。
该系统架构分为三个独立但紧密耦合的层级,每层都有明确的职责边界。
## 2. 架构与技术栈
```
┌─────────────────────────────────────────────────────────────────────────┐
│ ANDROID DEVICE (Rooted) │
│ │
│ ┌──────────────────┐ ┌─────────────────────────────────────────────┐ │
│ │ TIER 3 │ │ TIER 1 — PHP/SQLite Hotspot Backend │ │
│ │ Native Android │ │ │ │
│ │ App (Java) │ │ ┌──────────────────┐ ┌────────────────┐ │ │
│ │ │ │ │ Captive Portal │ │ Admin Panel │ │ │
│ │ • WifiService │──▶│ │ index.php │ │ admin.php │ │ │
│ │ • Heartbeat Loop │ │ │ status.php │ │ │ │ │
│ │ • PENTA-SHIELD │ │ └──────────────────┘ └────────────────┘ │ │
│ │ DNA injection │ │ │ │ │ │
│ └──────────────────┘ │ ┌──────────▼──────────────────▼─────────┐ │ │
│ │ │ INCLUDES LAYER │ │ │
│ ┌──────────────────┐ │ │ SessionManager │ firewall.php │ │ │
│ │ TIER 2 │ │ │ auth.php │ mac_detection.php │ │ │
│ │ FastAPI Local │ │ │ gift_system.php │ accounting.php │ │ │
│ │ Cloud (Python) │ │ │ device_telemetry│ captive_trace.php │ │ │
│ │ │ │ └───────────────────────────────────────┘ │ │
│ │ • Media Hub (VOD)│ │ │ │ │
│ │ • Social Network │ │ ┌──────────▼───────────────────────────┐ │ │
│ │ • File Library │ │ │ API LAYER (/api/) │ │ │
│ │ │ │ │ heartbeat.php │ payments.php │ │ │
│ │ • Admin UI │ │ │ users.php │ analytics.php │ │ │
│ │ • WebSocket │ │ │ vouchers.php │ system.php │ │ │
│ │ Telemetry │ │ └──────────────────────────────────────┘ │ │
│ └──────────────────┘ │ │ │ │
│ :8090 │ ┌──────────▼───────────────────────────┐ │ │
│ │ │ SQLite (WAL Mode) — hotspot.db │ │ │
│ ┌──────────────────┐ │ └──────────────────────────────────────┘ │ │
│ │ DAEMONS │ └─────────────────────────────────────────────┘ │
│ │ ghost_radar.sh │ │
│ │ fw-worker.php │ ┌─────────────────────────────────────────────┐ │
│ │ captive_dns │ │ KERNEL LAYER │ │
│ │ _server.php │ │ iptables │ tc (HTB) │ /proc/net/arp │ │
│ └──────────────────┘ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│
Wi-Fi AP Interface
│
┌─────────────────────┴─────────────────────┐
│ Wi-Fi Clients │
│ Browser (Captive Portal) → :8080 │
│ Offline Platform → :8090 │
└────────────────────────────────────────────┘
```
### 各层技术栈
| 层级 | 技术 | 选择理由 |
|---|---|---|
| **热点后端** | PHP (CLI Server, 4 workers) | 原生 Termux 支持;无需单独的 HTTP 服务器 |
| **数据库 (Hotspot)** | SQLite 3 (WAL + `mmap`) | 原子写入,防崩溃,无守护进程,兼容 SD 卡 |
| **本地云** | FastAPI + `aiosqlite` (Python) | 异步 I/O 在单核上处理并发媒体流而不阻塞 |
| **WSGI/ASGI Server** | Uvicorn (`--workers 1`) | Android 内核缺乏 `multiprocessing.fork`;asyncio 是正确的模型 |
| **防火墙** | `iptables-legacy` / `/system/bin/iptables` | 运行时检测;当 legacy 不可用时回退到原生 Android iptables |
| **带宽整形** | Linux `tc` HTB (Hierarchical Token Bucket) | 每用户专用类别;在内核支持的地方使用 `fq_codel` 叶节点 |
| **DNS** | 自定义 PHP UDP DNS 服务器 | 双模式:强制门户 (欺骗) 和托管 (拦截列表 + 日志) |
| **Android App** | 原生 Java (Android SDK) | 通过 `NetworkInterface`、`ActivityManager` 直接进行内核级硬件访问 |
| **会话存储** | SQLite (`local_platform.db`) | 与 hotspot 数据库隔离,防止跨层级锁定 |
## 3. 核心创新与基础设施
### 3.1 PENTA-SHIELD 设备指纹
**问题:** 现代 Android 设备 (Android 10+) 默认针对每个 Wi-Fi 网络随机化其 MAC 地址。用户的硬件地址在每次重新连接时都会改变,这使得在标准方法下,所有基于 MAC 的会话跟踪和计费从根本上变得不可靠。
**解决方案:** PENTA-SHIELD 是一个五信号设备身份系统,它构建了一个持久的、不可变的设备指纹,能够在 MAC 随机化后依然生效。它跨越原生 Android 应用程序和基于浏览器的 captive portal JavaScript 运行。
#### 信号层 1:原生 Android 应用注入 (最高信任度)
`WifiService` 前台服务通过 `Settings.Secure` 读取设备的 `ANDROID_ID`(一种基于硬件的、恢复出厂设置后才会改变的唯一标识符),并将其作为每次心跳 POST 请求中的 `native_id` 字段进行传输。`ConnectivityChecker` 进一步读取 `Build.BRAND`、`Build.MODEL` 以及通过 `ActivityManager.MemoryInfo` 获取的物理 RAM 总量,在页面渲染前将这些作为查询参数 (`n_brand`、`n_model`、`n_ram`、`native_id`) 直接注入到 captive portal URL 中。这些数据在*用户甚至还没与门户交互之前*就已到达服务器端。
当后端收到 `native_id` 时,它会覆盖所有其他 token 来源:
```
// STRICT ANCHOR: If native_id is present, it is the ultimate, immutable device token.
$native_id = $payload['native_id'] ?? $profile['native_id'] ?? '';
if (!empty($native_id)) {
$token = device_telemetry_text($native_id, 128);
}
```
携带 `native_id` 的会话将被永久标记为 `device_token = 'native_app'`。此 token 在数据库中受写保护——随后的任何遥测更新都无法覆盖它。
#### 信号层 2:浏览器端 DNA 采集
嵌入式 JavaScript 遥测脚本 (`device_telemetry.php`) 在每次页面加载和心跳时收集 13 个维度的硬件指纹:
| 信号 | 方法 |
|---|---|
| **操作系统与浏览器** | User-Agent 解析 + `navigator.userAgentData.getHighEntropyValues()` |
| **品牌与型号** | UA Client Hints (API)、UA 字符串回退、平台检查 |
| **内存** | `navigator.deviceMemory` |
| **CPU 核心** | `navigator.hardwareConcurrency` |
| **屏幕几何尺寸** | `screen.width × screen.height` (横/竖屏归一化) |
| **GPU 特性 Hash** | WebGL `UNMASKED_RENDERER_WEBGL`、视口尺寸、纹理限制 |
| **Canvas Hash** | GPU 渲染的 2D Canvas 像素 hash (亚像素渲染因 GPU 而异) |
| **音频 Hash** | WebAudio `DynamicsCompressor` 参数指纹 |
| **字体 Hash** | 13 种字体系列的字符规格测量 |
| **语言与时区** | `navigator.language`、`Intl.DateTimeFormat().resolvedOptions().timeZone` |
这些信号在设备端进行哈希处理,并作为 `raw_dna` POST 到 `api/heartbeat.php`。服务器端的 `calculate_fuzzy_match()` 函数会计算这 13 个维度的加权余弦相似度得分。如果匹配度超过可配置的阈值,则确认设备连续性,即使在 MAC 地址更改后也是如此。
#### 信号层 3:Evercookie 持久化
浏览器端的遥测脚本会同时将 `device_token` 写入三个独立的存储位置:
- `localStorage`
- `sessionStorage`
- HTTP Cookie (`max-age=31536000`,`SameSite=Lax`)
这种三重写入方法确保 token 在单个存储被清除后依然能够存活。恢复时会从这三个存储中读取,并且每次访问时都会重新同步这三个存储。
#### 信号层 4:影子档案与 MAC 变更迁移
每次提交遥测数据都会触发以 `mac_address` 为键向 `shadow_profiles` 表中进行 UPSERT 操作。当检测到 MAC 变更(相同的 `device_token`,不同的 MAC)时,`updateMacAddress()` 会在单个事务中原子性地迁移 `vouchers`、`users`、`free_trials`、`payment_requests` 和 `gifts` 表中的所有关联记录——从而在新的硬件地址下保留完整的购买和会话历史记录。
#### 信号层 5:ARP 表主权
后端从不仅将客户端提交的 MAC 地址作为主要来源信任。规范的 MAC 解析顺序是:
1. `/proc/net/arp` 内核表(直接读取文件,无 shell 执行)——由内核不可伪造地设置
2. `ip neigh show` 命令(Linux 邻居缓存——L2 硬件表)
3. GET 参数(仅当步骤 1 和 2 未产生结果时使用——竞态条件回退)
### 3.2 幽灵雷达与会话管理
幽灵雷达是会话过期和执行子系统。它由两个协同工作的组件组成:`ghost_radar.sh` 监督守护进程和 `SessionManager` PHP 类。
#### ghost_radar.sh — 看门狗循环
`ghost_radar.sh` 作为持久后台守护进程在基于 `mkdir` 的锁定下运行(在 `flock` 不可靠的 Android 上是 POSIX 安全的)。它以可配置的间隔(默认:30 秒)执行 `admin.php ghost_radar`,并在失败时以 5 秒的退避时间自动重启。这确保了过期执行流程始终在运行并具有自我修复能力。
#### SessionManager — 防火墙状态机
`SessionManager` 是数据库状态与实时 `iptables` 规则集之间关系的唯一权威。它实现了文件锁 (`flock(LOCK_EX)`),以防止并发会话发出冲突的防火墙修改指令。
**核心操作:**
- **`reconcileClientAccess($mac)`** — 主要的单设备对账路径。从数据库读取所需的授权状态,从 `iptables` 计数器同步任何待处理的计费字节(单调计费修复——防止在清空链时丢失数据),然后调用 `firewall_apply_client_state()`。
- **`reconcileAll($pdo)`** — 启动时和定期运行的全面扫描对账。执行一次 `deepCleanupFirewall()` 清理过程,清除未在授权列表中的 MAC 对应的任何 `ipset` 条目,然后为所有当前活动的 voucher 重新应用规则。
- **`invalidateClientAccess($mac)` — 断头台** — 在检测到心跳超时时调用。执行三个原子操作:
1. `firewall_apply_client_state($mac, ..., authorized=false)` — 删除该 MAC 的所有 ACCEPT/RETURN 规则。
2. `UPDATE vouchers SET ended_at = ..., end_reason = 'heartbeat_timeout'` — 在数据库中关闭会话。
3. 向 captive 跟踪日志写入 `guillotine_fired` 事件。
- **`suspendClientAccess($mac)` — 软挂起** — 当原生 Android 应用会话静默超过 600 秒但 voucher 仍然有效时应用。它不会终止会话,而是应用 `is_soft_dropped` 标志,并重新配置防火墙以发出 `REJECT --reject-with icmp-port-unreachable` 响应,这会迫使 OS captive portal 检测引擎触发并提示用户重新打开门户。
- **`guillotineSweep($pdo)`** — 主动识别上次心跳时间戳早于 600 秒,或者其心跳 token 不再是 `native_app` 的、活动的、非软挂起的 `native_android` 会话。这些会话被批量标记为 `is_soft_dropped = 1`,并被推送到异步防火墙工作队列。
#### L2 物理层取消身份验证 — `hotspot_l2_kick_client()`
当会话被撤销 (`authorized=false`) 时,防火墙模块通过内核驱动程序直接向客户端发出 Layer 2 Wi-Fi 取消身份验证帧:
```
iw dev $iface station del $mac
# 或 fallback:
hostapd_cli -i $iface deauthenticate $mac
```
这是一种物理层的强制断开连接。客户端的 Wi-Fi 协议栈断开链路,OS 检测到重新连接,captive portal 检测引擎立即重新触发——无需用户任何操作。取消身份验证在后台以非阻塞方式执行,以防止 PHP 进程停滞。
#### 防火墙架构 — 自定义 iptables 链
所有防火墙规则都在隔离的、应用拥有的链中运行,以防止干扰现有的 Android 网络共享规则:
| 链 | 表 | 用途 |
|---|---|---|
| `CP_NAT` | `nat PREROUTING` | 默认拒绝的重定向 (HTTP→:8080, DNS→盲解析器) |
| `CP_FILTER` | `filter FORWARD` | 针对未授权客户端的基于 MAC/IP 的 REJECT |
| `CP_NODOT` | `filter FORWARD` | 全局屏蔽 DNS-over-TLS (端口 853) 和已知的 DoH 端点 |
| `NOC_ACCT` | `filter FORWARD` | 父级计费链,跳转至各 voucher 的 `ACCT_V_{id}` 子链 |
| `ACCT_V_{id}` | `filter FORWARD` | 用于带宽计费的会话级字节计数器链 |
| `CP_SPEED` | `filter FORWARD` | 限速链钩子 |
| `CP_MANGLE` | `mangle POSTROUTING` | TTL 归一化 (设为 64) 以对抗网络共享检测 |
| `CP_FILTER_V6` | `ip6tables filter` | 通过 `icmp6-port-unreachable` 全屏蔽 IPv6 |
**路由覆盖:** 高优先级的 `ip rule` (`priority 15000`) 强制将来自热点接口的所有流量引入 `main` 路由表,抢占 Android 用于自身网络共享子系统的 OEM 表 1028/97/98。
**DNS 架构 — 两种模式:**
自定义 PHP DNS 服务器 (`tools/captive_dns_server.php`) 在不同端口上以两种模式运行:
- **Captive 模式** (盲解析器端口):使用网关 IP 响应所有 DNS 查询,将所有 HTTP 流量困在 captive portal 中。
- **托管模式** (标准端口):作为授权客户端的透明转发解析器,应用下载的域名拦截列表(色情、赌博、管理类)并将所有 DNS 查询记录到流量日志中。
**DoH/DoT 抑制:** `CP_NODOT` 链使用 `tcp-reset` 拒绝 DNS-over-TLS (TCP/UDP 端口 853),并阻止对 14 个已知公共 DoH 提供商 (Google, Cloudflare, Quad9 等) 的所有 HTTPS 访问。使用 `tcp-reset` 响应是刻意为之——它会导致即时 TLS 失败,从而触发 Android 11+ 和 iOS 14+ captive portal 检测中的 HTTP 回退,而不是发出网络“被管理性阻止”的信号,否则将完全抑制 captive portal 通知。
### 3.3 智能存储与硬件遥测
#### USB 混合存储向导
启动时,`start.sh` 会在四个存储命名空间中执行多轮存储候选发现扫描:
1. **内部存储** — 应用根文件系统
2. **原始 SD 卡** — `/mnt/media_rw/
` (通过 `su -c` 进行 root 提权的 `df` 读取)
3. **FUSE SD 卡** — `/storage/` (同一张物理卡的 FUSE 覆盖层)
4. **可采纳存储** — `/mnt/expand/` (格式化为内部存储的 SD 卡)
5. **USB OTG 驱动器** — 硬编码路径 + `/mnt/*usb*` 的通配符扫描
每个候选者都要通过最低可用空间 (>50 MB) 的资格验证,通过 `/proc/mounts` 进行文件系统类型检测,并进行去重。如果存在多个候选者,将显示一个带有 30 秒超时的交互式菜单。选定的路径将作为 `OFFLINE_STORAGE_PATH` 导出,并在启动时注入 FastAPI 服务器和 PHP 门户。
FastAPI 媒体服务器使用由本地 SQLite 设置表支持运行时设置 (`storage_mode`:`internal` | `usb`) 动态切换活动上传根目录,从而无需重启即可在存储后端之间进行热切换。
#### 实时硬件遥测 (FastAPI)
FastAPI 本地云管理面板通过 `asyncio` 后台任务维护每 2 秒运行一次的实时遥测循环:
| 指标 | 来源 |
|---|---|
| **CPU %** | `psutil.cpu_percent()` (3 次采样滚动平均值) |
| **RAM %** | `psutil.virtual_memory().percent` (3 次采样滚动平均值) |
| **CPU 温度** | `psutil.sensors_temperatures()` → 标签启发式算法 (`cpu`, `soc`, `core`, `cluster`) |
| **表面温度** | 主板/电池传感器,或以 CPU 温度的 60% 作为校准估算值 |
| **DB 延迟** | `DBTimerMiddleware` 拦截每个请求周期,按间隔聚合 |
| **电池 %** | `psutil.sensors_battery()` |
| **磁盘 I/O** | `psutil.disk_io_counters()` 每秒增量 |
| **网络 I/O** | `psutil.net_io_counters()` 每秒增量 |
| **活跃 WebSocket 连接数** | 来自 `ConnectionManager` 的实时计数 |
所有遥测数据同时通过 WebSocket 广播给所有已连接的管理面板客户端。`DBTimerMiddleware` ASGI 层拦截每个 HTTP 请求周期以记录响应延迟,该延迟经聚合后被推送为 `db_latency` 指标。
PHP 热点管理面板通过查询 `/sys/class/thermal/` 内核节点和 `/proc/meminfo` 获取 CPU 温度和 RAM 统计信息,独立读取硬件状态。
## 4. 游戏化与忠诚度引擎
忠诚度系统是一种可消耗的积分机制,旨在通过免费上网时间奖励回头客,同时提供防止重复兑换和并发会话滥用的保障措施。
### 积分累积
每个互联网套餐都带有可配置的积分值(例如,24h = 1 积分,72h = 3 积分,168h = 7 积分)。积分作为 `total_purchases` 存储在 `users` 表中,并在每次付费 voucher 激活时递增。忠诚度阈值(默认:10 次购买)是运行时可配置的系统设置。
### 礼物计算 — `calculate_and_award_gifts()`
奖励计算是严格确定性的,而不是累加的:
```
earned_gifts = floor(total_purchases / loyalty_threshold)
pending_gifts = COUNT(*) FROM gifts WHERE mac = ? AND status IN ('pending', 'redeeming')
new_gifts = MAX(0, earned_gifts - pending_gifts)
```
该公式是幂等的。它可以随时被调用而没有重复奖励的风险——因为礼物是基于总购买账本计算的,而不是基于增量。`redeeming` 状态充当悲观锁:已经进入兑换流程但尚未完全提交的礼物,将被计入待处理总数,以防止竞态条件。
### 礼物兑换 — `redeem_gift()`
兑换流程在数据库事务内原子性地强制执行以下不变性:
1. **强制单次使用:** 礼物记录被选中并进行 `FOR UPDATE` (通过 `UPDATE ... WHERE status = 'pending'` 并检查 `rowCount() === 1`)。如果两个并发请求试图兑换同一个礼物,只有一个会成功。
2. **无并发活动会话:** 对活动(未过期、未作废)voucher 的检查可防止在另一个套餐仍在运行时激活礼物。用户必须等到当前会话过期。
3. **悲观锁状态:** 在创建 voucher 之前,礼物会立即过渡到 `status = 'redeeming'`。此点之后的任何失败都会使礼物保持锁定状态,这可以通过计划的清理任务来解决。
4. **积分扣除:** 成功兑换后,`total_purchases` 将精确减去 `loyalty_threshold`,消耗掉赚取的礼物。这确保下一个礼物周期能从剩余部分干净利落地开始。
5. **防火墙对账:** 提交后立即调用 `SessionManager::reconcileClientAccess()`,以将新的授权状态推送到内核。
## 5. 本地云(离线内联网)
离线内联网作为独立进程 (`local_server/app.py`) 在端口 8090 上运行。所有连接的客户端(无论是否授权)都可以通过隔离区 (`walled-garden`) 的 `iptables` ACCEPT 规则 (`-p tcp --dport 8090 -j ACCEPT`) 访问它,该规则插入在 NAT `PREROUTING` 链的顶部,绕过所有 captive portal 重定向逻辑。这意味着用户无需购买任何上网时间即可浏览整个离线资料库。
### 媒体中心 (VOD)
一个结构化的文件库,分为 5 个顶级类别和 22 个子类别:
- **视频:** 电影、剧集、动漫、教程、YouTube 归档、短片
- **音频:** 古兰经、音乐、播客、有声读物
- **应用与游戏:** Android APK、PC 软件、游戏
- **图片:** 梗图、壁纸、设计图、常规照片
- **文档:** 书籍、学习资料、研究论文
文件通过支持 byte-range 的 FastAPI `StreamingResponse` 作为分块流式响应提供,从而实现原生 HTML5 视频和音频的进度拖拽,而无需完整下载文件。全局异步令牌桶限流器 (`_throttle()`) 将所有同时进行的文件流聚合上限限制为 1 MB/s,保护 Wi-Fi 半双工芯片免受 I/O 饱和的影响,同时保持 HTML 页面加载的即时性。
上传限流也在 ASGI 中间件层 (`UploadThrottleMiddleware`) 强制执行,它包装了 `receive` 可调用对象,以脉冲方式接收传入的数据块,而不是接受会导致事件循环停滞的突发上传。
### 本地社交网络
一个功能齐全的社交平台,具有以下功能:
- 用户注册、身份验证和个人资料管理(头像、个人简介、显示名称)
- 带有文本和图像内容的动态信息流;实时点赞和评论系统
- 具有 24 小时可见性、观看追踪和点赞反应的快闻
- 通过 WebSocket (`ConnectionManager` 及广播) 进行实时群聊
- 用户通知系统(点赞、评论、关注、帖子互动)
- 管理员审核面板:用户封禁、上传权限授予、内容管理
- 具有以 JSON 序列化的细粒度权限集的所有者角色系统
所有社交内容都存储在 `local_platform.db` (aiosqlite, WAL 模式) 中,与热点计费数据库完全隔离。
### 内容管理
FastAPI 管理面板提供:
- 实时硬件遥测仪表板(WebSocket 推送,2 秒刷新)
- 文件管理器:多类别上传、内联媒体预览、删除
- USB/SD 存储模式切换,带有实时路径验证
- 用户管理:封禁、提升、授予大文件上传权限
- 带有分页功能的活动日志查看器
- 维护模式切换(阻止所有非管理员访问)
## 6. 数据层与安全架构
### SQLite 配置 — 针对 Android eMMC 优化
两个数据库实例(hotspot 和本地平台)的配置完全相同,以确保在 Android 存储上的稳定性:
```
PRAGMA journal_mode = WAL; -- Concurrent readers + single writer
PRAGMA busy_timeout = 15000; -- 15-second lock wait before error
PRAGMA synchronous = NORMAL; -- Crash-safe without full fsync on every write
PRAGMA temp_store = MEMORY; -- Avoid temp file creation on flash storage
PRAGMA cache_size = -10000; -- 10 MB page cache
PRAGMA mmap_size = 268435456; -- 256 MB memory-mapped I/O
PRAGMA wal_autocheckpoint = 100; -- Checkpoint every ~400 KB to prevent WAL bloat
```
存储窒息防护 (`disk_free_space() < 10MB`) 会在任何写入操作可能导致部分提交或 WAL 文件损坏之前,以 `503 Service Unavailable` 响应暂停数据库层。
### 管理员身份验证
管理面板实现了一个经过强化的登录系统:
- 密码存储为 `bcrypt` 哈希 (`PASSWORD_DEFAULT`,成本因子约为 11)
- 登录时重新生成会话 token (`session_regenerate_id(true)`)
- 会话在不活动 30 分钟后过期 (`SESSION_LIFETIME`)
- 暴力破解防护:5 次失败尝试将触发由 `login_attempts` 表支持的 30 分钟 IP 锁定
- 锁定在 GET 和 POST 期间均被强制执行——登录表单在锁定期间完全隐藏,取而代之的是实时倒计时
- 过期锁定记录的被动清理在每次登录尝试时运行,增加了零后台开销
### 防火墙安全不变性
- **设计上默认关闭:** 所有 iptables 链都使用捕获所有的 `REJECT --reject-with icmp-port-unreachable` 规则进行初始化。未授权流量将被拒绝 (REJECT) 而不是丢弃 (DROP)——这很重要,因为 DROP 会导致 OS captive portal 引擎超时并将网络标记为损坏,从而抑制 captive portal 通知。
- **HTTPS 强制设为 `tcp-reset`:** 对于未授权客户端,端口 443 被拒绝时会使用 TCP 重置 (而不是 ICMP),这会导致即时 TLS 失败,从而在所有现代 Android 和 iOS 版本上触发 OS captive portal HTTP 回退。
- **防网络共享 (TTL/HL 篡改):** `MANGLE` 链将出站的 TTL 归一化为 64,从而击败蜂窝网络基于 TTL 的热点共享检测。
- **在 AP 接口上完全禁用 IPv6:** 通过 `/proc/sys/net/ipv6/conf/{iface}/disable_ipv6` 抑制 IPv6,以防止客户端通过 IPv6 连接绕过 captive portal。保留原始内核状态并在关机时恢复。
## 7. 部署与启动序列
系统通过单一入口点 `start.sh` 进行引导。启动序列具有严格的顺序:
**阶段 1 — 存储向导:**
交互式或自动选择离线平台的存储后端。对内部、SD 卡(原始 + FUSE)、可采纳存储和 USB OTG 挂载点进行多轮扫描。
**阶段 1.5 — 带宽配置:**
交互式提示输入默认下载速度和突发储层容量。这些值被写入 `config_override.php`,以便它们在 PHP worker 重启后依然保留,而无需重新运行向导。
**阶段 2 — FastAPI 服务器启动:**
`uvicorn` 通过 `setsid`(进程会话领导者)和 `nohup` 启动,使其免疫 shell 退出。该进程被授予 OOM 豁免权 (`oom_score_adj = -1000`),以防止 Android 的 Low Memory Killer 在内存紧张时将其驱逐。
**阶段 2.5 — APK 自动更新程序:**
后台 shell 循环每 24 小时轮询一次 GitHub Releases 以寻找新的 `app-release.apk`,并在成功时原子性地替换本地副本。
**阶段 3 — 热点监督器交接:**
`exec bin/hotspot start` 完全替换 shell 进程,使 FastAPI 进程同级进程保持活动。然后监督器会:
1. 验证并配置网络接口
2. 附加默认关闭的防火墙 (`setup_fail_closed_firewall()`)
3. 启动具有 4 个 worker 的 PHP 内置服务器
4. 以 captive 和托管模式启动自定义 DNS 服务器
5. 启动 `ghost_radar.sh` 和异步防火墙 worker (`fw-worker.php`)
6. 进入主监控循环
**关机:**
`SIGTERM`/`SIGINT` 触发 `cleanup_app_firewall_rules()`,该函数原子性地移除所有自定义链和钩子,恢复网络接口的 IPv6 状态,并清理 TC 带宽整形器——使内核保持在干净的状态。
## 8. 截图画廊
Admin Login
 |
Overview Dashboard
 |
Live Monitoring
 |
Financial Report
 |
Customers
 |
Vouchers
 |
User Profile
 |
Secondary Profile
 |
Maintenance Mode
 |
System Settings
 |
Secondary Overview
 |
*系统版本:`APP_DB_VERSION 2.1` — 架构文档源自对 `/root/wifi-4.5` 的源码审计。*标签:Termux, 域名枚举, 安卓, 强制门户, 微型ISP, 本地云, 用户忠诚度, 网络基础设施, 逆向工具