---
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"
---
<p>A CS 1.6 server answers every <code>A2S_INFO</code> 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.</p>
<h2>1. Understand what the flood looks like</h2>
<p>Query packets are <em>connectionless</em>: they start with the four bytes <code>0xFF 0xFF 0xFF 0xFF</code> followed by a request byte such as <code>T</code> (A2S_INFO), <code>U</code> (A2S_PLAYER) or <code>W</code>. 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.</p>
<h2>2. Confirm it with tcpdump</h2>
<p>Before you block anything, verify the traffic is really query spam and not legitimate load. On the host:</p>
<pre>tcpdump -ni any udp port 27015 -c 200</pre>
<p>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 <a href="/tutorials/fix-hlds-100-cpu">the HLDS 100% CPU guide</a>.</p>
<h2>3. Rate-limit queries with iptables hashlimit</h2>
<p>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 <code>hashlimit</code> module. This lets real browsers and players through while throttling a source that hammers the port:</p>
<pre>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</pre>
<p>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 <a href="/tutorials/ddos-protected-hosting">DDoS-protected hosting</a> begins.</p>
<h2>4. Drop malformed and oversized query packets</h2>
<p>Legitimate A2S queries are short. You can discard obviously abusive connectionless packets by length before they reach the game process:</p>
<pre>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</pre>
<p>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 <a href="/tutorials/cs16-server-firewall-ports">which ports a CS 1.6 server needs open</a>.</p>
<h2>5. Persist the rules</h2>
<p>iptables rules vanish on reboot. Save them so a restart does not leave you exposed:</p>
<pre>iptables-save > /etc/iptables/rules.v4</pre>
<p>On a systemd host, install <code>iptables-persistent</code> (or your distro's equivalent) so the rules reload at boot alongside your <a href="/tutorials/hlds-systemd-service">HLDS systemd service</a>.</p>
<h2>Common errors</h2>
<ul>
<li><strong>Server drops off the master list after adding rules</strong> — your limit is too aggressive and it is throttling the master server's own queries, or you accidentally blocked outbound. Loosen <code>--hashlimit-above</code> and confirm the port is still reachable. See <a href="/tutorials/fix-server-not-in-master-list">server not in the master list</a>.</li>
<li><strong>Real players still time out during a flood</strong> — the attack is distributed and each source stays under your per-IP cap. Host rules cannot fully stop that; you need upstream filtering.</li>
<li><strong>CPU still pinned after blocking</strong> — the flood may be hitting a different port, or it is a connection flood rather than a query flood. Re-run <code>tcpdump</code> to see the real target port.</li>
<li><strong>Legitimate server-list refreshes look like an attack</strong> — a popular server receives a lot of queries normally. Do not set the ceiling below what your genuine browse traffic needs, or you will hide yourself.</li>
</ul>
<h2>Verification</h2>
<p>With the rules loaded, watch the counters climb only during an actual flood:</p>
<pre>iptables -L INPUT -v -n --line-numbers</pre>
<p>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 <a href="/plugins/csb-high-ping-kicker">high-ping kicker</a> will not help here — that is for individual laggy players, not query floods.</p>