1 ## @defgroup network Netzwerk
2 ## @brie Umgang mit uci-Netzwerk-Interfaces und Firewall-Zonen
3 # Beginn der Doku-Gruppe
15 # Liefere alle IPs fuer diesen Namen zurueck
17 nslookup
"$1" | sed
'1,/^Name:/d' | awk
'{print $3}' | sort -n
22 nslookup
"$1" 2>/dev/
null | tail -n 1 | awk
'{ printf "%s", $4 }'
26 ## @fn query_srv_record()
27 ## @brief Liefere die SRV Records zu einer Domain zurück.
28 ## @param srv_domain Dienst-Domain (z.B. _mesh-openvpn._udp.opennet-initiative.de)
29 ## @returns Zeilenweise Ausgabe von SRV Records: PRIORITY WEIGHT PORT HOSTNAME
30 ## @details Siehe RFC 2782 für die SRV-Spezifikation. Die Abfrage erfordert dig drill oder unbound-host.
33 # verschiedene DNS-Werkzeuge sind nutzbar: dig, drill oder unbound-host
34 # "djbdns-tools" unterstützt leider nicht das Parsen von srv-Records (siehe "dnsq 33 DOMAIN localhost")
35 # "drill" ist das kleinste Werkzeug
36 if which dig >/dev/
null; then
37 dig +
short SRV
"$domain"
38 elif which drill >/dev/
null; then
39 drill
"$domain" SRV | grep -v
"^;" \
40 | grep
"[[:space:]]IN[[:space:]]\+SRV[[:space:]]\+[[:digit:]]\+[[:space:]]\+[[:digit:]]" \
41 | awk
'{print $5, $6, $7, $8}'
42 elif which unbound-host >/dev/
null; then
43 unbound-host -t SRV
"$domain" \
44 | awk
'{print $5, $6, $7, $8}'
46 msg_info "ERROR: Missing advanced DNS resolver for mesh gateway discovery"
48 # (siehe oben) entferne den abschliessenden Top-Level-Domain-Punkt ("on-i.de." statt "on-i.de")
52 ## @fn get_ping_time()
53 ## @brief Ermittle die Latenz eines Ping-Pakets auf dem Weg zu einem Ziel.
54 ## @param target IP oder DNS-Name des Zielhosts
55 ## @param duration die Dauer der Ping-Kommunikation in Sekunden (falls ungesetzt: 5)
56 ## @returns Ausgabe der mittleren Ping-Zeit in ganzen Sekunden; bei Nichterreichbarkit ist die Ausgabe leer
59 local duration=
"${2:-5}"
61 [ -z
"$ip" ] &&
return 0
62 ping -w
"$duration" -q
"$ip" 2>/dev/
null \
63 | grep
"min/avg/max" \
66 | awk
'{ print int($1 + 0.5); }'
70 # Lege eine Weiterleitungsregel fuer die firewall an (firewall.@forwarding[?]=...)
71 # WICHTIG: anschliessend muss "uci commit firewall" ausgefuehrt werden
72 # Parameter: Quell-Zone und Ziel-Zone
74 trap
"error_trap add_zone_forward '$*'" $GUARD_TRAPS
77 local uci_prefix=$(find_first_uci_section firewall forwarding
"src=$source" "dest=$dest")
78 # die Weiterleitungsregel existiert bereits -> Ende
79 [ -n
"$uci_prefix" ] &&
return 0
80 # neue Regel erstellen
81 uci_prefix=
"firewall.$(uci add firewall forwarding)"
82 uci
set "${uci_prefix}.src=$source"
83 uci
set "${uci_prefix}.dest=$dest"
87 # Das Masquerading in die Opennet-Zone soll nur fuer bestimmte Quell-Netze erfolgen.
88 # Diese Funktion wird bei hotplug-Netzwerkaenderungen ausgefuehrt.
89 update_opennet_zone_masquerading() {
90 trap
"error_trap update_opennet_zone_masquerading '$*'" $GUARD_TRAPS
93 local uci_prefix=$(find_first_uci_section firewall zone
"name=$ZONE_MESH")
94 # Abbruch, falls die Zone fehlt
95 [ -z
"$uci_prefix" ] &&
msg_info "failed to find opennet mesh zone ($ZONE_MESH)" &&
return 0
96 # alle masquerade-Netzwerke entfernen
98 # aktuelle Netzwerke wieder hinzufuegen
99 for network in $(get_zone_interfaces
"$ZONE_LOCAL");
do
100 networkprefix=$(get_address_of_network
"$network")
103 # leider ist masq_src im Zweifelfall nicht
"leer", sondern enthaelt ein Leerzeichen
104 if uci_get
"${uci_prefix}.masq_src" | grep -q
"[^ \t]"; then
105 # masquerading aktiveren (nur fuer die obigen Quell-Adressen)
106 uci
set "${uci_prefix}.masq=1"
108 # Es gibt keine lokalen Interfaces - also duerfen wir kein Masquerading aktivieren.
109 # Leider interpretiert openwrt ein leeres "masq_src" nicht als "masq fuer niemanden" :(
110 uci
set "${uci_prefix}.masq=0"
112 apply_changes firewall
116 # Liefere die IP-Adresse eines logischen Interface inkl. Praefix-Laenge (z.B. 172.16.0.1/24).
117 # Parameter: logisches Netzwerk-Interface
118 get_address_of_network() {
119 trap
"error_trap get_address_of_network '$*'" $GUARD_TRAPS
122 # Kurzzeitig den eventuellen strikten Modus abschalten.
123 # (lib/functions.sh kommt mit dem strikten Modus nicht zurecht)
126 .
"${IPKG_INSTROOT:-}/lib/functions/network.sh"
127 __network_ifstatus
"ranges" "$network" "['ipv4-address'][*]['address','mask']" "/"
135 # Liefere die logischen Netzwerk-Schnittstellen einer Zone zurueck.
136 get_zone_interfaces() {
137 trap
"error_trap get_zone_interfaces '$*'" $GUARD_TRAPS
139 local uci_prefix=$(find_first_uci_section firewall zone
"name=$zone")
140 # keine Zone -> keine Interfaces
141 [ -z
"$uci_prefix" ] &&
return 0
142 local interfaces=$(uci_get
"${uci_prefix}.network")
143 # falls 'network' und 'device' leer sind, dann enthaelt 'name' den Interface-Namen
144 # siehe http://wiki.openwrt.org/doc/uci/firewall#zones
145 [ -z
"$interfaces" ] && [ -z
"$(uci_get "${uci_prefix}.device
")" ] && interfaces=
"$(uci_get "${uci_prefix}.name
")"
151 # Liefere die physischen Netzwerk-Schnittstellen einer Zone zurueck.
153 trap
"error_trap get_zone_devices '$*'" $GUARD_TRAPS
157 for iface in $(get_zone_interfaces
"$zone");
do
158 for result in $(uci_get
"network.${iface}.ifname");
do
161 # Namen von Bridge-Interfaces werden explizit vergeben
162 [
"$(uci_get "network.${iface}.type
")" =
"bridge" ] && echo
"br-$iface"
168 # Ist das gegebene physische Netzwer-Interface Teil einer Firewall-Zone?
169 is_device_in_zone() {
170 trap
"error_trap is_device_in_zone '$*'" $GUARD_TRAPS
174 for log_interface in $(get_zone_interfaces
"$2");
do
175 for item in $(uci_get
"network.${log_interface}.ifname");
do
176 # Entferne den Teil nach Doppelpunkten - fuer Alias-Interfaces
177 [
"$device" =
"$(echo "$item
" | cut -f 1 -d :)" ] &&
return 0 ||
true
180 trap
"" $GUARD_TRAPS &&
return 1
184 # Ist das gegebene logische Netzwerk-Interface Teil einer Firewall-Zone?
185 is_interface_in_zone() {
189 for item in $(get_zone_interfaces
"$2");
do
190 [
"$item" =
"$interface" ] &&
return 0 ||
true
192 trap
"" $GUARD_TRAPS &&
return 1
196 add_interface_to_zone() {
199 local uci_prefix=$(find_first_uci_section firewall zone
"name=$zone")
200 [ -z
"$uci_prefix" ] &&
msg_debug "failed to add interface '$interface' to non-existing zone '$zone'" && trap
"" $GUARD_TRAPS &&
return 1
205 del_interface_from_zone() {
208 local uci_prefix=$(find_first_uci_section firewall zone
"name=$zone")
209 [ -z
"$uci_prefix" ] &&
msg_debug "failed to remove interface '$interface' from non-existing zone '$zone'" && trap
"" $GUARD_TRAPS &&
return 1
210 uci del_list
"${uci_prefix}.network=$interface"
214 ## @fn get_zone_of_device()
215 ## @brief Ermittle die Zone eines physischen Netzwerk-Interfaces.
216 ## @param interface Name eines physischen Netzwerk-Interface (z.B. eth0)
217 ## @details Das Ergebnis ist ein leerer String, falls zu diesem Interface keine Zone existiert
218 ## oder falls es das Interface nicht gibt.
219 get_zone_of_device() {
220 trap
"error_trap get_zone_of_device '$*'" $GUARD_TRAPS
225 find_all_uci_sections firewall zone |
while read uci_prefix;
do
226 zone=$(uci_get
"${uci_prefix}.name")
227 devices=$(get_zone_devices
"$zone")
228 is_in_list
"$device" "$devices" && echo -n
"$zone" &&
return 0 ||
true
230 # ein leerer Rueckgabewert gilt als Fehler
235 ## @fn get_zone_of_interface()
236 ## @brief Ermittle die Zone eines logischen Netzwerk-Interfaces.
237 ## @param interface Name eines logischen Netzwerk-Interface (z.B. eth0)
238 ## @details Das Ergebnis ist ein leerer String, falls zu diesem Interface keine Zone existiert
239 ## oder falls es das Interface nicht gibt.
240 get_zone_of_interface() {
241 trap
"error_trap get_zone_of_interface '$*'" $GUARD_TRAPS
246 find_all_uci_sections firewall zone |
while read uci_prefix;
do
247 zone=$(uci_get
"${uci_prefix}.name")
248 interfaces=$(get_zone_interfaces
"$zone")
249 is_in_list
"$interface" "$interfaces" && echo -n
"$zone" &&
return 0 ||
true
251 # ein leerer Rueckgabewert gilt als Fehler
256 # Liefere die sortierte Liste der Opennet-Interfaces.
258 # 1. dem Netzwerk ist ein Geraet zugeordnet
259 # 2. Netzwerkname beginnend mit "on_wifi", "on_eth", ...
260 # 3. alphabetische Sortierung der Netzwerknamen
261 get_sorted_opennet_interfaces() {
262 trap
"error_trap get_sorted_opennet_interfaces '$*'" $GUARD_TRAPS
265 # wir vergeben einfach statische Ordnungsnummern:
266 # 10 - konfigurierte Interfaces
267 # 20 - nicht konfigurierte Interfaces
268 # Offsets basierend auf dem Netzwerknamen:
272 for network in $(get_zone_interfaces
"$ZONE_MESH");
do
273 uci_prefix=network.$network
275 [
"$(uci_get "${uci_prefix}.ifname
")" ==
"none" ] && order=20
276 if [
"${network#on_wifi}" !=
"$network" ]; then
278 elif [
"${network#on_eth}" !=
"$network" ]; then
283 echo
"$order $network"
284 done | sort -n | cut -f 2 -
d " "
288 # Liefere alle vorhandenen logischen Netzwerk-Schnittstellen (lan, wan, ...) zurueck.
289 get_all_network_interfaces() {
291 uci show network | grep
"^network\.[^.]\+=interface$" | cut -f 2 -
d . | cut -f 1 -
d = |
while read interface;
do
292 # ignoriere loopback-Interface
293 [
"$interface" =
"loopback" ] &&
continue
294 # alle uebrigen sind reale Interfaces
301 rename_firewall_zone() {
302 trap
"error_trap rename_firewall_zone '$*'" $GUARD_TRAPS
308 local old_uci_prefix=$(find_first_uci_section firewall zone
"name=$old_zone")
309 # die Zone existiert nicht (mehr)
310 [ -z
"$old_uci_prefix" ] &&
return 0
311 local new_uci_prefix=$(find_first_uci_section firewall zone
"name=$new_zone")
312 [ -z
"$new_uci_prefix" ] && new_uci_prefix=
"firewall.$(uci add firewall zone)"
313 uci show
"$old_uci_prefix" | cut -f 3- -
d . |
while read setting;
do
314 # die erste Zeile (der Zonen-Typ) ueberspringen
315 [ -z
"$setting" ] &&
continue
316 uci
set "${new_uci_prefix}.$setting"
318 # den Namen ueberschreiben (er wurde oben von der alten Zone uebernommen)
319 uci
set "${new_uci_prefix}.name=$new_zone"
320 # aktualisiere alle Forwardings, Redirects und Regeln
321 for section in
"forwarding" "redirect" "rule";
do
322 for key in
"src" "dest";
do
323 find_all_uci_sections firewall
"$section" "${key}=$old_zone" |
while read uci_prefix;
do
324 uci
set "${uci_prefix}.${key}=$new_zone"
328 # fertig - wir loeschen die alte Zone
330 apply_changes firewall
333 # Ende der Doku-Gruppe