1 ## @defgroup openvpn OpenVPN (allgemein) 2 ## @brief Vorbereitung, Konfiguration und Prüfung von VPN-Verbindungen (z.B. für Nutzertunnel oder UGW). 3 # Beginn der openvpn-Doku-Gruppe 7 OPENVPN_CONFIG_BASEDIR=/var/etc/openvpn
10 ## @fn enable_openvpn_service() 11 ## @brief Erzeuge eine funktionierende openvpn-Konfiguration (Datei + UCI). 12 ## @param service_name Name eines Dienstes 13 ## @details Die Konfigurationsdatei wird erzeugt und eine openvpn-uci-Konfiguration wird angelegt. 14 ## Falls zu diesem openvpn-Dienst kein Zertifikat oder kein Schlüssel gefunden wird, dann passiert nichts. 16 trap
'error_trap enable_openvpn_service "$*"' EXIT
17 local service_name=
"$1" 18 local config_file=
"$OPENVPN_CONFIG_BASEDIR/${service_name}.conf" 20 msg_info "Refuse to enable openvpn server ('$service_name'): missing key or certificate" 21 trap
"" EXIT &&
return 1
23 local uci_prefix=
"openvpn.$service_name" 24 # zukuenftige config-Datei referenzieren 26 # zuvor ankuendigen, dass zukuenftig diese uci-Konfiguration an dem Dienst haengt 27 service_add_uci_dependency
"$service_name" "$uci_prefix" 28 # lege die uci-Konfiguration an und aktiviere sie 29 uci
set "${uci_prefix}=openvpn" 30 uci
set "${uci_prefix}.enabled=1" 31 uci
set "${uci_prefix}.config=$config_file" 36 ## @fn update_vpn_config() 37 ## @brief Schreibe eine openvpn-Konfigurationsdatei. 38 ## @param service_name Name eines Dienstes 40 trap
'error_trap update_vpn_config "$*"' EXIT
41 local service_name=
"$1" 42 local config_file=
"$2" 43 service_add_file_dependency
"$service_name" "$config_file" 44 # Konfigurationsdatei neu schreiben 45 mkdir -p
"$(dirname "$config_file
")" 50 ## @fn disable_openvpn_service() 51 ## @brief Löschung einer openvpn-Verbindung 52 ## @param service_name Name eines Dienstes 53 ## @details Die UCI-Konfiguration, sowie alle anderen mit der Verbindung verbundenen Elemente werden entfernt. 54 ## Die openvpn-Verbindung bleibt bestehen, bis zum nächsten Aufruf von 'apply_changes openvpn'. 56 trap
'error_trap disable_openvpn_service "$*"' EXIT
57 local service_name=
"$1" 58 # Abbruch, falls es keine openvpn-Instanz gibt 59 [ -z
"$(uci_get "openvpn.$service_name
")" ] &&
return 0
60 # openvpn wird automatisch neugestartet 61 cleanup_service_dependencies
"$service_name" 62 # nach einem reboot sind eventuell die dependencies verlorengegangen - also loeschen wir manuell 67 ## @fn get_openvpn_service_state() 68 ## @brief Prüfe ob eine openvpn-Verbindung besteht bzw. im Aufbau ist. 69 ## @param service_name Name eines Dienstes 70 ## @details Die Prüfung wird anhand der PID-Datei und der Gültigkeit der enthaltenen PID vorgenommen. 71 ## @returns "active", "connecting" oder einen leeren String (unbekannt, bzw. keine Verbindung). 73 trap
'error_trap get_openvpn_service_state "$*"' EXIT
74 local service_name=
"$1" 76 # existiert ein VPN-Eintrag? 77 [ -z
"$(uci_get "openvpn.$service_name
")" ] &&
return 78 # gibt es einen Verweis auf eine passende PID-Datei? 80 if check_pid_file
"$pid_file" "openvpn"; then
81 # Die "openvpn_established_indicator_file"-Variable wird vom up/down-Skript erzeugt. 82 # Die Variable verweist ebenfalls auf eine Datei mit der PID. Dies erlaubt die Unterscheidung 83 # einer Verbindung im Aufbau (bzw. in der Phase einer wiederholten Ablehnung) von einer 84 # beiderseits akzeptierten Datenverbindung. Dies ist insbesondere fuer die mesh-VPN-Verbindungen 85 # sinnvoll, da hier mehr Toleranz beim Verbindungsaufbau sinnvoll ist. 86 if check_pid_file
"$(get_service_value "$service_name
" "openvpn_established_indicator_file
")" "openvpn"; then
97 ## @fn _change_openvpn_config_setting() 98 ## @brief Ändere eine Einstellung in einer openvpn-Konfigurationsdatei. 99 ## @param config_file Name der Konfigurationsdatei. 100 ## @param config_key Name der openvpn-Einstellung. 101 ## @param config_value Neuer Inhalt der Einstellung - die Einstellung wird gelöscht, falls dieser Parameter fehlt oder leer ist. 102 ## @attention OpenVPN-Optionen ohne Parameter (z.B. --mtu-test) können nicht mittels dieser Funktion gesetzt werden. 104 local config_file=
"$1" 105 local config_key=
"$2" 106 local config_value=
"${3:-}" 107 sed -i
"/^$config_key"'[\t ]/d' "$config_file" 108 [ -n
"$config_value" ] && echo
"$config_key $config_value" >>
"$config_file" 113 ## @fn get_openvpn_config() 114 ## @brief liefere openvpn-Konfiguration eines Dienstes zurück 115 ## @param service_name Name eines Dienstes 117 trap
'error_trap get_openvpn_config "$*"' EXIT
118 local service_name=
"$1" 124 local proxy_service_type
125 local relayed_service
128 # Falls es sich um einen relay-Dienst handelt, koennen wir uns leider nicht mit uns selbst verbinden, 129 # da die firewall-redirect-Regeln keine "device"-Quelle kennen (anstelle des ueblichen "on_mesh"). 130 if [
"$remote" =
"$(get_main_ip)" ]; then
131 proxy_service_type=
"$RELAYABLE_SERVICE_PREFIX$(get_service_value "$service_name
" "service
")" 133 if [ -n
"$relayed_service" ]; then
134 # Hostname und Port ersetzen 138 msg_info "Failed to use locally relayed service for openvpn - trying to continue, anyway." 144 # schreibe die Konfigurationsdatei
145 echo
"# automatically generated by $0" 146 echo
"remote $remote $port $protocol" 147 echo
"writepid $pid_file" 149 # sicherstellen, dass die Konfigurationsdatei mit einem Zeilenumbruch endet (fuer
"echo >> ...")
154 ## @fn verify_vpn_connection() 155 ## @brief Prüfe einen VPN-Verbindungsaufbau 156 ## @param service_name Name eines Dienstes 157 ## @param key [optional] Schluesseldatei: z.B. $VPN_DIR/on_aps.key 158 ## @param cert [optional] Zertifikatsdatei: z.B. $VPN_DIR/on_aps.crt 159 ## @returns Exitcode=0 falls die Verbindung aufgebaut werden konnte 161 trap
'error_trap verify_vpn_connection "$*"' EXIT
162 local service_name=
"$1" 163 local key_file=
"${2:-}" 164 local cert_file=
"${3:-}" 168 config_file=$(mktemp -t
"VERIFY-${service_name}-XXXXXXX")
170 # wir benoetigen die template-Datei fuer das Erzeugen der Basis-Konfiguration 171 msg_debug "start vpn test of $service_name" 172 # erstelle die config-Datei 174 # filtere Einstellungen heraus, die wir ueberschreiben wollen 175 # nie die echte PID-Datei ueberschreiben (falls ein Prozess laeuft) 178 # some openvpn options: 179 # ifconfig-noexec: we do not want to configure a device (and mess up routing tables) 180 # route-noexec: keinerlei Routen hinzufuegen 181 echo
"ifconfig-noexec" 184 # some timing options: 185 # inactive: close connection after 15s without traffic 186 # ping-exit: close connection after 15s without a ping from the other side (which is probably disabled) 187 echo
"inactive 15 1000000" 191 # verb: verbose level 3 is required for the TLS messages 192 # nice: testing is not too important 193 # resolv-retry: fuer ipv4/ipv6-Tests sollten wir mehrere Versuche zulassen 196 echo
"resolv-retry 3" 198 # prevent a real connection (otherwise we may break our current vpn tunnel): 199 # tls-exit: stop immediately after tls handshake failure 200 # remote-cert-tls: enforce a connection against a server certificate (instead of peer-to-peer) 202 echo
"remote-cert-tls server" 206 # kein Netzwerkinterface erzeugen
208 # keine PID-Datei anlegen
210 # keine Netzwerkkonfiguration via up/down
213 # TLS-Pruefung immer fehlschlagen lassen
218 # nur fuer tcp-Verbindungen (ipv4/ipv6)
219 # connect-retry: Sekunden Wartezeit zwischen Versuchen 220 # connect-retry-max: Anzahl moeglicher Wiederholungen 221 if grep -q
"^remote.*tcp" "$config_file"; then
223 echo
"connect-retry 1" 224 echo
"connect-retry-max 1" 228 # Short timeout for connections (default: 120s) - otherwise the 45s timeout below allows 229 # only _one_ attempt. But we need at least two in order to try IPv4 and IPv6 connections. 230 echo
"connect-timeout 12" >>
"$config_file" 232 # Schluessel und Zertifikate bei Bedarf austauschen 233 [ -n
"$key_file" ] && \
234 _change_openvpn_config_setting
"$config_file" "key" "$key_file" 235 [ -n
"$cert_file" ] && \
236 _change_openvpn_config_setting
"$config_file" "cert" "$cert_file" 238 # Aufbau der VPN-Verbindung bis zum Timeout oder bis zum Verbindungsabbruch via "tls-exit" (/bin/false) 239 # Die Begrenzung durch "timeout" scheint für "unreachable" IPv6-Ziele notwendig zu sein. 240 # Andernfalls wartet der Prozess ewig. 241 timeout 45s openvpn --config
"$config_file" ||
true 242 # read the additional options from the config file (for debug purposes) 243 file_opts=$(grep -v
"^$" "$config_file" | grep -v
"^#" | sed
's/^/--/' | tr
'\n' ' ')
245 if [ -e
"$log_file" ]; then
246 grep -q
"Initial packet" "$log_file" &&
return 0
247 msg_debug "openvpn test failed: openvpn $file_opts" 249 # Die Log-Datei sollte nur dann fehlen, wenn die openvpn-Konfiguration defekt ist 250 # und somit den Start von openvpn verhindert. 251 msg_error "openvpn test failed unexpectedly: configuration error?" 253 trap
"" EXIT &&
return 1
257 ## @fn openvpn_service_has_certificate_and_key() 258 ## @brief Prüfe ob das Zertifikat eines openvpn-basierten Diensts existiert. 259 ## @returns exitcode=0 falls das Zertifikat existiert 260 ## @details Falls der Ort der Zertifikatsdatei nicht zweifelsfrei ermittelt 261 ## werden kann, dann liefert die Funktion "wahr" zurück. 263 local service_name=
"$1" 266 local config_template
268 # im Zweifelsfall (kein Template gefunden) liefern wir
"wahr" 269 [ -z
"$config_template" ] &&
return 0
270 # Verweis auf lokale config-Datei (keine uci-basierte Konfiguration) 271 if [ -e
"$config_template" ]; then
275 # im Zweifelsfall: liefere "wahr" 278 # das Zertifikat scheint irgendwie anders konfiguriert zu sein - im Zeifelsfall: OK 279 if [ -z
"$cert_file" ] || [ -z
"$key_file" ]; then
281 elif [ -e
"$cert_file" ] && [ -e
"$key_file" ]; then
282 # alle relevanten Dateien existieren 285 trap
"" EXIT &&
return 1
290 ## @fn has_openvpn_credentials_by_template() 291 ## @brief Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat. 292 ## @param template_file Name einer openvpn-Konfigurationsdatei (oder einer Vorlage). Aus dieser Datei werden "cert"- und "key"-Werte entnommen. 293 ## @returns Liefert "wahr", falls Schlüssel und Zertifikat vorhanden sind oder falls in irgendeiner Form Unklarheit besteht. 295 trap
'error_trap has_openvpn_credentials_by_template "$*"' EXIT
296 local template_file=
"$1" 302 # Pruefe, ob eine "cd"-Direktive enthalten ist - vervollständige damit relative Pfade 304 [ -n
"$base_dir" ] && [
"${cert_file:0:1}" !=
"/" ] && cert_file=
"$base_dir/$cert_file" 305 [ -n
"$base_dir" ] && [
"${key_file:0:1}" !=
"/" ] && key_file=
"$base_dir/$key_file" 306 # im Zweifel: liefere
"wahr" 307 if [ -z
"$key_file" ] || [ -z
"$cert_file" ]; then
309 elif [ -e
"$key_file" ] && [ -e
"$cert_file" ]; then
310 # beide Dateien existieren 313 trap
"" EXIT &&
return 1
318 ## @fn log_openvpn_events_and_disconnect_if_requested() 319 ## @brief Allgemeines Ereignisbehandlung fuer openvpn-Verbindungen: Logging und eventuell Dienst-Bereinigung (nur für "down"). 320 ## @details Alle Informationen (bis auf das Log-Ziel) werden aus den Umgebungsvariablen gezogen, die openvpn in 321 ## seinen Ereignisskripten setzt. 323 local log_target=
"$1" 324 # die config-Datei enthaelt den Dienst-Namen 327 local established_indicator_file
331 local same_host_service
332 # die folgenden Variablen stammen aus der OpenVPN-Umgebung 334 script_type=${script_type:-}
335 remote_1=${remote_1:-}
336 remote_port_1=${remote_port_1:-}
337 daemon_start_time=${daemon_start_time:-}
339 service_name=$(basename
"${config%.conf}")
341 established_indicator_file=$(
get_service_value "$service_name" "openvpn_established_indicator_file")
342 if [ -z
"$established_indicator_file" ] && [ -n
"$pid_file" ]; then
343 established_indicator_file=
"${pid_file}.established" 344 set_service_value "$service_name" "openvpn_established_indicator_file" "$established_indicator_file" 346 case "$script_type" in
349 [ -n
"$pid_file" ] && cat
"$pid_file" >
"$established_indicator_file" 353 # der openwrt-Build von openvpn setzt wohl leider nicht die
"time_duration"-Umgebungsvariable
354 [ -z
"${time_duration:-}" ] && time_duration=$(($(date +%s) - daemon_start_time))
355 # Verbindungsverlust durch fehlende openvpn-Pings? 356 if [
"${signal:-}" =
"ping-restart" ]; then
359 now=$(get_uptime_minutes)
361 "Lost connection with ${remote_1}:${remote_port_1} after ${time_duration}s" 362 # alle Verbindungen derselben Art zu diesem Host als unklar definieren
363 for same_host_service in $(
get_services "$service_type" \
369 [ -n
"$pid_file" ] && rm -f
"$pid_file" 370 [ -n
"$established_indicator_file" ] && rm -f
"$established_indicator_file" 374 "Closing connection with ${remote_1}:${remote_port_1} after ${time_duration}s" 384 ## @fn get_openvpn_service_pid_file() 385 ## @param Name eines Diensts 386 ## @brief PID-Datei für diesen Dienst ausgeben. 388 local service_name=
"$1" 389 echo
"/var/run/${service_name}.pid" 393 ## @fn get_openvpn_service_template_filename() 394 ## @param Name des Diensts 395 ## @brief Dateiname der Konfigurationsvorlage dieses Diensts ausgeben. 397 trap
'error_trap get_openvpn_service_template_filename "$*"' EXIT
398 local service_name=
"$1" 401 # Diese Stelle ist hier eigentlich falsch, da sie Kenntnisse und Variablen
402 # vorraussetzt, die nicht in
"on-core" definiert sind.
403 # Aufgrund der Wiederverwendung der generischen
404 #
"run_cyclic_service_tests"-Funktion ist eine Separierung dieser Auswahl
405 # jedoch leider nur mit großem Aufwand möglich.
406 if [
"$service_type" =
"gw" ]; then
407 echo
"$MIG_OPENVPN_CONFIG_TEMPLATE_FILE" 408 elif [
"$service_type" =
"mesh" ]; then
409 echo
"$MESH_OPENVPN_CONFIG_TEMPLATE_FILE" 411 msg_error "unknown service type for openvpn config preparation: $service_type" 412 trap
"" EXIT &&
return 1
417 ## @fn openvpn_get_mtu() 418 ## @brief Ermittle die MTU auf dem Weg zum Anbieter des Diensts. 419 ## @details The output can be easily parsed via 'cut'. Even the full status output of openvpn is safe for parsing since potential tabulator characters are removed. 420 ## @returns One line consisting of five fields separated by tab characters is returned (tried_to_remote real_to_remote tried_from_remote real_from_remote full_status_output). Failed tests are indicated by an empty result. 422 # TODO: dies ist ein (schlechter) Workaround für einen Fehler der MTU-Prüfung seit OpenVPN v2.4 423 # siehe https://dev.opennet-initiative.de/ticket/210 und https://community.openvpn.net/openvpn/ticket/1103 424 printf
'%d\t%d\t%d\t%d\t%s' 1520 1520 1493 1494
"Empirical MTU test completed [Tried,Actual] local->remote=[1520,1520] remote->local=[1493,1493]" 427 trap
'error_trap openvpn_get_mtu "$*"' EXIT
428 local service_name=
"$1" 433 config_file=$(mktemp -t
"MTU-${service_name}-XXXXXXX")
435 log_file=
"$(get_service_log_filename "$service_name
" "openvpn
" "mtu
")" 440 # kein Netzwerk konfigurieren 441 echo
"ifconfig-noexec" 445 # kein Netzwerkinterface, keine pid-Datei
457 openvpn --mtu-test --config
"$config_file" 2>&1 &
458 # warte auf den Startvorgang
462 pid=$(cat
"$pid_file" 2>/dev/
null ||
true)
464 local mtu_out_filtered
465 while [
"$wait_loops" -gt 0 ];
do 466 # keine Fehlermeldungen (-s) falls die Log-Datei noch nicht existiert 467 mtu_out=$(grep -s
"MTU test completed" "$log_file" ||
true)
469 # Thu Jul 3 22:23:01 2014 NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[1573,1573] remote->local=[1573,1573]
470 if [ -n
"$mtu_out" ]; then
471 # Ausgabe der vier Zahlen getrennt durch Tabulatoren
472 mtu_out_filtered=
"$(echo "$mtu_out
" | tr '[' ',' | tr ']' ',')" 473 # Leider koennen wir nicht alle Felder auf einmal ausgeben (tab-getrennt),
474 # da das busybox-cut nicht den --output-delimiter unterstützt. 475 echo
"$mtu_out_filtered" | cut -
d , -f 5 | tr
'\n' '\t' 476 echo
"$mtu_out_filtered" | cut -
d , -f 6 | tr
'\n' '\t' 477 echo
"$mtu_out_filtered" | cut -
d , -f 8 | tr
'\n' '\t' 478 echo
"$mtu_out_filtered" | cut -
d , -f 9 | tr
'\n' '\t' 479 # wir ersetzen alle eventuell vorhandenen Tabulatoren in der Statusausgabe - zur Vereinfachung des Parsers 480 echo -n
"$mtu_out" | tr
'\t' ' ' 482 elif [ -z
"$pid" ] || [ ! -d
"/proc/$pid" ]; then
483 msg_info "Failed to verify MTU resctrictions for '$host'" 487 wait_loops=$((wait_loops - 1))
489 # sicherheitshalber brechen wir den Prozess ab und loeschen alle Dateien 490 kill
"$pid" >/dev/
null 2>&1 ||
true 491 rm -f
"$config_file" "$pid_file" 492 # ist der Zaehler abgelaufen? 493 [
"$wait_loops" -eq 0 ] &&
msg_info "Timeout for openvpn_get_mtu '$host' - aborting." 498 ## @fn cleanup_stale_openvpn_services() 499 ## @brief Beräumung liegengebliebener openvpn-Konfigurationen, sowie Deaktivierung funktionsunfähiger Verbindungen. 500 ## @details Verwaiste openvpn-Konfigurationen können aus zwei Grunden auftreten: 501 ## 1) nach einem reboot wurde nicht die zuletzt aktive openvpn-Verbindung ausgewählt - somit 502 ## bleibt der vorher aktive uci-Konfigurationseintrag erhalten 503 ## 2) ein VPN-Verbindungsaufbau scheitert und hinterlässt einen uci-Eintrag, eine PID-Datei, 504 ## jedoch keinen laufenden Prozess 505 ## Achtung: falls eine Verbindung sich gerade im Aufbau befindet, wird ihre Konfiguration 506 ## ebenfalls entfernt. Diese Funktion sollte also nur in ausgewählten Situation 507 ## aufgerufen werden (nach einem Reboot und nach einem Verbindungsabbruch). 509 trap
'error_trap cleanup_stale_openvpn_services "$*"' EXIT
514 for uci_prefix in $(find_all_uci_sections
"openvpn" "openvpn");
do 515 config_file=$(uci_get
"${uci_prefix}.config")
516 # Keine config-Datei? Keine von uns verwaltete Konfiguration ...
517 [ -z
"$config_file" ] &&
continue 518 service_name=
"${uci_prefix#openvpn.}" 519 # Es scheint sich um eine von uns verwaltete Verbindung zu handeln.
521 # Falls die config-Datei oder die pid-Datei fehlt, dann ist es ein reboot-Fragment. Wir löschen die Überreste. 522 if [ ! -e
"$config_file" ] || [ ! -e
"$pid_file" ]; then
523 msg_info "Removing a reboot-fragment of a previously used openvpn connection: $service_name" 525 elif check_pid_file
"$pid_file" "openvpn"; then
526 # Prozess läuft - alles gut 529 # Falls die PID-Datei existiert, jedoch veraltet ist (kein dazugehöriger Prozess läuft), dann 530 # schlug der Verbindungsaufbau fehlt (siehe "tls-exit" und "single-session"). 531 # Wir markieren die Verbindung als kaputt. 532 msg_info "Marking a possibly interrupted openvpn connection as broken: $service_name" 537 apply_changes openvpn
540 # Ende der openvpn-Doku-Gruppe uci_delete(uci_path)
Lösche ein UCI-Element.
get_service_log_filename()
Ermittle den Namen der Log-Datei für diesen Dienst. Zusätzliche Details (z.B. "openvpn mtu"...
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird...
_change_openvpn_config_setting(config_file, config_key, config_value)
Ändere eine Einstellung in einer openvpn-Konfigurationsdatei.
openvpn_get_mtu()
Ermittle die MTU auf dem Weg zum Anbieter des Diensts.
append_to_custom_log(log_name, event)
Hänge eine neue Nachricht an ein spezfisches Protokoll an.
cleanup_stale_openvpn_services()
Beräumung liegengebliebener openvpn-Konfigurationen, sowie Deaktivierung funktionsunfähiger Verbindun...
get_openvpn_config(service_name)
liefere openvpn-Konfiguration eines Dienstes zurück
update_vpn_config(service_name)
Schreibe eine openvpn-Konfigurationsdatei.
set_service_value()
Setzen eines oder mehrerer Werte fuer einen Dienst. Je nach Schluesselname wird der Inhalt in die per...
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
log_openvpn_events_and_disconnect_if_requested()
Allgemeines Ereignisbehandlung fuer openvpn-Verbindungen: Logging und eventuell Dienst-Bereinigung (n...
get_openvpn_service_pid_file(Name)
PID-Datei für diesen Dienst ausgeben.
filter_services_by_value(key, value)
set eu grep root::etc shadow exit if command v chpasswd dev null
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
openvpn_service_has_certificate_and_key()
Prüfe ob das Zertifikat eines openvpn-basierten Diensts existiert.
get_openvpn_service_state(service_name)
Prüfe ob eine openvpn-Verbindung besteht bzw. im Aufbau ist.
enable_openvpn_service()
Erzeuge eine funktionierende openvpn-Konfiguration (Datei + UCI, service_name).
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
get_openvpn_service_template_filename(Name)
Dateiname der Konfigurationsvorlage dieses Diensts ausgeben.
set eu on function print_services services log for dir in etc on services d var on services volatile d
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
verify_vpn_connection(service_name, key, cert)
Prüfe einen VPN-Verbindungsaufbau.
msg_error(message)
Die Fehlermeldungen werden in die Standard-Fehlerausgabe und ins syslog geschrieben.
has_openvpn_credentials_by_template(template_file)
Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
disable_openvpn_service(service_name)
Löschung einer openvpn-Verbindung.