1## @defgroup routing Routing 
    2## @brief Abfrage von Routing-Informationen und Einrichtung des Policy-Routings. 
    3# Beginn der Doku-Gruppe 
    6ROUTING_TABLE_ON_UPLINK=on-tunnel
 
    7ROUTING_TABLE_MESH=olsrd
 
    8ROUTING_TABLE_MESH_DEFAULT=olsrd-
default 
    9OLSR_POLICY_DEFAULT_PRIORITY=20000
 
   10RT_FILE=/etc/iproute2/rt_tables
 
   12# Prioritaets-Offset fuer default-Routing-Tabellen (z.B. "default" und "olsrd-default")
 
   13# shellcheck disable=SC2034 
   14DEFAULT_RULE_PRIO_OFFSET=100
 
   15OLSR_ROUTE_CACHE_FILE=/tmp/olsr_routes.cache
 
   19## @brief Prüfe ob der übergebene Text eine IPv4-Adresse ist 
   20## @param target eine Zeichenkette (wahrscheinlich ein DNS-Name, eine IPv4- oder IPv6-Adresse) 
   21## @details Die IP-Adresse darf mit einem Netzwerkpraefix enden. 
   24    echo 
"$target" | grep -q -E 
'^[0-9]+(\.[0-9]+){3}(/[0-9]+)?$' 
   29## @brief Prüfe ob der übergebene Text eine IPv6-Adresse ist 
   30## @param target eine Zeichenkette (wahrscheinlich ein DNS-Name, eine IPv4- oder IPv6-Adresse) 
   31## @details Achtung: der Test ist recht oberflächlich und kann falsche Positive liefern. 
   34    echo 
"$target" | grep -q -E 
"^[0-9a-fA-F:]+(/[0-9]+)?$" 
   38## @fn filter_routable_addresses() 
   39## @brief Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert. 
   40## @details Lies IP-Addressen zeilenweise via stdin ein und gib alle Adressen aus, die (laut "ip route get") erreichbar sind.
 
   41##   Dies bedeutet nicht, dass wir mit den Adressen kommunizieren koennen - es geht lediglich um lokale Routing-Regeln. 
   42## @return zeilenweise Ausgabe der route-baren Ziel-IPs:w 
   46        [ -z 
"$(get_target_route_interface "$ip
")" ] || echo 
"$ip" 
   52## @fn get_target_route_interface() 
   53## @brief Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde. 
   54## @param target Hostname oder IP des Ziel-Hosts 
   55## @details Falls erforderlich, findet eine Namensauflösung statt. 
   56## @return Name des physischen Netzwerk-Interface, über den der Verkehr zum Ziel-Host fließen würde 
   65        all_addresses=
$(query_dns 
"$target")
 
   67    for ipaddr in $all_addresses; do
 
   68        # "failed_policy" wird von ipv6 fuer nicht-zustellbare Adressen zurueckgeliefert
 
   69        # Falls ein Hostname mehrere IP-Adressen ergibt (z.B. ipv4 und ipv6), dann werden beide geprüft. 
   70        # Die Ergebnis der Interface-Ermittlung für eine IPv6-Adresse bei fehlendem IPv6-Gateway sieht folgendermaßen aus: 
   71        #    root@AP-1-193:/tmp/log/on-services# ip route get 2a01:4f8:140:1222::1:7 
   72        #    12 2a01:4f8:140:1222::1:7 from :: dev lo  src fe80::26a4:3cff:fefd:7649  metric -1  error -1 
   74        #    root@AP-2-156:~# ip route get 2001:67c:1400:2430::1 
   75        #    prohibit 2001:67c:1400:2430::1 from :: dev lo  table unspec  proto kernel  src fe80::216:3eff:fe34:2aa5  metric 4294967295  error -13 
   76        # Wir ignorieren also Zeilen, die auf "error -1" oder "error -13" enden.
 
   77        # Fehlermeldungen (ip: RTNETLINK answers: Network is unreachable) werden ebenfalls ignoriert. 
   78        # shellcheck disable=SC2086 
   79        ip route get 
"$ipaddr" $route_get_args 2>/dev/
null \
 
   80            | grep -vE 
"^(failed_policy|prohibit)" \
 
   81            | grep -vE 
"error -(1|13)$" \
 
   83            | sed 
's/^.* dev \+\([^ \t]\+\) \+.*$/\1/' 
   88# Entferne alle Policy-Routing-Regeln die dem gegebenen Ausdruck entsprechen. 
   89# Es erfolgt keine Fehlerausgabe und keine Fehlermeldungen. 
   93    while ip -family 
"$family" rule del 
"$@"; 
do true; 
done 2>/dev/
null 
   97## @fn add_network_policy_rule_by_destination() 
   98## @brief erzeuge Policy-Rules entsprechend der IP-Bereiche eines Netzwerks 
   99## @param network logisches Netzwerkinterface 
  100## @param more weitere Parameter: Policy-Rule-Spezifikation 
  102    trap 
'error_trap add_network_policy_rule_by_destination "$*"' EXIT
 
  106    local network_with_prefix
 
  108        is_ipv4 "$network_with_prefix" && [ 
"$family" != 
"inet" ] && 
continue 
  109        is_ipv6 "$network_with_prefix" && [ 
"$family" != 
"inet6" ] && 
continue 
  110        ip -family 
"$family" rule add to 
"$network_with_prefix" "$@" || 
true 
  116## @fn add_zone_policy_rules_by_iif() 
  117## @brief Erzeuge Policy-Rules fuer Quell-Interfaces 
  118## @param family "inet" oder "inet6"
 
  119## @param zone Pakete aus allen Interfaces dieser Zone kommend sollen betroffen sein 
  120## @param route Spezifikation einer Route (siehe 'ip route add ...') 
  122    trap 
'error_trap add_zone_policy_rules "$*"' EXIT
 
  128    # ermittle alle physischen Geräte inklusive Bridge-Interfaces, die zu dieser Zone gehören 
  129    for interface in 
$(get_zone_log_interfaces "$zone"); 
do 
  134    done | sort | uniq | 
while read -r device; 
do 
  135        [ -n 
"$device" ] && [ 
"$device" != 
"none" ] && ip -family 
"$family" rule add iif 
"$device" "$@" 
  142## @fn initialize_olsrd_policy_routing() 
  143## @brief Policy-Routing-Initialisierung nach dem System-Boot und nach Interface-Hotplug-Ereignissen 
  144## @details Folgende Seiteneffekte treten ein: 
  145##   * alle Policy-Rules mit Bezug zu den Tabellen olsrd/olsrd-default/main werden gelöscht 
  146##   * die neuen Policy-Rules für die obigen Tabellen werden an anderer Stelle erzeugt 
  147##   Kurz gesagt: alle bisherigen Policy-Rules sind hinterher kaputt 
  149    trap 
'error_trap initialize_olsrd_policy_routing "$*"' EXIT
 
  151    local priority=
"$OLSR_POLICY_DEFAULT_PRIORITY" 
  153    # Sicherstellen, dass die Tabellen existieren und zur olsrd-Konfiguration passen 
  155    # die Uplink-Tabelle ist unabhaengig von olsr 
  158    # alle Eintraege loeschen 
  159    delete_policy_rule inet table 
"$ROUTING_TABLE_MESH" 
  160    delete_policy_rule inet table 
"$ROUTING_TABLE_MESH_DEFAULT" 
  161    delete_policy_rule inet table 
"$ROUTING_TABLE_ON_UPLINK" 
  162    delete_policy_rule inet table main
 
  163    delete_policy_rule inet table 
default 
  165    # free-Verkehr geht immer in den Tunnel (falls das Paket installiert ist) 
  166    if [ -n 
"${ZONE_FREE:-}" ]; then
 
  168        priority=
$((priority + 1))
 
  171    # sehr wichtig - also zuerst: keine vorbeifliegenden Mesh-Pakete umlenken 
  173    priority=
$((priority + 1))
 
  175    priority=
$((priority + 1))
 
  177    # Pakete mit passendem Ziel orientieren sich an der main-Tabelle 
  178    # Alle Ziele ausserhalb der mesh-Zone sind geeignet (z.B. local, free, ...). 
  179    # Wir wollen dadurch explizit keine potentielle default-Route verwenden. 
  180    # Aufgrund der "while"-Sub-Shell (mit separatem Variablenraum) belassen wir die Regeln
 
  181    # einfach bei gleicher Prioritaet und erhoehen diese erst anschliessend. 
  182    for iface in 
$(get_all_network_interfaces); 
do 
  183        is_interface_in_zone 
"$iface" "$ZONE_MESH" && 
continue 
  186    priority=
$((priority + 1))
 
  188    # alle nicht-mesh-Quellen routen auch ins olsr-Netz 
  189    #TODO: wir sollten nur private Ziel-IP-Bereiche (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) zulassen 
  190    # spaeter sind konfigurierbar weitere IPs (fuer HNAs oeffentlicher Dienste) moeglich 
  191    ip rule add table 
"$ROUTING_TABLE_MESH" prio 
"$priority" 
  192    priority=
$((priority + 1))
 
  193    ip rule add table "$ROUTING_TABLE_MESH_DEFAULT" prio "$priority"
 
  194    priority=
$((priority + 1))
 
  196    # Routen, die nicht den lokalen Netz-Interfaces entsprechen (z.B. default-Routen) 
  197    ip rule add table main prio 
"$priority" 
  198    priority=
$((priority + 1))
 
  200    # die default-Table und VPN-Tunnel fungieren fuer alle anderen Pakete als default-GW 
  201    ip rule add table 
default prio 
"$priority" 
  202    priority=
$((priority + 1))
 
  203    ip rule add table "$ROUTING_TABLE_ON_UPLINK" prio "$priority"
 
  204    priority=
$((priority + 1))
 
  208# Stelle sicher, dass eine sinnvolle routing-Tabellen-Datei existiert. 
  209# Dies ist erforderlich, falls kein echtes "ip"-Paket installiert ist (im busybox-Paket ist die Datei nicht enthalten).
 
  210_prepare_routing_table_file() {
 
  211    [ -e 
"$RT_FILE" ] && 
return 0
 
  212    mkdir -p 
"$(dirname "$RT_FILE
")" 
  213    cat >
"$RT_FILE" << EOF
 
  214# erzeugt von "on-core" 
  228## @fn get_routing_table_id() 
  229## @brief Ermittle die Nummer der namentlich gegebenen Routing-Tabelle. 
  230## @param table_name Name der gesuchten Routing-Tabelle 
  231## @return Routing-Tabellen-ID oder nichts (falls die Tabelle nicht existiert) 
  233    local table_name=
"$1" 
  234    _prepare_routing_table_file
 
  235    # Tabellennummer ausgeben, falls sie vorhanden ist 
  236    grep 
'^[0-9]\+[ \t]\+'"$table_name$" "$RT_FILE" | awk 
'{print $1}' 
  241## @fn add_routing_table() 
  242## @brief Erstelle einen neuen Routing-Tabellen-Eintrag. 
  243## @param table_name der Name der zu erstellenden Routing-Tabelle 
  244## @details Die Routing-Tabellen-Nummer wird automatisch ermittelt. 
  245##    Sollte die Tabelle bereits existieren, dann wird ihre Nummer zurückgeliefert. 
  246## @return die neue Routing-Tabellen-Nummer wird zurückgeliefert 
  248    trap 
'error_trap add_routing_table "$*"' EXIT
 
  249    local table_name=
"$1" 
  250    _prepare_routing_table_file
 
  254    [ -n 
"$table_id" ] && echo 
"$table_id" && 
return 0
 
  255    # wir muessen den Eintrag hinzufuegen 
  256    table_id=
"$RT_START_ID" 
  257    while [ -n 
"$(_get_file_dict_value "$table_id
" "$RT_FILE
")" ]; 
do 
  258        table_id=
$((table_id + 1))
 
  260    echo "$table_id      $table_name" >> "$RT_FILE"
 
  265## @fn get_hop_count_and_etx() 
  266## @brief Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück. 
  267## @param host die Ziel-IP 
  268## @returns Der Hop-Count und der ETX-Wert wird mit einem Leerzeichen separiert ausgegeben. Falls keine Route bekannt ist, ist das Ergebnis ein leerer String. 
  269## @details Die Quelle dieser Information ist olsrd. Routen außerhalb von olsrd werden nicht beachtet. 
  273    # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob) 
  274    [ ! -e 
"$OLSR_ROUTE_CACHE_FILE" ] && 
return 0
 
  275    result=
$(awk 
'{ if ($1 == "'"$target"'") { print $3, $4; exit; } }' <
"$OLSR_ROUTE_CACHE_FILE")
 
  276    [ -n 
"$result" ] && echo 
"$result" && 
return 0
 
  277    # Überprüfe, ob die IP des Zielhost die eigene IP ist. Dann sollte distance=0 gesetzt werden. 
  279        result=
$(ip route get 
"$target" 2>/dev/
null | grep -w 
"dev lo" || 
true)
 
  280        [ -n 
"$result" ] && echo 
"$result" | grep -vq 
"^unreachable" && echo 
"0 0" && 
return 0
 
  283    # Hole Daten von OLSR2 
  284    if is_ipv6 "$target" && is_function_available 
"request_olsrd2_txtinfo"; then
 
  285        request_olsrd2_txtinfo 
"olsrv2info" "route" \
 
  286            | awk 
'{ if ($1 == "'"$target"'") { cost=$(NF-1); hops=$NF; print(hops, 1 / cost) }}' 
  291## @fn get_traceroute() 
  292## @brief Liefere einen traceroute zu einem Host zurueck. 
  293## @param host der Ziel-IP 
  294## @return Eine mit Komma getrennte Liste von IPs 
  299    # wenn kein Parameter uebergeben, dann breche ab 
  300    [ -z 
"$target" ] && 
return 0
 
  303    #  - erste Zeile auslassen (traceroute-Header) 
  304    #  - unbekannte Hops ignorieren ("*" oder "???")
 
  305    #  - Einträge durch Kommata separieren 
  306    #  - unterdrücke Fehler (z.B. keine Route zum Host) 
  307    timeout 20 traceroute -w 1 -q 1 -n 
"$target" 2>/dev/
null | awk 
' 
  308        { if ((NR > 1) && ($2 != "*") && ($2 != "???") && $2) { 
  318# Diese Funktion sollte oft (minuetlich?) aufgerufen werden, um die olsrd-Routing-Informationen abzufragen. 
  319# Dies ist noetig, um deadlocks bei parallelem Zugriff auf den single-thread olsrd zu verhindern. 
  320# Symptome eines deadlocks: olsrd ist beendet; viele parallele nc-Instanzen; eine davon ist an den txtinfo-Port gebunden. 
  321update_olsr_route_cache() {
 
  322    trap 
'error_trap update_olsr_route_cache "$*"' EXIT
 
  323    # die temporaere Datei soll verhindern, dass es zwischendurch ein Zeitfenster mit unvollstaendigen Informationen gibt 
  324    local tmpfile=
"${OLSR_ROUTE_CACHE_FILE}.new" 
  325    # Bei der Ausfuehrung via cron wird SIGPIPE eventuell behandelt, auf dass die Ausfuehrung 
  326    # ohne Erzeugung der Datei abbrechen koennte. Daher ist die &&-Verknuepfung sinnvoll. 
  327    request_olsrd_txtinfo rou | sed 
'/^[^0-9]/d; s#/32##' > 
"$tmpfile" && mv 
"$tmpfile" "$OLSR_ROUTE_CACHE_FILE" 
  332## @fn get_olsr_route_count_by_device() 
  333## @brief Liefere die Anzahl von olsr-Routen, die auf ein bestimmtes Netzwerk-Interface verweisen 
  335    local device_regex=
"$1" 
  336    # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob) 
  337    [ -e 
"$OLSR_ROUTE_CACHE_FILE" ] || 
return 0
 
  338    awk 
'{ print $5 }' "$OLSR_ROUTE_CACHE_FILE" | grep -c 
"^$device_regex$" || 
true 
  342## @fn get_olsr_route_count_by_neighbour() 
  343## @brief Liefere die Anzahl von olsr-Routen, die auf einen bestimmten Routing-Nachbarn verweisen. 
  345    local neighbour_ip=
"$1" 
  346    # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob) 
  347    [ -e 
"$OLSR_ROUTE_CACHE_FILE" ] || 
return 0
 
  348    awk 
'BEGIN { count=0; } { if ($2 == "'"$neighbour_ip"'") count++; } END { print count; }' "$OLSR_ROUTE_CACHE_FILE" 
  352## @fn get_olsr_neighbours() 
  353## @brief Ermittle die direkten olsr-Nachbarn und liefere ihre IPs und interessante Kennzahlen zurück. 
  354## details Ergebnisformat: NEIGHBOUR_IP LINK_QUALITY NEIGHBOUR_LINK_QUALITY ETX ROUTE_COUNT 
  361    local ip_interface_map
 
  362    local interface_description
 
  365            | 
while read -r local_ip neighbour_ip lq nlq etx; 
do 
  366        # there may be one or more interfaces (e.g. multiple TAP tunnels for UGW APs) 
  367        interface_description=
$(echo 
"$ip_interface_map" | grep -wF 
"$local_ip" | awk 
'{print $2}' | tr 
'\n' '/' | sed 
's#/$##')
 
  368        [ -z 
"$interface_description" ] && interface_description=
"unknown" 
  369        echo 
"$neighbour_ip $interface_description $lq $nlq $etx $(get_olsr_route_count_by_neighbour "$neighbour_ip
")" 
  373# Ende der Doku-Gruppe 
get_subdevices_of_interface()
Ermittle die physischen Netzwerk-Geräte (bis auf wifi), die zu einem logischen Netzwerk-Interface geh...
get_device_of_interface()
Ermittle das physische Netzwerk-Gerät, das einem logischen Netzwerk entspricht.
get_current_addresses_of_network()
Liefere die IP-Adressen eines logischen Interface inkl. Praefix-Laenge (z.B. 172.16....
olsr_sync_routing_tables()
Synchronisiere die olsrd-Routingtabellen-Konfiguration mit den iproute-Routingtabellennummern.
request_olsrd_txtinfo(request)
Sende eine Anfrage an das txtinfo-Interface von olsrd.
get_hop_count_and_etx(host)
Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück.
add_network_policy_rule_by_destination(network, more)
erzeuge Policy-Rules entsprechend der IP-Bereiche eines Netzwerks
add_routing_table(table_name)
Erstelle einen neuen Routing-Tabellen-Eintrag.
get_traceroute(host)
Liefere einen traceroute zu einem Host zurueck.
get_target_route_interface(target)
Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde.
add_zone_policy_rules_by_iif(family, zone, route)
Erzeuge Policy-Rules fuer Quell-Interfaces.
is_ipv4(target)
Prüfe ob der übergebene Text eine IPv4-Adresse ist.
get_olsr_route_count_by_neighbour()
Liefere die Anzahl von olsr-Routen, die auf einen bestimmten Routing-Nachbarn verweisen.
get_olsr_route_count_by_device()
Liefere die Anzahl von olsr-Routen, die auf ein bestimmtes Netzwerk-Interface verweisen.
is_ipv6(target)
Prüfe ob der übergebene Text eine IPv6-Adresse ist.
initialize_olsrd_policy_routing()
Policy-Routing-Initialisierung nach dem System-Boot und nach Interface-Hotplug-Ereignissen.
get_routing_table_id(table_name)
Ermittle die Nummer der namentlich gegebenen Routing-Tabelle.
filter_routable_addresses()
Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert...
get_olsr_neighbours()
Ermittle die direkten olsr-Nachbarn und liefere ihre IPs und interessante Kennzahlen zurück....
set eu grep root::etc shadow exit if command v chpasswd dev null