Opennet Firmware
 Alle Dateien Funktionen Variablen Gruppen Seiten
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 
6 MIG_OPENVPN_DIR=/etc/openvpn/opennet_user
7 MIG_OPENVPN_CONFIG_TEMPLATE_FILE=/usr/share/opennet/openvpn-mig.template
8 DEFAULT_MIG_PORT=1600
9 # Pakete mit dieser TOS-Markierung duerfen nicht in den Tunnel
10 TOS_NON_TUNNEL=8
11 ## Quelldatei für Standardwerte des Nutzer-VPN-Pakets
12 ON_OPENVPN_DEFAULTS_FILE=/usr/share/opennet/openvpn.defaults
13 MIG_PREFERRED_SERVERS_FILE=/var/run/mig-tunnel-servers.list
14 ZONE_TUNNEL=on_vpn
15 NETWORK_TUNNEL=on_vpn
16 
17 
18 ## @fn get_on_openvpn_default()
19 ## @brief Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-openvpn).
20 ## @param key Name des Schlüssels
21 ## @sa get_on_core_default
23  local key="$1"
24  _get_file_dict_value "$key" "$ON_OPENVPN_DEFAULTS_FILE"
25 }
26 
27 
28 ## @fn has_mig_openvpn_credentials()
29 ## @brief Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
30 ## @returns Liefert "wahr", falls Schlüssel und Zertifikat vorhanden sind oder
31 ## falls in irgendeiner Form Unklarheit besteht.
33  has_openvpn_credentials_by_template "$MIG_OPENVPN_CONFIG_TEMPLATE_FILE" && return 0
34  trap "" $GUARD_TRAPS && return 1
35 }
36 
37 
38 ## @fn verify_mig_gateways()
39 ## @brief Durchlaufe die Liste aller Internet-Gateway-Dienste und aktualisieren deren Status.
40 ## @see run_cyclic_service_tests
42  local max_fail_attempts
43  local test_period_minutes
44  max_fail_attempts=$(get_on_openvpn_default "test_max_fail_attempts")
45  test_period_minutes=$(get_on_openvpn_default "test_period_minutes")
46  get_services "gw" | run_cyclic_service_tests "verify_vpn_connection" "$test_period_minutes" "$max_fail_attempts"
47 }
48 
49 
50 ## @fn select_mig_connection()
51 ## @brief Aktiviere den angegebenen VPN-Gateway
52 ## @param wanted Name eines Diensts
53 ## @attention Seiteneffekt: Beräumung aller herumliegenden Konfigurationen von alten Verbindungen.
55  trap "error_trap select_mig_connection '$*'" $GUARD_TRAPS
56  local wanted="$1"
57  local one_service
58  get_services "gw" | while read one_service; do
59  # loesche Flags fuer die Vorselektion
60  set_service_value "$one_service" "switch_candidate_timestamp" ""
61  # erst nach der Abschaltung der alten Dienste wollen wir den/die neuen Dienste anschalten (also nur Ausgabe)
62  [ "$one_service" = "$wanted" ] && echo "$one_service" && continue
63  disable_openvpn_service "$one_service" || true
64  done | while read one_service; do
65  enable_openvpn_service "$wanted" "host"
66  done
67 }
68 
69 
70 ## @fn find_and_select_best_gateway()
71 ## @brief Ermittle den besten Gateway und prüfe, ob ein Wechsel sinnvoll ist.
72 ## @param force_switch_now [optional] erzwinge den Wechsel auf den besten Gateway unabhängig von Wartezeiten (true/false)
73 ## @ref mig-switch
75  trap "error_trap find_and_select_best_gateway '$*'" $GUARD_TRAPS
76  local force_switch_now=${1:-false}
77  local service_name
78  local host
79  local best_gateway=
80  local current_gateway=
81  local result
82  local current_priority
83  local best_priority
84  local switch_candidate_timestamp
85  local now
86  local bettergateway_timeout
87  now=$(get_uptime_minutes)
88  bettergateway_timeout=$(get_on_openvpn_default vpn_bettergateway_timeout)
89  msg_debug "Trying to find a better gateway"
90  # suche nach dem besten und dem bisher verwendeten Gateway
91  # Ignoriere dabei alle nicht-verwendbaren Gateways.
92  result=$(get_services "gw" \
96  | while read service_name; do
97  # Ist der beste und der aktive Gateway bereits gefunden? Dann einfach weiterspringen ...
98  # (kein Abbruch der Schleife - siehe weiter unten - Stichwort SIGPIPE)
99  [ -n "$current_gateway" ] && continue
100  host=$(get_service_value "$service_name" "host")
101  uci_is_false "$(get_service_value "$service_name" "status" "false")" && \
102  msg_debug "$host did not pass the last test" && \
103  continue
104  # der Gateway ist ein valider Kandidat
105  # Achtung: Variablen innerhalb einer "while"-Sub-Shell wirken sich nicht auf den Elternprozess aus
106  # Daher wollen wir nur ein bis zwei Zeilen:
107  # den besten
108  # [den aktiven] (falls vorhanden)
109  # Wir brechen die Ausgabe jedoch nicht nach den ersten beiden Zeilen ab. Andernfalls muessten wir
110  # uns um das SIGPIPE-Signal kuemmern (vor allem in cron-Jobs).
111  [ -z "$best_gateway" ] && best_gateway="$service_name" && echo "$best_gateway"
112  [ -n "$(get_openvpn_service_state "$service_name")" ] && current_gateway="$service_name" && echo "$service_name" || true
113  done)
114  best_gateway=$(echo "$result" | sed -n 1p)
115  current_gateway=$(echo "$result" | sed -n 2p)
116  if [ "$current_gateway" = "$best_gateway" ]; then
117  if [ -z "$current_gateway" ]; then
118  msg_debug "There is still no usable gateway around"
119  else
120  msg_debug "Current gateway ($current_gateway) is still the best choice"
121  # Wechselzaehler zuruecksetzen (falls er hochgezaehlt wurde)
122  set_service_value "$current_gateway" "switch_candidate_timestamp" ""
123  fi
124  return 0
125  fi
126  msg_debug "Current ($current_gateway) / best ($best_gateway)"
127  # eventuell wollen wir den aktuellen Host beibehalten (sofern er funktioniert und wir nicht zwangsweise wechseln)
128  if [ -n "$current_gateway" ] \
129  && uci_is_false "$force_switch_now" \
130  && uci_is_true "$(get_service_value "$current_gateway" "status" "false")"; then
131  # falls der beste und der aktive Gateway gleich weit entfernt sind, bleiben wir beim bisher aktiven
132  current_priority=$(get_service_priority "$current_gateway")
133  best_priority=$(get_service_priority "$best_gateway")
134  [ "$current_priority" -eq "$best_priority" ] \
135  && msg_debug "Keeping current gateway since the best gateway has the same priority" \
136  && return 0
137  # falls der beste und der aktive Gateway gleich weit entfernt sind, bleiben wir beim bisher aktiven
138  # Haben wir einen besseren Kandidaten? Muessen wir den Wechselzaehler aktivieren?
139  # Zaehle hoch bis der switch_candidate_timestamp alt genug ist
140  switch_candidate_timestamp=$(get_service_value "$current_gateway" "switch_candidate_timestamp")
141  if [ -z "$switch_candidate_timestamp" ]; then
142  # wir bleiben beim aktuellen Gateway - wir merken uns allerdings den Switch-Zeitstempel
143  set_service_value "$current_gateway" "switch_candidate_timestamp" "$now"
144  msg_debug "Starting to count down until the switching timer reaches $bettergateway_timeout minutes"
145  return 0
146  else
147  # noch nicht alt genug fuer den Wechsel?
148  is_timestamp_older_minutes "$switch_candidate_timestamp" "$bettergateway_timeout" \
149  || { msg_debug "Counting down further until we reach $bettergateway_timeout minutes"; return 0; }
150  fi
151  fi
152  # eventuell kann hier auch ein leerer String uebergeben werden - dann wird kein Gateway aktiviert (korrekt)
153  [ -n "$best_gateway" ] \
154  && msg_debug "Switching gateway from $current_gateway to $best_gateway" \
155  || msg_debug "Disabling $current_gateway without a viable alternative"
156  select_mig_connection "$best_gateway"
157 }
158 
159 
160 ## @fn get_active_mig_connections()
161 ## @brief Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
162 ## @returns Liste der Namen aller Dienste, die aktuell eine aktive VPN-Verbindung halten.
163 ## @attention Diese Funktion braucht recht viel Zeit.
165  trap "error_trap get_active_mig_connections '$*'" $GUARD_TRAPS
166  local service_name
167  get_services "gw" | while read service_name; do
168  [ "$(get_openvpn_service_state "$service_name")" = "active" ] && echo "$service_name" || true
169  done
170 }
171 
172 
173 ## @fn get_starting_mig_connections()
174 ## @brief Liefere die im Aufbau befindlichen VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
175 ## @returns Liste der Namen aller Dienste, die aktuell beim Verbindungsaufbau sind.
176 ## @attention Diese Funktion braucht recht viel Zeit.
178  trap "error_trap get_starting_mig_connections '$*'" $GUARD_TRAPS
179  local service_name
180  get_services "gw" | while read service_name; do
181  [ "$(get_openvpn_service_state "$service_name")" = "connecting" ] && echo "$service_name" || true
182  done
183 }
184 
185 
186 ## @fn reset_mig_connection_test_timestamp()
187 ## @brief Löse eine erneute Prüfung dieses Gateways beim nächsten Prüflauf aus.
188 ## @param service_name Name eines Diensts
189 ## @details Das Löschen des *status_timestamp* Werts führt zu einer
190 ## erneuten Prüfung zum nächstmöglichen Zeitpunkt.
192  local service_name="$1"
193  set_service_value "$service_name" "status_timestamp" ""
194 }
195 
196 
197 ## @fn reset_all_mig_connection_test_timestamps()
198 ## @brief Löse eine erneute Prüfung aller Gateways zum nächstmöglichen Zeitpunkt aus.
199 ## @sa reset_mig_connection_test_timestamp
201  local service_name
202  get_services "gw" | while read service_name; do
204  done
205 }
206 
207 
208 ## @fn get_mig_connection_test_age()
209 ## @brief Ermittle das Test des letzten Verbindungstests in Minuten.
210 ## @returns Das Alter des letzten Verbindungstests in Minuten oder nichts (falls noch kein Test durchgeführt wurde).
211 ## @details Anhand des Test-Alters lässt sich der Zeitpunkt der nächsten Prüfung abschätzen.
213  local service_name="$1"
214  local timestamp
215  timestamp=$(get_service_value "$service_name" "status_timestamp")
216  # noch keine Tests durchgefuehrt?
217  [ -z "$timestamp" ] && return 0
218  local now
219  now=$(get_uptime_minutes)
220  echo "$timestamp" "$now" | awk '{ print $2 - $1 }'
221 }
222 
223 
224 ## @fn get_client_cn()
225 ## @brief Ermittle den Common-Name des Nutzer-Zertifikats.
226 ## @details Liefere eine leere Zeichenkette zurück, falls kein Zertifikat vorhanden ist.
227 get_client_cn() {
228  [ -e "$MIG_OPENVPN_DIR/on_aps.crt" ] || return 0
229  openssl x509 -in "$MIG_OPENVPN_DIR/on_aps.crt" \
230  -subject -nameopt multiline -noout 2>/dev/null | awk '/commonName/ {print $3}'
231 }
232 
233 
234 ## @fn get_mig_port_forward_range()
235 ## @brief Liefere den ersten und letzten Port der Nutzertunnel-Portweiterleitung zurück.
236 ## @param client_cn [optional] common name des Nutzer-Zertifikats
237 ## @returns zwei Zahlen durch Tabulatoren getrennt / keine Ausgabe, falls keine Main-ID gefunden wurde
238 ## @details Jeder AP bekommt einen Bereich von zehn Ports fuer die Port-Weiterleitung zugeteilt.
240  trap "error_trap get_mig_port_forward_range '$*'" $GUARD_TRAPS
241  local client_cn=${1:-}
242  [ -z "$client_cn" ] && client_cn=$(get_client_cn)
243  local port_count=10
244  local cn_address=
245  local portbase
246  local first_port
247  local last_port
248 
249  [ -z "$client_cn" ] && msg_debug "get_mig_port_forward_range: failed to get Common Name - maybe there is no certificate?" && return 0
250 
251  if echo "$client_cn" | grep -q '^\(\(1\.\)\?[0-9][0-9]\?[0-9]\?\.aps\.on\)$'; then
252  portbase=10000
253  cn_address=${client_cn%.aps.on}
254  cn_address=${cn_address#*.}
255  elif echo "$client_cn" | grep -q '^\([0-9][0-9]\?[0-9]\?\.mobile\.on\)$'; then
256  portbase=12550
257  cn_address=${client_cn%.mobile.on}
258  elif echo "$client_cn" | grep -q '^\(2[\._-][0-9][0-9]\?[0-9]\?\.aps\.on\)$'; then
259  portbase=15100
260  cn_address=${client_cn%.aps.on}
261  cn_address=${cn_address#*.}
262  elif echo "$client_cn" | grep -q '^\(3[\._-][0-9][0-9]\?[0-9]\?\.aps\.on\)$'; then
263  portbase=20200
264  cn_address=${client_cn%.aps.on}
265  cn_address=${cn_address#*.}
266  fi
267 
268  if [ -z "$cn_address" ] || [ "$cn_address" -lt 1 ] || [ "$cn_address" -gt 255 ]; then
269  msg_info "$(basename "$0"): invalidate certificate Common Name ($client_cn)"
270  else
271  first_port=$((portbase + (cn_address-1) * port_count))
272  last_port=$((first_port + port_count - 1))
273  echo -e "$first_port\t$last_port"
274  fi
275 }
276 
277 
279 ## @brief Je nach Status des Moduls: prüfe die VPN-Verbindungen bis mindestens eine Verbindung
280 ## aufgebaut wurde bzw. trenne alle Verbindungen.
281 ## @details Diese Funktion sollte regelmäßig als cronjob ausgeführt werden.
283  if is_on_module_installed_and_enabled "on-openvpn"; then
284  # die Gateway-Tests sind nur moeglich, falls ein Test-Schluessel vorhanden ist
288  fi
289  else
291  fi
292 }
293 
294 
295 ## @fn disable_on_openvpn()
296 ## @brief Trenne alle laufenden oder im Aufbau befindlichen Verbindungen.
298  local service_name
299  # möglicherweise vorhandene Verbindungen trennen und bei Bedarf openvpn neustarten
300  { get_active_mig_connections; get_starting_mig_connections; } | while read service_name; do
301  disable_openvpn_service "$service_name" && echo "$service_name"
302  true
303  done | grep -q . && apply_changes openvpn
304  true
305 }
306 
307 
308 ## @fn get_mig_tunnel_servers()
309 ## @brief Ermittle die Server für den gewünschen Dienst, die via Tunnel erreichbar sind.
310 ## @params stype Dienst-Typ (z.B. "DNS" oder "NTP") - entspricht den DHCP-Options, die vom OpenVPN-Server gepusht werden.
311 ## @details Die Ausgabe ist leer, falls kein Tunnel aufgebaut ist.
313  trap "error_trap get_mig_tunnel_server '$*'" $GUARD_TRAPS
314  local stype="$1"
315  [ -z "$(get_active_mig_connections)" ] && return 0
316  [ -f "$MIG_PREFERRED_SERVERS_FILE" ] || return 0
317  awk <"$MIG_PREFERRED_SERVERS_FILE" '{ if ($1 == "'"$stype"'") print $2 }'
318 }
319 
320 # Ende der Doku-Gruppe
321 ## @}
has_mig_openvpn_credentials()
Prüft, ob der Nutzer bereits einen Schlüssel und ein Zertifikat angelegt hat.
Definition: on-openvpn.sh:14
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird...
Definition: services.sh:61
get_mig_port_forward_range(client_cn)
Liefere den ersten und letzten Port der Nutzertunnel-Portweiterleitung zurück.
Definition: on-openvpn.sh:63
get_starting_mig_connections()
Liefere die im Aufbau befindlichen VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
Definition: on-openvpn.sh:38
disable_on_openvpn()
Trenne alle laufenden oder im Aufbau befindlichen Verbindungen.
Definition: on-openvpn.sh:71
find_and_select_best_gateway(force_switch_now)
Ermittle den besten Gateway und prüfe, ob ein Wechsel sinnvoll ist.
Definition: on-openvpn.sh:28
filter_reachable_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die erreichbar sind.
Definition: services.sh:38
filter_enabled_services()
Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die nicht manuell ausgeblendet wurden...
Definition: services.sh:43
set eu uci q show dhcp grep dhcp dnsmasq dns uci for fname in etc resolv conf tmp resolv conf auto var etc dnsmasq conf var run dnsmasq servers
Definition: dns:14
local key
Definition: core.sh:81
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
Definition: core.sh:81
select_mig_connection(wanted)
Aktiviere den angegebenen VPN-Gateway.
Definition: on-openvpn.sh:23
run_cyclic_service_tests(test_function)
Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist...
Definition: services.sh:149
get_mig_tunnel_servers()
Ermittle die Server für den gewünschen Dienst, die via Tunnel erreichbar sind. stype Dienst-Typ (z...
Definition: on-openvpn.sh:76
sort_services_by_priority()
Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste...
Definition: services.sh:31
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
Definition: core.sh:15
verify_mig_gateways()
Durchlaufe die Liste aller Internet-Gateway-Dienste und aktualisieren deren Status.
Definition: on-openvpn.sh:18
reset_all_mig_connection_test_timestamps()
Löse eine erneute Prüfung aller Gateways zum nächstmöglichen Zeitpunkt aus.
Definition: on-openvpn.sh:48
get_client_cn()
Ermittle den Common-Name des Nutzer-Zertifikats.
Definition: on-openvpn.sh:57
enable_openvpn_service()
Erzeuge eine funktionierende openvpn-Konfiguration (Datei + UCI, service_name).
Definition: openvpn.sh:9
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:44
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
Definition: core.sh:9
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
Definition: services.sh:74
get_active_mig_connections()
Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
Definition: on-openvpn.sh:33
set eu grep root::etc shadow exit if which chpasswd dev null
Definition: on-password:12
get_mig_connection_test_age()
Ermittle das Test des letzten Verbindungstests in Minuten.
Definition: on-openvpn.sh:53
get_on_openvpn_default()
Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-openvpn, key).
Definition: on-openvpn.sh:9
done
Definition: core.sh:81
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
is_on_module_installed_and_enabled(module)
Pruefe ob ein Modul sowohl installiert, als auch aktiv ist.
Definition: modules.sh:9
update_mig_connection_status()
Je nach Status des Moduls: prüfe die VPN-Verbindungen bis mindestens eine Verbindung aufgebaut wurde ...
Definition: on-openvpn.sh:68