socket-proxyd: fix off-by-one in connection limit

The limit is checked before the new connection is added to the set, so
with --connections-max=N and N connections open "set_size() > N" is
false and an additional connection is admitted. Use ">=" to refuse new
connections once the limit is reached.

(cherry picked from commit 9b51efd69fade39b0315251d02d1c9eab929891c)
This commit is contained in:
Kamil Monicz
2026-10-16 11:36:32 +01:00
committed by Luca Boccassi
parent bcf0a9ac58
commit f3d4d3e25a
3 changed files with 35 additions and 7 deletions
+1 -1
View File
@@ -409,7 +409,7 @@ static int context_add_connection(Context *context, int fd) {
log_debug("New connection from %s", strna(peer));
}
if (set_size(context->connections) > arg_connections_max)
if (set_size(context->connections) >= arg_connections_max)
return log_warning_errno(SYNTHETIC_ERRNO(EBUSY), "Hit connection limit, refusing connection.");
r = sd_event_source_set_enabled(context->idle_time, SD_EVENT_OFF);
@@ -7,12 +7,17 @@ import sys
data = sys.stdin.buffer.read()
s = socket.create_connection(('localhost', 12345), timeout=15)
s.settimeout(15)
s.sendall(data)
received = b''
while len(received) < len(data):
chunk = s.recv(65536)
if not chunk:
break
received += chunk
try:
s.sendall(data)
while len(received) < len(data):
chunk = s.recv(65536)
if not chunk:
break
received += chunk
except (ConnectionResetError, BrokenPipeError):
# A proxy refusing the connection closes it, which may arrive as a reset rather than EOF
if received:
raise
sys.stdout.buffer.write(received)
s.close()
@@ -65,3 +65,26 @@ PROXY_PID="$(systemctl show -P MainPID test-proxyd.service)"
read -r _ _ _ SOFT HARD _ < <(grep '^Max open files' "/proc/$PROXY_PID/limits")
assert_eq "$SOFT" 4096
assert_eq "$HARD" 4096
# --connections-max= is a hard cap: while one connection is held open, the next one is closed unserved
systemctl stop test-proxyd.socket test-proxyd.service
cat >/run/systemd/system/test-proxyd.service <<EOF
[Service]
ExecStart=/usr/lib/systemd/systemd-socket-proxyd --connections-max=1 $BACKEND_SOCK
EOF
systemctl daemon-reload
systemctl start test-proxyd.socket
exec {HELD}<>/dev/tcp/127.0.0.1/12345
echo -n held >&"$HELD"
read -r -N 4 -t 15 REPLY <&"$HELD"
assert_eq "$REPLY" "held"
# Assigned rather than passed to assert_eq, so that set -e fails the test when the client errors out
REFUSED="$(echo -n refused | proxy_echo)"
assert_eq "$REFUSED" ""
journalctl --sync
journalctl -b -u test-proxyd.service --grep "Hit connection limit" >/dev/null
echo -n still >&"$HELD"
read -r -N 5 -t 15 REPLY <&"$HELD"
assert_eq "$REPLY" "still"
exec {HELD}>&-