meow_netmgrd 期2:观测层(PID→实体归因+连接普查)+DNS 代理+事件日志+连接/DNS IPC 与 CLI

NETMGR_DESIGN.md 期2范围落地(全在 patch_v2/meow_netmgrd/ + meow_ipc.h 追加):
- 连接普查(§4):每 2s 解析 /proc/net/{tcp,udp}(IPv4) → socket inode→pid(由 inode 集驱动扫
  /proc/<pid>/fd,不逐 pid 盲扫)→ 三实体归因 app:<pkg>(amsd status)/svc:<svc>(svcd 落盘状态
  /tmp/meow_svcd.status,socket 查询兜底)/proc:<comm>(无则 proc:unknown)。连接表静态 ≤512:
  entity/五元组/状态/寿命;远端 IP 由 DNS 缓存反查域名。
- DNS 代理(§5):监听 127.0.0.1:53 UDP;启动备份 resolv.conf 写双行(127.0.0.1+原上游,崩溃零断流);
  透传转发+缓存(TTL 尊重;≤256 条);按源端口(port→entity)归因;域名规则 per-entity+global allow/deny
  (deny→NXDOMAIN+日志);atexit/SIGTERM/SIGHUP 恢复;5s 自检被第三方改回即重写;HibyOS 绝不启用/绝不改 resolv。
  DNS wire(deny NXDOMAIN / forward→A+cache / NXDOMAIN id 回显) 宿主+qemu 实测 PASS。
- 事件日志(§8):新连接/关闭/dns deny/接口状态变化;同 entity 同 dst 1 分钟去重(首条+计数)。
- IPC meow_ipc.h 追加 0x00E8 CONNS_REQ/RESULT、0x00EC DNS_CTL/RESULT(纯追加不改既有行;
  0x00EA 策略(期3)/0x00EE 事件推送(预留) 保留)。
- CLI meow_net 补 apps / conns [entity] / top(2s 刷新) / dns status|stats|flush。
- 内存:静态表禁 malloc,mipsel bss 228KB → RSS≈374KB,≤600KB 目标 / ≤1MB 预算。

宿主编译 -Wall -Wextra 0 warning;test_netmgrd.sh 48/48(宿主+qemu)、test_netmgrd_p2 全过(宿主+qemu)、
netmgrd_authtest 全过;真机(M6.0/0.8.0)只读实测 apps/conns/dns status 正确
(svc:meowpanel/svc:mdnsd/proc:dropbear 真实三实体归因),resolv.conf 测后核验原值未触碰。
This commit is contained in:
MeowOS committed 2026-09-01 20:40:46 +08:00
1 parent 239345bfd2
commit 52edf0c9e4
8 files changed
+1400 -8

No files matched your search

+106 -1
View File
@@ -37,6 +37,19 @@ EOF
printf 'nameserver 223.5.5.5\nnameserver 10.78.193.1\n' > "$T/resolv"
echo meow > "$T/boot_mode"
# ---- 期2 观测层打桩:/proc/net/{tcp,udp}(IPv4 LE hex)+ 域名规则 conf + amsd/svcd 缺省 ----
cat > "$T/tcp" <<'EOF'
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 32C14E0A:5137 0905CD8C:01BB 01 00000000:00000000 00:00000000 00000000 1000 0 12345 1 0 0 10 0
1: 32C14E0A:4F32 32C34E0A:01BB 01 00000000:00000000 00:00000000 00000000 1000 0 12346 1 0 0 10 0
2: 32C14E0A:0A00 00000000:0000 07 00000000:00000000 00:00000000 00000000 1000 0 67890 1 0 0 10 0
EOF
cat > "$T/udp" <<'EOF'
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:D301 0100007F:0035 07 00000000:00000000 00:00000000 00000000 0 0 99999 1 0 0 10 0
EOF
printf 'app:dev.player.ncm domain=-ads.example.com\nproc:dropbear domain=+x\n' > "$T/policy"
# 桩后端命令(popen stubbing)
cat > "$T/wpa_cli" <<'EOF'
#!/bin/sh
@@ -75,10 +88,13 @@ EOF
for f in wpa_cli hciconfig bluetoothctl ip; do chmod +x "$T/$f"; done
mkdir -p "$T/logs" "$T/pid"
# 期2:DNS 禁用(宿主无 root 不绑 53),观测层经 MEOW_TCP/UDP 打桩;amsd/svcd 缺省(实体归因走 proc:comm→unknown)。
ENVS="MEOW_NET_DIR=$NET MEOW_NETDEV=$T/netdev MEOW_NET_ROUTE=$T/route MEOW_RESOLV=$T/resolv
MEOW_RFKILL_DIR=$RF MEOW_BT_DIR=$BT MEOW_BOOT_MODE=$T/boot_mode MEOW_BOOTTS_CACHE=$T/bootts
MEOW_IP=$T/ip MEOW_WPA_CLI=$T/wpa_cli MEOW_HCICONFIG=$T/hciconfig MEOW_BLUETOOTHCTL=$T/bluetoothctl
MEOW_NET_SOCK=$T/net.sock MEOW_NET_POLL_SEC=1 MEOW_LOG_DIR=$T/logs"
MEOW_NET_SOCK=$T/net.sock MEOW_NET_POLL_SEC=1 MEOW_LOG_DIR=$T/logs
MEOW_TCP=$T/tcp MEOW_UDP=$T/udp MEOW_NET_POLICY=$T/policy
MEOW_AMS_SOCK=$T/no_ams MEOW_SVCD_SOCK=$T/no_svcd MEOW_DNS_DISABLE=1"
ln -sf "$(readlink -f "$BIN")" "$T/meow_net" # argv[0] 双形态 → CLI
# ---- T0: 守护起 ----
@@ -159,6 +175,95 @@ ck T9a "usage: meow_net" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_net" bogus 2>&1); RC=$?
ck T9b "usage: meow_net" "$OUT"
# ---- 重启 daemon A(T8 已停)供期2 观测/连接表/日志测试 ----
env $ENVS $Q "$BIN" --sock "$T/net.sock" >"$T/daemon2.log" 2>&1 &
DPID=$!
for i in $(seq 1 30); do [ -S "$T/net.sock" ] && break; sleep 0.2; done
[ -S "$T/net.sock" ] || { echo "FAIL T10-pre: daemon 未重启"; cat "$T/daemon2.log"; exit 1; }
# ---- T10: 期2 conns(读级;观测层经 MEOW_TCP/UDP 桩 + amsd/svcd 缺省 → proc:unknown 归因)----
sleep 1 # 等守护普查一拍
OUT=$(env $ENVS $Q "$T/meow_net" conns 2>&1)
ck T10a "proc:unknown" "$OUT"
ck T10b "10.78.193.50:20791" "$OUT"
ck T10b2 "140.205.5.9:443" "$OUT"
ck T10c "ESTAB" "$OUT"
ck T10d "UDP" "$OUT"
ck T10e "connection" "$OUT"
# ---- T11: apps(实体聚合)----
OUT=$(env $ENVS $Q "$T/meow_net" apps 2>&1)
ck T11a "entity" "$OUT"
ck T11b "proc:unknown" "$OUT"
# ---- T12: dns status/stats(DNS 禁用 → 显示 disabled)----
OUT=$(env $ENVS $Q "$T/meow_net" dns status 2>&1)
ck T12a "proxy disabled" "$OUT"
OUT=$(env $ENVS $Q "$T/meow_net" dns stats 2>&1)
ck T12b "proxy disabled" "$OUT"
# ---- T13: dns flush(写级;宿主 CLI=CALL_OTHER → 拒)----
OUT=$(env $ENVS $Q "$T/meow_net" dns flush 2>&1)
ck T13a "permission denied" "$OUT"
# ---- T14: DNS 代理 wire 实测(守护 B:高端口 + 桩上游 + 全局 deny;测 deny/forward/cache)----
HOSTIP=$(hostname -I 2>/dev/null | awk '{print $1}')
[ -n "$HOSTIP" ] || HOSTIP="127.0.0.1"
cat > "$T/policy_dns" <<'EOF'
global domain=-ads.example.com
EOF
printf 'nameserver %s\n' "$HOSTIP" > "$T/resolv_dns"
cat > "$T/dns_test.py" <<'PYEOF'
import socket, struct, threading, sys, os
UP_IP = os.environ.get("T_UP_IP", "0.0.0.0")
up = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
up.bind((UP_IP, 5311)) # 0.0.0.0 通配,绑到宿主自身 IP
up.settimeout(6)
def serve():
try:
while True:
d,a = up.recvfrom(1536)
off=12
while d[off]!=0: off += 1+d[off]
off += 1+4
qsec = d[12:off]
resp = d[:2] + b'\x81\x80' + b'\x00\x01\x00\x01\x00\x00\x00\x00' + qsec
resp += b'\xc0\x0c' + b'\x00\x01\x00\x01' + struct.pack('>I',60) + b'\x00\x04' + socket.inet_aton('11.22.33.44')
up.sendto(resp, a)
except Exception:
pass
threading.Thread(target=serve, daemon=True).start()
def query(name):
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM); s.settimeout(3)
hdr=b'\x12\x34'+b'\x01\x00'+b'\x00\x01\x00\x00\x00\x00\x00\x00'
q=b''.join(bytes([len(l)])+l.encode() for l in name.split('.'))+b'\x00'+b'\x00\x01\x00\x01'
s.sendto(hdr+q, ("127.0.0.1", 5300))
r,_=s.recvfrom(1536); rco=r[3]&0xf; an=struct.unpack('>H',r[6:8])[0]
return rco,an
try:
d1,a1 = query("ads.example.com") # deny → NXDOMAIN (rcode 3)
d2,a2 = query("music.163.com") # allow → forward → A 11.22.33.44
sys.stdout.write("DENY_RCODE=%d\nALLOW_AN=%d\n" % (d1, a2))
except Exception as e:
sys.stdout.write("ERR=%s\n" % e)
PYEOF
# 追加式覆写(env 左→右,后者胜出):DNS 启用、换独立 socket/resolv/policy、上游端口。
DNSENV="$ENVS MEOW_DNS_DISABLE=0 MEOW_NET_SOCK=$T/dns.sock MEOW_RESOLV=$T/resolv_dns
MEOW_NET_POLICY=$T/policy_dns MEOW_DNS_PORT=5300 MEOW_DNS_UPSTREAM_PORT=5311"
ln -sf "$(readlink -f "$BIN")" "$T/dns_netmgrd"
env $DNSENV $Q "$BIN" --sock "$T/dns.sock" >"$T/dnsd.log" 2>&1 &
D2PID=$!
for i in $(seq 1 30); do [ -S "$T/dns.sock" ] && break; sleep 0.2; done
sleep 1
OUT=$(env $DNSENV $Q "$T/meow_net" dns status 2>&1)
ck T14a "enabled=1 upstream=$HOSTIP" "$OUT"
WIRE=$(python3 "$T/dns_test.py" 2>&1)
ck T14b "DENY_RCODE=3" "$WIRE"
ck T14c "ALLOW_AN=1" "$WIRE"
OUT=$(env $DNSENV $Q "$T/meow_net" dns stats 2>&1)
ck T14d "q=2" "$OUT"
ck T14e "deny=1" "$OUT"
kill $D2PID 2>/dev/null; wait $D2PID 2>/dev/null
# 恢复守护 A 的 MEOW_RESOLV(其未被 DNS 触碰,此处确认)
grep -q "nameserver 223.5.5.5" "$T/resolv" && { PASS=$((PASS+1)); echo "PASS T14f daemonA resolv untouched"; } || { FAIL=$((FAIL+1)); echo "FAIL T14f daemonA resolv touched"; }
echo "=============================="
echo "PASS=$PASS FAIL=$FAIL"
[ $FAIL -eq 0 ]