# Minecraft 分析器 识别 Minecraft Java 版客户端在连接建立后发出的第一个数据包(Handshake,packet ID `0x00`),从中取出客户端请求的服务器地址、协议版本和后续状态。基岩版走 UDP/RakNet,不在本分析器范围内。 分析器名是 `minecraft`。和其他分析器一样,**只有当某条规则的表达式里出现了 `minecraft` 这个标识符时,它才会被启用**(见 `ruleset/expr.go` 的依赖收集逻辑),不写规则就不会有任何开销。 ## 属性 | 属性 | 类型 | 说明 | | --- | --- | --- | | `yes` | bool | 确认是 Minecraft 握手 | | `candidate` | bool | 数据还不完整,暂时无法判定,仍在等待后续分段 | | `protocol` | int | 协议版本号,**不是游戏版本号**,对照表见 [minecraft.wiki](https://minecraft.wiki/w/Protocol_version)(例如 767 对应 1.21) | | `server_addr` | string | 客户端在握手包里填写的服务器地址 | | `server_port` | uint16 | 客户端填写的端口 | | `next_state` | int | 1 = status,2 = login,3 = transfer | | `next_state_name` | string | 上面的可读形式:`status` / `login` / `transfer` | | `packet_length` | int | 握手包声明的长度(不含长度字段自身) | `yes` 和 `candidate` 一定存在,其余字段只在 `yes` 为 true 时出现。 ## 规则示例 只拦截真正进服的连接,放过服务器列表里的 ping: ```yaml - name: block-minecraft-login action: block log: true expr: minecraft != nil && minecraft.yes && minecraft.next_state_name == "login" ``` 只允许连接指定的服务器,其余一律拦截: ```yaml - name: minecraft-allowlist action: block expr: > minecraft != nil && minecraft.yes && !hasPrefix(minecraft.server_addr, "mc.example.com") ``` 按协议版本卡老客户端: ```yaml - name: block-old-minecraft-clients action: block expr: minecraft != nil && minecraft.yes && minecraft.protocol < 763 ``` 纯记录不拦截,先摸清楚流量情况: ```yaml - name: log-minecraft log: true expr: minecraft != nil && minecraft.yes ``` ## 写规则时要注意的几点 **`server_addr` 不一定是干净的域名。** 握手包里的地址字段被生态里几个东西复用了,客户端可能在真实域名后面追加以 `\0` 分隔的内容:Forge/FML 客户端会加 `\0FML\0`、`\0FML2\0`、`\0FML3\0` 之类的标记,BungeeCord 和 Velocity 的 IP 转发会把玩家真实 IP 和 UUID 拼在后面。分析器保存的是原始字节,不做任何清洗。所以不要用 `==` 精确比较,用 `hasPrefix(minecraft.server_addr, ...)`,或者先 `split(minecraft.server_addr, "\x00")[0]` 再比。 **这个字段是客户端自己填的,不可信。** 它反映客户端想连哪个域名(对 SRV 记录的情况是解析前的原始主机名),不是它实际连到的 IP。要认真限制目标,得配合 `ip.dst` 一起写。 **判定发生在第一个数据包。** 握手之后的登录、加密、游戏数据都不会再看。`Limit()` 是 2053 字节,正常握手包只有几十字节,绰绰有余;超过这个量还没解析成功的连接会被判为非 Minecraft。 **握手包被拆到多个 TCP 分段时也能正确解析。** 分析器内部有缓冲区,数据不够时返回 `candidate = true` 并继续等待,不会像只看单个分段的分析器那样被切包绕过。相关背景见 [TCP 窗口操纵规避](tcp-window-evasion.zh.md)。