Dienstag, 31. Juli 2018

Import static Leases in OpenWrt

OpenWrt kann mit speziellen Kommandos (uci) in der Shell konfiguriert werden.
Ich habe mir immer gewünscht, statische DHCP Reservierungen einfach durch Textdateien zu konfigurieren. OpenWrt kann zwar wenigsten in der Weboberfläche die MAC Adressen per Copy&Paste einfügen, aber ich hätte es gern komfortabler.
Wer spielen will, der macht zunächst nichts kaputt. Die Konfigurationsänderungen werden zunächst nur temporär ausgeführt.
Die dhcp Konfiguration anzeigen:
uci show dhcp
uci show dhcp | grep '@host\[0\]'
uci get dhcp.@host[0].ip
Die Host Einträge in der /etc/config/dhcp stehen dort am Ende und sind nicht indiziert. Das uci indiziert sie "fließend" für uns und einen direkten Zugriff:
  • [0] ist der erste, 
  • [-1] der letzte Eintrag.

Vorbemerkung

Ich habe ein paar Scripts als heredoc erstellt, die kann man einfach per copy&paste ins Terminal fallen lassen. Damit die $ Zeichen nicht als Variablen interpretiert werden, muss EOF in einfache ' ' gesetzt werden!
Die uci arbeitet temporär, man kann sich mit uci changes den Erfolg anzeigen lassen. Mit uci revert dhcp kann man alles immer wieder rückgängig machen.
Erst ein uci commit schafft Tatsachen.

Hosts hinzufügen

Will man einen neuen Host eintragen geht das mit folgendem Beispiel. Ein neuer Eintrag wird angefügt und ist damit der Letzte, dieser wird um die Werte ip und mac ergänzt:
script="addhost.sh"
cat <<'EOF' >$script
#!/bin/sh
if [ $# -eq 3 ]
  then
    echo "name=$1 ip=$2 mac=$3"
  else
    echo "Fehler: Bitte name ip und mac angeben."
    exit
fi
uci add dhcp host
uci set dhcp.@host[-1].name=$1
uci set dhcp.@host[-1].ip=$2
uci set dhcp.@host[-1].mac=$3
EOF
chmod +x $script
Jetzt kann man eine existierende Lease Zeile aus dem Browser kopieren und als Reservierung einfügen
./addhost.sh HPF43909586B94 192.168.56.111 F4:39:09:58:6B:94
Mit einer Schleife kann man Zeilenweise den stdin lesen und und pro Zeile einen neuen Hosteintrag erstellen. Damit die static Leases lesbar bleiben sollte ein Hostname mit in die Tabelle.
Read Host per Line -> rhpl.sh
script="rhpl.sh"
cat <<'EOF' >$script
#!/bin/sh
while read line; do
./addhost.sh $line
done
EOF
chmod +x $script
Dazu eine Datei mit Wertepaaren -> wp.txt
host1 192.168.1.1 aa:bb:cc:dd:ee:d1
host2 192.168.1.2 aa:bb:cc:dd:ee:d2
host3 192.168.1.3 aa:bb:cc:dd:ee:d3
Das Ganze mit der Pipe verknüpft und fertig ist der Import!
./rhpl.sh <wp.txt
Nachtrag 2021: Hat man mehrere Dateien, kann man diese gemeinsam lesen, die MAC Adressen in Großbuchstaben wandeln, sortieren, Doubletten entfernen und einlesen
cat leases.txt wpo.txt |awk '{ print( $1,$2,toupper($3) ) }'|sort|uniq|./rhpl.sh
Noch ist nichts aktiv!

Hosts löschen

Will man vor dem Import aufräumen, kann man mit einem (nicht perfekten) Einzeiler erst einmal alle Hosts löschen:
while uci delete dhcp.@host[0]; do :;done
Die Schleife läuft einmal zu viel, deswegen gibt es einen Fehler. Aber alle Hosts sind gelöscht.

Host auslesen

Damit man die Liste der Werte Paar nicht komplette per Hand erstellen muss, kann man existierende Daten auslesen. Die entstandenen Dateien kann man bei Bedarf bearbeiten und anschließend importieren.

Static Leases auslesen

Um alle Hosts in eine Datei zu exportieren, braucht man eine formatierte Ausgabe
printf "$(uci get dhcp.@host[-1].name) $(uci get dhcp.@host[-1].ip) $(uci get dhcp.@host[-1].mac)\n"
Und ein Array mit den vorhandenen Indizes. Ein doppelter "Eierkuchen" liefert uns dies aus dem show Befehl.
echo $(uci show dhcp | grep -oE "host\[\d+\].ip"|grep -oE '\d+')
Eine simple Schleife liefert uns die Wertepaare als Ausgabe.
script="wrlp.sh"
cat <<'EOF' > $script
#!/bin/sh
for i in $(uci show dhcp | grep -oE "host\[\d+\].ip"|grep -oE '\d+'); do
  printf "$(uci get dhcp.@host[$i].name) $(uci get dhcp.@host[$i].ip) $(uci get dhcp.@host[$i].mac)\n"
done
EOF
chmod +x $script
Die schreibt man einfach in eine Datei.
./wrlp.sh >wpo.txt

Aktuelle Leases auslesen

Nachtrag 2021: Ich habe noch eine bessere Variante zum Auslesen der aktiven Leases gefunden, lasse aber den alten Code bewusst noch stehen.
cat /tmp/dhcp.leases| awk '$4 != "*" { print( $4,$3,$2 ) }'
Um einfach mal alle existierenden Leases auszulesen genügt ein Einzeiler. Allerdings ist das Ausgabeformat anders als im Beispiel oben: mac IP Host (Darstellung im Browser Host IP mac)
cat /tmp/dhcp.leases |grep -oE '([a-f0-9]{2}:){5}[a-f0-9]{2}\s[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}\s[A-Z,a-z,0-9,-,_]*'
Das Script macht ein match auf mac Adresse, IP Adresse und String (Hostname)

Ich habe noch eine vereinfachte Form "experimentell" gefunden (\s.*\s passt auf IP Adresse und Hostname - warum? Der Rest wird abgeschnitten).
Aus der Ausgabe kann man noch per Pipe mit grep die Zeilen mit unbekannten Hostnamen (*) entfernen und mit awk formatieren.

grep -oE '([a-f0-9]{2}:){5}[a-f0-9]{2}\s.*\s' /tmp/dhcp.leases|grep -v "*"|awk '{print $3,$2,$1}'

Finale

Das uci System arbeitet temporär, will man seine Änderungen fest machen, muss man diese speichern und das jeweilige System(dhcp) neu starten. 
Achtung: Scheinbar wird seit einiger Zeit nicht mehr dnsmasq sondern odhcpd für den DHCP Service verwendet. Offenbar genügt aber ein commit Befehl den restart & reload kann man sparen?
uci commit dhcp
/etc/init.d/dnsmasq restart
luci-reload

Die uci Schnittstelle ist auch über JSON erreichbar.
wiki.teltonika.lt

Keine Kommentare:

Kommentar veröffentlichen