scripts/ur/fortinet.vpn.v7.sh

369 lines
11 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
#
# Purpose {{{
# This script will try to manage VPN with forticlient v7
# 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 {{{
## Exit on error {{{
set -o errexit
## }}}
## 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
## }}}
# }}}
# Vars {{{
PROGNAME=$(basename "${0}"); readonly PROGNAME
PROGDIR=$(readlink --canonicalize-missing $(dirname "${0}")); readonly PROGDIR
ARGS="${*}"; readonly ARGS
readonly NBARGS="${#}"
[ -z "${DEBUG-}" ] && DEBUG=1
## 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
readonly FORTICLIENT_NEW_VERSION="7.0.0.0"
## 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}
For a first connection, try to start \`forticlient gui\` first to configure EMS
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
printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}" >&2
unset local_error_message
exit "${local_error_code:=66}"
}
# }}}
define_vars() { # {{{
debug_message "-- define_vars BEGIN"
## If request_status wasn't defined (argument) {{{
if [ -z "${request_status-}" ]; then
## Use default value
readonly request_status="${REQUEST_STATUS_DEFAULT}"
fi
## }}}
## If vpn_profile_name wasn't defined (argument) {{{
if [ -z "${vpn_profile_name-}" ]; then
## Use default value
readonly vpn_profile_name="${VPN_PROFILE_NAME_DEFAULT}"
fi
## }}}
## If vpn_user wasn't defined (argument) {{{
if [ -z "${vpn_user-}" ]; then
## Use default value
readonly vpn_user="${VPN_USER_DEFAULT}"
fi
## }}}
## Try to get forticlient version {{{
is_command_available "dpkg" "| " \
&& forticlient_current_version=$(dpkg --list -- forticlient | awk '/^ii *forticlient/ {print $3}' | sed 's/.:\(.*\)-.*/\1/')
## }}}
debug_message "-- define_vars END"
}
# }}}
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}"
}
# }}}
is_version_greater_than() { # {{{
first_value="${1}"
value_to_compare="${2}"
## Return False by default
return_is_version_greater_than="1"
debug_message "is_version_greater_than \
Is first value (${first_value}) greater than the second value (${value_to_compare})."
if printf '%s\n' "${first_value}" "${value_to_compare}" | sort --check=quiet --version-sort; then
debug_message "is_version_greater_than ${first_value} <= ${value_to_compare} ."
return_is_version_greater_than="1"
else
debug_message "is_version_greater_than ${first_value} > ${value_to_compare} ."
return_is_version_greater_than="0"
fi
unset first_value
unset value_to_compare
return "${return_is_version_greater_than}"
}
# }}}
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
## If forticlient version is lower than expected one (7) {{{
### Exit with error
is_version_greater_than "${forticlient_current_version}" "${FORTICLIENT_NEW_VERSION}" \
|| error_message "Forticlient installed version (${forticlient_current_version}) seems lower than expected (>=${FORTICLIENT_NEW_VERSION}). Please see fortinet.vpn.v6.sh script instead." 02
## }}}
## 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 disconnect
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)
if [ "${systemd_forticlient_status}" != "active" ]; 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)
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 {{{
if [ -n "${DISPLAY-}" ] && [ "${TERM}" = "linux" ]; then
### 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"
## 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
# Parse all argument one by one
while printf -- '%s' "${1-}" | grep --quiet -- "."; do
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