scripts/ur/fortinet.vpn.sh

332 lines
9.7 KiB
Bash
Raw Normal View History

2023-01-24 17:46:57 +01:00
#!/bin/sh
#
# Purpose {{{
# This script will try to manage VPN with forticlient
# 1. Start a VPN will
# a. Ensure forticlient systemd unit is started.
# b. Try to connect to VPN with profile name.
# 2. Stop a VPN will
# a. Disconnect from the VPN.
# b. Stop and disable forticlient systemd unit.
# c. Restart systemd-resolved to ensure to have correct DNS resolvers.
#
# 2023-01-24
# }}}
# Flags {{{
2023-01-24 18:26:08 +01:00
## Exit on error {{{
2023-01-24 17:46:57 +01:00
set -o errexit
2023-01-24 18:26:08 +01:00
## }}}
## Exit on unset var {{{
### Use "${VARNAME-}" to test a var that may not have been set
set -o nounset
## }}}
## Pipeline command is treated as failed {{{
### Not available in POSIX sh https://github.com/koalaman/shellcheck/wiki/SC3040
#set -o pipefail
## }}}
## Help with debugging {{{
### Call the script by prefixing it with "TRACE=1 ./script.sh"
if [ "${TRACE-0}" -eq 1 ]; then set -o xtrace; fi
## }}}
2023-01-24 17:46:57 +01:00
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
2023-01-24 18:26:08 +01:00
PROGDIR=$(readlink --canonicalize-missing $(dirname "${0}")); readonly PROGDIR
2023-01-24 17:46:57 +01:00
ARGS="${*}"; readonly ARGS
readonly NBARGS="${#}"
2023-01-24 18:26:08 +01:00
[ -z "${DEBUG-}" ] && DEBUG=1
2023-01-24 17:46:57 +01:00
## Export DEBUG for sub-script
export DEBUG
## Default values for some vars
readonly REQUEST_STATUS_DEFAULT="start"
readonly VPN_PROFILE_NAME_DEFAULT="Universite Rennes 1"
VPN_USER_DEFAULT=$(whoami) ; readonly VPN_USER_DEFAULT
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- HELP
usage: $PROGNAME [-d|-h|-p|-u]
Try to easily manage VPN with forticlient.
EXAMPLES:
- Start VPN with default profife name and default user
${PROGNAME}
- Stop the VPN
${PROGNAME} stop
- Start VPN with specific VPN user
${PROGNAME} --user my_lambda_username start
- Start VPN with specific VPN profile name
${PROGNAME} --profile "My University name" start
OPTIONS:
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
-p,--profile
Define VPN profile name to use.
Default : ${VPN_PROFILE_NAME_DEFAULT}
-u,--user
Define VPN user name to use.
Default : ${VPN_USER_DEFAULT}
2023-01-24 18:26:08 +01:00
For a first connection, try to start \`forticlient gui\` first to configure EMS
2023-01-24 17:46:57 +01:00
and to check profile name.
HELP
}
# }}}
debug_message() { # {{{
local_debug_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_debug_message}"
unset local_debug_message
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print message
2023-01-24 18:26:08 +01:00
printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}" >&2
2023-01-24 17:46:57 +01:00
unset local_error_message
exit "${local_error_code:=66}"
}
# }}}
define_vars() { # {{{
## If request_status wasn't defined (argument) {{{
2023-01-24 18:26:08 +01:00
if [ -z "${request_status-}" ]; then
2023-01-24 17:46:57 +01:00
## Use default value
readonly request_status="${REQUEST_STATUS_DEFAULT}"
fi
## }}}
## If vpn_profile_name wasn't defined (argument) {{{
2023-01-24 18:26:08 +01:00
if [ -z "${vpn_profile_name-}" ]; then
2023-01-24 17:46:57 +01:00
## Use default value
readonly vpn_profile_name="${VPN_PROFILE_NAME_DEFAULT}"
fi
## }}}
## If vpn_user wasn't defined (argument) {{{
2023-01-24 18:26:08 +01:00
if [ -z "${vpn_user-}" ]; then
2023-01-24 17:46:57 +01:00
## Use default value
readonly vpn_user="${VPN_USER_DEFAULT}"
fi
## }}}
}
# }}}
is_command_available() { # {{{
local_command_available_cmd="${1}"
debug_prefix="${2:-}"
## Return False by default
return_command_available="1"
if [ "$(command -v ${local_command_available_cmd})" ]; then
debug_message "${debug_prefix}is_command_available \
${RED}${local_command_available_cmd}${COLOR_DEBUG} seems present on this host."
return_command_available="0"
else
debug_message "${debug_prefix}is_command_available \
${RED}${local_command_available_cmd}${COLOR_DEBUG} is not available on this host."
return_command_available="1"
fi
unset local_command_available_cmd
unset debug_prefix
return "${return_command_available}"
}
# }}}
main() { # {{{
debug_message "--- MAIN BEGIN"
## If forticlient command is not available {{{
### Exit with error
is_command_available "forticlient" "| " \
|| error_message "forticlient is not in PATH, ensure the package is installed." 01
## }}}
## Define all vars
define_vars
debug_message "| Define vars"
## If the VPN must be stopped {{{
if [ "${request_status}" = "stop" ]; then
debug_message "-- Disconnect VPN BEGIN"
### If the VPN is still connected {{{
forticlient_status=$(forticlient vpn status | head --lines=1 | sed 's/Status: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 22)
if [ "${forticlient_status}" = "Connected" ]; then
debug_message "| VPN is ${RED}${forticlient_status}${COLOR_DEBUG}, try to disconnect it…"
### Try to discconnect
forticlient vpn disconnect > /dev/null \
|| error_message "Error when disconnecting VPN." 11
fi
### }}}
### Stop the systemd service {{{
debug_message "| Try to stop and disable forticlient.service unit"
sudo systemctl stop forticlient.service \
|| error_message "Error while stopping forticlient.service unit" 12
### Ensure to disable it
sudo systemctl disable forticlient.service \
|| error_message "Error while disabling forticlient.service unit" 13
### }}}
### Ensure to restart DNS resolver {{{
debug_message "| Try to restart systemd-resolved.service unit to have correct DNS resolvers."
sudo systemctl restart systemd-resolved.service \
|| error_message "Error while restart systemd-resolved.service unit" 14
### }}}
debug_message "-- Disconnect VPN END"
fi
## }}}
## If the VPN must be started {{{
if [ "${request_status}" = "start" ]; then
debug_message "-- Connect VPN BEGIN"
### If forticlient.service unit is not started {{{
systemd_forticlient_status=$(systemctl show --property ActiveState --value forticlient.service || error_message "Error while requesting forticlient.service unit status." 21)
2023-01-24 17:46:57 +01:00
if [ "${systemd_forticlient_status}" = "failed" ]; then
debug_message "| Try to start forticlient.service unit."
sudo systemctl restart forticlient.service \
|| error_message "Error while (re)starting forticlient.service unit" 22
fi
### }}}
### If forticlient.service unit is started {{{
systemd_forticlient_status=$(systemctl show --property ActiveState --value forticlient.service || error_message "Error while requesting forticlient.service unit status." 21)
2023-01-24 17:46:57 +01:00
if [ "${systemd_forticlient_status}" = "active" ]; then
debug_message "| forticlient.service unit is ${RED}started${COLOR_DEBUG}."
fi
### }}}
### If the VPN is not connected {{{
forticlient_status=$(forticlient vpn status | head --lines=1 | sed 's/Status: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 23)
if [ "${forticlient_status}" = "Not Running" ]; then
### If script was started from a launcher {{{
2023-01-24 18:26:08 +01:00
if [ -n "${DISPLAY-}" ] && [ "${TERM}" = "linux" ]; then
2023-01-24 17:46:57 +01:00
### Try to launch a new TERM_EMULATOR to ask the password
"${TERM_EMULATOR}" -e forticlient vpn connect "${vpn_profile_name}" --password --user="${vpn_user}" \
|| error_message "Error when connecting to VPN profile (${vpn_profile_name})." 24
### }}}
### Else we consider it was started from CLI {{{
else
### Try to connect
forticlient vpn connect "${vpn_profile_name}" --password --user="${vpn_user}" \
|| error_message "Error when connecting to VPN profile (${vpn_profile_name})." 25
fi
### }}}
fi
### }}}
### If the VPN is connected {{{
forticlient_status=$(forticlient vpn status | head --lines=1 | sed 's/Status: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 25)
if [ "${forticlient_status}" = "Connected" ]; then
debug_message "| VPN is ${RED}${forticlient_status}${COLOR_DEBUG}."
fi
### }}}
debug_message "-- Connect VPN END"
fi
## }}}
debug_message "--- MAIN END"
}
# }}}
# Manage arguments # {{{
# This code can't be in a function due to argument management
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
2023-01-24 18:26:08 +01:00
## If the first argument ask for help (h|help|-h|-help|-*h|-*help)
if printf -- '%s' "${1-}" | grep --quiet --extended-regexp -- "^-*h(elp)?$"; then
usage
exit 0
fi
2023-01-24 17:46:57 +01:00
# Parse all argument one by one
2023-01-24 18:26:08 +01:00
while printf -- '%s' "${1-}" | grep --quiet -- "."; do
2023-01-24 17:46:57 +01:00
case "${1}" in
-d|--debug ) ## debug
DEBUG=0
debug_message "--- Manage argument BEGIN"
;;
--start|start ) ## Define request_status to start
## Define var
readonly request_status="start"
;;
--stop|stop ) ## Define request_status to stop
## Define var
readonly request_status="stop"
;;
-p|--profile ) ## Define vpn_profile_name with given arg
## Move to the next argument
shift
## Define var
readonly vpn_profile_name="${1}"
;;
-u|--user ) ## Define vpn_user with given arg
## Move to the next argument
shift
## Define var
readonly vpn_user="${1}"
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "| ${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "| ${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "| No arguments/options to manage."
fi
debug_message "--- Manage argument END"
# }}}
main
exit 0