1 ## @defgroup on-openvpn Nutzer-Tunnel 2 ## @brief Alles rund um die Nutzertunnel-Verbindung: Tests, Auswahl, Aufbau, Abbau, Portweiterleitungen und Logs. 3 # Beginn der Doku-Gruppe 6 MIG_OPENVPN_DIR=/etc/openvpn/opennet_user
7 MIG_OPENVPN_CONFIG_TEMPLATE_FILE=/usr/share/opennet/openvpn-mig.template
8 # shellcheck disable=SC2034 10 # Pakete mit dieser TOS-Markierung duerfen nicht in den Tunnel 11 # shellcheck disable=SC2034 13 ## Quelldatei für Standardwerte des Nutzer-VPN-Pakets 14 ON_OPENVPN_DEFAULTS_FILE=/usr/share/opennet/openvpn.defaults
15 MIG_PREFERRED_SERVERS_FILE=/var/run/mig-tunnel-
servers.list
16 # shellcheck disable=SC2034 18 # shellcheck disable=SC2034 20 TRACEROUTE_FILENAME=
"traceroute_gw_cache" 23 ## @fn get_on_openvpn_default() 24 ## @brief Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-openvpn). 25 ## @param key Name des Schlüssels 26 ## @sa get_on_core_default 33 ## @fn has_mig_openvpn_credentials() 34 ## @brief Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat. 35 ## @returns Liefert "wahr", falls Schlüssel und Zertifikat vorhanden sind oder 36 ## falls in irgendeiner Form Unklarheit besteht. 39 trap
"" EXIT &&
return 1
43 ## @fn verify_mig_gateways() 44 ## @brief Durchlaufe die Liste aller Internet-Gateway-Dienste und aktualisieren deren Status. 45 ## @see run_cyclic_service_tests 47 local max_fail_attempts
48 local test_period_minutes
55 ## @fn select_mig_connection() 56 ## @brief Aktiviere den angegebenen VPN-Gateway 57 ## @param wanted Name eines Diensts 58 ## @attention Seiteneffekt: Beräumung aller herumliegenden Konfigurationen von alten Verbindungen. 60 trap
'error_trap select_mig_connection "$*"' EXIT
64 # loesche Flags fuer die Vorselektion 66 # erst nach der Abschaltung der alten Dienste wollen wir den neuen Dienst anschalten 67 [
"$one_service" =
"$wanted" ] && found_service=1 &&
continue 68 # alle unerwuenschten Dienste abschalten 75 ## @fn find_and_select_best_gateway() 76 ## @brief Ermittle den besten Gateway und prüfe, ob ein Wechsel sinnvoll ist. 77 ## @param force_switch_now [optional] erzwinge den Wechsel auf den besten Gateway unabhängig von Wartezeiten (true/false) 79 # shellcheck disable=SC2120 81 trap
'error_trap find_and_select_best_gateway "$*"' EXIT
82 local force_switch_now=
"${1:-false}" 86 local current_gateway=
87 local current_priority
89 local switch_candidate_timestamp
91 local bettergateway_timeout
92 now=$(get_uptime_minutes)
94 msg_debug "Trying to find a better gateway" 95 # suche nach dem besten und dem bisher verwendeten Gateway 96 # Ignoriere dabei alle nicht-verwendbaren Gateways. 102 uci_is_false
"$(get_service_value "$service_name
" "status
" "false")" && \
103 msg_debug "$host did not pass the last test" && \
105 # dieser Gateway ist ein valider Kandidat
106 [ -z
"$best_gateway" ] && best_gateway=
"$service_name" &&
continue 107 [ -n
"$(get_openvpn_service_state "$service_name
")" ] && current_gateway=
"$service_name" &&
break 109 if [
"$current_gateway" =
"$best_gateway" ]; then
110 if [ -z
"$current_gateway" ]; then
111 msg_debug "There is still no usable gateway around" 113 # gibt es eine gueltige default-Route? 114 # Auf einem AP mit der v0.5.2 trat einmal eine Situation auf, in der zwei 115 # OpenVPN-Prozesse gleichzeitig gestartet wurden und somit um den 116 # Device-Namensraum (tun0/tun1) konkurrierten. 117 # Am Ende ueberlebte der Prozess mit tun0 - allerdings hatte der tun1-Prozess 118 # zuvor die default-Route ueberschrieben. Dieser Zustand ohne Internetzugang 119 # war als Fehlerzustand nicht zu erkennen. 120 if [ -z
"$(get_target_route_interface 1.1.1.1)" ]; then
121 # Durch aussergewoehnliche Umstaende (siehe oben) gibt es keine 122 # default-Route. Um sicherzugehen, dass wir uns nicht gerade im 123 # Verbindungsaufbau befinden, warten wir noch ein paar Sekunden und 124 # starten anschliessend openvpn neu. 126 [ -n
"$(get_target_route_interface 1.1.1.1)" ] || {
127 # immer noch keine default-Route 128 msg_info "Missing default route detected - restarting openvpn" 129 /etc/init.d/openvpn restart ||
true 133 msg_debug
"Current gateway ($current_gateway) is still the best choice" 134 # Wechselzaehler zuruecksetzen (falls er hochgezaehlt wurde) 139 msg_debug
"Current ($current_gateway) / best ($best_gateway)" 140 # eventuell wollen wir den aktuellen Host beibehalten (sofern er funktioniert und wir nicht zwangsweise wechseln) 141 if [ -n
"$current_gateway" ] \
142 && uci_is_false
"$force_switch_now" \
143 && uci_is_true
"$(get_service_value "$current_gateway
" "status
" "false")"; then
144 # falls der beste und der aktive Gateway gleich weit entfernt sind, bleiben wir beim bisher aktiven 145 current_priority=$(get_service_priority
"$current_gateway")
146 best_priority=$(get_service_priority
"$best_gateway")
147 [
"$current_priority" -eq
"$best_priority" ] \
148 && msg_debug
"Keeping current gateway since the best gateway has the same priority" \
150 # falls der beste und der aktive Gateway gleich weit entfernt sind, bleiben wir beim bisher aktiven 151 # Haben wir einen besseren Kandidaten? Muessen wir den Wechselzaehler aktivieren? 152 # Zaehle hoch bis der switch_candidate_timestamp alt genug ist 153 switch_candidate_timestamp=$(
get_service_value "$current_gateway" "switch_candidate_timestamp")
154 if [ -z
"$switch_candidate_timestamp" ]; then
155 # wir bleiben beim aktuellen Gateway - wir merken uns allerdings den Switch-Zeitstempel 157 msg_debug
"Starting to count down until the switching timer reaches $bettergateway_timeout minutes" 160 # noch nicht alt genug fuer den Wechsel? 161 if ! is_timestamp_older_minutes
"$switch_candidate_timestamp" "$bettergateway_timeout"; then
162 msg_debug
"Counting down further until we reach $bettergateway_timeout minutes" 167 # eventuell kann hier auch ein leerer String uebergeben werden - dann wird kein Gateway aktiviert (korrekt) 168 if [ -n
"$best_gateway" ]; then
169 msg_debug
"Switching gateway from $current_gateway to $best_gateway" 171 msg_debug
"Disabling $current_gateway without a viable alternative" 177 ## @fn get_active_mig_connections() 178 ## @brief Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück. 179 ## @returns Liste der Namen aller Dienste, die aktuell eine aktive VPN-Verbindung halten. 180 ## @attention Diese Funktion braucht recht viel Zeit. 182 trap
'error_trap get_active_mig_connections "$*"' EXIT
185 [
"$(get_openvpn_service_state "$service_name
")" !=
"active" ] || echo
"$service_name" 190 ## @fn get_starting_mig_connections() 191 ## @brief Liefere die im Aufbau befindlichen VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück. 192 ## @returns Liste der Namen aller Dienste, die aktuell beim Verbindungsaufbau sind. 193 ## @attention Diese Funktion braucht recht viel Zeit. 195 trap
'error_trap get_starting_mig_connections "$*"' EXIT
198 [
"$(get_openvpn_service_state "$service_name
")" !=
"connecting" ] || echo
"$service_name" 203 ## @fn reset_mig_connection_test_timestamp() 204 ## @brief Löse eine erneute Prüfung dieses Gateways beim nächsten Prüflauf aus. 205 ## @param service_name Name eines Diensts 206 ## @details Das Löschen des *status_timestamp* Werts führt zu einer 207 ## erneuten Prüfung zum nächstmöglichen Zeitpunkt. 209 local service_name=
"$1" 214 ## @fn reset_all_mig_connection_test_timestamps() 215 ## @brief Löse eine erneute Prüfung aller Gateways zum nächstmöglichen Zeitpunkt aus. 216 ## @sa reset_mig_connection_test_timestamp 225 ## @fn get_mig_connection_test_age() 226 ## @brief Ermittle das Test des letzten Verbindungstests in Minuten. 227 ## @returns Das Alter des letzten Verbindungstests in Minuten oder nichts (falls noch kein Test durchgeführt wurde). 228 ## @details Anhand des Test-Alters lässt sich der Zeitpunkt der nächsten Prüfung abschätzen. 230 local service_name=
"$1" 233 # noch keine Tests durchgefuehrt?
234 [ -z
"$timestamp" ] &&
return 0
235 echo
"$timestamp" "$(get_uptime_minutes)" | awk
'{ print $2 - $1 }' 240 ## @brief Ermittle den Common-Name des Nutzer-Zertifikats. 241 ## @details Liefere eine leere Zeichenkette zurück, falls kein Zertifikat vorhanden ist. 243 [ -e
"$MIG_OPENVPN_DIR/on_aps.crt" ] ||
return 0
244 get_ssl_certificate_cn
"$MIG_OPENVPN_DIR/on_aps.crt" 248 ## @fn get_mig_port_forward_range() 249 ## @brief Liefere den ersten und letzten Port der Nutzertunnel-Portweiterleitung zurück. 250 ## @param client_cn [optional] common name des Nutzer-Zertifikats 251 ## @returns zwei Zahlen durch Tabulatoren getrennt / keine Ausgabe, falls keine Main-ID gefunden wurde 252 ## @details Jeder AP bekommt einen Bereich von zehn Ports fuer die Port-Weiterleitung zugeteilt. 254 trap
'error_trap get_mig_port_forward_range "$*"' EXIT
255 local client_cn=
"${1:-}" 262 [ -z
"$client_cn" ] &&
msg_debug "get_mig_port_forward_range: failed to get Common Name - maybe there is no certificate?" &&
return 0
264 if echo
"$client_cn" | grep -q
'^\(\(1\.\)\?[0-9][0-9]\?[0-9]\?\.aps\.on\)$'; then
266 cn_address=${client_cn%.aps.on}
267 cn_address=${cn_address#*.}
268 elif echo
"$client_cn" | grep -q
'^\([0-9][0-9]\?[0-9]\?\.mobile\.on\)$'; then
270 cn_address=${client_cn%.mobile.on}
271 elif echo
"$client_cn" | grep -q
'^\(2[\._-][0-9][0-9]\?[0-9]\?\.aps\.on\)$'; then
273 cn_address=${client_cn%.aps.on}
274 cn_address=${cn_address#*.}
275 elif echo
"$client_cn" | grep -q
'^\(3[\._-][0-9][0-9]\?[0-9]\?\.aps\.on\)$'; then
277 cn_address=${client_cn%.aps.on}
278 cn_address=${cn_address#*.}
281 if [ -z
"$cn_address" ] || [
"$cn_address" -lt 1 ] || [
"$cn_address" -gt 255 ]; then
282 msg_info "$(basename "$0
"): invalidate certificate Common Name ($client_cn)" 284 first_port=$((portbase + (cn_address-1) * port_count))
285 # output first port and last port
286 printf
'%s\t%s\n' "$first_port" "$((first_port + port_count - 1))" 292 ## @brief Je nach Status des Moduls: prüfe die VPN-Verbindungen bis mindestens eine Verbindung 293 ## aufgebaut wurde bzw. trenne alle Verbindungen. 294 ## @details Diese Funktion sollte regelmäßig als cronjob ausgeführt werden. 297 # die Gateway-Tests sind nur moeglich, falls ein Test-Schluessel vorhanden ist 300 # shellcheck disable=SC2119 309 ## @fn disable_on_openvpn() 310 ## @brief Trenne alle laufenden oder im Aufbau befindlichen Verbindungen. 314 # möglicherweise vorhandene Verbindungen trennen und bei Bedarf openvpn neustarten 319 [
"$changed" =
"0" ] || apply_changes
"openvpn" 323 ## @fn get_mig_tunnel_servers() 324 ## @brief Ermittle die Server für den gewünschen Dienst, die via Tunnel erreichbar sind. 325 ## @params stype Dienst-Typ (z.B. "DNS" oder "NTP") - entspricht den DHCP-Options, die vom OpenVPN-Server gepusht werden. 326 ## @details Die Ausgabe ist leer, falls kein Tunnel aufgebaut ist. 328 trap
'error_trap get_mig_tunnel_server "$*"' EXIT
330 [ -z
"$(get_active_mig_connections)" ] &&
return 0
331 [ -f
"$MIG_PREFERRED_SERVERS_FILE" ] ||
return 0
332 awk <
"$MIG_PREFERRED_SERVERS_FILE" '{ if ($1 == "'"$stype"'") print $2 }' 336 ## @fn get_traceroute_csv() 337 ## @brief Liefere den gecachten Traceroute zum Service zurück 338 ## @param Service Name 339 ## @returns CSV Liste von Hops 341 local service_name=
"$1" 348 # noch keine Tests durchgefuehrt? 349 [ -z
"$traceroute" ] &&
return 0
354 ## @fn update_traceroute_gw_cache() 355 ## @brief Aktualisiere den traceroute zu allen Gateway Servern. 357 trap
'error_trap update_traceroute_gw_cache "$*"' EXIT
362 # do traceroute and get result as csv back 367 # es gab eine Aenderung
368 msg_info "updating traceroute to gateway servers" 372 # Ende der Doku-Gruppe
has_mig_openvpn_credentials()
Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird...
get_mig_port_forward_range(client_cn)
Liefere den ersten und letzten Port der Nutzertunnel-Portweiterleitung zurück.
get_starting_mig_connections()
Liefere die im Aufbau befindlichen VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
disable_on_openvpn()
Trenne alle laufenden oder im Aufbau befindlichen Verbindungen.
find_and_select_best_gateway(force_switch_now)
Ermittle den besten Gateway und prüfe, ob ein Wechsel sinnvoll ist.
update_traceroute_gw_cache()
Aktualisiere den traceroute zu allen Gateway Servern.
filter_reachable_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die erreichbar sind.
set_service_value()
Setzen eines oder mehrerer Werte fuer einen Dienst. Je nach Schluesselname wird der Inhalt in die per...
filter_enabled_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die nicht manuell ausgeblendet wurden...
pipe_service_attribute(key, default)
Liefere zu einer Reihe von Diensten ein gewähltes Attribut dieser Dienste zurück. ...
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
select_mig_connection(wanted)
Aktiviere den angegebenen VPN-Gateway.
run_cyclic_service_tests(test_function)
Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist...
get_mig_tunnel_servers()
Ermittle die Server für den gewünschen Dienst, die via Tunnel erreichbar sind. stype Dienst-Typ (z...
get_traceroute_csv(Service)
Liefere den gecachten Traceroute zum Service zurück.
sort_services_by_priority()
Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste...
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
verify_mig_gateways()
Durchlaufe die Liste aller Internet-Gateway-Dienste und aktualisieren deren Status.
get_traceroute(host)
Liefere einen traceroute zu einem Host zurueck.
reset_all_mig_connection_test_timestamps()
Löse eine erneute Prüfung aller Gateways zum nächstmöglichen Zeitpunkt aus.
get_client_cn()
Ermittle den Common-Name des Nutzer-Zertifikats.
enable_openvpn_service()
Erzeuge eine funktionierende openvpn-Konfiguration (Datei + UCI, service_name).
reset_mig_connection_test_timestamp(service_name)
Löse eine erneute Prüfung dieses Gateways beim nächsten Prüflauf aus.
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
get_active_mig_connections()
Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
set eu uci q show dhcp grep dhcp dnsmasq dns uci true for fname in etc resolv conf tmp resolv conf auto var etc dnsmasq conf var run dnsmasq servers
get_mig_connection_test_age()
Ermittle das Test des letzten Verbindungstests in Minuten.
get_on_openvpn_default()
Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-openvpn, key).
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.
is_on_module_installed_and_enabled(module)
Pruefe ob ein Modul sowohl installiert, als auch aktiv ist.
update_mig_connection_status()