Ajout de l'article 'Free, IPv6 et OPNsense'
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
attribution: "ChatGPT 5.3"
|
||||
description: "ChatGPT a été mon seul espoir."
|
||||
prompt: "Une illustration numérique vivante racontant une histoire de chaos numérique puis de sauvetage. À gauche, un enchevêtrement de câbles Ethernet serpente et étouffe une Freebox abîmée tandis que l’inscription IPv6 apparaît comme une tempête de feu au-dessus. Le logo flocon de NixOS est en train de sombrer dans une mer agitée faite de vagues et de pluie de code binaire. La scène est sombre et chaotique. À droite, la situation est lumineuse et paisible : un robot amical représentant ChatGPT, baigné de lumière, tend la main pour aider une personne soulagée qui sort de l’eau. Un arc-en-ciel traverse le ciel et une petite île technologique stable avec un symbole NixOS apparaît en arrière-plan. Dans le ciel est écrit ‘Merci ChatGPT !’. Style illustration numérique détaillée, composition narrative gauche-chaos / droite-sauvetage."
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
description: "On reporte alors cette adresse de lien local dans le premier **Préfixe secondaire** de la Freebox"
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
#description: ""
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
#description: ""
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
#description: ""
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
#description: ""
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
#description: ""
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
description: "Obtention de l'adresse de lien local depuis l'interface d'OPNsense. C'est la deuxième adresse de la ligne `IPv6 Addresses`, qui commence toujours par `fe80`."
|
||||
#prompt: ""
|
||||
@@ -0,0 +1,4 @@
|
||||
#title: ""
|
||||
#attribution: ""
|
||||
#description: ""
|
||||
#prompt: ""
|
||||
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 593 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 419 KiB |
|
After Width: | Height: | Size: 165 KiB |
@@ -0,0 +1,321 @@
|
||||
---
|
||||
title: Free, IPv6 et OPNsense
|
||||
date: "2026-03-04 16:50:00"
|
||||
cover: images/cover.png
|
||||
tags:
|
||||
- Administration réseau
|
||||
- OPNsense
|
||||
- ChatGPT
|
||||
- Intelligence artificielle
|
||||
- IPv6
|
||||
weather:
|
||||
temperature: 14.1666666666667
|
||||
humidity: 52
|
||||
pressure: 1025.73711915929
|
||||
illuminance: 11254.8
|
||||
wind_speed: 3.8624256
|
||||
wind_direction: 89
|
||||
precipitations: false
|
||||
source:
|
||||
- influxdb
|
||||
comments_url: https://com.richard-dern.fr/post/478
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Bien conscient de la [pénurie d'adresses IPv4](https://fr.wikipedia.org/wiki/Épuisement_des_adresses_IPv4) depuis très longtemps, cela fait des années que j'essayais de mettre en place [IPv6](https://fr.wikipedia.org/wiki/IPv6) sur mon réseau, sans que j'y parvienne.
|
||||
Et très honnêtement, c'est largement à cause de ma méconnaissance des implications techniques d'IPv6 qui me faisait craindre pour la sécurité de mon réseau si je m'y prenais mal.
|
||||
|
||||
J'ai finalement décidé de donner les clés de mon château ([OPNsense](https://opnsense.org)) à [ChatGPT](https://chatgpt.com), qui s'est occupé de tout pour moi [^1].
|
||||
Et je ne regrette pas un instant de l'avoir fait : il a **tout** mis en place, et tout fonctionne parfaitement bien.
|
||||
|
||||
[^1]:
|
||||
J'ai créé un utilisateur sur mon serveur principal à usage exclusif de _ChatGPT-5.3-Codex_, créé une paire de clés envoyée à mon routeur, et démarré une session `codex` à partir de laquelle ChatGPT pouvait se connecter en `root` via SSH vers le routeur.
|
||||
Une fois qu'il a accompli ses objectifs, il n'y avait plus qu'à supprimer l'utilisateur dédié et les clés SSH associées sur le routeur.
|
||||
|
||||
## Objectifs
|
||||
|
||||
Mes objectifs sont de fournir la double connectivité IPv4 et IPv6 aux clients de mon _LAN_, et que mes serveurs et services soient joignables en IPv4 ou IPv6.
|
||||
|
||||
## Mon réseau
|
||||
|
||||
Je le détaille dans [cet article](/interets/informatique/2021/03/09/mon-reseau/), mais en substance :
|
||||
|
||||
- J'ai une [Freebox Pop](https://www.free.fr/freebox/freebox-pop) Fibre en mode _bridge_
|
||||
- Un réseau local
|
||||
- Un routeur sous OPNsense qui fait le lien entre les deux
|
||||
|
||||
J'ai installé le [plugin](https://docs.opnsense.org/manual/how-tos/caddy.html) [caddy](https://caddyserver.com) sur OPNsense : il fait office de _reverse-proxy_ pour tout service que je veux exposer.
|
||||
Les services qui ne passent pas par un serveur web font l'objet de règles de [NAT](https://fr.wikipedia.org/wiki/Network_address_translation).
|
||||
|
||||
## Mise en place
|
||||
|
||||
Par souci de confidentialité, j'ai anonymisé les adresses IP et les identifiants matériels dans les extraits et les captures d'écran.
|
||||
|
||||

|
||||
|
||||
### Freebox
|
||||
|
||||
Dans [l'interface de configuration de la Freebox](http://mafreebox.freebox.fr/), on active le _Next Hop_ IPv6 du **premier préfixe secondaire** en indiquant l'adresse _lien local_ du routeur.
|
||||
|
||||
> [Une adresse IPv6](https://fr.wikipedia.org/wiki/Adresse_IPv6) de lien-local (préfixe `fe80::/10`) est une adresse valable uniquement sur le lien où elle a été émise, et qui n'est pas routée sur Internet. Une machine a une adresse de lien-local par interface, ce qui explique pourquoi on parle de l'adresse lien-local de l'interface _WAN_.
|
||||
|
||||
> Un préfixe IPv6 (notation `.../64`) désigne un bloc d'adresses, l'équivalent d'un réseau en IPv4.
|
||||
|
||||
> Le _Next Hop_ (le "prochain saut") revient à indiquer à la Freebox vers quel voisin elle doit [envoyer les paquets](https://fr.wikipedia.org/wiki/Table_de_routage) destinés à ce préfixe.
|
||||
|
||||

|
||||
|
||||
Mon erreur était de renseigner l'adresse _lien local_ de l'interface _WAN_ de mon routeur comme _Next Hop_ du préfixe _principal_, et l'adresse _lien local_ de l'interface _LAN_ de mon routeur dans le _Next Hop_ du premier préfixe secondaire.
|
||||
Je me suis laissé influencer [par ce post](https://lafibre.info/remplacer-freebox/freebox-delta-pop-mode-bridge-onpsense-freeplayer/), dont je n'ai lu que les images et pas le texte...
|
||||
|
||||
Il n'y a rien de plus à faire sur la Freebox.
|
||||
|
||||
En pratique, je devrais activer le serveur DHCPv6 pour que mon serveur se voit attribuer une adresse fixe, mais pour le moment, je veux juste m'assurer que tout fonctionne avant d'activer des options.
|
||||
|
||||
### OPNsense
|
||||
|
||||
C'est à partir de là que ChatGPT a pris le contrôle de mon routeur.
|
||||
|
||||
Je tiens à souligner que je l'ai laissé en totale autonomie après lui avoir donné mes instructions, et qu'à aucun moment je n'ai subi de déconnexion intempestive.
|
||||
Il a assuré, du début à la fin, en procédant à des sauvegardes avant chaque commande potentiellement destructive.
|
||||
Ma session de codex me permettait de voir en direct toutes les commandes qu'il exécutait, d'où la confiance que je lui ai accordée.
|
||||
Les commandes utilisées pour la vérification sont données plus loin à titre informatif, mais ces vérifications peuvent aussi être effectuées directement dans l'interface web de OPNsense.
|
||||
|
||||
Je précise aussi que je ne sauve pas des vies : si mon blog est hors-ligne pendant une grosse demi-heure (le temps de restaurer ma configuration initiale), ça ne va gêner personne, en particulier en plein milieu de la nuit.
|
||||
|
||||
#### Activation IPv6 WAN/LAN
|
||||
|
||||
Dans _Interfaces_, _[WAN]_, on active le mode `SLAAC` pour l'interface _WAN_.
|
||||
|
||||
[`SLAAC`](https://en.wikipedia.org/wiki/Stateless_address_autoconfiguration) (_Stateless Address Autoconfiguration_) est le mécanisme standard d'auto-configuration IPv6 à partir des messages _Router Advertisement_.
|
||||
Je le choisis sur le _WAN_ car la Freebox annonce déjà ce qu'il faut (route par défaut et préfixe), et cela simplifie le diagnostic tant que la connectivité de base n'est pas validée.
|
||||
|
||||

|
||||
|
||||
Dans _Interfaces_, _[LAN]_, on configure une IPv6 statique pour l'interface _LAN_ dans le préfixe secondaire.
|
||||
Traditionnellement, c'est le préfixe IPv6, suivi par `::1` (un peu comme `10.0.0.1` en IPv4).
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Et on applique la configuration.
|
||||
|
||||
#### Router Advertisements (RA) sur LAN
|
||||
|
||||
Dans _Services_, _Router Advertisements_, on active _RA_ pour le _LAN_.
|
||||
|
||||

|
||||
|
||||
Les [_Router Advertisements_](https://fr.wikipedia.org/wiki/Radvd) (RA) sont des messages envoyés par le routeur aux clients pour annoncer la passerelle par défaut, les préfixes disponibles, et les indicateurs liés à DHCPv6.
|
||||
Sans RA, un client ne peut pas apprendre sa route par défaut IPv6, même si un serveur DHCPv6 est présent.
|
||||
|
||||
Les modes de RA d'OPNsense servent essentiellement à indiquer aux clients s'ils doivent utiliser `SLAAC`, [`DHCPv6`](https://fr.wikipedia.org/wiki/DHCPv6), ou une combinaison des deux.
|
||||
Ils correspondent à des combinaisons de drapeaux standards des RA, notamment `AdvManagedFlag` (le drapeau `M`) et `AdvOtherConfigFlag` (le drapeau `O`), ainsi que le drapeau "autonomous" associé au préfixe qui autorise `SLAAC`.
|
||||
La [documentation](https://docs.opnsense.org/manual/radvd.html) d'OPNsense récapitule précisément ces modes et leurs drapeaux.
|
||||
|
||||
- `Router only` : le routeur n'annonce que la passerelle par défaut, ce qui suppose que les clients aient déjà une adresse IPv6 (par exemple via une configuration statique).
|
||||
- `Unmanaged` : les clients obtiennent leur adresse via `SLAAC`, sans que les RA ne signalent de service DHCPv6.
|
||||
- `Managed` : les clients sont censés obtenir leur adresse via DHCPv6 (configuration _stateful_), ce qui implique de ne pas utiliser `SLAAC` pour l'adressage.
|
||||
- `Assisted` : les clients peuvent obtenir une adresse via DHCPv6 tout en pouvant aussi utiliser `SLAAC`, ce qui peut aboutir à plusieurs adresses IPv6 globales sur une même interface.
|
||||
- `Stateless` : les clients utilisent `SLAAC` pour l'adressage, et peuvent utiliser DHCPv6 uniquement pour des informations "annexes" (par exemple les serveurs DNS).
|
||||
|
||||
Dans un premier temps, on le configure en `Unmanaged`.
|
||||
Une fois DHCPv6 (Kea) activé et le DNS correctement publié, je basculerai en `Assisted` afin que RA et DHCPv6 puissent cohabiter sans ambiguïté (expliqué plus bas).
|
||||
|
||||
#### DHCPv6 (Kea) sur LAN
|
||||
|
||||
Dans _Services_, _Kea DHCP_, _Kea DHCPv6_, on active DHCPv6 dans Kea pour le _LAN_.
|
||||
|
||||

|
||||
|
||||
On enregistre le _subnet_ (celui du préfixe pour lequel on a ajouté un _Next Hop_ dans la Freebox).
|
||||
|
||||

|
||||
|
||||
Je prévois ici d'utiliser l'adresse `...::53` pour mon serveur DNS, avec _fallback_ sur le serveur DNS du routeur (`...::1`).
|
||||
|
||||
#### Réservation IPv6 stable pour le serveur DNS
|
||||
|
||||
À ce stade, j'ai demandé à ChatGPT de fiabiliser l'adresse IPv6 de mon serveur DNS.
|
||||
Il s'agit de récupérer son _DUID_ depuis les baux déjà attribués dynamiquement et de l'ajouter aux réservations.
|
||||
C'est le même principe que pour IPv4, sauf que le _DUID_ est plus fiable que l'adresse _MAC_.
|
||||
|
||||
Après un redémarrage de mon pi-hole (`dns-1`), j'obtiens bien l'adresse en `...::53` qui a été configurée dans les baux statiques.
|
||||
|
||||
#### Mise à jour du RA
|
||||
|
||||
Dans _Services_, _Router Advertisements_, on peut maintenant passer au mode `Assisted`.
|
||||
|
||||

|
||||
|
||||
#### Vérifications techniques
|
||||
|
||||
##### Connectivité IPv6 depuis dns-1
|
||||
|
||||
`dns-1` a bien reçu l'IPv6 réservée :
|
||||
|
||||
```bash
|
||||
inet6 ...::53/128 scope global dynamic noprefixroute
|
||||
```
|
||||
|
||||
##### Résolution DNS via dns-1 en IPv6
|
||||
|
||||
Depuis OPNsense :
|
||||
|
||||
```bash
|
||||
drill @...::53 one.one.one.one AAAA
|
||||
```
|
||||
|
||||
Résultat attendu : réponse `NOERROR` avec des `AAAA` (ex. : Cloudflare).
|
||||
|
||||
##### Vérifier les annonces RA
|
||||
|
||||
```bash
|
||||
grep -nE 'RDNSS|AdvManagedFlag|AdvOtherConfigFlag' /var/etc/radvd.conf
|
||||
```
|
||||
|
||||
Résultat attendu :
|
||||
|
||||
- `AdvManagedFlag on`
|
||||
- `AdvOtherConfigFlag on`
|
||||
- `RDNSS ...::53 ...::1`
|
||||
|
||||
##### Vérifier les annonces DHCPv6
|
||||
|
||||
```bash
|
||||
sed -n '30,55p' /usr/local/etc/kea/kea-dhcp6.conf
|
||||
```
|
||||
|
||||
Résultat attendu :
|
||||
|
||||
- Serveurs DNS : `...::53,...::1`
|
||||
- Réservation `...::53` pour `dns-1`
|
||||
|
||||
##### Vérifier les règles IPv6 WAN (phase LAN uniquement)
|
||||
|
||||
Ici, "phase LAN uniquement" signifie que je valide d'abord l'IPv6 sortant pour les machines du _LAN_, sans encore exposer de services en IPv6 vers Internet.
|
||||
Je m'attends donc à ne voir, sur _WAN_, que les règles indispensables au fonctionnement côté routeur, et aucune règle `pass` destinée à des services.
|
||||
|
||||
```bash
|
||||
pfctl -sr | awk 'tolower($0) ~ /pass/ && $0 ~ / on igc1 / && tolower($0) ~ /inet6/ {print}'
|
||||
```
|
||||
|
||||
Résultat attendu : uniquement les règles DHCPv6 client.
|
||||
|
||||
À ce stade, n'importe quel client devrait pouvoir faire un [test d'IPv6](https://test-ipv6.com/) et obtenir un 10/10.
|
||||
|
||||

|
||||
|
||||
### Publication d'un site web en IPv6
|
||||
|
||||
#### Créer le AAAA public
|
||||
|
||||
Ajouter une entrée `AAAA` chez mon registrar ([OVH](https://www.ovhcloud.com/fr/)) avec l'adresse IP globale de l'interface _WAN_ obtenue depuis la Freebox.
|
||||
Cette adresse IP est dans le préfixe principal (celui dont le _Next Hop_ reste vide).
|
||||
|
||||
#### Ouvrir le firewall WAN en IPv6 pour le web
|
||||
|
||||
Ajouter l'équivalent IPv6 des règles IPv4 existantes, autrement dit :
|
||||
|
||||
- WAN `inet6` TCP `80` vers `wanip`
|
||||
- WAN `inet6` TCP `443` vers `wanip`
|
||||
|
||||
Rien de compliqué ici, c'est rigoureusement la même chose que pour IPv4.
|
||||
|
||||
#### Recharger et vérifier
|
||||
|
||||
Recharger le filtre :
|
||||
|
||||
```bash
|
||||
configctl filter reload
|
||||
```
|
||||
|
||||
Vérifier les règles actives :
|
||||
|
||||
```bash
|
||||
pfctl -sr | grep -E 'inet6 proto tcp.*port = http|inet6 proto tcp.*port = https'
|
||||
```
|
||||
|
||||
Résultat attendu : deux règles `pass in` WAN en IPv6 pour `80` et `443`.
|
||||
|
||||
Vérifier la résolution DNS AAAA :
|
||||
|
||||
```bash
|
||||
drill @1.1.1.1 AAAA richard-dern.fr
|
||||
```
|
||||
|
||||
Résultat attendu :
|
||||
|
||||
- `richard-dern.fr. ... AAAA ...:6789`
|
||||
|
||||
Vérifier l'accès HTTPS en IPv6 :
|
||||
|
||||
```bash
|
||||
curl -6 -I https://richard-dern.fr
|
||||
```
|
||||
|
||||
Résultat attendu : réponse `HTTP/2 200` (ou redirection HTTP vers HTTPS selon la politique du site).
|
||||
|
||||
### IRC en IPv6 : NAT ou routage ?
|
||||
|
||||
En IPv4, la publication d'un service passe très souvent par une [redirection de port](https://fr.wikipedia.org/wiki/Network_address_translation) (NAT) depuis l'IP publique du routeur vers une IP privée du serveur.
|
||||
En IPv6, un serveur du _LAN_ peut avoir une adresse globale routable, et la publication devient principalement une question de DNS (`AAAA`) et de filtrage firewall, pas de traduction d'adresse.
|
||||
|
||||
Autrement dit, ce qui "protège" le _LAN_ n'est pas le NAT, mais le fait que, par défaut, rien n'est autorisé en entrée tant qu'aucune règle `pass` n'est ajoutée sur _WAN_.
|
||||
Dans certains cas, on peut néanmoins conserver une logique de redirection IPv6 -> IPv6 (NAT66), par exemple quand un même nom de domaine doit pointer vers le routeur pour le web (reverse-proxy) tout en exposant d'autres ports vers un hôte interne.
|
||||
|
||||
Dans mon cas, je veux que `irc.dern.ovh` pointe vers le routeur pour servir le [client web](https://irc.dern.ovh/) via Caddy, et je redirige les ports [IRC](https://fr.wikipedia.org/wiki/Internet_Relay_Chat) vers `server-main` (la machine sur laquelle le serveur IRC est hébergé).
|
||||
|
||||
#### Pré-requis côté hôte (`server-main` sous NixOS)
|
||||
|
||||
Activer IPv6 dans la config NixOS de l'hôte :
|
||||
|
||||
```nix
|
||||
{
|
||||
networking = {
|
||||
enableIPv6 = true;
|
||||
tempAddresses = "disabled";
|
||||
};
|
||||
|
||||
systemd.services.dhcpcd.serviceConfig.SystemCallFilter = lib.mkForce [
|
||||
"@system-service"
|
||||
"~@aio"
|
||||
"~@keyring"
|
||||
"~@memlock"
|
||||
"~@mount"
|
||||
"~@resources"
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
Ces lignes sont un ajustement **spécifique à ma configuration**, et non un prérequis générique à IPv6.
|
||||
Dans mon cas, `dhcpcd` était trop durci côté `systemd`, ce qui l'empêchait d'appliquer correctement la configuration réseau (adresses et routes).
|
||||
Forcer un `SystemCallFilter` compatible a permis à `dhcpcd` de fonctionner, tout en conservant des restrictions sur des familles d'appels système inutiles ici (comme `@mount`).
|
||||
|
||||
#### Mise en place
|
||||
|
||||
J'ai affecté un nom de domaine à l'usage d'IRC : `irc.dern.ovh`.
|
||||
Or, cet usage est double :
|
||||
|
||||
- c'est l'adresse du serveur IRC
|
||||
- c'est aussi l'adresse que l'on peut ouvrir dans un navigateur pour accéder au client web
|
||||
|
||||
C'est un cas d'usage idéal pour justifier le NAT en IPv6.
|
||||
Donc, lorsque j'ai créé une entrée DNS `AAAA` pour `irc.dern.ovh`, je l'ai fait pointer non pas vers mon serveur IRC mais _vers mon routeur_, puis j'ai créé une règle de NAT pour le serveur IRC.
|
||||
De cette façon, le reverse-proxy répond pour servir le client web, et on NAT vers le serveur IRC quand on cherche à joindre le port approprié.
|
||||
|
||||

|
||||
|
||||
## Conclusion
|
||||
|
||||
Je le redis : j'ai laissé les clés du château à ChatGPT.
|
||||
Je lui ai fait confiance, et j'ai eu raison de le faire.
|
||||
Il m'a épargné des jours de prises de tête pour une tâche face à laquelle j'ai souvent échoué.
|
||||
|
||||
En outre, au cours de nos échanges, il m'a expliqué ce que je ne comprenais pas.
|
||||
Et comme je suis chiant, je lui ai posé plein de questions.
|
||||
|
||||
Maintenant, j'ai un réseau IPv6 fonctionnel et j'ai compris ce que j'ai fait.
|
||||
Merci ChatGPT, et **merci à ceux qui ont permis que ces informations se retrouvent dans ce qu'il m'a proposé**.
|
||||