diff --git a/cvpn b/cvpn index 3a431d5..956866f 100755 --- a/cvpn +++ b/cvpn @@ -70,6 +70,7 @@ function load_config() { thisroutes=$(cut -d, -f7 <<< "${line}") thisdomains=$(cut -d, -f8 <<< "${line}") thisservercert=$(cut -d, -f9 <<< "${line}") + thispidfile=${CONFDIR}/${thisprofile// /}.pid case $thisvpntype in "") thisvpntype="anyconnect";; "cisco") thisvpntype="anyconnect";; @@ -90,6 +91,7 @@ function load_config() { routes[$nvpns]="${thisroutes}" domains[$nvpns]="${thisdomains}" servercert[$nvpns]="${thisservercert}" + pidfile[$nvpns]="${thispidfile}" nvpns=$((nvpns + 1)) done <<< "${CONFLINES}" else @@ -132,36 +134,51 @@ function get_profile_id() { #1=profile_to_check return 1 } -function get_vpn_status() { # populates vprofile vuser vstatus vserver vvpntype, return 0 if vpn up - local rv=0 vpnpid pname - vprofile="" - vuser="" - vstatus="Disconnected" - vserver="" - vvpntype="" - - if [[ -e $VPNPIDFILE ]]; then - vpnpid=$(cat $VPNPIDFILE 2>/dev/null) - pname=$(ps -p $vpnpid -o command="" 2>/dev/null) - vstatus="Connected" - vserver=$(echo "$pname" | awk '{ print $NF }') - vuser=$(echo "$pname" | sed 's/^.*-u //;s/ .*//g') - vvpntype=$(echo "$pname" | sed 's/^.*--protocol=//;s/ .*//g') - else - rv=1 +function vpnisup() { # 1=profile + local idx pf rv pid + idx=$(get_profile_id "$1") + rv=$? + if [[ $rv -ne 0 || -z $idx ]]; then + return 1 fi - - if [[ $vstatus == "Connected" ]]; then - # find matching profile - for x in ${!profile[@]}; do - if [[ $vserver == ${server[$x]} ]]; then - vprofile="${profile[$x]}" - [[ -z $vuser ]] && vuser=${user[$x]} - [[ -z $vvpntype ]] && vvpntype=${vvpntype[$x]} - fi - done + pf=${pidfile[$idx]} + if [[ -n $pf && -e $pf ]]; then + pid=$(cat $pf) + ps -p $pid >/dev/null 2>&1 + if [[ $? -eq 0 ]]; then + return 0 + else + return 1 + fi fi - return $rv + return 1 +} + +function get_vpn_status() { # populates vprofile[] vpid[] vuser[] vstatus[] vserver[] vvpntype[] nup, return true if any vpns are up + local rv=0 vpnpid pname x + unset vprofile + unset vpnpid + unset vstatus + unset vserver + unset vuser + unset vvpntype + nup=0 + + for x in ${!profile[@]}; do + vpnisup "${profile[$x]}" + if [[ $? -eq 0 ]]; then + vprofile+=(${profile[$x]}) + vpid+=($(cat ${pidfile[$x]})) + vstatus+=("Connected") + vserver+=(${server[$x]}) + vuser+=(${user[$x]}) + vvpntype+=(${vpntype[$x]}) + nup=$((nup + 1)) + fi + done + [[ $nup -eq 0 ]] && return 1 + + return 0 } PROFILE="" @@ -196,7 +213,7 @@ load_config || exit 1 usingdefault=0 PROFILE="$2" -if [[ -z $PROFILE ]]; then +if [[ -z $PROFILE && $cmd == "up" ]]; then if [[ -n ${DEFAULTPROFILE} ]]; then PROFILE="${DEFAULTPROFILE}" usingdefault=1 @@ -204,28 +221,56 @@ if [[ -z $PROFILE ]]; then fi if [[ $cmd == "list" ]]; then - F="%s,%s,%s,%s,%s,%s\n" + F="%s,%s,%s,%s,%s,%s,%s,%s\n" + table=$( ( - printf "${F}" "Profile" "Username" "Password" "Group" "Server" "Type" + printf "${F}" "Profile" "Up?" "Username" "Password" "Group" "Server" "Type" "Scope" for x in ${!profile[@]}; do - p="${pw[$x]:0:2}....${pw[$x]: (-2)}" - prof="${profile[$x]}" - [[ $prof == $DEFAULTPROFILE ]] && prof="*${prof}" - printf "${F}" "${prof}" "${user[$x]}" "${p}" "${group[$x]:-(n/a)}" "${server[$x]:-(n/a)}" "${vpntype[$x]}" + p="${pw[$x]:0:2}....${pw[$x]: (-2)}" + prof="${profile[$x]}" + [[ $prof == $DEFAULTPROFILE ]] && prof="${prof}*" + vpnisup "${prof}" + if [[ $? -eq 0 ]]; then + yn="Yes" + c="${GREEN}" + else + yn="No" + c="${GREY}" + fi + scope="${domains[$x]} ${routes[$x]}" + vt=${vpntype[$x]} + [[ ${vt,,} == "anyconnect" ]] && vt=Cisco + printf "${F}" "${prof}" "$yn" "${user[$x]}" "${p}" "${group[$x]:-(n/a)}" "${server[$x]:-(n/a)}" "${vt}" "${scope%% *}" + + # show one route/domain per row + scope_a=( ${scope} ) +#echo "${profile[$x]} scope: [${scope}]" >&2 +#echo "${profile[$x]} scope_a: [${scope_a[@]}]" >&2 + if [[ ${#scope_a[@]} -ge 2 ]]; then + i=1 # skip first one + while [[ $i -lt ${#scope_a[@]} ]]; do + printf "${F}" " " " " " " " " " " " " " " "${scope_a[$i]}" + i=$((i + 1)) + done + fi done ) | column -s, -t ) - table=$(echo "$table" | sed "s/^\(Profile.*\)$/^b^u\1^p/;s/\(n\/a\)/^i\1^p/g") + + # underline heading + table=$(echo "$table" | sed "s/^\(Profile.*\)$/^b^u\1^p/;") + table=$(awk -v G="$GREEN" -v P="$PLAIN" '($2 == "Yes") { printf(G); } ($2 == "No") { printf(P); } { print }' <<<"$table") + csecho "$WHITE" "$table" echo echo "(* = default VPN)" exit 0 elif [[ $cmd == "on" ]]; then [[ $usingdefault -eq 1 ]] && inform "[using default VPN: ^b$DEFAULTPROFILE^p]" - get_vpn_status - if [[ $vstatus == "Connected" ]]; then - error "VPN profile $vprofile is already connected" + vpnisup "${PROFILE}" + if [[ $? -eq 0 ]]; then + error "VPN profile $PROFILE is already connected" exit 1 fi @@ -246,6 +291,7 @@ elif [[ $cmd == "on" ]]; then curservercert=${servercert[$id]} curroutes=${routes[$id]} curdomains=${domains[$id]} + curpidfile=${pidfile[$id]} #echo "got curprofile=${profile[$id]}" #echo "got curuser=${user[$id]}" #echo "got curpw=${pw[$id]}" @@ -255,6 +301,7 @@ elif [[ $cmd == "on" ]]; then #echo "got curservercert=${servercert[$id]}" #echo "got curroutes=${routes[$id]}" #echo "got curdomains=${domains[$id]}" +#echo "got curpidfile=${pidfile[$id]}" else error "Could not determine VPN ID for profile ^b${PROFILE}^p." exit 1 @@ -314,22 +361,26 @@ elif [[ $cmd == "on" ]]; then notify "${nstr}" - rm -f "$VPNPIDFILE" - if [[ -n $curroutes && -n $curdomains]]; then - printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg -s "$VPNSLICE --domains-vpn-dns ${curdomains// /,} $curroutes" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + rm -f "$curpidfile" + if [[ -n $curroutes && -n $curdomains ]]; then + printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg -s "$VPNSLICE --domains-vpn-dns ${curdomains// /,} $curroutes" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + rv=$? elif [[ -n $curroutes ]]; then - printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg -s "$VPNSLICE $curroutes" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg -s "$VPNSLICE $curroutes" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + rv=$? elif [[ -n $curdomains ]]; then - printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg -s "$VPNSLICE --domains-vpn-dns $curdomains" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg -s "$VPNSLICE --domains-vpn-dns $curdomains" --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + rv=$? else printf '%s' "$curpw" | sudo ${OPENCONNECT} --background --non-inter --protocol=$curvpntype -u "$curuser" --passwd-on-stdin $grouparg --servercert "$curservercert" "$curserver" >"${LOGFILE}" 2>&1 + rv=$? fi - rv=$? res=$(cat "$LOGFILE") if [[ $rv -eq 0 ]]; then - cpid=$(pgrep openconnect) + cpid=$(pgrep -f "openconnect.* ${curserver}") if [[ $? -eq 0 ]]; then - echo "$cpid" > "$VPNPIDFILE" + echo "$cpid" > "$curpidfile" + rv=0 else rv=1 fi @@ -345,55 +396,75 @@ elif [[ $cmd == "status" ]]; then BASECOL="$ORANGE" notify "Checking VPN status" get_vpn_status - [[ $? -eq 0 ]] && ok || fail - if [[ $vstatus == "Connected" ]]; then - col="$GREEN" + ok + if [[ $nup -eq 0 ]]; then + csecho "$ORANGE" "Not connected to any VPNs" + exit 0 + elif [[ $nup -eq 1 ]]; then + ess="" else - col="$RED" - fi - csecho -n "$BASECOL" "VPN status: ${col}${BOLD}${vstatus}^p" - if [[ ${vstatus,,} =~ "connected" ]]; then - [[ -n $vserver ]] && csecho "$BASECOL" " to ^b${vprofile}^p (${vvpntype}:${vuser}@${vserver})" || echo + ess="s" fi + csecho "$ORANGE" "Connected to ^b$nup^p VPN${ess}:" + for x in ${!vstatus[@]}; do + col="$GREEN" + csecho "$BASECOL" " ${col}${BOLD}${vstatus[$x]}^p ${BASECOL}to ^b${vprofile[$x]}^p (${vvpntype[$x]}:${vuser[$x]}@${vserver[$x]})" + done elif [[ $cmd == "off" ]]; then - rv=1 - get_vpn_status - if [[ $vstatus == "Connected" ]]; then - notify "Disconnecting from ${vvpntype} VPN ^b${vprofile}^p" - errstring="" - errdata="" + if [[ -n $PROFILE ]]; then + # bring down just one vpn + idxlist=$(get_profile_id "$PROFILE") + else + # bring down all vpns + idxlist="${!profile[@]}" + fi + ntried=0 + for x in $idxlist; do + vpnisup "${profile[$x]}" + if [[ $? -eq 0 ]]; then + rv=1 + ntried=$((ntried + 1)) + notify "Disconnecting from ^b${profile[$x]}^p VPN" + errstring="" + errdata="" - thepid=$(cat $VPNPIDFILE) - if [[ -n $thepid ]]; then - sudo kill $thepid - sleep 2 # give it some time - res=$(ps -p $thepid 2>&1) - if [[ $? -ne 0 ]]; then - rm -f "${VPNPIDFILE}" - rv=0 + thepid=$(cat ${pidfile[$x]}) + if [[ -n $thepid ]]; then + sudo kill $thepid + sleep 2 # give it some time + res=$(ps -p $thepid 2>&1) + if [[ $? -ne 0 ]]; then + rm -f "${pidfile[$x]}" + rv=0 + else + errstring="could not kill pid $thepid:" + errdata="$res" + rv=1 + fi else - errstring="could not kill pid $thepid:" - errdata="$res" + errstring="Cannot determine current VPN PID to kill." rv=1 fi - else - errstring="Cannot determine current VPN PID to kill." - rv=1 - fi - if [[ $rv -eq 0 ]]; then - ok - else - fail - error "$errstring" - [[ -n $errdata ]] && cecho -s "$RED" "$errdata" | sed 's/^/ /' + if [[ $rv -eq 0 ]]; then + ok + else + fail + error "$errstring" + [[ -n $errdata ]] && cecho -s "$RED" "$errdata" | sed 's/^/ /' + fi + elif [[ -n $PROFILE ]]; then + error "The VPN ^b${PROFILE}^p is already disconnected" + exit 1 fi - else - fail + done + if [[ $ntried -eq 0 && -z $PROFILE ]]; then error "All VPNs are already disconnected" + exit 1 fi else usage exit 1 fi +exit 0