--- title: "Stopping A2S Query Floods (Rate-Limiting Port 27015)" excerpt: "Why A2S_INFO query floods knock a CS 1.6 server offline, how to spot them with tcpdump, and how to rate-limit connectionless queries on UDP 27015 with iptables." category: "security" tags: "a2s, ddos" image: "" read_time: "8 min read" ---
A CS 1.6 server answers every A2S_INFO query it receives on UDP 27015 — that is how it appears in the master list and in server browsers. Attackers abuse this: they blast thousands of spoofed query packets per second, the server dutifully builds and sends a reply to each, and the main game thread spends all its time answering queries instead of simulating the round. Players see rubber-banding, then mass timeouts. This is a query flood, and unlike a raw bandwidth DDoS you can blunt most of it on the host itself.
Query packets are connectionless: they start with the four bytes 0xFF 0xFF 0xFF 0xFF followed by a request byte such as T (A2S_INFO), U (A2S_PLAYER) or W. They are tiny and cheap to send but force the server to assemble a larger reply, which is why the attack also works as a reflection/amplification vector against third parties. The key fact: a real player sends a handful of queries when browsing, then switches to a full connection. A flood sends the same query byte from many spoofed source addresses, hundreds of times a second each.
Before you block anything, verify the traffic is really query spam and not legitimate load. On the host:
tcpdump -ni any udp port 27015 -c 200
A flood shows a torrent of small inbound packets from many source IPs, often with implausible source ports or obviously spoofed ranges. Compare the packet rate to your player count — a 20-slot server does not generate thousands of packets per second of inbound queries under normal play. If CPU is pinned at the same time, cross-check with the HLDS 100% CPU guide.
The most effective host-level defence is to cap how many packets any single source IP may send to the game port per second, using the hashlimit module. This lets real browsers and players through while throttling a source that hammers the port:
iptables -A INPUT -p udp --dport 27015 \ -m hashlimit \ --hashlimit-name cs_queries \ --hashlimit-mode srcip \ --hashlimit-above 30/sec \ --hashlimit-burst 60 \ -j DROP
This drops packets from any single IP that exceeds 30 per second (with a short burst allowance of 60). Tune the numbers to your traffic — a busy server with a live feed of joins may need a higher ceiling. Because it keys on source IP, a distributed flood from thousands of hosts each staying under the limit will slip through, which is the boundary where host rules end and DDoS-protected hosting begins.
Legitimate A2S queries are short. You can discard obviously abusive connectionless packets by length before they reach the game process:
iptables -A INPUT -p udp --dport 27015 -m length --length 1:32 \ -m hashlimit --hashlimit-name cs_small \ --hashlimit-mode srcip --hashlimit-above 15/sec -j DROP
Apply the tighter limit to the small connectionless packets while leaving normal in-game traffic (which is larger and belongs to established clients) alone. Keep the rules in the right order and make sure your firewall still permits the port at all — see which ports a CS 1.6 server needs open.
iptables rules vanish on reboot. Save them so a restart does not leave you exposed:
iptables-save > /etc/iptables/rules.v4
On a systemd host, install iptables-persistent (or your distro's equivalent) so the rules reload at boot alongside your HLDS systemd service.
--hashlimit-above and confirm the port is still reachable. See server not in the master list.tcpdump to see the real target port.With the rules loaded, watch the counters climb only during an actual flood:
iptables -L INPUT -v -n --line-numbers
The DROP rule's packet counter should stay near zero in normal operation and spike when a flood hits. During an attack, confirm the server FPS holds and players stop timing out. If the counter never moves but the server still lags, the traffic is not a simple per-IP query flood and the fight moves upstream to your host or a scrubbing provider. A separate high-ping kicker will not help here — that is for individual laggy players, not query floods.