Opennet Firmware
 Alle Dateien Funktionen Variablen Gruppen Seiten
routing.sh
gehe zur Dokumentation dieser Datei
1 ## @defgroup routing Routing
2 ## @brief Abfrage von Routing-Informationen und Einrichtung des Policy-Routings.
3 # Beginn der Doku-Gruppe
4 ## @{
5 
6 ROUTING_TABLE_ON_UPLINK=on-tunnel
7 ROUTING_TABLE_MESH=olsrd
8 ROUTING_TABLE_MESH_DEFAULT=olsrd-default
9 OLSR_POLICY_DEFAULT_PRIORITY=20000
10 RT_FILE=/etc/iproute2/rt_tables
11 RT_START_ID=11
12 # Prioritaets-Offset fuer default-Routing-Tabellen (z.B. "default" und "olsrd-default")
13 DEFAULT_RULE_PRIO_OFFSET=100
14 OLSR_ROUTE_CACHE_FILE=/tmp/olsr_routes.cache
15 
16 
17 ## @fn is_ipv4()
18 ## @brief Prüfe ob der übergebene Text eine IPv4-Adresse ist
19 ## @param target eine Zeichenkette (wahrscheinlich ein DNS-Name, eine IPv4- oder IPv6-Adresse)
20 is_ipv4() {
21  local target="$1"
22  echo "$target" | grep -q -E "^[0-9]+(\.[0-9]+){3}$"
23 }
24 
25 
26 ## @fn is_ipv6()
27 ## @brief Prüfe ob der übergebene Text eine IPv6-Adresse ist
28 ## @param target eine Zeichenkette (wahrscheinlich ein DNS-Name, eine IPv4- oder IPv6-Adresse)
29 ## @details Achtung: der Test ist recht oberflächlich und kann falsche Positive liefern.
30 is_ipv6() {
31  local target="$1"
32  echo "$target" | grep -q "^[0-9a-fA-F:]\+$"
33 }
34 
35 
36 ## @fn filter_routable_addresses()
37 ## @brief Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert.
38 ## @details Lies IP-Addressen zeilenweise via stdin ein und gib alle Adressen aus, die (laut "ip route get") erreichbar sind.
39 ## Dies bedeutet nicht, dass wir mit den Adressen kommunizieren koennen - es geht lediglich um lokale Routing-Regeln.
40 ## @return zeilenweise Ausgabe der route-baren Ziel-IPs:w
42  local ip
43  while read ip; do
44  [ -n "$(get_target_route_interface "$ip")" ] && echo "$ip" || true
45  done
46  return 0
47 }
48 
49 
50 ## @fn get_target_route_interface()
51 ## @brief Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde.
52 ## @param target Hostname oder IP des Ziel-Hosts
53 ## @details Falls erforderlich, findet eine Namensauflösung statt.
54 ## @return Name des physischen Netzwerk-Interface, über den der Verkehr zum Ziel-Host fließen würde
56  local target=$1
57  local ipaddr
58  if is_ipv4 "$target" || is_ipv6 "$target"; then
59  echo "$target"
60  else
61  query_dns "$target"
62  fi | while read ipaddr; do
63  # "failed_policy" wird von ipv6 fuer nicht-zustellbare Adressen zurueckgeliefert
64  # Falls ein Hostname mehrere IP-Adressen ergibt (z.B. ipv4 und ipv6), dann werden beide geprüft.
65  # Die Ergebnis der Interface-Ermittlung für eine IPv6-Adresse bei fehlendem IPv6-Gateway sieht folgendermaßen aus:
66  # root@AP-1-193:/tmp/log/on-services# ip route get 2a01:4f8:140:1222::1:7
67  # 12 2a01:4f8:140:1222::1:7 from :: dev lo src fe80::26a4:3cff:fefd:7649 metric -1 error -1
68  # Wir ignorieren also Zeilen, die auf "error -1" enden.
69  # Fehlermeldungen (ip: RTNETLINK answers: Network is unreachable) werden ebenfalls ignoriert.
70  ip route get "$ipaddr" 2>/dev/null | grep -v ^failed_policy | grep -v "error -1$" | grep " dev " | sed 's/^.* dev \+\([^ \t]\+\) \+.*$/\1/'
71  done | tail -1
72 }
73 
74 
75 # Entferne alle Policy-Routing-Regeln die dem gegebenen Ausdruck entsprechen.
76 # Es erfolgt keine Fehlerausgabe und keine Fehlermeldungen.
77 delete_policy_rule() {
78  while ip rule del "$@"; do true; done 2>/dev/null
79 }
80 
81 
82 # erzeuge Policy-Rules entsprechend der IP-Bereiche eines Netzwerks
83 # Parameter: logisches Netzwerkinterface
84 # weitere Parameter: Rule-Spezifikation
85 add_network_policy_rule_by_destination() {
86  trap "error_trap add_network_policy_rule_by_destination '$*'" $GUARD_TRAPS
87  local network="$1"
88  shift
89  local networkprefix
90  for networkprefix in $(get_address_of_network "$network"); do
91  [ -n "$networkprefix" ] && ip rule add to "$networkprefix" "$@" || true
92  done
93  return 0
94 }
95 
96 
97 ## @fn add_zone_policy_rules_by_iif()
98 ## @brief Erzeuge Policy-Rules fuer Quell-Interfaces
99 ## @param zone Pakete aus allen Interfaces dieser Zone kommend sollen betroffen sein
100 ## @param route Spezifikation einer Route (siehe 'ip route add ...')
102  trap "error_trap add_zone_policy_rules '$*'" $GUARD_TRAPS
103  local zone=$1
104  shift
105  local device
106  for device in $(get_zone_devices "$zone"); do
107  [ -n "$device" -a "$device" != "none" ] && ip rule add iif "$device" "$@" || true
108  done
109  return 0
110 }
111 
112 
113 ## @fn initialize_olsrd_policy_routing()
114 ## @brief Policy-Routing-Initialisierung nach dem System-Boot und nach Interface-Hotplug-Ereignissen
115 ## @details Folgende Seiteneffekte treten ein:
116 ## * alle Policy-Rules mit Bezug zu den Tabellen olsrd/olsrd-default/main werden gelöscht
117 ## * die neuen Policy-Rules für die obigen Tabellen werden an anderer Stelle erzeugt
118 ## Kurz gesagt: alle bisherigen Policy-Rules sind hinterher kaputt
120  trap "error_trap initialize_olsrd_policy_routing '$*'" $GUARD_TRAPS
121  local iface
122  local current
123  local table
124  local priority=$OLSR_POLICY_DEFAULT_PRIORITY
125 
126  # Sicherstellen, dass die Tabellen existieren und zur olsrd-Konfiguration passen
128  # die Uplink-Tabelle ist unabhaengig von olsr
129  [ -z "$(get_routing_table_id "$ROUTING_TABLE_ON_UPLINK")" ] && add_routing_table "$ROUTING_TABLE_ON_UPLINK" >/dev/null
130 
131  # alle Eintraege loeschen
132  delete_policy_rule table "$ROUTING_TABLE_MESH"
133  delete_policy_rule table "$ROUTING_TABLE_MESH_DEFAULT"
134  delete_policy_rule table "$ROUTING_TABLE_ON_UPLINK"
135  delete_policy_rule table main
136  delete_policy_rule table default
137 
138  # free-Verkehr geht immer in den Tunnel
139  add_zone_policy_rules_by_iif "$ZONE_FREE" table "$ROUTING_TABLE_ON_UPLINK" prio "$((priority++))"
140 
141  # sehr wichtig - also zuerst: keine vorbeifliegenden Mesh-Pakete umlenken
142  add_zone_policy_rules_by_iif "$ZONE_MESH" table "$ROUTING_TABLE_MESH" prio "$((priority++))"
143  add_zone_policy_rules_by_iif "$ZONE_MESH" table "$ROUTING_TABLE_MESH_DEFAULT" prio "$((priority++))"
144 
145  # Pakete mit passendem Ziel orientieren sich an der main-Tabelle
146  # Alle Ziele ausserhalb der mesh-Zone sind geeignet (z.B. local, free, ...).
147  # Wir wollen dadurch explizit keine potentielle default-Route verwenden.
148  # Aufgrund der "while"-Sub-Shell (mit separatem Variablenraum) belassen wir die Regeln
149  # einfach bei gleicher Prioritaet und erhoehen diese erst anschliessend.
150  get_all_network_interfaces | while read iface; do
151  is_interface_in_zone "$iface" "$ZONE_MESH" && continue
152  add_network_policy_rule_by_destination "$iface" table main prio "$priority"
153  done
154  : $((priority++))
155 
156  # alle nicht-mesh-Quellen routen auch ins olsr-Netz
157  #TODO: wir sollten nur private Ziel-IP-Bereiche (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) zulassen
158  # spaeter sind konfigurierbar weitere IPs (fuer HNAs oeffentlicher Dienste) moeglich
159  ip rule add table "$ROUTING_TABLE_MESH" prio "$((priority++))"
160  ip rule add table "$ROUTING_TABLE_MESH_DEFAULT" prio "$((priority++))"
161 
162  # Routen, die nicht den lokalen Netz-Interfaces entsprechen (z.B. default-Routen)
163  ip rule add table main prio "$((priority++))"
164 
165  # die default-Table und VPN-Tunnel fungieren fuer alle anderen Pakete als default-GW
166  ip rule add table default prio "$((priority++))"
167  ip rule add table "$ROUTING_TABLE_ON_UPLINK" prio "$((priority++))"
168 }
169 
170 
171 # Stelle sicher, dass eine sinnvolle routing-Tabellen-Datei existiert.
172 # Dies ist erforderlich, da kein echtes "ip"-Paket installiert ist (im busybox-Paket ist die Datei nicht enthalten).
173 _prepare_routing_table_file() {
174  [ -e "$RT_FILE" ] && return 0
175  mkdir "$(dirname "$RT_FILE")"
176  cat >"$RT_FILE" << EOF
177 #
178 255 local
179 254 main
180 253 default
181 0 unspec
182 #
183 # local
184 #
185 #1 inr.ruhep
186 EOF
187 }
188 
189 
190 ## @fn get_routing_table_id()
191 ## @brief Ermittle die Nummer der namentlich gegebenen Routing-Tabelle.
192 ## @param table_name Name der gesuchten Routing-Tabelle
193 ## @return Routing-Tabellen-ID oder nichts (falls die Tabelle nicht existiert)
195  local table_name="$1"
196  _prepare_routing_table_file
197  # Tabellennummer ausgeben, falls sie vorhanden ist
198  grep "^[0-9]\+[ \t]\+$table_name$" "$RT_FILE" | awk '{print $1}'
199  return 0
200 }
201 
202 
203 ## @fn add_routing_table()
204 ## @brief Erstelle einen neuen Routing-Tabellen-Eintrag.
205 ## @param table_name der Name der zu erstellenden Routing-Tabelle
206 ## @details Die Routing-Tabellen-Nummer wird automatisch ermittelt.
207 ## Sollte die Tabelle bereits existieren, dann wird ihre Nummer zurückgeliefert.
208 ## @return die neue Routing-Tabellen-Nummer wird zurückgeliefert
210  trap "error_trap add_routing_table '$*'" $GUARD_TRAPS
211  local table_name="$1"
212  _prepare_routing_table_file
213  local table_id=$(get_routing_table_id "$table_name")
214  # schon vorhanden?
215  [ -n "$table_id" ] && echo "$table_id" && return 0
216  # wir muessen den Eintrag hinzufuegen
217  table_id="$RT_START_ID"
218  while [ -n "$(_get_file_dict_value "$table_id" "$RT_FILE")" ]; do
219  : $((table_id++))
220  done
221  echo "$table_id $table_name" >> "$RT_FILE"
222  echo "$table_id"
223 }
224 
225 
226 ## @fn get_hop_count_and_etx()
227 ## @brief Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück.
228 ## @param host die Ziel-IP
229 ## @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.
230 ## @details Die Quelle dieser Information ist olsrd. Routen außerhalb von olsrd werden nicht beachtet.
232  local target="$1"
233  # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob)
234  [ ! -e "$OLSR_ROUTE_CACHE_FILE" ] && return 0
235  awk '{ if ($1 == "'$target'") { print $3, $4; exit; } }' <"$OLSR_ROUTE_CACHE_FILE"
236 }
237 
238 
239 # Diese Funktion sollte oft (minuetlich?) aufgerufen werden, um die olsrd-Routing-Informationen abzufragen.
240 # Dies ist noetig, um deadlocks bei parallelem Zugriff auf den single-thread olsrd zu verhindern.
241 # Symptome eines deadlocks: olsrd ist beendet; viele parallele nc-Instanzen; eine davon ist an den txtinfo-Port gebunden.
242 update_olsr_route_cache() {
243  trap "error_trap update_olsr_route_cache '$*'" $GUARD_TRAPS
244  # die temporaere Datei soll verhindern, dass es zwischendurch ein Zeitfenster mit unvollstaendigen Informationen gibt
245  local tmpfile="${OLSR_ROUTE_CACHE_FILE}.new"
246  # Bei der Ausfuehrung via cron wird SIGPIPE eventuell behandelt, auf dass die Ausfuehrung
247  # ohne Erzeugung der Datei abbrechen koennte. Daher ist die &&-Verknuepfung sinnvoll.
248  request_olsrd_txtinfo routes | grep "^[0-9]" | sed 's#/32##' > "$tmpfile" && mv "$tmpfile" "$OLSR_ROUTE_CACHE_FILE"
249  return 0
250 }
251 
252 # Ende der Doku-Gruppe
253 ## @}