Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

Les RFC (Request For Comments) sont les documents de référence de l'Internet. Produits par l'IETF pour la plupart, ils spécifient des normes, documentent des expériences, exposent des projets...

Leur gratuité et leur libre distribution ont joué un grand rôle dans le succès de l'Internet, notamment par rapport aux protocoles OSI de l'ISO organisation très fermée et dont les normes coûtent cher.

Je ne tente pas ici de traduire les RFC en français (un projet pour cela existe mais je n'y participe pas, considérant que c'est une mauvaise idée), mais simplement, grâce à une courte introduction en français, de donner envie de lire ces excellents documents. (Au passage, si vous les voulez présentés en italien...)

Le public visé n'est pas le gourou mais l'honnête ingénieur ou l'étudiant.


RFC 9137: Considerations for Cancellation of IETF Meetings

Date de publication du RFC : Octobre 2021
Auteur(s) du RFC : M. Duke (F5 Networks)
Réalisé dans le cadre du groupe de travail IETF shmoo
Première rédaction de cet article le 12 octobre 2021


Pour son travail de normalisation technique, l'IETF tient normalement trois réunions physiques par an. La pandémie de Covid-19 a évidemment changé tout cela. Les premières décisions d'annulation ont été prises selon un procédure ad hoc, mais ce nouveau RFC fournit des critères plus rigoureux pour les prochaines décisions d'annulation.

La dernière réunion physique de l'IETF a eu lieu à Singapour en novembre 2019. Depuis, les conditions sanitaires ont forcé à annuler toutes les réunions. Mais notre nouveau RFC ne se limite pas au cas de la Covid-19. Une réunion, après tout, peut devoir être annulée pour d'autres raisons, un problème de dernière minute dans le bâtiment où elle devait se tenir, une catastrophe naturelle dans le pays d'accueil, un brusque changement dans la politique de visa de ce pays, etc. (Le RFC cite même le cas d'une guerre civile, mais ce n'est encore jamais arrivé à une réunion IETF.) Dans ces cas, l'IETF LLC (la direction administrative de l'IETF) et l'IESG vont devoir décider si on maintient la réunion ou pas.

La section 3 du RFC expose les critères de décision. L'IETF LLC (cf. RFC 8711) détermine si la réunion peut se tenir, l'IESG si cela vaut la peine de la tenir. L'IETF LLC doit évidemment travailler en toute transparence, informant l'IETF de la situation, des décisions possibles et d'un éventuel « plan B ». Il n'est pas toujours possible de procéder proprement et démocratiquement si la situation est urgente (tremblement de terre trois jours avant la réunion…). Dans ce cas, l'IETF LLC doit déterminer seule si la réunion peut se tenir (ce qui implique certaines garanties de sécurité pour les participants, de la restauration mais également un accès Internet qui marche ; les participants à l'IETF n'ont pas juste besoin de dormir et de manger, il leur faut aussi du réseau). L'IETF LLC doit aussi intégrer des paramètres internes comme la disponibilité de ses employés et des bénévoles, et bien sûr les conséquences financières du maintien ou de l'annulation (si le lieu de la réunion considère qu'il n'y avait pas force majeure et ne veut pas rembourser…). La section 3 du RFC 8718 contient des indications utiles à cette évaluation.

L'IESG, lui, doit déterminer s'il y aura suffisamment de monde à la réunion pour que ça vaille la peine. Il ne serait pas malin de maintenir une réunion pour que personne ne vienne.

La section 4 du RFC couvre les alternatives. Si on annule, que peut-on proposer à la place ? Il faut évaluer ces alternatives en tenant compte de leur efficacité (une réunion en ligne est moins efficace) et de leur coût (changer les billets d'avion au dernier moment coûte cher). Ces alternatives peuvent être, dans l'ordre décroissant de préférence :

  • Changer le lieu de la réunion. C'est ce qui dérange le moins le travail, surtout si le nouveau lieu est proche de l'ancien. Naturellement, le nouveau lieu doit correspondre aux critères des RFC 8718 et RFC 8719.
  • Passer en ligne, à une réunion « virtuelle », ce qui a été fait pour toutes les réunions annulées en raison de la Covid-19.
  • Repousser la réunion à plus tard. Ce n'est en général pas facilement faisable, puisque cela perturbe les agendas de tout le monde.
  • Annuler complètement, sans alternative. Le RFC note que cela aura des conséquences, non seulement sur le travail de normalisation, mais également sur des processus politiques comme la détermination de qui peut siéger dans des comités comme le NomCom (comité de nomination, cf. RFC 8788 et RFC 8989).

La section 5 de notre RFC couvre les questions financières. En gros, l'IETF ne remboursera pas les dépenses engagées par les participants (avion, hôtel, etc), seulement les frais d'inscription à la réunion, en totalité s'il y a annulation complète et partiellement dans les autres cas.


Téléchargez le RFC 9137


L'article seul

RFC 9132: Distributed Denial-of-Service Open Threat Signaling (DOTS) Signal Channel Specification

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : M. Boucadair (Orange), J. Shallow, T. Reddy.K (Akamai)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dots
Première rédaction de cet article le 10 octobre 2021


Le protocole DOTS (Distributed Denial-of-Service Open Threat Signaling) vise à permettre au client d'un service anti-dDoS de demander au service de mettre en route des mesures contre une attaque. Ce RFC décrit le canal de signalisation de DOTS, celui par lequel passera la demande d'atténuation de l'attaque. Il remplace le RFC 8782, mais les changements sont mineurs.

Si vous voulez mieux comprendre DOTS, il est recommandé de lire le RFC 8612, qui décrit le cahier des charges de ce protocole, et le RFC 8811, qui décrit l'architecture générale. Ici, je vais résumer à l'extrême : un client DOTS, détectant qu'une attaque par déni de service est en cours contre lui, signale, par le canal normalisé dans ce RFC, à un serveur DOTS qu'il faudrait faire quelque chose. Le serveur DOTS est un service anti-dDoS qui va, par exemple, examiner le trafic, jeter ce qui appartient à l'attaque, et transmettre le reste à son client.

Ces attaques par déni de service sont une des plaies de l'Internet, et sont bien trop fréquentes aujourd'hui (cf. RFC 4987 ou RFC 4732 pour des exemples). Bien des réseaux n'ont pas les moyens de se défendre seuls et font donc appel à un service de protection (payant, en général, mais il existe aussi des services comme Deflect). Ce service fera la guerre à leur place, recevant le trafic (via des manips DNS ou BGP), l'analysant, le filtrant et envoyant ce qui reste au client. Typiquement, le client DOTS sera chez le réseau attaqué, par exemple en tant que composant d'un IDS ou d'un pare-feu, et le serveur DOTS sera chez le service de protection. Notez donc que client et serveur DOTS sont chez deux organisations différentes, communiquant via le canal de signalisation (signal channel), qui fait l'objet de ce RFC.

La section 3 de notre RFC expose les grands principes du protocole utilisé sur ce canal de signalisation. Il repose sur CoAP, un équivalent léger de HTTP, ayant beaucoup de choses communes avec HTTP. Le choix d'un protocole différent de HTTP s'explique par les spécificités de DOTS : on l'utilise quand ça va mal, quand le réseau est attaqué, et il faut donc pouvoir continuer à fonctionner même quand de nombreux paquets sont perdus. CoAP a les caractéristiques utiles pour DOTS, il est conçu pour des réseaux où il y aura des pertes, il tourne sur UDP, il permet des messages avec ou sans accusé de réception, il utilise peu de ressources, il peut être sécurisé par DTLSTCP est également utilisable mais UDP est préféré, pour éviter le head-of-line blocking. CoAP est normalisé dans le RFC 7252. Parmi les choses à retenir, n'oubliez pas que l'encodage du chemin dans l'URI est un peu spécial, avec une option Uri-Path: par segment du chemin (RFC 7252, section 5.10.1). Par abus de langage, j'écrirai « le client CoAP demande /foo/bar/truc.cbor » alors qu'il y aura en fait trois options Uri-Path: :

Uri-Path: "foo"
Uri-Path: "bar"
Uri-Path: "truc.cbor" 
  

Par défaut, DOTS va utiliser le port 4646 (et non pas le port par défaut de CoAP, 5684, pour éviter toute confusion avec d'autres services tournant sur CoAP). Ce port a été choisi pour une bonne raison, je vous laisse la chercher, la solution est à la fin de cet article. Le plan d'URI sera coaps ou coaps+tcp (RFC 7252, section 6, et RFC 8323, section 8.2).

Le fonctionnement de base est simple : le client DOTS se connecte au serveur, divers paramètres sont négociés. Des battements de cœur peuvent être utilisés (par le client ou par le serveur) pour garder la session ouverte et vérifier son bon fonctionnement. En cas d'attaque, le client va demander une action d'atténuation. Pendant que celle-ci est active, le serveur envoie de temps en temps des messages donnant des nouvelles. L'action se terminera, soit à l'expiration d'un délai défini au début, soit sur demande explicite du client. Le serveur est connu du client par configuration manuelle, ou bien par des techniques de découverte comme celles du RFC 8973.

Les messages sont encodés en CBOR (RFC 8949). Rappelez-vous que le modèle de données de CBOR est très proche de celui de JSON, et notre RFC spécifie donc les messages avec une syntaxe JSON, même si ce n'est pas l'encodage utilisé sur le câble. Pour une syntaxe formelle des messages, le RFC utilise YANG (cf. RFC 7951). Le type MIME des messages est application/dots+cbor.

La section 4 du RFC décrit les différents messages possibles plus en détail. Je ne vais pas tout reprendre ici, juste donner quelques exemples. Les URI commencent toujours par /.well-known/dots (.well-known est normalisé dans le RFC 8615, et dots est désormais enregistré à l'IANA). Les différentes actions ajouteront au chemin dans l'URI /mitigate pour les demandes d'actions d'atténuation, visant à protéger de l'attaque, /hb pour les battements de cœur, etc.

Voici par exemple une demande de protection, effectuée avec la méthode CoAP PUT :

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "mitigate"
Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
Uri-Path: "mid=123"
Content-Format: "application/dots+cbor"

{
       ... Données en CBOR (représentées en JSON dans le RFC et dans
       cet article, pour la lisibilité).
}    
  

L'URI, en notation traditionnelle, sera donc /.well-known/dots/mitigate/cuid=dz6pHjaADkaFTbjr0JGBpw/mid=123. CUID veut dire Client Unique IDentifier et sert à identifier le client DOTS, MID est Mitigation IDentifier et identifie une demande d'atténuation particulière. Si ce client DOTS fait une autre demande de palliation, le MID changera mais le CUID sera le même.

Que met-on dans le corps du message ? On a de nombreux champs définis pour indiquer ce qu'on veut protéger, et pour combien de temps. Par exemple, on pourrait avoir (je rappelle que c'est du CBOR, format binaire, en vrai) :

     {
       "ietf-dots-signal-channel:mitigation-scope": {
         "scope": [
           {
             "target-prefix": [
                "2001:db8:6401::1/128",
                "2001:db8:6401::2/128"
              ],
             "target-port-range": [
               {
                 "lower-port": 80
               },
               {
                 "lower-port": 443
               }
              ],
              "target-protocol": [
                6
              ],
             "lifetime": 3600
           }
         ]
       }
     }
  

Ici, le client demande qu'on protège 2001:db8:6401::1 et 2001:db8:6401::2 (target veut dire qu'ils sont la cible d'une attaque, pas qu'on veut les prendre pour cible), sur les ports 80 et 443, en TCP, pendant une heure. (lower-port seul, sans upper-port indique un port unique, pas un intervalle.)

Le serveur va alors répondre avec le code 2.01 (indiquant que la requête est acceptée et traitée) et des données :

  {
     "ietf-dots-signal-channel:mitigation-scope": {
        "scope": [
           {
             "mid": 123,
             "lifetime": 3600
           }
         ]
      }
   }
  

La durée de l'action peut être plus petite que ce que le client a demandé, par exemple si le serveur n'accepte pas d'actions trop longues. Évidemment, si la requête n'est pas correcte, le serveur répondra 4.00 (format invalide), si le client n'a pas payé, 4.03, s'il y a un conflit avec une autre requête, 4.09, etc. Le serveur peut donner des détails, et la liste des réponses possibles figure dans des registres IANA, comme celui de l'état d'une atténuation, ou celui des conflits entre ce qui est demandé et d'autres actions en cours.

Le client DOTS peut ensuite récupérer des informations sur une action de palliation en cours, avec la méthode CoAP GET :

Header: GET (Code=0.01)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "mitigate"
Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
Uri-Path: "mid=123"    
  

Ce GET /.well-known/dots/mitigate/cuid=dz6pHjaADkaFTbjr0JGBpw/mid=123 va renvoyer de l'information sur l'action d'identificateur (MID) 123 :

   {
     "ietf-dots-signal-channel:mitigation-scope": {
       "scope": [
         {
           "mid": 123,
           "mitigation-start": "1507818393",
           "target-prefix": [
                "2001:db8:6401::1/128",
                "2001:db8:6401::2/128"
           ],
           "target-protocol": [
             6
           ],
           "lifetime": 1755,
           "status": "attack-stopped",
           "bytes-dropped": "0",
           "bps-dropped": "0",
           "pkts-dropped": "0",
           "pps-dropped": "0"
         }
       ]
     }
   }
  

Les différents champs de la réponse sont assez évidents. Par exemple, pkts-dropped indique le nombre de paquets qui ont été jetés par le protecteur.

Pour mettre fin aux actions du système de protection, le client utilise évidemment la méthode CoAP DELETE :

Header: DELETE (Code=0.04)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "mitigate"
Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
Uri-Path: "mid=123"
  

Le client DOTS peut se renseigner sur les capacités du serveur avec un GET de /.well-known/dots/config.

Ce RFC décrit le canal de signalisation de DOTS. Le RFC 8783, lui, décrit le canal de données. Le canal de signalisation est prévu pour faire passer des messages de petite taille, dans un environnement hostile (attaque en cours). Le canal de données est prévu pour des données de plus grande taille, dans un environnement où les mécanismes de transport normaux, comme HTTPS, sont utilisables. Typiquement, le client DOTS utilise le canal de données avant l'attaque, pour tout configurer, et le canal de signalisation pendant l'attaque, pour déclencher et arrêter l'atténuation.

Les messages possibles sont modélisés en YANG. YANG est normalisé dans le RFC 7950. Notez que YANG avait été initialement créé pour décrire les commandes envoyées par NETCONF (RFC 6241) ou RESTCONF (RFC 8040) mais ce n'est pas le cas ici : DOTS n'utilise ni NETCONF, ni RESTCONF mais son propre protocole basé sur CoAP. La section 5 du RFC contient tous les modules YANG utilisés.

La mise en correspondance des modules YANG avec l'encodage CBOR figure dans la section 6. (YANG permet une description abstraite d'un message mais ne dit pas, à lui tout seul, comment le représenter en bits sur le réseau.) Les clés CBOR sont toutes des entiers ; CBOR permet d'utiliser des chaînes de caractères comme clés mais DOTS cherche à gagner de la place. Ainsi, les tables de la section 6 nous apprennent que le champ cuid (Client Unique IDentifier) a la clé 4, suivie d'une chaîne de caractères en CBOR. (Cette correspondance est désormais un registre IANA.) D'autre part, DOTS introduit une étiquette CBOR, 271 (enregistrée à l'IANA, cf. RFC 8949, section 3.4) pour marquer un document CBOR comme lié au protocole DOTS.

Évidemment, DOTS est critique en matière de sécurité. S'il ne fonctionne pas, on ne pourra pas réclamer une action de la part du service de protection. Et s'il est mal authentifié, on risque de voir le méchant envoyer de faux messages DOTS, par exemple en demandant l'arrêt de l'atténuation. La section 8 du RFC rappelle donc l'importance de sécuriser DOTS par TLS ou plutôt, la plupart du temps, par son équivalent pour UDP, DTLS (RFC 6347). Le RFC insiste sur l'authentification mutuelle du serveur et du client, chacun doit s'assurer de l'identité de l'autre, par les méthodes TLS habituelles (typiquement via un certificat). Le profil de DTLS recommandé (TLS est riche en options et il faut spécifier lesquelles sont nécessaires et lesquelles sont déconseillées) est en section 7. Par exemple, le chiffrement intègre est nécessaire.

La section 11 revient sur les questions de sécurité en ajoutant d'autres avertissements. Par exemple, TLS ne protège pas contre certaines attaques par déni de service, comme un paquet TCP RST (ReSeT). On peut sécuriser la communication avec TCP-AO (RFC 5925) mais c'est un vœu pieux, il est très peu déployé à l'heure actuelle. Ah, et puis si les ressources à protéger sont identifiées par un nom de domaine, et pas une adresse ou un préfixe IP (target-fqdn au lieu de target-prefix), le RFC dit qu'évidemment la résolution doit être faite avec DNSSEC.

Question mises en œuvre, DOTS dispose d'au moins quatre implémentations, dont l'interopérabilité a été testée plusieurs fois lors de hackathons IETF (la première fois ayant été à Singapour, lors de l'IETF 100) :

Notez qu'il existe des serveurs de test DOTS publics comme coaps://dotsserver.ddos-secure.net:4646.

Ah, et la raison du choix du port 4646 ? C'est parce que 46 est le code ASCII pour le point (dot en anglais) donc deux 46 font deux points donc dots.

L'annexe A de notre RFC résume les principaux changements depuis le RFC 8782. Le principal changement touche les modules YANG, mis à jour pour réparer une erreur et pour tenir compte du RFC 8791. Il y a aussi une nouvelle section (la 9), qui détaille les codes d'erreur à renvoyer, et l'espace des valeurs des attributs a été réorganisé… Rien de bien crucial, donc.


Téléchargez le RFC 9132


L'article seul

RFC 9117: Revised Validation Procedure for BGP Flow Specifications

Date de publication du RFC : Août 2021
Auteur(s) du RFC : J. Uttaro (AT&T), J. Alcaide, C. Filsfils, D. Smith (Cisco), P. Mohapatra (Sproute Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 28 septembre 2021


Le RFC 8955 spécifie comment utiliser BGP pour diffuser des règles de filtrage (dites « FlowSpec ») aux routeurs. On voit facilement qu'une annonce de règles de filtrage maladroite ou malveillante pourrait faire bien des dégâts et c'est pour cela que le RFC 8955 insiste sur l'importance de valider ces annonces. Mais les règles de validation étaient trop strictes et ce nouveau RFC les adoucit légèrement.

Le changement ? Le RFC 8955 imposait que la machine qui annonce une règle de filtrage pour un préfixe de destination donné soit également le routeur suivant (next hop) pour le préfixe en question. Cela limitait l'annonce aux routeurs situés sur le trajet des données. En iBGP (BGP interne à un AS, où les routeurs qui annoncent ne sont pas toujours ceux qui transmettent les paquets), cette règle était trop restrictive. (Pensez par exemple à un réflecteur de routes interne, par exemple géré par le SOC, réflecteur qui n'est même pas forcément un routeur.)

La règle nouvelle, plus libérale, ne concerne que du iBGP, interne à un AS ou à une confédération d'AS (RFC 5065). Entre des AS gérés par des organisations différentes (par exemple un AS terminal informant son opérateur Internet de ses désirs de filtrage), la règle de validation reste inchangée.

Plus formellement, la section 6 du RFC 8955, sur la validation des annonces de filtrage, est modifiée, l'étape « l'annonceur doit être également l'annonceur de la meilleure route » devient « l'annonceur doit être l'annonceur de la meilleure route ou bien le chemin d'AS doit être vide (ou n'inclure que des AS de la confédération, s'il y en a une) ». Le RFC précise également que cette validation relâchée doit pouvoir être désactivée par l'administrateur réseaux (s'ielle sait qu'il n'y aura pas d'annonces de filtrage par un routeur qui n'est pas sur le chemin des paquets). Vous noterez plus bas que, pour l'instant, seul Huawei le permet.

Il y a également un léger changement des règles de validation du chemlin d'AS, pour les cas des serveurs de route (a priori, ils ne relaient pas ce genre d'annonces et peuvent donc les rejeter). Le RFC note que, même avec une validation stricte, certaines faiblesses de BGP permettent quand même dans certains cas à tort l'envoi de règles de filtrage. C'est un problème fondamental du RFC 8955, qui n'est donc pas nouveau.

Les nouvelles règles de ce RFC sont déjà largement mises en œuvre chez les routeurs.


Téléchargez le RFC 9117


L'article seul

RFC 9115: An Automatic Certificate Management Environment (ACME) Profile for Generating Delegated Certificates

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : Y. Sheffer (Intuit), D. López, A. Pastor Perales (Telefonica I+D), T. Fossati (ARM)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF acme
Première rédaction de cet article le 21 septembre 2021


Ce nouveau RFC décrit un profil du protocole ACME d'obtention de certificat, profil qui permet de déléguer la demande à un tiers. C'est surtout utile pour le cas où vous sous-traitez l'hébergement de votre site Web (par exemple sur un CDN) : le sous-traitant peut alors demander un certificat, avec sa clé privée à lui, pour un nom de domaine que vous contrôlez et prouver qu'il héberge bien le serveur pour ce nom. Serveurs et clients TLS n'ont pas besoin d'être modifiés (seuls les serveurs et clients ACME le seront), et, bien entendu, le titulaire du nom de domaine garde un complet contrôle et peut, par exemple, révoquer les certificats obtenus par ses sous-traitants.

Ce profil utilise lui-même le profil STAR (Short-Term, Automatically Renewed) décrit dans le RFC 8739 donc faites bien attention à avoir lu le RFC 8739 avant. Le cas typique d'utilisation de ce mécanisme de délégation est le CDN. Un webmestre (l'IdO pour Identifier Owner car il est titulaire du nom de domaine, mettons foobar.example) a un site Web et sous-traite tout ou partie du service à un CDN, appelé ici NDC pour Name Delegation Consumer (et la ressemblance entre les sigles CDN et NDC est volontaire). Le CDN devra pouvoir répondre aux requêtes HTTPS pour www.foobar.example et donc présenter un certificat au nom www.foobar.example. Avec ACME, l'IdO peut obtenir un tel certifiat mais il ne souhaite probablement pas transmettre la clé privée correspondante au NDC. La solution de notre RFC est d'utiliser une extension à ACME, permettant la délégation du nom. Le NDC pourra alors obtenir un certificat STAR (de courte durée de vie, donc) pour www.foobar.example. Pas besoin de partager une clé privée, ni de transmettre des secrets de longue durée de vie (les délégations sont révocables, et les certificats STAR ne durent pas longtemps, le NDC devra renouveller souvent et ça cessera en cas de révocation). C'est l'utilisation typique de la délégation mais d'autres sont possibles (par exemple avec des certificats ordinaires, non-STAR). Le RFC note que la solution de délégation ne modifie qu'ACME, et pas TLS, et qu'elle marche donc avec les clients et serveurs TLS actuels (contrairement à d'autres propositions qui sont étudiées).

Pour que la délégation fonctionne, l'IdO doit avoir un serveur ACME, auquel le NDC devra se connecter, et s'être mis d'accord avec le NDC sur les paramètres à utiliser. C'est donc une étape relativement nouvelle, l'utilisateur d'ACME typique n'ayant qu'un client ACME, seule l'AC a un serveur. Mais c'est quand même plus simple que de monter une AC. Le serveur ACME chez l'IdO ne signera pas de certificats, il relaiera simplement la requête. Quand le NDC aura besoin d'un certificat, il enverra une demande à l'IdO, qui la vérifiera et, devenant client ACME, l'IdO enverra une demande à l'AC. Si ça marche, l'IdO prévient le NDC, et celui-ci récupérera le certificat chez l'AC (par unauthenticated GET, RFC 8739, section 3.4).

Le protocole ACME gagne un nouveau type d'objet, les délégations, qui indiquent ce qu'on permet au NDC. Comme les autres objets ACME, elles sont représentées en JSON et voici un exemple :

{
     "csr-template": {
       "keyTypes": [
         {
           "PublicKeyType": "id-ecPublicKey",
           "namedCurve": "secp256r1",
           "SignatureType": "ecdsa-with-SHA256"
         }
       ],
       "subject": {
         "country": "FR",
         "stateOrProvince": "**",
         "locality": "**"
       },
       "extensions": {
         "subjectAltName": {
           "DNS": [
             "www.foobar.example"
           ]
         },
         "keyUsage": [
           "digitalSignature"
         ],
         "extendedKeyUsage": [
           "serverAuth"
         ]
         }
     }
}
  

(Les champs des extensions comme keyUsage sont dans un nouveau registre IANA ; on peut ajouter des champs, selon la politique « spécification nécessaire ».) Ici, le NDC est autorisé à demander des certificats ECDSA pour le nom www.foobar.example. Quand le NDC enverra sa requête de certificat à l'IdO, il devra inclure cet objet « délégation », que l'IdO pourra comparer avec ce qu'il a configuré pour ce NDC. Voici un exemple partiel, envoyé lors d'un POST HTTPS au serveur ACME de l'IdO :

   {
     "protected": base64url({
       "alg": "ES256",
       "kid": "https://acme.ido.example/acme/acct/evOfKhNU60wg",
       "nonce": "Alc00Ap6Rt7GMkEl3L1JX5",
       "url": "https://acme.ido.example/acme/new-order"
     }),
     "payload": base64url({
       "identifiers": [
         {
           "type": "dns",
           "value": "www.foobar.example"
         }
       ],
       "delegation":
         "https://acme.ido.example/acme/delegation/gm0wfLYHBen"
     }),
     "signature":    ...
  

(Le nouveau champ delegation a été placé dans le registre IANA.) Le NDC enverra ensuite le CSR, et l'IdO relaiera la requête vers le serveur ACME de l'AC (moins l'indication de délégation, qui ne regarde pas l'AC).

Quand on utilise un CDN, il est fréquent qu'on doive configurer un alias dans le DNS pour pointer vers un nom indiqué par l'opérateur du CDN. Voici par exemple celui de l'Élysée :

% dig CNAME www.elysee.fr 
...
;; ANSWER SECTION:
www.elysee.fr.		3600 IN	CNAME 3cifmt6.x.incapdns.net.
...

L'extension au protocole ACME spécifiée dans notre RFC permet au NDC d'indiquer cet alias dans sa requête, l'IdO peut alors l'inclure dans sa zone DNS.

Tous les serveurs ACME ne seront pas forcément capables de gérer des délégations, il faudra donc l'indiquer dans les capacités du serveur, avec le champ delegation-enabled (mis dans le registre IANA).

Comme indiqué plus haut, l'IdO peut arrêter la délégation quand il veut, par exemple parce qu'il change de CDN. Cet arrêt se fait par une interruption explicite de la demande STAR (RFC 8739, section 3.1.2). Si les certificats ne sont pas des STAR, le mécanisme à utiliser est la révocation normale des certificats.

Après cet examen du protocole, la section 3 de notre RFC décrit le comportement de l'AC. Il n'y a pas grand'chose à faire pour l'AC (le protocole est entre le NDC et l'IdO) à part à être capable d'accepter des récupérations non authentifiées de certificats (car le NDC n'a pas de compte à l'AC).

On a parlé plus haut du CSR. Il doit se conformer à un certain gabarit, décidé par l'IdO. Ce gabarit est évidemment au format JSON, comme le reste d'ACME. La syntaxe exacte est décrite avec le langage CDDL (RFC 8610) et figure dans l'annexe A ou bien, si vous préférez, avec le langage JSON Schema, utilisé dans l'annexe B. Voici l'exemple de gabarit du RFC :

  {
     "keyTypes": [
       {
         "PublicKeyType": "rsaEncryption",
         "PublicKeyLength": 2048,
         "SignatureType": "sha256WithRSAEncryption"
       },
       {
         "PublicKeyType": "id-ecPublicKey",
         "namedCurve": "secp256r1",
         "SignatureType": "ecdsa-with-SHA256"
       }
     ],
     "subject": {
       "country": "CA",
       "stateOrProvince": "**",
       "locality": "**"
     },
     "extensions": {
       "subjectAltName": {
         "DNS": [
           "abc.ido.example"
         ]
       },
       "keyUsage": [
         "digitalSignature"
       ],
       "extendedKeyUsage": [
         "serverAuth",
         "clientAuth"
       ]
     }
   }

Dans cet exemple, l'IdO impose au NDC un certificat RSA ou ECDSA et rend impérative (c'est le sens des deux astérisques) l'indication de la province et de la ville. L'IdO doit évidemment vérifier que le CSRT reçu se conforme bien à ce gabarit.

Le RFC présente (en section 5) quelques autres cas d'utilisation de cette délégation. Par exemple, un IdO peut déléguer à plusieurs CDN, afin d'éviter que la panne d'un CDN n'arrête tout. Avec la délégation, ça se fait tout seul, chacun des CDN est authentifié, et demande séparément son certificat.

Autre cas rigolo, celui où le CDN délègue une partie du service à un CDN plus petit. Le modèle de délégation ACME peut s'y adapter (le petit CDN demande un certificat au gros, qui relaie à l'IdO…), si les différentes parties sont d'accord.

Enfin, la section 7 du RFC revient sur les propriétés de sécurité de ces délégations. En gros, il faut avoir confiance en celui à qui on délègue car, pendant la durée de la délégation, il pourra faire ce qu'il veut avec le nom qu'on lui a délégué, y compris demander d'autres certificats en utilisant sa délégation du nom de domaine. Il existe quelques mesures techniques que l'IdO peut déployer pour empêcher le NDC de faire trop de bêtises. C'est le cas par exemple des enregistrements DNS CAA (RFC 8659) qui peuvent limiter le nombre d'AC autorisées (voir aussi le RFC 8657).

Je ne connais pas encore d'opérateur de CDN qui mette en œuvre cette solution.


Téléchargez le RFC 9115


L'article seul

RFC 9109: Network Time Protocol Version 4: Port Randomization

Date de publication du RFC : Août 2021
Auteur(s) du RFC : F. Gont, G. Gont (SI6 Networks), M. Lichvar (Red Hat)
Chemin des normes
Première rédaction de cet article le 13 septembre 2021


Le protocole NTP utilisait traditionnellement un port bien connu, 123, comme source et comme destination. Cela facilite certaines attaques en aveugle, lorsque l'attaquant ne peut pas regarder le trafic, mais sait au moins quels ports seront utilisés. Pour compliquer ces attaques, ce RFC demande que NTP utilise des numéros de ports aléatoires autant que possible.

NTP est un très vieux protocole (sa norme actuelle est le RFC 5905 mais sa première version date de 1985, dans le RFC 958). Dans son histoire, il a eu sa dose des failles de sécurité. Certaines des attaques ne nécessitaient pas d'être le chemin entre deux machines qui communiquent car elles pouvaient se faire en aveugle. Pour une telle attaque, il faut deviner un certain nombre de choses sur la communication, afin que les paquets de l'attaquant soient acceptés. Typiquement, il faut connaitre les adresses IP source et destination, ainsi que les ports source et destination et le key ID de NTP (RFC 5905, section 9.1). NTP a plusieurs modes de fonctionnement (RFC 5905, sections 2 et 3). Certains nécessitent d'accepter des paquets non sollicités et, dans ce cas, il faut bien écouter sur un port bien connu, en l'occurrence 123. Mais ce n'est pas nécessaire dans tous les cas et notre RFC demande donc qu'on n'utilise le port bien connu que si c'est nécessaire, au lieu de le faire systématiquement comme c'était le cas au début de NTP et comme cela se fait encore trop souvent (« Usage Analysis of the NIST Internet Time Service »). C'est une application à NTP d'un principe général sur l'Internet, documenté dans le RFC 6056 : n'utilisez pas de numéros de port statiques ou prévisibles. Si on suit ce conseil, un attaquant en aveugle aura une information de plus à deviner, ce qui gênera sa tâche. Le fait d'utiliser un port source fixe a valu à NTP un CVE, CVE-2019-11331.

La section 3 du RFC résume les considérations à prendre en compte. L'idée de choisir aléatoirement le port source pour faire face aux attaques en aveugle est présente dans bien d'autres RFC comme le RFC 5927 ou le RFC 4953. Elle est recommandée par le RFC 6056. Un inconvénient possible (mais mineur) est que la sélection du chemin en cas d'ECMP peut dépendre du port source (calcul d'un condensat sur le tuple à cinq élements {protocole, adresse IP source, adresse IP destination, port source, port destination}, avant d'utiliser ce condendat pour choisir le chemin) et donc cela peut affecter les temps de réponse, troublant ainsi NTP, qui compte sur une certaine stabilité du RTT. D'autre part, le port source aléatoire peut gêner certaines stratégies de filtrage par les pare-feux : on ne peut plus reconnaitre un client NTP à son port source. Par contre, un avantage du port source aléatoire est que certains routeurs NAT sont suffisamment bogués pour ne pas traduire le port source s'il fait partie des ports « système » (inférieurs à 1 024), empêchant ainsi les clients NTP situés derrière ces routeurs de fonctionner. Le port source aléatoire résout le problème.

Assez de considérations, passons à la norme. Le RFC 5905, section 9.1, est modifié pour remplacer la supposition qui était faite d'un port source fixe par la recommandation d'un port source aléatoire.

Cela ne pose pas de problème particulier de mise en œuvre. Par exemple, sur un système POSIX, ne pas faire de bind() sur la prise suffira à ce que les paquets associés soient émis avec un port source aléatoirement sélectionné par le système d'exploitation.

À propos de mise en œuvre, où en sont les logiciels actuels ? OpenNTPD n'a jamais utilisé le port source 123 et est donc déjà compatible avec la nouvelle règle. Même chose pour Chrony. Par contre, à ma connaissance, ntpd ne suit pas encore la nouvelle règle.


Téléchargez le RFC 9109


L'article seul

RFC 9108: YANG Types for DNS Classes and Resource Record Types

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : L. Lhotka (CZ.NIC), P. Spacek (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 9 septembre 2021


YANG est le langage standard à l'IETF pour décrire des modèles de données, afin de, par exemple, gérer automatiquement des ressources. Ce RFC décrit le module YANG iana-dns-class-rr-type, qui rassemble les définitions des types d'enregistrements DNS.

YANG est normalisé dans le RFC 7950, et d'innombrables RFC décrivent des modules YANG pour de nombreux protocoles. YANG est utilisé par des protocoles de gestion à distance de ressources, comme RESTCONF (RFC 8040) ou NETCONF (RFC 6241). Mais ce RFC est le premier qui va utiliser YANG pour le DNS. L'un des objectifs (à long terme pour l'instant) est d'utiliser RESTCONF ou un équivalent pour gérer des serveurs DNS, résolveurs ou serveurs faisant autorité. (C'est un très vieux projet que cette gestion automatisée et normalisée des serveurs DNS.) Un mécanisme standard de gestion des serveurs nécessite un modèle de données commun, et c'est là que YANG est utile. Notre RFC est encore loin d'un modèle complet, il ne définit que le socle, le type des données que le DNS manipule. C'est la version YANG de deux registres IANA, celui des types d'enregistrements DNS et celui des classes (même si ce dernier concept est bien abandonné aujourd'hui).

Le registre IANA pour le DNS contient treize sous-registres. Le RFC n'en passe que deux en YANG, les classes et les types d'enregistrement. Les autres devront attendre un autre RFC. Les types d'enregistrement sont modélisés ainsi :

typedef rr-type-name {
    type enumeration {
      enum A {
        value 1;
        description
          "a host address";
        reference
          "RFC 1035";
      }
      enum NS {
        value 2;
        description
          "an authoritative name server";
...
  

Et les classes (mais, rappelez-vous, seule la classe IN compte aujourd'hui) :

typedef dns-class-name {
    type enumeration {
      enum IN {
        value 1;
        description
          "Internet (IN)";
        reference
          "RFC 1035";
      }
      enum CH {
        value 3;
        description
          "Chaos (CH)";
        reference
          "D. Moon, 'Chaosnet', A.I. Memo 628, Massachusetts Institute of
Technology Artificial Intelligence Laboratory, June 1981.";
}
...
  

Le module YANG complet se retrouve dans le registre IANA (créé par le RFC 6020).

Le module YANG devra suivre l'actuel registre IANA, qui utilise un autre format. Pour faciliter la synchronisation, le RFC contient une feuille de style XSLT pour convertir l'actuel format, qui est la référence, vers le format YANG. La feuille de style est dans l'annexe A du RFC mais vous avez une copie ici. Voici comment produire et vérifier le module YANG :

% wget https://www.iana.org/assignments/dns-parameters/dns-parameters.xml

% xsltproc iana-dns-class-rr-type.xsl dns-parameters.xml > iana-dns-class-rr-type.yang

% pyang iana-dns-class-rr-type.yang
  

Le moteur XSLT xsltproc fait partie de la libxslt. Le vérificateur YANG Pyang est distribué via GitHub mais on peut aussi l'installer avec pip (pip install pyang).


Téléchargez le RFC 9108


L'article seul

RFC 9107: BGP Optimal Route Reflection (BGP ORR)

Date de publication du RFC : Août 2021
Auteur(s) du RFC : R. Raszuk (NTT Network Innovations), B. Decraene (Orange), C. Cassar, E. Aman, K. Wang (Juniper Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 13 septembre 2021


Les grands AS ont tellement de routeurs BGP qu'ils ne peuvent pas connecter chaque routeur à tous les autres. On utilise alors souvent des réflecteurs de route, un petit nombre de machines parlant BGP auxquelles tout le monde se connecte, et qui redistribuent les routes externes apprises. Mais une machine BGP ne redistribue que les routes qu'elle utiliserait elle-même. Or, le réflecteur risque de faire un choix en fonction de sa position dans le réseau, qui n'est pas la même que celle du routeur « client ». Les routeurs risquent donc d'apprendre du réflecteur des routes sous-optimales (la route optimale étant typiquement celle qui amène à la sortie le plus vite possible, en application de la méthode de la patate chaude). Ce RFC définit une extension de BGP qui va permettre de sélectionner des routes spécifiques à un client, ou à un groupe de clients.

Un petit rappel : un réflecteur de routes (route reflector) fonctionne sur iBGP (Internal BGP), à l'intérieur d'un AS, alors que les serveurs de routes (route server) font de l'eBGP (External BGP), par exemple sur un point d'échange. Ces réflecteurs sont décrits dans le RFC 4456. Ils ne sont pas la seule méthode pour distribuer l'information sur les routes externes à l'intérieur d'un grand AS, mais c'est quand même la solution la plus fréquente.

Le RFC 4456 notait déjà que, vu les coûts attribués aux liens internes à l'AS, le réflecteur ne choisirait pas forcément les mêmes routes que si on avait utilisé un maillage complet. Le routage « de la patate chaude » (qui consiste à essayer de faire sortir le paquet de son réseau le plus vite possible, pour que ce soit un autre qui l'achemine) risque donc de ne pas aussi bien marcher : le point de sortie lorsqu'on utilise le réflecteur sera peut-être plus éloigné que si on avait le maillage complet, surtout si le réflecteur est situé en dehors du chemin habituel des paquets et n'a donc pas la même vision que les routeurs « normaux ». Or, c'est un cas fréquent. Le réflecteur choisira alors des routes qui sont optimales pour lui, mais qui ne le sont pas pour ces routeurs « normaux ».

La solution ? Permettre à l'administrateur réseaux de définir une localisation virtuelle pour le réflecteur, à partir de laquelle il fera ses calculs et choisira ses routes, au lieu d'utiliser sa localisation physique. Cette localisation virtuelle sera une adresse IP. Le réflecteur peut avoir plusieurs de ces localisations virtuelles, adaptées à des publics différents. Bref, le texte du RFC 4271 qui concerne la sélection de la meilleure route (section 9.1.2.2 du RFC 4271) est modifié pour remplacer « en fonction du saut suivant » par « en fonction de l'adresse IP configurée dans le réflecteur ».

Pour que cela marche, il faut que le réflecteur ait une vue complète du réseau, pour pouvoir calculer des coûts à partir de n'importe quel point du réseau. C'est possible avec les IGP à état des liens comme OSPF, ou bien avec BGP-LS (RFC 7752).

Et si le réflecteur a plusieurs clients ayant des desiderata différents, par exemple parce qu'ils sont situés à des endroits différents ? Dans ce cas, il doit faire tourner plusieurs processus de décision, chacun configuré avec une localisation vituelle différente.

Les principales marques de routeurs mettent déjà en œuvre ce RFC, comme on peut le voir sur la liste des implémentations. Du côté des logiciels qui ne sont pas forcément installés sur des routeurs, il semble que BIRD ne sache pas encore faire comme décrit dans ce RFC.


Téléchargez le RFC 9107


L'article seul

RFC 9106: Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : A. Biryukov, D. Dinu (University of Luxembourg), D. Khovratovich (ABDK Consulting), S. Josefsson (SJD AB)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF cfrg
Première rédaction de cet article le 8 septembre 2021


En général, en informatique, on essaie de diminuer la consommation de mémoire et de processeur des programmes, afin de les rendre plus efficaces. Mais il y a aussi des cas où on va tenter de réduire délibérement l'efficacité d'un programme. C'est le cas des fonctions de condensation qui sont utilisées en sécurité : on ne veut pas faciliter la tâche de l'attaquant. Ainsi, Argon2, spécifié dans ce RFC est volontairement très consommatrice de mémoire et d'accès à cette mémoire. Elle peut être utilisée pour condenser des mots de passe, ou pour des sytèmes à preuve de travail.

L'article original décrivant Argon2 est « Argon2: the memory-hard function for password hashing and other applications » et vous pouvez également lire « Argon2: New Generation of Memory-Hard Functions for Password Hashing and Other Applications ». Notre RFC reprend la description officielle, mais en s'orientant davantage vers les programmeurs et programmeuses qui devront mettre en œuvre cette fonction. Argon2 est conçu pour être memory-hard, c'est-à-dire faire souvent appel à la mémoire de la machine. Cela permet notamment aux ordinateurs classiques de tenir tête aux systèmes à base d'ASIC. (Par exemple, nombreuses sont les chaînes de blocs utilisant des preuves de travail. La fonction utilisée par Bitcoin, SHA-256, conçue pour être simple et rapide, n'est pas memory-hard et le résultat est qu'il y a belle lurette qu'un ordinateur, même rapide, n'a plus aucune chance dans le minage de Bitcoin. Seules les machines spécialisées peuvent rester en course, ce qui contribue à centraliser le minage dans peu de fermes de minage.) Argon2 est donc dur pour la mémoire, comme décrit dans l'article « High Parallel Complexity Graphs and Memory-Hard Functions ». À noter qu'Argon2 est très spécifique à l'architecture x86.

Argon2 se décline en trois variantes, Argon2id (celle qui est recommandée par le RFC), Argon2d et Argon2i. Argon2d a des accès mémoire qui dépendent des données, ce qui fait qu'il ne doit pas être employé si un attaquant peut examiner ces accès mémoire (attaque par canal auxiliaire). Il convient donc pour du minage de cryptomonnaie mais pas pour une carte à puce, que l'attaquant potentiel peut observer en fonctionnement. Argon2i n'a pas ce défaut mais est plus lent, ce qui ne gêne pas pour la condensation de mots de passe mais serait un problème pour le minage. Argon2id, la variante recommandée, combine les deux et est donc à la fois rapide et résistante aux attaques par canal auxiliaire. (Cf. « Tradeoff Cryptanalysis of Memory-Hard Functions », pour les compromis à faire en concevant ces fonctions dures pour la mémoire.) Si vous hésitez, prenez donc Argon2id. La section 4 du RFC décrit plus en détail les paramètres des variantes, et les choix recommandés.

Argon repose sur une fonction de condensation existante (qui n'est pas forcément dure pour la mémoire) et le RFC suggère Blake (RFC 7693).

La section 3 du RFC décrit l'algorithme mais je n'essaierai pas de vous le résumer, voyez le RFC.

La section 5 contient des vecteurs de test si vous voulez programmer Argon2 et vérifier les résultats de votre programme.

La section 7 du RFC revient en détail sur certaines questions de sécurité, notamment l'analyse de la résistance d'Argon2, par exemple aux attaques par force brute.


Téléchargez le RFC 9106


L'article seul

RFC 9103: DNS Zone Transfer over TLS

Date de publication du RFC : Août 2021
Auteur(s) du RFC : W. Toorop (NLnet Labs), S. Dickinson (Sinodun IT), S. Sahib (Brave Software), P. Aras, A. Mankin (Salesforce)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 12 septembre 2021


Traditionnellement, le transfert d'une zone DNS depuis le serveur maitre vers ses esclaves se fait en clair. Si l'authentification et l'intégrité sont protégées, par exemple par TSIG, le transfert en clair ne fournit pas de confidentialité. Or on n'a pas forcément envie qu'un tiers puisse lire l'entièreté de la zone. Ce RFC normalise un transfert de zones sur TLS, XoT (zone transfer over TLS). Il en profite pour faire quelques ajustement dans l'utilisation de TCP pour les transferts de zone.

Le RFC fait quarante-deux pages mais le principe est très simple. Au lieu de faire le transfert de zones (aussi nommé AXFR, RFC 5936) directement sur TCP, on le fait sur du TLS, comme le fait DoT (RFC 7858). Le reste du RFC est consacré à des détails pratiques, mais le concept tient en une seule phrase.

Le DNS sur TLS est normalisé depuis cinq ans, mais il ne couvre officiellement que la communication entre la machine terminale et le résolveur. Bien que des essais aient été faits pour communiquer en TLS avec des serveurs faisant autorité, rien n'est encore normalisé. Mais, au fait, est-ce que les transferts de zone ont vraiment besoin de confidentialité ? Le RFC 9076 ne traite pas le problème, le renvoyant aux RFC 5936 (la norme du transfert de zones, qui parle de la possibilité de restreindre ce transfert à des machines autorisées) et au RFC 5155 (qui parle des risques d'énumération de tous les noms d'une zone). Certes, le DNS étant public, tout le monde peut interroger les serveurs faisant autorité, et connaitre ainsi les données associées à un nom de domaine, mais il faut pour cela connaitre les noms. Si les petites zones n'ont rien de secret (elles ne contiennent que l'apex et www), si certaines zones sont publiques (la racine, par exemple), pour les autres zones, leur responsable ne souhaite pas forcément qu'on ait accès à tous les noms. Certains peuvent être le nom d'une personne (le-pc-de-henri.zone.example), et donc être des données personnelles, à protéger (le RFC note bien sûr que c'est une mauvaise pratique, mais elle existe), certains noms peuvent renseigner sur les activités et les projets d'une entreprise. Bref, il peut être tout à fait raisonnable de ne pas vouloir transmettre la zone en clair.

À noter qu'une surveillance du réseau pendant un transfert de zones fait en clair n'est pas la seule façon de trouver tous les noms. Une autre technique est l'énumération, utilisant par exemple les enregistrement NSEC de DNSSEC. Les enregistrement NSEC3 du RFC 5155 ont été conçus pour limiter ce risque (mais pas le supprimer ; le projet NSEC5 va essayer de résoudre le problème mais c'est loin d'être garanti).

Comment sécurise-t-on les transferts de zone aujourd'hui ? Les TSIG du RFC 8945 protègent l'intégrité mais pas la confidentialité. Vous pouvez trouver des détails pratiques sur la sécurisation des transferts de zone, combinant TSIG et ACL, dans un document du NIST en anglais et un document de l'ANSSI en français. On peut aussi en théorie utiliser IPsec entre maitre et esclaves mais cela semble irréaliste. D'où l'idée de base de ce nouveau RFC : mettre le transfert de zones sur TLS. Après tout, on utilise déjà TLS pour sécuriser la communication entre le client final et le résolveur : le protocole DoT, normalisé dans le RFC 7858.

Notre RFC introduit quelques nouveaux acronymes rigolos :

  • XFR : couvre à la fois AXFR (RFC 5936) et IXFR (transferts incrémentaux, RFC 1995). Donc, XFR-over-TLS, c'est un transfert de zones, complet ou incrémental, sur TLS.
  • XoT : acronyme pour XFR-over-TLS.
  • AXoT : AXFR sur TLS.
  • IXoT : IXFR sur TLS.

Pour la terminologie liée à la vie privée, voir le RFC 6973.

La section 3 du RFC spécifie le modèle de menace : on veut protéger le transfert de zones contre l'espionnage par un tiers, mais on n'essaie pas de cacher l'existence de la zone, ou le fait que telle machine soit serveur faisant autorité pour la zone. En effet, ces informations peuvent être obtenues facilement en interrogeant le DNS ou, dans le cas d'un maitre caché, en regardant le trafic réseau, sans même en décrypter le contenu.

Les principes de conception de XoT ? Fournir de la confidentialité et de l'authentification grâce à TLS, mais aussi en profiter pour améliorer les performances. Un certain nombre de programmes DNS ne peuvent pas, par exemple, utiliser la même connexion TCP pour plusieurs transferts de zone (même si le RFC 5936 le recommande). Il est difficile de résoudre ce problème sans casser les programmes existants et pas encore mis à jour. Par contre, XoT étant nouveau, il peut spécifier dès le début certains comportements qui améliorent les performances, comme l'utilisation d'une seule connexion pour plusieurs transferts.

Petit rappel de comment fonctionne le transfert de zones (RFC 5936, si vous voulez tous les détails). D'abord, le fonctionnement le plus courant : le serveur maitre (ou primaire) envoie un NOTIFY (RFC 1996) à ses esclaves (ou secondaires). Ceux-ci envoient une requête de type SOA au maitre puis, si le numéro de série récupéré est supérieur au leur, ils lancent l'AXFR sur TCP. Il y a des variations possibles : si le maitre n'envoie pas de NOTIFY ou bien s'ils sont perdus, les esclaves testent quand même de temps en temps le SOA (paramètre Refresh du SOA). Autre variante possible : les esclaves peuvent utiliser IXFR (RFC 1995) au lieu de AXFR pour ne transférer que la partie de la zone qui a changé. Et ils peuvent avoir à se rabattre en AXFR si le maitre ne gérait pas IXFR. Et les messages IXFR peuvent être sur UDP ou sur TCP (en pratique, BIND, NSD et bien d'autres font toujours l'IXFR sur TCP). Bref, il y a plusieurs cas. Les messages NOTIFY et SOA ne sont pas considérés comme sensibles du point de vue de la confidentialité et XoT ne les protège pas.

Maintenant, avec XoT, comment ça se passera (section 6 du RFC) ? Une fois le transfert de zones décidé (via SOA, souvent précédé du NOTIFY), le client (qui est donc le serveur secondaire) doit établir une connexion TLS (1.3 minimum), en utilisant ALPN, avec le nom dot (on notera que c'est donc le même ALPN pour XoT et pour DoT, l'annexe A du RFC explique ce choix). Le port est par défaut le classique 853 de DoT. Le client authentifie le serveur via les techniques du RFC 8310. Le serveur vérifie le client, soit avec des mécanismes TLS (plus sûrs mais plus compliqués à mettre en œuvre), soit avec les classiques ACL. Le client TLS (le serveur DNS esclave) fait ensuite de l'IXFR ou du AXFR classique sur ce canal TLS. Le serveur doit être capable d'utiliser les codes d'erreur étendus du RFC 8914.

Voilà, c'est tout. Maintenant, quelques détails pratiques. D'abord, rappelez-vous qu'il n'existe pas à l'heure actuelle de norme pour du DoT entre résolveur et serveur faisant autorité. Mais il y a des expériences en cours. Ici, par exemple, je fais du DoT avec un serveur faisant autorité pour facebook.com :

% kdig +tls @a.ns.facebook.com.  SOA facebook.com   
;; TLS session (TLS1.3)-(ECDHE-X25519)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
...
;; ANSWER SECTION:
facebook.com.       	3600	IN	SOA	a.ns.facebook.com. dns.facebook.com. 1631273358 14400 1800 604800 300

;; Received 86 B
;; Time 2021-09-10 13:35:44 CEST
;; From 2a03:2880:f0fc:c:face:b00c:0:35@853(TCP) in 199.0 ms

Mais on pourrait imaginer des serveurs faisant autorité qui ne fournissent pas ce service, pas encore normalisé, mais qui veulent faire du XoT. Est-ce possible de réserver TLS aux transferts de zone, mais sans l'utiliser pour les requêtes « normales » ? Oui, et dans ce cas le serveur doit répondre REFUSED à ces requêtes normales, avec le code d'erreur étendu 21 (Not supported). Ceci dit, il est difficile de dire comment réagiront les clients ; ils risquent d'ignorer le code d'erreur étendu et de recommencer bêtement (ou au contraire d'arrêter complètement d'utiliser le serveur).

Le but de XoT est de protéger le contenu de la zone contre les regards indiscrets. Mais comme vous le savez, TLS ne dissimule pas la taille des données qui passent entre ses mains et l'observation de cette taille peut donner des informations à un observateur, par exemple la taille des mises à jour en IXFR indique l'activité d'une zone. Le RFC suggère donc de remplir les données. Cela peut nécessiter d'envoyer des réponses vides, ce qui était interdit par les précédents RFC mais est maintenant autorisé.

Et les différentes formes de parallélisme des requêtes que permet le DNS sur TCP (et donc DoT) ? Elles sont décrites dans le RFC 7766. Si elles sont nécessaires pour exploiter le DNS de manière satisfaisante, elles ne sont pas forcément utiles pour XoT et notre RFC explique qu'on n'est pas forcé, par exemple, de permettre le pipelining (envoi d'une nouvelle requête quand la réponse à la précédente n'est pas encore arrivée) quand on fait du XoT. Par contre, comme avec tous les cas où on utilise du DNS sur TCP, il est recommandé de garder les connexions ouvertes un certain temps, par exemple en suivant le RFC 7828.

J'ai parlé plus haut de l'authentification dans une session XoT. La section 9 du RFC revient en détail sur cette question. Quels sont les mécanismes existants pour authentifier un transfert de zones ? Ils diffèrent par les services qu'ils rendent :

  • Authentification de la source des données DNS.
  • Authentification du correspondant (qui n'est pas forcément la source des données).
  • Confidentialité.

Les mécanismes possibles sont :

  • TSIG (RFC 8945) ; utiisant des clés partagées (ce qui n'est pas pratique), il permet d'authentifier la source des données.
  • SIG(0) (RFC 2931) ; utilisant de la cryptographie asymétrique, il permet d'authentifier la source des données. Ceci dit, il n'est quasiment jamais mis en œuvre dans les programmes DNS.
  • TLS en mode « opportuniste » (sans authentification) ; il ne garantit rien, sauf peut-être contre un observateur passif.
  • TLS en mode strict (obligation d'authentification du serveur par le client, RFC 8310) ; cela permet l'authentification du correspondant, et la confidentialité (mais ne garantit pas que le correspondant est la vraie source des données).
  • TLS mutuel ; le client s'authentifie également.
  • ACL fondées sur l'adresse IP ; très répandu, ce mécanisme permet au serveur d'« authentifier » le client. Une faiblesse pour le cas de XoT : le serveur doit accepter l'établissement de la session TLS avant de savoir s'il s'agit de XoT ou de DNS ordinaire sur TLS.
  • ZONEMD (RFC 8976) ; ce n'est pas vraiment une technique d'authentification mais elle peut être utile, en combinaison avec XoT.

Quelles sont les mises en œuvres actuelles de XoT ? Une liste existe. Actuellement, il n'y a guère que NSD qui permet le XoT mais le travail est en cours pour d'autres. Voyons comment faire du XoT avec NSD. On télécharge la dernière version (XoT est apparu en 4.3.7), on la compile (pas besoin d'options particulières) et on la configure, par exemple ainsi :

server:
       port: 7053
       ...
       tls-service-key: "server.key"
       tls-service-pem: "server.pem"
       # No TLS service if the port is not explicit in an interface definition
       ip-address: 127.0.0.1@7153
       tls-port: 7153

zone:
        name: "fx"
        zonefile: "fx"
	# NSD 4.3.7 (september 2021) : not yet a way to restrict XoT
        provide-xfr: 127.0.0.1 NOKEY 
  

Ainsi configuré, NSD va écouter sur le port 7153 en TLS. Notons qu'il n'y a pas de moyen de configurer finement : il accepte forcément XoT et les requêtes « normales ». De même, on ne peut pas obliger un client DNS à n'utiliser que XoT. Testons avec kdig, un client DNS qui accepte TLS, d'abord une requête normale :

    
% kdig +tls @localhost -p 7153 SOA fx 
;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 11413
...
;; ANSWER SECTION:
fx.                 	600	IN	SOA	ns1.fx. root.fx. 2021091201 604800 86400 2419200 86400
...
;; Time 2021-09-12 11:06:39 CEST
;; From 127.0.0.1@7153(TCP) in 0.2 ms

  

Parfait, tout marche. Et le transfert de zones ?


% kdig +tls @localhost -p 7153 AXFR fx
;; AXFR for fx.
fx.                 	600	IN	SOA	ns1.fx. root.fx. 2021091201 604800 86400 2419200 86400
...
;; Received 262 B (1 messages, 9 records)
;; Time 2021-09-12 11:07:25 CEST
;; From 127.0.0.1@7153(TCP) in 2.3 ms

  

Excellent, nous faisons du XoT. Wireshark nous le confirme :

% tshark -d tcp.port==7153,tls -i lo port 7153
...
4 0.001200185    127.0.0.1 → 127.0.0.1    TLSv1 439 Client Hello
...
6 0.006305031    127.0.0.1 → 127.0.0.1    TLSv1.3 1372 Server Hello, Change Cipher Spec, Application Data, Application Data, Application Data, Application Data
...
10 0.007385823    127.0.0.1 → 127.0.0.1    TLSv1.3 140 Application Data
  

Dans ce cas, on utilisait NSD comme serveur primaire, recevant les clients XoT. Il peut aussi fonctionner comme serveur secondaire et il est alors client XoT. Je n'ai pas testé mais John Shaft l'a fait et en gros la configuration ressemble à :

tls-auth:
   name: un-nom-pour-identifier-ce-bloc
   auth-domain-name: nom-du-serveur-principal
zone:
   ...
   request-xfr: AXFR 2001:db8::1 NOKEY un-nom-pour-identifier-ce-bloc
  

Téléchargez le RFC 9103


L'article seul

RFC 9102: TLS DNSSEC Chain Extension

Date de publication du RFC : Août 2021
Auteur(s) du RFC : V. Dukhovni (Two Sigma), S. Huque (Salesforce), W. Toorop (NLnet Labs), P. Wouters (Aiven), M. Shore (Fastly)
Expérimental
Première rédaction de cet article le 12 août 2021


Lorsqu'on authentifie un serveur TLS (par exemple un serveur DoT) avec DANE, le client TLS doit utiliser un résolveur DNS validant et tenir compte de son résultat (données validées ou pas), ce qui n'est pas toujours facile, ni même possible dans certains environnements. Ce RFC propose une solution pour cela : une extension à TLS, dnssec_chain, qui permet au serveur TLS d'envoyer l'ensemble des enregistrements DNS pertinents au client, le dispensant ainsi de solliciter un résolveur validant. Toute la cuisine de vérification peut ainsi se faire sans autre canal que TLS.

TLS (normalisé dans les RFC 5246 et RFC 8446) fournit un canal de communication sécurisé, si on a authentifié le serveur situé en face. La plupart du temps, on authentifie via un certificat PKIX (RFC 5280). Dans certains cas, ce n'est pas facile d'utiliser PKIX. Par exemple, pour DoT (RFC 7858), le résolveur DoT n'est typiquement connu que par une adresse IP, alors que le certificat ne contient en général qu'un nom (oui, le RFC 8738 existe, mais n'est pas toujours activé par les autorités de certification). Les serveurs DoT sont souvent authentifiables par DANE (RFC 6698 et RFC 7671). Par exemple, mon résolveur DoT public, dot.bortzmeyer.fr, est authentifiable avec DANE (regardez les données TLSA de _853._tcp.dot.bortzmeyer.fr). Mais DANE dépend de la disponibilité d'un résolveur DNS validant. Diverses raisons font que le client TLS peut avoir du mal à utiliser un résolveur validant, et à récupérer l'état de la validation (toutes les API de résolution de noms ne donnent pas accès à cet état). L'article « Discovery method for a DNSSEC validating stub resolver » donne des informations sur ces difficultés. Bref, devoir récupérer ces enregistrements DANE de manière sécurisée peut être un problème. Et puis utiliser le DNS pour récupérer des données permettant d'authentifier un résolveur DNS pose un problème d'œuf et de poule.

D'où l'idée centrale de ce RFC : le client TLS demande au serveur de lui envoyer ces enregistrements. Le client n'a plus « que » à les valider à partir d'une clé de confiance DNSSEC (typiquement celle de la racine, commune à tout le monde). Le serveur peut aussi, s'il n'utilise pas DANE, renvoyer la preuve de non-existence de ces enregistrements, le client saura alors, de manière certaine, qu'il peut se rabattre sur un autre mécanisme d'authentification. L'extension TLS de notre RFC peut servir à authentifier un certificat complet, ou bien une clé brute (RFC 7250). Dans ce dernier cas, cette extension protège en outre contre les attaques dites « Unknown Key-Share ».

Notez le statut de ce RFC : cette spécification est pour l'instant expérimentale, elle n'a pas vraiment réuni de consensus à l'IETF, mais elle fait partie des solutions proposées pour sécuriser DoT, dans le RFC 8310 (section 8.2.2).

Bon, maintenant, l'extension elle-même (section 2). C'est une extension TLS (ces extensions sont spécifiées dans la section 4.2 du RFC 8446), elle est nommée dnssec_chain et enregistrée dans le registre IANA, avec le code 59. Son champ de données (extension_data) vaut, dans le ClientHello, le port de connexion et, dans le ServerHello, un ensemble d'enregistrements DNS au format binaire du DNS (pour TLS 1.2 ; en 1.3, cet ensemble est attaché au certificat du serveur). Dans le langage de description des données TLS, cela donne, du client vers le serveur :

struct {
    uint16 PortNumber;
} DnssecChainExtension;
  

Et du serveur vers le client :

struct {
    uint16 ExtSupportLifetime;
    opaque AuthenticationChain<1..2^16-1>
} DnssecChainExtension;    
  

(Le ExtSupportLifetime indique que le serveur s'engage à continuer à gérer cette extension pendant au moins ce temps - en heures. Si ce n'est plus le cas avant l'expiration du délai, cela peut indiquer une usurpation par un faux serveur.) Cette extension est donc une forme, assez spéciale, de « DNS sur TLS ». Le client ne doit pas oublier d'envoyer un SNI (RFC 6066), pour que le serveur sache quel nom va être authentifié et donc quels enregistrements DNS renvoyer. Quant au serveur, s'il ne gère pas cette extension, il répond au client avec un ServerHello n'ayant pas l'extension dnssec_chain. Même chose si le serveur accepte l'extension mais, pour une raison ou pour une autre, n'a pas pu rassembler tous les enregistrements DNS.

Et pourquoi le client doit-il indiquer le port auquel il voulait se connecter ? Le serveur le connait, non ? Mais ce n'est pas forcément le cas, soit parce qu'il y a eu traduction de port quelque part sur le chemin, soit parce que le client a été redirigé, par exemple via le type d'enregistrement SVCB. Le port indiqué par le client doit être le port original, avant toute traduction ou redirection.

Revenons à la « chaine », l'ensemble d'enregistrements DNS qui va permettre la validation DANE. Le format est le format binaire habituel du DNS, décrit dans le RFC 1035, section 3.2.1. L'utilisation de ce format, quoiqu'il soit inhabituel dans le monde TLS, permet, entre autres avantages, l'utilisation des bibliothèques logicielles DNS existantes. Le RFC recommande d'inclure dans l'ensemble d'enregistrements une chaine complète, y compris la racine et incluant donc les clés DNSSEC de celle-ci (enregistrements DNSKEY), même si le client les connait probablement déjà. Cela donne par exemple la chaine suivante, pour le serveur www.example.com écoutant sur le port 443. Notez qu'on inclut les signatures (RRSIG) :

  • _443._tcp.www.example.com TLSA
  • RRSIG(_443._tcp.www.example.com TLSA)
  • example.com. DNSKEY
  • RRSIG(example.com DNSKEY)
  • example.com DS
  • RRSIG(example.com DS)
  • com DNSKEY
  • RRSIG(com DNSKEY)
  • com DS
  • RRSIG(com DS)
  • . DNSKEY
  • RRSIG(. DNSKEY)

(L'exemple suppose que _443._tcp.www.example.com et example.com sont dans la même zone.) Voilà, avec tous ces enregistrements, le client peut, sans faire appel à un résolveur DNS validant, vérifier (s'il a confiance dans la clé de la racine) l'authenticité de l'enregistrement DANE (type TLSA) et donc le certificat du serveur. De la même façon, si on n'a pas d'enregistrement TLSA, le serveur peut envoyer les preuves de non-existence (enregistrements NSEC ou NSEC3). Bon, évidemment, dans ce cas, c'est moins utile, autant ne pas gérer l'extension dnssec_chain… Face à ce déni, le client TLS n'aurait plus qu'à se rabattre sur une autre méthode d'authentification.

Le serveur TLS construit la chaine des enregistrements comme il veut, mais pour l'aider, la section 3 du RFC fournit une procédure possible, à partir d'interrogations du résolveur de ce serveur. Une autre possibilité, plus simple pour le serveur, serait d'utiliser les requêtes chainées du RFC 7901 (mais qui n'ont pas l'air très souvent déployées aujourd'hui).

Comme tous les enregistrements DNS, ceux inclus dans l'extension TLS dnssec_chain ont une durée de vie. Et les signatures DNSSEC ont une période de validité (en général plus longue que la durée de vie). Le serveur TLS qui construit l'ensemble d'enregistrements qu'il va renvoyer peut donc mémoriser cet ensemble, dans la limite du TTL et de l'expiration des signatures DNSSEC. Le client TLS peut lui aussi mémoriser ces informations, dans les mêmes conditions.

On a vu plus haut que les données de l'extension TLS incluaient un ExtSupportLifetime qui indiquait combien de temps le client pouvait s'attendre à ce que le serveur TLS continue à gérer cette extension. Car le client peut épingler (pinning) cette information. Cela permet de détecter certaines attaques (« ce serveur gérait l'extension dnssec_chain et ce n'est maintenant plus le cas ; je soupçonne un détournement vers un serveur pirate »). Cet engagement du serveur est analogue au HSTS de HTTPS (RFC 6797) ; dans les deux cas, le serveur s'engage à rester « sécurisé » pendant un temps minimum (mais pas infini, car on doit toujours pouvoir changer de politique). À noter que « gérer l'extension dnssec_chain » n'est pas la même chose que « avoir un enregistrement TLSA », on peut accepter l'extension mais ne pas avoir de données à envoyer (il faudra alors envoyer la preuve de non-existence mentionnée plus haut). Bien sûr, le client TLS est libre de sa politique. Il peut aussi décider d'exiger systématiquement l'acceptation de l'extension TLS dnssec_chain (ce qui, aujourd'hui, n'est réaliste que si on ne parle qu'à un petit nombre de serveurs).

Si un serveur gérait l'extension dnssec_chain mais souhaite arrêter, il doit bien calculer son coup : d'abord réduire ExtSupportLifetime à zéro puis attendre que la durée annoncée dans le précédent ExtSupportLifetime soit écoulée, afin que tous les clients aient arrêté de l'épingler comme serveur à dnssec_chain. Il peut alors proprement stopper l'extension (cf. section 10 du RFC).

Un petit problème se pose si on fait héberger le serveur TLS chez un tiers. Par exemple, imaginons que le titulaire du domaine boulanger.example ait un serveur chez la société JVL (Je Vous Loge) et que server.boulanger.example soit un alias (enregistrement de type CNAME) vers clients.jvl.example. Le client TLS va envoyer server.boulanger.example comme SNI. Il ne sera pas pratique du tout pour JVL de coordonner la chaine d'enregistrements DNS et le certificat. Il est donc conseillé que l'enregistrement TLSA du client soit lui aussi un alias vers un enregistrement TLSA de l'hébergeur. Cela pourrait donner (sans les signatures, pour simplifier la liste) :

  • server.boulanger.example CNAME (vers clients.jvl.example)
  • _443._tcp.server.boulanger.example CNAME (vers _dane443.node1.jvl.example)
  • clients.jvl.example AAAA
  • _dane443.node1.jvl.example TLSA

Les deux premiers enregistrements sont gérés par l'hébergé, les deux derniers par l'hébergeur. (La section 9 du RFC explique pourquoi l'enregistrement TLSA de l'hébergeur n'est pas en _443._tcp…)

Comme dit plus haut, le client TLS est maitre de sa politique : il peut exiger l'extension TLS, il peut l'accepter si elle existe, il peut l'ignorer. Si l'authentification par DANE échoue mais que celle par PKIX réussit, ou le contraire, c'est au client TLS de décider, en fonction de sa politique, ce qu'il fait.

Est-ce que le serveur TLS qui gère cette extension doit envoyer la chaine complète de certificats ? S'il veut pouvoir également être identifié avec PKIX, oui. Si non, s'il se contente de DANE et plus précisément de DANE-EE ou DANE-TA (ces deux termes sont définis dans le RFC 7218), il peut envoyer uniquement le certificat du serveur (pour DANE-EE).

Question mise en œuvre, l'excellente bibliothèque ldns a (je n'ai pas testé…) tout ce qu'il faut pour générer et tester ces chaines d'enregistrements DNS. Si vous voulez développer du code pour gérer cette extension, l'annexe A du RFC contient des vecteurs de test qui vous seront probablement bien utiles.


Téléchargez le RFC 9102


L'article seul

RFC 9099: Operational Security Considerations for IPv6 Networks

Date de publication du RFC : Août 2021
Auteur(s) du RFC : E. Vyncke (Cisco), K. Chittimaneni (Square), M. Kaeo (Double Shot Security), E. Rey (ERNW)
Pour information
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 7 septembre 2021


Tous les gens qui gèrent des réseaux IPv4 savent comment les sécuriser (normalement…). Et pour IPv6 ? Si ce n'est pas un protocole radicalement différent, il a quand même quelques particularités de sécurité. Ce RFC donne des conseils pratiques et concrets sur la sécurisation de réseaux IPv6. (Je le répète, mais c'est juste une nouvelle version d'IP : l'essentiel du travail de sécurisation est le même en v4 et en v6.)

Les différences entre IPv4 et IPv6 sont subtiles (mais, en sécurité, la subtilité compte, des petits détails peuvent avoir de grandes conséquences). Ceci dit, le RFC a tendance à les exagérer. Par exemple, il explique que la résolution d'adresses de couche 3 en adresses de couche 2 ne se fait plus avec ARP (RFC 826) mais avec NDP (RFC 4861). C'est vrai, mais les deux protocoles fonctionnent de manière très proche et ont à peu près les mêmes propriétés de sécurité (en l'occurrence, aucune sécurité). Plus sérieusement, le remplacement d'un champ d'options de taille variable dans IPv4 par les en-têtes d'extension d'IPv6 a certainement des conséquences pour la sécurité. Le RFC cite aussi le cas du NAPT (Network Address and Port Translation, RFC 2663). Souvent appelée à tort NAT (car elle ne traduit pas que l'adresse mais également le port), cette technique est très utilisée en IPv4. En IPv6, on ne fait pas de traduction ou bien on fait du vrai NAT, plus précisement du NPT (Network Prefix Translation, RFC 6296) puisqu'on change le préfixe de l'adresse. La phrase souvent entendue « en IPv6, il n'y a pas de NAT » est doublement fausse : c'est en IPv4 qu'on n'utilise pas le NAT, mais le NAPT, et on peut faire de la traduction d'adresses en IPv6 si on veut. NAT, NAPT ou NPT ne sont évidemment pas des techniques de sécurité mais elles peuvent avoir des conséquences pour la sécurité. Par exemple, toute traduction d'adresse va complexifier le réseau, ce qui introduit des risques. Autre facteur nouveau lié à IPv6 : la plupart des réseaux vont devoir faire de l'IPv4 et de l'IPv6 et les différentes techniques de coexistence de ces deux versions peuvent avoir leur propre impact sur la sécurité (RFC 4942).

La section 2 du RFC est le gros morceau du RFC ; c'est une longue liste de points à garder en tête quand on s'occupe de la sécurité d'un réseau IPv6. Je ne vais pas tous les citer, mais en mentionner quelques-uns qui donnent une bonne idée du travail du ou de la responsable de la sécurité.

D'abord, l'adressage. Aux débuts d'IPv6, l'idée était que les spécificités d'IPv6 comme le SLAAC allaient rendre la renumérotation des réseaux tellement triviale qu'on pourrait changer les adresses souvent. En pratique, ce n'est pas tellement le cas (RFC 7010) et il faut donc prêter attention à la conception de son adressage : on aura du mal à en changer. Heureusement, c'est beaucoup plus facile qu'en IPv4 : l'abondance d'adresses dispense des astuces utilisées en IPv4 pour essayer d'économiser chaque adresse. Par exemple, on peut donner à tous ses sous-réseaux la même longueur de préfixe, quelle que soit leur taille, ce qui simplifie bien les choses (le RFC 6177 est une lecture instructive). Comme en IPv4, les adresses peuvent être liées au fournisseur d'accès (PA, Provider Allocated) ou bien obtenues indépendamment de ce fournisseur (PI, Provider Independent). Le RFC 7381 discute ce cas. Cela peut avoir des conséquences de sécurité. Par exemple, les adresses PA sont en dernier ressort gérées par l'opérateur à qui il faudra peut-être demander certaines actions. Et ces adresses PA peuvent pousser à utiliser la traduction d'adresses, qui augmente la complexité. (D'un autre côté, les adresses PI sont plus difficiles à obtenir, surtout pour une petite organisation.) Ah, et puis, pour les machines terminales, le RFC 7934 rappelle à juste titre qu'il faut autoriser ces machines à avoir plusieurs adresses (il n'y a pas de pénurie en IPv6). Une des raisons pour lesquelles une machine peut avoir besoin de plusieurs adresses est la protection de la vie privée (RFC 8981).

Les gens habitués à IPv4 demandent souvent quel est l'équivalent du RFC 1918 en IPv6. D'abord, de telles adresses privées ne sont pas nécessaires en IPv6, où on ne manque pas d'adresses. Mais si on veut, on peut utiliser les ULA (Unique Local Addresses) du RFC 4193. Par rapport aux adresses privées du RFC 1918, elles ont le gros avantage d'être uniques, et donc d'éviter toute collision, par exemple quand deux organisations fusionnent leurs réseaux locaux. Le RFC 4864 décrit comment ces ULA peuvent être utilisés pour la sécurité.

Au moment de concevoir l'adressage, un choix important est celui de donner ou non des adresses IP stables aux machines. (Ces adresses stables peuvent leur être transmises par une configuration statique, ou bien en DHCP.) Les adresses stables facilitent la gestion du réseau mais peuvent faciliter le balayage effectué par un attaquant pendant une reconnaissance préalable. Contrairement à ce qu'on lit parfois encore, ce balayage est tout à fait possible en IPv6, malgré la taille de l'espace d'adressage, même s'il est plus difficile qu'en IPv4. Le RFC 7707 explique les techniques de balayage IPv6 possibles. Même chose dans l'article « Mapping the Great Void ». Bref, on ne peut pas compter sur la STO et donc, adresses stables ou pas, les machines connectées à l'Internet peuvent être détectées, et doivent donc être défendues.

Cela n'empêche pas de protéger la vie privée des utilisateurs en utilisant des adresses temporaires pour contacter l'extérieur. L'ancien système de configuration des adresses par SLAAC était mauvais pour la vie privée puisqu'il utilisait comme partie locale de l'adresse (l'IID, Interface IDentifier) l'adresse MAC, ce qui permettait d'identifier une machine même après qu'elle ait changé de réseau. Ce système est abandonné depuis longtemps (RFC 8064) au profit d'adresses aléatoires (RFC 8981). Ceci dit, ces adresses aléatoires posent un autre problème : comme elles changent fréquemment, elles ne permettent pas à l'administrateur réseau de suivre les activités d'une machine (c'est bien leur but), et on ne peut plus utiliser de mécanismes comme les ACL. Une solution possible est d'utiliser des adresses qui sont stables pour un réseau donné mais qui ne permettent pas de suivre une machine quand elle change de réseau, les adresses du RFC 7217. C'est dans beaucoup de cas le meilleur compromis. (Le RFC 7721 contient des détails sur les questions de sécurité liées aux adresses IP.)

On peut aussi couper SLAAC (cela peut se faire à distance avec des annonces RA portant le bit M) et n'utiliser que DHCP mais toutes les machines terminales n'ont pas un client DHCP.

En parlant de DHCP, lui aussi pose des problèmes de vie privée (décrits dans le RFC 7824) et si on veut être discret, il est recommandé d'utiliser le profil restreint défini dans le RFC 7844.

Après les adresses, la question des en-têtes d'extension, un concept nouveau d'IPv6. En IPv4, les options sont placées dans l'en-tête, qui a une longueur variable, ce qui complique et ralentit son analyse. En IPv6, l'en-tête a une longueur fixe (40 octets) mais il peut être suivi d'un nombre quelconque d'en-têtes d'extension (RFC 8200, section 4). Si on veut accéder à l'information de couche 4, par exemple pour trouver le port TCP, il faut suivre toute la chaîne d'en-têtes. Ce système était conçu pour être plus facile et plus rapide à analyser que celui d'IPv4, mais à l'usage, ce n'est pas le cas (le RFC estime même que le système d'IPv6 est pire). En partie pour cette raison, certains nœuds intermédiaires jettent tous les paquets IPv6 contenant des en-têtes d'extension (RFC 7872). D'autres croient que la couche Transport suit immédiatement l'en-tête, sans tenir compte de la possibilité qu'il y ait un en-tête d'extension, ce qui fausse leur analyse. L'en-tête d'extension Hop-by-hop options était particulièrement problématique, car devant être traité par tous les routeurs (le RFC 8200 a adouci cette règle).

Pour faciliter la tâche des pare-feux, plusieurs règles ont été ajoutées aux en-têtes d'extension depuis les débuts d'IPv6 : par exemple le premier fragment d'un datagramme doit contenir la totalité des en-têtes d'extension.

À l'interface d'IPv6 et de la couche 2, on trouve quelques problèmes supplémentaires. D'abord, concernant la résolution d'adresses IP en adresses MAC, pour laquelle IPv6 utilise le protocole NDP (Neighbor Discovery Protocol, RFC 4861). NDP partage avec ARP un problème fondamental : n'importe quelle machine du réseau local peut répondre ce qu'elle veut. Par exemple, si une machine demande « qui est 2001:db8:1::23:42:61 ? », toutes les machines locales peuvent techniquement répondre « c'est moi » et donner leur adresse MAC. Ce problème et quelques autres analogues sont documentés dans les RFC 3756 et RFC 6583. DHCP pose le même genre de problèmes, toute machine peut se prétendre serveur DHCP et répondre aux requêtes DHCP à la place du serveur légitime. Pour se prémunir contre les attaques faites par des machines envoyant de faux RA, on peut aussi isoler les machines, par exemple en donnant un /64 à chacune, ou bien en configurant commutateurs ou points d'accès Wifi pour bloquer les communications de machine terminale à machine terminale (celles qui qui ne sont pas destinées au routeur). Le RFC recommande le RA guard du RFC 6105.

Et sur les mobiles ? Un lien 3GPP est un lien point-à-point, l'ordiphone qui est à un bout ne peut donc pas parler aux autres ordiphones, même utilisant la même base. On ne peut parler qu'au routeur (GGSN - GPRS Gateway Support Node, ou bien PGW - Packet GateWay). Pour la même raison, il n'y a pas de résolution des adresses IP et donc pas de risque liés à cette résolution. Ce mécanisme empêche un grand nombre des attaques liées à NDP. Si vous voulez en apprendre plus à ce sujet, il faut lire le RFC 6459.

Le multicast peut être dangereux sur un réseau local, puisqu'il permet d'écrire à des machines qui n'ont rien demandé. Certains réseaux WiFi bloquent le multicast. En IPv6, cela empêche des actions néfastes comme de pinguer ff01::1 (l'adresse multicast qui désigne toutes les machines du réseau local), mais cela bloque aussi des protocoles légitimes comme mDNS (RFC 6762).

Compte-tenu de la vulnérabilité du réseau local, et des risques associés, il a souvent été proposé de sécuriser l'accès à celui-ci et IPv6 dispose d'un protocole pour cela, SEND, normalisé dans le RFC 3971, combiné avec les CGA du RFC 3972. Très difficile à configurer, SEND n'a connu aucun succès, à part dans quelques environnements ultra-sécurisés. On ne peut clairement pas compter dessus.

Voyons maintenant la sécurité du plan de contrôle : les routeurs et le routage (RFC 6192). Les problèmes de sécurité sont quasiment les mêmes en IPv4 et en IPv6, la principale différence étant le mécanisme d'authentification pour OSPF. Un routeur moderne typique sépare nettement le plan de contrôle (là où on fait tourner les protocoles comme OSPF, mais aussi les protocoles de gestion comme SSH qui sert à configurer le routeur) et le plan de transmission, là où se fait la transmission effective des paquets. Le second doit être très rapide, car il fonctionne en temps réel. Il utilise en général du matériel spécialisé, alors que le plan de contrôle est la plupart du temps mis en œuvre avec un processeur généraliste, et un système d'exploitation plus classique. Pas toujours très rapide, il peut être submergé par un envoi massif de paquets. Le plan de contrôle ne gère que les paquets, relativement peu nombreux, qui viennent du routeur ou bien qui y arrivent, le plan de transmission gérant les innombrables paquets que le routeur transmet, sans les garder pour lui. Chaque paquet entrant est reçu sur l'interface d'entrée, le routeur consulte une table qui lui dit quel est le routeur suivant pour ce préfixe IP, puis il envoie ce paquet sur l'interface de sortie. Et le tout très vite.

Notre RFC conseille donc de protéger le plan de contrôle en bloquant le plus tôt possible les paquets anormaux, comme des paquets OSPF qui ne viendraient pas d'une adresse locale au lien, ou les paquets BGP qui ne viennent pas d'un voisin connu. (Mais, bien sûr, il faut laisser passer l'ICMP, essentiel au déboguage et à bien d'autres fonctions.) Pour les protocoles de gestion, il est prudent de jeter les paquets qui ne viennent pas du réseau d'administration. (Tout ceci est commun à IPv4 et IPv6.)

Protéger le plan de contrôle, c'est bien, mais il faut aussi protéger le protocole de routage. Pour BGP, c'est pareil qu'en IPv4 (lisez le RFC 7454). Mais OSPF est une autre histoire. La norme OSPFv3 (RFC 4552) comptait à l'origine exclusivement sur IPsec, dont on espérait qu'il serait largement mis en œuvre et déployé. Cela n'a pas été le cas (le RFC 8504 a d'ailleurs supprimé cette obligation d'IPsec dans IPv6, obligation qui était purement théorique). Le RFC 7166 a pris acte de l'échec d'IPsec en créant un mécanisme d'authentification pour OSPFv3. Notre RFC recommande évidemment de l'utiliser.

Sinon, les pratiques classiques de sécurité du routage tiennent toujours. Ne pas accepter les routes « bogons » (conseil qui n'est plus valable en IPv4, où tout l'espace d'adressage a été alloué), celles pour des adresses réservées (RFC 8190), etc.

Pas de sécurité sans surveillance (c'est beau comme du Ciotti, ça) et journalisation. En IPv6 comme en IPv4, des techniques comme IPFIX (RFC 7011), SNMP (RFC 4293), etc sont indispensables. Comme en IPv4, on demande à son pare-feu, son serveur RADIUS (RFC 2866) et à d'autres équipements de journaliser les évènements intéressants. À juste titre, et même si ça va chagriner les partisans de la surveillance massive, le RFC rappelle que, bien que tout cela soit très utile pour la sécurité, c'est dangereux pour la vie privée, et que c'est souvent, et heureusement, encadré par des lois comme le RGPD. Administrateur réseaux, ne journalise pas tout, pense à tes responsabilités morales et légales !

Bon, mais cela, c'est commun à IPv4 et IPv6. Qu'est-ce qui est spécifique à IPv6 ? Il y a le format textuel canonique des adresses, normalisé dans le RFC 5952, qui permet de chercher une adresse sans ambiguité. Et la mémoire des correspondances adresses IP adresses MAC dans les routeurs ? Elle est très utile à enregistrer, elle existe aussi en IPv4, mais en IPv6 elle est plus dynamique, surtout si on utilise les adresses favorables à la vie privée du RFC 8981. Le RFC recommande de la récupérer sur le routeur au moins une fois toutes les 30 secondes. Et le journal du serveur DHCP ? Attention, en IPv6, du fait de l'existence de trois mécanismes d'allocation d'adresses (DHCP, SLAAC et statique) au lieu de deux en IPv4, le journal du serveur DHCP ne suffit pas. Et puis il ne contiendra pas l'adresse MAC mais un identificateur choisi par le client, qui peut ne rien vous dire. (Ceci dit, avec les machines qui changent leur adresse MAC, DHCPv4 a un problème du même genre.) En résumé, associer une adresse IP à une machine risque d'être plus difficile qu'en IPv4.

Une autre spécificité d'IPv6 est l'existence de nombreuses technologies de transition entre les deux protocoles, technologies qui apportent leurs propres problèmes de sécurité (RFC 4942). Normalement, elles n'auraient dû être que temporaires, le temps que tout le monde soit passé à IPv6 mais, comme vous le savez, la lenteur du déploiement fait qu'on va devoir les supporter longtemps, les réseaux purement IPv6 et qui ne communiquent qu'avec d'autres réseaux IPv6 étant une petite minorité. La technique de coexistence la plus fréquente est la double pile, où chaque machine a à la fois IPv4 et IPv6. C'est la plus simple et la plus propre, le trafic de chaque version du protocole IP étant natif (pas de tunnel). Avec la double pile, l'arrivée d'IPv6 n'affecte pas du tout IPv4. D'un autre côté, il faut donc gérer deux versions du protocole. (Anecdote personnelle : quand j'ai commencé dans le métier, IP était très loin de la domination mondiale, et il était normal, sur un réseau local, de devoir gérer cinq ou six protocoles très différents. Prétendre que ce serait une tâche insurmontable de gérer deux versions du même protocole, c'est considérer les administrateurs réseaux comme très paresseux ou très incompétents.) L'important est que les politiques soient cohérentes, afin d'éviter, par exemple, que le port 443 soit autorisé en IPv4 mais bloqué en IPv6, ou le contraire. (C'est parfois assez difficile à réaliser sans une stricte discipline : beaucoup de pare-feux n'ont pas de mécanisme simple pour indiquer une politique indépendante de la version du protocole IP.)

Notez que certains réseaux peuvent être « double-pile » sans que l'administrateur réseaux l'ait choisi, ou en soit conscient, si certaines machines ont IPv6 activé par défaut (ce qui est fréquent et justifié). Des attaques peuvent donc être menées via l'adresse locale au lien même si aucun routeur du réseau ne route IPv6.

Mais les plus gros problèmes de sécurité liés aux techniques de coexistence/transition viennent des tunnels. Le RFC 6169 détaille les conséquences des tunnels pour la sécurité. Sauf s'ils sont protégés par IPsec ou une technique équivalente, les tunnels permettent bien des choses qui facilitent le contournement des mesures de sécurité. Pendant longtemps, l'interconnexion entre réseaux IPv6 isolés se faisait via des tunnels, et cela a contribué aux légendes comme quoi IPv6 posait des problèmes de sécurité. Aujourd'hui, ces tunnels sont moins nécessaires (sauf si un réseau IPv6 n'est connecté que par des opérateurs archaïques qui n'ont qu'IPv4).

Les tunnels les plus dangereux (mais aussi les plus pratiques) sont les tunnels automatiques, montés sans configuration explicite. Le RFC suggère donc de les filtrer sur le pare-feu du réseau, en bloquant le protocole IP 41 (ISATAPRFC 5214, 6to4RFC 3056, mais aussi 6rdRFC 5969 - qui, lui, ne rentre pas vraiment dans la catégorie « automatique »), le protocole IP 47 (ce qui bloque GRE, qui n'est pas non plus un protocole « automatique ») et le port UDP 3544, pour neutraliser TeredoRFC 4380. D'ailleurs, le RFC rappelle plus loin que les tunnels statiques (RFC 2529), utilisant par exemple GRE (RFC 2784), sont plus sûrs (mais IPsec ou équivalent reste recommandé). 6to4 et Teredo sont de toute façon très déconseillés aujourd'hui (RFC 7526 et RFC 3964).

Et les mécanismes de traduction d'adresses ? On peut en effet traduire des adresses IPv4 en IPv4 (le traditionnel NAT, qui est plutôt du NAPT en pratique, puisqu'il traduit aussi le port), ce qui est parfois présenté à tort comme une fonction de sécurité, mais on peut aussi traduire de l'IPv4 en IPv6 ou bien de l'IPv6 en IPv6. Le partage d'adresses que permettent certains usages de la traduction (par exemple le CGNAT) ouvre des problèmes de sécurité bien connus. Les techniques de traduction d'IPv4 en IPv6 comme NAT64RFC 6146 ou 464XLATRFC 6877 apportent également quelques problèmes, décrits dans leurs RFC.

J'ai parlé plus haut du fait que les systèmes d'exploitation modernes ont IPv6 et l'activent par défaut. Cela implique de sécuriser les machines contre les accès non voulus faits avec IPv6. Du classique, rien de spécifique à IPv6 à part le fait que certains administrateurs système risqueraient de sécuriser les accès via IPv4 (avec un pare-feu intégré au système d'exploitation, par exemple) en oubliant de le faire également en IPv6.

Tous les conseils donnés jusqu'à présent dans cette section 2 du RFC étaient communs à tous les réseaux IPv6. Les sections suivantes s'attaquent à des types de réseau spécifiques à certaines catégories d'utilisateurs. D'abord (section 3), les « entreprises » (en fait, toutes les organisations - RFC 7381, pas uniquement les entreprises capitalistes privées, comme le terme étatsunien enterprise pourrait le faire penser). Le RFC contient quelques conseils de sécurité, proches de ce qui se fait en IPv4, du genre « bloquer les services qu'on n'utilise pas ». (Et il y a aussi le conseil plus évident : bloquer les paquets entrants qui ont une adresses IP source interne et les paquets sortants qui ont une adresse IP source externe.)

Et pour les divers opérateurs (section 4 du RFC) ? C'est plus délicat car ils ne peuvent pas, contrairement aux organisations, bloquer ce qu'ils ne veulent pas (sauf à violer la neutralité, ce qui est mal). Le RFC donne des conseils de sécurisation BGP (identiques à ceux d'IPv4) et RTBH (RFC 5635). Il contient également une section sur l'« interception légale » (le terme politiquement correct pour les écoutes et la surveillance). Légalement, les exigences (et les problèmes qu'elles posent) sont les mêmes en IPv4 et en IPv6. En IPv4, le partage d'adresses, pratique très répandue, complique sérieusement la tâche des opérateurs quand ils reçoivent un ordre d'identifier le titulaire de telle ou telle adresse IP (RFC 6269). En IPv6, en théorie, la situation est meilleure pour la surveillance, une adresse IP n'étant pas partagée. Par contre, l'utilisateur peut souvent faire varier son adresse au sein d'un préfixe /64.

Quand au réseau de l'utilisateur final, il fait l'objet de la section 5. Il n'y a pas actuellement de RFC définitif sur la délicate question de la sécurité de la maison de M. Michu. Notamment, les RFC 6092 et RFC 7084 ne prennent pas position sur la question très sensible de savoir si les routeurs/pare-feux d'entrée de ce réseau devraient bloquer par défaut les connexions entrantes. La sécurité plaiderait en ce sens mais ça casserait le principe de bout en bout.

Voilà, nous avons terminé cette revue du long RFC. Je résumerai mon opinion personnelle en disant : pour la plupart des questions de sécurité, les ressemblances entre IPv4 et IPv6 l'emportent sur les différences. La sécurité n'est donc pas une bonne raison de retarder la migration si nécessaire vers IPv6. J'ai développé cette idée dans divers exposés et articles.


Téléchargez le RFC 9099


L'article seul

RFC 9098: Operational Implications of IPv6 Packets with Extension Headers

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : F. Gont (SI6 Networks), N. Hilliard (INEX), G. Doering (SpaceNet AG), W. Kumari (Google), G. Huston (APNIC), W. Liu (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 20 septembre 2021


IPv6 souffre de réseaux mal gérés qui se permettent de jeter les paquets ayant des caractéristiques normales, mais qui déplaisent à certains équipements réseau. C'est par exemple le cas des paquets utilisant les en-têtes d'extension. Pourquoi les paquets utilisant ces en-têtes sont-ils souvent jetés ?

Ces en-têtes d'extension (qui n'ont pas d'équivalent en IPv4) sont normalisés dans le RFC 8200, section 4. Ils servent à la fois à des fonctions de base d'IPv6 (comme la fragmentation) et à étendre le protocole si nécessaire. Mais, en pratique, on observe trop souvent que les paquets IPv6 utilisant ces en-têtes d'extension ne passent pas sur certains réseaux. Ce RFC vise à étudier pourquoi, et à expliquer les conséquences. Comme toujours quand on explique un phénomène (la délinquance, par exemple), des gens vont comprendre de travers et croire qu'on justifie le phénomène en question (« expliquer, c’est déjà vouloir un peu excuser », avait stupidement dit un ancien premier ministre français, à propos du terrorisme djihadiste). Le cas est d'autant plus fréquent qu'en français, « comprendre » est ambigu, car il peut désigner l'explication (qui est utile aussi bien aux partisans qu'aux adversaires d'un phénomène) que la justification. Bref, ce RFC explique pourquoi des paquets innocents sont détruits, il ne dit pas qu'il faut continuer à le faire !

La section 4 du RFC explique la différence entre l'en-tête d'un paquet IPv6 et celui d'un paquet de l'ancienne version. Dans les deux versions, le problème est de placer des options dans les en-têtes. Le gros changement est l'utilisation par IPv6 d'un en-tête de taille fixe (40 octets), suivi d'une liste chainée d'en-têtes d'extension permettant d'encoder ces options. Au contraire, IPv4 avait un en-tête de taille variable (entre 20 et 60 octets), avec un champ indiquant sa longueur, champ qu'il fallait lire avant d'accéder à l'en-tête. Le mécanisme d'IPv4 n'était ni pratique, ni rapide, mais celui d'IPv6 n'est pas plus satisfaisant : il faut lire toute la liste chainée (dont la longueur est quelconque et non limitée) si on veut accéder aux informations au-dessus de la couche 3. Ce n'est pas un problème pour les routeurs, à qui la couche 3 suffit (à part le cas de l'en-tête Hop-by-hop options), mais c'est ennuyeux pour les autres boitiers situés sur le chemin, comme les pare-feux. Les évolutions récentes d'IPv6 ont aidé, comme l'obligation que tous les en-têtes d'extension soient dans le premier fragment, si le datagramme est fragmenté (RFC 7112), ou comme l'imposition d'un format commun aux futurs en-têtes d'extension (dans le RFC 6564), mais l'analyse de la liste des en-têtes d'extension reste un travail pénible pour les machines.

Le problème est identifié depuis longtemps. Il est analysé dans l'Internet-Draft draft-taylor-v6ops-fragdrop, dans draft-wkumari-long-headers, dans draft-kampanakis-6man-ipv6-eh-parsing, dans draft-ietf-opsec-ipv6-eh-filtering mais aussi dans des RFC, le RFC 7113 et le RFC 8900. Cela a mené à plusieurs changements dans la norme, je vous renvoie aux RFC 5722, RFC 7045, RFC 8021, etc. Plusieurs changements ont été intégrés dans la dernière révision du RFC principal de la norme, le RFC 8200. Ainsi, celui-ci dispense désormais les routeurs de chercher un éventuel en-tête d'extension Hop-by-hop options.

Parallèlement à ces analyses du protocole, diverses études ont porté sur le phénomène des paquets jetés s'ils contenaient des en-têtes d'extension. Cela a été documenté dans « Discovering Path MTU black holes on the Internet using RIPE Atlas », dans « IPv6 Extension Headers in the Real World v2.0 », également dans « Dealing with IPv6 fragmentation in the DNS » et « Measurement of IPv6 Extension Header Support » ainsi que dans le RFC 7872.

Comment est-ce que les équipements intermédiaires du réseau fonctionnent, et pourquoi est-ce que les en-têtes d'extension IPv6 peuvent parfois les défriser ? La section 6 du RFC rappelle l'architecture de ces machines. Un routeur de cœur de réseau est très différent de l'ordinateur de base, avec son processeur généraliste et sa mémoire de grande taille, ce qui le rend lent, mais souple. Au contraire, la transmission des paquets par le routeur est en général faite par du matériel spécialisé, ASIC ou NPU. (Vous pouvez consulter des explications dans l'exposé fait à l'IETF « Modern Router Architecture for Protocol Designers » et dans l'article « Modern router architecture and IPv6 ».) Avant de transmettre un paquet reçu sur l'interface de sortie, le routeur doit trouver quelle interface utiliser. Une méthode courante est de prendre les N premiers octets du paquet et de les traiter dans une TCAM ou une RLDRAM, où se fera la détermination du saut suivant (et donc de l'interface de sortie). Le choix du nombre N est crucial : plus il est petit, plus le routeur pourra traiter de paquets, mais moins il aura d'information sur le paquet. (En pratique, on observe des N allant de 192 à 384 octets.) Du fait qu'un routeur se limite normalement à la couche Réseau, et que l'en-tête IPv6 a une taille fixe, envoyer simplement les 40 octets de cet en-tête devrait suffire. Mais lisez plus loin : certains routeurs ou autres équipements intermédiaires sont configurés pour regarder au-delà, et voudraient des informations de la couche Transport, plus dure à atteindre.

Une solution, pour les routeurs qui ne lisent qu'un nombre limité d'octets avant de prendre une décision, est de lire les en-têtes d'extension un par un, et de réinjecter le reste du paquet dans le dispositif de traitement. Ça se nomme la recirculation, c'est plus lent, mais ça marche quelle que soit la longueur de la chaîne des en-têtes d'extension.

Comme le routeur comprend toujours un processeur généraliste (ne serait-ce que pour faire tourner les fonctions de contrôle comme SSH et les protocoles de routage), une autre solution serait d'envoyer à ce processeur les paquets « compliqués » (mais lire le RFC 6192 d'abord). L'énorme différence de performance entre le processeur généraliste et les circuits spécialisés fait que ce ne serait pas une solution réaliste sauf pour un trafic très modéré. (Le RFC note que certains routeurs ont trois dispositifs de traitement des paquets, et pas seulement deux comme présenté plus haut : outre le processeur généraliste, qui ne leur sert qu'aux fonctions de contrôle, et des circuits matériels spécialisés, ils ont un dispositif logiciel de transmission des paquets. Plus souple que les circuits spécialisés, il n'est pas forcément plus rapide que le processeur généraliste mais, au moins, il n'interfère pas avec les fonctions de contrôle.)

Bon, on l'a déjà dit, mais cela vaut la peine de le répéter : à part le cas (agaçant) de l'en-tête Hop-by-hop options, un routeur, équipement de couche 3 n'a normalement aucun besoin d'aller regarder tous les en-têtes d'extension (qui sont presque tous pour la machine terminale de destination uniquement). Encore moins de faire du DPI et d'aller chercher des informations dans les couches 4 à 7. Mais la section 7 du RFC explique pourquoi certains routeurs le font quand même (il s'agit d'une description de leurs pratiques, pas une approbation ; beaucoup des raisons données sont mauvaises).

D'abord, la répartition de charge et l'ECMP. Si un routeur peut faire passer un paquet via deux interfaces différentes, laquelle choisir ? Alterner (un coup à gauche, un coup à droite) augmenterait la probabilité d'une arrivée des paquets dans le désordre. On préfère la prédictabilité : tous les paquets d'un même flot doivent suivre le même chemin. Comment déterminer le « flot », notion parfois un peu floue ? En restant dans les couches basses, on peut utiliser uniquement les adresses IP de source et de destination mais elles ne sont pas assez discriminantes. En IPv6, on peut en théorie utiliser l'étiquette de flot (normalisé dans le RFC 6437, ainsi que les RFC 6438 et RFC 7098 pour son utilisation) mais elle n'est pas toujours présente, en partie (encore !) par la faute de middleboxes qui, ignorant ce concept d'étiquette de flot, jetaient les paquets qui en avaient une. (Voir les articles de I. Cunha, «  IPv4 vs IPv6 load balancing in Internet routes » et J. Jaeggli, «  IPv6 flow label: misuse in hashing ».) En pratique, les systèmes qui ont besoin d'identifier les flots utilisent plutôt une heuristique : le tuple à cinq élements {protocole de transport, adresse IP source, adresse IP destination, port source, port destination}. Ce n'est pas parfait mais, en pratique, cela marche à peu près. On voit que cela nécessite d'accéder à de l'information de la couche Transport, les ports. (Cette heuristique a d'autres limites : par exemple elle ne marche pas si une partie de la couche Transport est chiffrée, comme c'est le cas avec QUIC.)

Autre cas où un boitier intermédiaire ressent le besoin d'accéder aux informations des couches supérieures, les ACL. La plupart des pare-feux permettent d'utiliser comme critère de filtrage les numéros de ports, ce qui va nécessiter d'analyser la chaine des en-têtes d'extension IPv6 pour parvenir à la couche Transport. Entre les pare-feux mal faits qui cherchent les informations de la couche Transport immédiatement après l'en-tête fixe (car le programmeur a tout simplement sauté la partie du RFC qui parlait des en-têtes d'extension) et les difficultés posées par le fait, qu'avant le RFC 6564, les en-têtes d'extension inconnus étaient impossibles à analyser, on voit qu'arriver à la couche Transport n'est pas si facile que ça (le RFC dit qu'il est plus compliqué d'analyser IPv6 qu'IPv4, ce qui est très contestable ; mais ce n'est en effet pas plus facile). Cela peut avoir des conséquences en terme de sécurité, par exemple si un méchant ajoute des en-têtes d'extension dans l'espoir que ses paquets ne soient pas correctement identifiés (cf. RFC 7113).

Autre exemple, le réassemblage des paquets fragmentés nécessite un état (mémoriser les fragments en cours de réassemblage), ce qui peut être fatal à la mémoire du pare-feu, notamment en cas d'attaque. Pour les coûts de ce filtrage, voir l'article d'E. Zack « Firewall Security Assessment and Benchmarking IPv6 Firewall Load Tests ». Cette difficulté peut encourager les pare-feux à jeter les paquets ayant des en-têtes d'extension, surtout si un administrateur réseaux ignorant dit bien fort « ces en-têtes d'extension ne servent à rien de toute façon » (RFC 7872).

Un problème proche est celui de la protection contre les attaques par déni de service. Filtrer avec les adresses IP peut être fait rès efficacement (cf. RFC 5635) mais ne marche pas, par exemple si l'adresse IP source est usurpée. Une des méthodes utilisées alors est de repérer un motif récurrent dans les paquets envoyés par l'attaquant, et de filtrer sur ce motif (vous pouvez lire ici un exemple avec le DNS). Là encore, des informations au-delà de la couche Réseau sont nécessaires. Toujours en sécurité, les NIDS ont aussi besoin de plus d'informations que ce que fournit la couche Réseau.

Et, bien sûr, comme toute complexité, les en-têtes d'extension augmentent les risques de sécurité, d'autant plus qu'il y a un cercle vicieux : comme ils sont peu utilisés, le code qui les traite est peu testé, donc il y a des bogues, donc ils sont peu utilisés, etc.

Donc, un certain nombre de machines intermédiaires, qui assurent des fonctions allant au-delà de ce que fait un « simple » routeur, ont des problèmes avec les en-têtes d'extension IPv6 et choisissent souvent la solution de facilité, qui est de les jeter systématiquement.


Téléchargez le RFC 9098


L'article seul

RFC 9096: Requirements for Customer Edge Routers to Mitigate IPv6 Renumbering Events

Date de publication du RFC : Août 2021
Auteur(s) du RFC : F. Gont (SI6 Networks), J. Zorz (6connect), R. Patterson (Sky UK), B. Volz (Cisco)
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 7 septembre 2021


Quand un FAI modifie la configuration de son réseau IPv6, les routeurs chez les clients finaux, les CPE, ne retransmettent pas toujours rapidement ce changement, ce qui mène parfois à des problèmes de connectivité. Ce RFC décrit ce que doivent faire ces CPE pour minimiser les conséquence négatives d'une rénumérotation d'un réseau.

Le problème est documenté dans le RFC 8978 : par exemple, lorsqu'un routeur chez M. Toutlemonde (une « box ») redémarre et « oublie » sa configuration réseau précédente, si elle a changé chez le FAI entretemps, les machines du réseau local de M. Toutlemonde risquent de continuer à utiliser pendant un certain une ancienne configuration, désormais invalide. Comment éviter cela ?

Notre RFC se penche surtout sur le cas où le routeur de M. Toutlemonde a appris son préfixe IPv6 depuis le FAI via la délégation de préfixe DHCP du RFC 8415, et qu'il retransmet l'information sur ce préfixe dans le réseau local avec le SLAAC du RFC 4862 (via les RA, Router Advertisements, RFC 4861) ou bien DHCP. Les machines terminales sur le réseau local peuvent aussi agir (ce sera dans un futur RFC) mais l'actuel RFC ne concerne que les routeurs. Il consiste en une série d'exigences auxquelles doivent se prêter les routeurs, exigences qui s'ajoutent à celles déjà présentes dans le RFC 7084 ou bien qui modifient des exigences de ce RFC 7084.

Beaucoup de ces exigences nécessitent un mécanisme de stockage d'informations sur le routeur, stockage qui doit survivre aux redémarrages, ce qui ne sera pas évident pour tous les routeurs. Ainsi, le RFC demande que, du côté WAN, le routeur utilise toujours le même identificateur (IAID, Identity Association IDentifier, RFC 8415, section 4.2) en DHCP (pour essayer de garder le même préfixe). Certains routeurs choisissent apparemment l'IAID au hasard à chaque démarrage, ce qui leur obtient un nouveau préfixe. Il vaut mieux le garder, mais cela nécessite qu'il puisse être stocké et mémorisé même en cas de redémarrage. Comme tous les routeurs n'ont pas de mécanisme de stockage stable, les exigences du RFC sont exprimées (dans le langage du RFC 2119) par un SHOULD et pas un MUST.

Autre exigence, qui relève du bon sens, le routeur ne doit pas, lorsqu'il utilise un préfixe du côté LAN (le réseau local), utiliser une durée de vie plus longue (options Preferred Lifetime et Valid Lifetime du message d'information sur le préfixe envoyé par le routeur, RFC 4861, section 4.6.2) que celle qu'il a lui-même appris en DHCP côté WAN. On ne doit pas promettre ce qu'on ne peut pas tenir, la durée du bail DHCP s'impose au routeur et aux annonces qu'il fait sur le réseau local.

Enfin, le routeur ne doit pas, au redémarrage, envoyer systématiquement un abandon du préfixe appris en DHCP (message DHCP RELEASE). Certains routeurs font apparemment cela, ce qui risque de déclencher une renumérotation brutale (RFC 8978).

Lorsque le préfixe change, le routeur devrait aussi signaler cela sur le réseau local. Là encore, cela impose une mémoire, un stockage stable. Il doit se souvenir de ce qu'il a reçu, et annoncé, précédemment, pour pouvoir annoncer sur le réseau local que ces anciens préfixes ne doivent plus être utilisés (cela se fait en annonçant ces préfixes, mais avec une durée de vie nulle). Dans un monde idéal, le routeur sera prévenu des changements de préfixe parce que le FAI réduira la durée de vie de ses baux DHCP, permettant un remplacement ordonné d'un préfixe par un autre. Dans la réalité, on a parfois des renumérotations brutales, sans préavis (RFC 8978). Le routeur doit donc également gérer ces cas.


Téléchargez le RFC 9096


L'article seul

RFC 9095: Extensible Provisioning Protocol (EPP) Domain Name Mapping Extension for Strict Bundling Registration

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : J. Yao, L. Zhou, H. Li (CNNIC), N. Kong (Consultant), W. Tan (Cloud Registry), J. Xie
Pour information
Première rédaction de cet article le 30 juillet 2021


Le bundling est le rassemblement de plusieurs noms de domaine dans un seul lot (bundle) qui va être traité comme un nom unique pour des opérations comme l'enregistrement du nom ou son transfert à un autre titulaire. Il est surtout pratiqué par les registres qui ont beaucoup de noms en écriture chinoise. Ce RFC décrit une extension au protocole d'avitaillement EPP pour pouvoir traiter ces lots.

Le problème n'existe pas qu'en chinois mais ce sont surtout les sinophones qui se sont manifestés à ce sujet, en raison de la possibilité d'écrire le même mot en écriture traditionnelle ou en écriture simplifiée (on parle de variantes : l'ensemble des variantes forme le lot). Pour prendre un exemple non-chinois, PIR avait décidé qu'un nom dans .ngo et dans .ong devaient être dans le même lot. Un registre qui décide que ces deux termes sont équivalents et doivent être gérés ensemble (par exemple, appartenir au même titulaire) les regroupent dans un lot (bundle, ou parfois package). C'est la politique suggérée dans les RFC 3743 et RFC 4290, et le RFC 6927 décrit les pratiques existantes. Par exemple, certains registres peuvent n'autoriser qu'une variante par lot, et bloquer les autres (empêcher leur enregistrement), tandis que d'autres enregistreront tous les noms ensemble. Sans compter bien sûr les registres qui n'ont pas de système de lot du tout. Notre nouveau RFC 9095 ne prend pas position sur ce sujet délicat, il décrit juste un moyen technique de manipuler ces lots avec EPP (RFC 5731).

Les variantes dans un même lot n'ont pas forcément tout en commun. Un registre peut par exemple décider que l'enregistrement des variantes doit être fait par le même titulaire mais qu'un nom du lot peut ensuite être transféré à un autre titulaire. Notre RFC se limite au cas strict où les membres du lot ont presque tous leurs attributs (titulaires, contacts, date d'expiration, peut-être serveurs de noms et, pourquoi pas, clés DNSSEC) en commun.

La lecture du RFC nécessite un peu de terminologie spécifique, décrite dans sa section 2. Par exemple, le RDN (Registered Domain Name) est celui qui a été demandé par le titulaire lors de l'enregistrement, et le BDN (Bundled Domain Name) est un nom qui a été inclus dans le lot, en fonction des règles du registre. Par exemple, si un registre décidait que tout nom avec des traits d'union était équivalent au même nom sans traits d'union, et qu'un titulaire enregistre tarte-poireaux.example (le RDN), alors tartepoireaux.example et tarte-poi-reaux.example seraient des BDN, membres du même lot que le RDN. Dans le modèle de notre RFC, les métadonnées comme la date d'expiration ou comme l'état du domaine sont attachées au RDN, les BDN du lot partageant ces métadonnées.

Notons aussi que le RFC n'envisage que le cas de lots assez petits (par exemple le nom en écriture chinoise traditionnelle et celui en écriture chinoise simplifiée). L'exemple que je donnais avec le trait d'union ne rentre pas tellement dans le cadre de ce RFC car le nombre de BDN est alors beaucoup plus élevé et serait difficile à gérer. (Amusez-vous à calculer combien de variantes de tartepoireaux.example existeraient si un décidait que le trait d'union n'est pas significatif.)

Dans l'extension EPP décrite dans ce RFC, le RDN est représenté (section 5 du RFC) en Unicode (le « U-label ») ou bien en ASCII (le « A-label », la forme « punycodée »). L'élement XML est <b-dn:rdn> (où b-dn est un préfixe possible pour l'espace de noms XML de notre RFC, urn:ietf:params:xml:ns:epp:b-dn). Si le RDN est représenté en ASCII, un attribut XML uLabel permet d'indiquer la version Unicode du nom. Cela donnerait, par exemple, <b-dn:rdn uLabel="实例.example">xn--fsq270a.example</b-dn:rdn>.

Enfin, la section 6 décrit les commandes et réponses EPP pour notre extension. La commande <check> n'est pas modifiée dans sa syntaxe mais le RFC impose que, si un nom qui fait partie d'un lot est envoyé dans la question, la réponse doit contenir le RDN et le BDN. Pour un RDN en sinogrammes, on aurait ainsi la version en écriture traditionnelle et en écriture simplifiée (ici, le nom est disponible à l'enregistrement) :


<response>
  <result code="1000">
    <msg>Command completed successfully</msg>
  </result>
  <resData>
    <domain:chkData
      xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:cd>
         <domain:name avail="1">
          xn--fsq270a.example</domain:name>
        </domain:cd>
        <domain:cd>
          <domain:name avail="1">
            xn--fsqz41a.example
          </domain:name>
          <domain:reason>This associated domain name is
            a produced name based on bundle name policy.
          </domain:reason>
        </domain:cd>
    </domain:chkData>
...

  

La commande <info> n'est pas non plus modifiée mais sa réponse l'est, par l'ajout d'un élément <bundle> qui décrit le lot :


<response>
  <result code="1000">
    <msg>Command completed successfully</msg>
  </result>
  <resData>
    <domain:infData
      xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
      <domain:name>xn--fsq270a.example</domain:name>
      <domain:roid>58812678-domain</domain:roid>
      <domain:status s="ok"/>
...
    </domain:infData>
  </resData>
  <extension>
    <b-dn:infData
      xmlns:b-dn="urn:ietf:params:xml:ns:epp:b-dn">
      <b-dn:bundle>
        <b-dn:rdn uLabel="实例.example">
          xn--fsq270a.example
        </b-dn:rdn>
        <b-dn:bdn uLabel="實例.example">
          xn--fsqz41a.example
        </b-dn:bdn>
      </b-dn:bundle>
    </b-dn:infData>
  </extension>

  

Quand on crée un domaine qui fait partie d'un lot, la commande <create> doit inclure une extension indiquant que le client EPP connait la gestion de lots, et la réponse à <create> lui donnera le BDN. D'une manière analogue, la commande <delete> détruira tout le lot et l'indiquera dans la réponse. La commande <update> fonctionne sur le même principe : elle modifie le RDN et indique dans sa réponse le BDN affecté. La syntaxe complète de cette extension EPP figure dans la section 7 du RFC, sous forme d'un schéma W3C. Par ailleurs, cette extension est enregistrée dans le registre des extensions EPP (celui créé par le RFC 7451).

Un petit mot sur la sécurité, car de nombreux adversaires de l'internationalisation, notamment anglophones, ont critiqué les noms de domaine en Unicode, les accusant de tous les maux : les auteurs du RFC notent que des noms en chinois sont enregistrés depuis plus de quinze ans, et qu'aucun problème particulier n'a été signalé.

Questions mises en œuvre de ce RFC, les registres chinois (comme .cn ou .tw) suivent les principes de ce RFC (l'enregistrement d'un lot) depuis longtemps. CNNIC déploie cette extension EPP. En dehors de la sinophonie, PIR utilise les lots pour .ngo et .ong. Et cette extension EPP est mise en œuvre dans Net::DRI.

Et, comme souvent, il y a un brevet de Verisign sur la technique décrite dans ce RFC. Je ne l'ai pas lu mais il y a des chances qu'il soit sans mérite, comme beaucoup de brevets logiciels.


Téléchargez le RFC 9095


L'article seul

RFC 9083: JSON Responses for the Registration Data Access Protocol (RDAP)

Date de publication du RFC : Juin 2021
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs), A. Newton (AWS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 16 juin 2021


Dans l'ensemble des normes sur le protocole RDAP, ce RFC est destiné à décrire le format de sortie, celui des réponses envoyées par le serveur d'information RDAP. Ce format est basé sur JSON et, pour utiliser RDAP en remplacement de whois, il faudra donc se munir de quelques outils pour traiter le JSON. Ce RFC remplace le RFC 7483 mais il y a très peu de changements.

JSON est normalisé dans le RFC 8259 et représente aujourd'hui le format de choix pour les données structurées c'est-à-dire analysables par un programme. (L'annexe E de notre RFC explique en détail le pourquoi du choix de JSON.) Une des caractéristiques importantes de whois est en effet que son format de sortie n'a aucune structure, c'est du texte libre, ce qui est pénible pour les programmeurs qui essaient de le traiter (mais, d'un autre côté, cela ralentit certains usages déplorables, comme la récolte d'adresses de courrier à des fins de spam, jouant ainsi un rôle de semantic firewall). L'utilisation typique de RDAP est en HTTP (RFC 7480) avec les requêtes exprimées dans la syntaxe des URL du RFC 9082. Voici tout de suite un exemple réel, avec la réponse JSON :

% curl https://rdap.afilias.net/rdap/info/domain/kornog-computing.info
...
{
   "entities": [
...
         "objectClassName": "entity", 
         "roles": [
            "technical", 
            "billing", 
            "administrative"
         ], 
         "vcardArray": [
            "vcard", 
            [
               [
                  "version", 
                  {}, 
                  "text", 
                  "4.0"
               ], 
               [
                  "fn", 
                  {}, 
                  "text", 
                  "KORNOG computing"
               ], 
               [
		    "adr",
		    {
		      "cc": "FR"
		    },
		    "text",
		    {}
	      ]
...
   "events": [
      {
         "eventAction": "registration", 
         "eventDate": "2007-08-14T17:02:33Z"
      }, 
      {
         "eventAction": "last changed", 
         "eventDate": "2014-08-14T01:54:07Z"
      }, 
      {
         "eventAction": "expiration", 
         "eventDate": "2015-08-14T17:02:33Z"
      }
   ], 
   "handle": "D19378523-LRMS", 
   "lang": "en", 
   "ldhName": "kornog-computing.info", 
...
   "nameservers": [
      {
         "ldhName": "ns1.kornog-computing.net", 
         "objectClassName": "nameserver", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
         ]
      }, 
      {
         "ldhName": "ns2.kornog-computing.net", 
         "objectClassName": "nameserver", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
         ]
      }
   ], 
   "notices": [
      {
         "description": [
            "Access to AFILIAS WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the Afilias registry database. The data in this record is provided by Afilias Limited for informational purposes only, and Afilias does not guarantee its accuracy. [...]"
         ], 
         "title": "TERMS OF USE"
      }
   ], 
   "objectClassName": "domain", 
...
   "rdapConformance": [
      "rdap_level_0"
   ], 
   "secureDNS": {
      "zoneSigned": false
   }, 
   "status": [
      "clientDeleteProhibited -- http://www.icann.org/epp#clientDeleteProhibited", 
      "clientTransferProhibited -- http://www.icann.org/epp#clientTransferProhibited"
   ]
}

La section 1.2 présente le modèle de données de RDAP. Dans les réponses, on trouve des types simples (comme des chaînes de caractères), des tableaux JSON, et des objets JSON qui décrivent les trucs sur lesquels on veut de l'information (noms de domaine, adresses IP, etc). Ces objets peuvent comporter des tableaux ou d'autres objets et, lorsqu'une réponse renvoie plusieurs objets (cas des recherches ouvertes, cf. RFC 9082, section 3.2), peuvent eux-même être regroupés en tableaux. Il existe plusieurs classes de ces objets. D'abord, les classes communes aux registres de noms de domaine et aux RIR (registres d'adresses IP) :

  • Domaines (oui, même pour les RIR, pensez à in-addr.arpa et ip6.arpa),
  • Serveurs de noms,
  • Entités diverses, comme les handles, les identificateurs des contacts, genre GR283-FRNIC.

Deux classes sont spécifiques aux RIR :

On verra peut-être apparaître d'autres classes avec le temps, si l'usage de RDAP se répand.

La section 2 de notre RFC décrit comment JSON est utilisé. Le type MIME renvoyé est application/rdap+json. La section 2 commence par un rappel que le client RDAP doit ignorer les membres inconnus dans les objets JSON, afin de préserver la future extensibilité. (Cette règle ne s'applique pas au jCard - cf. RFC 7095 - embarqué.) Si un serveur veut ajouter des membres qui lui sont spécifiques, il est recommandé qu'il préfixe leur nom avec un identificateur court suivi d'un tiret bas. Ainsi, cet objet RDAP standard :

{
     "handle" : "ABC123",
     "remarks" :
     [
       {
         "description" :
         [
           "She sells sea shells down by the sea shore.",
           "Originally written by Terry Sullivan."
         ]
       }
     ]
   }

S'il est servi par le « registre de la Lune » (registre imaginaire qui fournit les exemples de ce RFC), celui-ci, lorsqu'il voudra ajouter des membres, les précédera de lunarNIC_ :

{
     "handle" : "ABC123",
     "lunarNic_beforeOneSmallStep" : "TRUE THAT!",
     "remarks" :
     [
       {
         "description" :
         [
           "She sells sea shells down by the sea shore.",
           "Originally written by Terry Sullivan."
         ]
       }
     ],
     "lunarNic_harshMistressNotes" :
     [
       "In space,",
       "nobody can hear you scream."
     ]
   }

(Je vous laisse décoder les références geeks dans l'exemple.)

La section 3 s'occupe des types de données de base. On utilise du JSON normal, tel que spécifié dans le RFC 8259, avec ses chaînes de caractères, ses booléens, son null... Un handle (l'identifiant unique - par registre - d'un contact, parfois nommé NIC handle ou registry ID) est une chaîne. Les adresses IP se représentent également par une chaîne de caractères (ne pas oublier le RFC 5952 pour IPv6). Les pays sont identifiés par le code à deux lettres de ISO 3166. Les noms de domaines peuvent être sous une forme ASCII ou bien en Unicode. Les dates et heures suivent le RFC 3339, et les URI le RFC 3986.

Les informations plus complexes (comme les détails sur un contact) utilisent jCard, normalisé dans le RFC 7095.

Que trouve-t-on dans les objets JSON renvoyés par un serveur RDAP ? Une indication de la version de la norme :

"rdapConformance" :
   [
     "rdap_level_0"
   ]

(Éventuellement avec d'autres identificateurs pour les extensions locales.) Et des liens vers des ressources situées ailleurs, suivant le cadre du RFC 8288 :

         "links": [
            {
               "href": "http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5", 
               "rel": "self", 
               "type": "application/rdap+json", 
               "value": "http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5"
            }

On peut aussi avoir du texte libre, comme dans l'exemple plus haut avec le membre remarks. Ce membre sert aux textes décrivant la classe, alors que notices est utilisé pour le service RDAP. Un exemple :

   "notices": [
      {
         "description": [
            "Access to AFILIAS WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the Afilias registry database. The data in this record is provided by Afilias Limited for informational purposes only, and Afilias does not guarantee its accuracy. [...]"
         ], 
         "title": "TERMS OF USE"
      }
   ], 

Contrairement à whois, RDAP permet l'internationalisation sous tous ses aspects. Par exemple, on peut indiquer la langue des textes avec une étiquette de langue (RFC 5646) :

   "lang": "en", 

Enfin, la classe (le type) de l'objet renvoyé par RDAP est indiquée par un membre objectClassName :

   "objectClassName": "domain", 

Ces classes, justement. La section 5 les décrit. Il y a d'abord la classe Entity qui correspond aux requêtes /entity du RFC 9082. Elle sert à décrire les personnes et les organisations. Parmi les membres importants pour les objets de cette classe, handle qui est un identificateur de l'instance de la classe, et roles qui indique la relation de cette instance avec l'objet qui la contient (par exemple "roles": ["technical"] indiquera que cette Entity est le contact technique de l'objet). L'information de contact sur une Entity se fait avec le format vCard du RFC 7095, dans un membre vcardArray. Voici un exemple avec le titulaire du domaine uba.ar :

% curl https://rdap.nic.ar/entity/30546666561
...
  "objectClassName": "entity",
  "vcardArray": [
    "vcard",
    [
      [
        "version",
        {},
        "text",
        "4.0"
      ],
      [
        "fn",
        {},
        "text",
        "UNIVERSIDAD DE BUENOS AIRES"
      ]
    ]
  ],
...

(jCard permet de mentionner plein d'autres choses qui ne sont a priori pas utiles pour RDAP, comme la date de naissance ou le genre.)

La classe Nameserver correspond aux requêtes /nameserver du RFC 9082. Notez qu'un registre peut gérer les serveurs de noms de deux façons : ils peuvent être vus comme des objets autonomes, enregistrés tels quel dans le registre (par exemple via le RFC 5732), ayant des attributs par exemple des contacts, et interrogeables directement par whois ou RDAP (c'est le modèle de .com, on dit alors que les serveurs de noms sont des « objets de première classe »). Ou bien ils peuvent être simplement des attributs des domaines, accessibles via le domaine. Le principal attribut d'un objet Nameserver est son adresse IP, pour pouvoir générer des colles dans le DNS (enregistrement DNS d'une adresse IP, pour le cas où le serveur de noms est lui-même dans la zone qu'il sert). Voici un exemple avec un des serveurs de noms de la zone afilias-nst.info :

% curl https://rdap.afilias.net/rdap/info/nameserver/b0.dig.afilias-nst.info 
...
  "ipAddresses": {
    "v4": [
      "65.22.7.1"
    ],
    "v6": [
      "2a01:8840:7::1"
    ]
  },
...

Notez que l'adresse IP est un tableau, un serveur pouvant avoir plusieurs adresses.

La classe Domain correspond aux requêtes /domain du RFC 9082. Un objet de cette classe a des membres indiquant les serveurs de noms, si la zone est signée avec DNSSEC ou pas, l'enregistrement DS si elle est signée, le statut (actif ou non, bloqué ou non), les contacts, etc. Voici un exemple :

% curl http://rdg.afilias.info/rdap/domain/afilias-nst.info  
...
   "nameservers": [
      {
         "ldhName": "a0.dig.afilias-nst.info", 
...
  "secureDNS": {
    "delegationSigned": false
  },
  ...
  "status": [
    "client transfer prohibited",
    "server delete prohibited",
    "server transfer prohibited",
    "server update prohibited"
  ],
...

La classe IP network rassemble les objets qu'on trouve dans les réponses aux requêtes /ip du RFC 9082. Un objet de cette classe ne désigne en général pas une seule adresse IP mais un préfixe, dont on indique la première (startAddress) et la dernière adresse (endAddress). Personnellement, je trouve cela très laid et j'aurai préféré qu'on utilise une notation préfixe/longueur. Voici un exemple :

% curl https://rdap.db.ripe.net/ip/131.111.150.25    
...
{
  "handle" : "131.111.0.0 - 131.111.255.255",
  "startAddress" : "131.111.0.0/32",
  "endAddress" : "131.111.255.255/32",
  "ipVersion" : "v4",
  "name" : "CAM-AC-UK",
  "type" : "LEGACY",
  "country" : "GB",
...

La dernière classe normalisée à ce stade est autnum (les AS), en réponse aux requêtes /autnum du RFC 9082. Elle indique notamment les contacts de l'AS. Pour l'instant, il n'y a pas de format pour indiquer la politique de routage (RFC 4012). Un exemple d'un objet de cette classe :

% curl  https://rdap.db.ripe.net/autnum/20766 
{
  "handle" : "AS20766",
  "name" : "GITOYEN-MAIN-AS",
  "type" : "DIRECT ALLOCATION",
...
    "handle" : "GI1036-RIPE",
    "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "NOC Gitoyen" ], [ "kind", { }, "text", "group" ], [ "adr", {
      "label" : "Gitoyen\n21 ter rue Voltaire\n75011 Paris\nFrance"
    }, "text", null ], [ "email", { }, "text", "noc@gitoyen.net" ] ] ],
...

Comme, dans la vie, il y a parfois des problèmes, une section de notre RFC, la section 6, est dédiée aux formats des erreurs que peuvent indiquer les serveurs RDAP. Le code de retour HTTP fournit déjà des indications (404 = cet objet n'existe pas ici, 403 = vous n'avez pas le droit de le savoir, etc) mais on peut aussi ajouter un objet JSON pour en indiquer davantage, objet ayant un membre errorCode (qui reprend le code HTTP), un membre title et un membre description. Voici un exemple sur le serveur RDAP de l'ARIN :

% curl -v http://rdap.arin.net/registry/autnum/99999
< HTTP/1.0 404 Not Found
< Mon, 10 May 2021 09:07:52 GMT
< Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips
...
{
...
  "errorCode" : 404,
  "title" : "AUTNUM NOT FOUND",
  "description" : [ "The autnum you are seeking as '99999' is/are not here." ]

Plus positive, la possibilité de demander de l'aide à un serveur RDAP, en se renseignant sur ses capacités, avec la requête /help. Son résultat est décrit dans la section 7 mais tous les serveurs RDAP actuels n'utilisent pas cette possibilité. En voici un où ça marche, à l'ARIN :

%  curl -s https://rdap.arin.net/registry/help 
{
  "rdapConformance" : [ "rdap_level_0" ],
  "notices" : [ {
    "title" : "Terms of Service",
    "description" : [ "By using the ARIN RDAP/Whois service, you are agreeing to the RDAP/Whois Terms of Use" ],
    "links" : [ {
      "value" : "https://rdap.arin.net/registry/help",
      "rel" : "about",
      "type" : "text/html",
      "href" : "https://www.arin.net/resources/registry/whois/tou/"
    } ]
  }, {
    "title" : "Whois Inaccuracy Reporting",
    "description" : [ "If you see inaccuracies in the results, please visit: " ],
    "links" : [ {
      "value" : "https://rdap.arin.net/registry/help",
      "rel" : "about",
      "type" : "text/html",
      "href" : "https://www.arin.net/resources/registry/whois/inaccuracy_reporting/"
    } ]
  }, {
    "title" : "Copyright Notice",
    "description" : [ "Copyright 1997-2021, American Registry for Internet Numbers, Ltd." ]
  } ]
}

Et les résultats des recherches ouvertes (section 3.2 du RFC 9082), qui peuvent renvoyer plusieurs objets ? Ce sont des tableaux JSON, dans des membres dont le nom se termine par Results. Par exemple, en cherchant les noms de domaines commençant par ra (ce test a été fait sur un serveur expérimental qui ne marche plus depuis) :

% curl http://rdg.afilias.info/rdap/domains\?name=ra\*|more           
   "domainSearchResults": [
      {
         "ldhName": "RAINSTRAGE.INFO", 
         ...
         "objectClassName": "domain", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
...
         "ldhName": "RADONREMOVAL.INFO", 
...
         "ldhName": "RANCONDI.INFO", 
...

Les vrais serveurs RDAP en production ne répondent pas forcément à ces requêtes trop coûteuses et qui peuvent trop facilement être utilisées pour le renseignement économique :

%  curl https://rdap.afilias.net/rdap/info/domains\?name=ra\*
...
"errorCode": 422,
  "title": "Error in processing the request",
  "description": [
    "WildCard search is not supported on sub-zone or tld"
  ]
  

Vous avez peut-être noté dans le tout premier exemple le membre events (section 4.5 du RFC). Ces événements comme created ou last-changed donnent accès à l'histoire d'un objet enregistré. Ici, nous apprenons que le domaine kornog-computing.info a été enregistré en 2007.

Certaines valeurs qui apparaissent dans les résultats sont des chaînes de caractères fixes, stockées dans un nouveau registre IANA. Elles sont conçues pour être utilisées dans les notices, remarks, status, roles et quelques autres. Parmi les remarques, on trouvera le cas où une réponse a été tronquée (section 9 du RFC), comme dans l'exemple ci-dessus avec la mention Incomplete Data. Parmi les statuts, on trouvera, par exemple validated (pour un objet vérifié, par exemple un nom de domaine dont on a vérifié les coordonnées du titulaire), locked (pour un objet verrouillé), obscured (qui n'est pas un statut dans le base du données du registre mais simplement la mention du fait que le serveur RDAP a délibérement modifié certaines informations qu'il affiche, par exemple pour protéger la vie privée), etc. Pour les rôles, on trouvera registrant (titulaire), technical (contact technique), etc.

Pour ceux qu'intéressent les questions d'internationalisation, la section 12 contient d'utiles mentions. L'encodage des données JSON doit être de l'UTF-8. Et, comme indiqué plus haut, les IDN peuvent être sous la forme Punycode ou bien directement en UTF-8.

Et la vie privée, un problème permanent avec whois, où il faut toujours choisir entre la distribution de données utiles pour contacter quelqu'un et les risques pour sa vie privée ? La section 13 revient sur cette question. Un point important : RDAP est un protocole, pas une politique. Il ne définit pas quelles règles suivre (c'est de la responsabilité des divers registres) mais il fournit les outils pour mettre en œuvre ces règles. Notamment, RDAP permet de marquer des parties de la réponse comme étant connues du registre, mais n'ayant délibérement pas été envoyées (avec les codes private et removed) ou bien comme ayant été volontairement rendues peu ou pas lisibles (code obscured).

Vous avez vu dans les exemples précédents que les réponses d'un serveur RDAP sont souvent longues et, a priori, moins lisibles que celles d'un serveur whois. Il faudra souvent les traiter avec un logiciel qui comprend le JSON. Un exemple très simple et que j'apprécie est jq. Il peut servir à présenter le résultat de manière plus jolie :

% curl -s https://rdap.centralnic.com/pw/domain/centralnic.pw  | jq .
...
{
  "objectClassName": "domain",
  "handle": "D956082-CNIC",
  "ldhName": "centralnic.pw",
  "nameservers": [
    {
      "objectClassName": "nameserver",
      "ldhName": "ns0.centralnic-dns.com",
...

(Essayez ce même serveur RDAP sans jq !)

Mais on peut aussi se servir de jq pour extraire un champ particulier, ici le pays :

% curl -s  https://rdap.db.ripe.net/ip/131.111.150.25 | jq ".country"
"GB"

% curl -s  https://rdap.db.ripe.net/ip/192.134.1.1 | jq ".country"
"FR"

Il y a évidemment d'autres logiciels que jq sur ce créneau, comme JSONpath, jpath ou, pour les programmeurs Python, python -m json.tool.

Un dernier mot, sur le choix de JSON pour le format de sortie, alors que le protocole standard d'avitaillement des objets dans les bases Internet, EPP (RFC 5730) est en XML. L'annexe E de notre RFC, qui discute ce choix, donne comme principaux arguments que JSON est désormais plus répandu que XML (cf. l'article « The Stealthy Ascendancy of JSON ») et que c'est surtout vrai chez les utilisateurs (EPP étant utilisé par une population de professionnels bien plus réduite).

Quels changements depuis le RFC 7483 ? La plupart sont mineurs et sont de l'ordre de la clarification. D'autres sont des corrections d'erreurs, par exemple une coquille qui avait mis registrant là où il aurait fallu dire registrar (la proximité des mots en anglais entraine souvent des erreurs, même chez les professionnels). Il y a une certaine tendance au durcissement des règles, des éléments qui étaient optionnels dans le RFC 7483 sont devenus obligatoires comme, par exemple, rdapConformance (dont le statut optionnel avait causé des problèmes).

Et question logiciels qui mettent en œuvre RDAP ? Beaucoup de logiciels de gestion de registre le font aujourd'hui, notamment ceux sous contrat avec l'ICANN, puisqu'ils n'ont pas le choix. Mais les logiciels ne sont pas forcément publiquement disponibles. Parmi ceux qui le sont, il y a RedDog, Fred, celui de l'APNIC


Téléchargez le RFC 9083


L'article seul

RFC 9082: Registration Data Access Protocol (RDAP) Query Format

Date de publication du RFC : Juin 2021
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs), A. Newton (AWS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 16 juin 2021


Le protocole d'information RDAP, qui vise à remplacer whois, est décrit dans un ensemble de RFC. Celui présenté ici normalise la façon de former les requêtes RDAP. Celles-ci ont la forme d'une URL, puisque RDAP repose sur l'architecture REST. Ce RFC remplace l'ancienne norme sur les requêtes RDAP, qui était dans le RFC 7482, mais il n'y a pas de changement significatif.

RDAP peut être utilisé pour beaucoup de sortes d'entités différentes mais ce RFC ne couvre que ce qui correspond aux usages actuels de whois, les préfixes d'adresses IP, les AS, les noms de domaine, etc. Bien sûr, un serveur RDAP donné ne gère pas forcément tous ces types d'entités, et il doit renvoyer le code HTTP 501 (Not implemented) s'il ne sait pas gérer une demande donnée. Ce RFC ne spécifie que l'URL de la requête, le format de la réponse est variable (JSON, XML...) et le seul actuellement normalisé, au-dessus de JSON, est décrit dans le RFC 9083. Quant au protocole de transport, le seul actuellement normalisé pour RDAP (dans le RFC 7480) est HTTP. D'autre part, ces RFC RDAP ne décrivent que le protocole entre le client RDAP et le serveur, pas « l'arrière-cuisine », c'est-à-dire l'avitaillement (création, modification et suppression) des entités enregistrées. RDAP est en lecture seule et ne modifie pas le contenu des bases de données qu'il interroge.

Passons aux choses concrètes. Une requête RDAP est un URL (RFC 3986). Celui-ci est obtenu en ajoutant un chemin spécifique à une base. La base (par exemple https://rdap.example.net/) va être obtenue par des mécanismes divers, comme celui du RFC 7484, qui spécifie un registre que vous pouvez trouver en ligne. On met ensuite un chemin qui dépend du type d'entité sur laquelle on veut se renseigner, et qui indique l'identificateur de l'entité. Par exemple, avec la base ci-dessus, et une recherche du nom de domaine internautique.fr, on construirait un URL complet https://rdap.example.net/domain/internautique.fr. Il y a cinq types d'entités possibles :

  • ip : les préfixes IP (notez qu'on peut chercher un préfixe en donnant juste une des adresses IP couvertes par ce préfixe),
  • autnum : les numéros de systèmes autonomes,
  • domain : un nom de domaine (notez que cela peut être un domaine dans in-addr.arpa ou ipv6.arpa),
  • nameserver : un serveur de noms,
  • entity : une entité quelconque, comme un bureau d'enregistrement, ou un contact identifié par un handle.

La requête est effectuée avec la méthode HTTP GET (les méthodes permettant de modifier le contenu du registre n'ont pas de sens ici, les modifications dans le registre sont plutôt faites avec EPP). Pour juste savoir si un objet existe, on peut aussi utiliser la méthode HEAD. Si on n'obtient pas de code 404, c'est que l'objet existe.

Pour ip, le chemin dans l'URL est /ip/XXXXXX peut être une adresse IPv4 ou IPv6 sous forme texte. Il peut aussi y avoir une longueur de préfixe à la fin donc /ip/2001:db8:1:a::/64 est un chemin valable. Ainsi, sur le service RDAP du RIPE-NCC, https://rdap.db.ripe.net/ip/2001:4b98:dc0:41:: est un URL possible. Testons-le avec curl (le format de sortie, en JSON, est décrit dans le RFC 9083, vous aurez peut-être besoin de passer le résultat à travers jq pour l'afficher joliment) :

% curl https://rdap.db.ripe.net/ip/2001:4b98:dc0:41:: 
{
  "handle" : "2001:4b98:dc0::/48",
  "startAddress" : "2001:4b98:dc0::/128",
  "endAddress" : "2001:4b98:dc0:ffff:ffff:ffff:ffff:ffff/128",
  "ipVersion" : "v6",
  "name" : "GANDI-HOSTING-DC0",
  "type" : "ASSIGNED",
  "country" : "FR",
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "GAD42-RIPE",
    "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "Gandi Abuse Department" ], [ "kind", { }, "text", "group" ], [ "adr", {
      "label" : "63-65 Boulevard Massena\n75013 Paris\nFrance"
...

J'ai utilisé curl mais, notamment pour formater plus joliment la sortie de RDAP, les vrais utilisateurs se serviront plutôt d'un client RDAP dédié comme RDAPBrowser sur Android, ou nicinfo. Voici une vue de RDAPbrowser: rdapbrowser.png

Pour autnum, on met le numéro de l'AS après /autnum/ (au format « asplain » du RFC 5396). Toujours dans l'exemple RIPE-NCC, https://rdap.db.ripe.net/autnum/208069 permet de chercher de l'information sur l'AS 208069 :

% curl https://rdap.db.ripe.net/autnum/208069
{
  "handle" : "AS208069",
  "name" : "ATAXYA",
  "type" : "DIRECT ALLOCATION",
  "entities" : [ {
    "handle" : "mc40833-RIPE",
    "roles" : [ "administrative", "technical" ],
    "objectClassName" : "entity"
  }, {
...

Pour les noms de domaines, on met le nom après /domain/. Ainsi, sur le serveur RDAP d'Afilias, https://rdap.afilias.net/rdap/info/domain/rmll.info nous donnera de l'information sur le domaine rmll.info. On peut mettre un nom en Unicode donc https://rdap.example.net/domain/potamochère.fr est valable, mais il devra être encodé comme l'explique la section 6.1, plus loin (en gros, UTF-8 en NFC). Si on ne veut pas lire cette information sur l'encodage, on peut aussi utiliser la forme Punycode, donc chercher avec https://rdap.example.net/domain/xn--potamochre-66a.fr. Un exemple réel, en Russie :

% curl https://api.rdap.nic.рус/domain/валфекс.рус
...
         {
      "eventAction": "registration",
      "eventDate": "2018-12-26T07:53:41.776927Z"
    },
    ...
                "adr",
            {
              "type": "Registrar Contact"
            },
            "text",
            [
              "",
              "",
              "125476, g. Moskva, ul. Vasilya Petushkova, dom 3, str. 1",
              "",
              "",
              "",
              "RU"
            ]
          ]
...
  

(Attention, le certificat ne sera accepté par curl que si curl a été compilé avec l'option « IDN ».)

On peut aussi se servir de RDAP pour les noms de domaines qui servent à traduire une adresse IP en nom :

% curl https://rdap.db.ripe.net/domain/1.8.a.4.1.0.0.0.0.d.1.4.1.0.0.2.ip6.arpa
{
  "handle" : "0.d.1.4.1.0.0.2.ip6.arpa",
  "ldhName" : "0.d.1.4.1.0.0.2.ip6.arpa",
  "nameServers" : [ {
    "ldhName" : "dns15.ovh.net"
  }, {
    "ldhName" : "ns15.ovh.net"
  } ],
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "OK217-RIPE",
    "roles" : [ "administrative" ]
  }, {
    "handle" : "OTC2-RIPE",
    "roles" : [ "zone", "technical" ]
  }, {
    "handle" : "OVH-MNT",
    "roles" : [ "registrant" ]
  } ],
  "remarks" : [ {
    "description" : [ "OVH IPv6 reverse delegation" ]
  } ],
...

Pour un serveur de noms, on met son nom après /nameserver donc, chez Afilias :

% curl https://rdap.afilias.net/rdap/info/nameserver/rmll1.rmll.info
{
...
   "ipAddresses": {
      "v4": [
         "80.67.169.65"
      ]
   }, 
   "lang": "en", 
   "ldhName": "rmll1.rmll.info", 
...

Pour entity, on indique juste un identificateur. Voici un exemple :

% curl  http://rdg.afilias.info/rdap/entity/81
{
   "handle": "81", 
   "lang": "en", 
...
   "roles": [
      "registrar"
   ], 
   "vcardArray": [
      "vcard", 
      [
         [
            "version", 
            {}, 
            "text", 
            "4.0"
         ], 
         [
            "fn", 
            {}, 
            "text", 
            "Gandi SAS"
         ], 
         [
            "adr", 
            {}, 
            "text", 
            [
               "", 
               "", 
               "63-65 boulevard Massena", 
               "Paris", 
               "", 
               "F-75013", 
               "FR"
            ]
...
  

Certains registres, qui stockent d'autres types d'objets, pourront ajouter leurs propres requêtes, en prenant soin d'enregistrer les préfixes de ces requêtes dans le registre IANA. Par exemple, le logiciel de gestion de registres FRED permet d'interroger le registre sur les clés DNSSEC avec les requêtes /fred_keyset (la syntaxe des requêtes locales est identificateur du préfixe + tiret bas + type cherché).

Dernière possibilité, un chemin spécial indique qu'on veut récupérer de l'aide sur ce serveur RDAP particulier. En envoyant help (par exemple https://rdap.example.net/help), on obtient un document décrivant les capacités de ce serveur, ses conditions d'utilisation, sa politique vis-à-vis de la vie privée, ses possibilités d'authentification (via les mécanismes de HTTP), l'adresse où contacter les responsables, etc. C'est l'équivalent de la fonction d'aide qu'offrent certains serveurs whois, ici celui de l'AFNIC :

% whois -h whois.nic.fr  -- -h
...
%% Option   Function
%% -------  -------------------------------------
%% -r       turn off recursive lookups
%% -n       AFNIC output format
%% -o       old fashioned output format (Default)
%% -7       force 7bits ASCII output format
%% -v       verbose mode for templates and help options
%%          (may be use for reverse query)
%% -T type  return only objects of specified type
%% -P       don't return individual objects in case of contact search
%% -h       informations about server features
%% -l lang  choice of a language for informations (you can specify US|EN|UK for
%%          english or FR for french)
%%
...

Pour RDAP, voyez par exemple https://rdap.nic.bzh/help (qui renvoie de l'HTML), ou, plus austères et se limitant à un renvoi à une page Web, http://rdap.apnic.net/help ou https://rdap.nic.cz/help.

Toutes les recherches jusque-là ont été des recherches exactes (pas complètement pour les adresses IP, où on pouvait chercher un réseau par une seule des adresses contenues dans le réseau). Mais on peut aussi faire des recherches plus ouvertes, sur une partie de l'identificateur. Cela se fait en ajoutant une requête (la partie après le point d'interrogation) dans l'URL et en ajoutant un astérisque (cf. section 4.1). Ainsi, https://rdap.example.net/domains?name=foo* cherchera tous les domaines dont le nom commence par la chaîne de caractères foo. (Vous avez noté que c'est /domains, au pluriel, et non plus /domain ?) Voici un exemple d'utilisation :

% curl  https://rdap.afilias.net/rdap/info/domains\?name=rm\*
...
  "errorCode": 422,
  "title": "Error in processing the request",
  "description": [
    "WildCard search is not supported on sub-zone or tld"
  ]
...

Eh oui, les requêtes ouvertes comme celle-ci posent à la fois des problèmes techniques (la charge du serveur) et politico-juridiques (la capacité à extraire de grandes quantités de la base de données). Elles sont donc typiquement utilisables seulement après une authentification.

On peut aussi chercher un domaine d'après ses serveurs de noms, par exemple https://rdap.example.net/domains?nsLdhName=ns1.example.com chercherait tous les domaines délégués au serveur DNS ns1.example.com. Une telle fonction peut être jugée très indiscrète et le serveur RDAP est toujours libre de répondre ou pas mais, ici, cela marche, on trouve bien le domaine qui a ce serveur de noms :

% curl  https://rdap.afilias.net/rdap/info/domains\?nsLdhName=ns0.abul.org 
...
"domainSearchResults": [
    {
      "objectClassName": "domain",
      "handle": "D10775367-LRMS",
      "ldhName": "rmll.info",
...
  

Deux autres types permettent ces recherches ouvertes, /nameservers (comme dans https://rdap.example.net/nameservers?ip=2001:db8:42::1:53, mais notez qu'on peut aussi chercher un serveur par son nom) et /entities (comme dans https://rdap.example.net/entities?fn=Jean%20Dupon*) :

% curl  http://rdg.afilias.info/rdap/entities\?fn=go\*     
{
   "entitySearchResults": [
      {
         "fn": "Go China Domains, Inc.", 
...
         "fn": "Gotnames.ca Inc.", 
...

Notez que ce type de recherche peut représenter un sérieux danger pour la vie privée (comme noté dans le RFC, par exemple en section 4.2) puisqu'elle permet, par exemple de trouver tous les titulaires prénommés Jean. Elle est donc parfois uniquement accessible à des clients authentifiés, et de confiance.

La section 4 détaille le traitement des requêtes. N'oubliez pas qu'on travaille ici sur HTTP et que, par défaut, les codes de retour RDAP suivent la sémantique HTTP (404 pour un objet non trouvé, par exemple). Il y a aussi quelques cas où le code à retourner est moins évident. Ainsi, si un serveur ne veut pas faire une recherche ouverte, il va répondre 422 (Unprocessable Entity).

Vous avez noté plus haut, mais la section 6 le rappelle aux distraits, que le nom de domaine peut être exprimé en Unicode ou en ASCII. Donc, https://rdap.example.net/domain/potamochère.fr et https://rdap.example.net/domain/xn--potamochre-66a.fr sont deux requêtes acceptables.

Enfin, la section 8 rappelle quelques règles de sécurité comme :

  • Les requêtes ouvertes peuvent mener à une forte consommation de ressources sur le serveur. Le serveur qui ne vaut pas se faire DoSer doit donc faire attention avant de les accepter.
  • Les requêtes RDAP, et surtout les requêtes ouvertes, peuvent soulever des questions liées à la vie privée. Les serveurs RDAP doivent donc réfléchir avant de renvoyer de l'information. Rappelez-vous que RDAP, contrairement à whois, peut avoir un mécanisme d'authentification, donc peut envoyer des réponses différentes selon le client.
  • Et, corollaire du précédent point, les gérants de serveurs RDAP doivent définir une politique d'autorisation : qu'est-ce que je renvoie, et à qui ?

Les changements depuis le RFC 7482 sont peu nombreux et sont surtout de clarification.


Téléchargez le RFC 9082


L'article seul

RFC 9079: Source-Specific Routing in Babel

Date de publication du RFC : Août 2021
Auteur(s) du RFC : M. Boutier, J. Chroboczek (IRIF, University of Paris)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF babel
Première rédaction de cet article le 29 août 2021


Traditionnellement, le routage dans l'Internet se fait sur la base de l'adresse IP de destination. Mais on peut aussi envisager un routage où l'adresse IP source est prise en compte. Ce nouveau RFC étend le protocole de routage Babel en lui ajoutant cette possibilité.

Babel, normalisé dans le RFC 8966 est un protocole de routage à vecteur de distance. Il est prévu par défaut pour du routage IP traditionnel, où le protocole de routage construit une table de transmission qui associe aux préfixes IP de destination le routeur suivant (next hop). Un paquet arrive dans un routeur ? Le routeur regarde dans sa table le préfixe le plus spécifique qui correspond à l'adresse IP de destination (utilisant pour cela une structure de données comme, par exemple, le Patricia trie) et, lorsqu'il le trouve, la table contient les coordonnées du routeur suivant. Par exemple, si une entrée de la table dit que 2001:db8:1:fada::/64 a pour routeur suivant fe80::f816:3eff:fef2:47db%eth0, un paquet destiné à 2001:db8:1:fada::bad:1234 sera transmis à ce fe80::f816:3eff:fef2:47db, sur l'interface réseau eth0. Cette transmission classique a de nombreux avantages : elle est simple et rapide, et marche dans la plupart des cas.

Mais ce mécanisme a des limites. On peut vouloir prendre en compte d'autres critères que l'adresse de destination pour la transmission d'un paquet. Un exemple où un tel critère serait utile est le multihoming. Soit un réseau IP qui est connecté à plusieurs opérateurs, afin d'assurer son indépendance et pour faire face à un éventuel problème (technique ou commercial) chez l'un des opérateurs. La méthode officielle pour cela est d'acquérir des adresses indépendantes du fournisseur et de faire router ces adresses par les opérateurs auxquels on est connectés (par exemple en leur parlant en BGP). Mais avoir de ces adresses PI (Provider-Independent) est souvent difficile. Quand on est passionnée, on y arrive mais ce n'est pas vraiment accessible à tout le monde. On se retrouve donc en général avec des adresses dépendant du fournisseur. C'est par exemple le cas de loin le plus courant pour le particulier, la petite association ou la PME. Dans ce cas, le multihoming est compliqué. Mettons que les deux fournisseurs d'accès se nomment A et B et que chacun nous fournisse un préfixe d'adresses IP. Si une machine interne a deux adresses IP, chacune tirée d'un des préfixes, et qu'elle envoie vers l'extérieur un paquet ayant comme adresse source une adresse de B, que se passe-t-il ? Si le paquet est envoyé via le fournisseur B, tout va bien. Mais s'il est envoyé via le fournisseur A, il sera probablement jeté par le premier routeur de A, puisque son adresse IP source ne sera pas une adresse du fournisseur (RFC 3704 et RFC 8704). Pour éviter cela, il faudrait pouvoir router selon l'adresse IP source, envoyant les paquets d'adresse source A vers le fournisseur A et ceux ayant une adresse source B vers B. En gros, soit l'information de routage influe sur le choix de l'adresse source, soit c'est le choix de l'adresse source qui influe sur le routage. On ne peut pas faire les deux, ou alors on risque une boucle de rétroaction. Ce RFC choisit la deuxième solution.

La première solution serait que la machine émettrice choisisse l'adresse IP source selon que les adresses de destination soient routées vers A ou vers B. Le RFC 3484 explique comment le faire en séquentiel et le RFC 8305 le fait en parallèle (algorithme dit des « globes oculaires heureux »). Mais les systèmes actuels ne savent typiquement pas le faire et, de toute façon, cela ne réglerait pas le cas où le routage change pendant la vie d'une connexion TCP. TCP, contrairement à QUIC ou SCTP, ne supporte pas qu'une adresse IP change en cours de route, sauf à utiliser les extensions du RFC 8684. Une dernière solution serait de laisser les applications gérer cela (cf. RFC 8445) mais on ne peut pas compter que toutes les applications le fassent. Bref, le routage tenant compte de la source reste souvent la meilleure solution.

À part le cas du multihoming, d'autres usages peuvent tirer profit d'un routage selon la source. Ce routage peut simplifier la configuration des tunnels. Il peut aussi être utile dans le cas de l'anycast. Lorsqu'on utilise du routage classique, fondé uniquement sur la destination, il est difficile de prédire quels clients du groupe anycast seront servis par quelle instance du groupe. Cela rend la répartition de charge compliquée (il faut jouer avec les paramètres des annonces BGP, par exemple) et cela pose des problèmes aux protocoles avec état, comme TCP, où un même client doit rester sur la même instance du groupe anycast. (Des utilisations de l'anycast pour des services sans état, comme le DNS sur UDP, n'ont pas ce problème.) Au contraire, avec du routage fait selon la source, chaque instance anycast peut annoncer sa route avec le ou les préfixes IP qu'on veut que cette instance serve.

D'ailleurs, si vous voulez en savoir plus sur le routage selon la source (ou SADR Source-Address Dependent Routing, également appelé SSR pour Source-Specific Routing), vous pouvez lire l'article détaillé des auteurs du RFC, « Source-Specific Routing ». On peut aussi noter que ce routage dépendant de la source n'est pas la même chose qu'un routage décidé par la source (source routing), qui indiquerait une liste de routeurs par où passer. Ici, chaque routeur reste maitre du saut suivant (sur le routage décidé par la source, voir RFC 8354, et un exemple dans le RFC 6554).

Bon, le routage tenant compte de la source est intéressant, OK. Mais, avant de s'y lancer, il faut faire attention à un petit problème, la spécificité des routes. Lorsqu'on route uniquement selon la destination, et que plusieurs routes sont possibles, la règle classique d'IP est celle de la spécificité. La route avec le préfixe le plus spécifique (le plus long) gagne. Mais que se passe t-il si on ajoute l'adresse source comme critère ? Imaginons qu'on ait deux routes, une pour la destination 2001:db8:0:1::/64 et s'appliquant à toutes les sources et une autre route pour toutes les destinations (route par défaut), ne s'appliquant qu'à la source 2001:db8:0:2::/64. On va noter ces deux routes sous forme d'un tuple (destination, source) donc, ici, (2001:db8:0:1::/64, ::/0) et (::/0, 2001:db8:0:2::/64). Pour un paquet venant de 2001:db8:0:2::1 et allant en 2001:db8:0:1::1, quelle est la route la plus spécifique ? Si on considère la spécificité de la destination d'abord, la route choisie sera la (2001:db8:0:1::/64, ::/0). Mais si on regarde la spécificité de la source en premier, ce sera l'autre route, la (::/0, 2001:db8:0:2::/64) qui sera adoptée. Doit-on laisser chaque machine libre de faire du destination d'abord ou du source d'abord ? Non, car tous les routeurs du domaine doivent suivre la même règle, autrement des boucles pourraient se former, un paquet faisant du ping-pong éternel entre un routeur « destination d'abord » et un routeur « source d'abord ». Babel impose donc une règle : pour déterminer la spécificité d'une route, on regarde la destination d'abord. Le choix n'est pas arbitraire, il correspond à des topologies réseau typique, avec des réseaux locaux pour lesquelles on a une route spécifique, et une route par défaut pour tout le reste.

Un autre point important est celui du système de transmission des paquets. Il faut en effet rappeler que le terme « routage » est souvent utilisé pour désigner deux choses très différentes. La première est le routage à proprement parler (routing en anglais), c'est-à-dire la construction des tables de transmission, soit statiquement, soit avec des protocoles de routage comme Babel. La seconde est la transmission effective des paquets qui passent par le routeur (forwarding en anglais). Si on prend un routeur qui tourne sur Unix avec le logiciel babeld, ce dernier assure bien le routage au sens strict (construire les tables de routage grâce aux messages échangés avec les autres routeurs) mais c'est le noyau Unix qui s'occupe de la transmission. Donc, si on veut ajouter des fonctions de routage tenant compte de la source, il ne suffit pas de le faire dans le programme qui fait du Babel, il faut aussi s'assurer que le système de transmission en est capable, et avec la bonne sémantique (notamment l'utilisation de la destination d'abord pour trouver la route la plus spécifique). Si Babel, avec les extensions de ce RFC, tourne sur un système qui ne permet pas cela, il faut se résigner à ignorer les annonces spécifiques à une source. (Pour des systèmes comme Linux, qui permet le routage selon la source mais avec une mauvaise sémantique, puisqu'il utilise la source d'abord pour trouver la route la plus spécifique, la section V-B de l'article des auteurs cité plus haut fournit un algorithme permettant de créer des tables de transmission correctes.)

Le passage du routage classique au routage tenant compte de la source nécessite de modifier les structures de données du protocole de routage, ici Babel (section 3 du RFC). Les différentes structures de données utilisées par une mise en œuvre de Babel doivent être modifiées pour ajouter le préfixe de la source, et plusieurs des TLV dans les messages que s'échangent les routeurs Babel doivent être étendus avec un sous-TLV (RFC 8966, section 4.4) qui contient un préfixe source. La section 5 du RFC détaille les modifications nécessaires du protocole Babel. Les trois types de TLV qui indiquent un préfixe de destination, Updates, Route Requests et Seqno, doivent désormais transporter en plus un sous-TLV indiquant le préfixe source, marqué comme obligatoire (RFC 8966, section 4.4), de façon à ce qu'une version de Babel ne connaissant pas le routage selon la source n'accepte pas des annonces incomplètes. Si une annonce ne dépend pas de l'adresse IP source, il ne faut pas envoyer un sous-TLV avec le préfixe ::/0 mais au contraire ne pas mettre de sous-TLV (les autres versions de Babel accepteront alors l'annonce).

Ainsi, des versions de Babel gérant les extensions de notre RFC 9079 et d'autres qui ne les gèrent pas (fidèles au RFC 8966) pourront coexister sur le même réseau, sans que des boucles de routage ne se forment. En revanche, comme la notion de sous-TLV obligatoire n'est apparue qu'avec le RFC 8966, les vieilles versions de Babel, qui suivent l'ancien RFC 6126, ne doivent pas être sur le même réseau que les routeurs à routage dépendant de la source.

Le nouveau sous-TLV Source Prefix a le type 128 et sa valeur comporte un préfixe d'adresses IP, encodé en {longueur, préfixe}.

Notez que si les routeurs qui font du routage selon la source n'annoncent que des routes ayant le sous-TLV indiquant un préfixe source, les routeurs qui ne gèrent pas ce routage selon la source, et qui ignorent donc cette annonce, souffriront de famine : il n'y aura pas de routes vers certaines destinations, conduisant le routeur à jeter les paquets. Il peut donc être prudent, par exemple, d'avoir une route par défaut sans condition liée à la source, pour ces routeurs qui ignorent cette extension.

Question sécurité, il faut signaler (section 9 du RFC), que cette extension au routage apporte davantage de souplesse, et que cela peut nécessiter une révision des règles de sécurité, si celles-ci supposaient que tous les paquets vers une destination donnée suivaient le même chemin. Ainsi, le filtrage des routes (RFC 8966, annexe C) pourra être inutile si des routes spécifiques à une source sont présentes. Autre supposition qui peut être désormais fausse : une route spécifique à une machine de destination (host route, c'est-à-dire un préfixe /128) n'est plus forcément obligatoire, une autre route pour certaines sources peut prendre le dessus.

Au moins deux mises en œuvre de cette extension existent, dans babeld depuis la version 1.6 (en IPv6 seulement), et dans BIRD depuis la 2.0.2.

Merci à Juliusz Chroboczek pour sa relecture, et pour ses bonnes remarques sur le choix entre le routage selon la source et les autres solutions.


Téléchargez le RFC 9079


L'article seul

RFC 9078: Reaction: Indicating Summary Reaction to a Message

Date de publication du RFC : Août 2021
Auteur(s) du RFC : D. Crocker (Brandenburg InternetWorking), R. Signes (Fastmail), N. Freed (Oracle)
Expérimental
Première rédaction de cet article le 5 août 2021


Vous trouvez que le courrier électronique, c'est vieux et ringard, et que les réseaux sociaux avec leurs possibilités de réaction (« J'aime ! », « Je partage ! », « Je rigole ! »), c'est mieux ? Et bien, vous n'êtes pas le seul ou la seule. Ce nouveau RFC normalise un mécanisme pour mettre des réactions courtes et impulsives dans le courrier électronique.

L'idée de base est que, si ce RFC plait et est mis en œuvre par les auteurs de MUA, on verra près du message qu'on lit un menu avec des émojis, et on cliquera dessus, et l'émetteur du message verra sur son propre MUA le message qu'il a envoyé accompagné de ces réactions. (Le RFC ne normalise pas une apparence particulière à ces réactions, cf. section 5.2 pour des idées qui ne sont que des suggestions.)

Bien sûr, on peut déjà répondre à un message avec des émojis dans le corps de la réponse. Mais l'idée est de structurer cette réaction pour permettre une utilisation plus proche de celle des réseaux sociaux, au lieu que la réaction soit affichée comme un message comme les autres. Liée au message originel, cette structuration permettra, par exemple, au MUA de l'émetteur originel de voir le nombre de Likes de son message… (Quant à savoir si c'est utile, c'est une autre histoire…)

Techniquement, cela fonctionnera avec la combinaison des en-têtes Content-Disposition: et In-Reply-To:. Voici un exemple montrant le format d'une réaction (négative…) à un message (le 12345@example.com) :

    
To: author@example.com
From: recipient@example.org
Date: Today, 29 February 2021 00:00:10 -800
Message-id: 56789@example.org
In-Reply-To: 12345@example.com
Subject: Re: Meeting
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Disposition: Reaction

👎

  

(Si vous n'avez pas les bons émojis sur votre système, le caractère en question était le pouce vers le bas.) Recevant cette réponse, le MUA de l'auteur (author@example.com) peut rechercher le message 12345@example.com et afficher que recipient@example.org n'est pas enthousiaste.

Le paramètre Reaction pour l'en-tête Content-Disposition: (RFC 2183) a été ajouté au registre IANA.

Le texte dans la partie MIME qui a l'en-tête Content-Disposition: Reaction est une ligne d'émojis. On peut utiliser les séquences d'émojis. Tous les émojis sont utilisables mais le RFC en liste cinq qui sont particulièrement importants car considérés comme la base, le minimum que devrait reconnaitre tout MUA :

Notez que le concept de séquence d'émojis n'est pas simple. Ce concept permet d'éviter de normaliser des quantités astronomiques d'émojis, en autorisation la combinaison d'émojis. Il est utilisé entre autres pour les drapeaux nationaux, ainsi le drapeau libanais sera 🇱🇧 (U+1F1F1 qui indique le L du code pays ISO 3166 et U+1F1E7 qui indique le B). Le RFC rappelle qu'écrire du code dans son application pour gérer ces séquences n'est pas raisonnable et qu'il vaut mieux utiliser une bibliothèque Unicode existante.

Les sections 4 et 5 du RFC donnent quelques idées aux auteurs de MUA sur la gestion de ces réactions. Normalement, l'IETF normalise des protocoles, pas des interfaces utilisateur. Mais cela n'interdit pas de parler un peu d'UX dans le RFC, comme indiqué plus haut. En outre, l'interface utilisateur vers le courrier est typiquement assez différente de celle des réseaux sociaux où ce concept de réaction existe. Ainsi, le RFC ne tranche pas sur la question de savoir s'il faut envoyer la réaction uniquement à l'auteur original du message, ou bien à tous les destinataires. Ou bien s'il faut envoyer un message contenant juste la partie Réaction ou si on peut la combiner avec un autre contenu. Et que faire si, depuis la même adresse, on reçoit plusieurs réactions, éventuellement contradictoires ? Ne garder que la dernière (attention, le courrier électronique ne conserve pas l'ordre d'envoi) ? Les additionner ?

Toujours en UX, le RFC note que la réception d'une image dépend beaucoup du récepteur. (Et, contrairement à ce que laisse entendre le RFC, ce n'est pas juste une question de « culture », des personnes de la même « culture » peuvent comprendre différemment la même image.) Il faut donc faire attention aux réactions, qui peuvent être mal comprises. (Ceci dit, c'est exactement pareil avec le texte seul.) Et, comme toujours sur l'Internet, cette possibilité pourra ouvrir de nouveaux problèmes de sécurité (utilisation pour l'hameçonnage ?).


Téléchargez le RFC 9078


L'article seul

RFC 9077: NSEC and NSEC3: TTLs and Aggressive Use

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : P. van Dijk (PowerDNS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 25 juillet 2021


Ce nouveau RFC corrige une légère bavure. Lorsqu'on utilise la mémorisation énergique du RFC 8198 pour synthétiser des réponses DNS en utilisant les informations DNSSEC, les normes existantes permettaient une mémorisation pendant une durée bien trop longue. Cette erreur (peu grave en pratique) est désormais corrigée.

Rappelons que le principe du RFC 8198 est d'autoriser un résolveur DNS à synthétiser des informations qu'il n'a normalement pas dans sa mémoire, notamment à partir des enregistrements NSEC de DNSSEC (RFC 4034, section 4). Si un résolveur interroge la racine du DNS :

    
%     dig @a.root-servers.net A foobar
...
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 37332
...
foo.			86400 IN NSEC food. NS DS RRSIG NSEC

  

La réponse est négative (NXDOMAIN) et un enregistrement NSEC annonce au client DNS qu'il n'y a pas de nom dans la racine entre .foo et .food. Si le résolveur mémorise cette information et qu'on lui demande par la suite un nom en .foocat, il n'aura pas besoin de contacter la racine, il sait, en raison de l'enregistrement NSEC que ce nom ne peut pas exister.

Bon, mais combien de temps le résolveur peut-il mémoriser cette non-existence ? Le RFC 2308 disait qu'une réponse négative (NXDOMAIN) pouvait être mémorisée pendant une durée indiquée par le minimum du champ Minimum de l'enregistrement SOA et du TTL de ce même enregistrement SOA. Mais le RFC 4034, normalisant DNSSEC, disait que l'enregistrement NSEC devait avoir un TTL égal au champ Minimum du SOA. Dans l'exemple de la racine du DNS, à l'heure actuelle, cela ne change rien, ces durées sont toutes égales. Mais elles pourraient être différentes. Si un enregistrement SOA a un Minimum à une journée mais un TTL d'une heure, le RFC 2308 impose une heure de mémorisation au maximum, le RFC 4034 permettait une journée… Ça pourrait même être exploité pour une attaque en faisant des requêtes qui retournent des enregistrements NSEC, afin de nier l'existence d'un nom pendant plus longtemps que prévu. [Bon, dans le monde réel, je trouve que c'est un problème assez marginal mais ce n'est pas une raison pour ne pas le corriger.]

Le RFC 8198 avait déjà tenté de corriger le problème mais sans y réussir. Notre nouveau RFC impose désormais clairement que, contrairement à ce que dit le RFC 4034 (et deux ou trois autres RFC sur DNSSEC), la durée maximale de mémorisation est bien le minimum du champ Minimum de l'enregistrement SOA et du TTL de ce même enregistrement SOA.

Si les logiciels que vous utilisez pour signer les zones ne peuvent pas être corrigées immédiatement, le RFC demande que vous changiez le contenu de la zone pour mettre la même valeur au champ Minimum de l'enregistrement SOA et au TTL de ce même enregistrement SOA.

En pratique, les signeurs suivants ont déjà été corrigés :


Téléchargez le RFC 9077


L'article seul

RFC 9076: DNS Privacy Considerations

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : T. Wicinski
Pour information
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 24 juillet 2021


La surveillance généralisée sur l'Internet est un gros problème pour la vie privée. L'IETF s'active donc à améliorer la protection de la vie privée contre cette surveillance (RFC 7258). Un protocole qui avait souvent été négligé dans ce travail est le DNS. Ce RFC décrit les problèmes de vie privée liés au DNS. Il remplace le RFC 7626, avec deux changements important, l'intégration des techniques de protection développées et déployées depuis l'ancien RFC et, malheureusement, beaucoup de propagande anti-chiffrement imposée par les acteurs traditionnels des résolveurs DNS qui ne veulent pas se priver de leurs possibilités de contrôle et de surveillance.

Ce RFC est en fait à la croisée de deux activités. L'une d'elles consiste à documenter les problèmes de vie privée, souvent ignorés jusqu'à présent dans les RFC. Cette activité est symbolisée par le RFC 6973, dont la section 8 contient une excellente analyse de ces problèmes, pour un service particulier (la présence en ligne). L'idée est que, même si on ne peut pas résoudre complètement le problème, on peut au moins le documenter, pour que les utilisateurs soient conscients des risques. Et la seconde activité qui a donné naissance à ce RFC est le projet d'améliorer effectivement la protection de la vie privée des utilisateurs du DNS, en marchant sur deux jambes : minimiser les données envoyées et les rendre plus résistantes à l'écoute, via le chiffrement. L'objectif de diminution des données a débouché sur la QNAME minimization spécifiée dans le RFC 7816 et le chiffrement a donné DoT (RFC 7858) et DoH (RFC 8484).

Donc, pourquoi un RFC sur les questions de vie privée dans le DNS ? Ce dernier est un très ancien protocole, dont l'une des particularités est d'être mal spécifié : aux deux RFC originaux, les RFC 1034 et RFC 1035, il faut ajouter dix ou vingt autres RFC dont la lecture est nécessaire pour tout comprendre du DNS. Et aucun travail de consolidation n'a jamais été fait, contrairement à ce qui a eu lieu pour XMPP, HTTP ou SMTP. Or, le DNS est crucial, car quasiment toutes les transactions Internet mettent en jeu au moins une requête DNS (ne me dites pas des bêtises du genre « moi, je télécharge avec BitTorrent, je n'utilise pas le DNS » : comment allez-vous sur thepiratebay.am ?) Mais, alors que les questions de vie privée liées à HTTP ont fait l'objet d'innombrables articles et études, celles liées au DNS ont été largement ignorées pendant longtemps (voir la bibliographie du RFC pour un état de l'art). Pourtant, on peut découvrir bien des choses sur votre activité Internet uniquement en regardant le trafic DNS.

Une des raisons du manque d'intérêt pour le thème « DNS et vie privée » est le peu de compétences concernant le DNS : le protocole est souvent ignoré ou mal compris. C'est pourquoi le RFC doit commencer par un rappel (section 1) du fonctionnement du DNS.

Je ne vais pas reprendre tout le RFC ici. Juste quelques rappels des points essentiels du DNS : il existe deux sortes de serveurs DNS, qui n'ont pratiquement aucun rapport. Il y a les serveurs faisant autorité et les résolveurs. Les premiers sont ceux qui connaissent de première main l'information pour une zone DNS donnée (comme fr ou wikipedia.org). Ils sont gérés par le titulaire de la zone ou bien sous-traités à un hébergeur DNS. Les seconds, les résolveurs, ne connaissent rien (à part l'adresse IP des serveurs de la racine). Ils interrogent donc les serveurs faisant autorité, en partant de la racine. Les résolveurs sont gérés par le FAI ou le service informatique qui s'occupe du réseau local de l'organisation. Ils peuvent aussi être individuels, ou bien au contraire être de gros serveurs publics comme Google Public DNS, gros fournisseur de la NSA. Pour prendre un exemple concret (et en simplifiant un peu), si M. Michu veut visiter le site Web http://thepiratebay.am/, son navigateur va utiliser les services du système d'exploitation sous-jacent pour demander l'adresse IP de thepiratebay.am. Le système d'exploitation va envoyer une requête DNS au résolveur (sur Unix, les adresses IP des résolveurs sont dans /etc/resolv.conf). Celui-ci va demander aux serveurs de la racine s'ils connaissent thepiratebay.am, il se fera rediriger vers les serveurs faisant autorité pour am, puis vers ceux faisant autorité pour thepiratebay.am. Le résolveur aura alors une réponse qu'il pourra transmettre au navigateur de M. Michu.

Principal point où j'ai simplifié : le DNS s'appuie beaucoup sur la mise en cache des données, c'est-à-dire sur leur mémorisation pour gagner du temps la fois suivante. Ainsi, si le même M. Michu, cinq minutes après, veut aller en http://armenpress.am/, son résolveur ne demandera rien aux serveurs de la racine : il sait déjà quels sont les serveurs faisant autorité pour am.

Le trafic DNS est un trafic IP ordinaire, typiquement porté par UDP. Mais il peut aussi fonctionner sur TCP et bientôt sur QUIC. Il peut être écouté, et comme il n'est pas toujours chiffré, un indiscret peut tout suivre. Voici un exemple pris avec tcpdump sur un serveur racine (pas la racine officielle, mais, techniquement, cela ne change rien) :

15:29:24.409283 IP6 2001:67c:1348:8002::7:107.10127 > \
    2001:4b98:dc2:45:216:3eff:fe4b:8c5b.53: 32715+ [1au] \
    AAAA? www.armenpress.am. (46)

On y voit que le client 2001:67c:1348:8002::7:107 a demandé l'adresse IPv6 de www.armenpress.am.

Pour compléter le tableau, on peut aussi noter que les logiciels génèrent un grand nombre de requêtes DNS, bien supérieur à ce que voit l'utilisateur. Ainsi, lors de la visite d'une page Web, le résolveur va envoyer la requête primaire (le nom du site visité, comme thepiratebay.am), des requêtes secondaires dues aux objets contenus dans la page Web (JavaScript, CSS, divers traqueurs et autres outils de cyberflicage ou de cyberpub) et même des requêtes tertiaires, lorsque le fonctionnement du DNS lui-même nécessitera des requêtes. Par exemple, si abc.xyz est hébergé sur des serveurs dans google.com, une visite de http://abc.xyz/ nécessitera de résoudre les noms comme ns1.google.com, donc de faire des requêtes DNS vers les serveurs de google.com.

Bien sûr, pour un espion qui veut analyser tout cela, le trafic DNS représente beaucoup de données, souvent incomplètes en raison de la mise en cache, et dont l'interprétation peut être difficile (comme dans l'exemple ci-dessus). Mais les organisations qui pratiquent l'espionnage massif, comme la NSA, s'y connaissent en matière de big data et savent trouver les aiguilles dans les bottes de foin.

Les sections 3 à 7 du RFC détaille les risques pour la vie privée dans les différents composants du DNS. Notez que la confidentialité du contenu du DNS n'est pas prise en compte (elle l'est dans les RFC 5936 et RFC 5155). Il est important de noter qu'il y a une énorme différence entre la confidentialité du contenu et la confidentialité des requêtes. L'adresse IP de www.charliehebdo.fr n'est pas un secret : les données DNS sont publiques, dès qu'on connait le nom de domaine, et tout le monde peut faire une requête DNS pour la connaitre. Mais le fait que vous fassiez une requête pour ce nom ne devrait pas être public. Vous n'avez pas forcément envie que tout le monde le sache. (On peut quand même nuancer un peu le côté « public » des données DNS : on peut avoir des noms de domaine purement internes à une organisation. Mais ces noms « fuitent » souvent, par la marche sur la zone décrite dans le RFC 4470, ou via des systèmes de « passive DNS).

Pour comprendre les risques, il faut aussi revenir un peu au protocole DNS. Les deux informations les plus sensibles dans une requête DNS sont l'adresse IP source et le nom de domaine demandé (qname, pour Query Name, cf. RFC 1034, section 3.7.1). L'adresse IP source est celle de votre machine, lorsque vous parlez au résolveur, et celle du résolveur lorsqu'il parle aux serveurs faisant autorité. Elle peut indiquer d'où vient la demande. Lorsque on utilise un gros résolveur, celui-ci vous masque vis-à-vis des serveurs faisant autorité (par contre, ce gros résolveur va avoir davantage d'informations). Ceci dit, l'utilisation d'ECS (RFC 7871) peut trahir votre adresse IP, ou au moins votre préfixe. (Cf. cette analyse d'ECS. D'autre part, certains opérateurs se permettent d'insérer des informations comme l'adresse MAC dans des options EDNS de la requête.)

Quant au qname, il peut être très révélateur : il indique les sites Web que vous visitez, voire, dans certains cas, les logiciels utilisés. Au moins un client BitTorrent fait des requêtes DNS pour _bittorrent-tracker._tcp.domain.example, indiquant ainsi à beaucoup de monde que vous utilisez un protocole qui ne plait pas aux ayant-droits. Et si vous utilisez le RFC 4255, pas mal de serveurs verront à quelles machines vous vous connectez en SSH...

Donc où un méchant qui veut écouter votre trafic DNS peut-il se placer ? D'abord, évidemment, il suffit qu'il écoute le trafic réseau. On l'a dit, le trafic DNS aujourd'hui est souvent en clair donc tout sniffer peut le décoder. Même si vous utilisez HTTPS pour vous connecter à un site Web, le trafic DNS, lui, ne sera pas chiffré. (Les experts pointus de TLS noteront qu'il existe d'autres faiblesses de confidentialité, comme le SNI du RFC 6066, qui n'est pas encore protégé, cf. RFC 8744.) À noter une particularité du DNS : le trafic DNS peut passer par un autre endroit que le trafic applicatif. Alice peut naïvement croire que, lorsqu'elle se connecte au serveur de Bob, seul un attaquant situé physiquement entre sa machine et celle de Bob représente une menace. Alors que son trafic DNS peut être propagé très loin, et accessible à d'autres acteurs. Si vous utilisez, par exemple, le résolveur DNS public de FDN, toute la portion de l'Internet entre vous et FDN peut facilement lire votre trafic DNS.

Donc, l'éventuel espion peut être près du câble, à écouter. Mais il peut être aussi dans les serveurs. Bercé par la musique du cloud, on oublie souvent cet aspect de la sécurité : les serveurs DNS voient passer le trafic et peuvent le copier. Pour reprendre les termes du RFC 6973, ces serveurs sont des assistants : ils ne sont pas directement entre Alice et Bob mais ils peuvent néanmoins apprendre des choses à propos de leur conversation. Et l'observation est très instructive. Elle est utilisée à de justes fins dans des systèmes comme DNSDB (section 6 du RFC) mais il n'est pas difficile d'imaginer des usages moins sympathiques comme dans le cas du programme NSA MORECOWBELL.

Les résolveurs voient tout le trafic puisqu'il y a peu de mise en cache en amont de ces serveurs. Il faut donc réfléchir à deux fois avant de choisir d'utiliser tel ou tel résolveur ! Il est déplorable qu'à chaque problème DNS (ou supposé tel), des ignorants bondissent sur les réseaux sociaux pour dire « zyva, mets 8.8.8.8 [Google Public DNS] comme serveur DNS et ça ira plus vite » sans penser à toutes les données qu'ils envoient à la NSA ainsi.

Les serveurs faisant autorité voient passer moins de trafic (à cause des caches des résolveurs) mais, contrairement aux résolveurs, ils n'ont pas été choisis délibérement par l'utilisateur. Celui-ci peut ne pas être conscient que ses requêtes DNS seront envoyées à plusieurs acteurs du monde du DNS, à commencer par la racine. Le problème est d'autant plus sérieux que, comme le montre une étude, la concentration dans l'hébergement DNS est élevée : dix gros hébergeurs hébergent le tiers des domaines des 100 000 sites Web les plus fréquentés (listés par Alexa).

Au passage, le lecteur attentif aura noté qu'un résolveur personnel (sur sa machine ou dans son réseau local) a l'avantage de ne pas envoyer vos requêtes à un résolveur peut-être indiscret mais l'inconvénient de vous démasquer vis-à-vis des serveurs faisant autorité, puisque ceux-ci voient alors votre adresse IP. Une bonne solution (qui serait également la plus économe des ressources de l'Internet) serait d'avoir son résolveur local et de faire suivre les requêtes non résolues au résolveur du FAI. Du point de vue de la vie privée, ce serait sans doute la meilleure solution mais cela ne résout hélas pas un autre problème, celui des DNS menteurs, contre lesquels la seule protection est d'utiliser uniquement un résolveur de confiance. On peut résoudre ce problème en ayant son propre résolveur mais qui fait suivre à un résolveur public de confiance. Notez que la taille compte : plus un résolveur est petit, moins il protège puisque ses requêtes sortantes ne seront dues qu'à un petit nombre d'utilisateurs.

Enfin, il y a aussi les serveurs DNS « pirates » (installés, par exemple, via un serveur DHCP lui-même pirate) qui détournent le trafic DNS, par exemple à des fins de surveillance. Voir par exemple l'exposé de Karrenberg à JCSA 2012 disponible en ligne (transparents 27 et 28, Unknown et Other qui montrent l'existence de clones pirates du serveur racine K.root-servers.net).

Pour mes lecteurs en France férus de droit, une question intéressante : le trafic DNS est-il une « donnée personnelle » au sens de la loi Informatique & Libertés ? Je vous laisse plancher sur la question, qui a été peu étudiée.

Les changements depuis le RFC 7626 sont résumés dans l'annexe A. Outre des retours d'expérience basés sur le déploiement de solutions minimisant et/ou chiffrant les données, ils consistent essentiellement en remarques négatives sur le chiffrement, défendant le mécanisme traditionnel de résolution DNS. Il n'y avait d'ailleurs pas forcément d'urgence à sortir un nouveau RFC. Comme le demandait Alissa Cooper, l'auteure du RFC 6973, « Why not wait to see how QUIC, DOH, ADD, ODNS, etc. shake out in the next few years and take this up then? ». C'est en raison de ces changements négatifs que je ne suis pas cité comme auteur du RFC (contraitement à son prédécesseur). Sara Dickinson, qui avait géré l'essentiel du travail pour les débuts de ce nouveau RFC, s'est également retirée, en raison de la dureté des polémiques qui ont déchiré l'IETF sur ce document.

Depuis la sortie du RFC 7626, il y a eu un certain nombre de déploiement de techniques améliorant la protection de la vie privée dans le cas du DNS, notamment la minimisation des données (RFC 7816) et le chiffrement (DoT, RFC 7858, DoH, RFC 8484, et le futur DoQ). Cela permet des retours d'expérience. Par exemple, sur l'ampleur du déploiement de la minimisation, ou sur les performances du chiffrement (voir « An End-to-End, Large-Scale Measurement of DNS-over-Encryption »). Il y a eu également des discussions politiques à propos de ces techniques et de leur déploiement, souvent malhonnêtes ou confuses (et ce RFC en contient plusieurs) comme l'accusation de « centralisation », qui sert surtout à protéger l'état actuel, où l'opérateur de votre réseau d'accès à l'Internet peut à la fois vous surveiller et contrôler ce que vous voyez, via sa gestion de la résolution DNS. Mais il est vrai que rien n'est simple en matière de sécurité et que DoH (mais pas DoT) est trop bavard, puisqu'il hérite des défauts de HTTP, en envoyant trop d'informations au serveur.

Le RFC essaie de décourager les utilisateurs d'utiliser le chiffrement (dans l'esprit du RFC 8404) en notant que ce n'est pas une technologie parfaite (par exemple, l'observation des métadonnées peut donner des indications ou, autre exemple, une mauvaise authentification du résolveur peut vous faire envoyer vos requêtes à un méchant). C'est vrai mais c'est le cas de toutes les solutions de sécurité et on ne trouve pas de tels avertissements dans d'autres RFC qui parlent de chiffrement. L'insistance des opérateurs pour placer ces messages anti-chiffrement dans ce RFC montre bien, justement, l'importance de se protéger contre la curiosité des opérateurs.

Le RFC remarque également qu'il n'existe pas actuellement de moyen de découvrir automatiquement le résolveur DoT ou DoH. Mais c'est normal : un résolveur DoT ou DoH annoncé par le réseau d'accès, par exemple via DHCP, n'aurait guère d'intérêt, il aurait les mêmes défauts (et les mêmes qualités) que le résolveur traditionnel. DoT et DoH n'ont de sens qu'avec un résolveur configuré statiquement. Le RFC cite des déploiements de résolveurs DNS avec chiffrement faits par plusieurs FAI (aucun en France, notons-le). Cela montre une grosse incompréhension du problème : on ne chiffre pas pour le plaisir de chiffrer, mais parce que cela permet d'aller de manière sécurisée vers un autre résolveur. Chiffrer la communication avec le résolveur habituel ne fait pas de mal mais on ne gagne pas grand'chose puisque ce résolveur a les mêmes capacités de surveillance et de modification des réponses qu'avant. Notons que le RFC, inspiré par la propagande des telcos, raconte que le risque de surveillance est minimisé par le chiffrement du lien radio dans les réseaux 4G et après. Cela oublie le fait que la surveillance peut justement venir de l'opérateur.

Plus compliqué est le problème de l'endroit où se fait cette configuration. Traditionnellement, la configuration du résolveur à utiliser était faite globalement par le système d'exploitation. Ce n'est pas du tout une règle du protocole DNS (les RFC normalisant le DNS ne contrôlent que ce qui circule sur le câble, pas les choix locaux de chaque machine) et il serait donc absurde d'invoquer un soi-disant principe comme quoi le DNS serait forcément géré au niveau du système. Certains déploiements de DoH (celui de Firefox, par exemple), mettent le réglage dans l'application (en l'occurrence le navigateur Web). La question est discutable et discutée mais, de toute façon, elle ne relève pas de l'IETF (qui normalise ce qui passe sur le réseau) et il est anormal que le RFC en parle.

Le temps passé depuis le RFC 7626 a également permis la mise en service d'un plus grand nombre de résolveurs publics, comme Quad9 ou comme celui de Cloudflare. Mais il n'y a pas que les grosses boîtes états-uniennes qui gèrent des résolveurs DNS publics. Ainsi, je gère moi-même un modeste résolveur public. Le très intéressant RFC 8932 explique le rôle des politiques de vie privée dans ces résolveurs publics et comment en écrire une bonne. Bien sûr, comme toujours en sécurité, la lutte de l'épée contre la cuirasse est éternelle et des nouvelles actions contre la vie privée et la liberté de choix apparaissent, par exemple des réseaux qui bloquent l'accès à DoT (en bloquant son port 853) ou aux résolveurs DoH connus (DoH a été développé en partie pour être justement plus difficile à bloquer).


Téléchargez le RFC 9076


L'article seul

RFC des différentes séries : 0  1000  2000  3000  4000  5000  6000  7000  8000  9000