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 ## @details Die IP-Adresse darf mit einem Netzwerkpraefix enden.
21 is_ipv4() {
22  local target="$1"
23  echo "$target" | grep -q -E "^[0-9]+(\.[0-9]+){3}(/[0-9]+)?$"
24 }
25 
26 
27 ## @fn is_ipv6()
28 ## @brief Prüfe ob der übergebene Text eine IPv6-Adresse ist
29 ## @param target eine Zeichenkette (wahrscheinlich ein DNS-Name, eine IPv4- oder IPv6-Adresse)
30 ## @details Achtung: der Test ist recht oberflächlich und kann falsche Positive liefern.
32  local target="$1"
33  echo "$target" | grep -q -E "^[0-9a-fA-F:]+(/[0-9]+)?$"
34 }
35 
36 
37 ## @fn filter_routable_addresses()
38 ## @brief Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert.
39 ## @details Lies IP-Addressen zeilenweise via stdin ein und gib alle Adressen aus, die (laut "ip route get") erreichbar sind.
40 ## Dies bedeutet nicht, dass wir mit den Adressen kommunizieren koennen - es geht lediglich um lokale Routing-Regeln.
41 ## @return zeilenweise Ausgabe der route-baren Ziel-IPs:w
43  local ip
44  while read ip; do
45  [ -n "$(get_target_route_interface "$ip")" ] && echo "$ip" || true
46  done
47  return 0
48 }
49 
50 
51 ## @fn get_target_route_interface()
52 ## @brief Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde.
53 ## @param target Hostname oder IP des Ziel-Hosts
54 ## @tos_field tos Optionale type-of-service-Zahl
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
58  local target="$1"
59  local tos_field="${2:-}"
60  local ipaddr
61  local route_get_args=
62  [ -n "$tos_field" ] && route_get_args="tos $tos_field"
63  if is_ipv4 "$target" || is_ipv6 "$target"; then
64  echo "$target"
65  else
66  query_dns "$target"
67  fi | while read ipaddr; 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
73  # oder:
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  ip route get "$ipaddr" $route_get_args 2>/dev/null \
79  | grep -vE "^(failed_policy|prohibit)" \
80  | grep -vE "error -(1|13)$" \
81  | grep " dev " \
82  | sed 's/^.* dev \+\([^ \t]\+\) \+.*$/\1/'
83  done | tail -1
84 }
85 
86 
87 # Entferne alle Policy-Routing-Regeln die dem gegebenen Ausdruck entsprechen.
88 # Es erfolgt keine Fehlerausgabe und keine Fehlermeldungen.
89 delete_policy_rule() {
90  while ip rule del "$@"; do true; done 2>/dev/null
91 }
92 
93 
94 ## @fn add_network_policy_rule_by_destination()
95 ## @brief erzeuge Policy-Rules entsprechend der IP-Bereiche eines Netzwerks
96 ## @param network logisches Netzwerkinterface
97 ## @param more weitere Parameter: Policy-Rule-Spezifikation
99  trap "error_trap add_network_policy_rule_by_destination '$*'" $GUARD_TRAPS
100  local network="$1"
101  shift
102  local network_with_prefix
103  local ip_version
104  for network_with_prefix in $(get_current_addresses_of_network "$network"); do
105  [ -z "$network_with_prefix" ] && continue
106  is_ipv4 "$network_with_prefix" && ip_version="-4" || ip_version="-6"
107  ip "$ip_version" rule add to "$network_with_prefix" "$@" || true
108  done
109  return 0
110 }
111 
112 
113 ## @fn add_zone_policy_rules_by_iif()
114 ## @brief Erzeuge Policy-Rules fuer Quell-Interfaces
115 ## @param zone Pakete aus allen Interfaces dieser Zone kommend sollen betroffen sein
116 ## @param route Spezifikation einer Route (siehe 'ip route add ...')
118  trap "error_trap add_zone_policy_rules '$*'" $GUARD_TRAPS
119  local zone="$1"
120  shift
121  local interface
122  local device
123  # ermittle alle physischen Geräte inklusive Bridge-Interfaces, die zu dieser Zone gehören
124  for interface in $(get_zone_interfaces "$zone"); do
125  get_device_of_interface "$interface"
126  for device in $(get_subdevices_of_interface "$interface"); do
127  echo "$device"
128  done
129  done | sort | uniq | while read device; do
130  [ -n "$device" -a "$device" != "none" ] && ip rule add iif "$device" "$@"
131  true
132  done
133  return 0
134 }
135 
136 
137 ## @fn initialize_olsrd_policy_routing()
138 ## @brief Policy-Routing-Initialisierung nach dem System-Boot und nach Interface-Hotplug-Ereignissen
139 ## @details Folgende Seiteneffekte treten ein:
140 ## * alle Policy-Rules mit Bezug zu den Tabellen olsrd/olsrd-default/main werden gelöscht
141 ## * die neuen Policy-Rules für die obigen Tabellen werden an anderer Stelle erzeugt
142 ## Kurz gesagt: alle bisherigen Policy-Rules sind hinterher kaputt
144  trap "error_trap initialize_olsrd_policy_routing '$*'" $GUARD_TRAPS
145  local iface
146  local current
147  local table
148  local priority=$OLSR_POLICY_DEFAULT_PRIORITY
149 
150  # Sicherstellen, dass die Tabellen existieren und zur olsrd-Konfiguration passen
152  # die Uplink-Tabelle ist unabhaengig von olsr
153  [ -z "$(get_routing_table_id "$ROUTING_TABLE_ON_UPLINK")" ] && add_routing_table "$ROUTING_TABLE_ON_UPLINK" >/dev/null
154 
155  # alle Eintraege loeschen
156  delete_policy_rule table "$ROUTING_TABLE_MESH"
157  delete_policy_rule table "$ROUTING_TABLE_MESH_DEFAULT"
158  delete_policy_rule table "$ROUTING_TABLE_ON_UPLINK"
159  delete_policy_rule table main
160  delete_policy_rule table default
161 
162  # free-Verkehr geht immer in den Tunnel (falls das Paket installiert ist)
163  [ -n "${ZONE_FREE:-}" ] \
164  && add_zone_policy_rules_by_iif "$ZONE_FREE" table "$ROUTING_TABLE_ON_UPLINK" prio "$((priority++))"
165 
166  # sehr wichtig - also zuerst: keine vorbeifliegenden Mesh-Pakete umlenken
167  add_zone_policy_rules_by_iif "$ZONE_MESH" table "$ROUTING_TABLE_MESH" prio "$((priority++))"
168  add_zone_policy_rules_by_iif "$ZONE_MESH" table "$ROUTING_TABLE_MESH_DEFAULT" prio "$((priority++))"
169 
170  # Pakete mit passendem Ziel orientieren sich an der main-Tabelle
171  # Alle Ziele ausserhalb der mesh-Zone sind geeignet (z.B. local, free, ...).
172  # Wir wollen dadurch explizit keine potentielle default-Route verwenden.
173  # Aufgrund der "while"-Sub-Shell (mit separatem Variablenraum) belassen wir die Regeln
174  # einfach bei gleicher Prioritaet und erhoehen diese erst anschliessend.
175  get_all_network_interfaces | while read iface; do
176  is_interface_in_zone "$iface" "$ZONE_MESH" && continue
177  add_network_policy_rule_by_destination "$iface" table main prio "$priority"
178  done
179  : $((priority++))
180 
181  # alle nicht-mesh-Quellen routen auch ins olsr-Netz
182  #TODO: wir sollten nur private Ziel-IP-Bereiche (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) zulassen
183  # spaeter sind konfigurierbar weitere IPs (fuer HNAs oeffentlicher Dienste) moeglich
184  ip rule add table "$ROUTING_TABLE_MESH" prio "$((priority++))"
185  ip rule add table "$ROUTING_TABLE_MESH_DEFAULT" prio "$((priority++))"
186 
187  # Routen, die nicht den lokalen Netz-Interfaces entsprechen (z.B. default-Routen)
188  ip rule add table main prio "$((priority++))"
189 
190  # die default-Table und VPN-Tunnel fungieren fuer alle anderen Pakete als default-GW
191  ip rule add table default prio "$((priority++))"
192  ip rule add table "$ROUTING_TABLE_ON_UPLINK" prio "$((priority++))"
193 }
194 
195 
196 # Stelle sicher, dass eine sinnvolle routing-Tabellen-Datei existiert.
197 # Dies ist erforderlich, falls kein echtes "ip"-Paket installiert ist (im busybox-Paket ist die Datei nicht enthalten).
198 _prepare_routing_table_file() {
199  [ -e "$RT_FILE" ] && return 0
200  mkdir -p "$(dirname "$RT_FILE")"
201  cat >"$RT_FILE" << EOF
202 # erzeugt von "on-core"
203 #
204 255 local
205 254 main
206 253 default
207 0 unspec
208 #
209 # local
210 #
211 #1 inr.ruhep
212 EOF
213 }
214 
215 
216 ## @fn get_routing_table_id()
217 ## @brief Ermittle die Nummer der namentlich gegebenen Routing-Tabelle.
218 ## @param table_name Name der gesuchten Routing-Tabelle
219 ## @return Routing-Tabellen-ID oder nichts (falls die Tabelle nicht existiert)
221  local table_name="$1"
222  _prepare_routing_table_file
223  # Tabellennummer ausgeben, falls sie vorhanden ist
224  grep "^[0-9]\+[ \t]\+$table_name$" "$RT_FILE" | awk '{print $1}'
225  return 0
226 }
227 
228 
229 ## @fn add_routing_table()
230 ## @brief Erstelle einen neuen Routing-Tabellen-Eintrag.
231 ## @param table_name der Name der zu erstellenden Routing-Tabelle
232 ## @details Die Routing-Tabellen-Nummer wird automatisch ermittelt.
233 ## Sollte die Tabelle bereits existieren, dann wird ihre Nummer zurückgeliefert.
234 ## @return die neue Routing-Tabellen-Nummer wird zurückgeliefert
236  trap "error_trap add_routing_table '$*'" $GUARD_TRAPS
237  local table_name="$1"
238  _prepare_routing_table_file
239  local table_id
240  table_id=$(get_routing_table_id "$table_name")
241  # schon vorhanden?
242  [ -n "$table_id" ] && echo "$table_id" && return 0
243  # wir muessen den Eintrag hinzufuegen
244  table_id="$RT_START_ID"
245  while [ -n "$(_get_file_dict_value "$table_id" "$RT_FILE")" ]; do
246  : $((table_id++))
247  done
248  echo "$table_id $table_name" >> "$RT_FILE"
249  echo "$table_id"
250 }
251 
252 
253 ## @fn get_hop_count_and_etx()
254 ## @brief Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück.
255 ## @param host die Ziel-IP
256 ## @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.
257 ## @details Die Quelle dieser Information ist olsrd. Routen außerhalb von olsrd werden nicht beachtet.
259  local target="$1"
260  local result
261  # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob)
262  [ ! -e "$OLSR_ROUTE_CACHE_FILE" ] && return 0
263  result=$(awk '{ if ($1 == "'$target'") { print $3, $4; exit; } }' <"$OLSR_ROUTE_CACHE_FILE")
264  [ -n "$result" ] && echo "$result" && return 0
265  # Überprüfe, ob die IP des Zielhost die eigene IP ist. Dann sollte distance=0 gesetzt werden.
266  if is_ipv4 "$target" || is_ipv6 "$target"; then
267  result=$(ip route get "$target" | grep -w "dev lo")
268  [ -n "$result" ] && echo "0 0" || true
269  fi
270 }
271 
272 
273 # Diese Funktion sollte oft (minuetlich?) aufgerufen werden, um die olsrd-Routing-Informationen abzufragen.
274 # Dies ist noetig, um deadlocks bei parallelem Zugriff auf den single-thread olsrd zu verhindern.
275 # Symptome eines deadlocks: olsrd ist beendet; viele parallele nc-Instanzen; eine davon ist an den txtinfo-Port gebunden.
276 update_olsr_route_cache() {
277  trap "error_trap update_olsr_route_cache '$*'" $GUARD_TRAPS
278  # die temporaere Datei soll verhindern, dass es zwischendurch ein Zeitfenster mit unvollstaendigen Informationen gibt
279  local tmpfile="${OLSR_ROUTE_CACHE_FILE}.new"
280  # Bei der Ausfuehrung via cron wird SIGPIPE eventuell behandelt, auf dass die Ausfuehrung
281  # ohne Erzeugung der Datei abbrechen koennte. Daher ist die &&-Verknuepfung sinnvoll.
282  request_olsrd_txtinfo routes | grep "^[0-9]" | sed 's#/32##' > "$tmpfile" && mv "$tmpfile" "$OLSR_ROUTE_CACHE_FILE"
283  return 0
284 }
285 
286 
287 ## @fn get_olsr_route_count_by_device()
288 ## @brief Liefere die Anzahl von olsr-Routen, die auf ein bestimmtes Netzwerk-Interface verweisen
290  local device_regex="$1"
291  # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob)
292  [ -e "$OLSR_ROUTE_CACHE_FILE" ] || return 0
293  awk '{ print $5 }' "$OLSR_ROUTE_CACHE_FILE" | grep "^$device_regex$" | wc -l
294 }
295 
296 
297 ## @fn get_olsr_route_count_by_neighbour()
298 ## @brief Liefere die Anzahl von olsr-Routen, die auf einen bestimmten Routing-Nachbarn verweisen.
300  local neighbour_ip="$1"
301  # kein Ergebnis, falls noch kein Routen-Cache vorliegt (minuetlicher cronjob)
302  [ -e "$OLSR_ROUTE_CACHE_FILE" ] || return 0
303  awk 'BEGIN { count=0; } { if ($2 == "'$neighbour_ip'") count++; } END { print count; }' "$OLSR_ROUTE_CACHE_FILE"
304 }
305 
306 
307 ## @fn get_olsr_neighbours()
308 ## @brief Ermittle die direkten olsr-Nachbarn und liefere ihre IPs und interessante Kennzahlen zurück.
309 ## details Ergebnisformat: NEIGHBOUR_IP LINK_QUALITY NEIGHBOUR_LINK_QUALITY ETX ROUTE_COUNT
311  local ip
312  local lq
313  local nlq
314  local etx
315  local route_count
316  request_olsrd_txtinfo links | grep "^[0-9]" | awk '{ print $2,$4,$5,$6 }' | while read ip lq nlq etx; do
317  echo "$ip $lq $nlq $etx $(get_olsr_route_count_by_neighbour "$ip")"
318  done
319 }
320 
321 # Ende der Doku-Gruppe
322 ## @}
get_hop_count_and_etx(host)
Liefere den Hop-Count und den ETX-Wert für einen Zielhost zurück.
Definition: routing.sh:61
is_ipv4(target)
Prüfe ob der übergebene Text eine IPv4-Adresse ist.
Definition: routing.sh:8
olsr_sync_routing_tables()
Synchronisiere die olsrd-Routingtabellen-Konfiguration mit den iproute-Routingtabellennummern.
Definition: olsr.sh:7
get_olsr_route_count_by_device()
Liefere die Anzahl von olsr-Routen, die auf ein bestimmtes Netzwerk-Interface verweisen.
Definition: routing.sh:64
add_zone_policy_rules_by_iif(zone, route)
Erzeuge Policy-Rules fuer Quell-Interfaces.
Definition: routing.sh:36
get_routing_table_id(table_name)
Ermittle die Nummer der namentlich gegebenen Routing-Tabelle.
Definition: routing.sh:48
add_routing_table(table_name)
Erstelle einen neuen Routing-Tabellen-Eintrag.
Definition: routing.sh:55
add_network_policy_rule_by_destination(network, more)
erzeuge Policy-Rules entsprechend der IP-Bereiche eines Netzwerks
Definition: routing.sh:31
request_olsrd_txtinfo(request)
Sende eine Anfrage an das txtinfo-Interface von olsrd.
Definition: olsr.sh:17
is_ipv6(target)
Prüfe ob der übergebene Text eine IPv6-Adresse ist.
Definition: routing.sh:13
get_subdevices_of_interface()
Ermittle die physischen Netzwerk-Geräte (bis auf wifi), die zu einem logischen Netzwerk-Interface geh...
Definition: network.sh:35
get_current_addresses_of_network()
Liefere die IP-Adressen eines logischen Interface inkl. Praefix-Laenge (z.B. 172.16.0.1/24, network).
Definition: network.sh:19
get_olsr_neighbours()
Ermittle die direkten olsr-Nachbarn und liefere ihre IPs und interessante Kennzahlen zurück...
Definition: routing.sh:71
filter_routable_addresses()
Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert...
Definition: routing.sh:19
shift
Definition: core.sh:81
set eu grep root::etc shadow exit if which chpasswd dev null
Definition: on-password:12
get_device_of_interface()
Ermittle das physische Netzwerk-Gerät, das einem logischen Netzwerk entspricht.
Definition: network.sh:28
initialize_olsrd_policy_routing()
Policy-Routing-Initialisierung nach dem System-Boot und nach Interface-Hotplug-Ereignissen.
Definition: routing.sh:43
done
Definition: core.sh:81
get_target_route_interface(target)
Ermittle das Netzwerkinterface, über den der Verkehr zu einem Ziel laufen würde.
Definition: routing.sh:26
get_olsr_route_count_by_neighbour()
Liefere die Anzahl von olsr-Routen, die auf einen bestimmten Routing-Nachbarn verweisen.
Definition: routing.sh:67