#!/bin/bash # # This script is a simple daemon that checks (and restart/reinit) your vpnc # and your RH kerberos ticket. The script is remember your password so you # don't have to repeatedly type your password. # # Usage: rh-vpnc-watcher [ vpnc-config [ watch-addr ]] # # vpnc-config -- vpnc config file (default: /etc/vpnc/default.conf) # watch-addr -- an internal VPN address (default: porkchop.devel.redhat.com) # # Copyright (C) 2008 Karel Zak # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This file is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # # Last change: Thu Feb 21 13:00:06 CET 2008 # VPNC_CONFIG=${1:-"/etc/vpnc/default.conf"} VPNC_WATCH_ADDR=${2:-"10.10.36.73"} VPNC_BIN="/usr/sbin/vpnc" # Set when your local username is different to VPN/kerberos username #LOCAL_ACCOUNT="matej" PWD_TIMEOUT=30 PING_TIMEOUT=5 PROGNAME=$(basename $0) PIDFILE="/var/run/${PROGNAME}.pid" LOGFILE="/var/log/rh-vpnc-watcher" export LC_ALL=C INITIALIZED="" loops=0 function log() { echo "$(date '+%b %d %H:%M:%S') $PROGNAME[$MY_PID]: $1" >> $LOGFILE } function fatal() { if [ -n "$LOGFILE_ENABLED" ]; then log "FATAL: $1" else echo "$PROGNAME: FATAL: $1" fi rm -f "$PIDFILE" exit 1 } function warning() { if [ -n "$LOGFILE_ENABLED" ]; then log "WARNING: $1" else echo "$PROGNAME: WARNING: $1" fi } function infomsg() { if [ -n "$LOGFILE_ENABLED" ]; then log "INFO: $1" else echo "$PROGNAME: INFO: $1" fi } function killpid() { local pid pid=$1 kill -TERM $pid &> /dev/null usleep 100000 if [ -d "/proc/$pid" ]; then kill -KILL $pid &> /dev/null fi } function vpnc_stop() { local pid pid=$(/sbin/pidof vpnc) if [ -n "$pid" ]; then infomsg "vpnc ($pid) is running, stopping" killpid $pid fi } function vpnc_start() { local i infomsg "starting vpnc" expect -f - &> /dev/null << EOF spawn /usr/sbin/vpnc $VPNC_CONFIG expect "Enter password for $VPNC_USER@$VPNC_GW: " send $VPNC_PWD\n expect eof EOF for i in 1 2 4 6 8; do if [ -n "$(/sbin/pidof vpnc)" ]; then return 0 fi sleep $i done warning "start vpnc failed" return 1 } function kerb_init() { infomsg "call kinit" su $LOCAL_ACCOUNT -c "( expect -f - << EOF spawn /usr/kerberos/bin/kinit expect \"Password for $VPNC_USER@REDHAT.COM: \" send $VPNC_PWD\n expect eof EOF )" &> /dev/null } function kerb_check() { local ex extime extime=0 mytime=$(date '+%s') ex="$(su - $LOCAL_ACCOUNT -c /usr/kerberos/bin/klist 2> /dev/null | gawk '/^[0-9]+\/[0-9]+\/[0-9]+.*REDHAT.COM@REDHAT.COM$/ { print $3, $4 }')" if [ -n "$ex" ]; then extime=$(date --date "$ex" '+%s') fi if [ $mytime -ge $(( $extime - 1200 )) ]; then warning "kerberos ticket for $LOCAL_ACCOUNT expires now or in next 10 mins, reinitialize" kerb_init fi } # check dependencies if [ ! -x "$VPNC_BIN" ]; then fatal "Sir, install vpnc!" fi if [ ! -x "/usr/bin/expect" ]; then fatal "Sir, install expect!" fi # running? if [ -f "$PIDFILE" ]; then old_pid=$(cat $PIDFILE) if [ -d "/proc/$old_pid" ]; then echo "$PROGNAME: FATAL: a $PROGNAME ($old_pid) is already running" exit 1 fi fi echo "$$" > $PIDFILE # config file if [ ! -f "$VPNC_CONFIG" ]; then fatal "cannot found $VPNC_CONFIG" fi # gateway VPNC_GW=$(gawk '/^IPSec gateway / { print $3 }' $VPNC_CONFIG) if [ -z "$VPNC_GW" ]; then fatal "cannot found 'IPSec gateway' in $VPNC_CONFIG" fi # user VPNC_USER=$(gawk '/^Xauth username / { print $3 }' $VPNC_CONFIG) if [ -z "$VPNC_USER" ]; then fatal "cannot found 'Xauth username' in $VPNC_CONFIG" fi # default interface IF_DEFAULT=$(route -n | gawk '/^0\.0\.0\.0/ { print $8 }') if [ -z "$IF_DEFAULT" ]; then fatal "default system route undefined" fi ping -c 2 -w $PING_TIMEOUT -v -I $IF_DEFAULT $VPNC_GW &> /dev/null if [ "$?" != "0" ]; then warning "IPSec gateway $IF_DEFAULT is unreachable" LINK_UP=0 else LINK_UP=1 fi echo -n "Enter your password for $VPNC_USER@$VPNC_GW: " read -t $PWD_TIMEOUT -s VPNC_PWD <&1 echo LOCAL_ACCOUNT=${LOCAL_ACCOUNT:-"$VPNC_USER"} # start new background subshell while [ 1 ]; do if [ -z "$INITIALIZED" ]; then trap "{ vpnc_stop; rm -f $PIDFILE; infomsg 'terminated'; exit 1; }" TERM INT EXIT MY_PID=$(pidof -x $PROGNAME) echo "$MY_PID" > $PIDFILE touch $LOGFILE LOGFILE_ENABLED="yes" infomsg "----- successfully started -----" INITIALIZED="yes" fi if [ "$LINK_UP" == "0" ]; then infomsg "$IF_DEFAULT seems DOWN, waiting" while [ 1 ]; do ping -c 2 -w 20 -I $IF_DEFAULT $VPNC_GW &> /dev/null if [ "$?" == "0" ]; then LINK_UP=1 break fi sleep 5 done infomsg "$IF_DEFAULT seems UP" fi ping -c 2 -w $PING_TIMEOUT $VPNC_WATCH_ADDR &> /dev/null if [ "$?" != "0" ]; then infomsg "VPN seems DOWN" # check link ping -c 2 -w 10 -I $IF_DEFAULT $VPNC_GW &> /dev/null if [ "$?" != "0" ]; then LINK_UP=0 else # link is OK, restart VPN LINK_UP=1 vpnc_stop vpnc_start kerb_check # DNS get screwed all the time rndc flush fi else # VPN and links are UP, so .. relax! sleep 60 # check kerberos ticket (every 10mins) let loops++ if [ $loops -ge 10 ]; then loops=0 kerb_check fi fi done & exit 0