meow_netmgrd 期4:SDK 自愿通道 + wifi forget + RSSI signal_poll + AAAA 过滤 + iptables 评估

NETMGR_DESIGN.md §7/§13 期4 落地(只动 patch_v2/meow_netmgrd/ + patch_v2/sdk/ 追加式):
1. SDK 自愿通道(§6.3/§4):meow_ui.h 新增 meow_net_policy_check(host)(0=放行 1=block;
   netmgrd 不在/超时→0 乐观放行)+ meow_net_report(rx,tx)(自愿上报,§4 字节级记账自报通道)。
   meow_ipc.h 追加 0xEE MSG_NET_SDK(op=CHECK/REPORT)/ 0xEF RESULT。netmgrd 侧:CHECK 以
   app_id→实体 app:<pkg> 评估 policy_net_blocked||dns_query_domain_denied;REPORT 记入 per-实体
   g_ent_bytes(status JSON 新增 entity_bytes)。SDK 实现 meow_net_ipc.c(一次 connect+send+read,
   降级不崩);meow_ui.a 重编。
2. wifi forget <id>:wpa_cli remove_network+save_config(MeowOS;HibyOS 只读门控),CLI+IPC 接通
   (286 launcher 录入 UI 缺口)。
3. RSSI:wifi_status 在 status 无 signal= 时回退 wpa_cli signal_poll(真机 rssi=-38,修面板 rssi=null 缺口)。
4. DNS AAAA 过滤:global dns.filter_aaaa=0|1(默认 0 透传;纯 IPv4 设备可置 1 让 AAAA 查询回空答案回落 A)。
5. 静态 iptables 评估(devdocs/plan/NETMGR_IPTABLES_EVAL.md,本机不入库):iptables-legacy 1.8.9 交叉
   编译成功(~578KB,含 owner/cgroup/REDIRECT 等全部 extension),但内核实测 matches 仅
   quota/icmp/udp/tcp、targets 仅 NFQUEUE/NFLOG/ERROR、无 nat 表、全部进程 UID 0 → **per-app 管控
   与 REDIRECT 透明代理判不可行**(与 NETWORK_HW_FACTS 一致);正路为 per-app UID 框架改造(单独立项)。

验证:宿主 test_netmgrd.sh 70/70 + qemu 70/70;test_netmgrd_p2/p3/p5 宿主全过 + 交叉 0 warning;
netmgrd_authtest 全过;sdk meow_net_ipc 交叉 0 warning。真机(固件 netmgrd 共存,独立 socket+DNS off):
wifi status rssi=-38(signal_poll)、wifi forget 0(DISABLED 安全移除,id1 CURRENT 保留、wifi 未断)、
SDK policy check(CHECK_GOOD=0/CHECK_BLOCK=1/REPORT ok)、policy show 正常;resolv.conf 未触碰、
固件 meow_netmgrd(pid) running 未动;测试产物全清。

新 md5:meow_netmgrd 20243ea1a800b29badefebb395603aaf;meow_ui.a be24214e24faadba63577f3a98c2c9d1
(主会话更 fw_content.conf / 热更设备 / 记录新 meow_ui.a)。
This commit is contained in:
MeowOS committed 2026-09-02 16:19:40 +08:00
1 parent 4e0e7441fd
commit 8a43f17653
17 files changed
+563 -16

No files matched your search

+1 -1
View File
@@ -40,7 +40,7 @@ FT_INCS="-I$FT_BUILD -I$FT_BUILD/include -I$FT_SRC/include"
rm -f meow_ui.a *.o
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_ui_str meow_ui_ft"
OBJS="meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_ui_str meow_ui_ft meow_net_ipc"
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
for f in $OBJS; do
echo "== cc $f =="
+33
View File
@@ -0,0 +1,33 @@
/*
* meow_ui_net.h — MeowOS SDK 网络自愿通道(NETMGR_DESIGN §6.3/§4;追加式 API,含入 meow_ui.h)。
*
* 定位:框架 App 联网前的**自愿自治**通道 + **自愿字节上报**,二者都不强制(防君子不防小人)。
* - meow_net_policy_check(host):联网前自查 host 是否被 netmgrd 管控策略放行。
* 返回 0=allow(可联网);1=block(策略拒绝,App 应中止本次联网)。
* netmgrd 不在 / 超时 → 0(乐观放行,绝不因监控不可用而误封业务)。
* - meow_net_report(rx,tx):App 自愿上报本进程累计收发字节。内核无 per-socket/per-uid
* 字节计数器(NETMGR_DESIGN §4 表),§4 的「字节级精确记账走 SDK 自报通道」由此落地;
* netmgrd 记入 per-实体统计(status JSON `entity_bytes`)。best-effort,失败静默不影响业务。
* 用法:App 在发起 HTTP/TLS 前调 meow_net_policy_check(host),若返回 1 则按产品语义处理(如提示被限)。
*/
#ifndef MEOW_UI_NET_H
#define MEOW_UI_NET_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* 检查 host 是否被策略放行。0=allow;1=block;netmgrd 不在/超时 → 0(乐观放行)。
* host 为域名(如 "music.163.com");判定以当前 App(MEOW_LOG_APP)为实体,服务端策略引擎权威执行。 */
int meow_net_policy_check(const char *host);
/* 上报本进程累计收发字节(best-effort,失败静默)。 */
void meow_net_report(uint32_t rx, uint32_t tx);
#ifdef __cplusplus
}
#endif
#endif /* MEOW_UI_NET_H */
+157
View File
@@ -0,0 +1,157 @@
/*
* meow_net_ipc.c — MeowOS SDK 网络自愿通道 → netmgrd IPC 桥(期4;追加式协议 0x00EE/0x00EF)。
*
* 与 meow_notify_ipc.c 同型:只做「一次性 connect + send + read」,不维护连接/订阅循环。
* - meow_net_policy_check(host):MSG_NET_SDK op=NET_SDK_CHECK(app_id=MEOW_LOG_APP + host);
* 读到 allow=1 → 返回 0(allow),allow=0 → 返回 1(block);任何失败(无 socket/超时/非法应答)
* → 返回 0(乐观放行,绝不因监控不可用误封业务——NETMGR_DESIGN §6.3 自愿性质)。
* - meow_net_report(rx,tx):MSG_NET_SDK op=NET_SDK_REPORT;send 后读一次应答头即关(不读文本),
* best-effort,失败静默(返回值 void)。
* 映射层(SDK 入参 ↔ IPC m_net_sdk_t 字段)集中在本文件;app_id 取 env MEOW_LOG_APP(与 meow_ui_log.c
* 口径一致),socket 路径取 env MEOW_NET_SOCK(宿主/qemu 覆盖)缺省 /usr/data/meow_net.sock。
*
* 线程安全:app_id pthread_once 缓存;本文件纯传输层不调 meow_log(与 meow_notify_ipc.c 同约定)。
*/
#include "meow_net_ipc.h"
#include "meow_ipc.h" /* 共享协议:帧头/m_net_sdk_t/m_net_sdk_result_t/MSG_NET_SDK* —— 防漂移 */
#include <stdio.h> /* snprintf */
#include <stdlib.h> /* getenv */
#include <string.h>
#include <errno.h> /* EINTR */
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#define MEOW_NET_IPC_TIMEOUT_MS 500 /* 应答读超时:netmgrd 单线程 poll,>500ms 视为降级 */
static pthread_once_t g_once = PTHREAD_ONCE_INIT;
static char g_app_id[MEOW_APP_ID_MAX] = "app";
static void ipc_init(void)
{
const char *s = getenv("MEOW_LOG_APP");
if (s && s[0]) snprintf(g_app_id, sizeof g_app_id, "%s", s);
}
const char *meow_net_ipc_app_id(void)
{
pthread_once(&g_once, ipc_init);
return g_app_id;
}
/* socket 路径:优先 env MEOW_NET_SOCK,缺省 /usr/data/meow_net.sock。 */
static const char *ipc_sock_path(void)
{
const char *s = getenv("MEOW_NET_SOCK");
return (s && s[0]) ? s : "/usr/data/meow_net.sock";
}
/* 连接 socket;失败 -1(调用方降级)。 */
static int conn_path(const char *path)
{
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) return -1;
struct sockaddr_un a;
memset(&a, 0, sizeof a);
a.sun_family = AF_UNIX;
strncpy(a.sun_path, path, sizeof a.sun_path - 1);
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return -1; }
return fd;
}
static int write_all(int fd, const uint8_t *p, size_t n)
{
size_t off = 0;
while (off < n) {
ssize_t w = write(fd, p + off, n - off);
if (w < 0) { if (errno == EINTR) continue; return 0; }
if (w == 0) return 0;
off += (size_t)w;
}
return 1;
}
static int read_all(int fd, uint8_t *p, size_t n)
{
size_t off = 0;
while (off < n) {
ssize_t r = read(fd, p + off, n - off);
if (r < 0) { if (errno == EINTR) continue; return 0; }
if (r == 0) return 0;
off += (size_t)r;
}
return 1;
}
static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len)
{
uint8_t hdr[MEOW_IPC_HDR_LEN];
uint32_t magic = MEOW_IPC_MAGIC, rl = len;
uint16_t ver = MEOW_IPC_VERSION, t = type;
memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &t, 2);
memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &rl, 4);
if (!write_all(fd, hdr, sizeof hdr)) return 0;
if (len && payload && !write_all(fd, payload, len)) return 0;
return 1;
}
static void set_timeout(int fd)
{
struct timeval tv;
tv.tv_sec = MEOW_NET_IPC_TIMEOUT_MS / 1000;
tv.tv_usec = (MEOW_NET_IPC_TIMEOUT_MS % 1000) * 1000;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
}
int meow_net_policy_check(const char *host)
{
if (!host || !host[0]) return 0;
m_net_sdk_t q;
memset(&q, 0, sizeof q);
q.op = NET_SDK_CHECK;
snprintf(q.app_id, sizeof q.app_id, "%s", meow_net_ipc_app_id());
snprintf(q.host, sizeof q.host, "%s", host);
int fd = conn_path(ipc_sock_path());
if (fd < 0) return 0; /* java socket:乐观放行 */
set_timeout(fd);
int allow = 0; /* 默认放行 */
if (send_frame(fd, MSG_NET_SDK, 0x4E455443u /* "NETC" */, &q, (uint32_t)sizeof q)) {
uint8_t rhdr[MEOW_IPC_HDR_LEN];
if (read_all(fd, rhdr, sizeof rhdr)) {
uint16_t rtype; uint32_t rlen;
memcpy(&rtype, rhdr + 6, 2); memcpy(&rlen, rhdr + 12, 4);
if (rtype == MSG_NET_SDK_RESULT && rlen >= 10) {
uint8_t pay[12];
if (read_all(fd, pay, 12)) { /* code(4)+allow(4)+text_len(2)+pad(2) */
m_net_sdk_result_t res;
memset(&res, 0, sizeof res);
memcpy(&res.code, pay, 4);
memcpy(&res.allow, pay + 4, 4);
memcpy(&res.text_len, pay + 8, 2);
if (res.text_len < sizeof res.text)
read_all(fd, (uint8_t *)res.text, res.text_len);
if (res.code == MEOW_OK) allow = (res.allow != 0) ? 1 : 0;
}
}
}
}
close(fd);
return allow ? 0 : 1; /* allow=1 → 返回 0(放行);allow=0 → 返回 1(block) */
}
void meow_net_report(uint32_t rx, uint32_t tx)
{
m_net_sdk_t q;
memset(&q, 0, sizeof q);
q.op = NET_SDK_REPORT;
snprintf(q.app_id, sizeof q.app_id, "%s", meow_net_ipc_app_id());
q.rx = rx; q.tx = tx;
int fd = conn_path(ipc_sock_path());
if (fd < 0) return; /* 无 socket:静默 */
set_timeout(fd);
if (send_frame(fd, MSG_NET_SDK, 0x4E455452u /* "NETR" */, &q, (uint32_t)sizeof q)) {
uint8_t rhdr[MEOW_IPC_HDR_LEN];
read_all(fd, rhdr, sizeof rhdr); /* best-effort:读一次应答头即关,不解析 */
}
close(fd);
}
+28
View File
@@ -0,0 +1,28 @@
/*
* meow_net_ipc.h — MeowOS SDK 网络自愿通道 → netmgrd IPC 桥(内部头,不随 meow_ui.h 发布)。
*
* 定位(NETMGR_DESIGN §6.3/§4):让框架 App 的 meow_net_policy_check()/meow_net_report() 真正经
* AF_UNIX IPC 到 netmgrd(/usr/data/meow_net.sock)。协议帧与负载结构复用共享 meow_ipc.h:
* - MSG_NET_SDK(0x00EE) ↑:op=NET_SDK_CHECK(app_id+host)/ NET_SDK_REPORT(app_id+rx+tx);
* - MSG_NET_SDK_RESULT(0x00EF) ↓:code + (CHECK)allow + 状态文本。
* 约定:只做「一次性 connect + send + read」,不维护订阅循环(同 meow_notify_ipc.c 型);
* 全部失败路径优雅降级(无 socket/写失败/超时/非法应答 → check 返回 0 放行、report 静默)。
*/
#ifndef MEOW_NET_IPC_H
#define MEOW_NET_IPC_H
#include <stdint.h>
#include "meow_ui.h" /* meow_net_policy_check / meow_net_report */
#ifdef __cplusplus
extern "C" {
#endif
/* 当前 app 的 app_id(env MEOW_LOG_APP,缺省 "app";pthread_once 缓存,线程安全)。 */
const char *meow_net_ipc_app_id(void);
#ifdef __cplusplus
}
#endif
#endif /* MEOW_NET_IPC_H */
+1
View File
@@ -71,5 +71,6 @@
#include "include/meow_ui_anim.h"
#include "include/meow_ui_scroll.h"
#include "include/meow_ui_str.h"
#include "include/meow_ui_net.h" /* 期4 网络自愿通道:meow_net_policy_check / meow_net_report */
#endif /* MEOW_UI_H */
+27
View File
@@ -0,0 +1,27 @@
/* test_net_ipc.c — MeowOS SDK 网络自愿通道 宿主自测(非生产代码)。
*
* 通过链接 meow_net_ipc.c 调 meow_net_policy_check()/meow_net_report(),对运行中的 netmgrd
* (MEOW_NET_SOCK 指向测试 socket)验证:
* - meow_net_policy_check(host):按 MEOW_LOG_APP 实体判定 allow/block(netmgrd 决策权威);
* - meow_net_report(rx,tx):best-effort 上报(netmgrd 记入 entity_bytes)。
* 用法:cc -Iinclude -I. -I../meow_launcherd test_net_ipc.c meow_net_ipc.c -o test_net_ipc
* 然后 MEOW_NET_SOCK=<sock> MEOW_LOG_APP=<pkg> ./test_net_ipc
*/
#include "include/meow_ui_net.h"
#include <stdio.h>
int main(void)
{
/* CHECK:域名放行/拒绝判定(netmgrd 决策)。 */
int a = meow_net_policy_check("music.163.com");
printf("CHECK_GOOD=%d\n", a); /* 期望 0(allow/放行) */
int b = meow_net_policy_check("ads.example.com");
printf("CHECK_BLOCK=%d\n", b); /* 期望 1(block/拒绝,若策略 deny 该域) */
/* 空 host → 0 放行(防御)。 */
int c = meow_net_policy_check(NULL);
printf("CHECK_NULL=%d\n", c);
/* REPORT:best-effort 上报。 */
meow_net_report(12345, 67890);
printf("REPORT_DONE\n");
return 0;
}