Add safe-start and safe-restart

These commands will run a background safety check to stop the firewall if a safety lock is removed in 30 seconds.
This will reduce the risk to get locked out because of a bad configuration.
This commit is contained in:
Jérémy Lecour 2023-07-05 12:18:44 +02:00 committed by Jérémy Lecour
parent 64fd067ce9
commit 54fa2ea8eb
Signed by: jlecour
SSH key fingerprint: SHA256:h+5LgHRKwN9lS0SsdVR5yZPeFlJE4Mt+8UtL4CcP8dY
2 changed files with 89 additions and 1 deletions

View file

@ -5,6 +5,8 @@ and this project **does not adhere to [Semantic Versioning](http://semver.org/sp
### Added
* safe-start and safe-restart
### Changed
### Deprecated

View file

@ -111,6 +111,10 @@ STATE_FILE_DIFF='/var/run/minifirewall_state_diff'
ACTIVE_CONFIG='/var/run/minifirewall_active_config'
ACTIVE_CONFIG_DIFF="${ACTIVE_CONFIG}.diff"
SAFETY_LOCK='/var/run/minifirewall_safety.lock'
SAFETY_OUTPUT='/var/run/minifirewall_safety.out'
SAFETY_TIMER=30
LOGGER_BIN=$(command -v logger)
# No colors by default
@ -123,8 +127,12 @@ CYAN=''
WHITE=''
BOLD=''
RESET=''
# check if stdout is a terminal...
if [ -t 1 ]; then
if [ -t 0 ]; then
INTERACTIVE=1
elif [ -t 1 ]; then
INTERACTIVE=0
# see if it supports colors...
ncolors=$(tput colors)
@ -142,6 +150,7 @@ if [ -t 1 ]; then
RESET='\e[m'
fi
fi
readonly INTERACTIVE
## pseudo dry-run :
## Uncomment and call these functions instead of the real iptables and ip6tables commands
@ -155,6 +164,9 @@ fi
# }
## Beware that commands executed from included files are not modified by this trick.
is_interactive() {
test "${INTERACTIVE}" = "1"
}
remove_colors() {
sed -r 's/\x1B\[(;?[0-9]{1,3})+[mGK]//g'
}
@ -1143,6 +1155,57 @@ reset() {
syslog_info "reset"
printf "${GREEN}${BOLD}${PROGNAME} reset${RESET}\n"
}
stop_if_locked() {
count=0
while [ ${count} -lt ${SAFETY_TIMER} ] && [ -f "${SAFETY_LOCK}" ]; do
count=$(( count + 1 ))
sleep 1
done
if [ -f "${SAFETY_LOCK}" ]; then
syslog_error "safety lock is still here after ${SAFETY_TIMER} seconds, we need to stop"
stop
syslog_info "remove safety lock"
rm -f "${SAFETY_LOCK}"
else
syslog_info "safety lock is not there anymore, life goes on"
fi
}
safe_start() {
# start the firewall
start
# create the lock file
syslog_info "add safety lock"
touch "${SAFETY_LOCK}"
# run the special background command
nohup "${0}" stop-if-locked > "${SAFETY_OUTPUT}" 2>&1 &
if is_interactive; then
syslog_info "safe-restart in interactive mode ; if safety lock (${SAFETY_LOCK}) is not removed in the next ${SAFETY_TIMER} seconds, minifirewall will be stopped."
# Ask for input
confirm_default="I'm locked out, please stop the firewall"
printf "If the restart has locked you out you might see this\nbut you should not be able to type anything.\nPlease confirm you're still here: "
read -r confirm
if [ ! -f "${SAFETY_LOCK}" ]; then
printf "Safety lock is not there anymore.\nYou've probably been rescued by the safety checks.\n"
elif [ "${confirm}" != "${confirm_default}" ]; then
printf "OK, let's remove the safety lock.\n"
rm -f "${SAFETY_LOCK}"
fi
else
syslog_info "safe-restart in non-interactive mode ; if safety lock (${SAFETY_LOCK}) is not removed in the next ${SAFETY_TIMER} seconds, minifirewall will be stopped."
fi
}
show_version() {
cat <<END
${PROGNAME} version ${VERSION}
@ -1169,8 +1232,10 @@ Usage: ${PROGNAME} [COMMAND]
Commands
start Start minifirewall
safe-start Start minifirewall, with baground safety checks
stop Stop minifirewall
restart Stop then start minifirewall
safe-restart Restart minifirewall, with background safety checks
status Print minifirewall status
reset Reset iptables tables
check-active-config Check if active config is up-to-date with stored config
@ -1187,6 +1252,13 @@ case "${1:-''}" in
start
;;
safe-start)
source_configuration
check_unpersisted_state
safe_start
;;
stop)
source_configuration
check_unpersisted_state
@ -1216,6 +1288,20 @@ case "${1:-''}" in
start
;;
safe-restart)
source_configuration
check_unpersisted_state
stop
safe_start
;;
stop-if-locked)
source_configuration
stop_if_locked
;;
check-active-config)
check_active_configuration
;;