Move to openconnet + vpnslice

This commit is contained in:
Rob Pearce 2023-10-11 11:43:11 +11:00
parent 119d9c0d38
commit bb03283347
1 changed files with 104 additions and 38 deletions

142
cvpn
View File

@ -15,7 +15,15 @@ VALID_VENDORS="cisco|f5"
cp -p "$LOGFILE" "${LOGFILE}.0" cp -p "$LOGFILE" "${LOGFILE}.0"
cp /dev/null "$LOGFILE" cp /dev/null "$LOGFILE"
VPN=/opt/cisco/anyconnect/bin/vpn OPENCONNECT=$(which openconnect 2>/dev/null)
if [[ $? -ne 0 ]]; then
warn "Can't find openconnect binary - Cisco VPNs won't work."
fi
VPNSLICE=$(which vpn-slice 2>/dev/null)
if [[ $? -ne 0 ]]; then
warn "Can't find vpn-slice binary - Cisco VPNs won't work."
fi
mkdir -p "${CONFDIR}" mkdir -p "${CONFDIR}"
@ -41,7 +49,7 @@ function alias_to_cmd() {
} }
function load_config() { function load_config() {
local CONFLINES line thisprofile thisuser thispw thisgroup local CONFLINES line thisprofile thisuser thispw thisgroup thisroutes thisservercert
DEFAULTPROFILE="" DEFAULTPROFILE=""
if [[ -e ${CONFFILE} ]]; then if [[ -e ${CONFFILE} ]]; then
DEFAULTPROFILE=$(grep '^#default:' "${CONFFILE}" | sed 's/^#default://') DEFAULTPROFILE=$(grep '^#default:' "${CONFFILE}" | sed 's/^#default://')
@ -55,6 +63,8 @@ function load_config() {
thisgroup=$(cut -d, -f4 <<< "${line}") thisgroup=$(cut -d, -f4 <<< "${line}")
thisvendor=$(cut -d, -f5 <<< "${line}") thisvendor=$(cut -d, -f5 <<< "${line}")
thisserver=$(cut -d, -f6 <<< "${line}") thisserver=$(cut -d, -f6 <<< "${line}")
thisroutes=$(cut -d, -f7 <<< "${line}")
thisservercert=$(cut -d, -f8 <<< "${line}")
[[ -z $thisvendor ]] && thisvendor="cisco" [[ -z $thisvendor ]] && thisvendor="cisco"
[[ -z $thisserver ]] && thisvendor="n/a" [[ -z $thisserver ]] && thisvendor="n/a"
if [[ ! $thisvendor =~ $VALID_VENDORS ]]; then if [[ ! $thisvendor =~ $VALID_VENDORS ]]; then
@ -68,6 +78,8 @@ function load_config() {
group[$nvpns]="${thisgroup}" group[$nvpns]="${thisgroup}"
vendor[$nvpns]="${thisvendor}" vendor[$nvpns]="${thisvendor}"
server[$nvpns]="${thisserver}" server[$nvpns]="${thisserver}"
routes[$nvpns]="${thisroutes}"
servercert[$nvpns]="${thisservercert}"
nvpns=$((nvpns + 1)) nvpns=$((nvpns + 1))
done <<< "${CONFLINES}" done <<< "${CONFLINES}"
else else
@ -128,19 +140,14 @@ function get_vpn_status() { # populates vprofile vuser vstatus vserver vvendor,
vserver=$(echo "$pname" | sed 's/^.*--server //;s/ .*//g') vserver=$(echo "$pname" | sed 's/^.*--server //;s/ .*//g')
vuser=$(echo "$pname" | sed 's/^.*--username //;s/ .*//g') vuser=$(echo "$pname" | sed 's/^.*--username //;s/ .*//g')
vvendor=F5 vvendor=F5
elif [[ $pname =~ openconnect ]]; then
vstatus="Connected"
vserver=$(echo "$pname" | awk '{ print $NF }')
vuser=$(echo "$pname" | sed 's/^.*-u //;s/ .*//g')
vvendor=Cisco
fi fi
else else
# no f5 vpn, check anyconnect rv=1
res=$(${VPN} stats 2>&1)
if [[ $? -eq 0 ]]; then
vstatus=$(grep 'Connection State:' <<< "$res" | grep -v Manage | awk '{ print $3 }' )
if [[ $vstatus == "Connected" ]]; then
vvendor="Cisco"
vserver=$(grep 'Server Address:' <<< "$res" | awk '{ print $3 }' )
fi
else
rv=1
fi
fi fi
if [[ $vstatus == "Connected" ]]; then if [[ $vstatus == "Connected" ]]; then
@ -232,25 +239,69 @@ elif [[ $cmd == "on" ]]; then
fi fi
id=$(get_profile_id "${PROFILE}") id=$(get_profile_id "${PROFILE}")
if [[ -n $id ]]; then if [[ -n $id ]]; then
curprofile=${profile[$id]}
curuser=${user[$id]} curuser=${user[$id]}
curpw=${pw[$id]} curpw=${pw[$id]}
curgroup=${group[$id]} curgroup=${group[$id]}
curvendor=${vendor[$id]} curvendor=${vendor[$id]}
if [[ $curvendor == "f5" ]]; then curserver=${server[$id]}
curserver=${server[$id]} curservercert=${servercert[$id]}
else curroutes=${routes[$id]}
curserver=""
fi
else else
error "Could not determine VPN ID for profile ^b${PROFILE}^p."
exit 1 exit 1
fi fi
if [[ -z $curservercert && ${curvendor,,} == "cisco" ]]; then
inform "No server certificate is defined for ^b$curprofile^p."
notify "Trying to obtain server certificate"
foundcert=$(sudo ${OPENCONNECT} --non-inter --protocol=anyconnect -u "$curuser" --authgroup="$curgroup" "$curserver" 2>&1 | grep -- --servercert | awk '{ print $NF }')
if [[ -n $foundcert ]]; then
ok
inform "Got server certificate '^b${foundcert}^p'"
notify "Updating configuration file ^b$CONFFILE^p"
bakfile="${CONFFILE}".backup
prevlines=$(cat "$CONFFILE" | awk NF | wc -l | bc)
newconfig=$(cat "${CONFFILE}" | awk -v p="$curprofile" -v c="$foundcert" -F, '{ OFS=","; if ($1 == p) { $8 = c; } print }')
newlines=$(echo "$newconfig" | awk NF | wc -l | bc)
err=""
if [[ $newlines -ne $prevlines ]]; then
err="line count different"
elif ! grep -q pin-sha256 <<<"$newconfig"; then
err="new config missing server cert"
fi
if [[ -z $err ]]; then
ok
cp -p "${CONFFILE}" "${bakfile}"
echo "$newconfig" > ${CONFFILE}
curservercert="$foundcert"
else
fail
error "Regenerated config file seems wrong ($err)"
cecho -s "$RED" "Current config:"
cecho -s "$RED" "$(cat "$CONFFILE")" | sed 's/^/ /'
echo
cecho -s "$RED" "Newly generated config:"
cecho -s "$RED" "$newconfig" | sed 's/^/ /'
echo
exit 1
fi
else
fail
exit 1
fi
fi
nstr="Connecting to ^b${PROFILE}^p as user ^b${curuser}^p" nstr="Connecting to ^b${PROFILE}^p as user ^b${curuser}^p"
[[ -n $curgroup ]] && nstr="${nstr} group ${curgroup}" [[ -n $curgroup ]] && nstr="${nstr} group ${curgroup}"
[[ -n $curserver ]] && nstr="${nstr} server ${curserver}"
notify "${nstr}" notify "${nstr}"
rm -f "$VPNPIDFILE"
if [[ $curvendor == "f5" ]]; then if [[ $curvendor == "f5" ]]; then
rm -f "$VPNPIDFILE"
nohup sudo gof5 --server "${curserver}" --username "${curuser}" --password "${curpw}" >>${LOGFILE} 2>&1 & nohup sudo gof5 --server "${curserver}" --username "${curuser}" --password "${curpw}" >>${LOGFILE} 2>&1 &
f5pid=$! f5pid=$!
nlines=0 nlines=0
@ -286,25 +337,28 @@ elif [[ $cmd == "on" ]]; then
echo "$f5pid" > "$VPNPIDFILE" echo "$f5pid" > "$VPNPIDFILE"
fi fi
else else
if [[ -n $curgroup ]]; then if [[ -n $curroutes ]]; then
answers="y\n${curgroup}\n${curuser}\n${curpw}\n" printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=anyconnect -u "$curuser" --passwd-on-stdin --authgroup="$curgroup" -s "$VPNSLICE $routesarg" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1
else else
answers="y\n${curuser}\n${curpw}\n" printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=anyconnect -u "$curuser" --passwd-on-stdin --authgroup="$curgroup" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1
fi fi
res=$(echo -e "$answers" | ${VPN} -s connect "$PROFILE" 2>&1 | tee ${LOGFILE})
grep -q 'state: Connected' <<< "$res$"
rv=$? rv=$?
res=$(cat "$LOGFILE")
if [[ $rv -eq 0 ]]; then
cpid=$(pgrep openconnect)
if [[ $? -eq 0 ]]; then
echo "$cpid" > "$VPNPIDFILE"
else
rv=1
fi
fi
fi fi
if [[ $rv -eq 0 ]]; then if [[ $rv -eq 0 ]]; then
ok "connected" ok "connected"
else else
fail fail
if [[ $curvendor == "cisco" ]]; then error "Connection failed, logs are below:"
error "Connection failed, logs are in ^b${LOGFILE}^p." cecho -s "$RED" "$res" | sed 's/^/ /'
else
error "Connection failed, logs are below:"
cecho -s "$RED" "$res" | sed 's/^/ /'
fi
fi fi
elif [[ $cmd == "status" ]]; then elif [[ $cmd == "status" ]]; then
BASECOL="$ORANGE" BASECOL="$ORANGE"
@ -325,21 +379,33 @@ elif [[ $cmd == "off" ]]; then
get_vpn_status get_vpn_status
if [[ $vstatus == "Connected" ]]; then if [[ $vstatus == "Connected" ]]; then
notify "Disconnecting from ${vvendor} VPN ^b${vprofile}^p" notify "Disconnecting from ${vvendor} VPN ^b${vprofile}^p"
errstring=""
errdata=""
if [[ ${vvendor,,} == "f5" ]]; then thepid=$(cat $VPNPIDFILE)
#sudo gof5 --server ${s} --close-session if [[ -n $thepid ]]; then
sudo kill $(cat $VPNPIDFILE) sudo kill $thepid
rm -f "${VPNPIDFILE}" sleep 2 # give it some time
rv=0 res=$(ps -p $thepid 2>&1)
if [[ $? -ne 0 ]]; then
rm -f "${VPNPIDFILE}"
rv=0
else
errstring="could not kill pid $thepid:"
errdata="$res"
rv=1
fi
else else
${VPN} disconnect > ${LOGFILE} 2>&1 errstring="Cannot determine current VPN PID to kill."
rv=$? rv=1
fi fi
if [[ $rv -eq 0 ]]; then if [[ $rv -eq 0 ]]; then
ok ok
else else
fail fail
error "Connection failed, logs are in ^b${LOGFILE}^p." error "$errstring"
[[ -n $errdata ]] && cecho -s "$RED" "$errdata" | sed 's/^/ /'
fi fi
else else
fail fail