|
|
@@ -807,9 +807,82 @@ mkdir -p "$(dirname "$ziel")"
|
|
|
|
printf %s '@FRACHT@' | base64 -d > "$ziel"
|
|
|
|
printf %s '@FRACHT@' | base64 -d > "$ziel"
|
|
|
|
chmod 0644 "$ziel"
|
|
|
|
chmod 0644 "$ziel"
|
|
|
|
echo "geschrieben: $ziel"
|
|
|
|
echo "geschrieben: $ziel"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Der Uebersetzer: systemd legt fremde Optionen roh und unter ihrer Nummer ab
|
|
|
|
|
|
|
|
# ("OPTION_225=687474..."), weil im DHCP-Paket weder Name noch Typ steht.
|
|
|
|
|
|
|
|
# Beides weiss nur dieser Server -- also schreibt er die Zuordnung mit.
|
|
|
|
|
|
|
|
mkdir -p /usr/local/lib/tesm
|
|
|
|
|
|
|
|
printf %s '@UEBERSETZER@' | base64 -d > /usr/local/lib/tesm/dhcp-options
|
|
|
|
|
|
|
|
chmod 0755 /usr/local/lib/tesm/dhcp-options
|
|
|
|
|
|
|
|
printf %s '@DIENST@' | base64 -d > /etc/systemd/system/tesm-dhcp-options.service
|
|
|
|
|
|
|
|
printf %s '@PFADEINHEIT@' | base64 -d > /etc/systemd/system/tesm-dhcp-options.path
|
|
|
|
|
|
|
|
chmod 0644 /etc/systemd/system/tesm-dhcp-options.service /etc/systemd/system/tesm-dhcp-options.path
|
|
|
|
|
|
|
|
systemctl daemon-reload
|
|
|
|
|
|
|
|
systemctl enable --now tesm-dhcp-options.path >/dev/null 2>&1 || true
|
|
|
|
|
|
|
|
systemctl enable tesm-dhcp-options.service >/dev/null 2>&1 || true
|
|
|
|
|
|
|
|
|
|
|
|
networkctl reload
|
|
|
|
networkctl reload
|
|
|
|
networkctl reconfigure "$schnittstelle"
|
|
|
|
networkctl reconfigure "$schnittstelle"
|
|
|
|
|
|
|
|
# Der Pfadwaechter loest bei der naechsten Lease aus; einmal von Hand, damit
|
|
|
|
|
|
|
|
# die Datei sofort dasteht.
|
|
|
|
|
|
|
|
sleep 2
|
|
|
|
|
|
|
|
systemctl start tesm-dhcp-options.service || true
|
|
|
|
echo "Lease: /run/systemd/netif/leases/$(cat /sys/class/net/"$schnittstelle"/ifindex)"
|
|
|
|
echo "Lease: /run/systemd/netif/leases/$(cat /sys/class/net/"$schnittstelle"/ifindex)"
|
|
|
|
|
|
|
|
echo "Klartext: /run/tesm-dhcp-options.env"
|
|
|
|
|
|
|
|
cat /run/tesm-dhcp-options.env 2>/dev/null || true
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#: Uebersetzt die rohen Optionen der Lease in "name=wert".
|
|
|
|
|
|
|
|
#:
|
|
|
|
|
|
|
|
#: Warum es das braucht: in einem DHCP-Paket stehen nur Nummer, Laenge und
|
|
|
|
|
|
|
|
#: Bytes. Dass 225 "url" heisst und eine Zeichenkette ist, steht allein im
|
|
|
|
|
|
|
|
#: Katalog dieses Servers -- systemd kann es nicht wissen und legt deshalb
|
|
|
|
|
|
|
|
#: Hex unter der Nummer ab. Diese Zuordnung reist mit.
|
|
|
|
|
|
|
|
UEBERSETZER = """#!/bin/sh
|
|
|
|
|
|
|
|
# Von TESM erzeugt. Schreibt die eigenen DHCP-Optionen im Klartext nach
|
|
|
|
|
|
|
|
# /run/tesm-dhcp-options.env -- eine Zeile "name=wert" je Option.
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
ziel=/run/tesm-dhcp-options.env
|
|
|
|
|
|
|
|
schnittstelle=$(ip -o -4 route show default 2>/dev/null | awk '{print $5; exit}')
|
|
|
|
|
|
|
|
[ -n "$schnittstelle" ] || exit 0
|
|
|
|
|
|
|
|
lease=/run/systemd/netif/leases/$(cat /sys/class/net/"$schnittstelle"/ifindex 2>/dev/null)
|
|
|
|
|
|
|
|
[ -f "$lease" ] || exit 0
|
|
|
|
|
|
|
|
zwischen=$(mktemp)
|
|
|
|
|
|
|
|
for paar in @PAARE@; do
|
|
|
|
|
|
|
|
code=${paar%%:*}
|
|
|
|
|
|
|
|
name=${paar#*:}
|
|
|
|
|
|
|
|
roh=$(sed -n "s/^OPTION_$code=//p" "$lease" | head -n1)
|
|
|
|
|
|
|
|
[ -n "$roh" ] || continue
|
|
|
|
|
|
|
|
wert=$(/usr/bin/printf "$(echo "$roh" | sed 's/../@BS@x&/g')")
|
|
|
|
|
|
|
|
echo "$name=$wert" >> "$zwischen"
|
|
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
mv -f "$zwischen" "$ziel"
|
|
|
|
|
|
|
|
chmod 0644 "$ziel"
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#: Einmal beim Start und nach jeder Lease.
|
|
|
|
|
|
|
|
DIENST_EINHEIT = """[Unit]
|
|
|
|
|
|
|
|
Description=TESM -- DHCP-Optionen im Klartext
|
|
|
|
|
|
|
|
After=systemd-networkd.service
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Service]
|
|
|
|
|
|
|
|
Type=oneshot
|
|
|
|
|
|
|
|
ExecStart=/usr/local/lib/tesm/dhcp-options
|
|
|
|
|
|
|
|
RemainAfterExit=no
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
|
|
|
|
WantedBy=multi-user.target
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PFAD_EINHEIT = """[Unit]
|
|
|
|
|
|
|
|
Description=TESM -- wacht ueber die DHCP-Lease
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Path]
|
|
|
|
|
|
|
|
PathModified=/run/systemd/netif/leases
|
|
|
|
|
|
|
|
Unit=tesm-dhcp-options.service
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Install]
|
|
|
|
|
|
|
|
WantedBy=multi-user.target
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
#: Ersetzt den eigenen Block in einer Datei, die dem Client gehoert.
|
|
|
|
#: Ersetzt den eigenen Block in einer Datei, die dem Client gehoert.
|
|
|
@@ -902,12 +975,55 @@ def client_konfiguration(conn: sqlite3.Connection, stil: str) -> dict[str, Any]:
|
|
|
|
"pfad": pfad,
|
|
|
|
"pfad": pfad,
|
|
|
|
"inhalt": inhalt,
|
|
|
|
"inhalt": inhalt,
|
|
|
|
"nachher": nachher,
|
|
|
|
"nachher": nachher,
|
|
|
|
"skript": _uebernahme_skript(stil, inhalt),
|
|
|
|
"skript": _uebernahme_skript(stil, inhalt, optionen),
|
|
|
|
|
|
|
|
"auslesen": _auslesen(stil, optionen),
|
|
|
|
"optionen": optionen,
|
|
|
|
"optionen": optionen,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _uebernahme_skript(stil: str, inhalt: str) -> str:
|
|
|
|
def _auslesen(stil: str, benannt: list[dict[str, Any]]) -> dict[str, str]:
|
|
|
|
|
|
|
|
"""Wie der Wert auf dem Client wieder herauskommt.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Gehoert dazu, weil "angekommen" sonst niemand pruefen kann -- und weil ein
|
|
|
|
|
|
|
|
RMM-Agent genau diese Zeile braucht.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Zwei Wege bei systemd-networkd, und das hat einen Grund: in der Lease
|
|
|
|
|
|
|
|
steht der Wert **hexkodiert unter seiner Nummer**. Im DHCP-Paket reisen
|
|
|
|
|
|
|
|
nur Code, Laenge und Bytes; dass 225 "url" heisst und Text enthaelt, weiss
|
|
|
|
|
|
|
|
allein der Katalog dieses Servers. Deshalb legt der SSH-Push einen kleinen
|
|
|
|
|
|
|
|
Uebersetzer mit, der nach jeder Lease ``/run/tesm-dhcp-options.env``
|
|
|
|
|
|
|
|
schreibt -- "name=wert", lesbar. ``roh`` bleibt fuer den Fall, dass nur
|
|
|
|
|
|
|
|
die Datei von Hand kopiert wurde.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not benannt:
|
|
|
|
|
|
|
|
return {}
|
|
|
|
|
|
|
|
code = int(benannt[0]["code"])
|
|
|
|
|
|
|
|
name = str(benannt[0]["name"])
|
|
|
|
|
|
|
|
if stil == "networkd":
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
"einfach": f"grep '^{name}=' /run/tesm-dhcp-options.env",
|
|
|
|
|
|
|
|
"roh": (
|
|
|
|
|
|
|
|
"lease=/run/systemd/netif/leases/$(cat /sys/class/net/$IF/ifindex); "
|
|
|
|
|
|
|
|
f"/usr/bin/printf \"$(sed -n 's/^OPTION_{code}=//p' \"$lease\" "
|
|
|
|
|
|
|
|
"| sed 's/../@BS@x&/g')\""
|
|
|
|
|
|
|
|
).replace("@BS@", "\\" * 2),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if stil == "dhcpcd":
|
|
|
|
|
|
|
|
# dhcpcd kennt den Namen, weil 'define' ihn ihm beigebracht hat.
|
|
|
|
|
|
|
|
return {"einfach": f"dhcpcd -U $IF | grep -i '^{name}='", "roh": ""}
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
"einfach": f"grep -i 'option {name}' /var/lib/dhcp/dhclient.leases | tail -n1",
|
|
|
|
|
|
|
|
"roh": "",
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _b64(text: str) -> str:
|
|
|
|
|
|
|
|
import base64
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return base64.b64encode(text.encode("utf-8")).decode("ascii")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _uebernahme_skript(stil: str, inhalt: str, benannt: list[dict[str, Any]] | None = None) -> str:
|
|
|
|
"""Das Skript, das die Konfiguration auf dem Client eintraegt.
|
|
|
|
"""Das Skript, das die Konfiguration auf dem Client eintraegt.
|
|
|
|
|
|
|
|
|
|
|
|
Zwei Dinge macht es anders als ein blosses ``tee``, und beide sind mit
|
|
|
|
Zwei Dinge macht es anders als ein blosses ``tee``, und beide sind mit
|
|
|
@@ -925,12 +1041,18 @@ def _uebernahme_skript(stil: str, inhalt: str) -> str:
|
|
|
|
Der Inhalt reist base64-kodiert und als **Argument**, nicht ueber stdin:
|
|
|
|
Der Inhalt reist base64-kodiert und als **Argument**, nicht ueber stdin:
|
|
|
|
dort steht bei einem Client mit Passwort das Kennwort fuer ``sudo``.
|
|
|
|
dort steht bei einem Client mit Passwort das Kennwort fuer ``sudo``.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
import base64
|
|
|
|
fracht = _b64(inhalt)
|
|
|
|
|
|
|
|
benannt = benannt or []
|
|
|
|
fracht = base64.b64encode(inhalt.encode("utf-8")).decode("ascii")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if stil == "networkd":
|
|
|
|
if stil == "networkd":
|
|
|
|
return NETWORKD_SKRIPT.replace("@FRACHT@", fracht)
|
|
|
|
paare = " ".join(f"{eintrag['code']}:{eintrag['name']}" for eintrag in benannt)
|
|
|
|
|
|
|
|
uebersetzer = UEBERSETZER.replace("@PAARE@", paare).replace("@BS@", "\\\\") # sed gibt aus zwei Zeichen eines aus
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
NETWORKD_SKRIPT.replace("@FRACHT@", fracht)
|
|
|
|
|
|
|
|
.replace("@UEBERSETZER@", _b64(uebersetzer))
|
|
|
|
|
|
|
|
.replace("@DIENST@", _b64(DIENST_EINHEIT))
|
|
|
|
|
|
|
|
.replace("@PFADEINHEIT@", _b64(PFAD_EINHEIT))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
ziel = "/etc/dhcpcd.conf" if stil == "dhcpcd" else "/etc/dhcp/dhclient.conf"
|
|
|
|
ziel = "/etc/dhcpcd.conf" if stil == "dhcpcd" else "/etc/dhcp/dhclient.conf"
|
|
|
|
dienst = (
|
|
|
|
dienst = (
|
|
|
|