From 6f483dad2f88d791363836f647167851af5e041e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gardais=20J=C3=A9r=C3=A9my?= Date: Tue, 24 Jan 2023 17:46:57 +0100 Subject: [PATCH] New script to manage VPN --- ur/fortinet.vpn.sh | 322 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100755 ur/fortinet.vpn.sh diff --git a/ur/fortinet.vpn.sh b/ur/fortinet.vpn.sh new file mode 100755 index 0000000..8fbbebf --- /dev/null +++ b/ur/fortinet.vpn.sh @@ -0,0 +1,322 @@ +#!/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 {{{ +## Exit on error +set -o errexit + +# }}} +# Vars {{{ +PROGNAME=$(basename "${0}"); readonly PROGNAME +PROGDIR=$(readlink -m $(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 + +## 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}" + + unset local_error_message + + exit "${local_error_code:=66}" +} +# }}} +define_vars() { # {{{ + + ## 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 + ## }}} +} +# }}} + +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" + #systemd_forticlient_status=$(sudo systemctl status forticlient.service | grep --word-regexp "Active:" | sed 's/Active: \(.*\)/\1/' || error_message "Error while requesting current VPN status." 22) + ### If forticlient.service unit is not started {{{ + systemd_forticlient_status=$(systemctl show forticlient.service | grep "^ActiveStat" | sed 's/.*=\(.*\)/\1/' || error_message "Error while requesting forticlient.service unit status." 21) + 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 forticlient.service | grep "^ActiveStat" | sed 's/.*=\(.*\)/\1/' || 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" +} +# }}} + +true > /tmp/vpn.env +env | sort >> /tmp/vpn.env + +# Manage arguments # {{{ +# This code can't be in a function due to argument management + +if [ ! "${NBARGS}" -eq "0" ]; then + + manage_arg="0" + + # Parse all argument one by one + while printf -- '%s' "${1}" | grep -q -- "."; do + + case "${1}" in + -d|--debug ) ## debug + DEBUG=0 + debug_message "--- Manage argument BEGIN" + ;; + -h|--help ) ## help + usage + ## Exit after help informations + exit 0 + ;; + --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