Werkzeuge waren zu umstaendlich, um sie beim Kunden wirklich zu benutzen: die Produktivdaten zeigen 19 Protokolle, aber nur 26 Messungen, fast durchweg ein einzelner IP-Scan. Der Standardfall "IP-Scan im aktuellen Netz" kostete drei Tipper, obwohl das einzige Feld ausdruecklich leer bleiben darf. - Kurzer Tap auf eine Werkzeugkarte startet sofort, langes Halten oeffnet die Optionen. Auf den betroffenen Karten steht "Tippen startet · Halten fuer Optionen" - sonst ist das Verhalten unsichtbar und der erste versehentliche Scan ueberrascht. - quickRun wird je Werkzeug AUSDRUECKLICH gesetzt, nicht hergeleitet: ToolParamField kennt kein 'required', die Pflicht steht allein im run()-Rumpf. portscan.ports hat keinen Vorgabewert und ist optional, iperf.host hat ebenfalls keinen und ist Pflicht - eine Heuristik ueber "hat Default" wuerde genau falsch herum raten. iperf bleibt deshalb bewusst ohne Schnellstart. - Der Lauf bleibt zwingend im ToolDialog: dort sitzen Bildschirmsperre, Fortschritt mit Abbrechen und die EINZIGE Fehlerbehandlung eines Werkzeuglaufs (runTool selbst hat kein try/catch). Ein Schnellstart daran vorbei wuerde Fehler verschlucken. - Die Vorschau wird nicht uebersprungen, sondern nur ohne Warnung automatisch durchgewunken. Der IP-Scan warnt ab ~1000 Adressen - genau der Fall, in dem ein versehentlicher Tap sonst minutenlang das falsche Netz absucht. - Langdruck bricht ab, sobald der Finger mehr als 10 px wandert: das Werkzeug-Raster liegt in einem Scroll-Bereich, sonst oeffnet jeder Wisch nach einer halben Sekunde den Dialog. - Nach einer Messung wird zum Ergebnis gescrollt und es 2,5 s hervorgehoben. Bei 46 Geraeten liegt die neue Karte sonst dutzende Bildschirme entfernt. block:'center', weil die feste Aktionsleiste den unteren Rand verdeckt; bei einer Geraete-Messung wird die Geraetekarte angesteuert, denn dort hinein wird gerendert. - Verwendete Parameter stehen in der Messkarte. Seit dem Schnellstart laeuft eine Messung auch ohne Dialog - dann ist das der einzige Ort, an dem man sieht, WOMIT gemessen wurde. Beschriftung aus tool.params, nicht aus der Ergebnistabelle: 'count' heisst dort "Gefundene Geraete", als Ping-Parameter aber "Anzahl Pakete". - Zuletzt benutzte Parameter werden gemerkt (neues Modul toolparams.ts). Ortsgebundene Schluessel wie 'subnet' ausdruecklich NICHT: ein aus dem vorigen Kundennetz uebernommener Netzbereich waere schlimmer als gar keiner, der Schnellstart wuerde stillschweigend das falsche Netz scannen. Im Emulator geprueft, und dabei zwei Fehler gefunden, die im Code nicht auffielen: die Parameterzeile wiederholte "Ziel: 8.8.8.8" direkt ueber dem Ergebnis (jetzt werden Werte ausgelassen, die das Ergebnis ohnehin nennt), und Traceroute schrieb "1 Hops" ins Kundendokument (jetzt "1 Station").
92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
/**
|
|
* Tool: IP-Konflikt-Prüfung — findet IP-Adressen, die von zwei Geräten
|
|
* gleichzeitig benutzt werden und so das Netz durcheinanderbringen.
|
|
*
|
|
* Verfahren ohne Root: Das Subnetz wird über mehrere Runden angepingt und
|
|
* jeweils die ARP-Tabelle ausgelesen. Tauchen für eine IP mehrere MAC-Adressen
|
|
* auf, nutzen mehrere Geräte dieselbe Adresse — ein Konflikt.
|
|
*/
|
|
|
|
import { scanner } from '../../scanner';
|
|
import type { MeasureStatus, Tool } from '../types';
|
|
|
|
export const ipConflictTool: Tool = {
|
|
id: 'ipconflict',
|
|
category: 'netzwerk',
|
|
name: 'IP-Konflikt',
|
|
icon: 'alert-triangle',
|
|
description: 'Findet IP-Adressen, die zwei Geräte gleichzeitig benutzen.',
|
|
scope: 'protocol',
|
|
// Netzbereich optional, Runden haben einen Vorgabewert
|
|
quickRun: true,
|
|
params: [
|
|
{
|
|
key: 'subnet',
|
|
label: 'Netzbereich (CIDR) — leer = aktiver Adapter',
|
|
type: 'text',
|
|
placeholder: 'leer lassen → automatisch über WLAN/LAN',
|
|
},
|
|
{
|
|
key: 'rounds',
|
|
label: 'Prüfrunden (mehr = zuverlässiger, dauert länger)',
|
|
type: 'number',
|
|
default: 4,
|
|
},
|
|
],
|
|
async run(ctx) {
|
|
// Netzbereich: Dialog → Protokoll → aktiver Adapter
|
|
let subnet =
|
|
String(ctx.params.subnet ?? '').trim() || String(ctx.protocol.subnet ?? '').trim();
|
|
if (!subnet) {
|
|
try {
|
|
subnet = String((await scanner.getLocalSubnet()).subnet ?? '').trim();
|
|
} catch {
|
|
/* unten abgefangen */
|
|
}
|
|
}
|
|
if (!subnet) {
|
|
return {
|
|
label: 'Kein Netzbereich — WLAN/LAN nicht aktiv?',
|
|
result: { error: 'Netzbereich konnte nicht ermittelt werden' },
|
|
measureStatus: 2,
|
|
};
|
|
}
|
|
|
|
const rounds = Number(ctx.params.rounds) || 4;
|
|
const res = await scanner.arpConflictScan({ subnet, rounds });
|
|
|
|
// ARP-Tabelle nicht lesbar → ehrliche Rückmeldung statt falscher Entwarnung
|
|
if (!res.arpAvailable) {
|
|
return {
|
|
label: 'ARP-Tabelle nicht lesbar — Konfliktprüfung nicht möglich',
|
|
result: {
|
|
subnet,
|
|
hinweis:
|
|
'Android gibt /proc/net/arp auf diesem Gerät nicht frei. Eine ' +
|
|
'zuverlässige IP-Konflikt-Erkennung ist ohne Root hier leider nicht möglich.',
|
|
},
|
|
measureStatus: 1,
|
|
};
|
|
}
|
|
|
|
const n = res.conflicts.length;
|
|
const status: MeasureStatus = n > 0 ? 2 : 0;
|
|
return {
|
|
label:
|
|
n > 0
|
|
? `${n} IP-Konflikt${n > 1 ? 'e' : ''} gefunden!`
|
|
: `Kein Konflikt — ${res.checked} Adressen geprüft`,
|
|
result: {
|
|
subnet,
|
|
geprueft: res.checked,
|
|
runden: res.rounds,
|
|
konflikte: res.conflicts.map((c) => `${c.ip} → ${c.macs.join(' / ')}`),
|
|
hinweis:
|
|
n > 0
|
|
? 'Mehrere MAC-Adressen pro IP — diese Geräte stören sich gegenseitig.'
|
|
: 'Jede gefundene IP wird von genau einem Gerät benutzt.',
|
|
},
|
|
measureStatus: status,
|
|
};
|
|
},
|
|
};
|