Files
Su YijunandClaude Opus 5.5 49b379626a v0.5.0:审计参照深信服 AC、家用 / 企业场景、通知参照 EasySub(debug10)
人员与场景
- 人员 / 家庭成员、部门 / 分组,设备归属,按人统计流量、在线时长、常用应用
- 家用:屏幕时间、游戏、短视频上限,熬夜,不良内容,学习时间玩娱乐;企业:工作时间娱乐占比、求职倾向、上班炒股
- 行为洞察(最近 7 天标签附依据)、效率 / 时长排行
- 终端类型识别:主机名、IEEE OUI 厂商、用过的应用、随机 MAC;可手动指定

审计
- 访问日志、时间线、报表按人员 / 部门;规则范围可选人员、部门
- 新规则:大流量外发、私接路由(IP TTL);私接检测页
- RouterOS 管控命令生成(封禁应用、定时断网、限速,附撤销),不写路由器
- Syslog 外发(RFC 5424);网页设置留存天数,显示数据库占用

通知(参照 EasySub)
- 13 种渠道,磁贴选择,可用未保存配置测试,密钥遮盖,旧配置自动迁移
- 规则可选渠道;免打扰期间先记下,结束后汇总推送

界面
- 应用统计大类、小类固定列出,矩形树图;访问目标世界地图与国家分布
- 时间范围只保留 今日 / 昨日 / 本周 / 本月;上下行颜色全站统一

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:53:57 +08:00

50 lines
2.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""私接路由 / 共享上网检测(参照深信服 AC 的“防共享上网”,只用镜像包里的 IP TTL 做被动判断)。
系统发出的包 TTL 初始值一般是 64(Linux、安卓、苹果)、128(Windows)或 255。每经过一个路由器减 1。
ROS-DPI 看到的是路由器镜像过来的包(forward 链,路由器自己已减过 1),所以正常设备一般是 63 / 127。
- 某台“设备”的包比全网常见的跳数还多一跳:它后面很可能接了路由器(私接路由、随身 WiFi、软路由)。
- 同一台“设备”同时出现两种系统的 TTL:后面可能有多台不同系统的设备在共享。
只作为提示:样本是 HTTPS / QUIC 握手和 DNS 之外的首包,数量有限;VPN、虚拟机、容器也可能造成同样的现象。
"""
from collections import Counter
BASES = (64, 128, 255)
MIN_PACKETS = 5
def hops(ttl: int) -> tuple[int, int]:
"""(初始值, 已经过的跳数)"""
base = next(b for b in BASES if b >= ttl)
return base, base - ttl
def suspects(ttl_by_host: dict[str, Counter]) -> tuple[int, list[dict]]:
"""返回 (全网常见跳数, 可疑终端列表)"""
usual = Counter()
for c in ttl_by_host.values():
if sum(c.values()) >= MIN_PACKETS:
usual[hops(c.most_common(1)[0][0])[1]] += 1
base_hops = usual.most_common(1)[0][0] if usual else 1
out = []
for host, c in ttl_by_host.items():
n = sum(c.values())
if n < MIN_PACKETS:
continue
by_os: Counter = Counter()
extra = 0
for ttl, k in c.items():
b, h = hops(ttl)
by_os[b] += k
if h > base_hops:
extra += k
reasons = []
if extra >= max(3, n * 0.3):
reasons.append("extra_hop")
if sum(1 for b, k in by_os.items() if k >= 3 and k >= n * 0.1) >= 2:
reasons.append("multi_os")
if reasons:
out.append({"host": host, "packets": n, "ttls": dict(c.most_common(6)), "reasons": reasons,
"extra_share": extra / n, "os": sorted(b for b, k in by_os.items() if k >= 3)})
out.sort(key=lambda x: (-len(x["reasons"]), -x["extra_share"]))
return base_hops, out