1 ## @defgroup services Dienste 2 ## @brief Verwaltung von Diensten (z.B. via olsrd-nameservice announciert) 3 # Beginn der Doku-Gruppe 6 VOLATILE_SERVICE_STATUS_DIR=/tmp/on-services-
volatile.d
7 PERSISTENT_SERVICE_STATUS_DIR=/etc/on-services.d
8 # eine grosse Zahl sorgt dafuer, dass neu entdeckte Dienste hinten angehaengt werden 9 DEFAULT_SERVICE_RANK=10000
10 DEFAULT_SERVICE_SORTING=etx
11 # Die folgenden Attribute werden dauerhaft (im Flash) gespeichert. Häufige Änderungen sind also eher unerwünscht. 12 # Gruende fuer ausgefallene/unintuitive Attribute: 13 # uci_dependency: später zu beräumende uci-Einträge wollen wir uns merken 14 # file_dependency: siehe uci_dependency 15 # priority: DNS-entdeckte Dienste enthalten ein "priority"-Attribut, nach einem reboot wieder verfügbar sein sollte 16 # rank/offset: Attribute zur Ermittlung der Dienstreihenfolge 17 # disabled: der Dienst wurde vom Nutzenden an- oder abgewählt 18 # source: die Quelle des Diensts (olsrd/dns/manual) muss erhalten bleiben, um ihn später löschen zu können 19 # Wir beachten den vorherigen Zustand der Variable, damit andere Module (z.B. on-usergw) diese 20 # ebenfalls beeinflussen können. 21 PERSISTENT_SERVICE_ATTRIBUTES=
"${PERSISTENT_SERVICE_ATTRIBUTES:-} service scheme host port protocol path uci_dependency file_dependency priority rank offset disabled source" 23 SERVICES_LOG_BASE=/var/log/on-services
24 # Namenspräfix für weiterzuleitende Dienste 25 RELAYABLE_SERVICE_PREFIX=
"proxy-" 26 UPDATE_TRUSTED_SERVICES_PERIOD_MINUTES=360
27 USER_SERVICES_URL=https:
29 # andere Module fügen eventuell weitere URLs hinzu 30 SERVICES_LIST_URLS=
"${SERVICES_LIST_URLS:-} $USER_SERVICES_URL" 33 ## @fn get_service_name() 34 ## @brief Ermittle en Namen eines Diensts basierend auf den Dienst-Attributen. 35 ## @details Reihenfolge der Eingabeparameter: SERVICE_TYPE SCHEMA HOST PORT PROTOCOL PATH 43 local name=
"${service}_${scheme}_${host}_${port}_${protocol}" 44 [ -n
"${path#/}" ] && name=
"${name}_${path#/}" 45 echo
"$name" | sed
's/[^A-Za-z0-9_]/_/g' 49 ## @fn notify_service() 50 ## @brief Aktualisiere den Zeitstempel und die Entfernung (etx) eines Dienstes 51 ## @param service z.B. "gw" 52 ## @param scheme z.B. "openvpn" 53 ## @param host z.B. "192.168.2.254" 54 ## @param port z.B. "1600" 55 ## @param path z.B. "/" 56 ## @param protocol z.B. "udp" 57 ## @param details z.B. "via:megumi" 58 ## @returns Der Dienstname wird ausgegeben. 60 trap
'error_trap notify_service "$*"' EXIT
61 # wir erwarten sieben Parameter 62 [
"$#" -eq 7 ] || [
"$#" -eq 8 ]
69 ## @fn notify_services() 70 ## @brief Siehe "notify_service" - jedoch effizienter im Umgang mit einer großen Anzahl von Diensten 71 ## @param source Quelle (z.B. "olsr") 72 ## @returns Alle Dienstnamen werden ausgegeben. 74 trap
'error_trap notify_services "$*"' EXIT
87 while read -r service scheme host port protocol path details;
do 88 service_name=$(
get_service_name "$service" "$scheme" "$host" "$port" "$protocol" "$path")
89 # Diese Attribute duerften sich nicht aendern, aber wir wollen sicherheitshalber lieber kaputten
91 #
"details",
"timestamp" und
"source" sind die flexiblen Werte.
93 "service" "$service" \
97 "protocol" "$protocol" \
99 "details" "$details" \
100 "timestamp" "$(get_uptime_minutes)" \
112 ## @fn is_existing_service() 113 ## @brief Prüfe ob ein Service existiert 114 ## @param service_name der Name des Diensts 115 ## @returns exitcode=0 falls der Dienst existiert 117 local service_name=
"$1" 118 if [ -n
"$service_name" ] && [ -e
"$PERSISTENT_SERVICE_STATUS_DIR/$service_name" ]; then
121 trap
"" EXIT &&
return 1
126 ## @fn _get_local_bias_for_service() 127 ## @brief Ermittle eine reproduzierbare Zahl von 0 bis (LOCAL_BIAS_MODULO-1) - abhängig von der lokalen IP und dem Dienstnamen. 128 ## @param service_name der Name des Diensts für den ein Bias-Wert zu ermitteln ist. 129 ## @details Dadurch können wir beim Sortieren strukturelle Bevorzugungen (z.B. durch alphabetische Sortierung) verhindern. 131 local service_name=
"$1" 132 # lade den Wert aus dem Cache, falls moeglich 135 if [ -z
"$bias_cache" ]; then
136 # Die resultierende host_number darf nicht zu gross sein (z.B. mit Exponentendarstellung), 137 # da andernfalls awk die Berechnung fehlerhaft durchführt. 139 host_number=$(echo
"$service_name$(get_local_bias_number)" | md5sum | sed
's/[^0-9]//g')
140 # Laenge von
'host_number' reduzieren (die Berechnung schlaegt sonst fehl)
141 # Wir fuegen die 1 an den Beginn, um die Interpretation als octal-Zahl zu verhindern (fuehrende Null). 142 bias_cache=$(( 1${host_number:0:6} % LOCAL_BIAS_MODULO))
145 echo -n
"$bias_cache" 149 # Ermittle die Service-Prioritaet eines Dienstes. 150 # Der Wert ist beliebig und nur im Vergleich mit den Prioritaeten der anderen Dienste verwendbar. 151 # Als optionaler zweiter Parameter kann die Sortierung uebergeben werden. Falls diese nicht uebergeben wurde, 152 # wird die aktuell konfigurierte Sortierung benutzt. 153 # Sollte ein Dienst ein "priority"-Attribut tragen, dann wird die uebliche Dienst-Sortierung aufgehoben 154 # und lediglich "priority" (und gegebenenfalls separat "offset") beachtet. 155 get_service_priority() {
156 trap
'error_trap get_service_priority "$*"' EXIT
157 local service_name=
"$1" 158 local sorting=
"${2:-}" 161 # priority wird von nicht-olsr-Clients verwendet (z.B. mesh-Gateways mit oeffentlichen IPs)
164 if [ -n
"$priority" ]; then
165 # dieses Ziel traegt anscheinend keine Routing-Metrik 168 echo
"$((priority + offset))" 170 # wir benoetigen Informationen fuer Ziele mit Routing-Metriken
171 # aus Performance-Gruenden kommt die Sortierung manchmal von aussen
172 [ -z
"$sorting" ] && sorting=$(get_service_sorting)
173 if [
"$sorting" =
"etx" ] || [
"$sorting" =
"hop" ]; then
174 get_distance_with_offset
"$service_name" "$sorting" 175 elif [
"$sorting" =
"manual" ]; then
178 msg_error "Unknown sorting method for services: $sorting" 184 echo
"${base_priority:-$DEFAULT_SERVICE_RANK}" | awk
'{ print $1 * 1000 + '"$service_bias"'; }' 188 get_distance_with_offset() {
189 trap
'error_trap get_distance_with_offset "$*"' EXIT
190 local service_name=
"$1" 191 local sorting=
"${2:-}" 195 # aus Performance-Gruenden wird manchmal das sorting von aussen vorgegeben 196 [ -z
"$sorting" ] && sorting=$(get_service_sorting)
198 [ -z
"$distance" ] &&
return 0
200 [ -z
"$offset" ] && offset=0
201 if [
"$sorting" =
"etx" ]; then
202 base_value=
"$distance" 203 elif [
"$sorting" =
"hop" ]; then
206 msg_debug "get_distance_with_offset: sorting '$sorting' not implemented" 208 [ -n
"$base_value" ] && echo
"$base_value" "$offset" | awk
'{ print $1 + $2 }' 212 set_service_sorting() {
213 trap
'error_trap set_service_sorting "$*"' EXIT
214 local new_sorting=
"$1" 216 old_sorting=$(get_service_sorting)
217 [
"$old_sorting" =
"$new_sorting" ] &&
return 0
218 if [
"$new_sorting" !=
"manual" ] && [
"$new_sorting" !=
"hop" ] && [
"$new_sorting" !=
"etx" ]; then
219 msg_error "Ignoring unknown sorting method: $new_sorting" 220 trap
"" EXIT &&
return 1
222 uci
set "on-core.settings.service_sorting=$new_sorting" 223 apply_changes
"on-core" 228 # Liefere die aktuelle Sortier-Methode. 229 # Falls eine ungueltige Sortier-Methode gesetzt ist, wird diese auf die Standard-Sortierung zurueckgesetzt. 230 # Die Ausgabe dieser Funktion ist also in jedem Fall eine gueltige Sortier-Methode. 231 get_service_sorting() {
232 trap
'error_trap get_service_sorting "$*"' EXIT
234 sorting=$(uci_get
"on-core.settings.service_sorting")
235 if [
"$sorting" =
"manual" ] || [
"$sorting" =
"hop" ] || [
"$sorting" =
"etx" ]; then
236 # zulaessige Sortierung 239 # unbekannte Sortierung: dauerhaft setzen 240 # keine Warnung falls die Sortierung nicht gesetzt wurde 241 [ -n
"$sorting" ] &&
msg_error "coercing unknown sorting method: $sorting -> $DEFAULT_SERVICE_SORTING" 242 uci
set "on-core.settings.service_sorting=$DEFAULT_SERVICE_SORTING" 243 echo -n
"$DEFAULT_SERVICE_SORTING" 249 ## @fn sort_services_by_priority() 250 ## @brief Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste. 251 ## @details Die Prioritätsinformation wird typischerweise für nicht-mesh-verteilte Dienste verwendet (z.B. den mesh-Tunnel). 253 trap
'error_trap sort_services_by_priority "$*"' EXIT
257 sorting=$(get_service_sorting)
258 while read -r service_name;
do 259 priority=$(get_service_priority
"$service_name" "$sorting")
260 # keine Entfernung (nicht erreichbar) -> ganz nach hinten sortieren (schmutzig, aber wohl ausreichend)
261 [ -z
"$priority" ] && priority=999999999999999
262 echo
"$priority" "$service_name" 263 done | sort -n | awk
'{print $2}' 267 ## @fn filter_reachable_services() 268 ## @brief Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die erreichbar sind. 269 ## @details Die Dienst-Namen werden über die Standardeingabe gelesen und an die Standardausgabe 270 ## weitergeleitet, falls der Dienst erreichbar sind. "Erreichbarkeit" gilt als erreicht, wenn 271 ## der Host via olsr route-bar ist oder wenn er als DNS-entdeckter Dienst eine Priorität hat 272 ## oder wenn er manuell hinzugefügt wurde. 275 while read -r service_name;
do 276 { [ -n
"$(get_service_value "$service_name
" "distance
")" ] \
277 || [ -n
"$(get_service_value "$service_name
" "priority
")" ] \
278 || [
"$(get_service_value "$service_name
" "source
")" =
"manual" ]
279 } && echo
"$service_name" 285 ## @fn filter_enabled_services() 286 ## @brief Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die nicht manuell ausgeblendet wurden. 287 ## @details Die Dienst-Namen werden über die Standardeingabe gelesen und an 288 ## die Standardausgabe weitergeleitet, falls der Dienst nicht abgewählt wurde. 292 while read -r service_name;
do 294 [ -n
"$disabled" ] && uci_is_true
"$disabled" &&
continue 301 ## @brief Liefere zu einer Reihe von Diensten ein gewähltes Attribut dieser Dienste zurück. 302 ## @param key Der Name eines Dienst-Attributs 303 ## @param default Der Standard-Wert wird anstelle des Attribut-Werts verwendet, falls dieser leer ist. 304 ## @details Die Dienstenamen werden via Standardeingabe erwartet. Auf der Standardausgabe wird für 305 ## einen Dienst entweder ein Wert oder nichts ausgeliefert. Keine Ausgabe erfolgt, falls der 306 ## Wert des Dienste-Attributs leer ist. Bei der Eingabe von mehreren Diensten werden also 307 ## eventuell weniger Zeilen ausgegeben, als eingelesen wurden. 308 ## Falls der optionale zweite 'default'-Parameter nicht leer ist, dann wird bei einem leeren 309 ## Ergebnis stattdessen dieser Wert ausgegeben. Der 'default'-Parameter sorgt somit dafür, dass 310 ## die Anzahl der eingelesenen Zeilen in jedem Fall mit der Anzahl der ausgegebenen Zeilen 312 ## Die Ausgabe besteht aus dem Service-Namen und dem Attributinhalt (getrennt durch einen Tabulator). 315 local
default=
"${2:-}" 318 while read -r service_name;
do 319 [ -z
"$service_name" ] &&
continue 321 [ -z
"$value" ] &&
value=
"$default" 322 [ -n
"$value" ] && printf
'%s\t%s\n' "$service_name" "$value" 329 ## @param service_type (optional) ein Service-Typ 330 ## @brief Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. 331 ## Falls kein Typ angegben wird, dann werden alle Dienste ungeachtet ihres Typs ausgegeben. 333 trap
'error_trap get_services "$*"' EXIT
334 local service_type=
"${1:-}" 335 # alle Dienste ausgeben 336 # kein Dienste-Verzeichnis? Keine Ergebnisse ... 337 [ -e
"$PERSISTENT_SERVICE_STATUS_DIR" ] ||
return 0
338 find
"$PERSISTENT_SERVICE_STATUS_DIR" -type f -size +1c -print0 \
339 | xargs -0 -r -n 1 basename \
340 |
if [ -n
"$service_type" ]; then
348 ## @fn filter_services_by_value() 349 ## @param key ein Schlüssel 350 ## @param value ein Wert 351 ## @details Als Parameter kann ein "key/value"-Schluesselpaar angegeben werden. 352 ## Nur diejenigen Dienste, auf die diese Bedingung zutrifft, werden zurueckgeliefert. 357 while read -r service_name;
do 358 [
"$value" !=
"$(get_service_value "$service_name
" "$key
")" ] || echo
"$service_name" 363 ## @fn set_service_value() 364 ## @brief Setzen eines oder mehrerer Werte fuer einen Dienst. 365 ## Je nach Schluesselname wird der Inhalt in die persistente uci- oder 366 # die volatile tmpfs-Datenbank geschrieben. 368 local service_name=
"$1" 373 [ -z
"$service_name" ] \
374 &&
msg_error "No service given for attribute change ($attribute=$value)" \
375 && trap
"" EXIT &&
return 1
376 while [
"$#" -gt 0 ];
do 380 # unverändert? ueberspringen ... 381 [
"$value" =
"$(get_service_value "$service_name
" "$attribute
")" ] &&
continue 382 if echo
"$PERSISTENT_SERVICE_ATTRIBUTES" | grep -q -w
"$attribute"; then
383 dirname=
"$PERSISTENT_SERVICE_STATUS_DIR" 385 dirname=
"$VOLATILE_SERVICE_STATUS_DIR" 387 _set_file_dict_value
"$dirname/$service_name" "$attribute" "$value" 392 ## @fn get_service_value() 393 ## @brief Auslesen eines Werts aus der Service-Datenbank. 394 ## @param key Der Name eines Dienst-Attributs 395 ## @param default Der Standard-Wert wird anstelle des Attribut-Werts verwendet, falls dieser leer ist. 396 ## @details Falls das Attribut nicht existiert, wird ein leerer Text zurückgeliefert. 397 ## Es gibt keinen abschließenden Zeilenumbruch. 399 local service_name=
"$1" 401 local
default=
"${3:-}" 404 [ -z
"$service_name" ] \
405 &&
msg_error "No service given for attribute request ('$attribute')" \
406 && trap
"" EXIT &&
return 1
407 value=$(
_get_file_dict_value "$attribute" "$PERSISTENT_SERVICE_STATUS_DIR/$service_name" "$VOLATILE_SERVICE_STATUS_DIR/$service_name")
408 [ -n
"$value" ] && echo -n
"$value" || echo -n
"$default" 413 # Liefere die Suffixe aller Schluessel aus der Service-Attribut-Datenbank,
414 # die mit dem gegebenen Praefix uebereinstimmen.
415 get_service_attributes() {
416 _get_file_dict_keys
"$PERSISTENT_SERVICE_STATUS_DIR/$1" "$VOLATILE_SERVICE_STATUS_DIR/$1" 420 ## @fn print_services() 421 ## @brief menschenfreundliche Ausgabe der aktuell angemeldeten Dienste 422 ## @param service_type (optional) ein Service-Type 423 ## @returns Ausgabe der bekannten Dienste (für Menschen - nicht parsebar) 425 trap
'error_trap print_services "$*"' EXIT
431 for attribute in $(get_service_attributes
"$service_name");
do 432 printf
'\t%s=%s\n' "$attribute" "$(get_service_value "$service_name
" "$attribute
")" 439 # Speichere das angegebene uci-Praefix als eine von einem Service abhaengige Konfiguration. 440 # Dies ist sinnvoll fuer abgeleitete VPN-Konfigurationen oder Portweiterleitungen. 441 # Schnittstelle: siehe _add_service_dependency 442 service_add_uci_dependency() {
443 _add_service_dependency
"uci_dependency" "$@" 447 # Speichere einen Dateinamen als Abhaengigkeit eines Service. 448 # Dies ist sinnvoll fuer Dateien, die nicht mehr gebraucht werden, sobald der Service entfernt wird. 449 # Schnittstelle: siehe _add_service_dependency 450 service_add_file_dependency() {
451 _add_service_dependency
"file_dependency" "$@" 455 # Speichere eine Abhaengigkeit fuer einen Dienst. 456 # Parameter: Service-Name 457 # Parameter: textuelle Darstellung einer Abhaengigkeit (ohne Leerzeichen) 458 _add_service_dependency() {
459 trap
'error_trap _add_service_dependency "$*"' EXIT
460 local dependency=
"$1" 461 local service_name=
"$2" 467 # schon vorhanden -> fertig 468 [
"$dep" =
"$token" ] &&
return 0
471 if [ -z
"$deps" ]; then
480 # Entferne alle mit diesem Service verbundenen Konfigurationen (inkl. Rekonfiguration von firewall, etc.). 481 cleanup_service_dependencies() {
482 trap
'error_trap cleanup_service_dependencies "$*"' EXIT
483 local service_name=
"$1" 491 # uci-Sektionen loeschen 494 # gib die oberste config-Ebene aus - fuer spaeteres "apply_changes" 495 echo
"$dep" | cut -f 1 -
d .
496 done | sort | uniq |
while read -r branch;
do 497 apply_changes
"$branch" 504 trap
'error_trap delete_service "$*"' EXIT
505 local service_name=
"$1" 506 [ -z
"$service_name" ] &&
msg_error "No service given for deletion" && trap
"" EXIT &&
return 1
507 cleanup_service_dependencies
"$service_name" 508 rm -f
"$PERSISTENT_SERVICE_STATUS_DIR/$service_name" 509 rm -f
"$VOLATILE_SERVICE_STATUS_DIR/$service_name" 513 # Durchlaufe alle Dienste und verteile Rangziffern ohne Doppelung an alle Dienste. 514 # Die Dienst-Arten (z.B. DNS und UGW) werden dabei nicht beachtet. 515 # Die Rangziffern sind anschliessend streng monoton aufsteigend - beginnend bei 1. 516 # Falls aktuell die manuelle Sortierung aktiv ist, wird deren Reihenfolge beibehalten. 517 # Ansonsten basiert die Vergabe der Rangziffern auf der Reihenfolge entsprechend der aktuell aktiven Sortierung. 518 _distribute_service_ranks() {
528 ## @fn move_service_up() 529 ## @brief Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach oben 530 ## @param service_name der zu verschiebende Dienst 531 ## @param service_type der Service-Typ innerhalb derer Mitglieder die Verschiebung stattfinden soll 532 ## @details Für verschiedene Sortier-Modi hat dies verschiedene Auswirkungen: 533 ## * manual: Verschiebung vor den davorplatzierten Dienst desselben Typs 534 ## * etx/hop: Reduzierung des Offsets um eins 535 ## Falls keine Dienst-Typen angegeben sind, bewegt der Dienst sich in der globalen Liste nach unten. 537 trap
'error_trap move_service_up "$*"' EXIT
538 local service_name=
"$1" 542 local current_service
544 sorting=$(get_service_sorting)
545 if [
"$sorting" =
"hop" ] || [
"$sorting" =
"etx" ]; then
546 # reduziere den Offset um eins 548 temp=$(echo
"$temp" | awk
'{ print $1 - 1 }')
550 elif [
"$sorting" =
"manual" ]; then
552 if [
"$current_service" =
"$service_name" ]; then
553 if [ -z
"$prev_service" ]; then
554 # es gibt keinen Dienst oberhalb des zu verschiebenden 557 # wir verschieben den Dienst ueber den davor liegenden 559 # ziehe einen halben Rang ab
560 temp=$(echo
"$temp" | awk
'{ print $1 - 0.5 }')
562 # erneuere die Rang-Vergabe 563 _distribute_service_ranks
568 prev_service=
"$current_service" 571 msg_info "Warning: [move_service_up] for this sorting method is not implemented: $sorting" 576 ## @fn move_service_down() 577 ## @brief Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach unten 578 ## @param service_name der zu verschiebende Dienst 579 ## @param service_type der Service-Typ innerhalb derer Mitglieder die Verschiebung stattfinden soll 580 ## @details Für verschiedene Sortier-Modi hat dies verschiedene Auswirkungen: 581 ## * manual: Verschiebung hinter den dahinterliegenden Dienst desselben Typs 582 ## * etx/hop: Erhöhung des Offsets um eins 583 ## Falls keine Dienst-Typen angegeben sind, bewegt der Dienst sich in der globalen Liste nach unten. 585 trap
'error_trap move_service_down "$*"' EXIT
586 local service_name=
"$1" 590 local current_service
592 sorting=$(get_service_sorting)
593 if [
"$sorting" =
"hop" ] || [
"$sorting" =
"etx" ]; then
594 # reduziere den Offset um eins 596 temp=$(echo
"$temp" | awk
'{ print $1 + 1 }')
598 elif [
"$sorting" =
"manual" ]; then
600 if [
"$prev_service" =
"$service_name" ]; then
601 # wir verschieben den Dienst hinter den danach liegenden 603 # fuege einen halben Rang hinzu
604 temp=$(echo
"$temp" | awk
'{ print $1 + 0.5 }')
606 # erneuere die Rang-Vergabe 607 _distribute_service_ranks
611 prev_service=
"$current_service" 614 msg_info "Warning: [move_service_down] for this sorting method is not implemented: $sorting" 619 ## @fn move_service_top() 620 ## @brief Verschiebe einen Dienst an die Spitze der Dienst-Sortierung 621 ## @param service_name der zu verschiebende Dienst 622 ## @param service_types ein oder mehrere Dienst-Typen, auf die die Ermittlung der Dienst-Liste begrenzt werden soll (z.B. "gw") 623 ## @details Der Dienst steht anschließend direkt vor dem bisher führenden Dienst der ausgewählten Typen (falls angegeben). 624 ## Falls keine Dienst-Typen angegeben sind, bewegt der Dienst sich in der globalen Liste an die Spitze. 626 trap
'error_trap move_service_top "$*"' EXIT
627 local service_name=
"$1" 638 sorting=$(get_service_sorting)
639 # kein top-Service oder wir sind bereits ganz oben -> Ende 640 if [ -z
"$top_service" ] || [
"$top_service" =
"$service_name" ]; then
642 elif [
"$sorting" =
"hop" ] || [
"$sorting" =
"etx" ]; then
643 top_distance=$(get_distance_with_offset
"$top_service" "$sorting")
644 our_distance=$(get_distance_with_offset
"$service_name" "$sorting")
645 [ -z
"$our_distance" ] &&
msg_info "Failed to move unreachable service ('$service_name') to top" &&
return 0
647 # wir verschieben unseren Offset, auf dass wir knapp ueber
"top" stehen
648 new_offset=$(echo | awk
"{ print $current_offset + int($top_distance - $our_distance) - 1 }")
650 elif [
"$sorting" =
"manual" ]; then
651 # setze den Rang des Dienstes auf den top-Dienst minus 0.5 653 new_rank=$(echo
"$top_rank" | awk
'{ print $1 - 0.5 }')
655 # erneuere die Rang-Vergabe 656 _distribute_service_ranks
658 msg_info "Warning: [move_service_top] for this sorting method is not implemented: $sorting" 663 ## @fn get_service_detail() 664 ## @brief Ermittle den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts 665 ## @param service_name Name eines Diensts 666 ## @param key Name des Schlüssels 667 ## @param default dieser Wert wird zurückgeliefert, falls der Schlüssel nicht gefunden wurde 668 ## @returns den ermittelten Wert aus dem Schlüssel-Wert-Paar 670 local service_name=
"$1" 672 local
default=
"${3:-}" 675 [ -n
"$value" ] && echo -n
"$value" || echo -n
"$default" 681 ## @brief Setze den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts 682 ## @param service_name Name eines Diensts 683 ## @param key Name des Schlüssels 684 ## @param value der neue Wert 685 ## @details Ein leerer Wert löscht das Schlüssel-Wert-Paar. 687 local service_name=
"$1" 691 new_details=$(
get_service_value "$service_name" "details" | replace_in_key_value_list
"$key" ":" "$value")
697 # Liefere eine Semikolon-separierte Liste von Service-Eigenschaften zurueck.
698 # Jede Eigenschaft wird folgendermassen ausgedrueckt:
699 # type|source|
key[|
default]
700 # Dabei sind folgende Inhalte moeglich:
701 # type: Rueckgabetyp (
string, number,
bool)
702 # source: Quelle der Informationen (value, detail, function, id) 703 # key: Name des Werts, des Details oder der Funktion 704 # default: Standardwert, falls das Ergebnis leer sein sollte 705 # Wahrheitswerte werden als "true" oder "false" zurueckgeliefert. Alle anderen Rueckgabetypen bleiben unveraendert. 706 # Das Ergebnis sieht folgendermassen aus: 707 # SERVICE_NAME;RESULT1;RESULT2;... 708 get_service_as_csv() {
709 local service_name=
"$1" 718 # Abbruch mit Fehler bei unbekanntem Dienst 720 echo -n
"$service_name" 721 for specification in
"$@";
do 722 rtype=$(echo
"$specification" | cut -f 1 -
d "|")
723 source=$(echo
"$specification" | cut -f 2 -
d "|")
724 key=$(echo
"$specification" | cut -f 3 -
d "|")
725 default=$(echo
"$specification" | cut -f 4- -
d "|")
726 # Ermittlung des Funktionsaufrufs 727 if [
"$source" =
"function" ]; then
728 if [
"$rtype" =
"bool" ]; then
729 "$key" "$service_name" &&
value=
"true" || value=
"false" 731 value=$(
"$key" "$service_name")
734 if [
"$source" =
"value" ]; then
736 elif [
"$source" =
"detail" ]; then
739 msg_error "Unknown service attribute requested: $specification" 740 echo -n
"${separator}" 743 [ -z
"$value" ] && [ -n
"$default" ] && value=
"$default" 744 if [
"$rtype" =
"bool" ]; then
745 # Pruefung auf wahr/falsch 746 value=$(uci_is_true
"$value" && echo
"true" || echo
"false")
749 echo -n
"${separator}${value}" 751 # mit Zeilenumbruch abschliessen
757 ## @brief Ermittle den Namen der Log-Datei für diesen Dienst. Zusätzliche Details (z.B. "openvpn mtu") sind möglich. 758 ## @param service Name eines Dienstes. 759 ## @param other Eine beliebige Anzahl weiterer Parameter ist erlaubt: diese erweitern den typischen Log-Dateinamen für diesen Dienst. 760 ## @details Die Funktion stellt sicher, dass das Verzeichnis der ermittelten Log-Datei anschließend existiert. 762 trap
'error_trap get_service_log_filename "$*"' EXIT
763 local service_name=
"$1" 766 local filename=
"$service_name" 767 while [ $# -gt 0 ];
do 768 filename=
"${filename}.$1" 771 full_filename=
"$SERVICES_LOG_BASE/$(get_safe_filename "$filename
").log" 772 mkdir -p
"$(dirname "$full_filename
")" 773 echo -n
"$full_filename" 777 ## @fn get_service_log_content() 778 ## @brief Lies den Inhalt einer Log-Datei für einen Dienst aus. 779 ## @param service Name eines Dienstes. 780 ## @param max_lines maximale Anzahl der auszuliefernden Zeilen (unbegrenzt: 0) 781 ## @param other Eine beliebige Anzahl weiterer Parameter ist erlaubt: diese erweitern den typischen Log-Dateinamen für diesen Dienst. 782 ## @see get_service_log_filename 784 trap
'error_trap get_service_log_content "$*"' EXIT
785 local service_name=
"$1" 790 [ -e
"$log_filename" ] ||
return 0
791 if [
"$max_lines" =
"0" ]; then
792 # alle Einträge ausgeben 795 # nur die letzten Einträge ausliefern 801 ## @fn is_service_routed_via_wan() 802 ## @brief Pruefe ob der Verkehr zum Anbieter des Diensts über ein WAN-Interface verlaufen würde. 803 ## @param service_name der Name des Diensts 804 ## @returns Exitcode == 0, falls das Routing über das WAN-Interface verläuft. 806 trap
'error_trap is_service_routed_via_wan "$*"' EXIT
807 local service_name=
"$1" 808 # verwende die übergebene TypeOfService-Angabe oder (falls vorhanden/installiert) den 809 # TOS-Wert, der fuer nicht-Tunnel-Verkehr verwendet wird (typischerweise ist dies die 810 # die Intention des Anfragenden) 811 local tos_field=
"${2:-}" 812 [ -z
"$tos_field" ] && tos_field=
"${TOS_NON_TUNNEL:-}" 814 local outgoing_device
818 if is_device_in_zone
"$outgoing_device" "$ZONE_WAN"; then
819 msg_debug "target '$host' routing through wan device: $outgoing_device" 823 msg_debug "warning: target '$host' is routed via interface '$outgoing_device' (zone '$outgoing_zone') instead of the expected WAN zone ($ZONE_WAN)" 824 trap
"" EXIT &&
return 1
829 _notify_service_success() {
830 local service_name=
"$1" 837 _notify_service_failure() {
838 local service_name=
"$1" 839 local max_fail_attempts=
"$2" 840 # erhoehe den Fehlerzaehler 842 fail_counter=$(( $(
get_service_value "$service_name" "status_fail_counter" "0") + 1))
844 # Pruefe, ob der Fehlerzaehler gross genug ist, um seinen Status auf
"fail" zu setzen.
845 if [
"$fail_counter" -ge
"$max_fail_attempts" ]; then
846 # Die maximale Anzahl von aufeinanderfolgenden fehlgeschlagenen Tests wurde erreicht:
847 # markiere ihn als kaputt.
849 elif uci_is_true
"$(get_service_value "$service_name
" "status
")"; then
850 # Bisher galt der Dienst als funktionsfaehig - wir setzen ihn auf
"neutral" bis
851 # die maximale Anzahl aufeinanderfolgender Fehler erreicht ist.
854 # Der Test gilt wohl schon als fehlerhaft - das kann so bleiben.
861 ## @fn is_trusted_service_list_outdated() 862 ## @brief Ermittle ob mindestens ein Zeitstempel für einen "trusted" Dienst vorhanden ist, der nicht älter 863 ## als die vorgegebene Aktualisierungsperiode ist. 864 ## @returns Wahr, falls kein Diest mit aktuellem Zeitstempel gefunden wurde. 866 trap
'error_trap is_trusted_service_list_outdated "$*"' EXIT
867 local most_recent_timestamp
872 # kein Zeitstempel -> dies gilt als
"veraltet" 873 [ -z
"$most_recent_timestamp" ] &&
return 0
874 # der aktuellste Zeitstempel ist zu alt
875 is_timestamp_older_minutes
"$most_recent_timestamp" "$UPDATE_TRUSTED_SERVICES_PERIOD_MINUTES" &&
return 0
876 trap
"" EXIT &&
return 1
880 retrieve_service_list_url() {
882 if is_function_available
"https_request_opennet"; then
883 https_request_opennet
"$url" \
884 || http_request
"$url" \
885 ||
msg_info "Failed to retrieve list of services from $url" 887 if ! http_request
"$url"; then
888 if echo
"$url" | grep -q
'^https://'; then
889 # The URL probably uses a certificate signed by the Opennet CA, 890 # while "on-certificate" is not installed. 891 # Thus we do not emit any warnings. 894 msg_info "Failed to retrieve list of services from $url" 901 ## @fn update_trusted_services_list() 902 ## @brief Hole die vertrauenswürdigen Dienste von signierten Opennet-Quellen. 903 ## @details Diese Dienste führen beispielsweise auf UGW-APs zur Konfiguration von Portweiterleitungen 904 ## ins Internet. Daher sind sie nur aus vertrauenswürdiger Quelle zu akzeptieren (oder manuell). 917 service_list=$(
for url in $SERVICES_LIST_URLS;
do retrieve_service_list_url
"$url";
done)
918 # leeres Ergebnis? Noch keine Internet-Verbindung? Keine Aktualisierung, keine Beraeumung ...
919 [ -z
"$service_list" ] &&
msg_info "No trusted services discovered: skipping update." &&
return 920 echo
"$service_list" | grep -v
"^#" | sed
's/\t\+/\t/g' |
while read -r line;
do 921 service_type=$(echo
"$line" | cut -f 1)
922 # falls der Dienst-Typ mit
"proxy-" beginnt, soll er weitergeleitet werden
923 if [
"${service_type#$RELAYABLE_SERVICE_PREFIX}" =
"$service_type" ]; then
929 # entferne das Praefix 931 scheme=$(echo
"$line" | cut -f 2)
932 host=$(echo
"$line" | cut -f 3)
933 port=$(echo
"$line" | cut -f 4)
934 protocol=$(echo
"$line" | cut -f 5)
935 priority=$(echo
"$line" | cut -f 6)
936 details=$(echo
"$line" | cut -f 7-)
937 service_name=$(
notify_service "trusted" "$service_type" "$scheme" "$host" "$port" "$protocol" "/" "$details")
939 if [ -n
"$is_proxy" ]; then
940 if is_function_available
"pick_local_service_relay_port"; then
941 pick_local_service_relay_port
"$service_name" >/dev/
null 946 # veraltete Dienste entfernen 948 min_timestamp=$(($(get_uptime_minutes) - $(get_on_core_default
"trusted_service_expire_minutes")))
949 # falls die uptime kleiner ist als die Verfallszeit, dann ist ein Test sinnfrei 950 if [
"$min_timestamp" -gt 0 ]; then
953 # Wurde der Service erst vor kurzem aktualisiert? Sonst loeschen ...
954 [
"$timestamp" -ge
"$min_timestamp" ] || delete_service
"$service_name" 957 # aktualisiere DNS- und NTP-Dienste
958 apply_changes on-core
963 ## @brief Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist 964 ## @param test_function der Name der zu verwendenden Test-Funktion für einen Dienst (z.B. "verify_vpn_connection") 965 ## @param test_period_minutes Wiederholungsperiode der Dienst-Prüfung 966 ## @param max_fail_attempts Anzahl von Fehlversuchen, bis ein Dienst von "gut" oder "unklar" zu "schlecht" wechselt 967 ## @details Die Diensteanbieter werden in der Reihenfolge ihrer Priorität geprüft. 968 ## Nach dem ersten Durchlauf dieser Funktion sollte typischerweise der nächstgelegene nutzbare Dienst 969 ## als funktionierend markiert sein. 970 ## Falls nach dem Durchlauf aller Dienste keiner positiv getestet wurde (beispielsweise weil alle Zeitstempel zu frisch sind), 971 ## dann wird in jedem Fall der älteste nicht-funktionsfähige Dienst getestet. Dies minimiert die Ausfallzeit im 972 ## Falle einer globalen Nicht-Erreichbarkeit aller Dienstenanbieter ohne auf den Ablauf der Test-Periode warten zu müssen. 973 ## @attention Seiteneffekt: die Zustandsinformationen des getesteten Diensts (Status, Test-Zeitstempel) werden verändert. 975 trap
'error_trap test_openvpn_service_type "$*"' EXIT
976 local test_function=
"$1" 977 local test_period_minutes=
"$2" 978 local max_fail_attempts=
"$3" 987 if [ -z
"$status" ] || is_timestamp_older_minutes
"$timestamp" "$test_period_minutes"; then
988 if "$test_function" "$service_name"; then
989 msg_debug "service $service_name successfully tested" 990 _notify_service_success
"$service_name" 991 # wir sind fertig - keine weiteren Tests 992 # Da "return" aufgrund der Pipe nicht die gesamte Funktion beenden 993 # würde, senden wir stattdessen die Markierung fuer "keine Tests 994 # noetig" und beenden die Schleife. 995 printf
'%s %s\n' "-1" "$service_name" 998 msg_debug "failed to verify $service_name" 999 _notify_service_failure
"$service_name" "$max_fail_attempts" 1001 elif uci_is_false
"$status"; then
1002 # Junge "kaputte" Dienste sind potentielle Kandidaten fuer einen vorzeitigen Test, falls 1003 # ansonsten kein Dienst positiv getestet wurde. 1004 echo
"$timestamp $service_name" 1006 # funktionsfaehige "alte" Dienste - es gibt nichts fuer sie zu tun 1007 # Wir sortieren sie nach ganz oben, um bei Existenz eines lauffaehigen Diensts 1008 # keine unnoetigen Tests von nicht-funktionierenden Hosts durchzufuehren. 1009 printf
'%s %s\n' "-1" "$service_name" 1011 done | sort -n |
while read -r timestamp service_name;
do 1012 # Mit dem Zeitstempel "-1" sind funktionierende Dienste markiert. Wir brauchen also keine 1014 [
"$timestamp" =
"-1" ] &&
return 0
1015 # Hier landen wir nur, falls alle defekten Gateways zu jung fuer einen Test waren und 1016 # gleichzeitig kein Dienst erfolgreich getestet wurde bzw. als erfolgreich gilt. 1017 # Dies stellt sicher, dass nach einer kurzen Nicht-Erreichbarkeit aller Gateways (z.B. olsr-Ausfall) 1018 # relativ schnell wieder ein funktionierender Gateway gefunden wird, obwohl alle Test-Zeitstempel noch recht 1020 msg_debug "there is no service to be tested - thus we pick the service with the oldest test timestamp: $service_name" 1021 if "$test_function" "$service_name"; then
1022 _notify_service_success
"$service_name" 1024 _notify_service_failure
"$service_name" "$max_fail_attempts" 1026 # wir wollen nur genau einen Test durchfuehren 1031 # Ende der Doku-Gruppe get_hop_count_and_etx(host)
Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück.
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...
notify_service()
Aktualisiere den Zeitstempel und die Entfernung (etx, service, scheme, host, port, path, protocol, details) eines Dienstes.
move_service_down(service_name, service_type)
Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach unten.
_get_local_bias_for_service()
Ermittle eine reproduzierbare Zahl von 0 bis (LOCAL_BIAS_MODULO-1, service_name) - abhängig von der l...
get_service_log_content(service, max_lines)
Lies den Inhalt einer Log-Datei für einen Dienst aus.
get_zone_of_device(interface)
Ermittle die Zone eines physischen Netzwerk-Interfaces.
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...
move_service_top(service_name, service_types)
Verschiebe einen Dienst an die Spitze der Dienst-Sortierung.
pipe_service_attribute(key, default)
Liefere zu einer Reihe von Diensten ein gewähltes Attribut dieser Dienste zurück. ...
update_trusted_services_list()
Hole die vertrauenswürdigen Dienste von signierten Opennet-Quellen.
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
run_cyclic_service_tests(test_function)
Durchlaufe alle via STDIN angegebenen Dienste bis mindestens ein Test erfolgreich ist...
sort_services_by_priority()
Sortiere den eingegebenen Strom von Dienstnamen und gib eine nach der Priorität sortierte Liste...
filter_services_by_value(key, value)
set eu grep root::etc shadow exit if command v chpasswd dev null
move_service_up(service_name, service_type)
Verschiebe einen Dienst in der Dienst-Sortierung um eine Stufe nach oben.
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
is_trusted_service_list_outdated()
Ermittle ob mindestens ein Zeitstempel für einen "trusted" Dienst vorhanden ist, der nicht älter als ...
set_service_detail(service_name, key, value)
Setze den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts.
print_services(service_type)
menschenfreundliche Ausgabe der aktuell angemeldeten Dienste
notify_services(source)
Siehe "notify_service" - jedoch effizienter im Umgang mit einer großen Anzahl von Diensten...
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
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.
msg_error(message)
Die Fehlermeldungen werden in die Standard-Fehlerausgabe und ins syslog geschrieben.
get_service_detail(service_name, key, default)
Ermittle den Wert eines Schlüssel-Wert-Paars im "details"-Attribut eines Diensts. ...
is_service_routed_via_wan(service_name)
Pruefe ob der Verkehr zum Anbieter des Diensts über ein WAN-Interface verlaufen würde.
get_service_name()
Ermittle en Namen eines Diensts basierend auf den Dienst-Attributen.
get_target_route_interface(target)
Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde.
is_existing_service(service_name)
Prüfe ob ein Service existiert.