Newsgroup: it.comp.os.linux.iniziare
Titolo: OpenVPN e return codes in bash

Sto rivendendo un semplice script bash per collegarmi ad una vpn con openvpn.
 
Il problema è semplice, il comando "openvpn ecc ecc" a volte fallisce
l'autenticazione, perchè sul server in questione cambiano di tanto in
tanto le credenziali di accesso.
 
Quanto questo accade mi aspetterei in bash un exit code diverso da zero.
 
Invece se provo ad accedere con user e password sbagliate, openvpn dà un
errore di login fallito giustamente, ma poi il retun code che ottengo
dalla bash è zero:
 
----------------------------------------------------------------------
[...]
Wed Apr  8 18:24:22 2015 AUTH: Received control message: AUTH_FAILED
Wed Apr  8 18:24:22 2015 SIGTERM[soft,auth-failure] received, process
                                                              exiting
# echo $?
0
----------------------------------------------------------------------
 
Ok, come si vede dalle ultime righe della sessione vpn sopra riportata
l'autenticazione fallisce, però se poi chiedo alla shell l'exit code del
comando precedente (ovvero proprio "opnvpn ecc") eco che mi dice "0".
 
Invece mi aspetterei un codice diverso...
 
 
Cosa vorrei farci.
Semplicemente un'instruzione condizionale del tipo:
__________________________
se "opvpn eccc " fallisce
   fai qualcosa
 altrimenti
   fai qualcos'altro
fine-se
========
 
Cosa ne pensate?
Perchè openvpn al contrario di molti programmi si comporta così?
 
E come fare allora a verificare che la VPN sia instaurata senza
problemi?


 
Bo', un po' rozzo ma qualcosa del genere:
<<
/usr/sbin/openvpn --daemon --writepid /var/run/openvpn/myopenvpn.pid
 
sleep 10
 
checkproc -p /var/run/openvpn/myopenvpn.pid /usr/sbin/openvpn
 >>
Dopo checkproc, $? restituisce un valore uguale a zero se openvpn è in 
esecuzione e diverso da zero negli altri casi.
 
Poiché in caso di autenticazione fallita openvpn esce (se non è 
impostato per ritentare, magari ad infinitum, il processo), questo può 
essere una base per impostare il tuo script.
 
Ovviamente lo sleep 10 è totalmente arbitrario, vedi un po' tu, magari 
prova con un loop ed un polling ad intervalli di un secondo.
 
LD

 checkproc -p /var/run/openvpn/myopenvpn.pid /usr/sbin/openvpn
 
 
Ti ringrazio, si anch'io ho aggirato il problema
con una soluzione del genere, la mia forse ancora
più "sporca"...
 
________________________________________________________________________
case $1 in
        start)  
                [ -f $PIDFILE ] && echo 'ERR: OpenVPN is already \
		     running, please terminate it first!' && exit 1
                openvpn --daemon --config $CONFIG --auth-user-pass $AUTH
                sleep 10
                if ! pidof openvpn > $PIDFILE
                then
                        rm $PIDFILE
                        if update_login $AUTH
                        then
                                echo 'Auth failed!'
                                echo 'login credential updated, \
				                     please retry'
                                exit 2
                        else
                                echo 'Auth and credential update \
				              failed - exiting...'
                                exit 3
                        fi
                fi
                ;;
========================================================================
 
Facendo qualche prova, il login impiga circa 8 secondi.
Quindi mettendo 10 si và sul sicuro...
 
update_login è una funzione che recupera le credenziali
aggiornate dal sito web con "curl" "sed" "grep" ecc...
e le piazza nel file apposito "$AUTH".
 
Si potrebbe migliorare lo script in modo che in caso
di credenziali errate le aggiornasse e riprovasse la
connessione senza uscire con l'"exit 2".
 
È che all'inizio avevo fatto uno scriptino molto semplice
poi usandolo ne ho visti i limiti e l'ho modificato, ma
adesso è diventato un po' più elaborato e si dovrebbe
riscrivere da zero per renderlo un po' più elegante.
 
Ad ogni modo sembra funzionare e per quello che mi serve
ne avanza...
Ogni tot giorni va semplicemente lanciato due volte, perchè
alla prima fallisce il login e esce, aggiornando comunque
le credenziali. Alla seconda usa le credenziali corrette.
Poco male...
 
Strano comunque che "openvpn" non esca con codici d'errore
diversi da zero in caso di login fallito. Pazienza...


A quel punto potresti tentare anche un diverso approccio.
 
Imposta il client con:
 
--auth-retry nointeract
--auth-user-pass $AUTHFILE
--auth-nocache (ma attento che in vecchie versioni questa opzione era 
buggata)
 
e ti limiti a fare l'update di $AUTHFILE con un cronjob, o qualcosa 
del genere, che lancia il tuo script di update delle credenziali.


Ho capito, sì potrebbe essere un'idea...
Come dicevo per quello che mi serve ora và già bene così.
 
Ho provato a fare un file di autenticazione del tipo:
 
------
pippo
yukyuk
------
 
E lo script mi ha aggiornato le credenziali dal sito
avvertendomi del fallito login.
Al chè ho rilanciato lo script e la vpn s'è messa in
piedi senza problemi.
 
Per l'uso che faccio attualmente di quella vpn, di fatto
solo per qualche test, va più che bene perchè:
 
1- non devo collegarmi al sito per copiare eventuali
   credenziali aggiornate
 
2- non mi devo ricordare a memoria le opzioni da dare
   a openvpn.
 
E questo è sufficiente.
Se poi un domani avessi la necessità di mettere in piedi
una vpn per scopi più importanti, allora considererò anche
la soluzione che dicevi.
Che però ha il difetto di stressare ogni tot secondi il sito
del servizio, anche quando non servirebbe.
 
La cosa migliore sarebbe trovare un modo per farsi dire da
openvpn quando fallisce il login.
Se non con un "error exit code" particolare, in qualche altro
modo (e anche lo sleep 10 non è il massimo perchè comprende
anche altri casi di fallimento magari non inerenti la variazione
delle credenziali).
 
Comqunque si fà per capire una cosa "nuova", per lo scopo
va già più che bene così.
 
In ogni caso grazie di nuovo!  :)


Figurati :)

 Spero che le credenziali non cambino ogni tot secondi :)
 
No, lo cambiano ogni due o tre giorni mi pare.
Mi hai dato l'idea di inserire l'aggiornamento credenziali
prima del lancio di openvpn.
Senza istrusioni condizionali insomma...
 
Questo vorrebbe dire che le credenziali verrebbero aggiornate
ogni volta che si tira su la vpn, quindi anche quando non
necessario, ma in effetti non è un problema.
 
Soluzione banale... Mi ero inerpicato su una complicazione
inutile.
Guarda un po':
 
============================================================
 start)  
	[ -f $PIDFILE ] && echo 'ERR: OpenVPN is already \
            running, please terminate it first!' && exit 1
	if ! update_login $AUTH
	then
		echo 'Auth and credential update failed - \
                                                 exiting...'
		exit 2
	fi
	openvpn --daemon --config $CONFIG \
                     --auth-user-pass $AUTH
	sleep 10
	if ! pidof openvpn > $PIDFILE
	then
		rm $PIDFILE
		echo 'Something went wrong, sorry...'
		exit 3
	fi
	;;
==========
 
 
Ho provato e così sembra funzionare....
Se metto un file credenziali farlocco, si autentica
lo stesso perchè le aggiorna in ogni caso dal sito.
 
Tutto è bene quel che finisce bene!  :)

 ==========
 
 
Consiglio di testare lo stato (running oppure no) di openvpn con
<<
checkproc -p $PIDFILE /usr/sbin/openvpn
 >>
 
e di far scrivere il pid a openvpn con
<<
/usr/sbin/openvpn --writepid $PIDFILE (...)
 >>
 
In tal modo minimizzi il rischio di basare il controllo su un pid che 
è stato successivamente riassegnato ad altro processo e risolvi il 
problema della "sindrome del pidfile scaduto" che si verifica se, per 
qualsiasi ragione, openvpn esce dopo che il tuo script è terminato.

 qualsiasi ragione, openvpn esce dopo che il tuo script è terminato.
 
Eh... oggi non so se riesco a seguire troppo... quindi
strafalcioni e castronerie non scandalizzino!  :)
 
Ad ogni modo, far scrivere il pid al lancio di openvpn
è una buona idea per identificare precisamente il pid
di quella specifica sessione openvpn e non confondersi
poi con altri processi relativi lo stesso eseguibile.
 
Se ho capito bene...
 
Dunque... adesso in pratica creo il $PIFILE eseguendo la
verifica, perchè "pidof openvpn" sputa fuori il pid e io
reindirizzo l'output sul pidfile.
 
Tu dici: se dopo 10 secondi openvpn stesse ancora
girando e fallisse uscendo solo in seguito, la mia
verifica non funzionerebbe, vedrebbe il pid ancora
presente e crederebbe che tutto è ok.
 
A quel punto openvpn uscirebbe, lo script terminerebbe,
ma il $PIDFILE non verrebbe rimosso...
E al prossimo avvio si finirebbe sempre fuori con "exit 1".
 
La cosa, proporresti di aggirarla così, giusto?
 
===================
 openvpn --daemon \
         --config $CONFIG \
	 --auth-user-pass $AUTH \
	 --writepid $PIDFILE
 sleep 10
 if ! checkproc -p $PIDFILE /usr/sbin/openvpn
 then
 	rm $PIDFILE
 	echo "Something went wrong"
	exit 3
 fi
==============================================
 
Comandi equivalenti a "checkproc"?
Tanto per curiosità...

 Tu su che sistema sei?
 
In questo momento Open SUSE. In effetti hai ragione, è un comando 
specifico di questa distro. Una routine in bash che ne faccia le veci 
non è però complessa.
 
Tieni presente che quanto sotto non è stato testato, l'ho scritto di 
getto (attento al wordwrap)
 
<<
#!/bin/bash
 
# Riceve <pidfilename> contenente il pid di un processo di cui si 
vuole verificare l'esistenza, e <procfullpath>
# Se pidfilename non esiste, restituisce 1
# Se pidfilename esiste, ma il pid in esso indicato non corrisponde ad 
alcun processo, restituisce 2
# Se pidfilename esiste, ma il pid in esso indicato corrisponde ad un 
processo diverso da procfullpath, restituisce 3
# Altrimenti restituisce 0
# Richiede readlink ed un kernel >= 2.2. Vedi man proc(5)
 
READLINK=/usr/bin/readlink
 
 
testpidofexec() {
   RETVAL=1
 
   test $# -ne 3 || return $RETVAL # Siamo stati chiamati con un 
numero errato di argomenti
 
   test -f "$1" || return $RETVAL # Pidfile non esiste
 
   PIDNUM="$(cat $1 2>/dev/null)"
 
   RETVAL=2
 
   # $PIDNUM è un numero o rumenta? Mai fidarsi
   case $PIDNUM in
     '' | *[!0-9]*) return $RETVAL ;;
   esac
 
   test "$PIDNUM" -gt 0 || return $RETVAL # Sanity check del PID
 
   test -f /proc/${PIDNUM}/exe || return $RETVAL # Processo $PIDNUM 
non in esecuzione
 
   RETVAL=3
 
   PROCNAME="$($READLINK /proc/${PIDNUM}/exe 2>/dev/null)" # 
/proc/${PIDNUM}/exe è link all'eseguibile
 
   test x"$2" = x"$PROCNAME" && return 0 # L'eseguibile del processo 
$PIDNUM è quello che ci interessa
 
   return $RETVAL
}
testpidofexec "$PIDFILE" "/usr/sbin/openvpn" && echo "Openvpn è in 
esecuzione!!!"
 
 
 >>
 
 

 [...]
 
Gentilissimo! Grazie mille!
Avendo letto un po' il man di checkproc avevo appreso che
funzionasse in modo simile alla routine che hai spiegato.
Però la tu conferma mi era necessaria, non essendo esperto
della faccenda.
A dirla tutta non sapevo che sotto "/proc" vi fossero tutti
i PIDs dei processi in uso. Tornerà sicuramente utile una
volta o l'altra.
 
Leggerò senza'altro con più calma il tuo script...
 
 
 
Una curiosità:
vedo che hai una mail fastweb, hai anche collegamento ad internet
con loro?
Non so se è ancora così, ma da tradizione ti davano accesso alla
loro rete nattata anche loro se non ricordo male.
 
Parlando di VPN, nel tuo caso sei collegato ad internet dietro il
loro NAT oppure ti danno IP pubblico?
 
Eventualmente, per uscire dal NAT usi per caso un tunnel VPN verso
qualche servizio remoto?

 con loro?
 
Puoi risalire al mio IP dal campo NNTP delle intestazioni di questo 
post. E' un IP statico di Fastweb. La rete è nattata, ma Fastweb ti fa 
gestire il port forwarding.
 
 


L'IP che leggo è un ip pubblico però.
Ma dietro quell'IP ci sei solo tu, col tuo router fornito da fastweb
e la tua sottorete che ti gestisci, oppure dietro quell'IP ci siete
N utenti fastweb?
Con "la rete è nattata" intendi, una tua rete casalinga oppure intendi
proprio la sottorete di fastweb...
Voglio dire l'IP che ti dà fastweb all'atto della connessione è pubblico
o privato?

 o privato?
 
Dall'hag di Fastweb si prende un IP della subnet 
192.168.1.0/24
.

 Dietro ci sono solo le mie macchine. Ed è anche statico.
 
Ok, quindi hai ip pubblico da fastweb...
Ma paghi qualcosa in più a per questo servizio oppure è il default
attuale di fastweb?


 
Non pago nulla di più rispetto ai normali servizi internet e voce per 
avere l'IP pubblico.
 
Che sia lo standard, e che quindi tutti gli abbonamenti siano come il 
mio (per inciso ho fibra FTTH), non posso dirlo, ho visto che altri 
utenti hanno diverse configurazioni.


Capito... Grazie per le info