Stop remote SSH sessions on close and timeout

This commit is contained in:
benya
2026-06-04 16:55:06 +03:00
parent 6fc805491e
commit 9143b43637
5 changed files with 113 additions and 10 deletions
+75 -4
View File
@@ -12,6 +12,7 @@ SPOOL_DIR="${SPOOL_DIR:-/tmp/rmm-agent-results}"
BACKUP_DIR="${BACKUP_DIR:-/tmp/rmm-agent-backups}"
CHECK_TARGETS="${CHECK_TARGETS:-1.1.1.1 8.8.8.8}"
TUNNEL_IDENTITY_FILE="${TUNNEL_IDENTITY_FILE:-/etc/rmm-agent/tunnel_key}"
TUNNEL_STATE_DIR="${TUNNEL_STATE_DIR:-/tmp/rmm-agent-tunnels}"
if [ -f "$CONFIG_FILE" ]; then
# shellcheck disable=SC1090
@@ -418,6 +419,12 @@ safe_user_name() {
[ -z "$clean" ]
}
safe_session_id() {
[ -n "$1" ] || return 1
clean="$(printf '%s' "$1" | tr -d 'A-Za-z0-9_-')"
[ -z "$clean" ]
}
package_manager() {
if command -v apk >/dev/null 2>&1; then
printf 'apk'
@@ -555,7 +562,7 @@ remote_ssh_reverse_output() {
[ -n "$server_user" ] || server_user="rmm-tunnel"
[ -n "$duration_seconds" ] || duration_seconds="900"
if ! safe_host_name "$server_host" || ! safe_host_name "$local_host" || ! safe_user_name "$server_user"; then
if ! safe_session_id "$session_id" || ! safe_host_name "$server_host" || ! safe_host_name "$local_host" || ! safe_user_name "$server_user"; then
printf 'remote tunnel host or user is invalid\n'
return 2
fi
@@ -565,6 +572,9 @@ remote_ssh_reverse_output() {
fi
log_file="/tmp/rmm-remote-${session_id:-session}.log"
mkdir -p "$TUNNEL_STATE_DIR"
pid_file="$TUNNEL_STATE_DIR/$session_id.pid"
remote_ssh_stop_session "$session_id" >/dev/null 2>&1 || true
rm -f "$log_file"
identity_args=""
if [ -f "$TUNNEL_IDENTITY_FILE" ]; then
@@ -572,18 +582,20 @@ remote_ssh_reverse_output() {
fi
if command -v ssh >/dev/null 2>&1; then
# shellcheck disable=SC2086
(ssh $identity_args -N -o StrictHostKeyChecking=accept-new -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=2 -R "$remote_port:$local_host:$local_port" -p "$server_port" "$server_user@$server_host"; printf 'ssh exited with code %s\n' "$?" >> "$log_file") >> "$log_file" 2>&1 &
ssh $identity_args -N -o StrictHostKeyChecking=accept-new -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=2 -R "$remote_port:$local_host:$local_port" -p "$server_port" "$server_user@$server_host" >> "$log_file" 2>&1 &
elif command -v dbclient >/dev/null 2>&1; then
# shellcheck disable=SC2086
(dbclient $identity_args -N -y -R "$remote_port:$local_host:$local_port" -p "$server_port" "$server_user@$server_host"; printf 'dbclient exited with code %s\n' "$?" >> "$log_file") >> "$log_file" 2>&1 &
dbclient $identity_args -N -y -R "$remote_port:$local_host:$local_port" -p "$server_port" "$server_user@$server_host" >> "$log_file" 2>&1 &
else
printf 'remote ssh reverse requires ssh or dbclient on router\n'
return 2
fi
pid="$!"
(sleep "$duration_seconds"; kill "$pid" >/dev/null 2>&1 || true) >/dev/null 2>&1 &
printf '%s\n' "$pid" > "$pid_file"
(sleep "$duration_seconds"; remote_ssh_stop_pid "$session_id" "$pid") >/dev/null 2>&1 &
sleep 2
if ! kill -0 "$pid" >/dev/null 2>&1; then
rm -f "$pid_file"
printf 'remote ssh reverse failed to stay running\n'
cat "$log_file" 2>/dev/null
return 1
@@ -595,6 +607,61 @@ remote_ssh_reverse_output() {
return 0
}
remote_ssh_stop_pid() {
session_id="$1"
expected_pid="$2"
pid_file="$TUNNEL_STATE_DIR/$session_id.pid"
[ -f "$pid_file" ] || return 0
pid="$(cat "$pid_file" 2>/dev/null)"
[ "$pid" = "$expected_pid" ] || return 0
case "$pid" in
''|*[!0-9]*)
rm -f "$pid_file"
return 1
;;
esac
kill "$pid" >/dev/null 2>&1 || true
rm -f "$pid_file"
}
remote_ssh_stop_session() {
session_id="$1"
remote_port="${2:-}"
if ! safe_session_id "$session_id"; then
printf 'remote session id is invalid\n'
return 2
fi
pid_file="$TUNNEL_STATE_DIR/$session_id.pid"
if [ ! -f "$pid_file" ]; then
if safe_port "$remote_port"; then
for cmdline in /proc/[0-9]*/cmdline; do
[ -f "$cmdline" ] || continue
command_line="$(tr '\000' ' ' < "$cmdline" 2>/dev/null)"
case "$command_line" in
*ssh*" -R $remote_port:"*|*dbclient*" -R $remote_port:"*)
pid="$(printf '%s' "$cmdline" | cut -d/ -f3)"
kill "$pid" >/dev/null 2>&1 || true
printf 'remote ssh session stopped by port\n'
return 0
;;
esac
done
fi
printf 'remote ssh session is already stopped\n'
return 0
fi
pid="$(cat "$pid_file" 2>/dev/null)"
remote_ssh_stop_pid "$session_id" "$pid"
printf 'remote ssh session stopped\n'
}
remote_ssh_close_output() {
args="$1"
session_id="$(command_arg_string "$args" "session_id")"
remote_port="$(command_arg_string "$args" "remote_port")"
remote_ssh_stop_session "$session_id" "$remote_port"
}
run_command() {
cmd_type="$1"
args="$2"
@@ -742,6 +809,10 @@ run_command() {
remote_ssh_reverse_output "$args"
return $?
;;
remote_ssh_close)
remote_ssh_close_output "$args"
return $?
;;
*)
printf 'command type is not allowlisted\n'
return 2