-- ITEM6 B0 存量普查(只读计数版) -- 用途:为第 6 条 sing-box 迁移的 N1-N10 风险项取得现网确切存量数字。 -- 纪律:全部语句只输出计数/分组计数,不输出任何设置内容、凭据、地址。 -- 跑法(在 HW-SG 上,对现网库的副本跑,不要直连生产文件): -- cp /etc/x-ui/x-ui.db /tmp/census.db -- sqlite3 /tmp/census.db < census.sql > census-out.txt -- 把 census-out.txt 整份贴回即可。 -- -- 防御式 JSON 读法:所有 json_extract 都套 -- case when json_valid(列) then 列 end -- 存量里存在 stream_settings='' 的行(备份库实证),裸 json_extract 会 -- 报 malformed JSON 中断整份脚本;套上后非法/空 JSON 一律按"无此字段"计。 -- 若某条报 "no such table"(如老库无 agent_nodes),把该条结果记为 -- 「表不存在」贴回,不要中断其余条目。 .mode list .headers off -- Q00 入站总量与启用分布 select 'Q00_total_inbounds', count(*) from inbounds; select 'Q00_enabled', count(*) from inbounds where enable; -- Q01 各协议入站数(ITEM6-SCOPE §4.1 全协议面) select 'Q01_protocol', protocol, count(*) from inbounds group by protocol order by count(*) desc; -- Q02 传输分布(stream_settings.network;空串/无 stream 的单列) select 'Q02_network', coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.network'), '(none)') as net, count(*) from inbounds group by net order by count(*) desc; -- Q03 安全层分布 select 'Q03_security', coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security'), '(none)') as sec, count(*) from inbounds group by sec order by count(*) desc; -- Q04 N8: xhttp 存量 select 'Q04_xhttp', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.network') = 'xhttp'; -- Q05 N8: kcp(mKCP) 存量 select 'Q05_kcp', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.network') = 'kcp'; -- Q06 N6: Shadowsocks method 分组(sing-box 已移除 cfb/ctr 类须单列) select 'Q06_ss_method', coalesce(json_extract(case when json_valid(settings) then settings end, '$.method'), '(missing)') as method, count(*) from inbounds where protocol = 'shadowsocks' group by method order by count(*) desc; -- Q07 Hysteria 版本分组(v1/v2 分发两个 sing-box type) select 'Q07_hysteria_version', coalesce(cast(json_extract(case when json_valid(settings) then settings end, '$.version') as text), '(missing)') as ver, count(*) from inbounds where protocol = 'hysteria' group by ver; -- Q08 N5: trojan 客户带 flow 的入站数 select 'Q08_trojan_flow_inbounds', count(*) from inbounds i where i.protocol = 'trojan' and exists ( select 1 from json_each(case when json_valid(i.settings) then json_extract(i.settings, '$.clients') end) je where coalesce(json_extract(je.value, '$.flow'), '') <> ''); -- Q09 vless flow 分布(vision / udp443 待归一 / 无 flow 三档,按入站计) select 'Q09_vless_flow_vision', count(*) from inbounds i where i.protocol = 'vless' and exists ( select 1 from json_each(case when json_valid(i.settings) then json_extract(i.settings, '$.clients') end) je where json_extract(je.value, '$.flow') = 'xtls-rprx-vision'); select 'Q09_vless_flow_udp443', count(*) from inbounds i where i.protocol = 'vless' and exists ( select 1 from json_each(case when json_valid(i.settings) then json_extract(i.settings, '$.clients') end) je where json_extract(je.value, '$.flow') = 'xtls-rprx-vision-udp443'); -- Q10 N3: vlessenc(settings.decryption 非 none)在用入站数 select 'Q10_vlessenc', count(*) from inbounds where protocol = 'vless' and coalesce(json_extract(case when json_valid(settings) then settings end, '$.decryption'), 'none') not in ('', 'none'); -- Q11 N4: vless 客户带 reverse 的入站数 select 'Q11_vless_reverse_inbounds', count(*) from inbounds i where i.protocol = 'vless' and exists ( select 1 from json_each(case when json_valid(i.settings) then json_extract(i.settings, '$.clients') end) je where json_extract(je.value, '$.reverse') is not null); -- Q12 N1: fallbacks 存量(表形态 + settings 内嵌形态,两处都要) select 'Q12_fallback_rows', count(*) from inbound_fallbacks; select 'Q12_fallback_masters', count(distinct master_id) from inbound_fallbacks; select 'Q12_fallback_children', count(distinct child_id) from inbound_fallbacks; select 'Q12_fallback_embedded', count(*) from inbounds where json_type(case when json_valid(settings) then settings end, '$.fallbacks') = 'array' and json_array_length(case when json_valid(settings) then settings end, '$.fallbacks') > 0; -- Q13 N9: finalmask 存量(入站 stream 级 + hosts 覆写级) select 'Q13_finalmask_inbounds', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.finalmask') is not null; select 'Q13_finalmask_salamander', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.finalmask') is not null and stream_settings like '%salamander%'; select 'Q13_finalmask_hosts', count(*) from hosts where coalesce(final_mask, '') <> ''; -- Q14 N10: Reality 高级字段在用计数(只数"设了的行数",不出值) select 'Q14_reality_total', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality'; select 'Q14_reality_xver_nonzero', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.xver'), 0) <> 0; select 'Q14_reality_mldsa65seed', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.mldsa65Seed'), '') <> ''; select 'Q14_reality_mldsa65verify', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.settings.mldsa65Verify'), '') <> ''; select 'Q14_reality_minclientver', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.minClientVer'), '') <> ''; select 'Q14_reality_maxclientver', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.maxClientVer'), '') <> ''; select 'Q14_reality_maxtimediff', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.maxTimediff'), 0) <> 0; select 'Q14_reality_limitfallback', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and (json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.limitFallbackUpload') is not null or json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.limitFallbackDownload') is not null); select 'Q14_reality_masterkeylog', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.masterKeyLog'), '') <> ''; select 'Q14_reality_show_on', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.security') = 'reality' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.realitySettings.show'), 0) <> 0; -- Q15 sockopt 存量(入站 stream 级 + hosts 覆写级) select 'Q15_sockopt_inbounds', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.sockopt') is not null; select 'Q15_sockopt_hosts', count(*) from hosts where coalesce(sockopt_params, '') <> ''; -- Q16 sniffing:启用数、destOverride 分组、fakedns 在用数 select 'Q16_sniff_enabled', count(*) from inbounds where coalesce(json_extract(case when json_valid(sniffing) then sniffing end, '$.enabled'), 0) <> 0; select 'Q16_sniff_destoverride', coalesce(json_extract(case when json_valid(sniffing) then sniffing end, '$.destOverride'), '(none)') as dest, count(*) from inbounds group by dest order by count(*) desc; select 'Q16_sniff_fakedns', count(*) from inbounds where sniffing like '%fakedns%'; -- Q17 Q4: agent 出口覆盖填写数(agent_nodes.outbounds / routing_rules 非空行数) select 'Q17_agent_nodes', count(*) from agent_nodes; select 'Q17_agent_outbounds_set', count(*) from agent_nodes where coalesce(trim(outbounds), '') <> ''; select 'Q17_agent_routing_set', count(*) from agent_nodes where coalesce(trim(routing_rules), '') <> ''; -- Q18 N2/Q5: tun / tunnel 入站(本地 node_id 为空 vs 挂 agent 分开计) select 'Q18_local_protocols', protocol, count(*) from inbounds where protocol in ('tun', 'tunnel') group by protocol; select 'Q18_tun_tunnel_on_agent', count(*) from inbounds where protocol in ('tun', 'tunnel') and node_id is not null and node_id <> 0; -- Q19 杂项小损项存量:SS ivCheck / HTTP allowTransparent / gRPC multiMode select 'Q19_ss_ivcheck_on', count(*) from inbounds where protocol = 'shadowsocks' and coalesce(json_extract(case when json_valid(settings) then settings end, '$.ivCheck'), 0) <> 0; select 'Q19_http_transparent_on', count(*) from inbounds where protocol = 'http' and coalesce(json_extract(case when json_valid(settings) then settings end, '$.allowTransparent'), 0) <> 0; select 'Q19_grpc_multimode_on', count(*) from inbounds where json_extract(case when json_valid(stream_settings) then stream_settings end, '$.network') = 'grpc' and coalesce(json_extract(case when json_valid(stream_settings) then stream_settings end, '$.grpcSettings.multiMode'), 0) <> 0; -- Q20 模板键体量(只出长度,语义 diff 由 B1 迁移报告做) select 'Q20_template_len', length(value) from settings where key = 'xrayTemplateConfig'; -- Q21 P9 转发启用数(inbounds.forwarding 非空且 mode=forward 的行数) select 'Q21_forwarding_on', count(*) from inbounds where coalesce(forwarding, '') <> '' and coalesce(json_extract(case when json_valid(forwarding) then forwarding end, '$.mode'), '') = 'forward';