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
7 SERVICE_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
24 pick_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.
45 update_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 dnat_chain="on_service_relay_dnat"
53  local parent_dnat_chain="prerouting_${ZONE_MESH}_rule"
54  local tos_chain="on_service_relay_tos"
55  local parent_tos_chain="PREROUTING"
56  local new_rules
57  main_ip=$(get_main_ip)
58  # calculate the entries for the new rules
59  # We need to do this in advance - otherwise it could happen, that DNS problems could cause
60  # invalid (i.e. missing) firewall rules. Only if at least one valid rule is calculated,
61  # the rules are updated.
62  new_rules=$(for service in $(get_services | filter_relay_services); do
63  is_service_relay_possible "$service" || continue
64  host=$(get_service_value "$service" "host")
65  port=$(get_service_value "$service" "port")
66  protocol=$(get_service_value "$service" "protocol")
67  local_port=$(get_service_value "$service" "local_relay_port")
68  target_ip=$(query_dns "$host" | filter_routable_addresses | tail -n 1)
69  # skip entries in case of broken DNS resolution
70  [ -z "$target_ip" ] && continue
71  echo "$host $port $protocol $local_port $target_ip"
72  done)
73  # do not apply changes, if there are no valid rules
74  [ -z "$new_rules" ] && return 0
75  # neue Chains erzeugen
76  iptables -t nat --new-chain "$dnat_chain" 2>/dev/null || iptables -t nat --flush "$dnat_chain"
77  iptables -t mangle --new-chain "$tos_chain" 2>/dev/null || iptables -t mangle --flush "$tos_chain"
78  # Verweis auf die neue Chain erzeugen
79  iptables -t nat --check "$parent_dnat_chain" -j "$dnat_chain" 2>/dev/null \
80  || iptables -t nat --insert "$parent_dnat_chain" -j "$dnat_chain"
81  iptables -t mangle --check "$parent_tos_chain" -j "$tos_chain" 2>/dev/null \
82  || iptables -t mangle --insert "$parent_tos_chain" -j "$tos_chain"
83  # DNAT- und TOS-Chain fuellen
84  echo "$new_rules" | while read -r host port protocol local_port target_ip; do
85  iptables -t nat -A "$dnat_chain" --destination "$main_ip" --protocol "$protocol" --dport "$local_port" \
86  -j DNAT --to-destination "${target_ip}:${port}"
87  # falls on-openvpn vorhanden ist, wollen wir vermeiden, dass mesh-Tunnel ueber den Internet-Tunnel laufen
88  [ -z "${TOS_NON_TUNNEL:-}" ] || iptables -t mangle -A "$tos_chain" --destination "$main_ip" \
89  --protocol "$protocol" --dport "$local_port" -j TOS --set-tos "$TOS_NON_TUNNEL"
90  done
91  # Connection-Tracking-Tabelle flushen
92  # Sonst werden Aenderungen fuer bestehende Verbindungen nicht wirksam.
93  echo f >/proc/net/nf_conntrack
94 }
95 
96 
97 _get_service_relay_olsr_announcement_prefix() {
98  trap 'error_trap _get_service_relay_olsr_announcement_prefix "$*"' EXIT
99  local service_name="$1"
100  local main_ip
101  local service_type
102  local scheme
103  local host
104  local port
105  local protocol
106  main_ip=$(get_main_ip)
107  service_type=$(get_service_value "$service_name" "service")
108  # remove prefix
109  service_type="${service_type#$RELAYABLE_SERVICE_PREFIX}"
110  scheme=$(get_service_value "$service_name" "scheme")
111  host=$(get_service_value "$service_name" "host")
112  port=$(pick_local_service_relay_port "$service_name")
113  protocol=$(get_service_value "$service_name" "protocol")
114  # announce the service
115  echo "${scheme}://${main_ip}:${port}|${protocol}|${service_type}"
116 }
117 
118 
119 ## @fn get_service_relay_olsr_announcement()
120 ## @brief Ermittle den oder die OLSR-Nameservice-Announcements, die zu dem Dienst gehoeren.
121 get_service_relay_olsr_announcement() {
122  trap 'error_trap get_service_relay_olsr_announcement "$*"' EXIT
123  local service_name="$1"
124  local announce_unique
125  local uci_prefix
126  announce_unique=$(_get_service_relay_olsr_announcement_prefix "$service_name")
127  uci_prefix=$(get_and_enable_olsrd_library_uci_prefix "nameservice")
128  uci_get_list "${uci_prefix}.service" | awk '{ if ($1 == "'"$announce_unique"'") print $0; }'
129 }
130 
131 
132 ## @fn announce_olsr_service_relay()
133 ## @brief Verkuende das lokale Relay eines öffentlichen Dienstes inkl. Geschwindigkeitsdaten via olsr nameservice.
134 ## @param service_name Name des zu veröffentlichenden Diensts
135 ## @attention Anschließend muss die uci-Sektion 'olsrd' committed werden.
136 announce_olsr_service_relay() {
137  trap 'error_trap announce_olsr_service_relay "$*"' EXIT
138  local service_name="$1"
139  local service_unique
140  local service_details
141  service_unique=$(_get_service_relay_olsr_announcement_prefix "$service_name")
142  # das 'service_name'-Detail wird fuer die anschliessende Beraeumung (firewall-Regeln usw.) verwendet
143  # nur nicht-leere Attribute werden geschrieben
144  service_details=$(while read -r key value; do [ -z "$value" ] && continue; echo "$key:$value"; done <<EOF
145  public_host $(get_service_value "$service_name" "host")
146  upload $(get_service_value "$service_name" "wan_speed_upload")
147  download $(get_service_value "$service_name" "wan_speed_download")
148  ping $(get_service_value "$service_name" "wan_ping")
149 EOF
150 )
151  # Zeilenumbrueche durch Leerzeichen ersetzen, abschliessendes Leerzeichen entfernen
152  service_details=$(echo "$service_details" | tr '\n' ' ' | sed 's/ $//')
153  # loesche alte Dienst-Announcements mit demselben Prefix
154  local this_unique
155  local this_details
156  local uci_prefix
157  uci_prefix=$(get_and_enable_olsrd_library_uci_prefix "nameservice")
158  # shellcheck disable=SC2034
159  get_service_relay_olsr_announcement "$service_name" | while read -r this_unique this_details; do
160  # der Wert ist bereits korrekt - wir koennen abbrechen
161  [ "$this_details" = "$service_details" ] && break
162  # der Wert ist falsch: loeschen und am Ende neu hinzufuegen
163  msg_debug "Deleting outdated service-relay announcement: $service_unique $this_details"
164  uci_delete_list "${uci_prefix}.service" "$service_unique $this_details"
165  done
166  # falls keine Treffer gibt, fuegen wir ein neues Announcement hinzu
167  if [ -z "$(get_service_relay_olsr_announcement "$service_name")" ]; then
168  msg_debug "Adding new service-relay announcement: $service_unique $service_details"
169  uci_add_list "${uci_prefix}.service" "$service_unique $service_details"
170  fi
171 }
172 
173 
174 ## @fn get_olsr_relay_service_name_from_description()
175 ## @brief Ermittle den Dienstnamen, der zu einer olsr-Relay-Service-Definition gehoert.
176 get_olsr_relay_service_name_from_description() {
177  trap 'error_trap get_olsr_relay_service_name_from_description "$*"' EXIT
178  local service_description="$1"
179  local fields
180  local port
181  local service_type
182  fields=$(echo "$service_description" | parse_olsr_service_descriptions)
183  port=$(echo "$fields" | cut -f 4)
184  service_type=$(echo "$fields" | cut -f 1)
185  get_services "${RELAYABLE_SERVICE_PREFIX}$service_type" | filter_services_by_value "local_relay_port" "$port"
186 }
187 
188 
189 # olsr-Nameservice-Beschreibungen entfernen falls der dazugehoerige Dienst nicht mehr relay-tauglich ist
190 deannounce_unused_olsr_service_relays() {
191  # wir erwarten einen ausführbaren Testnamen
192  local test_for_activity="$1"
193  local service_description
194  local service_name
195  local uci_prefix
196  uci_prefix=$(get_and_enable_olsrd_library_uci_prefix "nameservice")
197  uci_get_list "${uci_prefix}.service" | while read -r service_description; do
198  # unbenutzte Eintraege entfernen
199  service_name=$(get_olsr_relay_service_name_from_description "$service_description")
200  # falls es den Dienst noch gibt: ist er immer noch aktiv?
201  [ -n "$service_name" ] && "$test_for_activity" "$service_name" && continue
202  uci_delete_list "${uci_prefix}.service" "$service_description"
203  done
204  return 0
205 }
206 
207 
208 ## @fn is_service_relay_possible()
209 ## @brief Pruefe ob ein Relay-Dienst aktiviert (nicht "disabled") ist und ob das WAN-Routing korrekt ist.
210 is_service_relay_possible() {
211  trap 'error_trap is_service_relay_possible "$*"' EXIT
212  local service_name="$1"
213  local disabled
214  local wan_routing
215  disabled=$(get_service_value "$service_name" "disabled" "false")
216  uci_is_true "$disabled" && trap "" EXIT && return 1
217  wan_routing=$(get_service_value "$service_name" "wan_status" "false")
218  uci_is_false "$wan_routing" && trap "" EXIT && return 1
219  return 0
220 }
221 
222 
223 ## @fn update_service_relay_status()
224 ## @brief Pruefe regelmaessig, ob Weiterleitungen für alle bekannten durchgereichten Diensten existieren.
225 ## @details Fehlende Weiterleitungen oder olsr-Announcements werden angelegt.
227  trap 'error_trap update_service_relay_status "$*"' EXIT
228  local service_name
229  local wan_status
230  if is_on_module_installed_and_enabled "on-usergw"; then
231  for service_name in $(get_services | filter_relay_services); do
232  # WAN-Routing pruefen und aktualisieren
233  is_service_routed_via_wan "$service_name" && wan_status="true" || wan_status="false"
234  set_service_value "$service_name" "wan_status" "$wan_status"
235  is_service_relay_possible "$service_name" || continue
236  announce_olsr_service_relay "$service_name"
237  done
238  update_relay_firewall_rules
239  deannounce_unused_olsr_service_relays is_service_relay_possible
240  else
241  deannounce_unused_olsr_service_relays false
242  fi
243  apply_changes olsrd
244 }
245 
246 
247 ## @fn filter_relay_services()
248 ## @brief Filtere aus einer Reihe eingehender Dienste diejenigen heraus, die als Dienst-Relay fungieren.
249 ## @details Die Dienst-Namen werden über die Standardeingabe gelesen und an die Standardausgabe
250 ## weitergeleitet, falls es sich um einen Relay-Dienst handelt.
251 filter_relay_services() {
252  local service_name
253  while read -r service_name; do
254  [ -z "$(get_service_value "$service_name" "local_relay_port")" ] || echo "$service_name"
255  done
256 }
257 
258 # Ende der Doku-Gruppe
259 ## @}
set eu case in on usergw on function update_on_usergw_status on function update_service_relay_status
Definition: 120-on-usergw:9
get_services(service_type)
Liefere alle Dienste zurueck, die dem angegebenen Typ zugeordnet sind. Falls kein Typ angegben wird...
Definition: services.sh:68
while read r key value
Definition: core.sh:85
set_service_value()
Setzen eines oder mehrerer Werte fuer einen Dienst. Je nach Schluesselname wird der Inhalt in die per...
Definition: services.sh:79
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
local key
Definition: core.sh:85
filter_services_by_value(key, value)
Definition: services.sh:74
set eu grep root::etc shadow exit if command v chpasswd dev null
Definition: on-password:12
uci_delete_list(uci_path, value)
Lösche ein Element einer UCI-Liste.
Definition: uci.sh:33
uci_get_list(uci_path)
Liefere alle einzelnen Elemente einer UCI-Liste zurück.
Definition: uci.sh:15
filter_routable_addresses()
Filtere aus einer Menge von Ziel-IPs diejenigen heraus, für die eine passende Routing-Regel existiert...
Definition: routing.sh:19
msg_debug(message)
Debug-Meldungen ins syslog schreiben.
Definition: core.sh:9
get_service_value(key, default)
Auslesen eines Werts aus der Service-Datenbank.
Definition: services.sh:86
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
done
Definition: core.sh:85
set eu for table in filter nat mangle
Definition: firewall:10
is_on_module_installed_and_enabled(module)
Pruefe ob ein Modul sowohl installiert, als auch aktiv ist.
Definition: modules.sh:9