The HID failure came down to the endpoint type map being indexed by endpoint number without the direction bit. A composite device can have endpoint 1 as both interrupt IN (0x81) and bulk OUT (0x01); the last one read won, so interrupt URBs were submitted as bulk and the kernel rejected them. The device attached and stayed silent. Endpoint data now comes from the raw descriptors read from /dev/bus/usb rather than sysfs, which only ever exposes the active alternate setting — a webcam's isochronous endpoints are invisible there because they only exist after SET_INTERFACE. Two sysfs parsing bugs fell out of that too: the numeric endpoint attributes are hex without a prefix (wMaxPacketSize "0040" was read as 40, not 64), and bInterval was never read at all. Reliability: three places could freeze the whole process. The share path fed io.Pipe from the WebSocket read loop, so one slow USB transfer stalled every tunnel and the keepalives with them. The relay wrote to client sockets while holding the hub lock, so one peer that stopped reading blocked routing and registration for everyone. Control transfers ran inline in the protocol loop behind a 5s timeout. Also fixed: a use-after- free where a discarded URB's memory could be collected while the kernel still owned it, a reap loop that spun at 100% CPU on ioctl errors, a missing attach timeout, a double close(done) panic, and Hash[:8] in the relay's log line, which let a client with a short hash take the server down. Adds mode "both", so one client can offer and consume devices at once. The tunnel and client-left callbacks became multicast for it: as plain fields the second manager to register silently unhooked the first. Tunnel traffic is now AES-256-GCM end to end, on the relay path as well as directly. The key is derived from the three tokens, not from the group hash — the relay is told the hash, so a key derived from it would protect nothing from the one party in the middle. Group IDs are unchanged, so existing setups keep working; only clients configured without the tokens drop to unencrypted, relay-only operation. Peers now try to connect directly, with the relay supplying the public address neither side can determine for itself. Candidates are raced because an unreachable address hangs until timeout rather than refusing. Falling back to the relay is not an error. Platform reach: cross-compiled targets for ARM, MIPS and RISC-V (the Linux client needed no code changes — usbdevfs is not architecture specific), multi-arch Docker images, an Android bridge that accepts devices over SCM_RIGHTS because apps cannot open /dev/bus/usb, and macOS builds via system_profiler enumeration. Adds a Windows KMDF filter driver under driver/windows with its Go side. UNTESTED: it has never been compiled or run, needs the WDK to build and an EV certificate to distribute. Treat it as a starting point. Adds "usb-client diag": says per machine whether sharing and using are possible, what stands in the way, and what fixes it. Reports can be uploaded to a relay to get them off machines that are awkward to copy from. 96 tests, all green under -race. Builds for linux, windows and darwin on amd64 and arm64. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
523 lines
18 KiB
Markdown
523 lines
18 KiB
Markdown
# USB Server
|
|
|
|
USB-Sharing ueber Netzwerk mit Relay-Server fuer NAT-Traversal.
|
|
|
|
## Architektur
|
|
|
|
```
|
|
┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐
|
|
│ Client (both) │──ws/wss─│ Relay Server │─ws/wss──│ Client (both) │
|
|
│ gibt Geraete │ │ (Docker) │ │ gibt Geraete │
|
|
│ frei UND │ │ gruppiert │ │ frei UND │
|
|
│ empfaengt sie │ │ nach Hash │ │ empfaengt sie │
|
|
│ Web-UI :8080 │ │ │ │ Web-UI :8080 │
|
|
└────────┬─────────┘ └──────────────┘ └────────┬─────────┘
|
|
│ │
|
|
Physische USB-Geraete Virtuelle USB-Geraete
|
|
(usbdevfs) (vhci-hcd)
|
|
```
|
|
|
|
**Relay-Server:** WebSocket-Vermittler. Braucht keine Konfiguration - verbindet alle Clients die den gleichen Hash haben. Als Docker-Container deploybar. Er vermittelt die Verbindungen und reicht Tunneldaten weiter, ohne das USB/IP-Protokoll zu interpretieren.
|
|
|
|
**Verbindungswege:** Nach der Vermittlung durch den Relay versuchen zwei
|
|
Clients, sich **direkt** zu verbinden. Klappt das - im gleichen LAN, ueber VPN,
|
|
bei oeffentlicher IP oder Portfreigabe - laeuft der USB-Verkehr an der Relay
|
|
vorbei. Das spart eine komplette Netzwerkstrecke, was bei USB/IP spuerbar ist:
|
|
jeder Transfer ist ein eigener Round-Trip, und die Latenz addiert sich auf.
|
|
Scheitert der Versuch (beide hinter NAT ohne Portfreigabe), laeuft alles
|
|
unveraendert weiter ueber den Relay.
|
|
|
|
**Verschluesselung:** Tunneldaten sind Ende-zu-Ende mit AES-256-GCM
|
|
verschluesselt, auf beiden Wegen. Der Schluessel wird aus den **drei Tokens**
|
|
abgeleitet, nicht aus dem Hash - der Relay bekommt nur den Hash und kann
|
|
daraus die Tokens nicht zurueckrechnen. Er sieht also weder USB-Daten noch
|
|
kann er sich als Peer ausgeben.
|
|
|
|
> **Was der Relay trotzdem sieht und kann:** Metadaten - wer in welcher Gruppe
|
|
> ist, welche Geraete angeboten werden, wann welches angefordert wird, und wie
|
|
> viel Verkehr fließt. Der Hash gruppiert, er authentifiziert nicht: wer ihn
|
|
> kennt, kann der Gruppe beitreten, Geraetelisten sehen und Geraete anfordern.
|
|
> Die Tunneldaten kann so jemand ohne die Tokens aber nicht lesen.
|
|
>
|
|
> **Clients ohne Tokens:** Wer nur den Hash konfiguriert hat, kann keine
|
|
> Schluessel ableiten. Solche Clients funktionieren weiter, aber unverschluesselt
|
|
> und ohne Direktverbindung - und ein Peer, der verschluesselt, lehnt sie ab.
|
|
> Die Web-UI zeigt im Kopf an, welcher Fall vorliegt. Abhilfe: die drei Tokens
|
|
> auf alle Clients kopieren (Token-Tab). Die Gruppen-ID aendert sich dadurch
|
|
> **nicht**, bestehende Setups bleiben also verbunden.
|
|
|
|
**Client:** Kann in drei Modi betrieben werden:
|
|
- **both:** Gibt lokale Geraete frei *und* verbindet sich mit fremden. Das ist der uebliche Fall in einer Gruppe, in der jede Maschine Hardware verleiht und ausleiht.
|
|
- **share:** Gibt nur lokale USB-Geraete frei. Geraete werden erst dann vom System getrennt wenn ein Use-Client sie anfordert.
|
|
- **use:** Empfaengt nur. Zeigt verfuegbare Geraete aller Share-Clients an, einzeln verbindbar/trennbar.
|
|
|
|
**Gruppierung:** 3 zufaellige Tokens werden zu einem SHA256-Hash kombiniert. Alle Clients mit dem gleichen Hash gehoeren zusammen.
|
|
|
|
## Quick Start
|
|
|
|
### 1. Relay-Server starten
|
|
|
|
```bash
|
|
# Mit Docker
|
|
docker compose up -d
|
|
|
|
# Oder direkt
|
|
make relay
|
|
./bin/usb-relay --port 8443
|
|
```
|
|
|
|
### 2. Tokens generieren
|
|
|
|
Auf dem ersten Client:
|
|
|
|
```bash
|
|
./bin/usb-client generate-token
|
|
```
|
|
|
|
Ausgabe:
|
|
```
|
|
Token 1: aB3dE...
|
|
Token 2: xY7zW...
|
|
Token 3: mN4pQ...
|
|
Hash: a1b2c3d4e5...
|
|
```
|
|
|
|
Die 3 Tokens auf alle weiteren Clients kopieren.
|
|
|
|
### 3. Clients starten
|
|
|
|
Auf jeder Maschine, die Geraete freigeben *und* empfangen soll:
|
|
|
|
```bash
|
|
sudo ./bin/usb-client both --relay ws://relay-server:8443
|
|
```
|
|
|
|
Root wird auf der Share-Seite gebraucht: das Oeffnen der Geraete unter
|
|
`/dev/bus/usb/`, das Loesen der Kernel-Treiber und das spaetere Zurueckbinden
|
|
laufen ueber privilegierte Schnittstellen.
|
|
|
|
Wer die Rollen trennen will, startet stattdessen nur eine Seite:
|
|
|
|
```bash
|
|
sudo ./bin/usb-client share --relay ws://relay-server:8443 # nur freigeben
|
|
sudo ./bin/usb-client use --relay ws://relay-server:8443 # nur empfangen
|
|
```
|
|
|
|
Web-UI oeffnen: http://localhost:8080
|
|
|
|
## Installation
|
|
|
|
### Go installieren
|
|
|
|
#### Linux (Debian/Ubuntu)
|
|
|
|
```bash
|
|
# Aktuelle Version herunterladen (go1.25.0 oder neuer)
|
|
wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz
|
|
|
|
# Altes Go entfernen und neues installieren
|
|
sudo rm -rf /usr/local/go
|
|
sudo tar -C /usr/local -xzf go1.25.0.linux-amd64.tar.gz
|
|
|
|
# PATH einrichten - ans Ende von ~/.bashrc oder ~/.profile anfuegen:
|
|
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
|
|
source ~/.bashrc
|
|
|
|
# Pruefen
|
|
go version
|
|
```
|
|
|
|
#### Windows
|
|
|
|
1. Installer herunterladen: https://go.dev/dl/ (Datei `go1.25.0.windows-amd64.msi`)
|
|
2. MSI-Installer ausfuehren - installiert Go nach `C:\Program Files\Go`
|
|
3. Der Installer richtet den PATH automatisch ein
|
|
4. Neue Eingabeaufforderung oeffnen und pruefen:
|
|
```cmd
|
|
go version
|
|
```
|
|
|
|
Falls der PATH nicht automatisch gesetzt wurde:
|
|
1. Windows-Taste > "Umgebungsvariablen" suchen > "Umgebungsvariablen fuer dieses Konto bearbeiten"
|
|
2. Variable `Path` bearbeiten > Neu > `C:\Program Files\Go\bin` hinzufuegen
|
|
3. Eingabeaufforderung neu oeffnen
|
|
|
|
### Make installieren
|
|
|
|
#### Linux (Debian/Ubuntu)
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt install make
|
|
```
|
|
|
|
#### Linux (Fedora/RHEL)
|
|
|
|
```bash
|
|
sudo dnf install make
|
|
```
|
|
|
|
#### Windows
|
|
|
|
**Option A: Chocolatey** (empfohlen)
|
|
```powershell
|
|
# Chocolatey installieren (Admin-PowerShell):
|
|
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
|
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
|
|
|
# Make installieren:
|
|
choco install make
|
|
```
|
|
|
|
**Option B: MSYS2**
|
|
1. MSYS2 von https://www.msys2.org herunterladen und installieren
|
|
2. In der MSYS2-Shell:
|
|
```bash
|
|
pacman -S make
|
|
```
|
|
3. `C:\msys64\usr\bin` zum Windows PATH hinzufuegen
|
|
|
|
**Option C: Ohne Make** - Go-Befehle direkt ausfuehren (siehe unten)
|
|
|
|
### Plattform-Unterstuetzung
|
|
|
|
| Funktion | Linux | Windows | Android | macOS |
|
|
|----------|-------|---------|---------|-------|
|
|
| Share-Modus | Ja | Ungetestet (eigener Treiber noetig, siehe unten) | Ja, ueber App-Bridge | Nein (braucht IOKit) |
|
|
| Use-Modus | Ja (vhci-hcd) | Ja (usbip-win2) | Nein (kein vhci-hcd) | Nein (braucht Treiber) |
|
|
| Kombinierter Modus (`both`) | Ja | Nein | Nein | Nein |
|
|
| Relay-Server | Ja | Ja | - | Ja |
|
|
| Web-UI / Config | Ja | Ja | - | Ja |
|
|
|
|
**Windows Share:** Der Code ist vorhanden (`driver/windows/` plus die
|
|
Go-Anbindung), aber der Filtertreiber wurde nie gebaut oder getestet. Er
|
|
braucht das WDK zum Bauen und ein EV-Zertifikat zum Verteilen. Details und
|
|
ehrliche Einordnung in [driver/windows/README.md](driver/windows/README.md).
|
|
|
|
**Android Share:** Das Go-Binary laeuft dort unveraendert, aber eine App darf
|
|
`/dev/bus/usb` nicht oeffnen. Eine kleine App holt deshalb die Berechtigung
|
|
ueber das Framework und reicht den Dateideskriptor an den Client durch — siehe
|
|
[android/README.md](android/README.md). Die Go-Seite dieser Bruecke ist fertig
|
|
und getestet, die App-Seite ist eine ungetestete Referenzimplementierung.
|
|
|
|
**Docker und USB:** Auf einem Linux-Host koennen Geraete in den Container
|
|
durchgereicht werden (`/dev/bus/usb` mounten, `privileged: true`). Auf macOS
|
|
und Windows geht das **nicht**: Docker laeuft dort in einer Linux-VM, die die
|
|
USB-Hardware des Hosts nie zu sehen bekommt. Container teilen sich den Kernel
|
|
des Hosts — auf Linux ist das derselbe Kernel, der die Geraete verwaltet, auf
|
|
den anderen Plattformen nicht.
|
|
|
|
### Architekturen
|
|
|
|
Der Linux-Client laeuft unveraendert auf jeder Architektur - usbdevfs und
|
|
vhci-hcd sind nicht architekturspezifisch. `make release` baut fuer alle:
|
|
|
|
| Ziel | Typische Geraete |
|
|
|------|------------------|
|
|
| linux/amd64 | normale PCs, Intel-basierte Synology |
|
|
| linux/arm64 | Raspberry Pi 3/4/5 (64-Bit-OS), ARM-Synology |
|
|
| linux/arm | Raspberry Pi mit 32-Bit-OS, aeltere ARM-Boards |
|
|
| linux/386 | alte 32-Bit-x86-Rechner |
|
|
| linux/mips64le, linux/mipsle | diverse NAS- und Router-Plattformen |
|
|
| linux/riscv64 | RISC-V-Boards |
|
|
| windows/amd64, windows/arm64 | Windows (nur Use-Modus) |
|
|
|
|
Voraussetzung bleibt in allen Faellen: Share braucht Zugriff auf
|
|
`/dev/bus/usb` (Root), Use braucht das Kernel-Modul `vhci-hcd`. Auf
|
|
NAS-Systemen mit eigenem Kernel ist `vhci-hcd` haeufig nicht vorhanden -
|
|
solche Geraete taugen dann als Share-Client, nicht als Use-Client.
|
|
|
|
**Windows Use-Modus:** Benoetigt den [usbip-win2](https://github.com/vadimgrn/usbip-win2/releases) VHCI-Treiber (WHKL-zertifiziert, Microsoft-signiert). Der Client erkennt automatisch ob usbip-win2 installiert ist.
|
|
|
|
**Windows Share-Modus:** Nicht verfuegbar - erfordert Linux-spezifische Kernel-Schnittstelle (usbdevfs).
|
|
|
|
### Voraussetzungen (Laufzeit)
|
|
|
|
**Linux (Share-Modus):**
|
|
- Root-Rechte (fuer USB-Geraetezugriff)
|
|
|
|
**Linux (Use-Modus):**
|
|
- Kernel-Modul `vhci-hcd`:
|
|
```bash
|
|
sudo modprobe vhci-hcd
|
|
```
|
|
- Fuer automatisches Laden bei Boot:
|
|
```bash
|
|
echo "vhci-hcd" | sudo tee /etc/modules-load.d/vhci-hcd.conf
|
|
```
|
|
|
|
### Bauen
|
|
|
|
#### Mit Make
|
|
|
|
```bash
|
|
# Alles bauen (Relay + Client, Linux)
|
|
make all
|
|
|
|
# Nur Relay-Server
|
|
make relay
|
|
|
|
# Nur Client (Linux)
|
|
make client
|
|
|
|
# Client fuer Windows (Cross-Compilation von Linux)
|
|
make client-windows
|
|
```
|
|
|
|
#### Ohne Make (Go direkt)
|
|
|
|
```bash
|
|
# Linux Relay-Server
|
|
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/usb-relay ./cmd/usb-relay/
|
|
|
|
# Linux Client
|
|
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/usb-client ./cmd/usb-client/
|
|
|
|
# Windows Client (Cross-Compilation von Linux)
|
|
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o bin/usb-client.exe ./cmd/usb-client/
|
|
```
|
|
|
|
Unter Windows (cmd.exe):
|
|
```cmd
|
|
set CGO_ENABLED=0
|
|
go build -ldflags="-s -w" -o bin\usb-client.exe ./cmd/usb-client/
|
|
```
|
|
|
|
Unter Windows (PowerShell):
|
|
```powershell
|
|
$env:CGO_ENABLED=0
|
|
go build -ldflags="-s -w" -o bin\usb-client.exe ./cmd/usb-client/
|
|
```
|
|
|
|
### Docker (Relay-Server)
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
Der Relay lauscht auf Port 8443.
|
|
|
|
## CLI Befehle
|
|
|
|
```
|
|
usb-client generate-token # 3 Tokens + Hash generieren
|
|
usb-client both [optionen] # Freigeben und Empfangen gleichzeitig
|
|
usb-client share [optionen] # Nur freigeben
|
|
usb-client use [optionen] # Nur empfangen
|
|
usb-client list # Lokale USB-Geraete auflisten
|
|
usb-client list -v # Mit Interfaces und Endpunkten (Diagnose)
|
|
usb-client gui # Nur Web-UI starten
|
|
usb-client config # Konfiguration anzeigen
|
|
usb-client config set [optionen] # Konfiguration aendern
|
|
usb-client install-service # Als systemd-Service installieren
|
|
usb-client uninstall-service # Service deinstallieren
|
|
```
|
|
|
|
### Optionen
|
|
|
|
```
|
|
--config <pfad> Config-Datei (Standard: ~/.usb-server/config.json)
|
|
--relay <adresse> Relay-Server (z.B. ws://localhost:8443)
|
|
--hash <hash> Gruppen-Hash
|
|
--name <name> Client-Name
|
|
--web-port <port> Web-UI Port (Standard: 8080)
|
|
--no-gui Web-UI deaktivieren
|
|
```
|
|
|
|
### Netzwerk
|
|
|
|
Fuer Direktverbindungen oeffnet jeder Share-faehige Client einen TCP-Port
|
|
(standardmaessig zufaellig). Zwei Faelle brauchen Handarbeit:
|
|
|
|
- **Feste Portfreigabe:** `direct_port` in der Config setzen und diesen Port
|
|
in Firewall/Router weiterleiten. Dann finden auch Peers hinter NAT hierher.
|
|
- **Gar keine Direktverbindung gewuenscht:** `disable_direct: true` setzt alles
|
|
zurueck auf den reinen Relay-Betrieb.
|
|
|
|
Ob eine Verbindung direkt zustande kam, steht im Log des Use-Clients
|
|
(`direct connection to ... established` gegen `using the relay`).
|
|
|
|
### Umgebungsvariablen
|
|
|
|
```
|
|
USBSRV_DEBUG=1 Protokolliert jeden einzelnen USB-Transfer (URB).
|
|
Nur zur Fehlersuche - ein aktives Video- oder Audiogeraet
|
|
erzeugt tausende URBs pro Sekunde, und das Protokollieren
|
|
kostet dann mehr Zeit als das Weiterleiten.
|
|
```
|
|
|
|
## Fehlersuche
|
|
|
|
### Erste Anlaufstelle
|
|
|
|
```bash
|
|
usb-client diag
|
|
```
|
|
|
|
Sagt fuer die jeweilige Maschine, ob Freigeben und Empfangen moeglich sind,
|
|
was im Weg steht und was dagegen hilft. Laeuft auf Linux, Windows und macOS
|
|
und prueft plattformspezifisch das Richtige: Rechte auf `/dev/bus/usb` und das
|
|
`vhci-hcd`-Modul unter Linux, Treiberstatus und Testsignierung unter Windows,
|
|
die IOKit-Lage unter macOS. Fuer jedes Geraet steht dabei, ob es freigegeben
|
|
werden kann - und wenn nicht, warum.
|
|
|
|
Zum Weitergeben:
|
|
|
|
```bash
|
|
usb-client diag -json # maschinenlesbar
|
|
usb-client diag -out report.txt # zusaetzlich in eine Datei
|
|
usb-client diag -id meinreport # zum konfigurierten Relay hochladen
|
|
```
|
|
|
|
Der Upload legt den Report unter `<relay>/diag/<id>` ab, wo er 24 Stunden
|
|
liegt. Das erspart es, von einer schwer erreichbaren Maschine - headless NAS,
|
|
Windows-Rechner mitten im Treiber-Debugging - tausende Zeilen von Hand zu
|
|
kopieren.
|
|
|
|
> Der Report enthaelt Hostname, Geraeteliste und OS-Version. Beim Hochladen
|
|
> auf einen Relay kann jeder mit der ID ihn lesen. Auf einem oeffentlichen
|
|
> Relay also eine schwer zu erratende ID waehlen, oder den Report lokal
|
|
> speichern und selbst weitergeben.
|
|
|
|
### Haeufige Faelle
|
|
|
|
**Geraet verbindet sich, liefert aber keine Daten.**
|
|
`usb-client list -v` auf der Share-Seite zeigt, wie jeder Endpunkt eingestuft
|
|
wird. Der Transfertyp dort entscheidet, wie die Transfers zum Geraet
|
|
geschickt werden - steht bei einem Interrupt-Endpunkt `bulk`, weist der
|
|
Kernel die Uebertragungen ab. Ohne Root-Rechte koennen die vollstaendigen
|
|
Deskriptoren nicht gelesen werden; dann erscheint ein Hinweis statt der
|
|
Endpunktliste.
|
|
|
|
**Geraet bleibt nach einem Absturz auf "in Benutzung".**
|
|
Beim Verbindungsverlust zum Relay geben beide Seiten ihre Geraete
|
|
automatisch wieder frei. Bleibt trotzdem eines haengen, loest ein Neustart
|
|
des Share-Clients die Bindung; die Kernel-Treiber werden dabei ueber
|
|
sysfs `authorized` neu gebunden.
|
|
|
|
**Verbindung bricht regelmaessig ab.**
|
|
Client und Relay senden alle 20 Sekunden WebSocket-Pings und trennen nach 60
|
|
Sekunden Stille. Liegt ein Proxy dazwischen, der WebSockets frueher schliesst,
|
|
muss dessen Timeout hoeher liegen als 60 Sekunden.
|
|
|
|
## Web-UI
|
|
|
|
Die Web-UI ist unter http://localhost:8080 erreichbar und bietet:
|
|
|
|
- **Geraete-Tab:** Liste aller verfuegbaren/verbundenen USB-Geraete
|
|
- **Einstellungen:** Relay-Adresse, Modus, Name konfigurieren
|
|
- **Token:** Tokens generieren oder eintragen
|
|
- **Service:** Als Systemdienst installieren/deinstallieren
|
|
|
|
## Konfiguration
|
|
|
|
Die Konfiguration wird in `~/.usb-server/config.json` gespeichert:
|
|
|
|
```json
|
|
{
|
|
"relay_addr": "ws://localhost:8443",
|
|
"hash": "a1b2c3d4...",
|
|
"mode": "use",
|
|
"name": "Mein-PC",
|
|
"web_port": 8080,
|
|
"token1": "...",
|
|
"token2": "...",
|
|
"token3": "...",
|
|
"auto_connect": [
|
|
{"vendor_id": "1234", "product_id": "5678"},
|
|
{"bus_id": "1-1.4"}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Als Service installieren
|
|
|
|
```bash
|
|
# Service installieren (braucht root)
|
|
sudo ./bin/usb-client install-service
|
|
|
|
# Service Status pruefen
|
|
systemctl status usb-client
|
|
|
|
# Service deinstallieren
|
|
sudo ./bin/usb-client uninstall-service
|
|
```
|
|
|
|
## Sicherheit
|
|
|
|
- **Tunnel-Verschluesselung:** USB-Daten werden Ende-zu-Ende mit AES-256-GCM
|
|
verschluesselt - sowohl ueber den Relay als auch bei Direktverbindung. Der
|
|
Schluessel wird per HKDF aus den 3 Tokens abgeleitet, pro Tunnel neu. Jeder
|
|
Frame ist authentifiziert; manipulierte oder wiederholte Frames beenden den
|
|
Tunnel.
|
|
- **Gruppierung:** Die 3 Tokens sind das gemeinsame Geheimnis. Der Relay
|
|
bekommt nur ihren SHA256-Hash und kann daraus die Tokens nicht
|
|
zurueckrechnen - er kann also weder mitlesen noch sich als Peer ausgeben.
|
|
- **Direktverbindungen** werden mit einem aus den Tokens abgeleiteten Token
|
|
authentifiziert, das an die Tunnel-ID gebunden ist. Wer nur den Port
|
|
erreicht, kommt nicht hinein.
|
|
- **Transport-Verschluesselung:** Trotzdem `wss://` verwenden, wenn der Relay
|
|
ueber das Internet laeuft. Das schuetzt die Steuernachrichten und Metadaten,
|
|
die nicht Teil der Tunnel-Verschluesselung sind.
|
|
|
|
**Grenzen:** Der Hash gruppiert, er authentifiziert nicht - wer ihn kennt,
|
|
kann der Gruppe beitreten, Geraetelisten sehen und Geraete anfordern (ohne
|
|
die Tokens aber keine Tunneldaten lesen). Der Relay sieht Metadaten: wer
|
|
verbunden ist, welche Geraete angeboten und wann sie angefordert werden.
|
|
Ein Client mit den Tokens hat vollen Zugriff auf alle freigegebenen Geraete
|
|
der Gruppe; eine Rechteverwaltung pro Geraet oder Client gibt es nicht.
|
|
|
|
Fuer TLS am Relay-Server empfiehlt sich ein Reverse-Proxy (nginx/traefik) mit Let's Encrypt:
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl;
|
|
server_name relay.example.com;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/relay.example.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/relay.example.com/privkey.pem;
|
|
|
|
location /ws {
|
|
proxy_pass http://localhost:8443;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
}
|
|
}
|
|
```
|
|
|
|
## Technische Details
|
|
|
|
- **Sprache:** Go (single binary, keine Runtime-Abhaengigkeiten)
|
|
- **USB/IP:** Natives USB/IP-Protokoll (kein externes `usbip`-Paket noetig)
|
|
- **USB-Zugriff:** Direkte usbdevfs-ioctls (kein CGO/libusb)
|
|
- **VHCI:** Direkte sysfs-Schnittstelle zum vhci-hcd Kernel-Modul
|
|
- **Relay:** WebSocket mit JSON-Kontrollnachrichten und Binary-Tunneldaten
|
|
- **Tunnel:** USB/IP-Protokolldaten werden durch WebSocket-Binary-Frames getunnelt
|
|
|
|
## Verzeichnisstruktur
|
|
|
|
```
|
|
cmd/usb-relay/ - Relay-Server Binary
|
|
cmd/usb-client/ - Client Binary (share + use Modi)
|
|
internal/relay/ - WebSocket Relay & Hub
|
|
internal/protocol/ - Nachrichtentypen
|
|
internal/client/ - Client Core, Share & Use Manager
|
|
internal/usbip/ - USB/IP Protokoll, Server, VHCI
|
|
internal/usb/ - USB Enumeration & usbdevfs
|
|
internal/token/ - Token-Generierung
|
|
internal/config/ - Konfiguration
|
|
internal/web/ - Web-UI (embedded)
|
|
internal/service/ - Systemd Service
|
|
```
|
|
|
|
## Lizenz
|
|
|
|
Proprietaere Software. Alle Rechte vorbehalten.
|
|
Siehe [LICENSE](LICENSE) fuer Details.
|
|
|
|
### Third-Party Lizenzen
|
|
|
|
Diese Software verwendet Open-Source-Bibliotheken. Siehe [NOTICE](NOTICE) fuer Details.
|