Files

271 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Bintec W20XXax-Firmware in QEMU (Docker) Emulations- und Analyse-Umgebung
Die AP-Firmware (Bintec W2022ax / W2044ax, "Wanda Wave 2") laeuft **nicht** direkt
in QEMU: Sie ist fuer einen Qualcomm IPQ60xx-SoC ("kaio") gebaut, und QEMU hat
dafuer **kein Maschinenmodell**. Der Weg der Emulation ist daher:
> Firmware auseinandernehmen -> RootFS extrahieren -> RootFS mit generischem
> Debian-arm64-Kernel in `qemu-system-aarch64 -M virt` booten -> Webinterface + CLI beobachten
Das gesamte Setup laeuft unprivilegiert in Docker (TCG-Emulation, kein KVM,
keine Root-Rechte auf dem Host noetig). Alles liegt in diesem Ordner
(`qemu-fw-docker/`), der Host bleibt unveraendert.
## Ergebnis
```
root@osdx:/# uname -a
Linux osdx 6.1.0-50-arm64 #1 SMP Debian 6.1.176-1 aarch64 GNU/Linux
```
- Das OSDx-System bootet bis zur interaktiven **Root-Shell** auf der Serial-Console
- Das originale **Webinterface** antwortet (Login-Seite "bintec Wanda Wave 2",
XML/XSL-GUI ueber esi.cgi) auf Port 80 und 443
- SSH ist erreichbar (Port 22 in der VM)
- `poweroff`/`reboot` in der VM funktionieren sauber (Reboot-Loop ist entschaeft)
## Schnellstart (VM + Webinterface)
```bash
cd qemu-fw-docker
docker build -t bintec-fw . # einmalig
./start-vm.sh # VM als Container "bintec-vm" starten
```
Nach ~2-3 Minuten Boot:
| Zugang | Adresse | Anmerkung |
|---------------------|--------------------------------|-------------------------------|
| Webinterface HTTP | http://localhost:8080 | |
| Webinterface HTTPS | https://localhost:8443 | self-signed Zertifikat |
| SSH | ssh -p 2222 localhost | root/leer bzw. admin |
| Serial (lesend) | docker logs -f bintec-vm | |
| Serial (interaktiv) | docker attach bintec-vm | abkoppeln: Strg+P dann Strg+Q |
| Stoppen | docker stop bintec-vm && docker rm bintec-vm | |
Serial-Login: die VM startet direkt in eine Root-Shell auf ttyAMA0
(keine Anmeldung noetig).
## Von der Firmware zum lauffaehigen System (kompletter Ablauf)
### Schritt 0: Firmware-Paket besorgen
Es gibt zwei Paketformen (beide von Bintec/Teldat, Inhalt identisch):
| Paket | Inhalt | Aufbereitung |
|-------|--------|--------------|
| `WiFi6_System_Software_vX.Y.Z.img` | Full-Flash-Image, direkt verwendbar | kopieren nach `firmware/` |
| `OSDx_dist_W20XXax_vX.Y.Z.tgz` | Tar-Archiv mit `full_kaio_vX.Y.Z.img` + `README.txt` + `version_map.txt` | entpacken, .img nach `firmware/` |
Falls das Paket als Tar kommt:
```bash
tar xzf OSDx_dist_W20XXax_v3.6.1.2.tgz
# -> full_kaio_v3.6.1.2.img (identisch zur .img-Variante)
mkdir -p firmware && cp full_kaio_v3.6.1.2.img firmware/
```
Die `version_map.txt` im Archiv sagt, welche img-Datei zu welchem AP-Modell
gehoert (W2022ax / W2044ax / APR2044ax verwenden alle dasselbe `full_kaio`-Image).
### Schritt 1: Container-Image bauen (einmalig)
```bash
cd qemu-fw-docker
docker build -t bintec-fw .
```
### Schritt 2: Firmware zerlegen (Phase 2)
```bash
docker run --rm \
-v "$PWD:/build" \
-v "$PWD/firmware:/input:ro" \
bintec-fw /build/extract.sh /input/<name-der>.img
```
Was passiert:
1. `carve.py` sucht das SquashFS (versionsunabhaengig per Magic + Plausibilitaets-
pruefung, uebernimmt aber den bekannten Offset von v3.6.1.2 als Direkttreffer)
und schneidet es aus: `work/rootfs.squashfs`
2. Das FIT-Image (ARM64-Kernel gzip + Device-Trees) wird als FDT geparst:
`work/kernel.img` (bootfaehig), `work/kernel.raw`, `work/<modell>.dtb`
3. `unsquashfs` -> `work/rootfs/` (Debian-Userspace)
4. Inventur nach `logs/inventory.txt` (OS-Version, Dienste, GUI-Pfade, Module)
### Schritt 3: Boot-Artefakte bauen (Phase 4a)
```bash
docker run --rm -v "$PWD:/build" bintec-fw /build/build-generic.sh
```
- laedt Debian-arm64-Kernel (`linux-image-*-arm64`, bookworm) + arm64-busybox
- baut Mini-Initramfs (virtio/ext4/crc32c-Module + switch_root)
- kopiert RootFS nach `work/rootfs-generic/`, legt alle Emulations-Anpassungen
an (siehe Tabelle unten) und verpackt alles nach `work/rootfs.ext4`
- Schritte 2+3 sind idempotent und duerfen wiederholt werden
### Schritt 4: Booten
```bash
./start-vm.sh # Dauerbetrieb + Webinterface
# oder mit Log-Tail:
docker run --rm -v "$PWD:/build" bintec-fw /build/boot-generic.sh
```
### Andere Firmware-Versionen emulieren
- `carve.py` ist generisch gehalten: SquashFS wird ueber Magic+Superblock-
Pruefung gesucht, das FIT ueber `kernel@1` + beliebiges `fdt@*`-Node
(bevorzugt w2044ax). Getestet gegen v3.6.1.1 und v3.6.1.2 (`archive_.../`).
- Ablauf fuer eine neue Version: img in `firmware/` legen, Schritte 2-4 wiederholen.
`work/` vorher optional leeren (`rm -rf work/rootfs* work/kernel* work/fit.img`).
- Achtung: `work/rootfs.ext4` ist versionsspezifisch nach dem Wechsel auf
jeden Fall Schritt 3 neu ausfuehren.
- Falls eine kuenftige Version eine andere FIT-Struktur nutzt, verraten das
`logs/carve.log` (Kandidaten + Metadaten) und `binwalk firmware/<img>`.
## Ordnerinhalt
```
qemu-fw-docker/
├── firmware/
│ └── WiFi6_System_Software_v3.6.1.2.img Original-Firmware (143 MB, md5 bb4c065e...)
├── Dockerfile Container: Debian bookworm-slim + QEMU/Tools
├── carve.py Firmware-Carver: SquashFS + FIT (Kernel/DTB) extrahieren
├── extract.sh Phase 2: Firmware zerlegen + Inventur (erwartet /input/*.img)
├── build-generic.sh Phase 4: Debian-Kernel laden, RootFS aufbereiten, ext4+Initramfs bauen
├── boot-native.sh Versuch 1: Original-QSDK-Kernel in -M virt (erwartungsgemaess stumm)
├── boot-generic.sh Versuch 2 mit Logging (Timeout 420 s)
├── boot-interactive.sh Interaktiver Dauerbetrieb (Serial -> docker logs/attach)
├── test-web.sh Automatischer Webinterface-Test (QEMU im Hintergrund + wget)
├── start-vm.sh Bequemer Start (Container "bintec-vm", Ports published)
├── PLAN.md Urspruenglicher Plan
├── README.md Diese Datei
├── logs/ Alle Logfiles (carve, inventory, boot-*, webtest)
└── work/ Arbeitsartefakte (RootFS, Kernel, ext4-Image, ~2 GB)
├── rootfs/ entpacktes Original-RootFS (556 MB, read-only Basis)
├── rootfs.squashfs geschnitztes SquashFS aus der Firmware
├── kernel.img Original-QSDK-Kernel 4.4.60 (ARM64, dekomprimiert)
├── kernel.raw Original-Kernel gzip-Blob
├── w2044ax.dtb Device-Tree W2044ax (aus dem FIT)
├── fit.img komplettes FIT-Image
├── initramfs.img Mini-Initramfs (busybox + virtio/ext4-Module)
├── rootfs-generic/ aufbereitete RootFS-Kopie (siehe Aenderungen unten)
├── rootfs.ext4 das gebootete Root-Dateisystem (1,5 GB sparse)
└── deb-kernel/ Debian bookworm arm64-Kernel (6.1.0-50-arm64) + busybox
```
## Repo vs. lokal generierte Daten (firmware/ und work/)
Beide Ordner sind absichtlich **nicht** Teil des Repos (`.gitignore`):
- `firmware/` die Firmware ist proprietär (Bintec/Teldat). Bitte selbst
herunterladen (Schritt 0 oben) und das .img dort ablegen.
- `work/` wird **komplett generiert**, es gibt keine manuellen Dateien:
`extract.sh` (Schritt 2) erzeugt `work/rootfs/` aus dem Firmware-Image,
`build-generic.sh` (Schritt 3) baut daraus Kernel, Initramfs und
`rootfs.ext4` inkl. aller Emulations-Anpassungen (Tabelle unten).
Zum Nachbauen einfach die Schritte 1-4 der Schnellstart-Anleitung ausführen.
## Firmware-Layout (WiFi6_System_Software_v3.6.1.2.img)
Full-Flash-Dump "full.img", Plattform `kaio` (IPQ60xx), U-Boot 11.4-1-2016.01:
| Offset | Groesse | Inhalt |
|------------|-----------|------------------------------------------------------------------------|
| 0x00000000 | ~21 MB | Container-Header, u-boot.sbl.img, SBL1 (mit Qualcomm-Attestation) |
| 0x1503930 | 3,95 MB | FIT "ARM64 OpenWrt FIT": kernel@1 (Linux **4.4.60 QSDK**, gzip, load/entry 0x41080000), fdt@w2022ax, fdt@w2044ax, configs fuer beide AP-Varianten |
| 0x18c7854 | 117 MB | SquashFS v4 (xz) = RootFS |
RootFS-Inventur (Details: `logs/inventory.txt`):
- **Debian 10 (buster)**, arm64, glibc 2.28, init = systemd
- OSDx-Stack: `/etc/osdx`, `/opt/vyatta` (Vyatta/VyOS-CLI-Framework), `/opt/qsdk`
- Dienste: FRR (BGP/OSPF), SNMP, SSH, dnsmasq, radvd, PPP, python3.7
- Web-GUI: `/usr/sbin/gui` ("Bintec Elmeg VyOS GUI", boost.asio), gestartet
ueber `bevyosgui.service`, aktiviert durch die Factory-Config-Zeile `set service gui`
- GUI-Inhalte: `/usr/share/gui/` (XML/XSL-Ajax-GUI mit Telekom/Bintec-Branding)
- Login: Factory-User `admin` (Config-Zeile in `/opt/vyatta/etc/config-default.boot.default`)
- Kernelpakete: `/lib/modules/4.4.60` (QSDK)
## Pipeline im Detail (Technische Hintergruende)
### Phase 2 Firmware extrahieren (`extract.sh` + `carve.py`)
- `carve.py` liest die .img, findet per Superblock das SquashFS (Offset
0x18c7854 bei v3.6.1.x) und schneidet es exakt aus (`bytes_used`).
- Das FIT (bei 0x1503930, endet exakt am SquashFS-Start) wird als FDT geparst;
herauskommen `kernel.raw` (gzip), `kernel.img` (ARM64-Image, Magic "ARMd"
bei Offset 0x38), `<modell>.dtb`.
- Danach `unsquashfs` -> `work/rootfs/`, Inventur -> `logs/inventory.txt`.
Hinweis: das FIT-Struct-Block endet ohne FDT_END-Token (Generator-Besonderheit);
`carve.py` behandelt das toleriert.
### Phase 4a Kernel beschaffen + RootFS aufbereiten (`build-generic.sh`)
- Lautet den Debian-Package-Index (bookworm, arm64) und laedt
`linux-image-6.1.0-50-arm64` (aus linux-signed-arm64) + `busybox-static` (arm64).
- Config-Check: Debian-Kernel hat PL011-Konsole =y, aber EXT4/VIRTIO_BLK/VIRTIO_PCI
=m -> deshalb **Mini-Initramfs** (busybox + `modprobe virtio_pci virtio_blk
virtio_net crc32c ext4` + switch_root).
- Die Kernel-.deb enthaelt keine modules.dep -> `depmod -b` wird ausgefuehrt.
- RootFS wird kopiert (`rootfs-generic`), Kernel-Module fuer 6.1 hinzugefuegt
und mit `mkfs.ext4 -d` nach `rootfs.ext4` (1,5 GB sparse) verpackt.
### Phase 4b Booten (`boot-generic.sh` / `boot-interactive.sh` / `start-vm.sh`)
```
qemu-system-aarch64 -M virt -cpu cortex-a53 -m 1024 -smp 1 \
-kernel vmlinuz-6.1.0-50-arm64 -initrd initramfs.img \
-drive if=virtio,format=raw,file=rootfs.ext4 \
-netdev user,id=n0,hostfwd=...:2222-:22,hostfwd=...:8080-:80,hostfwd=...:8443-:443 \
-device virtio-net-pci,netdev=n0 -no-reboot -nographic \
-append "root=/dev/vda rw console=ttyAMA0,115200"
```
## Aenderungen im RootFS (nur in der Kopie rootfs-generic/rootfs.ext4)
Grund: OSDx erwartet die echte AP-Hardware (QCA-WLAN, Flash-Environment "0x0",
LEDs, Watchdog durch cfgd). Ohne Hardware haelt sich das System nicht oben
folgende Stellschrauben machen den Boot stabil und die Shell erreichbar:
| Eingriff (per systemd-Drop-In / Symlink) | Wirkung |
|------------------------------------------|---------|
| `serial-getty@ttyAMA0.service.d/autologin.conf` | Direkte Root-Shell auf ttyAMA0 (OSDx-PAM lehnt Autologin/leeres PW ab) |
| `vyos-cfgd.service.d/emulation.conf`: `WatchdogSec=0`, `TimeoutSec=0`, `StartLimitBurst=0` | Ohne echte HW sendet cfgd keine Watchdog-Pings -> sonst `StartLimitAction=reboot-force` bei ~200 s |
| `qca-osdx-mon.service` -> /dev/null (maskiert) | QCA-WLAN-Monitor braucht echte Hardware |
| `osdx-modulelauncher.service.d/…`: `TimeoutSec=0` | Timeout entschaeft |
| `systemd-reboot.service` -> /dev/null (maskiert) | `osdx-load-config` ruft bei Config-Fehlern `reboot` auf -> wird jetzt nur mit Fehler abgewiesen |
| `qemu-net.service` | Netz-Bringup: 10.0.2.15/24 auf eth0/br0, Default-Route ueber 10.0.2.2 (QEMU-Usernet) |
| `multi-user.target.wants/bevyosgui.service` | Web-GUI aktiviert |
| `/etc/shadow`: root-Passwort geleert | Fallback-Anmeldung |
| Debian-Module 6.1.0-50-arm64 nach `/lib/modules/` | RootFS brachte nur QSDK-4.4.60-Module mit |
## Logs
| Datei | Inhalt |
|-------|--------|
| `logs/carve.log` | Extraktion (Offsets, FIT-Metadaten) |
| `logs/inventory.txt` | RootFS-Inventur |
| `logs/kernel-config.txt` | Debian-Kernel-Config-Auszug |
| `logs/unsquashfs.log` | Entpacken |
| `logs/boot-native.log` | Versuch 1: Original-QSDK-Kernel 60 s komplett stumm (Crash vor jeder Konsolenausgabe, erwartbar: kein IPQ60xx-Modell) |
| `logs/boot-generic.log` | Versuch 2: vollstaendiger Boot bis `root@osdx:/#` |
| `logs/boot-interactive.log` | Interaktivitaets-Nachweis (uname, ip link, /opt/vyatta, sauberes poweroff) |
| `logs/boot-webtest.log` | Webinterface-Test |
## Bekannte Einschraenkungen
- QEMU `virt` emuliert kein IPQ60xx: kein WiFi, keine Switch-/LED-/NAND-HW.
Im Log normal: "Cannot open 0x0", "environment not initialized",
LED-/qca-**-Service-Fehler.
- OSDx-Config-Loader laeuft mit "factory configuration for default" ab
(echte Configs liegen im Flash-Environment, das emuliert nicht existiert).
- Versuch 1 (Original-QSDK-Kernel) bootet nicht dokumentiert in
`logs/boot-native.log`.
- TCG-Emulation: Boot ~2-3 min, laeuft danach stabil.
- GUI-Session-Login laeuft ueber vyos-cfgd; falls der Browser-Login mit
admin/Factory-Passwort scheitert, Serial-Shell nutzen (docker attach).