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:
committed by
Luca Boccassi
parent
bcf0a9ac58
commit
f3d4d3e25a
@@ -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}>&-
|
||||
|
||||
Reference in New Issue
Block a user