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}.device=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}.device")" = "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}.device"
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 
88  if is_on_module_installed_and_enabled "on-captive-portal"; then
90  else
91  disable_captive_portal
92  fi
93 }
94 
95 
96 change_captive_portal_wireless_disabled_state() {
97  local state="$1"
98  local uci_prefix
99  find_all_uci_sections wireless wifi-iface "network=$NETWORK_FREE" | while read -r uci_prefix; do
100  uci set "${uci_prefix}.disabled=$state"
101  done
102  apply_changes wireless
103 }
104 
105 
106 disable_captive_portal() {
107  trap "error_trap disable_captive_portal" EXIT
108  msg_info "on-captive-portal: wifi-Interfaces abschalten"
109  # free-Interface ist aktiv - es gibt jedoch keinen Tunnel
110  change_captive_portal_wireless_disabled_state "1"
111 }
112 
113 
114 ## @fn sync_captive_portal_state_with_mig_connections()
115 ## @brief Synchronisiere den Zustand (up/down) des free-Interface mit dem des VPN-Tunnel-Interface.
116 ## @details Diese Funktion wird nach Statusänderungen des VPN-Interface, sowie innerhalb eines
117 ## regelmäßigen cronjobs ausgeführt.
119  trap "error_trap sync_captive_portal_state_with_mig_connections" EXIT
120  # eventuelle defekte/verwirrende Netzwerk-Konfiguration korrigieren
122  # Abbruch, falls keine Netzwerk-Interfaces zugeordnet wurden
123  captive_portal_has_devices || return 0
124  local mig_active
125  local address
126  local device_active=
127  mig_active=$(get_active_mig_connections)
128  if is_interface_up "$NETWORK_FREE"; then
129  # Pruefe ob mindestens eine IPv4-Adresse konfiguriert ist.
130  # (aus unbekannten Gruenden kann es vorkommen, dass die IPv4-Adresse spontan wegfaellt)
131  for address in $(get_current_addresses_of_network "$NETWORK_FREE"); do
132  is_ipv4 "$address" && device_active=1 && break
133  true
134  done
135  fi
136  if [ -n "$device_active" ] && [ -z "$mig_active" ]; then
137  disable_captive_portal
138  elif [ -n "$mig_active" ]; then
139  [ -z "$device_active" ] && ifup "$NETWORK_FREE"
140  change_captive_portal_wireless_disabled_state "0"
141  fi
142 }
143 
144 
145 ## @fn is_captive_portal_running()
146 ## @brief Prüfe ob das Netzwerk-Interface des Captive-Portal aktiv ist.
148  is_interface_up "$NETWORK_FREE" && return 0
149  trap "" EXIT && return 1
150 }
151 
152 
153 ## @fn get_captive_portal_client_count()
154 ## @brief Ermittle die Anzahl der verbundenen Clients. Leere Ausgabe, falls keine aktiven
155 ## Interfaces vorhanden sind.
157  local count=
158  local this_count
159  local assoclist
160  local device
162  count=0
163  for device in $(get_subdevices_of_interface "$NETWORK_FREE"); do
164  if assoclist=$(iwinfo "$device" assoclist 2>/dev/null); then
165  this_count=$(echo "$assoclist" | awk '{ if (($1 == "TX:") && ($(NF-1) >= 100)) count++; } END { print count; }')
166  else
167  # determine the number of valid arp cache items for this interface
168  this_count=$(ip neighbor list dev "$device" | grep -c 'REACHABLE$' || true)
169  fi
170  count=$((count + this_count))
171  done
172  fi
173  # Liefere keine Ausgabe (leer), falls wir gar nichts zum Zaehlen gefunden haben.
174  # Dadurch kann das munin-Plugin (und andere Aufrufer) erkennen, dass das Portal nicht
175  # laeuft.
176  [ -z "$count" ] && return 0
177  echo -n "$count"
178 }
179 
180 
181 ## @fn get_captive_portal_clients()
182 ## @brief Zeilenweise aller aktuellen Clients inklusive ihrer relevanten Kenngrößen.
183 ## @details In jeder Zeile wird ein Client beschrieben, wobei die folgenden Detailinformationen durch Tabulatoren getrennt sind:
184 ## * IP-Adresse
185 ## * MAC-Adresse
186 ## * Zeitpunkt des Verbindungsaufbaus (seit epoch)
187 ## * Zeitpunkt der letzten Aktivität (seit epoch)
188 ## * Download-Verkehrsvolumen (kByte)
189 ## * Upload-Verkehrsvolumen (kByte)
190 ## Der Einfachheit halber nehmen wir an, dass alle DHCP-Clients auch Captive-Portal-Clients sind.
192  trap 'error_trap get_captive_portal_clients "'"$*"'"' EXIT
193  local ip_address
194  local mac_address
195  local timestamp
196  local packets_rxtx
197  # Die "iwinfo assoclist" ist wahrscheinlich der einzige brauchbare Weg, um
198  # Verkehrsstatistiken zu beliebigen Peers zu erhalten. Wir müssen es also gar nicht erst
199  # mit anderen (nicht-wifi) Interfaces versuchen.
200  local assoclist
201  assoclist=$(for device in $(get_subdevices_of_interface "$NETWORK_FREE"); do \
202  iwinfo wlan0 assoclist 2>/dev/null || true; done)
203  # erzwinge eine leere Zeile am Ende fuer die finale Ausgabe des letzten Clients
204  # shellcheck disable=SC2034
205  while read -r timestamp mac_address ip_address hostname misc; do
206  # eine assoclist-Zeile sieht etwa folgendermassen aus:
207  # TX: 6.5 MBit/s, MCS 0, 20MHz 217 Pkts.
208  packets_rxtx=$(echo "$assoclist" | awk '
209  BEGIN { my_mac = tolower("'"$mac_address"'"); }
210  {
211  if ($1 ~ /^(..:){5}..$/) current_mac = tolower($1);
212  if (($1 == "RX:") && (my_mac == current_mac)) my_rx=$(NF-1);
213  if (($1 == "TX:") && (my_mac == current_mac)) my_tx=$(NF-1);
214  }
215  END { OFS="\t"; print(my_rx, my_tx); }')
216  printf '%s\t%s\t%s\t%s\n' "$ip_address" "$mac_address" "$timestamp" "$packets_rxtx"
217  done </var/dhcp.leases
218 }
219 
220 # Ende der Doku-Gruppe
221 ## @}
set eu case in on captive portal on function update_captive_portal_status
get_captive_portal_clients()
Zeilenweise aller aktuellen Clients inklusive ihrer relevanten Kenngrößen.
sync_captive_portal_state_with_mig_connections()
Synchronisiere den Zustand (up/down) des free-Interface mit dem des VPN-Tunnel-Interface.
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.
get_captive_portal_client_count()
Ermittle die Anzahl der verbundenen Clients. Leere Ausgabe, falls keine aktiven Interfaces vorhanden ...
captive_portal_repair_empty_network_bridge()
Reduziere Konstruktionen wie beispielsweise "bridge(None, wlan0)" zu "wlan0".
get_on_captive_portal_default(key)
Liefere einen der default-Werte der aktuellen Firmware zurück (Paket on-captive-portal).
is_captive_portal_running()
Prüfe ob das Netzwerk-Interface des Captive-Portal aktiv ist.
_get_file_dict_value(key)
Auslesen eines Werts aus einem Schlüssel/Wert-Eingabestrom.
Definition: core.sh:85
key
Definition: core.sh:85
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
Definition: core.sh:15
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
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....
Definition: network.sh:19
is_interface_up(interface)
Prüfe ob ein logisches Netzwerk-Interface aktiv ist.
Definition: network.sh:72
get_active_mig_connections()
Liefere die aktiven VPN-Verbindungen (mit Mesh-Internet-Gateways) zurück.
Definition: on-openvpn.sh:34
is_ipv4(target)
Prüfe ob der übergebene Text eine IPv4-Adresse ist.
Definition: routing.sh:8
uci_delete(uci_path)
Lösche ein UCI-Element.
Definition: uci.sh:46