NETMGR_DESIGN.md §6/§13 期3 落地(全在 patch_v2/meow_netmgrd/ + meow_ipc.h 追加): 1. 策略引擎全量:/data/meow/netmgrd/net_policy.conf(/data=/usr/data)读改写单键+原子写 (temp+rename,绝不 O_TRUNC 整文件重写——watchdog 毁设置教训);per-实体(app:/svc:/proc:) net=allow|block + domain 白/黑(接通 DNS 层执行)+ global log_level;默认 allow。 2. 防自锁硬编码:dropbear/wpa_supplicant/udhcpc/meow_netmgrd/meow_svcd/meow_sysui/init 拒绝 block (CLI/IPC 拒 + 加载校验把手工改坏的文件里这些实体的 net=block 同样强制复位 allow——§14 红线)。 3. SOCK_DESTROY 真机实测(sockdestroy_probe.c,root @内核4.4):**内核接受 SOCK_DESTROY 请求(rc=0) 但未真正销毁 socket(cookie=0 与 dump-cookie 两法均 dead=0)→ 判定 no-op/不可用**。 ⇒ 连接级执行降级为「仅 DNS 层生效」(net=block → dns_query_domain_denied 全量 deny,DNS 层落地), policy show 头 enfor=dns_only 明示。SDK 自愿通道/设置页迁移期外。 4. IPC 0x00EA MSG_NET_POLICY(op: show/set net/set domain/del)+ RESULT 0x00EB:读级任意、写级仅系统身份。 CLI:policy show [entity] | set <entity> allow|block | domain <entity> +host|-host | del <entity>。 5. 两小修:①classify_exe 增认 MeowPanel 精确路径(修面板 dns flush 403;面板已有 PIN 门禁) ②连接未归因(inode=0/查不到)一律落 proc:unknown——修 apps 表出现「IP:port」原始端点行。 6. WiFi connect 持久化:MeowOS 模式 connect 后 wpa_cli save_config(HibyOS 只读由服务端门控)。 验证:宿主 test_netmgrd.sh 61/61 + qemu 61/61;test_netmgrd_p2/p3 宿主+qemu 全过;netmgrd_authtest 全过; 交叉 -Wall -Wextra 0 warning。真机只读实测(DNS-on 固件共存,用独立 socket+/tmp 临时 policy.json): policy set/domain/del 全链 + 防自锁拒绝 proc:dropbear(rc=1) + 空文件 del(size=0) + apps 无原始端点 + resolv.conf 未触碰(测后核验固件两行形式);Firmware meow_netmgrd(pid 8142) running 未动。 新 md5:meow_netmgrd 62369ebe29e7ef4b55067a0f14e240d0(主会话更 fw_content.conf/热更设备)。
120 lines
5.7 KiB
C
120 lines
5.7 KiB
C
/* test_netmgrd_p3.c — meow_netmgrd 期3 管控层 纯逻辑宿主自测(本程序非生产代码)。
|
||
*
|
||
* 通过 #include 生产源,同一 TU 直接访问 FILE-STATIC:policy_cmd / rules_load / policy_persist_entity /
|
||
* policy_net_blocked / dns_query_domain_denied / is_self_lock / policy_find / g_policy_log_level。
|
||
* 覆盖:policy set net(per-entity 持久化读改写)、防自锁拒绝 + 加载校验剔除、domain 白/黑、
|
||
* net=block → DNS 层全量 deny、del、global log_level、RMW 保留他行。真实 IPC 鉴权(CALL_OTHER 拒)
|
||
* 由 test_netmgrd.sh 覆盖。
|
||
*
|
||
* 用法:cc -Wall -Wextra -I../meow_launcherd test_netmgrd_p3.c -o test_netmgrd_p3 && ./test_netmgrd_p3
|
||
*/
|
||
#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 char rd[512];
|
||
static const char *readfile(const char *p)
|
||
{
|
||
FILE *f = fopen(p, "r");
|
||
if (!f) { rd[0] = 0; return rd; }
|
||
size_t n = fread(rd, 1, sizeof rd - 1, f); rd[n] = 0; fclose(f);
|
||
return rd;
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
static const char *T = "/tmp/nmg_p3";
|
||
char policy[192];
|
||
mkdir(T, 0755);
|
||
snprintf(policy, sizeof policy, "%s/policy", T);
|
||
g_net_policy[0] = 0; snprintf(g_net_policy, sizeof g_net_policy, "%s", policy);
|
||
FILE *f = fopen(policy, "w"); /* 先建空 policy 文件 */
|
||
if (f) { fputs("# boot\n", f); fclose(f); }
|
||
|
||
char out[512];
|
||
int rc;
|
||
|
||
printf("== policy_cmd SET_NET(per-entity 持久化)==\n");
|
||
rules_load();
|
||
CHECK(g_rule_n == 0);
|
||
rc = policy_cmd(NET_POLICY_SET_NET, "proc:thttpd", "block", out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(strstr(readfile(policy), "proc:thttpd net=block") != NULL);
|
||
CHECK(policy_net_blocked("proc:thttpd") == 1);
|
||
CHECK(policy_net_blocked("proc:unknown") == 0); /* 未显式规则 → 默认 allow */
|
||
|
||
printf("== 防自锁:拒绝 block + 加载校验剔除 ==\n");
|
||
rc = policy_cmd(NET_POLICY_SET_NET, "proc:dropbear", "block", out, sizeof out);
|
||
CHECK(rc == MEOW_ERR_PERM);
|
||
CHECK(strstr(out, "防自锁") != NULL);
|
||
CHECK(policy_net_blocked("proc:dropbear") == 0);
|
||
CHECK(policy_net_blocked("svc:meow_netmgrd") == 0);
|
||
/* 手工改坏文件塞入 dropbear net=block → 加载校验剔除 */
|
||
f = fopen(policy, "w");
|
||
if (f) { fputs("proc:dropbear net=block\nproc:thttpd net=block\n", f); fclose(f); }
|
||
rules_load();
|
||
CHECK(policy_net_blocked("proc:dropbear") == 0);
|
||
CHECK(policy_net_blocked("proc:thttpd") == 1);
|
||
|
||
printf("== policy SET_DOMAIN(白/黑;allow 覆盖)+ net=block → DNS 全量 deny ==\n");
|
||
rc = policy_cmd(NET_POLICY_SET_DOMAIN, "proc:web", "+music.163.com", out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
rc = policy_cmd(NET_POLICY_SET_DOMAIN, "proc:web", "-ads.example.com", out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(strstr(readfile(policy), "proc:web domain=+music.163.com,-ads.example.com") != NULL);
|
||
CHECK(dns_query_domain_denied("proc:web", "music.163.com") == 0); /* 白名单允许 */
|
||
CHECK(dns_query_domain_denied("proc:web", "p.music.163.com") == 0); /* 子域也允许 */
|
||
CHECK(dns_query_domain_denied("proc:web", "ads.example.com") == 1); /* 黑名单拒绝 */
|
||
CHECK(dns_query_domain_denied("proc:web", "other.com") == 0);
|
||
/* net=block 的实体 → DNS 全量 deny(即使白名单);且已有 domain 规则的实体被 block 后同样全 deny */
|
||
rc = policy_cmd(NET_POLICY_SET_NET, "proc:web", "block", out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(dns_query_domain_denied("proc:web", "music.163.com") == 1); /* block 覆盖白名单 */
|
||
rc = policy_cmd(NET_POLICY_SET_NET, "app:dev.player.ncm", "block", out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(dns_query_domain_denied("app:dev.player.ncm", "music.163.com") == 1);
|
||
|
||
printf("== del 移除实体(RMW 保留其它行)==\n");
|
||
rc = policy_cmd(NET_POLICY_DEL, "proc:thttpd", NULL, out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(strstr(readfile(policy), "proc:thttpd") == NULL);
|
||
CHECK(strstr(readfile(policy), "app:dev.player.ncm net=block") != NULL); /* 其它实体行保留 */
|
||
/* RMW 保留注释/无关行(写回前 seed 应有 # 头) */
|
||
f = fopen(policy, "w");
|
||
if (f) { fputs("# commentary\nproc:thttpd net=block\napp:dev.player.ncm domain=-tracker.net\n", f); fclose(f); }
|
||
rules_load();
|
||
rc = policy_cmd(NET_POLICY_SET_NET, "app:dev.player.ncm", "block", out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(strstr(readfile(policy), "# commentary") != NULL);
|
||
CHECK(strstr(readfile(policy), "app:dev.player.ncm domain=-tracker.net") != NULL); /* domain 行保留 */
|
||
CHECK(strstr(readfile(policy), "app:dev.player.ncm net=block") != NULL);
|
||
|
||
printf("== global log_level ==\n");
|
||
f = fopen(policy, "w");
|
||
if (f) { fputs("global log_level=debug\n", f); fclose(f); }
|
||
rules_load();
|
||
CHECK(strcmp(g_policy_log_level, "debug") == 0);
|
||
|
||
printf("== del 到空文件(write 0 字节场景)==\n");
|
||
f = fopen(policy, "w");
|
||
if (f) { fputs("proc:thttpd net=block\n", f); fclose(f); }
|
||
rules_load();
|
||
rc = policy_cmd(NET_POLICY_DEL, "proc:thttpd", NULL, out, sizeof out);
|
||
CHECK(rc == MEOW_OK);
|
||
CHECK(strstr(readfile(policy), "proc:thttpd") == NULL); /* 文件已无该实体(可为空) */
|
||
CHECK(g_rule_n == 0);
|
||
|
||
if (g_fail) { printf("\nNETMGR P3 TEST: %d FAIL\n", g_fail); return 1; }
|
||
printf("\nNETMGR P3 TEST: ALL PASS\n");
|
||
return 0;
|
||
}
|