Opennet Firmware
on-openvpn.sh
gehe zur Dokumentation dieser Datei
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
4## @{
5
6MIG_OPENVPN_DIR=/etc/openvpn/opennet_user
7MIG_OPENVPN_CONFIG_TEMPLATE_FILE=/usr/share/opennet/openvpn-mig.template
8# shellcheck disable=SC2034
9DEFAULT_MIG_PORT=1600
10## Quelldatei für Standardwerte des Nutzer-VPN-Pakets
11ON_OPENVPN_DEFAULTS_FILE=/usr/share/opennet/openvpn.defaults
12MIG_PREFERRED_SERVERS_FILE=/var/run/mig-tunnel-servers.list
13# shellcheck disable=SC2034
14ZONE_TUNNEL=on_vpn
15# shellcheck disable=SC2034
16NETWORK_TUNNEL=on_vpn
17TRACEROUTE_FILENAME="traceroute_gw_cache"
19
20## @fn get_on_openvpn_default()
21## @brief Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-openvpn).
22## @param key Name des Schlüssels
23## @sa get_on_core_default
25 local key="$1"
26 _get_file_dict_value "$key" "$ON_OPENVPN_DEFAULTS_FILE"
27}
28
30## @fn has_mig_openvpn_credentials()
31## @brief Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
32## @returns Liefert "wahr", falls Schlüssel und Zertifikat vorhanden sind oder
33## falls in irgendeiner Form Unklarheit besteht.
35 has_openvpn_credentials_by_template "$MIG_OPENVPN_CONFIG_TEMPLATE_FILE" && return 0
36 trap "" EXIT && return 1
37}
38
40## @fn verify_mig_gateways()
41## @brief Durchlaufe die Liste aller Internet-Gateway-Dienste und aktualisieren deren Status.
42## @see run_cyclic_service_tests
44 local max_fail_attempts
45 local test_period_minutes
46 max_fail_attempts=$(get_on_openvpn_default "test_max_fail_attempts")
47 test_period_minutes=$(get_on_openvpn_default "test_period_minutes")
48 get_services "gw" | run_cyclic_service_tests "verify_vpn_connection" "$test_period_minutes" "$max_fail_attempts"
50
51
52## @fn select_mig_connection()
53## @brief Aktiviere den angegebenen VPN-Gateway
54## @param wanted Name eines Diensts
55## @attention Seiteneffekt: Beräumung aller herumliegenden Konfigurationen von alten Verbindungen.
57 trap 'error_trap select_mig_connection "$*"' EXIT
58 local wanted="$1"
59 local found_service=0
60 for one_service in $(get_services "gw"); do
61 # loesche Flags fuer die Vorselektion
62 set_service_value "$one_service" "switch_candidate_timestamp" ""
63 # erst nach der Abschaltung der alten Dienste wollen wir den neuen Dienst anschalten
64 [ "$one_service" = "$wanted" ] && found_service=1 && continue
65 # alle unerwuenschten Dienste abschalten
66 disable_openvpn_service "$one_service" || true
67 done
68 [ "$found_service" = "0" ] || enable_openvpn_service "$wanted" "host"
70
71
72## @fn find_and_select_best_gateway()
73## @brief Ermittle den besten Gateway und prüfe, ob ein Wechsel sinnvoll ist.
74## @param force_switch_now [optional] erzwinge den Wechsel auf den besten Gateway unabhängig von Wartezeiten (true/false)
75## @ref mig-switch
76# shellcheck disable=SC2120
78 trap 'error_trap find_and_select_best_gateway "$*"' EXIT
79 local force_switch_now="${1:-false}"
80 local service_name
81 local host
82 local best_gateway=
83 local current_gateway=
84 local current_priority
85 local best_priority
86 local switch_candidate_timestamp
87 local now
88 local bettergateway_timeout
89 now=$(get_uptime_minutes)
90 bettergateway_timeout=$(get_on_openvpn_default vpn_bettergateway_timeout)
91 msg_debug "Trying to find a better gateway"
92 # suche nach dem besten und dem bisher verwendeten Gateway
93 # Ignoriere dabei alle nicht-verwendbaren Gateways.
94 for service_name in $(get_services "gw" \
98 host=$(get_service_value "$service_name" "host")
99 uci_is_false "$(get_service_value "$service_name" "status" "false")" && \
100 msg_debug "$host did not pass the last test" && \
101 continue
102 # dieser Gateway ist ein valider Kandidat
103 [ -z "$best_gateway" ] && best_gateway="$service_name" && continue
104 [ -n "$(get_openvpn_service_state "$service_name")" ] && current_gateway="$service_name" && break
105 done
106 if [ "$current_gateway" = "$best_gateway" ]; then
107 if [ -z "$current_gateway" ]; then
108 msg_debug "There is still no usable gateway around"
109 else
110 # gibt es eine gueltige default-Route?
111 # Auf einem AP mit der v0.5.2 trat einmal eine Situation auf, in der zwei
112 # OpenVPN-Prozesse gleichzeitig gestartet wurden und somit um den
113 # Device-Namensraum (tun0/tun1) konkurrierten.
114 # Am Ende ueberlebte der Prozess mit tun0 - allerdings hatte der tun1-Prozess
115 # zuvor die default-Route ueberschrieben. Dieser Zustand ohne Internetzugang
116 # war als Fehlerzustand nicht zu erkennen.
117 if [ -z "$(get_target_route_interface 1.1.1.1)" ]; then
118 # Durch aussergewoehnliche Umstaende (siehe oben) gibt es keine
119 # default-Route. Um sicherzugehen, dass wir uns nicht gerade im
120 # Verbindungsaufbau befinden, warten wir noch ein paar Sekunden und
121 # starten anschliessend openvpn neu.
122 sleep 20
123 [ -n "$(get_target_route_interface 1.1.1.1)" ] || {
124 # immer noch keine default-Route
125 msg_info "Missing default route detected - restarting openvpn"
126 /etc/init.d/openvpn restart || true
127 return
128 }
129 fi
130 msg_debug "Current gateway ($current_gateway) is still the best choice"
131 # Wechselzaehler zuruecksetzen (falls er hochgezaehlt wurde)
132 set_service_value "$current_gateway" "switch_candidate_timestamp" ""
133 fi
134 return 0
135 fi
136 msg_debug "Current ($current_gateway) / best ($best_gateway)"
137 # eventuell wollen wir den aktuellen Host beibehalten (sofern er funktioniert und wir nicht zwangsweise wechseln)
138 if [ -n "$current_gateway" ] \
139 && uci_is_false "$force_switch_now" \
140 && uci_is_true "$(get_service_value "$current_gateway" "status" "false")"; then
141 # falls der beste und der aktive Gateway gleich weit entfernt sind, bleiben wir beim bisher aktiven
142 current_priority=$(get_service_priority "$current_gateway")
143 best_priority=$(get_service_priority "$best_gateway")
144 [ "$current_priority" -eq "$best_priority" ] \
145 && msg_debug "Keeping current gateway since the best gateway has the same priority" \
146 && return 0
147 # falls der beste und der aktive Gateway gleich weit entfernt sind, bleiben wir beim bisher aktiven
148 # Haben wir einen besseren Kandidaten? Muessen wir den Wechselzaehler aktivieren?
149 # Zaehle hoch bis der switch_candidate_timestamp alt genug ist
150 switch_candidate_timestamp=$(get_service_value "$current_gateway" "switch_candidate_timestamp")
151 if [ -z "$switch_candidate_timestamp" ]; then
152 # wir bleiben beim aktuellen Gateway - wir merken uns allerdings den Switch-Zeitstempel
153 set_service_value "$current_gateway" "switch_candidate_timestamp" "$now"
154 msg_debug "Starting to count down until the switching timer reaches $bettergateway_timeout minutes"
155 return 0
156 else
157 # noch nicht alt genug fuer den Wechsel?
158 if ! is_timestamp_older_minutes "$switch_candidate_timestamp" "$bettergateway_timeout"; then
159 msg_debug "Counting down further until we reach $bettergateway_timeout minutes"
160 return 0
161 fi
162 fi
163 fi
164 # eventuell kann hier auch ein leerer String uebergeben werden - dann wird kein Gateway aktiviert (korrekt)
165 if [ -n "$best_gateway" ]; then
166 msg_debug "Switching gateway from $current_gateway to $best_gateway"
167 else
168 msg_debug "Disabling $current_gateway without a viable alternative"
169 fi
170 select_mig_connection "$best_gateway"
171}
172
173
174## @fn get_active_mig_connections()
175## @brief Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
176## @returns Liste der Namen aller Dienste, die aktuell eine aktive VPN-Verbindung halten.
177## @attention Diese Funktion braucht recht viel Zeit.
179 trap 'error_trap get_active_mig_connections "$*"' EXIT
180 local service_name
181 for service_name in $(get_services "gw"); do
182 [ "$(get_openvpn_service_state "$service_name")" != "active" ] || echo "$service_name"
183 done
184}
185
186
187## @fn get_starting_mig_connections()
188## @brief Liefere die im Aufbau befindlichen VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
189## @returns Liste der Namen aller Dienste, die aktuell beim Verbindungsaufbau sind.
190## @attention Diese Funktion braucht recht viel Zeit.
192 trap 'error_trap get_starting_mig_connections "$*"' EXIT
193 local service_name
194 for service_name in $(get_services "gw"); do
195 [ "$(get_openvpn_service_state "$service_name")" != "connecting" ] || echo "$service_name"
196 done
197}
198
199
200## @fn reset_mig_connection_test_timestamp()
201## @brief Löse eine erneute Prüfung dieses Gateways beim nächsten Prüflauf aus.
202## @param service_name Name eines Diensts
203## @details Das Löschen des *status_timestamp* Werts führt zu einer
204## erneuten Prüfung zum nächstmöglichen Zeitpunkt.
206 local service_name="$1"
207 set_service_value "$service_name" "status_timestamp" ""
208}
209
210
211## @fn reset_all_mig_connection_test_timestamps()
212## @brief Löse eine erneute Prüfung aller Gateways zum nächstmöglichen Zeitpunkt aus.
213## @sa reset_mig_connection_test_timestamp
215 local service_name
216 for service_name in $(get_services "gw"); do
218 done
219}
220
221
222## @fn get_mig_connection_test_age()
223## @brief Ermittle das Test des letzten Verbindungstests in Minuten.
224## @returns Das Alter des letzten Verbindungstests in Minuten oder nichts (falls noch kein Test durchgeführt wurde).
225## @details Anhand des Test-Alters lässt sich der Zeitpunkt der nächsten Prüfung abschätzen.
227 local service_name="$1"
228 local timestamp
229 timestamp=$(get_service_value "$service_name" "status_timestamp")
230 # noch keine Tests durchgefuehrt?
231 [ -z "$timestamp" ] && return 0
232 echo "$timestamp" "$(get_uptime_minutes)" | awk '{ print $2 - $1 }'
233}
234
235
236## @fn get_client_cn()
237## @brief Ermittle den Common-Name des Nutzer-Zertifikats.
238## @details Liefere eine leere Zeichenkette zurück, falls kein Zertifikat vorhanden ist.
240 [ -e "$MIG_OPENVPN_DIR/on_aps.crt" ] || return 0
241 get_ssl_certificate_cn "$MIG_OPENVPN_DIR/on_aps.crt"
242}
243
244
245## @fn get_mig_port_forward_range()
246## @brief Liefere den ersten und letzten Port der Nutzertunnel-Portweiterleitung zurück.
247## @param client_cn [optional] common name des Nutzer-Zertifikats
248## @returns zwei Zahlen durch Tabulatoren getrennt / keine Ausgabe, falls keine Main-ID gefunden wurde
249## @details Jeder AP bekommt einen Bereich von zehn Ports fuer die Port-Weiterleitung zugeteilt.
251 trap 'error_trap get_mig_port_forward_range "$*"' EXIT
252 local client_cn="${1:-}"
253 [ -z "$client_cn" ] && client_cn=$(get_client_cn)
254 local port_count=10
255 local cn_address=
256 local portbase
257 local first_port
258
259 [ -z "$client_cn" ] && msg_debug "get_mig_port_forward_range: failed to get Common Name - maybe there is no certificate?" && return 0
260
261 if echo "$client_cn" | grep -q '^\‍(\‍(1\.\‍)\?[0-9][0-9]\?[0-9]\?\.aps\.on\‍)$'; then
262 portbase=10000
263 cn_address=${client_cn%.aps.on}
264 cn_address=${cn_address#*.}
265 elif echo "$client_cn" | grep -q '^\‍([0-9][0-9]\?[0-9]\?\.mobile\.on\‍)$'; then
266 portbase=12550
267 cn_address=${client_cn%.mobile.on}
268 elif echo "$client_cn" | grep -q '^\‍(2[\._-][0-9][0-9]\?[0-9]\?\.aps\.on\‍)$'; then
269 portbase=15100
270 cn_address=${client_cn%.aps.on}
271 cn_address=${cn_address#*.}
272 elif echo "$client_cn" | grep -q '^\‍(3[\._-][0-9][0-9]\?[0-9]\?\.aps\.on\‍)$'; then
273 portbase=20200
274 cn_address=${client_cn%.aps.on}
275 cn_address=${cn_address#*.}
276 fi
277
278 if [ -z "$cn_address" ] || [ "$cn_address" -lt 1 ] || [ "$cn_address" -gt 255 ]; then
279 msg_info "$(basename "$0"): invalidate certificate Common Name ($client_cn)"
280 else
281 first_port=$((portbase + (cn_address-1) * port_count))
282 # output first port and last port
283 printf '%s\t%s\n' "$first_port" "$((first_port + port_count - 1))"
284 fi
285}
286
287
288## @fn update_mig_connection_status()
289## @brief Je nach Status des Moduls: prüfe die VPN-Verbindungen bis mindestens eine Verbindung
290## aufgebaut wurde bzw. trenne alle Verbindungen.
291## @details Diese Funktion sollte regelmäßig als cronjob ausgeführt werden.
293 if is_on_module_installed_and_enabled "on-openvpn"; then
294 # die Gateway-Tests sind nur moeglich, falls ein Test-Schluessel vorhanden ist
297 # shellcheck disable=SC2119
299 fi
300 else
302 fi
303}
304
305
306## @fn disable_on_openvpn()
307## @brief Trenne alle laufenden oder im Aufbau befindlichen Verbindungen.
309 local service_name
310 local changed=0
311 # möglicherweise vorhandene Verbindungen trennen und bei Bedarf openvpn neustarten
313 disable_openvpn_service "$service_name"
314 changed=1
315 done
316 [ "$changed" = "0" ] || apply_changes "openvpn"
317}
318
319
320## @fn get_mig_tunnel_servers()
321## @brief Ermittle die Server für den gewünschen Dienst, die via Tunnel erreichbar sind.
322## @param stype Dienst-Typ (z.B. "DNS" oder "NTP") - entspricht den DHCP-Options, die vom OpenVPN-Server gepusht werden.
323## @details Die Ausgabe ist leer, falls kein Tunnel aufgebaut ist.
325 trap 'error_trap get_mig_tunnel_server "$*"' EXIT
326 local stype="$1"
327 [ -z "$(get_active_mig_connections)" ] && return 0
328 [ -f "$MIG_PREFERRED_SERVERS_FILE" ] || return 0
329 awk <"$MIG_PREFERRED_SERVERS_FILE" '{ if ($1 == "'"$stype"'") print $2 }'
330}
331
332
333## @fn get_traceroute_csv()
334## @brief Liefere den gecachten Traceroute zum Service zurück
335## @param Service Name
336## @returns CSV Liste von Hops
338 local service_name="$1"
339 local traceroute
340 local host
341
342 host=$(get_service_value "$service_name" "host")
343 traceroute=$(get_service_value "$TRACEROUTE_FILENAME" "$host")
344
345 # noch keine Tests durchgefuehrt?
346 [ -z "$traceroute" ] && return 0
347 echo "$traceroute"
348}
349
350
351## @fn update_traceroute_gw_cache()
352## @brief Aktualisiere den traceroute zu allen Gateway Servern.
354 trap 'error_trap update_traceroute_gw_cache "$*"' EXIT
355 local host
356 local traceroute
357
358 for host in $(get_services "gw" | pipe_service_attribute "host" | cut -f 2- | sort | uniq); do
359 # do traceroute and get result as csv back
360 traceroute=$(get_traceroute "$host")
361 # update cache file
362 set_service_value "$TRACEROUTE_FILENAME" "$host" "$traceroute"
363 done
364 # es gab eine Aenderung
365 msg_info "updating traceroute to gateway servers"
366}
367
368
369# Ende der Doku-Gruppe
370## @}
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
Definition: dns:14
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
Definition: core.sh:85
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
Definition: core.sh:9
key
Definition: core.sh:85
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
Definition: core.sh:15
done
Definition: core.sh:85
is_on_module_installed_and_enabled(module)
Pruefe ob ein Opennet-Modul sowohl installiert, als auch aktiviert ist.
Definition: modules.sh:9
get_on_openvpn_default()
Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-openvpn, key).
Definition: on-openvpn.sh:9
verify_mig_gateways()
Durchlaufe die Liste aller Internet-Gateway-Dienste und aktualisieren deren Status.
Definition: on-openvpn.sh:18
get_mig_port_forward_range(client_cn)
Liefere den ersten und letzten Port der Nutzertunnel-Portweiterleitung zurück.
Definition: on-openvpn.sh:64
update_traceroute_gw_cache()
Aktualisiere den traceroute zu allen Gateway Servern.
Definition: on-openvpn.sh:85
get_traceroute_csv(Service)
Liefere den gecachten Traceroute zum Service zurück.
Definition: on-openvpn.sh:82
get_client_cn()
Ermittle den Common-Name des Nutzer-Zertifikats.
Definition: on-openvpn.sh:58
reset_mig_connection_test_timestamp(service_name)
Löse eine erneute Prüfung dieses Gateways beim nächsten Prüflauf aus.
Definition: on-openvpn.sh:45
disable_on_openvpn()
Trenne alle laufenden oder im Aufbau befindlichen Verbindungen.
Definition: on-openvpn.sh:72
get_mig_connection_test_age()
Ermittle das Test des letzten Verbindungstests in Minuten.
Definition: on-openvpn.sh:54
find_and_select_best_gateway(force_switch_now)
Ermittle den besten Gateway und prüfe, ob ein Wechsel sinnvoll ist.
Definition: on-openvpn.sh:29
reset_all_mig_connection_test_timestamps()
Löse eine erneute Prüfung aller Gateways zum nächstmöglichen Zeitpunkt aus.
Definition: on-openvpn.sh:49
get_active_mig_connections()
Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
Definition: on-openvpn.sh:34
update_mig_connection_status()
Je nach Status des Moduls: prüfe die VPN-Verbindungen bis mindestens eine Verbindung aufgebaut wurde ...
Definition: on-openvpn.sh:69
has_mig_openvpn_credentials()
Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
Definition: on-openvpn.sh:14
get_starting_mig_connections()
Liefere die im Aufbau befindlichen VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
Definition: on-openvpn.sh:39
select_mig_connection(wanted)
Aktiviere den angegebenen VPN-Gateway.
Definition: on-openvpn.sh:23
get_mig_tunnel_servers(stype)
Ermittle die Server für den gewünschen Dienst, die via Tunnel erreichbar sind.
Definition: on-openvpn.sh:77
has_openvpn_credentials_by_template(template_file)
Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
Definition: openvpn.sh:54
disable_openvpn_service(service_name)
Löschung einer openvpn-Verbindung.
Definition: openvpn.sh:19
enable_openvpn_service()
Erzeuge eine funktionierende openvpn-Konfiguration (Datei + UCI, service_name).
Definition: openvpn.sh:9
get_traceroute(host)
Liefere einen traceroute zu einem Host zurueck.
Definition: routing.sh:66
sort_services_by_priority()
Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste.
Definition: services.sh:37
run_cyclic_service_tests(test_function)
Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist.
Definition: services.sh:177
pipe_service_attribute(key, default)
Liefere zu einer Reihe von Diensten ein gewähltes Attribut dieser Dienste zurück.
Definition: services.sh:63
filter_enabled_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die nicht manuell ausgeblendet wurden.
Definition: services.sh:49
set_service_value()
Setzen eines oder mehrerer Werte fuer einen Dienst. Je nach Schluesselname wird der Inhalt in die per...
Definition: services.sh:79
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird,...
Definition: services.sh:68
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
Definition: services.sh:86
filter_reachable_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die erreichbar sind.
Definition: services.sh:44