Ich habe mir gestern einen Teil der auf sourceforge.net gelisteten Tools zu OpenVPN angesehen, ein paar ganz nette waren dabei – allerdings für meinen Geschmack teilweise etwas zu „aufgeblasen“! Ich will ja eigentlich nur auf einfache Art und Weise eine Statistik zum Openvpn Server.
Den Management Server von Openvpn wollte ich mir eigentlich sparen, es wird ja eh schon ein recht aussagekräftiges Logfile erzeugt (vorausgesetzt in der Server config steht folgender Eintrag: „status openvpn-status.log“).
Ein Tool hat Perl mit TK als grafische Ausgabe verwendet und sich mittels ssh-Tunnel direkt zum Management Server verbunden, leider aber nur den Aktuellen Stand angezeigt.
Andere wieder verwendeten Python oder C um die Daten auszulesen und anzuzeigen oder aber in eine Datenbank zu schreiben, aber extra einen Compiler installieren wollte ich jetzt auch nicht.
Irgendwie fehlte für mich ein kleines aber einfaches Tool welches die Daten regelmässig aus dem Logfile auswertet und in eine Datenbank wegschreibt. Auf die Datenbank kann man dann ja beliebig zugreifen und entsprechende Reports bauen – PHP, OpenOffice/Base, Calc, was auch immer…
Da OpenVpn das Status-File scheinbar nur jede Minute aktualisiert würde eine Verbindung die kürzer als eine Minute ausfällt durch den Rost fallen – angesichts der relativ geringen Datenmenge die innerhalb einer Minute übertragen werden kann kann ich das gut verkraften. Mir geht es in erster Linie darum zu sehen wer sich regelmässig einloggt und wie viel wirklich über OpenVPN gearbeitet wird. Dafür reicht mir der Minuten-Rhytmus völlig aus!
Dafür habe ich erst einmal eine Tabelle auf meinem MySQL Server erstellt:
CREATE TABLE `openvpn` (
`cname` char(50) NOT NULL,
`realaddr` char(22) NOT NULL,
`received` bigint(20) default NULL,
`sent` bigint(20) default NULL,
`starttime` datetime default NULL,
`endtime` datetime default NULL,
`vpnaddr` char(22) default NULL
)
Alle OpenVPN Schlüssel die von mir vergeben wurden tragen eindeutige Namen und ein Mehrfacher Login ist nicht erlaubt. Mit 50 Zeichen bei den Schlüsselnamen/CNAME komme ich locker aus.
Nach dem Anlegen der Tabelle habe ich mich daran gemacht ein BASH-Script zum Sammeln der Daten zu basteln, BASH darum weil es für mich sowas wie der kleinste gemeinsame Nenner ist – praktisch auf jedem System vorhanden und ausserdem eine wirklich geniale Script Sprache ist.
Das ganze Script war in ca. 30 Minuten geschrieben, ein Paar kleinere Fehler musste ich dann noch korrigieren – alles in allem eine Stunde Arbeit.
Die in der Variable INT gespeicherte IP-Adresse ist jene die aktiv sein muss damit das Script überhaupt durchläuft. In meinem konkreten Fall läuft das Script auf zwei Rechnern die als HA-Cluster zusammenarbeiten und nur jener Rechner der die IP-Adresse aktiviert hat bedient aktuell das OpenVPN, der Zweite wartet im Standby auf einen Ausfall des Ersten.
Alle Adressen die im VPN Netzwerk an Clients vergeben werden (ipp.txt) stammen aus dem Subnetz beginnend mit „10.99.1“.
Die restlichen Config-Zeilen sollten eigentlich selbsterklärend sein!
#!/bin/bash
### config start
INT=192.168.100.240
OVPNLOG=“/etc/openvpn/openvpn-status.log“
VPNNET=“10.99.1″
MYSQLHOST=127.0.0.1
MYSQLUSER=root
MYSQLPWD=secret
MYSQLDB=statistics
VPNTABLE=openvpn### config end
IPUP=$(ifconfig $INTETH | grep „$INT“)
if [ ! „$IPUP“ ]; then
exit
fi# check openvpn logfile for active connections
NOW=$(date +%F“ „%T)
OLOG=$(sed -n -e ‚/^Common Name/,/^ROUTING TABLE/p‘ $OVPNLOG | sed -e ‚1d‘ -e ‚$d‘)IFS=“
„for i in $OLOG; do
CNAME=$(echo $i|awk -F‘,‘ ‚{print $1}‘)
REALADDR=$(echo $i|awk -F‘,‘ ‚{print $2}‘)
RECEIVED=$(echo $i|awk -F‘,‘ ‚{print $3}‘)
SENT=$(echo $i|awk -F‘,‘ ‚{print $4}‘)
AKTDATE=$(echo $i|awk -F‘,‘ ‚{print $5}‘)
AKTDATE=$(date -d „$AKTDATE“ +%F“ „%T)# if connection exists in database do update
SQL=“SELECT endtime FROM $VPNTABLE WHERE cname=’$CNAME‘ AND endtime IS NULL „
AKTUAL=$(mysql -B -h $MYSQLHOST –user=$MYSQLUSER –password=$MYSQLPWD $MYSQLDB -e $SQL)# connection vpn ip-address
VPNADDR=$(grep „^$VPNNET“ $OVPNLOG |grep „$CNAME“|awk -F‘,‘ ‚{print $1}‘)if [ „$AKTUAL“ ]; then
# exists -> update
mysql -B -h $MYSQLHOST –user=$MYSQLUSER –password=$MYSQLPWD $MYSQLDB -e „UPDATE $VPNTABLE SET realaddr=’$REALADDR‘, received=’$RECEIVED‘, sent=’$SENT‘, vpnaddr=’$VPNADDR‘ WHERE cname=’$CNAME‘ AND endtime IS NULL“;
else
# new -> insert
mysql -B -h $MYSQLHOST –user=$MYSQLUSER –password=$MYSQLPWD $MYSQLDB -e „INSERT INTO $VPNTABLE SET realaddr=’$REALADDR‘, received=’$RECEIVED‘, sent=’$SENT‘, cname=’$CNAME‘, starttime=’$AKTDATE‘, vpnaddr=’$VPNADDR‘ „;
fidone
# check for closed connections
for U in $(mysql -s -B -h $MYSQLHOST –user=$MYSQLUSER –password=$MYSQLPWD $MYSQLDB -e „SELECT cname FROM $VPNTABLE WHERE endtime IS NULL“); do
for I in $OLOG; do
CNAME=$(echo $I|awk -F‘,‘ ‚{print $1}‘)
if [ „X$U“ == „X$CNAME“ ]; then
# user im moment aktiv
OK=1
fi
doneif [ ! „X$OK“ == „X1“ ]; then
mysql -B -h $MYSQLHOST –user=$MYSQLUSER –password=$MYSQLPWD $MYSQLDB -e „UPDATE $VPNTABLE SET endtime=’$NOW‘ WHERE cname=’$U‘ AND endtime IS NULL“;
fiunset CNAME
unset OKdone
Das Script habe ich unter /usr/local/sbin als check_ovpn.sh abgespeichert und mit den Rechten „0700“ versehen (chmod 0700 /usr/local/sbin/check_ovpn.sh).
Ein erster Test schreibt gleich mal alle aktiven verbindungen in die Datenbank – immer wieder schön wie ein paar Zeilen BASH das Admin-Leben verschönern können 🙂
Jetzt noch einen Eintrag in der crontab und schon wird fleissig gesammelt!
# openvpn status checken und in datenbank eintragen
* * * * * root /usr/local/sbin/check_ovpn.sh
Bei der Ausgabe werde ich mich dann wohl für PHP entscheiden, im Moment schwebt mir eine aktuelle Anzeige der aktiven Verbindungen vor, eine Statistik pro User nach Datenvolumen oder/und chronologisch, eine Statistik des Datenvolumens gesamt (das ganze eventuell grafisch aufbereitet) usw.
Ich hoffe das recht einfache Script hilft dem einen oder anderen, der andere Projekte auch für oversized hält, weiter und ich würde mich über feedback freuen!
Hey, super script! – Vielen Dank!
ich weis zwar nicht ob du das jemals liest, aber vielleicht hast du ja eine Idee, wie man die Daten aus der SQL datenbank am besten auswerten kann!
das ist auch kein grosses problem, hab da ein php script für gebastelt – ist allerdings hier bisserl blöd zu posten wegen der ganzen sonderzeichen 🙂
kann’s dir aber mailen wenn willst!
Hallo,
an dem PHP script wäre ich auch interessiert
Hallo,
das Script läuft wunderbar, an dem PHP Script wäre ich auch interessiert…..
hi bella, script ist kein problem – wohin soll ich’s dir schicken?
kannst ruhig deine mail adresse hier posten, ich werd den kommentar dann einfach nicht veröffentlichen 🙂
Hallo, noch eine Frage von mir: ich bekomme das script nicht zum laufen:
ich habe es so konfiguriert:
### config start
INT=192.168.10.100
OVPNLOG=“/home/user/statistics/ovpn_status.log“
VPNNET=“192.168.10.1″
MYSQLHOST=127.0.0.1
MYSQLUSER=root
MYSQLPWD=passwd
MYSQLDB=statistics
VPNTABLE=openvpn
### config end
int ist der rechner auf dem das script laufen soll, vpnnet ist das gleiche, da es ein bridged vpn ist.
Mysql sagt folgendes:
mysql> describe openvpn;
+———–+————+——+—–+———+——-+
| Field | Type | Null | Key | Default | Extra |
+———–+————+——+—–+———+——-+
| cname | char(50) | NO | MUL | NULL | |
| realaddr | char(22) | NO | | NULL | |
| received | bigint(20) | YES | | NULL | |
| sent | bigint(20) | YES | | NULL | |
| starttime | datetime | YES | | NULL | |
| endtime | datetime | YES | | NULL | |
| vpnaddr | char(22) | YES | | NULL | |
+———–+————+——+—–+———+——-+
7 rows in set (0.00 sec)
mysql> show databases;
+——————–+
| Database |
+——————–+
| information_schema |
| mysql |
| performance_schema |
| phpmyadmin |
| statistics |
| test |
+——————–+
6 rows in set (0.00 sec)
mysql>
es werden einfach keine daten in das mysql geschrieben. wenn ich im script in Zeile 25 das -n entferne, bekomme ich folgende ausgabe:
./scripts/openvpn_status.sh
date: ungültiges Datum „Virtual Address“
date: ungültiges Datum „304133“
date: ungültiges Datum „28206981“
date: ungültiges Datum „1784788“
date: ungültiges Datum „Real Address“
Was ist da falsch? Wo kann der fehler liegen?
Über hilfe würde ich mich wahnsinnig freuen!
Gruß
Hallo, noch ein Nachtrag:
Zeile 25 ist bei mir Fehlerhaft! Ich habe sie so neu geschrieben:
OLOG=$(grep CLIENT_LIST status.log | awk ‚{ FS = „,“} {print $2″,“$3″,“$5″,“$6″,“$7}‘ | sed -e ‚1d‘)
warscheinlich gibt es 1000 bessere möglichkeiten, aber nun funktioniert das Script wunderbar! Danke!
Gruß
PS.: Über das PHP script würde ich mich sehr freuen!
Zeile 44 funktioniert bei mir nicht
alternative so:
VPNADDR=$(grep „$CNAME“ status.log |awk -F‘,‘ ‚{print $4}‘ | sed -e ‚$d‘)
Gruß
hi unknown! 🙂
warum die beiden zeilen bei dir nicht funktionieren weiss ich nicht wirklich.
eventuell sieht dein logfile anders aus als der standard – es liegt auf jeden fall schon mal in einem ganz anderen verzeichnis.
die fehlermeldungen und auch die stellen die du verändert hast deuten darauf hin!
sg
grufo