Opennet Firmware
on-captive-portal.sh
gehe zur Dokumentation dieser Datei
1 ## @defgroup captive_portal Captive Portal
2 ## @brief Funktionen für den Umgang mit der Captive-Portal-Software für offene WLAN-Knoten
3 # Beginn der Doku-Gruppe
4 ## @{
5 
6 
7 # shellcheck disable=SC2034
8 ZONE_FREE=on_free
9 NETWORK_FREE=on_free
10 ## @var Quelldatei für Standardwerte des Hotspot-Pakets
11 ON_CAPTIVE_PORTAL_DEFAULTS_FILE=/usr/share/opennet/captive-portal.defaults
12 
13 
14 ## @fn configure_free_network()
15 ## @brief Erzeuge das free-Netzwerk-Interface, falls es noch nicht existiert.
17  local uci_prefix="network.$NETWORK_FREE"
18  # es wurde bereits einmalig konfiguriert
19  if [ -z "$(uci_get "$uci_prefix")" ]; then
20  uci set "${uci_prefix}=interface"
21  uci set "${uci_prefix}.ifname=none"
22  uci set "${uci_prefix}.proto=static"
23  uci set "${uci_prefix}.ipaddr=$(get_on_captive_portal_default free_ipaddress)"
24  uci set "${uci_prefix}.netmask=$(get_on_captive_portal_default free_netmask)"
25  uci set "${uci_prefix}.auto=1"
26  apply_changes network
27  fi
28  # konfiguriere DHCP
29  uci_prefix=$(find_first_uci_section "dhcp" "dhcp" "interface=$NETWORK_FREE")
30  # beenden, falls vorhanden
31  if [ -z "$uci_prefix" ]; then
32  # DHCP-Einstellungen fuer dieses Interface festlegen
33  uci_prefix="dhcp.$(uci add "dhcp" "dhcp")"
34  uci set "${uci_prefix}.interface=$NETWORK_FREE"
35  uci set "${uci_prefix}.start=10"
36  uci set "${uci_prefix}.limit=240"
37  uci set "${uci_prefix}.leasetime=30m"
38  apply_changes dhcp
39  fi
40 }
41 
42 
43 ## @fn get_on_captive_portal_default()
44 ## @param key Name des Schlüssels
45 ## @brief Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-captive-portal).
46 ## @details Die default-Werte werden nicht von der Konfigurationsverwaltung uci verwaltet.
47 ## Somit sind nach jedem Upgrade imer die neuesten Standard-Werte verfügbar.
49  local key="$1"
50  _get_file_dict_value "$key" "$ON_CAPTIVE_PORTAL_DEFAULTS_FILE"
51 }
52 
53 
54 ## @fn captive_portal_has_devices()
55 ## @brief Prüfe, ob dem Captive Portal mindestens ein physisches Netzwerk-Gerät zugeordnet ist.
56 ## @details Sobald ein Netzwerk-Gerät konfiguriert ist, gilt der Captive-Portal-Dienst als aktiv.
57 ## Es werden sowohl nicht-wifi-, als auch wifi-Interfaces geprueft.
59  [ -n "$(get_subdevices_of_interface "$NETWORK_FREE")" ] && return 0
60  [ -n "$(find_all_uci_sections wireless wifi-iface "network=$NETWORK_FREE")" ] && return 0
61  trap "" EXIT && return 1
62 }
63 
64 
65 ## @fn captive_portal_repair_empty_network_bridge()
66 ## @brief Reduziere Konstruktionen wie beispielsweise "bridge(None, wlan0)" zu "wlan0".
67 ## @details Brücken mit "none"-Elementen verwirren das nodogsplash-Start-Skript.
69  local uci_prefix="network.${NETWORK_FREE}"
70  local sub_device_count
71  if [ "$(uci_get "${uci_prefix}.type")" = "bridge" ] && [ "$(uci_get "${uci_prefix}.ifname")" = "none" ]; then
72  # verdaechtig: Bruecke mit "none"-Device
73  sub_device_count=$(get_subdevices_of_interface "$NETWORK_FREE" | wc -w)
74  if [ "$sub_device_count" -eq "1" ]; then
75  # wifi-Device is konfiguriert - Bruecke und "none" kann entfernt werden
76  uci_delete "${uci_prefix}.type"
77  uci_delete "${uci_prefix}.ifname"
78  else
79  # nichts ist konfiguriert - erstmal nur die Bruecke entfernen
80  uci_delete "${uci_prefix}.type"
81  fi
82  apply_changes network
83  fi
84 }
85 
86 
87 ## @fn captive_portal_uses_wifi_only_bridge()
88 ## @brief Prüfe ob eine fehleranfällige Brige-Konstruktion vorliegt.
89 ## @details Reine wifi-Bridges scheinen mit openwrt nicht nutzbar zu sein.
91  local uci_prefix="network.${NETWORK_FREE}"
92  local ifname
93  if [ "$(uci_get "${uci_prefix}.type")" = "bridge" ]; then
94  ifname=$(uci_get "${uci_prefix}.ifname")
95  if [ -z "$ifname" ] || [ "$ifname" = "none" ]; then
96  if [ -n "$(get_subdevices_of_interface "$NETWORK_FREE")" ]; then
97  # anscheinend handelt es sich um eine reine wifi-Bridge
98  return 0
99  fi
100  fi
101  fi
102  trap "" EXIT && return 1
103 }
104 
105 
107  if is_on_module_installed_and_enabled "on-captive-portal"; then
109  else
110  disable_captive_portal
111  fi
112 }
113 
114 
115 change_captive_portal_wireless_disabled_state() {
116  local state="$1"
117  local uci_prefix
118  find_all_uci_sections wireless wifi-iface "network=$NETWORK_FREE" | while read -r uci_prefix; do
119  uci set "${uci_prefix}.disabled=$state"
120  done
121  apply_changes wireless
122 }
123 
124 
125 disable_captive_portal() {
126  trap "error_trap disable_captive_portal" EXIT
127  msg_info "on-captive-portal: wifi-Interfaces abschalten"
128  # free-Interface ist aktiv - es gibt jedoch keinen Tunnel
129  change_captive_portal_wireless_disabled_state "1"
130 }
131 
132 
133 ## @fn sync_captive_portal_state_with_mig_connections()
134 ## @brief Synchronisiere den Zustand (up/down) des free-Interface mit dem des VPN-Tunnel-Interface.
135 ## @details Diese Funktion wird nach Statusänderungen des VPN-Interface, sowie innerhalb eines
136 ## regelmäßigen cronjobs ausgeführt.
138  trap "error_trap sync_captive_portal_state_with_mig_connections" EXIT
139  # eventuelle defekte/verwirrende Netzwerk-Konfiguration korrigieren
141  # Abbruch, falls keine Netzwerk-Interfaces zugeordnet wurden
142  captive_portal_has_devices || return 0
143  local mig_active
144  local address
145  local device_active=
146  mig_active=$(get_active_mig_connections)
147  if is_interface_up "$NETWORK_FREE"; then
148  # Pruefe ob mindestens eine IPv4-Adresse konfiguriert ist.
149  # (aus unbekannten Gruenden kann es vorkommen, dass die IPv4-Adresse spontan wegfaellt)
150  for address in $(get_current_addresses_of_network "$NETWORK_FREE"); do
151  is_ipv4 "$address" && device_active=1 && break
152  true
153  done
154  fi
155  if [ -n "$device_active" ] && [ -z "$mig_active" ]; then
156  disable_captive_portal
157  elif [ -n "$mig_active" ]; then
158  [ -z "$device_active" ] && ifup "$NETWORK_FREE"
159  change_captive_portal_wireless_disabled_state "0"
160  fi
161 }
162 
163 
164 ## @fn is_captive_portal_running()
165 ## @brief Prüfe ob das Netzwerk-Interface des Captive-Portal aktiv ist.
167  is_interface_up "$NETWORK_FREE" && return 0
168  trap "" EXIT && return 1
169 }
170 
171 
172 ## @fn get_captive_portal_client_count()
173 ## @brief Ermittle die Anzahl der verbundenen Clients. Leere Ausgabe, falls keine aktiven
174 ## Interfaces vorhanden sind.
176  local count=
177  local this_count
178  local assoclist
179  local device
181  count=0
182  for device in $(get_subdevices_of_interface "$NETWORK_FREE"); do
183  if assoclist=$(iwinfo "$device" assoclist 2>/dev/null); then
184  this_count=$(echo "$assoclist" | awk '{ if (($1 == "TX:") && ($(NF-1) >= 100)) count++; } END { print count; }')
185  else
186  # determine the number of valid arp cache items for this interface
187  this_count=$(ip neighbor list dev "$device" | grep -c 'REACHABLE$' || true)
188  fi
189  count=$((count + this_count))
190  done
191  fi
192  # Liefere keine Ausgabe (leer), falls wir gar nichts zum Zaehlen gefunden haben.
193  # Dadurch kann das munin-Plugin (und andere Aufrufer) erkennen, dass das Portal nicht
194  # laeuft.
195  [ -z "$count" ] && return 0
196  echo -n "$count"
197 }
198 
199 
200 ## @fn get_captive_portal_clients()
201 ## @brief Zeilenweise aller aktuellen Clients inklusive ihrer relevanten Kenngrößen.
202 ## @details In jeder Zeile wird ein Client beschrieben, wobei die folgenden Detailinformationen durch Tabulatoren getrennt sind:
203 ## * IP-Adresse
204 ## * MAC-Adresse
205 ## * Zeitpunkt des Verbindungsaufbaus (seit epoch)
206 ## * Zeitpunkt der letzten Aktivität (seit epoch)
207 ## * Download-Verkehrsvolumen (kByte)
208 ## * Upload-Verkehrsvolumen (kByte)
209 ## Der Einfachheit halber nehmen wir an, dass alle DHCP-Clients auch Captive-Portal-Clients sind.
211  trap 'error_trap get_captive_portal_clients "'"$*"'"' EXIT
212  local ip_address
213  local mac_address
214  local timestamp
215  local packets_rxtx
216  # Die "iwinfo assoclist" ist wahrscheinlich der einzige brauchbare Weg, um
217  # Verkehrsstatistiken zu beliebigen Peers zu erhalten. Wir müssen es also gar nicht erst
218  # mit anderen (nicht-wifi) Interfaces versuchen.
219  local assoclist
220  assoclist=$(for device in $(get_subdevices_of_interface "$NETWORK_FREE"); do \
221  iwinfo wlan0 assoclist 2>/dev/null || true; done)
222  # erzwinge eine leere Zeile am Ende fuer die finale Ausgabe des letzten Clients
223  # shellcheck disable=SC2034
224  while read -r timestamp mac_address ip_address hostname misc; do
225  # eine assoclist-Zeile sieht etwa folgendermassen aus:
226  # TX: 6.5 MBit/s, MCS 0, 20MHz 217 Pkts.
227  packets_rxtx=$(echo "$assoclist" | awk '
228  BEGIN { my_mac = tolower("'"$mac_address"'"); }
229  {
230  if ($1 ~ /^(..:){5}..$/) current_mac = tolower($1);
231  if (($1 == "RX:") && (my_mac == current_mac)) my_rx=$(NF-1);
232  if (($1 == "TX:") && (my_mac == current_mac)) my_tx=$(NF-1);
233  }
234  END { OFS="\t"; print(my_rx, my_tx); }')
235  printf '%s\t%s\t%s\t%s\n' "$ip_address" "$mac_address" "$timestamp" "$packets_rxtx"
236  done </var/dhcp.leases
237 }
238 
239 # Ende der Doku-Gruppe
240 ## @}
uci_delete(uci_path)
Lösche ein UCI-Element.
Definition: uci.sh:46
get_captive_portal_clients()
Zeilenweise aller aktuellen Clients inklusive ihrer relevanten Kenngrößen.
set eu case in on captive portal on function update_captive_portal_status
is_ipv4(target)
Prüfe ob der übergebene Text eine IPv4-Adresse ist.
Definition: routing.sh:8
sync_captive_portal_state_with_mig_connections()
Synchronisiere den Zustand (up/down) des free-Interface mit dem des VPN-Tunnel-Interface.
local key
Definition: core.sh:85
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
Definition: core.sh:85
set eu grep root::etc shadow exit if command v chpasswd dev null
Definition: on-password:12
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
Definition: core.sh:15
is_interface_up(interface)
Prüfe ob ein logisches Netzwerk-Interface aktiv ist.
Definition: network.sh:72
get_on_captive_portal_default(key)
Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-captive-portal).
get_subdevices_of_interface()
Ermittle die physischen Netzwerk-Geräte (bis auf wifi), die zu einem logischen Netzwerk-Interface geh...
Definition: network.sh:42
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
captive_portal_repair_empty_network_bridge()
Reduziere Konstruktionen wie beispielsweise "bridge(None, wlan0)" zu "wlan0".
captive_portal_has_devices()
Prüfe, ob dem Captive Portal mindestens ein physisches Netzwerk-Gerät zugeordnet ist.
configure_free_network()
Erzeuge das free-Netzwerk-Interface, falls es noch nicht existiert.
is_captive_portal_running()
Prüfe ob das Netzwerk-Interface des Captive-Portal aktiv ist.
get_active_mig_connections()
Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
Definition: on-openvpn.sh:34
get_captive_portal_client_count()
Ermittle die Anzahl der verbundenen Clients. Leere Ausgabe, falls keine aktiven Interfaces vorhanden ...
captive_portal_uses_wifi_only_bridge()
Prüfe ob eine fehleranfällige Brige-Konstruktion vorliegt.
done
Definition: core.sh:85
is_on_module_installed_and_enabled(module)
Pruefe ob ein Modul sowohl installiert, als auch aktiv ist.
Definition: modules.sh:9