保护 Unturned 服务器免受 DDoS 攻击

发布于 阅读时间 33 分钟

一台 Unturned 服务器真正需要哪些端口,为什么 27017 从 2021 年起就是多余的,如何限制查询洪水攻击、连接洪水攻击和插件负载,以及攻击到多大规模就只能靠服务器前面的网络过滤。

一台 Unturned 服务器如果在晚上从服务器列表里消失几分钟,同时把所有玩家以超时的方式踢下线,问题很少出在硬件上。多数情况下是有人正在攻击,而且时间恰好选在最热闹的时候。本文先讲您不花额外费用就能自己加固的部分,然后讲这些措施在技术上到哪里为止,最后讲服务器前面的网络里必须发生什么。

本文所有内容针对运行在 Debian 12、Debian 13、Ubuntu 22.04 LTS 或 Ubuntu 24.04 LTS 上的 Unturned 独立服务器(U3DS,SteamCMD 应用编号 1110390)。命令以 root 身份书写,普通用户请在前面加上 sudo。如果攻击正在进行,请先不要改动任何配置,也不要重启服务器:先保存测量数据(第 10 节),攻击结束后这些数据就没有了。

为什么偏偏是 Unturned 服务器被攻击

Unturned 服务器之所以被攻击,是因为它们的地址是公开的,游戏流量走 UDP,而且发起一次攻击既不需要什么本事,也花不了多少钱。这三点在 Unturned 上比在大多数其他游戏上都更突出。

公开的 Unturned 服务器会自己公布它的 IP 地址。它必须这么做,否则谁也找不到它:Steam 服务器浏览器直接向它发起查询,而 unturned-servers.net 或 BattleMetrics 这类第三方列表会以明文列出 IP 地址和端口。unturned-servers.net 按自己的说明每五分钟检查一次,看服务器是否在服务器端口上接受 UDP 连接。对攻击者来说,这不是什么工作量,而是填一张表的事。

再加上玩家群体。Unturned 是免费的,入门门槛等于零,角色扮演项目和生存项目之间为了同一批玩家存在真实的竞争。一个被封禁的玩家、一个心怀不满的前管理员或者一个隔壁项目,根本不需要拿到您服务器的访问权,就能让它一个小时不可用。DDoS 攻击在技术上到底是什么,以及为什么伪造的源地址让它很难追溯,请看文章 什么是 DDoS 攻击?。

真正相关的那些端口

一台 Unturned 服务器正好占用两个连续的 UDP 端口:Commands.dat 中设定的值,以及这个值加一。默认情况下就是 27015 和 27016。Smartly Dressed Games 的官方文档这样描述分工:第一个端口承载服务器列表的查询,第二个端口承载游戏流量。只需设定第一个,第二个会自动得出。

Name 我的 Unturned 服务器
Port 27015
MaxPlayers 24
Map PEI
Mode Normal
Perspective Both
Owner 76561198000000000

Commands.dat 位于 U3DS/Servers/<instance>/Server/Commands.dat。它的格式很特别,也是常见的出错来源:每行一条命令,没有等号,值用一个空格分隔,而且命令区分大小写。以 // 开头的行是注释。

对防火墙来说最重要的一点是:自 2021 年 11 月 21 日发布的 3.21.30.0 版本起,27017 端口不再需要。在那之前,Unturned 服务器需要三个端口,因为 Steam 查询位于游戏端口加二上。这次更新之后,查询与服务器本身共用同一个端口,第三个端口就取消了。尽管如此,路由器教程、主机商的 Wiki 和论坛帖子至今仍然在提 27017。开放 27017 对您已经没有任何好处,它只是纯粹的攻击面。

同样重要的一点:Unturned 没有内置的 RCON 端口。官方文档只有控制台输入和控制台输出,它们可以通过 ICommandInputOutput 接口替换掉。您在 Unturned 服务器上看到的任何远程控制都来自插件,并且会带来一个自己的 TCP 端口。这个端口您必须自己找出来、自己收紧,因为没有人替您把它保护好。

项目 数值(默认) 协议 设置位置
查询端口(Steam A2S,服务器列表) 27015 UDP Commands.dat 中的 Port
游戏端口 27016(Port 加一) UDP 无法单独设置
第三个端口 27017 自 3.21.30.0(2021 年 11 月 21 日)起取消 无 关闭
同一台机器上的第二台服务器 27017,第三台 27019 UDP Port,间距为二
RCON 没有内置端口 仅通过插件使用 TCP 插件配置
绑定地址 所有网络接口 无 Commands.dat 中的 Bind
每名玩家每秒的数据包数 50.0 UDP Max_Packets_Per_Second
允许的最高延迟 750 ms 无 Max_Ping_Milliseconds
每个时间窗口内的加入次数 40.0 秒内 10 次 无 Rate_Limit_Kick_Threshold
等待队列 8 个位置,最多 64 无 Commands.dat 中的 Queue_Size
反作弊 VAC 和 BattlEye,两者都启用 无 VAC_Secure、BattlEye_Secure
Steam 查询的放大系数 5.5(US-CERT TA14-017A) UDP 协议特性
24 名玩家时的正常入站数据包速率 每秒约 1200 个数据包 UDP 24 乘以 50
1 Gbit/s 线路被打满 125 MB/s,64 字节包大小时约为每秒 149 万个数据包 无 线路的物理极限
KernelHost 服务器上过滤过的攻击 473.4 Gbit/s,每秒 4150 万个数据包;112.2 Gbit/s 的 UDP 洪水攻击 UDP 运行中的实测数据

在花钱之前,您自己能做的事

这一节最长,而且是故意的。配置干净的 Unturned 服务器能靠自己扛住小型和中型攻击,无论它放在谁那里。

1. 清点:到底什么在监听

在写下第一条规则之前,先看清楚您的服务器对外提供了什么。不要猜,要查:

ss -lnup
ss -lntp

第一条命令显示正在监听的 UDP socket,第二条显示 TCP socket。要看的是本地地址那一列。0.0.0.0:27015 和 [::]:27015 表示“整个互联网都能访问”,127.0.0.1:3306 表示“仅本机”,不需要防火墙规则。除了游戏之外,这里经常还会出现一个 RCON 插件、一个 Web 面板、一个数据库,以及一台已经没人使用、却还占着 27017 的旧测试服务器。从外面做一次端口扫描,就能看到攻击者眼中的样子,对 Unturned 要明确指定 UDP:

nmap -Pn -sU -p 27000-27050 YOUR.SERVER.IP.ADDRESS
nmap -Pn -p- --min-rate 1000 YOUR.SERVER.IP.ADDRESS

2. 只保留 27015 和 27016 对外开放

Unturned 对外只需要放行两个 UDP 端口。运行游戏本身一个 TCP 端口都不需要:官方文档对这两个端口都明确要求 UDP,而游戏的网络层(Steam Networking Sockets,某次更新之后成为默认)完全通过 UDP 工作。额外放行 TCP 的人,照的是过时的教程。

ufw allow 22/tcp comment 'SSH'
ufw allow 27015/udp comment 'Unturned 查询'
ufw allow 27016/udp comment 'Unturned 游戏'
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
ufw status verbose

顺序很重要,否则您会把自己关在门外。包含自救办法的完整说明见 设置 UFW 防火墙而不把自己关在门外。如果您运行多个实例,请遵守推荐的间距二(27015、27017、27019),并且每个实例只放行它真正占用的那两个端口。

Web 面板、数据库或者 RCON 插件都不该暴露在公网上。请用 ufw allow from 203.0.113.10 to any port 8080 proto tcp 把相应端口限制到您自己的地址,或者通过本机的 SSH 转发 ssh -N -L 8080:127.0.0.1:8080 root@YOUR.SERVER.IP.ADDRESS 访问界面。数据库要绑定到 127.0.0.1。

3. 加固查询端口,又不从服务器列表里消失

查询端口是 Unturned 服务器上最脆弱的一点。服务器通过它回答 A2S_INFO、A2S_PLAYERS 和 A2S_RULES 这些 Steam 查询。把它完全封掉,服务器就会从所有服务器列表里消失,即使它运行得毫无问题。

一次 A2S 回应明显比请求大。US-CERT 在关于 UDP 放大攻击的概览(TA14-017A)中给出 Steam 协议的带宽放大系数为 5.5。具体来说:攻击者用伪造的源地址向别人的游戏服务器发送查询,把大约五倍半的回应引向他真正的目标。这时您的服务器不是受害者,而是打击第三方的放大器。反过来,一次查询洪水攻击就足以让服务器从服务器浏览器里消失,而一个玩家都不会掉线。运营者报告的正是这种情况:服务器在跑,上面的玩家什么都没察觉,但它再也找不到了。

对付小规模的查询洪水攻击,按源地址设上限就有效。正规查询来得很少:Steam 浏览器每显示一次查询一次,状态服务每隔几分钟查询一次。

iptables -I INPUT -p udp --dport 27015 -m hashlimit --hashlimit-name unturned_query --hashlimit-mode srcip --hashlimit-above 10/sec --hashlimit-burst 20 -j DROP
iptables -I INPUT -p udp --dport 27016 -m hashlimit --hashlimit-name unturned_game --hashlimit-mode srcip --hashlimit-above 300/sec --hashlimit-burst 500 -j DROP

第二个数字直接来自游戏本身:Unturned 默认把一名玩家限制在每秒 50 个数据包(Max_Packets_Per_Second)。因此每个源地址每秒 300 个数据包,给单个接入线路留了充足余量,即使同一个地址后面坐着好几名玩家也够。这两个值都是起始值,不是真理。请先在正常运行状态下测一周,否则您会把自己的玩家踢出去。

纯 iptables 规则在重启后就没了。在 Debian 和 Ubuntu 下用 apt-get install -y iptables-persistent 和 netfilter-persistent save 保存。在 UFW 下,这类规则应写进 /etc/ufw/before.rules,否则下一次 ufw reload 时就会消失。

另外还有一个不花钱的习惯:如果您的网站或 Discord 机器人显示在线人数,不要由访客去查询服务器,而是按固定间隔把结果缓存下来。否则一个访问量大的状态页面会变成每个访客一次查询,而不是每个间隔一次查询。

4. 在 Config.json 里设置内置的上限

Unturned 在与 Commands.dat 同一个 Server 文件夹下的 Config.json 中带了一个小节,它对防御的重要性超过名字给人的印象。默认值如下:

"Server": {
    "VAC_Secure": true,
    "BattlEye_Secure": true,
    "Max_Ping_Milliseconds": 750,
    "Timeout_Queue_Seconds": 15.0,
    "Timeout_Game_Seconds": 30.0,
    "Max_Packets_Per_Second": 50.0,
    "Join_Rate_Limit_Window_Seconds": 40.0,
    "Rate_Limit_Kick_Threshold": 10,
    "Use_FakeIP": false
}

Max_Packets_Per_Second 把一名已连接的玩家限制在每秒 50 个数据包。Join_Rate_Limit_Window_Seconds 和 Rate_Limit_Kick_Threshold 会把在 40 秒内超过十次越界的连接踢掉。VAC_Secure 和 BattlEye_Secure 在玩家一侧强制要求这两套反作弊系统,从而把大部分一次性客户端挡在外面。

有一点必须清楚:这些上限只对真正加入或尝试加入的客户端有效。对付伪造源地址的洪水攻击它们没有用,因为那里根本不会建立会话。它们仍然重要,因为它们挡住了最常见的单一情形:一个被改过的客户端,仅靠自己就把服务器压垮。把 Max_Ping_Milliseconds 保持在 750 是合理的;设得更低,网络稍有抖动服务器就会把半局玩家踢出去。

5. 给连接跟踪减压

这一点几乎总被忽视,而它能解释那些看起来像流量型攻击、其实不是的故障。内核也会为 UDP 流量在连接跟踪(conntrack)里建立条目,而在源地址被伪造的情况下,每个新地址都意味着一条新条目。表一满,内核就会不加区分地丢弃数据包:攻击和您的玩家一起被丢出去。这时系统日志里会出现 nf_conntrack: table full, dropping packet。

sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max
dmesg -T | grep -i conntrack

最有效的一步是让 Unturned 的流量根本不被跟踪。游戏自己管理会话,不需要内核里的状态跟踪:

iptables -t raw -A PREROUTING -p udp --dport 27015 -j NOTRACK
iptables -t raw -A PREROUTING -p udp --dport 27016 -j NOTRACK

请注意,这两个端口的放行之后就不能再依赖 ESTABLISHED,RELATED,而必须写成独立的接受规则。只有在这之后,提高 nf_conntrack_max 才有意义。先把表调大的人,只是把问题往后推了几分钟,还为此消耗了内存。

如果数据包到达的速度比服务器进程取走的速度更快,socket 的接收缓冲区还会溢出。在玩家看来这就像丢包,尽管线路是空的:

net.core.rmem_max = 16777216
net.core.rmem_default = 1048576
net.core.netdev_max_backlog = 16384

请把这些值放在 /etc/sysctl.d/ 下,并用 sysctl --system 让它们生效。是否真的需要,内核会告诉您:如果 nstat -az 中的 UdpRcvbufErrors 在上升,或者 ss -lunp 里接收队列长期有积压,那么它们就派得上用场。如果两者都一直是零,这项调整不会带来任何变化。这是余量,不是防护。

6. 连接洪水攻击、等待队列和白名单

连接洪水攻击是指攻击者利用正规的加入途径去耗掉槽位和计算时间,而不是去填满线路。Unturned 为此自带四个工具,它们都写在 Commands.dat 里:

  • Queue_Size 32 设定等待队列。默认是 8 个位置,最大 64。队列太大会帮到攻击者,太小则会在每次重启时把真实玩家挤掉。
  • Whitelisted 把服务器切换到白名单模式。通过控制台用 permit <SteamID64> 添加,用 unpermit <SteamID64> 移除。
  • Password YourPassword 把只是从某个列表里拿到地址的人全部排除在外。
  • Filter 拒绝名字里含有不允许字符的玩家,MaxPlayers 24 把槽位数量保持在硬件真正扛得住的水平。

白名单保护的是您的游戏逻辑,不是您的线路。向您服务器灌包的攻击者根本不想进服。他的数据包会被拒绝,但已经到达了,问题恰恰在这里。

7. RocketMod、OpenMod 和插件这一面

Unturned 有两个流行的插件平台,而且两者都与服务器跑在同一个进程里。RocketMod 是较早的那个:最初的维护者在 2019 年 12 月 20 日停止了维护,并把源代码置于 MIT 许可证之下。此后由 Smartly Dressed Games 维护它的分支 Legally Distinct Missile(LDM),独立服务器里已经随包提供:把 Rocket.Unturned 从 Extras 文件夹复制到 Modules 文件夹即可。开发者明确推荐这个分支,因为它修掉了线程错误和传送漏洞这类 Rocket 的老问题。

OpenMod 是较新的后继项目,由最初的 Rocket 维护者之一开发。它不取代 RocketMod,而是与它并行运行,并且可以通过一个集成继续使用已有的 Rocket 插件。对防御来说,这意味着两件事。

第一:每个插件都是主进程里的攻击面。一个在每条聊天消息或每个游戏事件上都触发数据库查询的插件,就是自己造出来的拒绝服务。这时单个玩家只要循环触发某个事件,就能不用任何带宽让服务器瘫掉。请把插件列表保持得短,优先选择开源插件,并在每次加装之后测一次服务器的帧率。

第二:由于 Unturned 没有自己的 RCON 端口,任何远程控制都来自插件。安装之后请用 ss -lntp 查清它打开了哪个 TCP 端口,并把它限制到您自己的地址。一个对外开放、密码又弱的远程控制端口不是 DDoS 问题,而是服务器被接管的问题。

8. Workshop 内容与加入流程

Steam Workshop 内容会让加入过程变得昂贵,而这直接影响服务器有多好打。它通过同一个 Server 文件夹下的 WorkshopDownloadConfig.json 控制:

{
    "File_IDs": [],
    "Ignore_Children_File_IDs": [],
    "Query_Cache_Max_Age_Seconds": 600,
    "Max_Query_Retries": 2,
    "Use_Cached_Downloads": true,
    "Should_Monitor_Updates": true,
    "Shutdown_Update_Detected_Timer": 600
}

File_IDs 里写的是地图和 Mod 的 Workshop 编号。服务器启动时会连同依赖一起下载它们,每名玩家在连接时也会自动补下载。有三个后果您应该知道。第一,Mod 列表很长时加入过程会很久,而在一次攻击之后所有玩家会同时回来,这会让服务器第二次承压。第二,只要有 Workshop 文件被更新,Should_Monitor_Updates 就会让服务器停下来:默认为 600 秒的 Shutdown_Update_Detected_Timer 随后会导致一次重启,而运营者在遭到攻击时经常把它当成攻击成功了。第三,每个 Mod 都是运行在您服务器上的别人的代码。

实际操作就是:把列表保持得尽可能短,每次出现意外重启时先在服务器日志里找关于 Workshop 更新的提示,并且只有在您自己安排更新的情况下才关闭 Should_Monitor_Updates。

9. 服务器列表、服务器代码和 Fake IP 功能

只要服务器是公开列出的,您的 IP 地址就不可能保密。每个连接过一次的玩家都知道它,第三方列表反正也会公布它。不过有两个习惯仍然有用:不要自己在任何地方公布裸地址,并让玩家通过一个主机名连接,这样换地址时不会让每个链接都失效。最典型的情况是那条指向旧地址、被遗忘的 A 记录,它会让任何更换都失去作用。

要在互联网上运营,您本来就需要一个来自 Steam 服务器管理页面、对应应用编号 304930 的 Game Server Login Token(GSLT)。它还能让您服务器的服务器代码在重启之后保持不变,而不是每次启动都重新生成。

Unturned 另外还提供一个 Fake IP 功能。它通过 Config.json 中的 "Use_FakeIP": true 开启,控制台命令 CopyFakeIP 会给出您随后对外公布的地址。此后流量经由中继网络 Steam Datagram Relay 传输,分配到的地址位于 169.254.0.0 到 169.254.255.255 之间,服务器的真实地址不再向玩家显示。Valve 把这种流量描述为经过身份验证、加密并且有速率限制的。

代价很高,而且很少有人一并说明:地址和端口在每次重启时都会变,没有自己写的脚本就无法把域名指向它,而且 Steam 的“收藏”和“历史记录”列表对它不起作用,只有书签功能可用。但最重要的是,这个功能只保护游戏这条路。您的服务器保留着它真实的地址,SSH、Web 面板、数据库和网站仍然可以通过它访问。谁从一条旧的 DNS 记录、一个状态页面或者一次早先的连接里知道了这个地址,就仍然会直接攻击它。所以 Fake IP 功能不能替代服务器前面网络中的过滤,它只是缩小了知道您地址的人的数量。

10. 记录日志,让您在攻击中不必猜

最重要的一步是几乎没人事先做的那一步:在一切正常的时候先建立基线。没有正常值,事后您就说不清每秒 4 万个数据包是很多,还是就是个普通的周五晚上。用 apt-get install -y vnstat sysstat 让测量常驻运行。事件发生时四条命令就够了:

sar -n DEV 1 10
ip -s link show eth0
dmesg -T | tail -50
tcpdump -ni eth0 udp portrange 27015-27016 -c 200 -q

用 tcpdump 时有一条铁律:一定要用 -c 限制数量,满载状态下抓包会让本来已经过载的服务器更吃力。如何解读这些数值、如何把攻击和软件缺陷区分开,见 识别服务器上的 DDoS 攻击。

这些措施到哪里为止

前面所有措施都跑在您的服务器上,也就是线路的末端。防火墙规则处理的是已经跑过网线的数据包。您可以把它丢弃,但没法让它没被发出来。

算一下就清楚了。一台典型的游戏服务器挂在 1 Gbit/s 上,也就是每秒 125 兆字节,只要有人发得比这更多,线路就满了。正常运行远低于这个水平:24 名玩家、每名玩家默认允许每秒 50 个数据包,进来的大约是每秒 1200 个数据包。一个 booter 服务不需要任何准备就能产生这个数量的好几倍。

第二个量是数据包速率,而它几乎总是比带宽先出事。在 64 字节的小包情况下,1 Gbit/s 的线路里能装进每秒约 149 万个数据包。普通的服务器内核视 CPU 和网卡而定,处理其中几十万个之后就会开始丢包。因此一次连您线路三分之一都填不满的攻击,仍然可能让您的服务器瘫掉,因为计算时间都花在丢包上了。运营者的体验是“负载根本不高,可是什么都没了”。

为了对真实的量级有个概念:在 KernelHost 的服务器上,过滤过的攻击包括一次打向语音服务器、超过 473.4 Gbit/s 且每秒超过 4150 万个数据包的攻击,以及一次打向游戏服务器、超过 112.2 Gbit/s 的 UDP 洪水攻击。对此没有任何本地设置可用。流量型攻击必须在服务器前面的网络里就被终结。

KernelHost 用什么来应对

每台服务器都标配的持续防护

KernelHost 的 DDoS 防护分两级,持续生效,您不需要开启、订购或配置任何东西:

  • 第 1 级:全球清洗网络中 17 Tbps 的清洗能力。流量型攻击在靠近来源的地方就被清洗掉,不会到达数据中心。
  • 第 2 级:法兰克福的 Arbor 实时过滤,容量 3.2 Tbps。就在服务器前面,逐个数据包地识别并丢弃与协议相关的攻击特征。

有两点是关键。防护持续运行,不需要先对攻击做出反应,所以开头不会有服务器失联的那几分钟。而且不使用黑洞路由:您的 IP 地址留在网络里,被丢弃的只有恶意数据包。把 IP 地址从网络里撤下来的做法,对您而言和攻击者达到的结果一样。地点是法兰克福。哪些游戏和协议在覆盖范围内,见 实时游戏服务器 DDoS 防护。

针对长期被攻击项目的 Advanced DDoS Protection

有些项目不是偶尔被打,而是被有针对性地连打几周。为此有 Advanced DDoS Protection,每月 50.00 欧元起,PrePaid 预付费,没有最低合约期,也没有开通费。区别不在于容量更大,而在于控制权:

  • 专用防护 IP,来自法兰克福的核心网络,您的服务器会在我们自己的网络内切换到它。您这边不需要做任何改造。
  • 按端口和协议自行管理的防护规则,就在客户中心里:您可以分别设置 27015 UDP 上允许什么(查询)和 27016 UDP 上允许什么(游戏流量),不必为此开工单。
  • 改动实时生效,因此您可以在攻击进行时随时调整,例如把查询管得更严,同时让游戏流量保持原样。
  • 与具体游戏匹配的防护策略,同样适用于任意 TCP 或 UDP 端口上经过修改的程序和自研程序,因此也适用于带自己端口的插件。

两级防护对比

对比项 标配的 DDoS 持续防护 Advanced DDoS Protection
价格 包含在每个服务器套餐中,不额外收费 每月 50.00 欧元起,PrePaid 预付费
过滤能力 17 Tbps 全球清洗,加上法兰克福 3.2 Tbps 的 Arbor 实时过滤 同样的两级过滤
IP 地址 您服务器本身的 IP 地址 额外的专用防护 IP
规则集 自动防护策略,无需配置 在客户中心里按端口和协议设置自己的规则
变更 自动跟进 实时生效,攻击进行时也可以
游戏策略 针对常见游戏的优化策略,包括 Unturned 与游戏匹配的策略,也适用于经过修改的程序
黑洞路由 否 否
合约期 与服务器套餐绑定 PrePaid 预付费,没有最低合约期,没有退订通知期,也没有开通费

对大多数 Unturned 项目来说,标配的持续防护配上干净的服务器配置就够了。Advanced DDoS Protection 针对的是有人把这件事当成私人恩怨的情况。

常见错误及解决办法

“我的教程说必须放行 27015 到 27017”:这份教程比 2021 年 11 月更早。自 3.21.30.0 版本起,Unturned 服务器只需要两个端口,因为 Steam 查询不再位于游戏端口加二上。请关闭 27017,除非那里跑着第二个实例。

“服务器在跑,但它不在任何服务器列表里了”:这是查询洪水攻击的典型样子,也可能是您自己在 27015 UDP 上的规则设得太严。请用 iptables -L INPUT -n -v 检查您自己的规则是否在累计命中。如果计数器涨得很快,那就是您正在把自己的列表条目过滤掉。千万不要把 27015 完全封掉。

“所有玩家同时因为超时掉线”:请先看连接跟踪是不是溢出了(dmesg -T | grep -i conntrack)。表一满,内核就会不加区分地丢弃。Timeout_Game_Seconds 默认是 30 秒:在这段时间内回来的人可以保住自己的位置。

“服务器在运行中途自己重启”:这很少是攻击。请在日志里查找关于检测到 Workshop 更新的提示。Should_Monitor_Updates 会在默认的 600 秒之后把服务器关掉。

“我换了 IP 地址,两小时后又离线了”:攻击者拿到新地址的渠道和旧地址一样,通常是某个服务器列表、某个 Discord 机器人或者一条旧的 DNS 记录。换地址是争取时间,不是解决办法。

“我打开了 Fake IP 功能,还是被攻击”:它对新玩家隐藏了地址,但并没有把地址从服务器上拿走。谁从一条旧的列表条目、一个状态页面或者一次早先的连接里知道了它,就仍然能直接访问到您的服务器,SSH 和上面的任何 Web 面板同样如此。

“我原来的主机商把我的 IP 地址封了”:那就是黑洞路由。主机商用它保护自己的网络,对您来说结果和一次成功的攻击完全一样,而且通常在那之后还要持续几个小时。有疑问时请直接问清楚:是过滤还是黑洞路由。这个答案对您可用性的影响,比任何硬件参数都大。

“我在 tcpdump 里看不到任何异常”:如果流量已经在前面的网络里被过滤掉了,服务器上当然就什么都收不到。这在过滤正常工作时是常态。反过来说:线路一旦被打满,您甚至可能连用来测量的那条 SSH 会话都进不来。这时请使用客户中心里的 VNC 控制台,它独立于虚拟机自身的网络运行。

要点总结

  • 一台 Unturned 服务器正好需要两个对外开放的 UDP 端口:Commands.dat 中设定的 Port(默认 27015)以及这个值加一(27016)。运行游戏本身不需要 TCP。
  • 自 2021 年 11 月 21 日发布的 3.21.30.0 版本起,27017 端口就是多余的,因为 Steam 查询不再位于游戏端口加二上。还开着它的人,照的是过时的教程。
  • Unturned 没有内置的 RCON 端口。任何远程控制都来自插件,会带来一个自己的 TCP 端口,并且必须由您自己收紧。
  • 查询端口 27015 是最脆弱的一点:一次查询洪水攻击会让服务器在服务器列表里变得不可见,却不会影响任何一名玩家,而且按 US-CERT TA14-017A,Steam 协议的放大系数为 5.5。
  • Config.json 里的上限(Max_Packets_Per_Second 50.0,Rate_Limit_Kick_Threshold 每 40 秒 10 次)只对真正加入的客户端有效,对伪造的源地址无效。
  • 1 Gbit/s 的线路在每秒 125 兆字节时就满了,在 64 字节包大小时每秒约 149 万个数据包就已经满了。24 名玩家的正常运行状态大约是每秒 1200 个数据包。超出这个范围的一切,由服务器前面的网络决定,而不是您的防火墙。
  • 在 KernelHost,两级持续防护包含在每个服务器套餐中,不额外收费,自服务器开通起即生效,并且不使用黑洞路由。想自己掌控过滤规则的人,可以额外加上每月 50.00 欧元起的 Advanced DDoS Protection。

如果您的项目已经放在 KernelHost,过滤就已经在工作,您什么都不用做。若仍然发现异常,请开一个 支持工单,以便为您的 IP 地址调整过滤规则。攻击正在进行时,您还可以通过 WhatsApp 紧急聊天联系我们:+43 650 8209883。

常见问题

运行一台 Unturned 服务器需要开放哪些端口?
正好两个 UDP 端口:Commands.dat 中设定的值,以及这个值加一,默认就是 27015 和 27016。只需通过 Port 27015 这一行设定第一个,第二个会自动得出。按官方文档,第一个端口承载服务器列表的查询,第二个端口承载游戏流量。运行游戏本身不需要任何 TCP 端口。如果您在一台机器上运行多个实例,文档建议间距为二,也就是 27015、27017、27019。
Unturned 需要放行 27017 端口吗?
不需要,自 2021 年 11 月 21 日发布的 3.21.30.0 版本起就不再需要。在那之前,Unturned 服务器需要三个端口,因为 Steam 查询位于游戏端口加二上。这次更新之后,查询与服务器共用同一个端口,第三个端口就取消了。尽管如此,非常多的路由器教程、主机商 Wiki 和论坛帖子仍然在提 27017。今天开放 27017 没有任何好处,它只是纯粹的攻击面,应该关闭,除非那里跑着第二个服务器实例。
我的 Unturned 服务器在跑,但不在任何服务器列表里了。这是攻击吗?
多数情况下是,而且是打向 27015 UDP 端口的查询洪水攻击。服务器通过这个端口回答 A2S_INFO、A2S_PLAYERS 和 A2S_RULES 这些 Steam 查询。它一旦被灌满,服务器就会从服务器浏览器里消失,而已经连上的玩家仍然可以不受干扰地继续玩。第二个常见原因是您自己在 27015 上的防火墙规则设得太严。请用 iptables -L INPUT -n -v 检查您的规则是否在累计命中。千万不要把 27015 完全封掉,否则服务器在任何列表里都找不到了。
Unturned 有内置的 RCON 端口吗?
没有。官方文档只有控制台输入和控制台输出,它们可以通过 ICommandInputOutput 接口用自己的实现替换。因此 Unturned 服务器上的任何远程控制都来自插件,并且会带来一个自己的 TCP 端口。安装之后请用 ss -lntp 查清打开了哪个端口,并把它限制到您自己的地址。一个对外开放、密码又弱的远程控制端口不是 DDoS 问题,而是服务器被接管的问题。
Unturned 的 Fake IP 功能能防住 DDoS 攻击吗?
只能部分防住。在 Config.json 中设置 Use_FakeIP true 之后,游戏流量会经由中继网络 Steam Datagram Relay 传输,真实地址也不再向新玩家显示。但这种保护只到游戏这条路为止:您的服务器保留着真实地址,SSH、Web 面板和网站仍然可以通过它访问,而谁从一条旧的 DNS 记录或一次早先的连接里知道了这个地址,就仍然会直接攻击。此外,地址和端口在每次重启时都会变,没有自己写的脚本就无法把域名指向它。
用 iptables 或 UFW 能挡住 DDoS 攻击吗?
对付小型攻击和不讲究的机器人可以,对付流量型攻击不行。服务器上的防火墙规则处理的是已经跑过您线路的数据包。线路一旦被打满,您玩家的数据包在更早的地方就已经过不来了,跟您的规则集写得多好完全无关。有意义的做法是在 27015 和 27016 上按源地址设速率上限,并对这两个端口使用 NOTRACK,以免内核的连接跟踪溢出。流量型攻击必须在服务器前面的网络里就被终结。
攻击到多大规模,我的 Unturned 服务器就靠自己撑不住了?
典型的游戏服务器挂在 1 Gbit/s 上,也就是每秒 125 兆字节。正常运行远低于这个水平:24 名玩家、每名玩家默认允许每秒 50 个数据包,进来的大约是每秒 1200 个数据包。比带宽更要紧的是数据包速率。在 64 字节包大小时,1 Gbit/s 里能装进每秒约 149 万个数据包,而普通的服务器内核只能处理其中的几十万个。因此即使带宽还没被用尽,一次攻击也可能让您瘫掉。
为什么 Unturned 服务器这么常被攻击?
因为它们的地址是公开的,游戏流量走 UDP,而且发起一次攻击既不需要什么本事,也花不了多少钱。公开列出的服务器必须交出自己的 IP 地址和端口,否则谁也找不到它:Steam 服务器浏览器直接发起查询,第三方列表以明文列出两者。而 UDP 没有可以强制要求的连接建立过程,源地址也可以伪造。因此攻击者既不必进入您的服务器,也不必正确地跟它对话,就能制造负载。
RocketMod 或 OpenMod 的插件能帮上 DDoS 防护吗?
不能,它们甚至可能让情况更糟。两个平台都与服务器跑在同一个进程里。一个在每条聊天消息或每个游戏事件上都触发数据库查询的插件,就是自己造出来的拒绝服务:这时单个玩家不用任何带宽就能让服务器瘫掉。请把插件列表保持得短,并在每次加装之后测量。RocketMod 自 2019 年 12 月 20 日起就不再由最初的维护者维护;推荐使用由 Smartly Dressed Games 维护的分支 Legally Distinct Missile,或者后继项目 OpenMod。
在 KernelHost,我的服务器会在攻击期间离线吗?
不会。我们不使用黑洞路由。您的 IP 地址留在网络里,被丢弃的只有恶意数据包。防护分两级:全球清洗网络中 17 Tbps 的清洗能力,以及法兰克福 3.2 Tbps 的 Arbor 实时过滤。它持续运行,不需要先对攻击做出反应,因此开头不会有服务器失联的那几分钟。
KernelHost 的 DDoS 防护要额外付费吗?
不用。两级持续防护包含在每个服务器套餐中,不额外收费,自服务器开通起即生效。您既不用订购,也不用开启或配置。这对 Unturned 服务器和同一台服务器上的任何其他应用同样适用,与您占用哪些端口无关。
什么时候我的 Unturned 服务器还需要额外的 Advanced DDoS Protection?
当您的项目不是偶尔被打,而是被有针对性地连打几周,并且您想自己掌控过滤时。您会获得一个专用防护 IP,并在客户中心里自行按端口和协议管理防护规则,也就是把 27015 UDP 上的查询和 27016 UDP 上的游戏流量分开设置。改动实时生效,因此您可以在攻击进行时随时调整。价格每月 50.00 欧元起,PrePaid 预付费,没有最低合约期,也没有开通费。

Unturned Unturned DDoS 防护 游戏服务器防护 27015 端口 27016 端口 Steam 查询 RocketMod OpenMod Advanced DDoS Protection