Opennet Firmware
service-relay.sh
gehe zur Dokumentation dieser Datei
1## @defgroup on-service-relay Dienst-Weiterleitungen
2# Beginn der Doku-Gruppe
3## @{
4
5## für die Kompatibilität mit Firmware vor v0.5
6## falls mehr als ein GW-Dienst weitergereicht wird, wird dieser Port und die folgenden verwendet
7SERVICE_RELAY_LOCAL_RELAY_PORT_START=5100
8
9
10# Pruefung ob ein lokaler Port bereits fuer einen ugw-Dienst weitergeleitet wird
11_is_local_service_relay_port_unused() {
12 local port="$1"
13 local collisions
14 collisions=$(get_services | filter_services_by_value "local_relay_port" "$port")
15 [ -n "$collisions" ] && trap "" EXIT && return 1
16 # keine Kollision entdeckt
17 return 0
18}
19
20
21# Liefere den Port zurueck, der einer Dienst-Weiterleitung lokal zugewiesen wurde.
22# Falls noch kein Port definiert ist, dann waehle einen neuen Port.
23# Parameter: config_name
24pick_local_service_relay_port() {
25 trap 'error_trap pick_local_service_relay_port "$*"' EXIT
26 local service_name="$1"
27 local port
28 port=$(get_service_value "$service_name" "local_relay_port")
29 # falls unbelegt: suche einen unbenutzten lokalen Port
30 if [ -z "$port" ]; then
31 port="$SERVICE_RELAY_LOCAL_RELAY_PORT_START"
32 until _is_local_service_relay_port_unused "$port"; do
33 port=$((port + 1))
34 done
35 fi
36 set_service_value "$service_name" "local_relay_port" "$port"
37 echo "$port"
38}
39
40
41## @fn update_relay_firewall_rules
42## @brief Erstelle die Liste aller Firewall-Regeln fuer Service-Relay-Weiterleitungen neu.
43## @details Diese Funktion wird als Teil des Firewall-Reload-Prozess und nach Service-Relay-Aenderungen
44## aufgerufen.
45update_relay_firewall_rules() {
46 trap 'error_trap update_relay_firewall_rules "$*"' EXIT
47 local host
48 local port
49 local protocol
50 local target_ip
51 local main_ip
52 local table="on_usergw_table"
53 local dnat_chain="on_service_relay_dnat"
54 local new_rules
55 main_ip=$(get_main_ip)
56 # calculate the entries for the new rules
57 # We need to do this in advance - otherwise it could happen, that DNS problems could cause
58 # invalid (i.e. missing) firewall rules. Only if at least one valid rule is calculated,
59 # the rules are updated.
60 new_rules=$(for service in $(get_services | filter_relay_services); do
61 is_service_relay_possible "$service" || continue
62 host=$(get_service_value "$service" "host")
63 port=$(get_service_value "$service" "port")
64 protocol=$(get_service_value "$service" "protocol")
65 local_port=$(get_service_value "$service" "local_relay_port")
66 target_ip=$(query_dns "$host" | filter_routable_addresses | tail -n 1)
67 # skip entries in case of broken DNS resolution
68 [ -z "$target_ip" ] && continue
69 echo "$host $port $protocol $local_port $target_ip"
70 done)
71 # do not apply changes, if there are no valid rules
72 [ -z "$new_rules" ] && return 0
73
74 # alte Regeln aus Chains löschen (siehe auch /usr/share/nftables.d/ fuer Definition der Chain)
75 nft flush chain inet "$table" "$dnat_chain"
76
77 # DNAT Chain fuellen
78 echo "$new_rules" | while read -r host port protocol local_port target_ip; do
79 if is_ipv4 "$main_ip"; then
80 nft add rule inet "$table" "$dnat_chain" ip daddr "$main_ip" "$protocol" dport "$local_port" counter dnat to "${target_ip}:${port}"
81 else
82 nft add rule inet "$table" "$dnat_chain" ip6 daddr "$main_ip" "$protocol" dport "$local_port" counter dnat to "${target_ip}:${port}"
83 fi
84 done
85 # Connection-Tracking-Tabelle flushen
86 # Sonst werden Aenderungen fuer bestehende Verbindungen nicht wirksam.
87 echo f >/proc/net/nf_conntrack
88}
89
90
91_get_service_relay_olsr_announcement_prefix() {
92 trap 'error_trap _get_service_relay_olsr_announcement_prefix "$*"' EXIT
93 local service_name="$1"
94 local main_ip
95 local service_type
96 local scheme
97 local host
98 local port
99 local protocol
100 main_ip=$(get_main_ip)
101 service_type=$(get_service_value "$service_name" "service")
102 # remove prefix
103 service_type="${service_type#$RELAYABLE_SERVICE_PREFIX}"
104 scheme=$(get_service_value "$service_name" "scheme")
105 host=$(get_service_value "$service_name" "host")
106 port=$(pick_local_service_relay_port "$service_name")
107 protocol=$(get_service_value "$service_name" "protocol")
108 # announce the service
109 echo "${scheme}://${main_ip}:${port}|${protocol}|${service_type}"
110}
111
112
113## @fn get_service_relay_olsr_announcement()
114## @brief Ermittle den oder die OLSR-Nameservice-Announcements, die zu dem Dienst gehoeren.
115get_service_relay_olsr_announcement() {
116 trap 'error_trap get_service_relay_olsr_announcement "$*"' EXIT
117 local service_name="$1"
118 local announce_unique
119 local uci_prefix
120 announce_unique=$(_get_service_relay_olsr_announcement_prefix "$service_name")
121 uci_prefix=$(get_and_enable_olsrd_library_uci_prefix "nameservice")
122 uci_get_list "${uci_prefix}.service" | awk '{ if ($1 == "'"$announce_unique"'") print $0; }'
123}
124
125
126## @fn announce_olsr_service_relay()
127## @brief Verkuende das lokale Relay eines öffentlichen Dienstes inkl. Geschwindigkeitsdaten via olsr nameservice.
128## @param service_name Name des zu veröffentlichenden Diensts
129## @attention Anschließend muss die uci-Sektion 'olsrd' committed werden.
130announce_olsr_service_relay() {
131 trap 'error_trap announce_olsr_service_relay "$*"' EXIT
132 local service_name="$1"
133 local service_unique
134 local service_details
135 service_unique=$(_get_service_relay_olsr_announcement_prefix "$service_name")
136 # das 'service_name'-Detail wird fuer die anschliessende Beraeumung (firewall-Regeln usw.) verwendet
137 # nur nicht-leere Attribute werden geschrieben
138 service_details=$(while read -r key value; do [ -z "$value" ] && continue; echo "$key:$value"; done <<EOF
139 public_host $(get_service_value "$service_name" "host")
140 upload $(get_service_value "$service_name" "wan_speed_upload")
141 download $(get_service_value "$service_name" "wan_speed_download")
142 ping $(get_service_value "$service_name" "wan_ping")
143EOF
144)
145 # Zeilenumbrueche durch Leerzeichen ersetzen, abschliessendes Leerzeichen entfernen
146 service_details=$(echo "$service_details" | tr '\n' ' ' | sed 's/ $//')
147 # loesche alte Dienst-Announcements mit demselben Prefix
148 local this_unique
149 local this_details
150 local uci_prefix
151 uci_prefix=$(get_and_enable_olsrd_library_uci_prefix "nameservice")
152 # shellcheck disable=SC2034
153 get_service_relay_olsr_announcement "$service_name" | while read -r this_unique this_details; do
154 # der Wert ist bereits korrekt - wir koennen abbrechen
155 [ "$this_details" = "$service_details" ] && break
156 # der Wert ist falsch: loeschen und am Ende neu hinzufuegen
157 msg_debug "Deleting outdated service-relay announcement: $service_unique $this_details"
158 uci_delete_list "${uci_prefix}.service" "$service_unique $this_details"
159 done
160 # falls keine Treffer gibt, fuegen wir ein neues Announcement hinzu
161 if [ -z "$(get_service_relay_olsr_announcement "$service_name")" ]; then
162 msg_debug "Adding new service-relay announcement: $service_unique $service_details"
163 uci_add_list "${uci_prefix}.service" "$service_unique $service_details"
164 fi
165}
166
167
168## @fn get_olsr_relay_service_name_from_description()
169## @brief Ermittle den Dienstnamen, der zu einer olsr-Relay-Service-Definition gehoert.
170get_olsr_relay_service_name_from_description() {
171 trap 'error_trap get_olsr_relay_service_name_from_description "$*"' EXIT
172 local service_description="$1"
173 local fields
174 local port
175 local service_type
176 fields=$(echo "$service_description" | parse_olsr_service_descriptions)
177 port=$(echo "$fields" | cut -f 4)
178 service_type=$(echo "$fields" | cut -f 1)
179 get_services "${RELAYABLE_SERVICE_PREFIX}$service_type" | filter_services_by_value "local_relay_port" "$port"
180}
181
182
183# olsr-Nameservice-Beschreibungen entfernen falls der dazugehoerige Dienst nicht mehr relay-tauglich ist
184deannounce_unused_olsr_service_relays() {
185 # wir erwarten einen ausführbaren Testnamen
186 local test_for_activity="$1"
187 local service_description
188 local service_name
189 local uci_prefix
190 uci_prefix=$(get_and_enable_olsrd_library_uci_prefix "nameservice")
191 uci_get_list "${uci_prefix}.service" | while read -r service_description; do
192 # unbenutzte Eintraege entfernen
193 service_name=$(get_olsr_relay_service_name_from_description "$service_description")
194 # falls es den Dienst noch gibt: ist er immer noch aktiv?
195 [ -n "$service_name" ] && "$test_for_activity" "$service_name" && continue
196 uci_delete_list "${uci_prefix}.service" "$service_description"
197 done
198 return 0
199}
200
201
202## @fn is_service_relay_possible()
203## @brief Pruefe ob ein Relay-Dienst aktiviert (nicht "disabled") ist und ob das WAN-Routing korrekt ist.
204is_service_relay_possible() {
205 trap 'error_trap is_service_relay_possible "$*"' EXIT
206 local service_name="$1"
207 local disabled
208 local wan_routing
209 disabled=$(get_service_value "$service_name" "disabled" "false")
210 uci_is_true "$disabled" && trap "" EXIT && return 1
211 wan_routing=$(get_service_value "$service_name" "wan_status" "false")
212 uci_is_false "$wan_routing" && trap "" EXIT && return 1
213 return 0
214}
215
216
217## @fn update_service_relay_status()
218## @brief Pruefe regelmaessig, ob Weiterleitungen für alle bekannten durchgereichten Diensten existieren.
219## @details Fehlende Weiterleitungen oder olsr-Announcements werden angelegt.
221 trap 'error_trap update_service_relay_status "$*"' EXIT
222 local service_name
223 local wan_status
224 if is_on_module_installed_and_enabled "on-usergw"; then
225 for service_name in $(get_services | filter_relay_services); do
226 # WAN-Routing pruefen und aktualisieren
227 is_service_routed_via_wan "$service_name" && wan_status="true" || wan_status="false"
228 set_service_value "$service_name" "wan_status" "$wan_status"
229 is_service_relay_possible "$service_name" || continue
230 announce_olsr_service_relay "$service_name"
231 done
232 update_relay_firewall_rules
233 deannounce_unused_olsr_service_relays is_service_relay_possible
234 else
235 deannounce_unused_olsr_service_relays false
236 fi
237 apply_changes olsrd
238}
239
240
241## @fn filter_relay_services()
242## @brief Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die als Dienst-Relay fungieren.
243## @details Die Dienst-Namen werden über die Standardeingabe gelesen und an die Standardausgabe
244## weitergeleitet, falls es sich um einen Relay-Dienst handelt.
245filter_relay_services() {
246 local service_name
247 while read -r service_name; do
248 [ -z "$(get_service_value "$service_name" "local_relay_port")" ] || echo "$service_name"
249 done
250}
251
252# Ende der Doku-Gruppe
253## @}
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
Definition: core.sh:9
key
Definition: core.sh:85
done
Definition: core.sh:85
while read r key value
Definition: core.sh:85
is_on_module_installed_and_enabled(module)
Pruefe ob ein Opennet-Modul sowohl installiert, als auch aktiviert ist.
Definition: modules.sh:9
set eu case $1 in on usergw on function update_on_usergw_status on function update_service_relay_status
Definition: 120-on-usergw:9
is_ipv4(target)
Prüfe ob der übergebene Text eine IPv4-Adresse ist.
Definition: routing.sh:8
filter_routable_addresses()
Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert...
Definition: routing.sh:19
is_service_routed_via_wan(service_name)
Pruefe ob der Verkehr zum Anbieter des Diensts über ein WAN-Interface verlaufen würde.
Definition: services.sh:148
set_service_value()
Setzen eines oder mehrerer Werte fuer einen Dienst. Je nach Schluesselname wird der Inhalt in die per...
Definition: services.sh:79
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird,...
Definition: services.sh:68
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
Definition: services.sh:86
filter_services_by_value(key, value)
Definition: services.sh:74
uci_get_list(uci_path)
Liefere alle einzelnen Elemente einer UCI-Liste zurück.
Definition: uci.sh:15
uci_add_list(uci_path, new_item)
Füge einen neuen Wert zu einer UCI-Liste hinzu und achte dabei auf Einmaligkeit.
Definition: uci.sh:10
uci_delete_list(uci_path, value)
Lösche ein Element einer UCI-Liste.
Definition: uci.sh:33