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

+110
View File
@@ -0,0 +1,110 @@
/* test_netmgrd_p5.c — meow_netmgrd 期4 纯逻辑宿主自测(非生产代码)。
*
* 通过 #include 生产源,同一 TU 直接访问 FILE-STATIC:wifi_status / dns_parse_query /
* rules_load / wifi_ctl_execute / g_dns_filter_aaaa / g_policy_log_level / policy_cmd。
* 覆盖:①wifi status 缺 signal= 时回退 signal_poll 取 RSSI(面板 rssi=null 缺口修复)
* ②dns_parse_query 解析 QTYPE(A=1/AAAA=28,供 AAAA 过滤)③global dns.filter_aaaa 配置加载
* ④wifi forget(remove_network + save_config,MeowOS)⑤策略引擎回归(net/domain/防自锁)。
*
* 用法:cc -Wall -Wextra -I../meow_launcherd test_netmgrd_p5.c -o test_netmgrd_p5 && ./test_netmgrd_p5
*/
#define main meow_netmgrd_prod_main_unused
#include "meow_netmgrd.c"
#undef main
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
static int g_fail = 0;
#define CHECK(cond) do { if (!(cond)) { printf(" FAIL: %s (line %d)\n", #cond, __LINE__); g_fail++; } \
else { printf(" ok : %s\n", #cond); } } while (0)
static void wf(const char *p, const char *s) { FILE *f=fopen(p,"w"); if(f){fputs(s,f);fclose(f);} }
int main(void)
{
static const char *T = "/tmp/nmg_p5";
char path[256];
mkdir(T, 0755);
printf("== wifi_status:status 无 signal= 回退 signal_poll ==\n");
snprintf(path, sizeof path, "%s/wpa_st", T);
wf(path, "#!/bin/sh\n"
"if [ \"$1\" = \"status\" ]; then echo 'wpa_state=COMPLETED'; echo 'ssid=MyWiFi'; echo 'ip_address=10.78.193.50'; fi\n"
"if [ \"$1\" = \"signal_poll\" ]; then echo 'RSSI=-56'; echo 'LINKSPEED=54'; fi\n"
"exit 0\n");
chmod(path, 0755);
g_wpa_cli = ""; { static char w[192]; snprintf(w,sizeof w,"%s",path); g_wpa_cli=w; }
wifi_t w;
wifi_status(&w);
CHECK(w.has_rssi == 1);
CHECK(w.rssi == -56);
CHECK(w.connected == 1 && strcmp(w.ssid, "MyWiFi") == 0);
printf("== dns_parse_query:QTYPE 解析 ==\n");
{
uint8_t q[256];
int off = 12;
const char *name = "music.163.com";
memset(q,0,sizeof q); q[2]=0x01; q[4]=0; q[5]=1; /* RD=1 qdcount=1 */
for (const char *p=name; *p;) {
const char *d = strchr(p, '.');
size_t l = d ? (size_t)(d - p) : strlen(p);
q[off++] = (uint8_t)l; memcpy(q+off, p, l); off += (int)l;
p = d ? d + 1 : p + l;
}
q[off++] = 0; /* qname 终止 */
q[off++] = 0; q[off++] = 1; /* qtype A */
q[off++] = 0; q[off++] = 1; /* qclass IN */
char dom[DNS_QNAME_MAX]; int qend=0,qt=0;
CHECK(dns_parse_query(q,off,dom,sizeof dom,&qend,&qt)==0);
CHECK(strcmp(dom,"music.163.com")==0 && qt==1); /* A=1 */
q[off-4] = 0; q[off-3] = 28; /* 改 QTYPE=AAAA */
CHECK(dns_parse_query(q,off,dom,sizeof dom,&qend,&qt)==0 && qt==28);
}
printf("== global dns.filter_aaaa 配置加载 + policy 回归 ==\n");
snprintf(path, sizeof path, "%s/policy", T);
wf(path, "global log_level=debug dns.filter_aaaa=1\nproc:thttpd net=block\n");
g_net_policy[0]=0; snprintf(g_net_policy,sizeof g_net_policy,"%s",path);
rules_load();
CHECK(g_dns_filter_aaaa == 1);
CHECK(strcmp(g_policy_log_level, "debug") == 0);
CHECK(policy_net_blocked("proc:thttpd") == 1);
CHECK(dns_query_domain_denied("proc:thttpd", "anything.com") == 1); /* net=block → DNS 全 deny */
CHECK(is_self_lock("proc:dropbear") == 1);
CHECK(policy_net_blocked("proc:dropbear") == 0);
printf("== wifi forget(remove_network + save_config)==\n");
{
char rm_path[192], sv_path[192];
snprintf(rm_path, sizeof rm_path, "%s/rm.log", T);
snprintf(sv_path, sizeof sv_path, "%s/sv.log", T);
snprintf(path, sizeof path, "%s/wpa_fg", T);
char script[512];
snprintf(script, sizeof script,
"#!/bin/sh\n"
"if [ \"$1\" = \"remove_network\" ]; then echo \"$@\" > \"%s\"; fi\n"
"if [ \"$1\" = \"save_config\" ]; then echo \"$@\" > \"%s\"; fi\n"
"exit 0\n", rm_path, sv_path);
wf(path, script);
chmod(path, 0755);
g_wpa_cli = ""; { static char w2[192]; snprintf(w2,sizeof w2,"%s",path); g_wpa_cli=w2; }
g_mode_meow = 1;
ctl_result_t r;
wifi_ctl_execute("forget", "7", &r);
CHECK(r.code == MEOW_OK);
CHECK(strstr(r.text, "network_id=7") != NULL);
CHECK(strstr(r.text, "save_config") != NULL);
char buf[64]; read_file_txt(rm_path, buf, sizeof buf);
CHECK(strstr(buf, "remove_network 7") != NULL);
read_file_txt(sv_path, buf, sizeof buf);
CHECK(strstr(buf, "save_config") != NULL);
}
if (g_fail) { printf("\nNETMGR P5 TEST: %d FAIL\n", g_fail); return 1; }
printf("\nNETMGR P5 TEST: ALL PASS\n");
return 0;
}