feat: tunnel WireGuard vers le serveur familyd et mode propriétaire de l'appareil
- Firebase et le pare-feu local (trou noir, liste blanche par application, coupure cyclique locale) sont retirés - Client WireGuard officiel (GoBackend) : tout le trafic passe par le serveur familyd, qui filtre - Appairage par code ou lien familyd:// ; clé privée WireGuard et jeton chiffrés par l'Android Keystore - Remontées par le tunnel : état, temps d'écran, applications installées, évènements (file persistante) - Mode propriétaire (Device Owner) : VPN toujours actif avec blocage hors VPN, réglages verrouillés, garde-fou si le serveur ne répond plus pendant 15 min - Plan de la refonte : docs/PLAN-wireguard.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9CBCVP5oDu2sfoYPisNCQ
This commit is contained in:
1 parent
f382eeb4fe
commit
33ea4ff947
40 files changed
+1680
-1635
No files matched your search
@@ -0,0 +1,425 @@
|
||||
# Plan : contrôle parental par WireGuard et serveur auto-hébergé
|
||||
|
||||
> Statut : **proposition**, rien n'est réalisé. Rédigé le 2026-10-25.
|
||||
> Concerne DataControl (téléphone de l'enfant), FamilyControl (téléphone du parent) et un nouveau
|
||||
> service serveur, `familyd`, hébergé sur le CT 233 de pve-home (192.168.77.233).
|
||||
|
||||
## 1. Objectif
|
||||
|
||||
Remplacer le fonctionnement actuel (pare-feu VPN local « trou noir » + Firebase) par :
|
||||
|
||||
- **un tunnel WireGuard permanent** entre le téléphone de l'enfant et le serveur : tout le trafic
|
||||
du téléphone (Wi-Fi comme 4G/5G) passe par le serveur ;
|
||||
- **un filtrage côté serveur** : coupures, plages horaires, quota, sites et services interdits ;
|
||||
- **un canal de contrôle** par ce même tunnel : consignes du parent, état de l'appareil, alertes ;
|
||||
- **plus aucune dépendance à Firebase / Google**.
|
||||
|
||||
Ce qui reste sur le téléphone : ce que seul le téléphone peut savoir (application au premier plan,
|
||||
temps d'écran, batterie, position, type de réseau) et le blocage du lancement des applications.
|
||||
|
||||
## 2. Principe et contrainte fondatrice
|
||||
|
||||
WireGuard transporte des **paquets IP** : le serveur voit des adresses, des ports et (via le DNS)
|
||||
des noms de domaine, **jamais l'application qui a émis le paquet**. D'où la répartition :
|
||||
|
||||
| Besoin | Où | Comment |
|
||||
|---|---|---|
|
||||
| Couper Internet (horaire, punition, coupure cyclique) | Serveur | Règle nftables de l'appareil → « coupé » |
|
||||
| Bloquer un service (TikTok, YouTube…) ou une catégorie | Serveur | DNS filtrant par appareil |
|
||||
| « Seul Pronote passe » (liste blanche) | Serveur | DNS limité aux domaines autorisés + jeu d'IP rempli par les réponses DNS |
|
||||
| Quota de données | Serveur | Compteur d'octets du pair WireGuard (fiable, non falsifiable) |
|
||||
| Interdire / limiter le temps d'une application | Téléphone | Service d'accessibilité existant (blocage au lancement) |
|
||||
| Temps d'écran, batterie, position, type de réseau | Téléphone | Remontés à l'API par le tunnel |
|
||||
| Empêcher de couper le VPN, de changer l'heure, de désinstaller | Téléphone | Mode Device Owner (§8) |
|
||||
|
||||
Le filtrage réseau **par application** n'est pas repris en phase 1 : une application interdite est
|
||||
bloquée à son lancement, ce qui couvre l'usage réel. Il reste possible en phase 5 (§11).
|
||||
|
||||
## 3. Architecture
|
||||
|
||||
```
|
||||
Téléphone enfant (DataControl) CT 233 srv-home-zoompilot (192.168.77.233)
|
||||
┌──────────────────────────────┐ ┌──────────────────────────────────────────────┐
|
||||
│ VPN = client WireGuard │ UDP 51721 │ wg1 10.78.0.1/24 (wg0 ZoomPilot inchangé) │
|
||||
│ AllowedIPs 0.0.0.0/0, ::/0 ├────────────────►│ ├ nftables table inet familyd │
|
||||
│ DNS 10.78.0.1, MTU 1280 │ Freebox │ │ modes par appareil, NAT sortant, │
|
||||
│ Service d'accessibilité │ 82.67.111.224 │ │ DNS forcé, DoT/DoH bloqués │
|
||||
│ Client API (+ WebSocket) │ │ ├ DNS filtrant (AdGuard Home) 10.78.0.1:53 │
|
||||
└──────────────────────────────┘ │ ├ familyd (FastAPI + SQLite) │
|
||||
│ │ 10.78.0.1:8100 (appareils, via wg1) │
|
||||
FamilyControl (parent) │ │ 192.168.77.233:8100 (Traefik, parents) │
|
||||
┌──────────────────────────────┐ HTTPS │ ├ compteurs `wg show wg1 transfer` │
|
||||
│ API REST + WebSocket ├──► Traefik CT 201 ─►└ ntfy :8090 (existant) pour les alertes │
|
||||
│ Alertes : appli ntfy │ family.tuxtech.fr │
|
||||
└──────────────────────────────┘ └──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Cohabitation avec ZoomPilot sur le CT 233
|
||||
|
||||
Tout est séparé pour qu'un changement d'un côté ne touche pas l'autre :
|
||||
|
||||
| | ZoomPilot (existant) | Contrôle parental (nouveau) |
|
||||
|---|---|---|
|
||||
| Interface WireGuard | `wg0` 10.77.0.1/24, UDP 51720 | `wg1` 10.78.0.1/24, UDP **51721** |
|
||||
| Pare-feu | `table inet filter`, `table ip zp_nat` | `table inet familyd` (dédiée) |
|
||||
| Service | `zoompilot` :8000 | `familyd` :8100, `adguardhome` :53 + :3000 (admin, local) |
|
||||
| Utilisateur système | `zoompilot` | `familyd` |
|
||||
| Données | /var/lib/zoompilot | /var/lib/familyd |
|
||||
|
||||
Plages et ports vérifiés libres le 2026-10-25 : 10.6.0.0/24, 10.8.0.0/23 et 10.77.0.0/24 sont pris ;
|
||||
UDP 51720, 51820, 51900 pris.
|
||||
|
||||
**Risque assumé** : le CT devient critique pour l'accès Internet de l'enfant (voir §9). Un CT dédié
|
||||
(ex. 234) isolerait mieux ; le plan reste valable tel quel en changeant l'IP.
|
||||
|
||||
## 4. Serveur
|
||||
|
||||
### 4.1 Ressources du CT 233
|
||||
|
||||
Actuel : 1 cœur, 512 Mo, disque 3,9 Go (2,4 Go libres). À porter à **2 cœurs, 1,5 Go de RAM,
|
||||
disque +8 Go** (journaux DNS, historique SQLite). Sur pve-home, lire `/etc/pve` plutôt que
|
||||
`pct list` (stockage lent) ; le CT est sur `local-lvm`.
|
||||
|
||||
```bash
|
||||
# sur pve-home
|
||||
pct set 233 --cores 2 --memory 1536
|
||||
pct resize 233 rootfs +8G
|
||||
```
|
||||
|
||||
### 4.2 Réseau
|
||||
|
||||
- **Freebox** : rediriger **UDP 51721** → 192.168.77.233.
|
||||
- **Nom** : `fam-vpn.tuxtech.fr` → 82.67.111.224 (point de terminaison WireGuard ; un nom plutôt
|
||||
qu'une IP, pour survivre à un changement d'adresse).
|
||||
- **Traefik (CT 201)** : `family.tuxtech.fr` → 192.168.77.233:8100, certificat Let's Encrypt,
|
||||
**uniquement** les routes parent et appairage (`/api/parent/*`, `/api/pair`). Les routes
|
||||
appareil ne sont servies que sur 10.78.0.1.
|
||||
- **Retour en boucle (hairpin)** : quand le téléphone est sur le Wi-Fi de la maison, il joint
|
||||
82.67.111.224 depuis le réseau local. À vérifier sur la Freebox en phase 0 ; sinon, résolution
|
||||
DNS locale de `fam-vpn.tuxtech.fr` vers 192.168.77.233.
|
||||
- **IPv6** : le tunnel annonce `::/0` pour qu'aucun trafic IPv6 ne contourne le serveur ; le
|
||||
serveur ne route pas l'IPv6 (les applications retombent sur IPv4). NAT66 éventuel plus tard.
|
||||
|
||||
### 4.3 WireGuard `wg1`
|
||||
|
||||
```ini
|
||||
# /etc/wireguard/wg1.conf
|
||||
[Interface]
|
||||
Address = 10.78.0.1/24
|
||||
ListenPort = 51721
|
||||
PrivateKey = <clé serveur, chmod 600>
|
||||
# Les pairs sont ajoutés par familyd (wg set + wg-quick save) — pas d'édition à la main.
|
||||
```
|
||||
|
||||
Pair type (écrit par familyd à l'appairage) :
|
||||
|
||||
```ini
|
||||
[Peer]
|
||||
# device=<uuid> family=<id>
|
||||
PublicKey = <clé publique générée sur le téléphone>
|
||||
AllowedIPs = 10.78.0.10/32
|
||||
```
|
||||
|
||||
Côté téléphone : `PersistentKeepalive = 25` (indispensable derrière le NAT des opérateurs), MTU 1280.
|
||||
|
||||
### 4.4 Pare-feu nftables (`table inet familyd`)
|
||||
|
||||
Chaque appareil a un **mode** appliqué par familyd, via une map plutôt qu'une réécriture des
|
||||
règles :
|
||||
|
||||
| Mode | Effet |
|
||||
|---|---|
|
||||
| `open` | Tout passe (filtrage DNS seul) |
|
||||
| `allowlist` | Seules les IP du jeu `allow4` (remplies par les réponses DNS des domaines autorisés) passent |
|
||||
| `cut` | Rien ne sort, sauf le serveur lui-même (API + DNS sur 10.78.0.1) |
|
||||
|
||||
```nft
|
||||
table inet familyd {
|
||||
map mode4 { type ipv4_addr : verdict; } # 10.78.0.10 : jump m_open …
|
||||
set allow4 { type ipv4_addr; flags timeout; timeout 1h; } # rempli par dnsmasq (nftset)
|
||||
set doh4 { type ipv4_addr; flags interval; } # résolveurs DoH connus
|
||||
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat;
|
||||
iifname "wg1" udp dport 53 dnat ip to 10.78.0.1 # DNS forcé
|
||||
iifname "wg1" tcp dport 53 dnat ip to 10.78.0.1
|
||||
}
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat;
|
||||
iifname "wg1" oifname "eth0" masquerade
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy accept;
|
||||
iifname != "wg1" return
|
||||
tcp dport 853 drop # DNS sur TLS
|
||||
udp dport 853 drop
|
||||
ip daddr @doh4 tcp dport 443 drop # DNS sur HTTPS vers IP connues
|
||||
ip saddr vmap @mode4
|
||||
drop # appareil inconnu
|
||||
}
|
||||
chain m_open { accept }
|
||||
chain m_allowlist { ip daddr @allow4 accept; drop; }
|
||||
chain m_cut { drop }
|
||||
chain input {
|
||||
type filter hook input priority 0; policy accept;
|
||||
iifname "wg1" ip daddr 10.78.0.1 tcp dport { 53, 8100 } accept
|
||||
iifname "wg1" ip daddr 10.78.0.1 udp dport 53 accept
|
||||
iifname "wg1" drop # rien d'autre du CT (ZoomPilot, SSH…)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Points à respecter :
|
||||
- règles **idempotentes**, rechargées au démarrage de familyd depuis la base (source de vérité :
|
||||
SQLite, pas nftables) ;
|
||||
- **isolation entre pairs** : un appareil ne joint ni les autres pairs de `wg1`, ni `wg0`, ni le
|
||||
réseau 192.168.77.0/24 (règles `ip daddr { 10.77.0.0/24, 10.78.0.0/24, 192.168.77.0/24 } drop`
|
||||
dans `forward`, sauf 10.78.0.1) ;
|
||||
- après un changement de mode, purger les connexions en cours de l'appareil
|
||||
(`conntrack -D -s 10.78.0.x`), sinon une connexion ouverte survit à la coupure.
|
||||
|
||||
### 4.5 DNS filtrant
|
||||
|
||||
**Choix : AdGuard Home** (binaire unique, API REST, réglages par client) :
|
||||
- un **client par appareil** (identifié par son IP 10.78.0.x) avec ses **services bloqués**
|
||||
(liste intégrée : TikTok, YouTube, Snapchat…), contrôle parental, recherche sécurisée ;
|
||||
- règles par appareil avec le modificateur `$client` (mode liste blanche :
|
||||
`/.*/$client='10.78.0.10'` + `@@||index-education.net^$client='10.78.0.10'`) ;
|
||||
- blocage des domaines DoH connus (`dns.google`, `cloudflare-dns.com`…) et du domaine canari
|
||||
`use-application-dns.net` (désactive le DoH de Firefox) ;
|
||||
- journal des requêtes conservé **7 jours** (consultable par le parent, à mentionner à l'enfant) ;
|
||||
- interface d'administration sur 127.0.0.1:3003 uniquement, pilotée par familyd ; les règles de
|
||||
blocage DoH portent `$important` (sinon les exceptions du filtre AdGuard par défaut l'emportent).
|
||||
|
||||
**Liste blanche (validé en phase 0)** : la fonction `ipset` d'AdGuard Home ne remplit que les
|
||||
anciens jeux « ipset », illisibles par nftables. On utilise donc une petite instance **dnsmasq**
|
||||
(`familyd-dnsmasq`, 127.0.0.1:5353, option `nftset=`) à laquelle AdGuard Home transmet les seuls
|
||||
domaines de la liste blanche ; chaque adresse obtenue entre dans le jeu `allow4` (expiration 1 h,
|
||||
renouvelée à chaque requête ; AdGuard Home plafonne son cache à 300 s pour que le renouvellement
|
||||
ait lieu). Conséquence : `allow4` est **commun à tous les appareils** (union des listes blanches) ;
|
||||
la liste propre à chaque appareil s'applique au niveau DNS (règles `$client`).
|
||||
|
||||
### 4.6 Service `familyd` (FastAPI + SQLite)
|
||||
|
||||
Même pile que ZoomPilot (déjà maîtrisée et déployée sur ce CT) : `/opt/familyd`, venv,
|
||||
`/etc/familyd/familyd.env` (600), données `/var/lib/familyd`, unité systemd, utilisateur
|
||||
`familyd`. Les opérations privilégiées (`wg set`, `nft`, `conntrack`) passent par un petit
|
||||
assistant root appelé via `sudo` avec une liste de commandes fermée (pas de shell libre).
|
||||
|
||||
**Tâches de fond**
|
||||
- toutes les 60 s : relevé `wg show wg1 transfer` + `latest-handshakes` → octets par appareil
|
||||
(deltas stockés), « appareil en ligne » (dernière poignée de main < 3 min) ;
|
||||
- moteur de règles : à chaque minute et à chaque changement, calcule le mode de chaque appareil
|
||||
(consigne du parent, plage horaire, coupure cyclique sur données mobiles, quota) et l'applique
|
||||
(nft + AdGuard) ;
|
||||
- alertes vers **ntfy** (déjà sur le CT) : appareil hors ligne > 15 min, VPN coupé, protection
|
||||
retirée, heure modifiée, quota atteint.
|
||||
|
||||
**Schéma SQLite (esquisse)**
|
||||
|
||||
| Table | Contenu |
|
||||
|---|---|
|
||||
| `parents` | id, e-mail, hachage argon2, créé le |
|
||||
| `families` / `family_parents` | famille, parents associés |
|
||||
| `devices` | id (uuid), famille, nom, IP tunnel, clé publique WG, hachage du jeton, créé le, dissocié le |
|
||||
| `pairing_codes` | code (8 car.), famille, appareil prévu, expire le, utilisé le |
|
||||
| `policies` | appareil, mode manuel, plages horaires, quota, coupure cyclique, services bloqués, liste blanche, règles d'applications (JSON), version |
|
||||
| `device_state` | appareil, batterie, position, réseau (mobile/Wi-Fi), version de l'appli, Device Owner actif, vu le |
|
||||
| `traffic` | appareil, jour, octets mobile, octets Wi-Fi (attribués selon le réseau déclaré) |
|
||||
| `usage` | appareil, jour, temps d'écran total et par application |
|
||||
| `events` | appareil, type, détail, horodatage |
|
||||
|
||||
**API (esquisse)**
|
||||
|
||||
| Route | Qui | Rôle |
|
||||
|---|---|---|
|
||||
| `POST /api/parent/login` | parent | jeton de session |
|
||||
| `GET/PUT /api/parent/devices/{id}/policy` | parent | lire / modifier les consignes (versionnées) |
|
||||
| `POST /api/parent/devices/{id}/pairing-code` | parent | créer un code d'appairage (10 min, usage unique) |
|
||||
| `POST /api/parent/devices/{id}/bonus` | parent | temps supplémentaire du jour |
|
||||
| `GET /api/parent/devices/{id}/{state,traffic,usage,events,dns-log}` | parent | suivi |
|
||||
| `WS /api/parent/ws` | parent | changements en direct |
|
||||
| `POST /api/pair` | appareil (public, limité en débit) | code + clé publique → IP tunnel, clé serveur, point de terminaison, jeton |
|
||||
| `GET /api/device/policy` | appareil (tunnel) | consignes en vigueur |
|
||||
| `POST /api/device/{state,usage,events}` | appareil (tunnel) | remontées |
|
||||
| `WS /api/device/ws` | appareil (tunnel) | consignes poussées en direct |
|
||||
| `GET /api/device/time` | appareil (tunnel) | heure de référence (horloge de confiance) |
|
||||
|
||||
**Authentification**
|
||||
- parent : mot de passe (argon2) + jeton de session ;
|
||||
- appareil : jeton remis à l'appairage (stocké haché) **et** adresse source 10.78.0.x qui doit
|
||||
correspondre à l'appareil du jeton. Un jeton volé est inutilisable hors du tunnel de cet appareil ;
|
||||
- `/api/pair` : 5 essais par minute et par IP, code invalidé après usage.
|
||||
|
||||
## 5. Appairage
|
||||
|
||||
```
|
||||
Parent (FamilyControl) familyd Enfant (DataControl)
|
||||
│ créer l'appareil ───────────►│ réserve 10.78.0.x
|
||||
│◄── code ABCD2345 (10 min) ───│
|
||||
│ affiche code + QR ··································►│ saisit le code (ou scanne)
|
||||
│ │ │ génère sa paire de clés WG
|
||||
│ │◄── POST /api/pair ─────│ (clé privée jamais transmise)
|
||||
│ │ {code, clé publique} │
|
||||
│ │ wg set wg1 peer … │
|
||||
│ │ code consommé │
|
||||
│ │──► {IP, clé serveur, fam-vpn.tuxtech.fr:51721, DNS, jeton}
|
||||
│ │ │ monte le tunnel
|
||||
│◄── WS : « appareil en ligne » │◄── 1re poignée de main ─│
|
||||
```
|
||||
|
||||
- Le QR code contient l'URL `https://family.tuxtech.fr` et le code : rien à taper sur le téléphone
|
||||
de l'enfant.
|
||||
- La clé privée WireGuard est générée et stockée sur le téléphone (chiffrée par l'Android
|
||||
Keystore) ; perdue = ré-appairage.
|
||||
- Dissociation (par le parent) : pair retiré de `wg1`, jeton révoqué, mode `cut` jusqu'au retrait.
|
||||
|
||||
## 6. DataControl (téléphone de l'enfant) — v0.2
|
||||
|
||||
**Retiré**
|
||||
- `FirewallVpnService` (trou noir) et la logique de liste blanche locale par application ;
|
||||
- Firebase (`FirebaseGateway`, `RemoteSync`, dépendances `firebase-*`, écran de configuration
|
||||
Firebase) — l'APK s'allège d'autant ;
|
||||
- la coupure cyclique locale (devient une règle serveur).
|
||||
|
||||
**Ajouté**
|
||||
- client WireGuard : bibliothèque officielle `com.wireguard.android:tunnel` (`GoBackend`, qui
|
||||
fournit son propre `VpnService`) ; un seul VPN sur l'appareil, donc aucun conflit. Compter
|
||||
quelques Mo par architecture pour la bibliothèque native ; ne livrer que `arm64-v8a` (et
|
||||
`armeabi-v7a` si un vieil appareil l'exige) ;
|
||||
- écran d'appairage (code ou QR) ;
|
||||
- client API (HTTP + WebSocket sur 10.78.0.1:8100) avec file d'attente hors ligne pour les
|
||||
remontées ;
|
||||
- surveillance du tunnel : poignée de main trop ancienne → nouvelle tentative, alerte locale,
|
||||
événement envoyé dès le retour.
|
||||
|
||||
**Conservé**
|
||||
- service d'accessibilité et `GuardEngine` (blocage au lancement, temps d'écran) ; les règles
|
||||
arrivent par l'API au lieu de Firestore ; l'horloge de confiance se recale sur
|
||||
`/api/device/time` ;
|
||||
- mot de passe local (verrouillage des réglages), journal, mises à jour Gitea ;
|
||||
- suivi de consommation local (`TrafficStats`) à titre de contrôle croisé du compteur serveur.
|
||||
|
||||
**Type de réseau** : le téléphone déclare à chaque changement s'il est en données mobiles ou en
|
||||
Wi-Fi ; le serveur s'en sert pour attribuer les octets (forfait) et pour les règles propres aux
|
||||
données mobiles (coupure cyclique).
|
||||
|
||||
## 7. FamilyControl (parent) — v0.2
|
||||
|
||||
- `src/firebase/*` remplacé par un client de l'API familyd (`src/api/`) : même découpage
|
||||
fonctionnel, pour garder les écrans ;
|
||||
- écran de configuration : URL du serveur + compte parent au lieu de la configuration Firebase ;
|
||||
- nouveaux écrans : mode en cours (libre / liste blanche / coupé) avec bascule immédiate, services
|
||||
bloqués, journal DNS, consommation réelle mesurée par le serveur ;
|
||||
- alertes : appli **ntfy** abonnée au sujet de la famille (ntfy exposé par Traefik en HTTPS, accès
|
||||
refusé par défaut, un jeton par parent). Intégration directe dans FamilyControl plus tard ;
|
||||
- **clé de signature** : FamilyControl est signé aujourd'hui avec la clé de débogage publique du
|
||||
modèle React Native. La v0.2 est l'occasion de passer à une clé privée (une réinstallation
|
||||
unique du téléphone parent).
|
||||
|
||||
## 8. Verrouillage du téléphone : mode Device Owner
|
||||
|
||||
Sans ce mode, l'enfant peut toujours couper le VPN dans les réglages Android (le serveur le voit
|
||||
hors ligne et alerte le parent, sans pouvoir l'empêcher). Avec ce mode, DataControl impose :
|
||||
|
||||
| Politique | API Android |
|
||||
|---|---|
|
||||
| VPN toujours actif + blocage des connexions hors VPN | `setAlwaysOnVpnPackage(admin, pkg, lockdown = true, exemptions)` (API 29+ pour les exemptions) |
|
||||
| Impossible de modifier les VPN | `addUserRestriction(DISALLOW_CONFIG_VPN)` |
|
||||
| Impossible de changer date et heure | `DISALLOW_CONFIG_DATE_TIME` |
|
||||
| Pas de réinitialisation ni de mode sans échec | `DISALLOW_FACTORY_RESET`, `DISALLOW_SAFE_BOOT` |
|
||||
| DataControl indésinstallable | `setUninstallBlocked(admin, pkg, true)` |
|
||||
| Pas d'autre utilisateur | `DISALLOW_ADD_USER` |
|
||||
| Mises à jour silencieuses de DataControl | `PackageInstaller` (autorisé au Device Owner) |
|
||||
|
||||
**Mise en place** (une fois, câble USB) :
|
||||
1. retirer temporairement le compte Google du téléphone (Android refuse sinon) ;
|
||||
2. `adb shell dpm set-device-owner com.jttools.datacontrol/.admin.AppDeviceAdminReceiver` ;
|
||||
3. remettre le compte Google.
|
||||
|
||||
**Précautions**
|
||||
- **essayer d'abord sur un téléphone de test** ;
|
||||
- prévoir dans DataControl « Retirer le mode propriétaire » (mot de passe + confirmation du
|
||||
parent) : sans lui, seule une réinitialisation complète l'enlève ;
|
||||
- `DISALLOW_DEBUGGING_FEATURES` n'est **pas** activé par défaut (garder adb pour la maintenance) ;
|
||||
activable à distance par le parent ;
|
||||
- **politique en cas de serveur injoignable** (choix du parent) :
|
||||
- *fermé* : plus d'Internet tant que le serveur ne répond pas (sûr, mais une panne du CT prive
|
||||
l'enfant d'Internet) ;
|
||||
- *ouvert après délai* (recommandé) : au bout de 15 min sans poignée de main, DataControl lève
|
||||
le blocage hors VPN (`lockdown = false`), garde le blocage des applications au lancement, et
|
||||
signale l'incident dès le retour du serveur.
|
||||
- applications exemptées du VPN (liste du parent) : téléphone et messagerie de l'opérateur,
|
||||
appels d'urgence.
|
||||
|
||||
## 9. Exploitation
|
||||
|
||||
- **Disponibilité** : redémarrage automatique du CT (`onboot`), `Restart=on-failure` pour familyd
|
||||
et AdGuard Home, sonde de santé (`/api/health`) surveillée, alerte ntfy si familyd ou `wg1`
|
||||
tombe.
|
||||
- **Sauvegarde** : `sqlite3 familyd.db ".backup …"` quotidien (jamais `cp`), clé privée du
|
||||
serveur et `wg1.conf`, configuration AdGuard Home ; intégration aux sauvegardes existantes de
|
||||
pve-home.
|
||||
- **Débit** : tout le trafic du téléphone (vidéos comprises) passe par la Freebox deux fois
|
||||
(entrée + sortie). Mesurer en phase 0 ; la fibre Free est en général largement suffisante.
|
||||
- **Batterie** : WireGuard est le VPN le plus sobre ; `PersistentKeepalive = 25` coûte un peu,
|
||||
à mesurer sur une journée en phase 0.
|
||||
- **Vie privée** : le journal DNS et la position sont des données sur un mineur ; durée de
|
||||
conservation courte (7 jours DNS, 30 jours position), accès réservé aux parents de la famille.
|
||||
|
||||
## 10. Migration depuis Firebase
|
||||
|
||||
Une seule famille et un ou deux appareils : **bascule franche** plutôt que fonctionnement mixte.
|
||||
|
||||
1. Serveur en place et testé (phases 0–1).
|
||||
2. Publier FamilyControl v0.2 et DataControl v0.2 (sans Firebase).
|
||||
3. Mettre à jour les deux téléphones, ré-appairer l'enfant (QR code).
|
||||
4. Vérifier une journée complète (coupures, horaires, quota, alertes).
|
||||
5. Supprimer le projet Firebase. L'historique Firestore n'est pas repris (option : script d'export
|
||||
ponctuel si tu veux garder l'historique de trafic).
|
||||
|
||||
Tant que la v0.2 n'est pas installée, la v0.1.x continue de fonctionner avec Firebase.
|
||||
|
||||
## 11. Phases
|
||||
|
||||
| Phase | Contenu | Critère de fin |
|
||||
|---|---|---|
|
||||
| **0. Essai** (≈ 1 j) | `wg1` à la main + appli WireGuard officielle sur un téléphone de test ; AdGuard Home ; essais nft `open` / `cut` / `allowlist` | Débit et batterie mesurés ; hairpin Freebox vérifié ; mode liste blanche validé (AdGuard `ipset` ou repli dnsmasq) |
|
||||
| **1. Serveur** | familyd (API, moteur de règles, compteurs, alertes), assistant root, déploiement documenté, tests pytest | Appairage, changement de mode et quota testés de bout en bout avec un pair manuel |
|
||||
| **2. DataControl v0.2** | Client WireGuard, appairage, client API, suppression trou noir + Firebase | Téléphone de test piloté uniquement par familyd pendant 48 h |
|
||||
| **3. FamilyControl v0.2** | Client API, nouveaux écrans, clé de signature privée | Toutes les fonctions actuelles disponibles sans Firebase |
|
||||
| **4. Device Owner** | Politiques §8, provisionnement, sortie du mode | VPN impossible à couper sur le téléphone de test ; reprise après panne serveur conforme à la politique choisie |
|
||||
| **5. Option** | Filtrage réseau par application sur le téléphone : couche Go entre l'interface du VPN et wireguard-go, identification de l'application par `getConnectionOwnerUid` (API 29+) | Une application précise coupée sans couper le reste |
|
||||
|
||||
## 12. Phase 0 — état au 2026-10-25
|
||||
|
||||
**Réalisé sur le CT 233** (sauvegarde des règles et configurations d'origine :
|
||||
`/root/backup-familyd-phase0/`) :
|
||||
- CT agrandi : 2 cœurs, 1,5 Go, disque 20 Go ;
|
||||
- `wg1` 10.78.0.1/24, UDP 51721 (`wg-quick@wg1`), pair de test 10.78.0.10 ;
|
||||
- `/etc/nftables.conf` : ouvertures minimales pour `wg1` dans `table inet filter` + `include
|
||||
"/etc/nftables.d/*.nft"` ; `table inet familyd` dans `/etc/nftables.d/familyd.nft` ;
|
||||
- AdGuard Home v0.107.79 (`/opt/AdGuardHome`, DNS 10.78.0.1:53, admin 127.0.0.1:3003, mot de
|
||||
passe `/root/adguard-admin.password`), client « test-phase0 » avec TikTok bloqué ;
|
||||
- `familyd-dnsmasq` (liste blanche → `allow4`) ;
|
||||
- `fam-mode IP open|allowlist|cut` et `fam-mode list` en attendant familyd ;
|
||||
- fichiers de travail : `/root/familyd-phase0/` (config et QR du téléphone de test,
|
||||
`famsim-test.sh` : faux téléphone en espace réseau isolé pour rejouer les tests).
|
||||
|
||||
**Tests passés avec le faux téléphone** : les trois modes se comportent comme prévu ; DNS forcé
|
||||
(une requête « vers 8.8.8.8 » est servie par le DNS filtrant) ; DoH par IP et DoT bloqués ; LAN,
|
||||
ZoomPilot et ntfy injoignables depuis le tunnel ; ZoomPilot, ntfy et `wg0` inchangés.
|
||||
|
||||
**Reste à mesurer avec un vrai téléphone** : redirection Freebox UDP 51721 (en 4G), retour en
|
||||
boucle sur le Wi-Fi de la maison, débit, batterie sur une journée, blocage TikTok, applications
|
||||
qui contournent le DNS.
|
||||
|
||||
## 13. Questions ouvertes
|
||||
|
||||
1. **Politique en cas de serveur injoignable** : *fermé* ou *ouvert après 15 min* (recommandé) ?
|
||||
2. **Device Owner** : d'accord pour retirer temporairement le compte Google du téléphone de
|
||||
l'enfant (ou le réinitialiser) ? Existe-t-il un téléphone de test ?
|
||||
3. **CT dédié** plutôt que le CT 233 partagé avec ZoomPilot ?
|
||||
4. **Coupure cyclique** (toutes les X minutes sur données mobiles) : la garder dans le nouveau
|
||||
modèle, ou la remplacer par le quota et les plages horaires ?
|
||||
5. **Exemptions** du VPN : quelles applications doivent toujours passer (opérateur, banque…) ?
|
||||
Reference in new issue
Block a user