Quelltext des aktuellen Standes
<?php $this->layout('layouts/admin', [
'page_title' => 'IPAM Remote-Scan-Agent',
'current_admin_page' => 'ipam-scan-agent',
'page_actions' => '<a href="/admin/ipam-scan-agent/download" class="btn btn-secondary"><i class="fas fa-server"></i> Linux-Script (.sh)</a> <a href="/admin/ipam-scan-agent/download-windows" class="btn btn-primary"><i class="fas fa-desktop"></i> Windows-Script (.ps1)</a>',
]); ?>
<style>
.isa-card { background:var(--color-bg); border:1px solid var(--gray-200); border-radius:6px; margin-bottom:20px; overflow:hidden; }
.isa-card-head { display:flex; align-items:center; gap:8px; padding:14px 20px; background:var(--color-gray-50);
border-bottom:1px solid var(--gray-200); font-weight:700; color:var(--color-primary-deep); font-size:0.95rem; }
.isa-card-body { padding:18px 20px; }
.isa-card-body p { color:var(--gray-700); line-height:1.65; margin:0 0 12px; }
.isa-steps { margin:0; padding-left:22px; line-height:1.9; color:var(--gray-700); }
.isa-steps li { margin-bottom:6px; }
code, .isa-code { font-family:monospace; background:var(--color-gray-100); border:1px solid var(--gray-200); border-radius:3px;
padding:1px 6px; font-size:0.85em; color:var(--gray-900); }
.isa-pre { display:block; background:var(--slate-900); color:var(--slate-200); padding:14px 16px; border-radius:6px;
font-family:monospace; font-size:0.82rem; overflow-x:auto; white-space:pre; margin:8px 0 0; line-height:1.55; }
.isa-pre .c { color:var(--sky-300); }
.isa-note { background:var(--amber-50); border:1px solid var(--amber-200); border-radius:6px; padding:12px 16px;
font-size:0.88rem; color:var(--amber-800); }
.isa-tag { display:inline-block; background:var(--sky-100); color:var(--sky-800); border:1px solid var(--sky-200);
border-radius:4px; padding:1px 8px; font-size:0.8rem; font-weight:600; }
.isa-method { display:flex; gap:14px; align-items:flex-start; padding:14px 0; border-bottom:1px solid var(--color-gray-100); }
.isa-method:last-child { border-bottom:none; }
.isa-method-num { flex:0 0 28px; height:28px; border-radius:50%; background:var(--color-primary-deep); color:var(--color-on-accent);
display:flex; align-items:center; justify-content:center; font-weight:700; font-size:0.85rem; }
.isa-method-body { flex:1; min-width:0; }
.isa-method-body h4 { margin:2px 0 6px; font-size:0.95rem; color:var(--gray-900); }
</style>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-link"></i> <?= $this->te('Asset-Verknüpfung') ?></div>
<div class="isa-card-body">
<p><?= $this->t('Beim Scan (Agent oder Modul-Scan) wird die MAC-Adresse erfasst, sofern das Gerät im selben Netzsegment erreichbar ist. Ist diese Option aktiv, sucht OpenNIT zu einer neu erfassten MAC automatisch ein passendes Inventar-Asset und verknüpft die IP-Adresse damit. Assets werden dabei <strong>nicht</strong> in IPAM angelegt – es wird nur verknüpft, wenn ein Asset existiert. Eine manuelle Auswahl in der IP-Adressmaske hat immer Vorrang.') ?></p>
<form method="POST" action="/admin/ipam-scan-agent/settings" style="display:flex;align-items:center;gap:10px;margin:0;">
<input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
<label class="toggle-label" style="display:flex;align-items:center;gap:8px;margin:0;cursor:pointer;">
<input type="checkbox" name="asset_autolink" value="1" <?= !empty($asset_autolink) ? 'checked' : '' ?>>
<span><?= $this->te('Assets automatisch per MAC verknüpfen') ?></span>
</label>
<button type="submit" class="btn btn-primary btn-sm"><?= $this->te('Speichern') ?></button>
</form>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-info-circle"></i> <?= $this->te('So funktioniert es') ?></div>
<div class="isa-card-body">
<p>
<?= $this->t('Der eingebaute IP-Scan läuft auf diesem Webserver. Steht dieser in der DMZ, erreicht er interne Netze oft nicht. Der <strong>Remote-Scan-Agent</strong> ist ein kleines Script, das du auf einem internen Server ablegst und zeitgesteuert ausführst – wahlweise unter <strong>Linux</strong> (Bash-Script per Cron) oder <strong>Windows</strong> (PowerShell-Script per Aufgabenplanung). Es ruft die zum Scannen freigegebenen Subnetze über die API ab, scannt sie per Ping und meldet die erreichbaren Hosts (inkl. Hostname & MAC, sofern ermittelbar) zurück ins IPAM.') ?>
</p>
<p style="margin-bottom:0;">
<?= $this->t('Welche Netze gescannt werden, steuerst du pro Subnetz im Subnetz-Formular über die Option <strong>„Dieses Subnetz scannen"</strong>. Der Agent fragt nur freigegebene Netze ab.') ?>
</p>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-key"></i> <?= $this->te('Schritt 1: API-Token erzeugen') ?></div>
<div class="isa-card-body">
<ol class="isa-steps">
<li><?= $this->te('Öffne') ?> <a href="/admin/api"><strong><?= $this->te('Admin → API') ?></strong></a>.</li>
<li><?= $this->t('Lege unter <em>„Neuen API-Token erstellen"</em> einen Token an und wähle als Berechtigung <span class="isa-tag">IPAM-Scan-Agent</span> aus (andere Haken kannst du entfernen).') ?></li>
<li><?= $this->t('Nach dem Erstellen wird der Token <strong>einmalig im Klartext angezeigt</strong> – kopiere ihn sofort. Er lässt sich später nicht erneut anzeigen.') ?></li>
</ol>
<div class="isa-note" style="margin-top:14px;">
<?= $this->t('Der Token ist auf den Scope <code>ipam_scan</code> begrenzt – er kann ausschließlich Subnetze lesen und Scan-Ergebnisse schreiben. Die Verbindung läuft zwingend über HTTPS.') ?>
</div>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-server"></i> <?= $this->te('Linux · Schritt 2: Script ablegen & Token hinterlegen') ?></div>
<div class="isa-card-body">
<p>
<?= $this->t('Lade das Script oben über <strong>„Scan-Script herunterladen"</strong> und kopiere es auf den internen Server, z. B. nach <code>/opt/opennit/ipam-scan-agent.sh</code>. Die Server-URL (<span class="isa-code">{url}</span>) ist bereits eingetragen. Den Token hinterlegst du auf eine von zwei Arten:', ['url' => $this->e($server_url)]) ?>
</p>
<div class="isa-method">
<div class="isa-method-num">A</div>
<div class="isa-method-body">
<h4><?= $this->te('Im Script eintragen (empfohlen)') ?></h4>
<p style="margin-bottom:8px;">
<?= $this->te('Öffne die Datei in einem Editor und suche im Konfigurationsblock die Zeile:') ?>
</p>
<span class="isa-pre">API_TOKEN="${OPENNIT_TOKEN:-}"</span>
<p style="margin:10px 0 8px;"><?= $this->te('Trage deinen Token zwischen die Anführungszeichen ein:') ?></p>
<span class="isa-pre">API_TOKEN="<span class="c"><?= $this->te('dein-kopierter-token') ?></span>"</span>
<p style="margin:10px 0 0;"><?= $this->te('Danach ausführbar machen und testen:') ?></p>
<span class="isa-pre">chmod +x /opt/opennit/ipam-scan-agent.sh
/opt/opennit/ipam-scan-agent.sh</span>
</div>
</div>
<div class="isa-method">
<div class="isa-method-num">B</div>
<div class="isa-method-body">
<h4><?= $this->te('Per Umgebungsvariable (Token nicht im Script)') ?></h4>
<p style="margin-bottom:8px;">
<?= $this->t('Das Script übernimmt den Token auch aus der Variable <code>OPENNIT_TOKEN</code>. So bleibt er aus der Datei heraus – praktisch z. B. direkt in der Crontab-Zeile:') ?>
</p>
<span class="isa-pre">*/30 * * * * OPENNIT_TOKEN="<span class="c"><?= $this->te('dein-token') ?></span>" /opt/opennit/ipam-scan-agent.sh >> /var/log/opennit-ipam-scan.log 2>&1</span>
</div>
</div>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-server"></i> <?= $this->te('Linux · Schritt 3: Per Cron automatisieren') ?></div>
<div class="isa-card-body">
<p><?= $this->te('Trage das Script in die Crontab des internen Servers ein (z. B. alle 30 Minuten):') ?></p>
<span class="isa-pre">*/30 * * * * /opt/opennit/ipam-scan-agent.sh >> /var/log/opennit-ipam-scan.log 2>&1</span>
<p style="margin:14px 0 0;">
<?= $this->t('<strong>Voraussetzungen</strong> auf dem internen Server: <code>bash</code>, <code>curl</code>, <code>ping</code> (iputils). Optional für mehr Details: <code>ip</code>/<code>arp</code> (MAC-Adressen) und <code>getent</code> (Hostnamen). Der Server muss die zu scannenden Netze erreichen.') ?>
</p>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-desktop"></i> <?= $this->te('Windows · Schritt 2: Script ablegen & Token hinterlegen') ?></div>
<div class="isa-card-body">
<p>
<?= $this->t('Lade oben das <strong>„Windows-Script (.ps1)"</strong> herunter und kopiere es auf den internen Windows-Server, z. B. nach <code>C:\\OpenNIT\\ipam-scan-agent.ps1</code>. Die Server-URL (<span class="isa-code">{url}</span>) ist bereits eingetragen. Den Token hinterlegst du auf eine von zwei Arten:', ['url' => $this->e($server_url)]) ?>
</p>
<div class="isa-method">
<div class="isa-method-num">A</div>
<div class="isa-method-body">
<h4><?= $this->te('Im Script eintragen (empfohlen)') ?></h4>
<p style="margin-bottom:8px;"><?= $this->t('Öffne die <code>.ps1</code> in einem Editor und suche die Zeile:') ?></p>
<span class="isa-pre">$ApiToken = ''</span>
<p style="margin:10px 0 8px;"><?= $this->te('Trage deinen Token zwischen die Anführungszeichen ein:') ?></p>
<span class="isa-pre">$ApiToken = '<span class="c"><?= $this->te('dein-kopierter-token') ?></span>'</span>
</div>
</div>
<div class="isa-method">
<div class="isa-method-num">B</div>
<div class="isa-method-body">
<h4><?= $this->te('Per Umgebungsvariable (Token nicht im Script)') ?></h4>
<p style="margin-bottom:8px;">
<?= $this->t('Das Script übernimmt den Token auch aus der Umgebungsvariable <code>OPENNIT_TOKEN</code>. Systemweit (für die Aufgabenplanung als Dienstkonto) setzt du sie z. B. so:') ?>
</p>
<span class="isa-pre">setx OPENNIT_TOKEN "<span class="c"><?= $this->te('dein-token') ?></span>" /M</span>
<p style="margin:10px 0 0;font-size:0.85rem;color:var(--gray-500);">
<?= $this->t('Hinweis: <code>setx /M</code> erfordert eine administrative PowerShell und wirkt erst in neuen Prozessen.') ?>
</p>
</div>
</div>
<p style="margin:14px 0 0;"><?= $this->te('Einmaliger Test in einer PowerShell (umgeht die Ausführungsrichtlinie nur für diesen Lauf):') ?></p>
<span class="isa-pre">powershell -NoProfile -ExecutionPolicy Bypass -File C:\OpenNIT\ipam-scan-agent.ps1</span>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-desktop"></i> <?= $this->te('Windows · Schritt 3: Per Aufgabenplanung automatisieren') ?></div>
<div class="isa-card-body">
<p>
<?= $this->t('Am schnellsten per Eingabeaufforderung/PowerShell <strong>als Administrator</strong> – legt eine alle 30 Minuten laufende Aufgabe an, die als <code>SYSTEM</code> ausgeführt wird und die Ausgabe protokolliert:') ?>
</p>
<span class="isa-pre">schtasks /Create /SC MINUTE /MO 30 /TN "OpenNIT IPAM Scan" /RU SYSTEM ^
/TR "powershell -NoProfile -ExecutionPolicy Bypass -File C:\OpenNIT\ipam-scan-agent.ps1 >> C:\OpenNIT\ipam-scan.log 2>&1"</span>
<p style="margin:16px 0 8px;"><?= $this->t('<strong>Alternativ über die grafische Aufgabenplanung</strong> (<code>taskschd.msc</code>):') ?></p>
<ol class="isa-steps">
<li><em><?= $this->te('Aufgabenplanung') ?></em> <?= $this->te('öffnen → rechts') ?> <strong><?= $this->te('„Aufgabe erstellen…"') ?></strong> <?= $this->te('(nicht „Einfache Aufgabe")') ?>.</li>
<li><?= $this->t('Reiter <strong>Allgemein</strong>: Name vergeben, <em>„Unabhängig von der Benutzeranmeldung ausführen"</em> und <em>„Mit höchsten Privilegien"</em> aktivieren; als Konto z. B. <code>SYSTEM</code> oder ein Dienstkonto, das die Zielnetze erreicht.') ?></li>
<li><?= $this->t('Reiter <strong>Trigger</strong> → <em>Neu…</em> → <em>„Nach einem Zeitplan / Täglich"</em>, dann <em>„Aufgabe wiederholen alle: 30 Minuten"</em>, Dauer <em>„Unbegrenzt"</em>.') ?></li>
<li><?= $this->te('Reiter') ?> <strong><?= $this->te('Aktionen') ?></strong> → <em><?= $this->te('Neu…') ?></em> <?= $this->t('→ Programm: <code>powershell.exe</code>,') ?>
<?= $this->te('Argumente:') ?>
<span class="isa-pre" style="margin-top:6px;">-NoProfile -ExecutionPolicy Bypass -File C:\OpenNIT\ipam-scan-agent.ps1</span>
</li>
<li><?= $this->t('Speichern. Über <em>„Ausführen"</em> einmal testen und im Reiter <em>Verlauf</em> bzw. in der Logdatei das Ergebnis prüfen.') ?></li>
</ol>
<p style="margin:14px 0 0;">
<?= $this->t('<strong>Voraussetzungen:</strong> Windows PowerShell 5.1 (vorinstalliert) oder PowerShell 7+. Es werden nur Bordmittel genutzt (keine Zusatzsoftware). Das Konto, unter dem die Aufgabe läuft, muss die zu scannenden Netze erreichen; eine eventuelle Firewall muss ausgehende Pings/TCP zulassen.') ?>
</p>
</div>
</div>
<div class="isa-card">
<div class="isa-card-head"><i class="fas fa-sliders-h"></i> <?= $this->te('Optionale Einstellungen') ?></div>
<div class="isa-card-body">
<p style="margin-bottom:10px;">
<?= $this->t('Alle Werte stehen im Konfigurationsblock oben im jeweiligen Script (Linux wie Windows) und lassen sich auch per Umgebungsvariable überschreiben (unter Windows z. B. via <code>setx … /M</code>):') ?>
</p>
<p style="margin:0 0 10px;font-size:0.88rem;color:var(--gray-700);">
<?= $this->t('<strong>Hinweis:</strong> Die ausführliche Erkennung (Port-Scan, Banner, TCP-Fallback, zufällige Reihenfolge) ist <strong>standardmäßig aktiv</strong>, um möglichst viele Daten zu erfassen. Für sehr große Netze oder einen besonders schnellen Lauf lässt sie sich gezielt abschalten.') ?>
</p>
<ul class="isa-steps" style="list-style:disc;">
<li><?= $this->t('<code>OPENNIT_SUBNET_IDS</code> – nur bestimmte Subnetz-IDs scannen (Komma-getrennt), leer = alle freigegebenen.') ?></li>
<li><?= $this->t('<code>OPENNIT_PARALLEL</code> – Anzahl gleichzeitiger Pings (Standard 48).') ?></li>
<li><?= $this->t('<code>OPENNIT_DETAIL_PARALLEL</code> – Anzahl gleichzeitig erhobener Hosts in der Detailphase (Linux, Standard 16). Bewusst niedriger als bei den Pings: Jeder Host öffnet während des Port-Scans so viele Verbindungen, wie Ports geprüft werden.') ?></li>
<li><?= $this->t('<code>OPENNIT_SUBNET_MAX_SECONDS</code> – Zeitbudget je Subnetz (Standard 900, <code>0</code> = unbegrenzt). Läuft es ab, werden die bis dahin erhobenen Hosts übertragen.') ?></li>
<li><?= $this->t('<code>OPENNIT_TOTAL_MAX_SECONDS</code> – Zeitbudget für den gesamten Lauf (Standard <code>0</code> = unbegrenzt). Übrige Subnetze kommen beim nächsten Lauf dran.') ?></li>
<li><?= $this->t('<code>OPENNIT_RDNS=0</code> – Rückwärtsauflösung der Hostnamen abschalten. In Netzen ohne PTR-Einträge ist sie der mit Abstand langsamste Schritt.') ?></li>
<li><?= $this->t('<code>OPENNIT_MAX_ONLINE_PCT</code> – Schwelle für die Plausibilitätsprüfung (Standard 90, <code>0</code> = aus), <code>OPENNIT_ALLOW_FULL_SUBNET=1</code> hebelt sie aus.') ?></li>
<li><?= $this->t('<code>OPENNIT_PROGRESS_EVERY</code> – Fortschrittszeile je N Hosts (Standard 50, <code>0</code> = aus).') ?></li>
<li><?= $this->t('<code>OPENNIT_PORTSCAN=0</code> – ausführlichen Port-Scan abschalten (nur Ping, deutlich schneller).') ?></li>
<li><?= $this->t('<code>OPENNIT_PORTS</code> – zu prüfende Ports (Komma-getrennt); Standard ist eine breite Liste gängiger Dienste.') ?></li>
<li><?= $this->t('<code>OPENNIT_BANNER=0</code> – Banner-Erkennung (HTTP-Server, Webseiten-Titel, SSH-Banner) abschalten.') ?></li>
<li><?= $this->t('<code>OPENNIT_TCP_PING=0</code> – TCP-Fallback abschalten (sonst werden auch Hosts erkannt, die Ping blockieren).') ?></li>
<li><?= $this->t('<code>OPENNIT_TCP_PING_PORTS</code> – Ports für den TCP-Fallback (Standard 80,443,445,22,3389,139,8080,8006).') ?></li>
<li><?= $this->t('<code>OPENNIT_SHUFFLE=0</code> – Scan-Reihenfolge nicht zufällig mischen (Standard: gemischt).') ?></li>
<li><?= $this->t('<code>OPENNIT_JITTER_MS</code> – zufällige Pause (0–N ms) je Probe, entzerrt die Last (Standard 0).') ?></li>
<li><?= $this->t('<code>OPENNIT_SNMP=0</code> / <code>OPENNIT_SNMP_COMMUNITY</code> – SNMP-Abfrage (Linux, nur bei offenem Port 161 und installiertem <code>snmpget</code>); Community Standard <code>public</code>.') ?></li>
<li><?= $this->t('<code>OPENNIT_MARK_OFFLINE=1</code> – zuvor aktive, jetzt nicht mehr erreichbare Hosts auf <em>offline</em> setzen.') ?></li>
<li><?= $this->t('<code>OPENNIT_MAX_HOSTS</code> – Obergrenze pro Subnetz (Standard 4096).') ?></li>
<li><?= $this->t('<code>OPENNIT_INSECURE=1</code> – TLS-Zertifikatsprüfung deaktivieren (nur für Self-Signed-Setups).') ?></li>
</ul>
<p style="margin:14px 0 0;font-size:0.88rem;color:var(--gray-700);">
<?= $this->t('<strong>Viele Subnetze automatisch scannen:</strong> Der Agent arbeitet die Subnetze nacheinander ab, erhebt die Details innerhalb eines Subnetzes aber parallel; am Ende steht eine Zusammenfassung je Subnetz im Protokoll. Eine Sperre verhindert, dass sich Läufe überholen – wird der Agent gestartet, während noch einer läuft, endet der neue Aufruf sofort und ohne Fehler. Mit den Zeitbudgets lässt sich ein Lauf so begrenzen, dass er zuverlässig vor dem nächsten Start fertig ist.') ?>
</p>
<p style="margin:10px 0 0;font-size:0.88rem;color:var(--gray-700);">
<?= $this->t('<strong>Plausibilitätsprüfung:</strong> Antworten fast alle Adressen eines Subnetzes (Standard: ab 90 %), stammt das in aller Regel von Proxy-ARP oder einem Gateway, das stellvertretend für den ganzen Bereich antwortet – die Adressen existieren dann gar nicht. Ein solches Ergebnis wird verworfen statt eingetragen, mit einem Hinweis im Protokoll. Ist das Netz wirklich so dicht belegt, hebt <code>OPENNIT_ALLOW_FULL_SUBNET=1</code> die Prüfung auf.') ?>
</p>
<p style="margin:10px 0 0;font-size:0.88rem;color:var(--gray-700);">
<?= $this->t('<strong>Erfasste Zusatzinfos im IPAM:</strong> Hostname (Reverse-DNS, NetBIOS, mDNS), MAC-Adresse, Antwortzeit, Erkennungsmethode (ICMP/TCP), OS-Vermutung (aus TTL), offene Ports samt Dienstnamen, HTTP-Server & Webseiten-Titel, SSH-Banner sowie – unter Linux mit <code>snmpget</code> – SNMP-Name und -Beschreibung. Daraus wird eine Gerätetyp-Vermutung abgeleitet (Server, Workstation, Drucker, Switch, Router, Access Point, Kamera, Telefon). Alles landet in den <em>Details</em> der jeweiligen IP; manuell gepflegte Kernfelder (Hostname/MAC) werden nicht überschrieben. Jede Änderung erscheint zudem im <em>Verlauf</em> der IP-Adresse.') ?>
</p>
<p style="margin:10px 0 0;font-size:0.88rem;color:var(--gray-700);">
<?= $this->t('<strong>Gateway-Vorschlag:</strong> Der Scan ermittelt pro Subnetz ein wahrscheinliches Gateway in gestufter Reihenfolge (erstes Ergebnis gewinnt): <strong>1. SNMP</strong> – ein erreichbarer Host, der laut SNMP routet (<code>ipForwarding</code>), ist das Gateway; <strong>2. direkt angeschlossen</strong> – steht der Agent selbst im Subnetz, wird sein Standard-Gateway genommen; <strong>3. Traceroute</strong> – letzter Hop einer Route, der noch im Subnetz liegt; <strong>4. Heuristik</strong> – <code>.1</code> bzw. letzte Host-Adresse (Notnagel). Der Vorschlag erscheint in der Subnetz-Detailansicht mit der Schaltfläche <em>„Übernehmen"</em>; ein bereits eingetragenes Gateway wird <strong>nie</strong> automatisch überschrieben. <br>Reihenfolge/Abschaltung über <code>OPENNIT_GW_DETECT</code> (z. B. <code>snmp,connected,traceroute</code> ohne Heuristik, oder <code>off</code> via leerer Liste). SNMP steht nur unter Linux zur Verfügung (Windows-PowerShell hat kein SNMP-Bordmittel); Traceroute benötigt unter Linux <code>traceroute</code>/<code>tracepath</code>, unter Windows die <code>tracert</code>-Bordmittel.') ?>
</p>
<p style="margin:12px 0 0;font-size:0.85rem;color:var(--gray-500);">
<?= $this->t('<strong>Mehr Daten unter Linux:</strong> zusätzlich <code>snmpget</code> (net-snmp), <code>nmblookup</code> (samba-common-bin) und <code>avahi-resolve-address</code> (avahi-utils) installieren. Unter Windows werden NetBIOS-Name und Arbeitsgruppe automatisch per <code>nbtstat</code> ermittelt.') ?>
</p>
</div>
</div>