Sonar——可能是目前最好的反假人解决方案

前言

其实大多时候并不缺好用的插件,只是人们不了解好插件的存在。

所以我写了这篇文章,用于分享一下我的开服经验,最主要的是介绍一些我觉得很好用的插件,以后可能会成为一个系列也说不定。

Sonar

介绍

这是一款反作弊类型的插件,可以阻止绝大多数的假人(bot)进入你的服务器。

注:这里的假人并不是生电概念上的假人,而是指使用某些软件直接向服务器发送大量数据包来制造假玩家进服,从而对服务器进行攻击。

Sonar 内置多种反假人模式,可以根据服务器实际情况自行选择,我会在下面给出一种我正在用的配置文件。

支持范围

支持平台:Java 版 1.7.2-1.21.8 | 基岩版需要通过 Geyser 才能处理

软件支持:Velocity (3.3.0 build 330或更高) | BungeeCord (1.20或更高) | Paper、Bukkit 和 Spigot (1.8.8或更高)
注意:该插件依赖 Netty 4.1(或更高),这会导致在一些低版本服务器上不可用,你可以参照插件文档来解决这个问题。

下载

下载:SpigotMC | Modrinth | GitHub

官方文档(只有英文)

安装

把插件放进 plugins 文件夹里就行了,可以通过 /sonar reload 来重载插件,所以我们可以直接修改配置文件。

如果你使用群组服架构,你只需要在 Velocity/BungeeCord 上安装即可,无需在其他服务器上安装。

配置文件

插件自带一个汉化过的配置文件,我会贴在下面,并把要改的地方标注出来。

另外,我目前只在 Velocity 上使用这个插件,不过 Paper 上的配置文件应该差不多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# ./sonar/config.yml

# 常规的设置
general:
# Sonar 是否应该自动检查新的更新?
# Sonar 使用 GitHub API 检查当前版本是否过时
check-for-updates: false # <-- 建议关闭,毕竟大多时候根本连不上 Github,不如定期手动检查更新
# Sonar 应该在控制台中打印玩家的 IP 地址吗?
log-player-addresses: true
# 具有相同 IP 地址的在线玩家的最大数量
max-online-per-ip: 3

# 攻击检测器
# 只有当您知道自己在做什么的时候才应该编辑它
attack-tracker:
# 在一段时间内至少需要多少个新玩家加入才满足触发条件?
min-players-for-attack: 8
# 至少经过多少毫秒后才可以解除遭受攻击模式
# (该值为毫秒. 1秒等于1000毫秒.)
min-attack-duration: 30000
# 要重复检测到多少次攻击 才应该被确认为服务器正在遭受攻击?
# 该值作为缓冲区 以避免可能的误判
min-attack-threshold: 2
# 当从遭受攻击状态标记为已缓解攻击状态时
# 至少需要多少毫秒才允许为对于可能检测到的攻击重新进入遭受攻击状态?
# (该值为毫秒. 1秒等于1000毫秒.)
attack-cooldown-delay: 3000

# 您可以让 Sonar 连接到数据库 以便从数据库中保存和读取已经过验证的 IP 和玩家.
# 提示: IP 地址将以纯文本形式保存 请确保您的数据库安全!
database:
# 要连接到的数据库类型
# 可用类型: NONE (不使用数据库), MYSQL, MARIADB, H2 (本地数据库)
type: H2 # <-- H2 足够用了,如果你服务器上有 MySQL 之类的数据库也可以用,不过不如 H2 配置简单
# Sonar 插件目录中用于 H2 数据库的文件
filename: verified_players
# 数据库的地址
host: localhost
# 数据库的端口
port: 3306
# 数据库名称
name: sonar
# 用于登录数据库的用户名
username: ''
# 用于登录数据库的密码
password: ''
# Sonar 应该在数据库中保留在白名单中的玩家最多多少天?
maximum-age: 5

# 在遭到攻击时 每个新玩家的登录请求将排队 以避免大量连接同时进行验证
# 队列将每1秒刷新一次
queue:
# 每秒最多处理多少个登录请求?
max-polls: 30

# 每个需要验证的玩家都将被发送到一个轻量级的虚拟服务器来检查高级机器人
verification:
# Sonar 应该在什么时候验证玩家?
# 可用类型: ALWAYS, DURING_ATTACK
# - ALWAYS: 玩家始终需要验证 直到他们通过验证为止
# - DURING_ATTACK: 玩家仅在服务器疑似遭到攻击时验证
timing: ALWAYS
checks:
# 检查玩家的下落移动是否遵循原版客户端.
gravity:
# Sonar 是否应该检查玩家的下落移动? (推荐启用)
enabled: true
# 当玩家验证失败时 是否向他们发送地图验证码?
captcha-on-fail: false
# 玩家跌落在平台上多少tick后才能被算作站在平台上?
max-movement-ticks: 8

# 检查玩家是否可以正确地站在方块上
collision:
# Sonar 是否应该生成方块平台以检查玩家下落与方块之间的碰撞? (推荐启用)
enabled: true

# 检查客户端坐在实体上时是否发送了正确的数据包
vehicle:
# Sonar 是否应该让玩家坐在实体上, 以便检查他们的数据包是否合法?
enabled: true
# 客户端需要发送的所需的最小数据包数量
minimum-packets: 2

# 手持地图验证码
map-captcha:
# Sonar 应该在什么时候向玩家发送验证码?
# 可用类型: ALWAYS, DURING_ATTACK, NEVER
# - ALWAYS: 始终应用该检查
# - DURING_ATTACK: 仅在疑似遭受攻击时应用该检查
# - NEVER: 永远不应用该检查
timing: NEVER
# 用于当作验证码的背景的图片
# 如果未找到指定的图片, 则自动通过噪音生成一个随机的背景图片.
# 如果图片在该插件的配置文件夹下, 则可以简单地输入图片的文件名.
background: ''
# 地图验证码的风格(默认:'modern').
# 要使用旧设计, 请将其设置为 'legacy'.
style: 'modern'
# Sonar 应该一次准备多少个验证码?
precompute: 500
# Sonar 应该给玩家多少时间完成验证码?
# (该值为毫秒. 1秒等于1000毫秒.)
max-duration: 30000
# 玩家最多能输入多少次错误的验证码?
max-tries: 3
# 允许出现在验证码答案中的字符
# 不建议添加可能看起来彼此相似的数字或字母
alphabet: 'abcdefhjkmnoprstuxyz'

# 检查玩家是否正在向服务器发送有效的客户端标识符
client-brand:
# 是否启用此检查? (建议启用)
enabled: true
# 用于检查客户端标识符的正则表达式
valid-regex: ^[!-~ ]+$
# 客户端标识符的最长长度限制
max-length: 64

# 用于检查用户名是否有效的正则表达式
valid-name-regex: ^[a-zA-Z0-9_]+$

# 开启后 玩家将在验证成功后被重定向到指定的服务器
# 该功能由 Mojang 在 Minecraft 1.20.5 版本中引入
# https://docs.jonesdev.xyz/administration/configuring-sonar/configuring-the-verification/using-1.20.5+-transfers
transfer:
# Sonar 是否应该将玩家重定向到指定的服务器而不是踢出玩家?
# 为此您必须在服务器软件的配置文件中允许接受来自transfer的连接.
# 此外 您可能希望减少 Velocity 或其它服务器软件/插件的登录速率限制
# 因为这可能会阻止玩家快速地重新连接到服务器
# 如果你的服务器允许 Bedrock 玩家通过 Geyser 加入, 请确保为 Geyser 设置了
# TransferTool 扩展, 以便将 Bedrock 玩家重定向到正确的服务器.
# https://github.com/onebeastchris/TransferTool
enabled: false # <-- 建议启用,可以让玩家直接切换到服务器里,无需玩家重新连接
# 当玩家通过验证后, Sonar 应该将玩家转移到哪个服务器
# 请输入玩家正常连接服务器时使用的服务器IP或域名
# 例如使用域名("mc.hypixel.net") 或使用 IP 地址("1.1.1.1").
destination-host: "play.my-server.com" # <-- 记得改成你服务器的 IP/域名
# Sonar 应该告诉玩家通过以上域名的什么端口来连接到服务器?
# 如果服务器地址不包含端口 请保留25565.
destination-port: 25565 # <-- 当然也别忘了改端口

# 玩家正在验证时所使用的游戏模式
# 可用类型: SURVIVAL, CREATIVE, ADVENTURE
# - SURVIVAL: 生存模式, 所有UI可见
# - CREATIVE: 创造模式, 隐藏血量和饱食度
# - ADVENTURE: 冒险模式, 所有UI可见
gamemode: ADVENTURE
# 验证过程中玩家所看到的当前世界中的一天时间
# 您可以在这里找到您想要的时间:
# https://minecraft.wiki/w/Daylight_cycle
# 该选项不会改变验证过程.
# 如果该值设置为 1000, 则不会发送数据包.
time-of-day: 1000
# Sonar 缓存它发送到客户端的大部分数据包, 包括 LoginSuccess 数据包.
# Sonar 应该使用哪个用户名来接收 LoginSuccess 数据包?
# 如果不修改客户端, 用户名将不会对玩家可见
cached-username: "Sonar"
# 当 Sonar 尝试验证玩家时 是否在控制台中打印有关玩家的信息?
log-connections: true
# Sonar 是否应该在攻击期间内打印日志?
log-during-attack: false
# Sonar 是否应该记录验证过程中玩家的移动位置的变化?
# 有助于发现错误 但不建议在生产环境下的服务器启用该选项.
debug-xyz-positions: false
# Sonar 是否应该检查来自 Geyser 的(基岩版)玩家?
# 此功能是实验性的. 请报告任何因为误判而导致无法通过检查的问题
# 如果关闭该选项 Sonar 将不检查这些玩家以便直接连接到服务器.
check-geyser-players: false
# 播放器断开连接前停止发送数据包的时间
# (该值为毫秒. 1秒等于1000毫秒.)
read-timeout: 8000
# 服务器在断开玩家连接前停止发送数据包的时间
# (该值为毫秒. 1秒等于1000毫秒.)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# 当玩家在还未通过检查的情况下断开连接后需要等待多少毫秒才可以重新连接?
# (该值为毫秒. 1秒等于1000毫秒.)
rejoin-delay: 5000
# 当玩家验证失败后, Sonar 应该记住他多久?
# (该值为毫秒. 1秒等于1000毫秒.)
remember-time: 120000
# 黑名单应在多少秒后过期? (可能由于频繁验证失败. 在黑名单中将会被拒绝进入服务器.)
# (该值为毫秒. 1秒等于1000毫秒.)
blacklist-time: 600000
# 玩家必须验证失败多少次才会被列入黑名单? (设置为0以完全禁用)
blacklist-threshold: 2
# 黑名单中的协议将阻止所有使用该协议的客户端.
# 您可以在 https://wiki.vg/Protocol_version_numbers 找到所有协议号
# 例如 Minecraft 1.20 对应的协议号为763.
blacklisted-protocols: []

原理

插件模拟了一个假的服务器用于给客户端发包(别的啥也干不了),通过测试客户端行为与分析客户端发回的数据包来判断连入的玩家是不是机器人。

因为玩家首先连入的是 Sonar 模拟的假服务器,所以需要配置 transfer 来将玩家转移到真正的服务器。

备注

Sonar 的官网在这里

目前比较流行的 Sonar 版本是 2.x,而官网上正在售卖 Sonar 3.x,Sonar 3 包括云端检测,但它是付费的。

我仍建议你使用免费的 Sonar 2,毕竟对于大多数中小型服务器,免费版就足够用了。

内网穿透后让 Velocity 获取玩家真实 IP 的方法

由于本土运营商对公网 IP 管控十分严格,有不少 Minecraft 服主会选择使用内网穿透服务来开设服务器。

但是以这种网络结构开设的服务器有一个问题,服务端无法拿到玩家的真实 IP(内网穿透会导致玩家的 IP 都变成 127.0.0.1)。

这会导致部分涉及处理玩家 IP 的功能完全无法使用,比如某些管理插件提供的 /banip IP 封禁功能,因为所有玩家的 IP 都是一样的,执行这个指令后会导致所有玩家都会被封禁。

本文将为有这类困扰的服主提供解决方案。

Case:1 纯代理线路入服

配置 frpc

在 frpc 配置文件中添加下面一行:

1
2
3
4
5
# .\frpc.toml

[[proxies]]
... # 省略隧道的其他信息,不要复制这一行
transport.proxyProtocolVersion = "v2" # 在已有隧道添加这一行即可

修改完需要重启 frpc 后才会生效。

如果你使用的是 SakuraFrp(比如我),可以看此处的文档

配置 velocity.toml

在 Velocity 的配置文件中,启用如下配置项。

1
2
3
4
# .\velocity.toml

[advanced]
haproxy-protocol = true

重启 Velocity 后,配置项即生效。

Case:2 直连与代理并用

经过 Case:1 对服务器进行设置后,你会发现直连线路无法访问。为了解决这个问题,我们需要请出接下来的妙妙工具。

HAProxyReduce,是 HAProxyDetector 的替代品,支持 Paper/Folia/Velocity。

把它放进 Velocity 工作目录下的 plugins 文件夹就行了。

安装好插件后,先启动一下 Velocity,让插件把默认配置文件吐出来,然后关掉代理端,我们需要调整一下插件配置。

进入 /plugins/haproxy-reduce,打开 whitelist.conf

1
2
3
4
5
# ./whitelist.conf

127.0.0.0/8 # 默认配置
::1/128 # 默认配置
example.com # 在这里写上玩家连接服务器要用的那个域名就行了,不用写端口号,没域名就写 IP 地址

其他类型的服务端开启 HAproxy 的方法

正在使用 BungeeCord/Waterfall、Paper 及其分支、Geyser 的话,请看这篇文档

如果你使用的是 Spigot,请继续使用 HAProxyDetector,你可以在这里找到中文的使用方法

如果你正在使用较新的 Paper及其分支或 Velocity,换成HAProxyReduce

自检用 frp 搭建教程

材料(大嘘):

  • 服务端:Windows Server 2022 (21H2) | 有公网 | 位于上海某处
  • 客户端:Debian 12 | 有公网 | 位于天津某处
  • frp 版本:v0.64.0

目标:搭建一条用于某 Minecraft 服务器的加速线路。

Step1 下载 frp

最近在网上搜到某个冒充 frp 官方文档的使用 WordPress 搭建的网站,请认准真正的官方文档

先在此处下载构建好的二进制包,记得看好操作系统和 CPU 架构,如果你找不到的话,记得点下“Show all assets”展开。

另外特别提醒,不要搞混 amd64arm64 !!!

Step2 安装 frps

由于我使用的服务端是 Windows 操作系统,以下内容仅针对 Windows,你可以在这里找到在 Linux 系统上部署 frps 的教程。

随便找个自己喜欢的文件夹,把压缩包里的“frps.exe”和“frps.toml”解压到这个文件夹里。

frps 的默认端口是 7000,如果你需要改到其他端口,可以修改 frps.toml。

1
2
3
4
# .\frps.toml
bindPort = 11451 # 此处可以换成任意合法的端口号,注意不要开在已经被占用的端口上

auth.token = "foo" # 密钥,防止被陌生人滥用,建议设置的复杂点

接下来,在文件夹窗口按住 Shift 键右键空白处,点击“在此处打开 PowerShell 窗口”。

在 PowerShell 中,输入 .\frps.exe -c .\frps.toml ,即可启动 fprs。

顺便一提,别忘了给 frps 开放必要的端口(比如防火墙、路由器端口转发等)。

Step2.1 使用 MCSManager 管理 frps

这一步非必需,你也可以用自己的方法管理 frps。

如果你正好部署过 MCSManager,那么恭喜你,你获得了一个可以远程管理+自动启动 frps 的工具。

当然,部署 MCSManager 的方法这里不再赘述,去看官方文档

首先,在 MCSManager Web(以下简称面板)上新建应用,选择直接创建,选择服务器(如果有),然后填写一下名称和启动命令(上面有,就是在 PowerShell 里输的那条),设置好后就可以创建实例了。

不过别着急,我们还需要设置一下才能用。打开你刚创建的实例,在“应用实例设置 -> 高级设置”里,把工作目录改成 frps 所在文件夹,记得点保存。

然后,在“事件任务”里,按需勾选“自动重启”和“自动启动”,记得点保存。

最后点一下右上角那个绿色的启动按钮,测试一下是否正常。如果没有报错,那么恭喜你,frps on mcsm 已成功部署。

Step3 安装 frpc

因为我这里的客户端是 Linux 系统,所以我需要重新下载一个适用于 Linux 的二进制包,如果你的客户端还是 Windows,那你可以重复使用刚才下载的压缩包。

随便找个能把文件上传到服务器的软件,把压缩包里的“frpc”和“frpc.toml”解压到合适的文件夹里,我这里把工作目录选在了 /opt/frpc

上传好文件后,开始修改 fprc 的配置文件。

1
2
3
4
5
6
7
8
9
10
11
# .\frpc.toml
serverAddr = "server.address" # 服务端的公网地址
serverPort = 11451 # 你之前在 frps 设置的那个端口
auth.token = "foo" # 你在 frps 上设置的那个密钥

[[proxies]]
name = "Minecraft" # 隧道名称
type = "tcp" # 连接类型,对于 Java 版,选 TCP 就行
localIP = "127.0.0.1" # 服务器 IP,如果服务器在同一台机器的话就写“127.0.0.1”
localPort = 23300 # 服务器端口,跟 server.properties 里的 server-port 写一样的就行
remotePort = 23303 # 设置服务端那边的端口,希望你还记得要在防火墙开放端口

设置好后,就可以使用这个命令 ./frpc -c ./frpc.toml 启动 frpc 了。

如果启动不了的话,别忘了检查 frpc 的执行权限。可以用 sudo chmod 755 /opt/frpc/frpc 来赋予权限(记得换成你自己的路径)。

记得测试一下隧道能否连通,一般来说连接地址应该是 serverAddr:remotePort。

Step3.1 使用 MCSManager 管理 frpc

实际上和用 MCSManager 管理 fprs 的步骤差不多。

在面板上新建应用,选择直接创建,选择服务器(如果有),然后填写一下名称和启动命令,设置好后就可以创建实例了。

别着急,我们还需要设置一下才能用。前往你刚创建的实例,在“应用实例设置 -> 高级设置”里,把工作目录改成 frpc 所在文件夹,记得点保存。

然后,在“事件任务”里,按需勾选“自动重启”和“自动启动”,记得点保存。

最后点一下右上角那个绿色的启动按钮,测试一下是否正常。如果输出内容如图所示,那么恭喜你,frpc on mcsm 已成功部署。

Intro

这道彩虹的尽头会是什么颜色
会是只属于两人的光波吗

/ 介绍 /

省去无趣的自我介绍吧,欢迎来到专属于我的树洞!

/ 近况 /

目前正在试着学习 GodotPython (Godot 使用的 GDScript 语法像它,所以我觉得一起学也可以)。

目标是做一款好玩的独立游戏,没有任何原因,因为我想这么干。

选择 Godot 的原因是很多同类型游戏也是用这个引擎制作的,我觉得这个选择应该不算坏。

/ 社交账号 /

目前可以公开的情报:

我的 GitHub: Trcmoe
我的爱发电账号:Trcmoe
我的 X(前 Twitter):FelysMiro <- 我很少看这个平台
我的个人群 QQ 群号:1055184287