View previous topic :: View next topic |
Author |
Message |
dambacher Apprentice
Joined: 11 Feb 2003 Posts: 290 Location: Germany
|
Posted: Thu Dec 29, 2005 9:09 pm Post subject: openvpn callback on demand... |
|
|
Es Klappt
Ich habe grade diald, capisuite, openvpn und rp-pppoe zu einer on-demand dsl-tunnel-Lösung kombiniert.
Zwei Rechner an unterschiedlichen Standorten haben sowohl einen dsl als auch einen isdn-Anschluss.
Auf beiden lauscht capisuite am isdn auf eingehende Anrufe.
Bei bestimmten Nummern startet capisuite den Internetzugang.
Dann wartet openvpn auf eine Verbundung.
Der zweite Rechner kann zusätzlich über diald und capisuite den ersten anrufen.
Dann startet diald den Internetzugang und openvpn und voilas die Verbindung steht!
Es brauchte aber ein paar zusätzliche Codezeilen in diald und capisuite.
Wenn jemand an den Details interessiert ist... einfach rückmailen
Guten Rutsch! |
|
Back to top |
|
|
manuels Advocate
Joined: 22 Nov 2003 Posts: 2146 Location: Europe
|
Posted: Thu Dec 29, 2005 10:49 pm Post subject: |
|
|
Quote: | Wenn jemand an den Details interessiert ist... einfach rückmailen |
RÜCKMAIL!
hört sich interressant an.
der held des ausklingenden jahres wärst du, wenn du ein howto schreiben würdest!
Tschö mt ö
Manuel _________________ Build your own live cd with catalyst 2.0! |
|
Back to top |
|
|
dambacher Apprentice
Joined: 11 Feb 2003 Posts: 290 Location: Germany
|
Posted: Fri Dec 30, 2005 8:40 am Post subject: |
|
|
OK, überredet!
Also der Reihe nach:
Für die Installation von rp-pppoe und dsl gibt es gute Dokumentation, danach bin ich auch vorgegangen.
Auch zur Installation in Inbetriebnahme von openvpn gibt es ein gutes HOWTO.
Meine Lösung basiert darauf, dass ich beiden Server-Rechnern eine feste IP-Adresse erkauft habe.
(Dadurch spare ich mir das Übermitteln der IP während des Telefonanrufes)
Als Beispiel: auf dem Server sehen meine local.conf folgendermaßen aus:
Für die "roadwarrior"-Einwahl:
Code: |
# config for openvpn connection vpn
dev tun1
tls-server
ca /etc/certs/ca.crt
cert /etc/certs/server.crt
key /etc/keys/server.key # This file should be kept secret
dh /etc/openvpn/certs/dh1024.pem
port 1194
local 217.xx.xx.xx
server 192.168.4.0 255.255.255.0
push "route 192.168.0.0 255.255.255.0"
keepalive 10 120
ping-timer-rem
|
und für die automatische Einwahl
Code: |
# config for openvpn on demand connection
dev tun0
tls-server
tls-remote my_client
ca /etc/certs/ca.crt
cert /etc/certs/server.crt
key /etc/keys/server.key # This file should be kept secret
dh /etc/openvpn/certs/dh1024.pem
local 217.xx.xx.xx
port 1195
ifconfig 192.168.5.2 192.168.5.1
route 192.168.1.0 255.255.255.0
keepalive 10 120
ping-timer-rem
|
Ein Client bekommt folgende Konfiguration
Code: |
dev tun
tls-client
ca /etc/certs/ca.crt
cert /etc/certs/laptop.crt
key /etc/keys/laptop.key
remote 217.xx.xx.xx
tls-remote server
pull
|
|
|
Back to top |
|
|
dambacher Apprentice
Joined: 11 Feb 2003 Posts: 290 Location: Germany
|
Posted: Fri Dec 30, 2005 8:54 am Post subject: |
|
|
Jetzt zum den individuellen Anpassungen.
Zunächst zu capisuite.
Um einen Anruf abzupassen und Aktionen auszuführen ist das incomming-script nötig. Ich habe das Default skript durch folgendes ersetzt:
Code: |
# implement simple callback to internet function
# Iniziiere internetverbindung wenn bestimmter Anschluss anruft.
# Danach kann mit vpn ein Zugang hergestellt werden...
import os, string, capisuite, commands
numbers="hier stehen meine erlaubten Telefonnummern mit komma getrennt"
msn="meine msn"
def callIncoming(call,service,call_from,call_to):
if (call_from not in numbers.split(',') or call_to!=msn):
capisuite.log("call from "+call_from+" to "+call_to+" ignoring",1,call)
capisuite.reject(call,0x3495)
return
# Wenn menschlicher Anrufer, dann Rueckmeldung
if (service==capisuite.SERVICE_VOICE):
capisuite.log("call from "+call_from+" to "+call_to+" accepted",1,call)
capisuite.connect_voice(call,2)
capisuite.audio_send(call,"/usr/share/capisuite/beep.la")
else:
capisuite.reject(call,0x3490)
capisuite.disconnect(call)
# Starte Verbindung
erg=commands.getoutput("ping -c 4 www.t-com.de")
capisuite.log("ping command output: "+erg,1,call)
erg=commands.getoutput("logger \"capisuite initiated connection\" ")
capisuite.log("logger command output: "+erg,1,call)
|
Das Skript testet, ob die Nummer gelistet ist. Wenn ja startet es ein Ping zur Interneteinwahl und gibt ein "beep" aus.
Nun musste ich feststellen, das das idle-skript nicht auf Kommando zum Laufen gebacht werden konnnte. Und einen Dauerlauf alle 2s
ist zu viel und 30s waren zu lange. Also habe ich capisuite gepatch um das Skript auf Signal SIGUSR1 zu starten. Zusätzlich kann ich im Skript Abfragen, ob der Start erzwungen war oder nicht.
Der Patch dazu ist hier:
Code: |
Nur in capisuite-0.4.5u1/scripts: capisuitefax.
diff -ur capisuite-0.4.5/src/application/capisuite.cpp capisuite-0.4.5u1/src/application/capisuite.cpp
--- capisuite-0.4.5/src/application/capisuite.cpp 2004-11-28 14:35:24.000000000 +0100
+++ capisuite-0.4.5u1/src/application/capisuite.cpp 2005-12-25 17:25:13.000000000 +0100
@@ -47,6 +47,14 @@
capisuiteInstance->reload();
signal(SIGHUP,hup_handler);
}
+
+void usr1_handler(int)
+{
+ if (capisuiteInstance)
+ capisuiteInstance->forceIdleRun();
+ signal(SIGUSR1,usr1_handler);
+}
+
CapiSuite::CapiSuite(int argc,char **argv)
:capi(NULL),waiting(),config(),idle(NULL),py_state(NULL),debug(NULL),error(NULL),finish_flag(false),custom_configfile(),daemonmode(false)
@@ -129,6 +137,7 @@
signal(SIGTERM,exit_handler);
signal(SIGINT,exit_handler); // this must be located after pyhton initialization
signal(SIGHUP,hup_handler);
+ signal(SIGUSR1,usr1_handler);
}
catch (CapiError e) {
capisuiteInstance=NULL;
@@ -199,6 +208,21 @@
idle->activate();
}
+void CapiSuite::forceIdleRun()
+{
+ if (debug_level >= 2)
+ (*debug) << prefix() << "forced start of idle script" << endl;
+ if (idle)
+ idle->forceRun();
+}
+
+bool CapiSuite::idleRunWasForced() {
+ if (idle)
+ return idle->runWasForced();
+ else
+ return false;
+}
+
void
CapiSuite::callWaiting (Connection *conn)
{
diff -ur capisuite-0.4.5/src/application/capisuite.h capisuite-0.4.5u1/src/application/capisuite.h
--- capisuite-0.4.5/src/application/capisuite.h 2004-11-28 14:35:24.000000000 +0100
+++ capisuite-0.4.5u1/src/application/capisuite.h 2005-12-25 15:53:57.000000000 +0100
@@ -114,6 +114,14 @@
*/
void reload();
+ /** @brief force run of idle script on SIGUSR1
+ */
+ void forceIdleRun();
+
+ /** @brief check if Idle was forced to run
+ */
+ bool idleRunWasForced();
+
/** @brief print a message to the log
Prints message to the log if it's level is high enough.
@@ -162,7 +170,6 @@
map<string,string> config; ///< holds the configuration read from the configfile
string custom_configfile; ///< holds the name of the custom config file if given
-
};
#endif
diff -ur capisuite-0.4.5/src/application/capisuitemodule.cpp capisuite-0.4.5u1/src/application/capisuitemodule.cpp
--- capisuite-0.4.5/src/application/capisuitemodule.cpp 2004-11-28 14:35:25.000000000 +0100
+++ capisuite-0.4.5u1/src/application/capisuitemodule.cpp 2005-12-25 17:28:23.000000000 +0100
@@ -915,6 +915,16 @@
return (result);
}
+static PyObject*
+capisuite_forced_run(PyObject*, PyObject *args)
+{
+ PyArg_NoArgs(args);
+ if (capisuiteInstance->idleRunWasForced())
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
/** PCallControlMethods - array of functions in module capisuite
*/
@@ -935,6 +945,7 @@
{"read_DTMF", capisuite_read_DTMF, METH_VARARGS, "Read and clear received DTMF. For further details see capisuite module reference."},
{"log", capisuite_log, METH_VARARGS, "Write log message. For further details see capisuite module reference."},
{"error", capisuite_error, METH_VARARGS, "Write error message. For further details see capisuite module reference."},
+ {"forced_run", capisuite_forced_run, METH_NOARGS, "Check if idle script was forced to run via SIGUSR. For further details see capisuite module reference."},
{NULL,NULL,0,NULL}
};
@@ -977,7 +988,6 @@
}
}
-
/* History
$Log: capisuitemodule.cpp,v $
diff -ur capisuite-0.4.5/src/application/idlescript.h capisuite-0.4.5u1/src/application/idlescript.h
--- capisuite-0.4.5/src/application/idlescript.h 2004-11-28 14:35:24.000000000 +0100
+++ capisuite-0.4.5u1/src/application/idlescript.h 2005-12-25 17:34:16.000000000 +0100
@@ -82,6 +82,12 @@
*/
void activate(void);
+ /** @brief force run of idle script (e.g. for user signals)
+ */
+ void forceRun(void);
+
+ bool runWasForced(void);
+
private:
/** @brief Thread body. Calls the python function idle().
@@ -109,8 +115,10 @@
int idlescript_interval; ///< interval between subsequent executions of idle script
Capi *capi; ///< reference to Capi object
bool active; ///< used to disable IdleScript in case of too much errors
-
+ bool forced; ///< used to force run of IdleScript
pthread_t thread_handle; ///< handle for the created pthread thread
+ pthread_mutex_t idle_mut; //< mutex for forced run of IdleScript
+ pthread_cond_t idle_cond; //< condition for forced run of IdleScript
};
#endif
|
Wie man den patch einspielt? Durch einen Trick. Ich juble ebuild meinen Patch einfach unter, weil ich zu faul bin einen eigenen ebuild zu schreiben.
Code: |
ebuild /usr/portage/net-dialup/capisuite/capisuite-0.4.5.ebuild unpack
cd /var/lib/portage/capisuite-0.4.5/work
patch -p0 < capisuite-0.4.5-u1.patch
ebuild /usr/portage/net-dialup/capisuite/capisuite-0.4.5.ebuild compile install qmerge
|
Danach kann ich mein idle-skript auf der client-Seite wie folgt erstellen:
Code: |
# idle script fuer client
import os, string, capisuite
my_nr="hier meine msn"
callback_nr="hier die anzurufende Nummer"
def idle(capi):
capisuite.log("idle script running",2)
if (capisuite.forced_run()):
capisuite.log("idle script forced to run",2)
capisuite.log("initiating callback for server...",1)
(call,result)=capisuite.call_voice(capi,1,my_nr,callback_nr,20,0)
if (result!=0):
capisuite.log("...no success! Error is 0x%x" % result,1)
else:
capisuite.log("...success!",1)
capisuite.disconnect(call)
return
|
Es testet zunächst, ob es normal oder per Signal gestartet wurde. Wenn das Signal kam, wählt es die gewünschte Nummer und wartet auf eine erfolgreiche Antwort, legt dann gleich auf. Voila!
(Hier könnte man jetzt auch eine Übermittlung dynamischer ip-Adressen per dialtone einbauen...)
Last edited by dambacher on Fri Dec 30, 2005 9:21 am; edited 1 time in total |
|
Back to top |
|
|
dambacher Apprentice
Joined: 11 Feb 2003 Posts: 290 Location: Germany
|
Posted: Fri Dec 30, 2005 9:13 am Post subject: |
|
|
Jetzt zu diald.
Auch hier musste ich ein bisschen hand anlegen, denn diald startet seine skripten erst, wenn es ein funktionierendes netzwerkgerät hat. openvpn macht das aber erst, wenn der link steht. Hier beisst sich die Katze in den Schwanz
In diald gibt eis eine undokumentierte skripting-Funktion, mit der man alles routing selber machen kann.
Also habe ich diald dazu gebracht diese Funktion aufzurufen, wenn es ein funktionierendes device haben will.
Den Patch dazu habe ich unten. Mit dem vorher beschriebenen Trick installiert man das ganze. Nicht wundern. Ein paar hunks macht gentoo auch schon, die sind doppelt...
Code: |
diff -ur diald-1.0/dev.c diald-1.0ud1/dev.c
--- diald-1.0/dev.c 2001-06-16 21:51:39.000000000 +0200
+++ diald-1.0ud1/dev.c 2005-12-29 16:01:20.000000000 +0100
@@ -33,6 +33,14 @@
rx_count = -1;
mon_syslog(LOG_INFO, "Open device %s", current_dev);
dead = 0;
+
+ /* call ifsetup to maybe create interface */
+ if (ifsetup) {
+ char buf[1024];
+ sprintf(buf, "%s create link %s",
+ ifsetup, current_dev);
+ run_shell(SHELL_WAIT, "create link", buf, -1);
+ }
}
/*
@@ -226,6 +234,13 @@
req_pid = 0;
dead = 1;
}
+ /* call ifsetup to maybe destroy interface */
+ if (ifsetup) {
+ char buf[1024];
+ sprintf(buf, "%s destroy link %s",
+ ifsetup, current_dev);
+ run_shell(SHELL_WAIT, "destroy link", buf, -1);
+ }
}
void dev_reroute()
@@ -260,6 +275,13 @@
req_pid = 0;
dead = 1;
}
+ /* call ifsetup to maybe destroy interface */
+ if (ifsetup) {
+ char buf[1024];
+ sprintf(buf, "%s destroy link %s",
+ ifsetup, current_dev);
+ run_shell(SHELL_WAIT, "destroy link", buf, -1);
+ }
}
void dev_zombie()
diff -ur diald-1.0/diald.h diald-1.0ud1/diald.h
--- diald-1.0/diald.h 2001-06-16 18:01:25.000000000 +0200
+++ diald-1.0ud1/diald.h 2005-12-29 16:03:53.000000000 +0100
@@ -11,6 +11,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+#include <time.h>
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
diff -ur diald-1.0/firewall.c diald-1.0ud1/firewall.c
--- diald-1.0/firewall.c 2001-06-16 21:51:39.000000000 +0200
+++ diald-1.0ud1/firewall.c 2005-12-29 16:06:06.000000000 +0100
@@ -69,7 +69,7 @@
#if 0
mon_syslog(LOG_DEBUG,"slot def: %d %d %x %x %x",
slot->start, slot->end, slot->wday, slot->mday, slot->month);
-#endif 0
+#endif
if ((slot->start <= ctime)
&& (ctime <= slot->end)
&& (slot->wday & (1<<ltime->tm_wday))
diff -ur diald-1.0/log.c diald-1.0ud1/log.c
--- diald-1.0/log.c 2001-06-16 21:51:39.000000000 +0200
+++ diald-1.0ud1/log.c 2005-12-29 16:17:06.000000000 +0100
@@ -14,7 +14,7 @@
#include <diald.h>
-
+#if 0
static char *
xstrerror(int n)
{
@@ -25,7 +25,9 @@
sprintf(buf, "Error code %d\n", n);
return buf;
}
-
+#else
+#define xstrerror(x) strerror(x)
+#endif
void
mon_syslog(int pri, char *fmt, ...)
diff -ur diald-1.0/timer.c diald-1.0ud1/timer.c
--- diald-1.0/timer.c 2001-06-16 22:16:22.000000000 +0200
+++ diald-1.0ud1/timer.c 2005-12-29 16:08:37.000000000 +0100
@@ -90,9 +90,9 @@
int validate_function(struct timer_lst *c)
{
- if (c->function == del_impulse
- || c->function == del_connection
- || c->function == slip_start_fail)
+ if (c->function == (void*)(void*)del_impulse
+ || c->function == (void*)(void*)del_connection
+ || c->function == (void*)(void*)slip_start_fail)
return 1;
mon_syslog(LOG_ERR, "Caught a bad function value %p. Tell Eric.\n",
c->function);
|
Die Konfigurationsdatei von diald sieht wie folgt aus:
Code: |
#diald.conf
mode dev
device tun0
ifsetup "/etc/diald/ifsetup_openvpn.sh"
local <client-ip>
remote <server-ip>
connect-timeout 90
redial-timeout 10
retry-count 3
demand
# 10min timeout fuer alle ssh
accept tcp 600 tcp.dest=tcp.ssh
accept tcp 600 tcp.source=tcp.ssh
# 2min fuer Druckjobs...
keepup tcp 120 tcp.source=tcp.printer
keepup tcp 120 tcp.source=631
keepup udp 120 tcp.source=631
accept any 30 any
|
Wichtig ist der Eintrag des ifsetup-skriptes. Hier kann man jetzt nach herzenslust das routing verändern.
Mein Skript sieht folgendermaßen aus.
Code: |
#!/bin/bash
logger "starting $0 $@ ..."
MY_DIR=$(dirname $0)
FUNCTION=$1
MODE=$2
INTERFACE=$3
case $FUNCTION in
start)
case $MODE in
proxy)
ifconfig $INTERFACE 192.168.1.254 pointopoint 192.168.0.254 up
;;
esac
;;
stop)
case $MODE in
proxy)
ifconfig $INTERFACE down
;;
esac
;;
create)
case $MODE in
link)
logger -- "start_openvpn.sh: starting openvpn connection"
#hier muss ein Kommando hin zum Anwaehlen des Rechnes, aber welches?
killall -USR1 capisuite
#internetverbindung starten
ping -c 4 www.t-com.de 2>&1 >/dev/null
#openvpn starten
openvpn --daemon --config /etc/openvpn/dialin.conf
;;
esac
;;
destroy)
case $MODE in
link)
logger -- "stop_openvpn.sh: stopping openvpn connection"
kill $(cat /var/run/openvpn_dialin.pid)
;;
esac
;;
esac
|
Meine openvpn-konfiguration für die Einwahl sieht dann so aus. Wichtig ist die writepid-Zeile am ende!
Code: |
# client configuration
dev tun0
tls-client
tls-remote server
ca /etc/openvpn/certs/ca.crt
cert /etc/openvpn/certs/client.crt
key /etc/openvpn/keys/client.key
port 1195
local 217.xx.xx.xx.xx
remote 217.xx.xx.xx.xx
ifconfig 192.168.5.1 192.168.5.2
route 192.168.0.0 255.255.255.0
writepid /var/run/openvpn_dialin.pid
|
So. Jetzt sollte das ganze soweit sein.
diald, openvpn und capisuite weden per rc-update in das default-profiil gebracht und der Test kann beginnen.
Ich bastle jetzt noch an den Timeout-Einstellungen rum. Eventuell brauche ich für das ifsetup-skript noch einen
Locking-Mechanismus.
Aber zunächst läuft alles mal.
Die Patches versuche grade an die maintainer der Programme weiterzuleiten...
Grüße
dambacher |
|
Back to top |
|
|
dambacher Apprentice
Joined: 11 Feb 2003 Posts: 290 Location: Germany
|
Posted: Fri Dec 30, 2005 9:24 am Post subject: |
|
|
Kann eigentlich jemand dem Forum eine deutsche tippkorrektur einbauen? |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|