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 1997: BGP Communities Attribute

Date de publication du RFC : Août 1996
Auteur(s) du RFC : Ravishanker Chandrasekeran (cisco Systems), Paul Traina (cisco Systems), Tony Li
Chemin des normes
Première rédaction de cet article le 17 février 2017


Il n'y a pas de rapport simple entre la longueur d'un RFC et l'importance de la norme technique qu'il spécifie. Ce RFC (vieux de plus de vingt ans) ne fait que cinq pages mais décrit une technique qui est essentielle au bon fonctionnement du routage sur l'Internet, la technique des communautés BGP.

Rien de plus simple que cette idée : une communauté est juste une étiquette numérique qu'on ajoute aux annonces de routes IP transportées par le protocole BGP. On peut ainsi « décorer » ses annonces comme on veut, et les autres routeurs BGP pourront ainsi prendre des décisions fondées sur cette information supplémentaire. Les communautés sont juste une syntaxe, on leur met la signification qu'on veut.

Un tout petit rappel sur BGP : c'est le protocole d'échange de routes entre les opérateurs Internet. Son principe est simple (RFC 4271) : quand une route apparait, on annonce à ses pairs BGP la route, sous la forme d'un préfixe d'adresses IP, avec un certain nombre d'attributs. Les attributs ont un format et une sémantique précise. Voici un exemple d'une annonce reçue par le service RouteViews, et affichée sous forme texte par le logiciel bgpdump :

TIME: 02/17/17 15:00:00
TYPE: BGP4MP/MESSAGE/Update
FROM: 208.51.134.246 AS3549
TO: 128.223.51.102 AS6447
ORIGIN: IGP
ASPATH: 3549 3356 2914 30259
NEXT_HOP: 208.51.134.246
MULTI_EXIT_DISC: 13920
ATOMIC_AGGREGATE
AGGREGATOR: AS30259 10.11.1.1
COMMUNITY: 2914:410 2914:1001 2914:2000 2914:3000 3356:3 3356:86 3356:575 3356:666 3356:2011 3356:11940 3549:2011 3549:2017 3549:2521 3549:2582 3549:2950 3549:2991 3549:30840 3549:31826 3549:32344 3549:33036 3549:34076
WITHDRAW
  93.181.192.0/19
ANNOUNCE
  199.193.160.0/22
  

On y voit que le routeur 208.51.134.246, appartenant à l'AS 3549 (Level 3, ex-Global Crossing) a annoncé une route à destination du préfixe 199.193.160.0/22 (il a aussi retiré une autre route mais on ne s'en soucie pas ici). Cette annonce avait plusieurs attributs comme le chemin d'AS (ASPATH) emprunté. Les communautés (au nombre de 21 ici) sont un attribut COMMUNITY dont le format est défini mais dont on fait ensuite ce qu'on veut. L'utilisation la plus courante est d'indiquer l'origine d'une route, pour d'éventuelles décisions ultérieures, en fonction de la politique de routage. Les communautés sont donc un outil pour gérer la complexité de ces politiques.

Le RFC définit d'ailleurs une communauté comme « un groupe de destinations partageant une propriété commune ». Ainsi, dans le cas de l'annonce ci-dessus, la lecture de la documentation des différents opérateurs nous apprend que 3549:31826 indique que la route a été apprise en Europe, au Royaume-Uni, que 2914:410 nous montre qu'il s'agissait d'une route d'un client (et non pas d'un pair) de NTT, etc.

L'exemple d'utilisation donné par le RFC date pas mal (NSFNET n'existe plus) mais ce genre de cas est toujours fréquent. NSFNET, financé par l'argent public, ne permettait pas d'utilisation purement commerciale. Une entreprise à but lucratif pouvait s'y connecter, mais seulement pour échanger avec les organismes de recherche ou d'enseignement (le RFC parle d'organismes respectant l'AUP, qui étaient les conditions d'utilisation de NSFNET). Une telle politique est facile à faire avec les communautés : on étiquette toutes les routes issues du monde enseignement/recherche avec une communauté signifiant « route AUP », et NSFNET pouvait annoncer les routes AUP à tous et les routes non-AUP (n'ayant pas cette communauté) seulement aux client AUP. Ainsi, deux entreprises commerciales ne pouvaient pas utiliser NSFNET pour communiquer entre elles. Sans les communautés, une telle politique aurait nécessité une base complexe de préfixes IP, base difficile à maintenir, d'autant plus que tous les routeurs de bord devaient y accéder. (Avant les communautés, c'était bien ainsi qu'on procédait, avec les retards et les erreurs qu'on imagine.)

Autre exemple d'utilisation donné par le RFC, l'agrégation de routes. Si on annonce à la fois un préfixe englobant et un sous-préfixe plus spécifique pour optimiser l'accès à un site particulier, on ne souhaite en général annoncer ce sous-préfixe qu'aux pairs proches (les autres n'ont pas de chemin meilleur vers ce site). On va donc étiqueter l'annonce faite à ces pairs proches avec une communauté indiquant « cette route est pour vous, mais ne la propagez pas ». D'autres exemples d'utilisation figurent dans les RFC 1998 et RFC 4384.

L'attribut COMMUNITY (le RFC le nomme COMMUNITIES, ce qui est effectivement plus logique, mais il a bien été enregistré sous le nom COMMUNITY) est donc un attribut optionnel (certaines annonces BGP ne l'utiliseront pas) et transitif (c'est-à-dire qu'il est conçu pour être transmis avec l'annonce lorsqu'on la relaie à ses pairs). Il consiste en un ensemble (non ordonné, donc) de communautés, chacune occupant quatre octets (ce qui est bien insuffisant aujourd'hui). Son code de type d'attribut est 8. Le nombre de communautés dans une annonce est très variable. Par exemple, le LU-CIX voit une moyenne de 10,5 communautés par route sur ses serveurs de routes.

Si un attribut COMMUNITY est mal formé, en vertu du RFC 7606, la route annoncée sera retirée. (À l'époque du RFC originel, une erreur aboutissait à fermer toute la session BGP, retirant toutes les routes.)

Chaque communauté peut donc aller de 0x0000000 à 0xFFFFFFFF mais les valeurs de 0x0000000 à 0x0000FFFF, et de 0xFFFF0000 à 0xFFFFFFFF sont réservées. D'autre part, la convention recommandée est de mettre son numéro d'AS dans les deux premiers octets, et une valeur locale à l'AS dans les deux derniers. (Notez que ce système ne marche plus avec les AS de quatre octets du RFC 6793, ce qui a mené aux RFC 4360 et RFC 8092.) Prenons comme exemple de communauté 0x0D1C07D1. On note les communautés sous forme de deux groupes de deux octets chacun, séparés par un deux-points. Cette communauté est donc 3356:2001 : AS 3356 (Level 3) et valeur locale 2001 (le choix des valeurs locales est une décision... locale donc on ne peut savoir ce que signifie 2001 qu'en regardant la documentation de Level 3. Dit autrement, la valeur locale est opaque.)

Certaines valeurs sont réservées à des communautés « bien connues ». C'est le cas par exemple de 0xFFFFFF01 (alias NO_EXPORT : ne pas transmettre cette annonce en dehors de son AS), de 0xFFFFFF02 (NO_ADVERTISE, ne transmettre cette annonce à aucun autre routeur) ou bien de la plus récente 0xFFFF029A (BLACKHOLE, RFC 7999). Rappelez-vous que chaque routeur est maître de ses décisions : les communautés bien connues sont une suggestion, mais on ne peut jamais être sûr que le pair va la suivre (c'est ainsi que, malgré les NO_EXPORT que mettent les nœuds anycast qui veulent rester relativement locaux, on voit dans certains cas les annonces se propager plus loin, parfois pour des bonnes et parfois pour des mauvaises raisons.)

Enfin, le RFC précise qu'un routeur est libre d'ajouter ses propres communautés aux annonces qu'il relaie, voire de supprimer des communautés existantes (chacun est maître de son routage).

Quelques bonnes lectures sur les communautés BGP :

Certains looking glass affichent les communautés par exemple celui de Cogent :

 BGP routing table entry for 129.250.0.0/16, version 3444371605
Paths: (1 available, best #1, table Default-IP-Routing-Table)
  2914
    130.117.14.250 (metric 10109031) from 38.28.1.83 (38.28.1.83)
      Origin IGP, metric 4294967294, localpref 100, valid, internal, best
      Community: 174:11102 174:20666 174:21100 174:22010
      Originator: 38.28.1.32, Cluster list: 38.28.1.83, 38.28.1.67, 38.28.1.235

Les communautés sont souvent documentées dans l'objet AS stocké dans la base d'un RIR et accessible via whois (ou, aujourd'hui, RDAP). Ici, celle du France-IX (notez l'utilisation d'AS privés) :

% whois AS51706
...
aut-num:        AS51706
as-name:        FRANCE-IX-AS
...
remarks:        The following communities can be used by members:
remarks:
remarks:        *****************************************************
remarks:        ** Note: These communities are evaluated
remarks:        ** on a "first match win" basis
remarks:        *****************************************************
remarks:        0:peer-as = Don't send route to this peer as
remarks:        51706:peer-as = Send route to this peer as
remarks:        0:51706 = Don't send route to any peer
remarks:        51706:51706 = Send route to all peers
remarks:        *****************************************************
remarks:        ** Note: the community (51706:51706) is applied
remarks:        ** by default by the route-server
remarks:        *****************************************************
remarks:
remarks:        65101:peer-as = Prepend 1x to this peer
remarks:        65102:peer-as = Prepend 2x to this peer
remarks:        65103:peer-as = Prepend 3x to this peer
remarks:        65201:peer-as = Set MED 50 to this peer
remarks:        65202:peer-as = Set MED 100 to this peer
remarks:        65203:peer-as = Set MED 200 to this peer
remarks:
remarks:        -----------------------------------------------------
remarks:        BLACKHOLING, set the next-hop to the blackhole router
remarks:        can be use with the basic community (above)
remarks:
remarks:        65535:666 = BLACKHOLE [RFC7999]
remarks:
remarks:        https://www.franceix.net/en/technical/blackholing/
remarks:
remarks:        -----------------------------------------------------
remarks:        Set peer-as value as listed below for all IXP members:
remarks:        (Can't be used for 51706:peer-as)
remarks:        64649 = FranceIX Marseille peers
remarks:        64650 = FranceIX Paris peers
remarks:        64651 = SFINX peers
remarks:        64652 = LyonIX peers
remarks:        64653 = LU-CIX peers
remarks:        64654 = TOP-IX peers
remarks:        64655 = TOUIX peers
remarks:
remarks:        -----------------------------------------------------
remarks:        Set peer-as value as listed below for 32 bits ASNs:
remarks:        AS197422 -> AS64701 (Tetaneutral)
remarks:        AS196689 -> AS64702 (Digicube)
[...]
remarks:
remarks:        Extended Communities are supported and usage is
remarks:        encouraged instead of 32b->16b mapping
remarks:        -----------------------------------------------------
remarks:        Communities that are in the public range
remarks:        (1-64495:x) and (131072-4199999999:x)
remarks:        will be preserved by the route-servers
remarks:        -----------------------------------------------------
remarks:        Well-known communities are not interpreted by the
remarks:        route-servers and are propagated to all peers
remarks:        -----------------------------------------------------
remarks:
remarks:        The following communities are applied by the route-server:
remarks:
remarks:        *****************************************************
remarks:        ** WARNING
remarks:        ** You should not set any of these by yourself
remarks:        ** (from 51706:64495 to 51706:64699)
remarks:        ** (and 51706:64800 to 51706:65535)
remarks:        ** If you do so, your routes will be rejected
remarks:        *****************************************************
remarks:
remarks:        51706:64601 = Prefix received from a peer on RS1 Paris
remarks:        51706:64602 = Prefix received from a peer on RS2 Paris
remarks:        51706:64611 = Prefix received from a peer on RS1 Marseille
remarks:        51706:64612 = Prefix received from a peer on RS2 Marseille
remarks:
remarks:        51706:64649 = Prefix received from a FranceIX Marseille peer
remarks:        51706:64650 = Prefix received from a FranceIX Paris peer
remarks:        51706:64651 = Prefix received from a SFINX peer
remarks:        51706:64652 = Prefix received from a LyonIX peer
remarks:        51706:64653 = Prefix received from a LU-CIX peer
remarks:        51706:64654 = Prefix received from a TOP-IX peer
remarks:        51706:64655 = Prefix received from a TOUIX peer
remarks:
remarks:        51706:64666 = Prefix with invalid route origin
...

Téléchargez le RFC 1997


L'article seul

RFC 1996: A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY)

Date de publication du RFC : Août 1996
Auteur(s) du RFC : Paul Vixie (Internet Software Consortium)
Chemin des normes
Première rédaction de cet article le 27 septembre 2013


Avant ce RFC, il n'existait pas de mécanisme dans le DNS pour prévenir les serveurs esclaves de la disponibilité de nouvelles données chez le serveur maître. Il fallait attendre que l'esclave contacte le maître (mécanisme de polling). Depuis notre RFC 1996, un serveur maître peut prévenir ses esclaves avec un message NOTIFY, entraînant ainsi une mise à jour plus rapide des zones DNS.

Avant cela, le rythme de mise à jour était contrôlé par le champ Refresh de l'enregistrement SOA. Ce champ indiquait à quel rythme l'esclave devait contacter le maître à la recherche de nouvelles données. En moyenne, donc, le temps de mise à jour de tous les serveurs faisant autorité (maître et esclaves) était de la moitié du Refresh. Par exemple, la zone eu.org a un Refresh de 3 600 secondes :

% dig SOA eu.org
...
;; ANSWER SECTION:
eu.org.			86400 IN SOA ns.eu.org. hostmaster.eu.org. (
				2013092601 ; serial
				3600       ; refresh (1 hour)
				1800       ; retry (30 minutes)
				604800     ; expire (1 week)
				86400      ; minimum (1 day)
				)
...

Ce qui fait que les esclaves testeront le maître à intervalles d'une heure, lui demandant s'il a des nouvelles données depuis le numéro de série 2013092601. Si le maître répond aux requêtes SOA de ces esclaves avec un numéro de série plus récent, l'esclave transférera la zone (RFC 5936). Le problème est qu'on peut attendre longtemps. Dans le pire cas (si l'esclave a testé le maître juste avant que ce dernier ne soit mis à jour), on attendra une heure. La synchronisation entre serveurs faisant autorité (maîtres et esclaves) contribue donc au délai total de réjuvénation.

Le message NOTIY complète ce mécanisme de polling par un mécanisme d'interruption. Le maître envoit ce message à ses esclaves dès la mise à jour, et ceux-ci testent immédiatement.

À noter que le graphe des relations entre serveurs faisant autorité n'est pas forcément composé que d'un maître et d'esclaves transférant depuis le maître. On peut avoir des configurations plus complexes avec des esclaves transférant depuis un autre esclave, plusieurs maîtres, etc (c'est d'ailleurs pour cela que l'ancienne terminologie de serveur primaire et secondaires a été abandonnée).

La section 3 décrit le NOTIFY. Les messages DNS ont un champ nommé Opcode (section 4.1.1 du RFC 1035) dont les valeurs possibles sont dans un registre IANA. Le principal opcode rencontré dans la nature, et de loin, est le 0, QUERY, indiquant une requête DNS normale. NOTIFY est un autre opcode possible, de numéro 4. Lorsqu'un serveur a des données nouvelles, il envoie un message NOTIFY à tous ses esclaves, message auquel les esclaves répondront, pour rassurer le maître sur la bonne réception de ses informations. Autrement, le maître réessaiera (les NOTIFY, comme la plupart des messages DNS, sont transportés sur UDP et peuvent donc se perdre), un certain nombre de fois (le RFC recommande cinq fois). Le message du maître peut aussi contenir les nouvelles données. Dans les exemples ci-dessous, les maîtres envoient le nouveau SOA de la zone. Si le message avec un nouveau SOA est bien reçu par l'esclave, celui-ci se comporte comme si le délai Refresh était écoulé : il interroge le maître sur son numéro de série (les NOTIFY ne sont pas authentifiés et peuvent donc être trompeurs, cf. section 5) et, s'il y a bien eu mise à jour, transfère la zone.

La section 4 du RFC donne quelques exemples, mais j'ai plutôt inclus les miens. Tout d'abord, un serveur maître sur NSD. Sa configuration pour la zone bortzmeyer.42 comprendra la liste des esclaves à notifier (ici, un seul) :

zone:
     	name: "bortzmeyer.42"
	zonefile: "primary/bortzmeyer.42"
	notify: 204.62.14.153 NOKEY

Maintenant, le serveur a de nouvelles données. Au moment où l'administrateur tape nsdc reload, le serveur envoie un NOTIFY que tcpdump montre ainsi :


22:58:53.934862 IP (tos 0x0, ttl 55, id 0, offset 0, flags [DF], proto UDP (17), length 59)
    217.70.190.232.51962 > 204.62.14.153.53: [udp sum ok] 32223 notify [b2&3=0x2400] SOA? bortzmeyer.42. (31)
22:58:53.935055 IP (tos 0x0, ttl 64, id 26939, offset 0, flags [none], proto UDP (17), length 59)
    204.62.14.153.53 > 217.70.190.232.51962: [bad udp cksum 0x733f -> 0x1d3a!] 32223 notify*- q: SOA? bortzmeyer.42. 0/0/0 (31)

Le maître a notifié, l'esclave a répondu positivement.

Avec BIND, il n'est pas nécessaire de lister les serveurs esclaves, il les trouve par défaut dans l'enregistrement NS de la zone (contrairement à NSD, BIND a un résolveur interne). On peut compléter cette liste (ajouter des esclaves) avec la directive also-notify. Voici une notification envoyée par BIND :


23:11:40.781190 IP6 (hlim 55, next-header UDP (17) payload length: 100) 2001:67c:2218:3::1:4.1396 > 2605:4500:2:245b::42.53: [udp sum ok] 46225 notify [b2&3=0x2400] [1a] SOA? langtag.net. langtag.net. [0s] SOA ns4.generic-nic.net. hostmaster.langtag.net. 2013092301 30480 26400 2419200 86400 (92)
23:11:40.781462 IP6 (hlim 64, next-header UDP (17) payload length: 37) 2605:4500:2:245b::42.53 > 2001:67c:2218:3::1:4.1396: [udp sum ok] 46225 notify*- q: SOA? langtag.net. 0/0/0 (29)

On trouve quelques enregistrements de trafic DNS avec NOTIFY sur pcapr : http://www.pcapr.net/browse?q=dns+notify (avec quelques faux positifs, aussi).

Si on veut envoyer à la main un NOTIFY, à des fins de test ou de débogage, NSD a un outil utile, la commande nsd-notify :

% nsd-notify -z bortzmeyer.42 ns3.example.net

Si l'esclave n'est pas configuré pour recevoir des notifications de ce maître, NSD répond avec un refus :

[1379966010] nsd-notify[3346]: warning: bad reply from ns3.example.net \
    for zone bortzmeyer.42., error response REFUSED (5).

Alors que le RFC recommandait plutôt d'ignorer ce message NOTIFY inattendu. La configuration dans NSD pour accepter les notifications se fait avec la directive allow-notify :

allow-notify: 217.70.190.232 NOKEY

(Si vous voulez authentifier les NOTIFY, voyez mon autre article sur TSIG.)


Téléchargez le RFC 1996


L'article seul

RFC 1995: Incremental Zone Transfer in DNS

Date de publication du RFC : Août 1996
Auteur(s) du RFC : Masataka Ohta (Computer Center Tokyo Institute of Technology)
Chemin des normes
Première rédaction de cet article le 28 septembre 2010


Le mécanisme standard de transfert d'une zone DNS entre deux serveurs faisant autorité (depuis le maître vers l'esclave) est normalement le transfert de zones, dit AXFR, aujourd'hui normalisé dans le RFC 5936. Ce mécanisme convient parfaitement aux « petites zones » (de quelques centaines d'enregistrement au plus) mais achoppe, par exemple, lorsqu'un « gros » TLD veut pousser les changements du jour (ou de l'heure) vers tous ses esclaves. En raison, entre autre, de l'anycast, certains de ces esclaves sont situés dans des endroits pas très bien connectés (comme l'île de la Réunion) et l'envoi d'un fichier de la taille de celui de .fr (aujourd'hui, 1,8 millions de domaines et 190 Mo) peut prendre du temps. On peut transférer les zones par d'autres moyens que le DNS, par exemple rsync. Mais il existe une solution DNS standard (qui est celle utilisée par .fr), IXFR (Incremental Zone Transfer), normalisée dans ce RFC 1995.

Le principe est simple et résumé en section 2 du RFC. Lorsqu'un client veut un transfert (typiquement, parce qu'il est esclave et a appris que sa version de la zone était en retard), il envoie un message DNS de type IXFR (code 251, AXFR étant 252, cf. https://www.iana.org/assignments/dns-parameters) au maître qui lui transmet alors uniquement les nouveaux enregistrements. Le serveur IXFR (le maître) doit donc garder trace des changements entre les différentes versions, pour ne transmettre que ces changements (BIND ne le fait, par défaut, que si on utilise les mises à jour dynamiques du RFC 2136 ; autrement, il faut ajouter l'option ixfr-from-differences yes;). À noter qu'un serveur IXFR a toujours le droit de renvoyer la zone complète, par exemple si le client a un numéro de version trop vieux, ne correspondant plus à une version qui avait été gardée (voir la section 5).

Comme la réponse IXFR a des chances d'être de petite taille, le serveur a même le droit de répondre en UDP. Autrement, on utilise TCP, comme avec AXFR. Donc, l'algorithme recommandé est, pour le client, d'essayer en UDP d'abord, puis TCP.

La requête IXFR a le format DNS standard (section 3), la section Autorité contenant le SOA de la version courante chez le client. La réponse (section 4) ressemble beaucoup à une réponse AXFR. Elle est composée de séquences, chaque séquence commençant par l'ancien SOA, puis comportant les enregistrements supprimés, puis le nouvel enregistrement SOA, indiquant la version actuelle sur le maître, puis enfin les enregistrements ajoutés. Les séquences sont classés chronologiquement donc on peut voir la réponse IXFR comme un historique des changements. À noter que ce sont bien des enregistrements qui sont transmis, pas des RRsets. Si on a :

foobar  IN   NS   ns1.example.net.
        IN   NS   ns3.example.net.

et qu'on ajoute un serveur ns2.example.net, seul l'enregistrement NS de ce serveur aura besoin d'être transmis, pas les trois enregistrements du nouveau RRset.

La réponse commence, comme pour AXFR, par le SOA de la version locale du serveur mais le client peut savoir si sa demande IXFR a reçu une réponse IXFR ou AXFR en examinant le second enregistrement : si la réponse est incrémentale (IXFR), ce second enregistrement est un SOA.

Naturellement, le client IXFR ne doit mettre à jour sa copie locale qu'une fois qu'il a reçu tous les enregistrements. (Dit autrement, IXFR doit être atomique.)

La section 5 spécifie le comportement d'un serveur IXFR pour ce qui concerne les vieilles versions : il n'est évidemment pas obligé de les garder toutes et peut donc supprimer les plus anciennes, pour gagner de la place. C'est d'autant plus important qu'au bout d'un moment, les changements s'accumulant, la réponse IXFR deviendra plus longue que la réponse AXFR ! Remarquons aussi (section 6) que la réponse incrémentale n'est pas forcée de refléter l'histoire exacte des changements : un serveur a le droit de condenser plusieurs changements successifs en un seul. (Les exemples de la section 7 incluent une telle condensation.)

Voyons maintenant un exemple de mise en œuvre, entre deux BIND 9.7. Deux serveurs font autorité pour .fr. Sans IXFR, le transfert prend une demi-minute sur un Ethernet à 100 M/s (et bien plus longtemps avec des serveurs mal connectés au bout du monde ; il ne faut pas oublier que .fr a un serveur à Katmandou, un à Manille, etc). Sur le maître, on voit :

28-Sep-2010 10:54:35.388 client 192.0.2.97#56385: transfer of 'fr/IN': AXFR started
28-Sep-2010 10:55:00.162 client 192.0.2.97#56385: transfer of 'fr/IN': AXFR ended

Et sur l'esclave (tous les serveurs utilisent le port 9053, pour des tests, et pas le port standard 53 ; ainsi, le serveur esclave est configuré avec masters { 192.0.2.69 port 9053; };) :

28-Sep-2010 10:55:00.182 transfer of 'fr/IN' from 192.0.2.69#9053: \
                    Transfer completed: 2699 messages, 3965064 records, \
                    106151552 bytes, 24.857 secs (4270489 bytes/sec)

(Notez au passage que ce sont des enregistrements binaires DNS qui sont transférés, pas un fichier texte, ce qui explique la taille totale plus petite.)

Pour activer IXFR sur la maître, on modifie la configuration du serveur avec ixfr-from-differences yes; dans la directive zone :

zone "fr" {
        type master;
        file "fr";
        ixfr-from-differences yes;
};

On ne change rien sur le client IXFR : avec BIND, le client essaie IXFR par défaut. Sur le maître, le transfert est quasi-instantané :

28-Sep-2010 11:05:47.103 client 192.0.2.97#54496: transfer of 'fr/IN': IXFR started
28-Sep-2010 11:05:47.103 client 192.0.2.97#54496: transfer of 'fr/IN': IXFR ended

ce que confirme le journal de l'esclave, à qui il a suffi de transférer dix changements :

28-Sep-2010 11:05:47.049 transfer of 'fr/IN' from 192.0.2.69#9053: \
                Transfer completed: 1 messages, 10 records, \
                334 bytes, 0.004 secs (83500 bytes/sec)

(Note au passage : pour prévenir un serveur esclave de test, qui ne reçoit pas les NOTIFY du RFC 1996, qu'un changement a eu lieu chez le maître, le plus simple est d'envoyer un NOTIFY forcé. BIND ne permet pas de le faire facilement mais, si on a nsd, il suffit de faire un nsd-notify -p 9053 -z fr NOM-SERVEUR).

On peut aussi admirer le transfert incrémental avec tshark (l'option -d est nécessaire car on utilise un port alternatif). Un domaine a été ajouté, un autre retiré (les deux domaines avaient le même jeu de serveur) :

% tshark -d tcp.port==9053,dns -d udp.port==9053,dns  -r ixfr.pcap 
...
  3   0.001347 192.0.2.97 -> 192.0.2.69 DNS Standard query SOA fr
  4   0.001455 192.0.2.69 -> 192.0.2.97 DNS Standard query response SOA nsmaster.nic.fr
...
 10   0.002930 192.0.2.97 -> 192.0.2.69 DNS Standard query IXFR fr
...
 12   0.003089 192.0.2.69 -> 192.0.2.97 DNS Standard query response \
                       SOA nsmaster.nic.fr \
                       SOA nsmaster.nic.fr NS ns1.example.net NS ns3.example.net \
                       SOA nsmaster.nic.fr NS ns1.example.net NS ns3.example.net \
                       SOA nsmaster.nic.fr

On y voit bien le test initial du SOA, puis la requête du client, puis une séquence composée d'une partie « retrait » et d'une partie « ajouts ». Le fichier pcap complet est sur pcapr, en http://www.pcapr.net/view/bortzmeyer+pcapr/2010/8/2/6/ixfr.pcap.html.

Si le serveur refuse ou ne peut pas faire un transfert incrémental, le maître BIND indiquera :

28-Sep-2010 10:48:04.007 client 192.0.2.97#45524: transfer of 'fr/IN': AXFR-style IXFR started
28-Sep-2010 10:48:29.802 client 192.0.2.97#45524: transfer of 'fr/IN': AXFR-style IXFR ended

Et l'esclave recevra la totalité de la zone.

Les tests ici ont été faits avec BIND. Et avec nsd ? Il ne peut être qu'esclave : un maître nsd ne sait pas servir des transferts incrémentaux. Lorsque nsd est esclave, il essaie IXFR (en TCP par défaut mais on peut le configurer pour utiliser UDP) puis AXFR. (Il semble qu'il n'envoie pas de requête SOA avant la demande IXFR, la ligne 3 dans la trace Wireshark plus haut ; ce n'est en effet pas imposé par le RFC, puisque l'IXFR contient déjà le numéro de série connu du client.) On peut aussi lui demander de ne pas tenter IXFR :

zone:
        name: "langtag.net"
...
        request-xfr: AXFR 192.134.7.248 mykey

Ici, en raison du mot-clé AXFR, le serveur esclave ne tentera pas de faire de l'IXFR. Le même réglage, pour BIND, ne peut être que global au serveur (dans le bloc options, request-ixfr no;).

Le fait qu'un serveur puisse répondre à une demande IXFR par une copie complète de la zone peut être gênant dans certains cas. À la réunion IETF 75 de Stockholm en juillet 2009 a été présentée la proposition IXFR only (Internet-Draft draft-kerr-ixfr-only) qui normalisait un nouveau type de requête « IXFR seul » mais qui n'a pas encore été sérieusement pris en considération.


Téléchargez le RFC 1995


L'article seul

RFC 1984: IAB and IESG Statement on Cryptographic Technology and the Internet

Date de publication du RFC : Août 1996
Auteur(s) du RFC : IAB & IESG
Pour information
Première rédaction de cet article le 22 septembre 2005


Un RFC très politique, que ce 1984 qui s'attaque aux restrictions d'usage à la cryptographie. Au moment où il est sorti, la cryptographie était de fait interdite en France (et la situation, si elle s'est améliorée, est encore loin d'être parfaite). Et les États-Unis restreignaient très sévèrement l'exportation de logiciels cryptographiques (là encore, ces restrictions n'ont pas complètement disparu).

Le RFC prend nettement position : l'IAB et l'IESG, ensemble, affirment que la cryptographie forte (pas les systèmes ultra-bridés qui étaient proposés à l'époque avec les navigateurs Web) est indispensable à la sécurité de l'Internet, qu'il n'existe aucune autre méthode réaliste d'assurer une sécurité raisonnable sur un réseau ayant l'architecture de l'Internet et que cette sécurité ne doit pas être sacrifiée aux intérêts des polices et des services secrets.

Le RFC se penche aussi sur des cas plus techniques, comme sur les clés cryptographiques ne servant qu'à la signature, qui ne devraient jamais faire l'objet d'un dépôt de séquestre, puisqu'il n'existe aucune raison légitime de les "saisir".

Ce RFC dont le numéro ne doit rien au hasard, a marqué une étape dans la construction politique de l'Internet.


Téléchargez le RFC 1984


L'article seul

RFC 1981: Path MTU Discovery for IP version 6

Date de publication du RFC : Août 1996
Auteur(s) du RFC : Jack McCann (Digital Equipment Corporation), Stephen E. Deering (Xerox Palo Alto Research Center), Jeffrey Mogul (Digital Equipment Corporation, Western Research Laboratory)
Chemin des normes
Première rédaction de cet article le 16 décembre 2007


Ce RFC est l'adaptation à IPv6 du protocole décrit dans le RFC 1191, protocole qui permet de découvrir la MTU du chemin entre deux machines reliées par Internet. Il a depuis été remplacé par le RFC 8201.x

Avec IPv4, déterminer la MTU maximale du chemin est très utile pour optimiser les performances. Mais elle devient presque indispensable en IPv6, où les routeurs n'ont pas le droit de fragmenter les paquets trop gros (toute fragmentation doit être faite dans la machine de départ). PMTU fait donc quasi-obligatoirement partie d'IPv6 (une alternative est de n'envoyer que des paquets suffisamment petits pour passer partout).

L'algorithme est le même qu'en v4, envoyer des paquets, et voir si on reçoit des paquets ICMP Packet too big qui contiennent en général la MTU maximale du lien suivant. (Pas de bit DF - Don't fragment - en IPv6 puisque la fragmentation n'est possible qu'à la source. L'annexe A détaille les différences avec l'algorithme IPv4 décrit dans le RFC 1191.)

Comme avec IPv4, l'algorithme PMTU marche mal en pratique car beaucoup de sites filtrent stupidement tous les paquets ICMP et la machine qui tente de faire de la Path MTU discovery n'aura jamais de réponse. IPv6, comme IPv4, devra donc sans doute utiliser la nouvelle technique du RFC 4821

(Un excellent article très complet sur la question est A Tale of Two Protocols: IPv4, IPv6, MTUs and Fragmentation.)


Téléchargez le RFC 1981


L'article seul

RFC 1958: Architectural Principles of the Internet

Date de publication du RFC : Juin 1996
Auteur(s) du RFC : Brian E. Carpenter (CERN, European Laboratory for Particle Physics)
Pour information
Première rédaction de cet article le 2 janvier 2013


Ce très court RFC posait en 1996 les bases de l'architecture de l'Internet... longtemps après que celui-ci soit largement déployé. C'est une application du principe « faire tourner d'abord, documenter après » qui a été justement un des principes fondamentaux de l'Internet.

Ce document est surtout une synthèse de deux articles essentiels, celui de David Clark, « The Design Philosophy of the DARPA Internet Protocols » (Proc SIGCOMM 88, ACM CCR Vol 18, Number 4, August 1988) et celui de J.H. Saltzer, D.P. Reed et David Clark, « End-To-End Arguments in System Design » (ACM TOCS, Vol 2, Number 4, November 1984) qui expose très bien les raisons pour lesquelles il ne faut pas de réseau intelligent et pourquoi tout le travail difficile doit être fait aux extrémités, dans les machines terminales.

Ce RFC 1958 affiches des ambitions modestes : son but était de décrire les principes fondamentaux de l'architecture de l'Internet or, dès le résumé, le RFC note que l'Internet n'a pas été bâti en suivant des grands principes, mais a évolué. Cette capacité à évoluer a fait son succès et tout texte sur les principes ne peut donc être qu'un cliché momentané, pas un texte sacré de principes immuables.

En 1996, date de publication du RFC, la capacité de l'épine dorsale du réseau avait été multipliée par 1 000 depuis les débuts d'ARPANET et son nombre de machines par 1 000 000. Depuis, ces chiffres ont évidemment encore augmenté. Face à de tels changements quantitatifs, il faut s'attendre à ce que les principes qualitatifs aient également changé. Comme le note le RFC « la seule constante de l'Internet, c'est le changement ». On est loin des beaux plans académiques tellement jolis sur le papier mais jamais mis à l'épreuve des faits. L'Internet, comme un être vivant (la comparaison est de moi, elle n'est pas dans le RFC), n'a pas été conçu par un démiurge parfait et c'est pour cela qu'il est si réussi.

La comparaison qu'utilise le RFC est celle d'une ville : de même qu'on ne peut pas détruire une ville pour la refaire « en mieux », on ne peut pas refaire l'Internet de zéro. La ville change tout le temps mais n'a jamais été conçue à partir de zéro (contrairement à ce que voudraient faire aujourd'hui les raseurs de table).

Le RFC appelle donc à la prudence : il est difficile de prévoir le futur. Et à l'humilité. À noter qu'il ne suit pas toujours ses propres règles. Ainsi, la section 1 parle sans hésiter du « besoin de qualité de service », besoin qui, en 2013, est toujours aussi flou (cf. RFC 5290).

La section 2 commence la liste des principes, après avoir répondu à ceux qui disent, en n'exagérant qu'à moitié, qu'il n'existe pas d'architecture de l'Internet, juste des traditions. Les premiers principes (section 2.1) : la connectivité est un but en soi (contrairement aux experts qui expliquaient doctement qu'il ne servait à rien d'avoir des tuyaux sans contenus, ou aux marketeux qui s'obstinaient à vendre des applications intégrées, et pas juste de la connectivité), l'outil principal d'interconnexion est IP et les fonctions un tant soi peu avancées doivent être dans les extrémités, pas dans le réseau. La connectivité est un but en soi car ce sont les utilisateurs du réseau qui fourniront contenu et applications. (Mon avis est que ceux qui disent le contraire sont ceux qui voudraient verrouiller l'usage de l'Internet en définissant les usages qu'on peut en faire.)

À l'époque de ce RFC, Internet était récemment devenu un réseau mono-protocole, tout fonctionnait avec IPv4. Quelques années auparavant, de nombreux concurrents (de DECnet à UUCP) existaient encore. Depuis, l'Internet est redevenu multi-protocoles, avec IPv6. Notre RFC estime (section 2.2) qu'il ne devrait y avoir qu'un seul protocole au niveau 3, sauf lors d'une transition vers une nouvelle version (le cas actuel) ou si un nouveau protocole est franchement meilleur (personne n'a encore proposé un tel protocole).

La section 2.3 expose et défend le fameux principe de bout en bout. Ce principe dit que, toutes les fois où on hésite sur le meilleur endroit pour placer une fonction, on doit la mettre dans les machines terminales et pas dans le réseau. Une des principales justifications de ce principe est qu'il permet à une session en cours de survivre à un redémarrage du réseau, puisque les routeurs ne conservent pas d'état. C'est pour cela que le datagramme est meilleur que le circuit.

Bien sûr, les équipements du réseau ont quand même un état : le routeur connait les routes actuelles, par exemple, et il a un cache ARP. Mais cet état doit être auto-réparable : au cas où le routeur redémarre, il doit pouvoir reconstituer son état seul, et que les applications qui l'utilisaient continuent comme si rien ne s'était passé.

Ce principe de bout en bout est également crucial pour la sécurité : une application ne doit pas avoir à faire confiance au réseau (même si le RFC ne le dit pas, l'attaquant peut être le FAI), elle doit pouvoir assurer sa propre sécurité (point traité dans la section 6.2).

Une opinion au passage : ce principe de bout en bout a un autre avantage, bien plus important mais peu mentionné dans le RFC. Ce principe permet l'innovation. Aucun routeur, aucun câble sous-marin n'a dû être modifié pour permettre des inventions comme le Web (apparu quelques années avant ce RFC). Si l'Internet avait été géré par des technocrates français, il aurait fallu réunir une commission avant l'introduction de toute nouvelle application, et le Web n'aurait jamais été déployé. Il n'est donc pas étonnant que le principe de bout en bout soit surtout combattu par ceux qui regrettent le bon temps où le même groupe de technocrates concevait le réseau et toutes les applications.

Depuis la publication de ce RFC, ce principe de bout en bout est aujourd'hui très sérieusement remis en cause par la multiplication des middleboxes, routeurs NAT, pare-feux et autres engins qui, volontairement ou parce qu'ils ont été programmés avec les pieds, bloquent aujourd'hui de nombreuses possibilités du modèle de bout en bout (par exemple, déployer un nouveau protocole de transport comme SCTP est devenu quasiment impossible).

Une des rares incursions de ce RFC dans la politique est en section 2.4 : personne n'est propriétaire de l'Internet, personne ne peut l'éteindre. Et c'est une bonne chose (même si c'est parfois agaçant).

La section 3 porte sur tout un tas de problèmes de conception d'un grand réseau mondial. Par exemple, il est essentiel de penser au passage à l'échelle (section 3.3). Et de ne pas seulement regarder les fonctions offertes par le réseau mais aussi leur coût (section 3.4), en euros et en performance (un certain nombre de plans alternatifs promettent beaucoup mais oublient de chiffrer les conséquences). Plus généralement, le mieux est l'ennemi du bien : il vaut mieux une solution partielle que d'attendre une solution parfaite et complète (section 3.7).

La longue expérience des praticiens de l'Internet au moment de la publication de ce RFC a aussi mené à d'autres principes : par exemple, que les réglages manuels sont une source d'ennuis sans fin et qu'il faut donc que tout soit automatique (section 3.8). Et il faut éviter les dépendances circulaires (section 3.11), par exemple que le routage dépende du DNS puisque celui-ci dépend du routage... (Des techniques comme Rover ont été critiquées pour cela, pas forcément à juste titre).

C'est dans cette section que le RFC 1958 rappelle un principe souvent cité et souvent discuté, le principe de robustesse (section 3.9). Présent bien avant (je crois que le premier RFC qui le citait explicitement est le RFC 791), il est ici défini comme « soyez strict en envoyant et tolérant en recevant ». L'idée est qu'un programme a intérêt à coller aux moindres détails de la spécification lorsqu'il envoie des données (pour maximiser les chances d'être compris) mais à interpréter cette spécification de manière ouverte lorsqu'il reçoit des données (permettre que le réseau fonctionne est plus important que de pinailler sur la qualité de l'implémentation d'en face).

Et le dernier principe de cette nouvelle section : on ne normalise pas tant qu'on n'a pas deux mises en œuvre distinctes d'un protocole (section 3.14). Notez bien que ce n'est qu'un principe, pas une loi et qu'en pratique, celui-ci est loin d'être toujours respecté.

La section 4 est consacrée aux questions, toujours chaudement disputées, du nommage et de l'adressage. Elle pose des principes comme (section 4.1) d'utiliser des noms plutôt que des adresses (pour leur stabilité), et n'avoir qu'un seul espace de nommage (section 4.2, qui fait écho au RFC 2826).

Plus rétrograde, le principe 4.3 qui demande que les noms soient uniquement en US-ASCII. Aujourd'hui, où les IDN existent et sont utilisés depuis longtemps, cela sent son époque...

La section 5 porte sur les questions non strictement techniques : acceptation des technologies brevetées (section 5.1), ne pas tenir compte des restrictions à l'exportation (section 5.2, un problème typique des années 1990 où la diffusion des logiciels de cryptographie était bien plus dure qu'aujourd'hui). Il y a aussi un principe (section 5.4) sur l'importance de n'utiliser que des techniques complètement internationalisées, ce qui est franchement contradictoire avec le principe 4.3...


Téléchargez le RFC 1958


L'article seul

RFC 1918: Address Allocation for Private Internets

Date de publication du RFC : Février 1996
Auteur(s) du RFC : Yakov Rekhter (Cisco systems), Robert G. Moskowitz (Chrysler Corporation), Daniel Karrenberg (RIPE NCC), Geert Jan de Groot (RIPE NCC), Eliot Lear (Silicon Graphics)
Première rédaction de cet article le 1 novembre 2007


Depuis longtemps, le manque d'adresses IPv4 se fait sentir. Pour obtenir ces précieuses adresses, il faut remplir de longs documents à envoyer au RIR, ou bien payer son FAI pour une offre « pro » ou n'importe quel autre qualificatif indiquant que, entre autres, on aura d'avantage d'adresses, peut-être un /29 au lieu d'un simple /32 (pour les politiques d'allocation, voir le RFC 7020). D'où la demande pour un stock d'adresses IPv4 privées, non annoncées sur l'Internet et non uniques globalement, mais dans lequel on pourrait piocher à loisir. C'est ce que propose ce RFC, certainement un des plus cités, le "1918" étant devenu synonyme de ressource privée.

Ce RFC est court et pourrait se contenter de lister (section 3) les trois préfixes privés réservés :

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16, certainement le plus utilisé des trois.

Et les bases des RIR, accessibles via whois, reflètent bien cette réservation à l'IANA :

% whois  10.42.0.1                 

OrgName:    Internet Assigned Numbers Authority 
OrgID:      IANA
Address:    4676 Admiralty Way, Suite 330
City:       Marina del Rey
StateProv:  CA
PostalCode: 90292-6695
Country:    US

NetRange:   10.0.0.0 - 10.255.255.255 
CIDR:       10.0.0.0/8 
NetName:    RESERVED-10
NetHandle:  NET-10-0-0-0-1
Parent:     
NetType:    IANA Special Use
NameServer: BLACKHOLE-1.IANA.ORG
NameServer: BLACKHOLE-2.IANA.ORG
Comment:    This block is reserved for special purposes.
Comment:    Please see RFC 1918 for additional information.
Comment:    
RegDate:    
Updated:    2002-09-12
...

Mais l'idée même d'adresses IP privées ne s'est pas imposée sans mal. Un des principes d'architecture de l'Internet est en effet la connectivité de bout en bout. Toute machine peut parler directement à toute autre. C'est l'une des grandes innovations de l'Internet, tous les réseaux concurrents à l'époque (années 1970 et 80) n'envisageaient que des réseaux isolés. Or, s'il existe des adresses privées, elles ne sont pas globalement uniques. Deux machines sur des sites différents peuvent avoir la même adresses 192.168.1.1. Cela remet donc en cause le modèle de base et le prédécesseur de notre RFC, le RFC 1597 avait été fortement critiqué, notamment dans le RFC 1627, intitulé Network 10 Considered Harmful.

Notre RFC détaille donc aussi, dans ses sections 2 et 4, les motivations de ces adresses privées et explique pourquoi on ne peut pas s'en passer.

Si la poussière soulevée par le débat est bien retombée par la suite, c'est parce qu'on envisageait un déploiement rapide d'IPv6 qui règlerait le problème, grâce à son abondance d'adresses. Ce déploiement ne s'étant pas (encore ?) produit, notre RFC et ses adresses privées continuent à bénéficier d'un grand succès.

Ce succès s'étend même à des domaines non prévus, comme la documentation, qui devrait normalement utiliser 192.0.2.0/24 (cf. RFC 5737).

Pourquoi ces trois préfixes-là et pas d'autres ? Pour 10.0.0.0/8 la raison semble connue mais pas pour les autres.

Parfois, ces adresses privées « sortent » même, par accident, du réseau local où elles auraient dû rester confinées, malgré la section 5 du RFC qui explique qu'il ne faut pas le faire. On doit donc prendre soin de les filtrer. Les règles d'ACL d'un coupe-feu commencent souvent par quelque chose du genre (ici, des règles de Netfilter dans le noyau Linux) :

Chain norfc1918 (2 references)
target     prot opt source               destination
rfc1918    all  --  172.16.0.0/12        0.0.0.0/0
rfc1918    all  --  192.168.0.0/16       0.0.0.0/0
rfc1918    all  --  10.0.0.0/8           0.0.0.0/0
...
Chain rfc1918 (6 references)
target     prot opt source               destination
LOG        all  --  0.0.0.0/0            0.0.0.0/0           LOG flags 0 level 6 prefix `Shorewall:rfc1918:DROP:'
DROP       all  --  0.0.0.0/0            0.0.0.0/0

(Dans le cas ci-dessus, les règles sont ajoutées automatiquement par Shorewall.)

De même, un routeur BGP refuse en général de ses pairs des annonces pour ces préfixes (ici, la syntaxe d'IOS) :

! http://www.cymru.com/Bogons/index.html
! Deny any packets from the RFC 1918 netblocks to block
! attacks from commonly spoofed IP addresses.
access-list 2010 remark Anti-bogon ACL
! Bogons
access-list 2010 deny ip 10.0.0.0 0.255.255.255 any log-input
access-list 2010 deny ip 172.16.0.0 0.15.255.255 any log-input
access-list 2010 deny ip 192.168.0.0 0.0.255.255 any log-input

Et le nombre de serveurs DNS faisant des requêtes de type PTR pour ces adresses, et fatiguant ainsi pour rien les serveurs de in-addr.arpa, a nécessité le déploiement d'un système dédié pour les absorber, l'AS112.

Aujourd'hui, le petit réseau local typique a donc presque toujours des adresses tirées du RFC 1918, un routeur NAT et/ou des relais applicatifs et une seule adresse IP publique, attribuée par le FAI.


Téléchargez le RFC 1918


L'article seul

RFC 1876: A Means for Expressing Location Information in the Domain Name System

Date de publication du RFC : Janvier 1996
Auteur(s) du RFC : Christopher Davis (Kapor Enterprises, Inc.), Paul Vixie (Vixie Enterprises), Tim Goodwin (Public IP Exchange Ltd (PIPEX)), Ian Dickinson (FORE Systems)
Expérimental
Première rédaction de cet article le 24 mai 2006


Ce n'est pas une question de vie ou de mort pour l'Internet mais il est quand même bien agréable de pouvoir spécifier la localisation physique d'une machine, en indiquant sa latitude et sa longitude. Notre RFC permet de le faire dans le DNS.

Les applications possibles sont nombreuses : un traceroute un peu plus explicite, par exemple, ou bien un lien direct vers Google Maps ou encore le guidage automatique d'un missile intercontinental vers sa cible. Une mise en œuvre complète du RFC, en logiciel libre, se trouve dans le répertoire contrib/query-loc de BIND (à partir de la version 9.3).

Le système fonctionne avec des enregistrements de type LOC. Voici un exemple pour nic.af :

% dig +short LOC nic.af. 
34 31 0.000 N 69 12 0.000 E 1000.00m 1000m 10000m 10m

qui nous indique que le NIC afghan se trouve à 34°31 de latitude Nord et 69°12 de longitude Est (soit à Kaboul). Les chiffres supplémentaires dans l'enregistrement indiquent la précision, y compris en hauteur.

www.bortzmeyer.org n'a pas aujourd'hui d'enregistrement LOC. La zone est gérée par le registrar, Gandi, via une interface qui ne permettait pas ce type de données. C'est désormais possible (LOC est un des choix possibles lors de l'édition de la zone sur le Web de Gandi) mais l'interface est peu pratique (il faut tout calculer soi-même) donc cela attendra.

Notre RFC permet aussi de trouver un enregistrement LOC à partir d'une adresse IP. Par exemple, pour 130.104.3.1 :

  • On cherche si cette adresse IP a un nom (ce n'est pas le cas),
  • On cherche si son réseau a un nom (et on le trouve, 0.0.104.130.in-addr.arpa nous mène vers uclouvain.sri.ucl.ac.be),
  • On cherche alors le LOC du réseau (et on trouve 50°40 Nord et 4°37 Est, à Louvain-la-Neuve en Belgique).

En pratique, notre RFC n'a pas été un grand succès. Très peu d'enregistrements de type LOC se trouvent aujourd'hui dans Internet, ce qui réduit l'intérêt des applications qui les utilisent. Si on veut faire de la géolocalisation, il faut donc plutôt compter sur des bases de données plus ou moins informelles et de plus ou moins bonne qualité, souvent obtenues à partir des bases des RIR.

On trouvera plus de détails sur les enregistrements LOC en http://www.ckdhr.com/dns-loc ou en http://blog.fupps.com/2010/11/14/where-is-your-dns-server-located/. Il existe des services sur le Web qui transforment un nom de domaine en carte, en utilisant les enregistrements LOC, comme http://idefix.net/~koos/kismet/loc2map.php ou http://hewgill.com/tools/dnsloc.

Une utilisation amusante des LOC est celle qui permet de trouver la longitude et la latitude d'un point au Royaume-Uni d'après son code postal, via le domaine find.me.uk :

% dig TW110LW.find.me.uk. LOC +short
51 25 35.560 N 0 20 38.043 W 0.00m 0.00m 0.00m 0.00m

(C'était l'adresse du NPL à Teddington.)

Un service équivalent existe pour la France, ici pour Villequier :

% dig +short +nodnssec LOC 76490.cp.bortzmeyer.fr
49 32 58.987 N 0 41 15.835 E 0.00m 1m 10000m 10m

Un autre service amusant avec ces enregistrements est le résolveur DNS latlon.v4.powerdns.org qui retourne un enregistrement LOC correspondant à la géolocalisation de votre résolveur DNS :

% dig +short LOC latlon.v4.powerdns.org  
48 53 33.007 N 2 20 39.840 E 0.00m 1m 10000m 10m

Vous pouvez voir des enregistrements LOC à travers un DNS Looking Glass, par exemple https://dns.bortzmeyer.org/TW110LW.find.me.uk/LOC.


Téléchargez le RFC 1876


L'article seul

RFC 1812: Requirements for IP Version 4 Routers

Date de publication du RFC : Juin 1995
Auteur(s) du RFC : Fred Baker (Cisco Systems)
Chemin des normes
Première rédaction de cet article le 31 octobre 2007


Un RFC de synthèse, qui rassemble tout ce que le fabricant d'un routeur IP doit savoir, parmi tous les RFC dispersés. L'idée était bonne mais, n'ayant jamais été mis à jour, ce RFC contient également pas mal de choses dépassées.

Créer un nouveau routeur IP est un gros travail, en partie parce qu'il faut lire des dizaines de RFC différents, sans avoir de vision d'ensemble et sans toujours pouvoir déterminer facilement ce qu'on doit faire et ce qui est facultatif. D'où l'idée de RFC de synthèse, comme celui-ci pour les routeurs (il succède au RFC 1716) ou comme le RFC 1123 pour les machines « terminales ». Mais, si le principe est bon, l'actualisation d'un tel document s'est révélée difficile. L'IETF travaillant sur la base du volontariat et la mise à jour de grosses synthèses étant moins intéressante que la création de nouveaux protocoles, le RFC a pris sérieusement la poussière. Officiellement, seul le RFC 2644 le modifie mais, en pratique, d'autres points de notre RFC semblent bien dépassés aujourd'hui. Par exemple, rares sont encore les équipements qui utilisent les paquets ICMP de répression de la source (Source Quench, section 4.3.3.3) car ces paquets facilitent trop les DoS (le RFC 6633 a officialisé l'abandon de ces paquets). Même chose pour le routage dirigé par la source (source routing).

Ce RFC fait 175 pages et est donc un gros morceau à lire (mais on ne crée pas un nouveau routeur tous les jours). C'est néanmoins une excellente source d'information pour quiconque s'intéresse au fonctionnement réel des réseaux informatiques.

Il commence par rappeler quelques principes généraux (sections 1 et 2), notamment le fait que ce RFC ne remplace pas les RFC standardisant tel ou tel protocole ou comme le principe de robustesse, Be conservative in what you do, be liberal in what you accept from others ou, dit autrement, « Ne faites pas le malin, essayez de coopérer avec les autres, pas de leur prouver qu'ils ont tort ». La section 2, sur l'architecture de l'Internet, est une bonne source sur ce sujet, recommandée à ceux qui apprennent comment fonctionne Internet. Puis chaque section est consacrée à une couche particulière, la section 3 à la couche 2, deux sections, 4 et 5, à la couche 3 (la section 5 s'occupant spécifiquement des cas où le paquet est transmis - forwarding), etc. La section 7, qui concerne la couche application s'occupe notamment des protocoles de routage.

Ainsi, pour citer quelques exemples des règles que pose ce RFC :

  • La section 3 sur la couche de liaison précise que le routeur IPv4 qui met en œuvre ARP (RFC 826) ne devrait pas abandonner les paquets tout de suite s'il manque provisoirement une entrée dans la table ARP (ce conseil n'est plus du tout suivi aujourd'hui où, pour éviter l'encombrement des files d'attentes et les DoS, les routeurs du cœur de l'Internet jettent immédiatement les paquets qui ne peuvent pas être transmis pour cette raison).
  • La section 4 n'impose pas de respecter les options IP comme Timestamp ou Record route qui n'ont jamais été réellement déployées (et ont disparu en IPv6).
  • La section 4 rappelle que le routeur doit être capable de fragmenter les paquets trop gros (cela a disparu en IPv6 et, même en IPv4, c'est peu utilisé, au profit des techniques décrites dans les RFC 1191 et RFC 4821).
  • La section 4 parle aussi d'ICMP et note que, pour éviter les avalanches, un paquet ICMP d'erreur ne doit jamais être envoyé en réponse à un autre paquet ICMP d'erreur.

Comme noté au début, le RFC n'a jamais été mis à jour donc il ne faut pas espérer y trouver d'informations sur les techniques apparues depuis, comme le NAT ou IPv6.


Téléchargez le RFC 1812


L'article seul

RFC 1796: Not All RFCs are Standards

Date de publication du RFC : Avril 1995
Auteur(s) du RFC : Christian Huitema (INRIA, Sophia-Antipolis), Jon Postel (USC/Information Sciences Institute), Steve Crocker (CyberCash, Inc.)
Pour information
Première rédaction de cet article le 14 décembre 2006


Un RFC pour rappeler une règle simple : tous les RFC ne sont pas des normes.

En effet, chaque RFC a un statut, disponible en ligne ou dans le fichier texte en ftp://ftp.rfc-editor.org/in-notes/rfc-index.txt. Il peut être (liste non limitative) :

  • Standards track (sur le chemin des normes, qui compte trois étapes, Proposed standard, Draft standard et Full standard, également appelé Standard tout court), leur liste est en http://www.rfc-editor.org/rfcxx00.html,
  • Informational (pour information seulement),
  • Experimental (à utiliser avec prudence).

Le RFC 791, sur IP est évidemment Full standard (un statut très rare), comme le RFC 1034 sur le DNS ou le RFC 5234 sur ABNF. Le RFC 2821 sur SMTP n'est que proposed standard (probablement parce que personne n'a passé son temps à argumenter pour son avancement). Et notre RFC 1796 lui-même n'est que informational.


Téléchargez le RFC 1796


L'article seul

RFC 1738: Uniform Resource Locators (URL)

Date de publication du RFC : Décembre 1994
Auteur(s) du RFC : Tim Berners-Lee (CERN, World-Wide Web project), Larry Masinter (Xerox PARC), Mark McCahill (University of Minnesota)
Intérêt historique uniquement
Première rédaction de cet article le 24 janvier 2008


En même temps qu'étaient normalisés les URI, dans le RFC 1630, un effort était en cours pour normaliser leurs prédécesseurs, les URL et cet effort a donné ce RFC.

Ce RFC a aujourd'hui essentiellement un intérêt historique, puisque la spécification des URI, RFC 3986, le remplace en grande partie. Il a gardé longtemps son intérêt (et son statut de norme, désormais perdu) du fait qu'il normalisait certains plans d'URL comme news:. Ceux-ci sont désormais dans le RFC 5538.

Les URL sont issus du travail dont le cahier des charges est décrit dans le RFC 1737. Contrairement aux URI, plus généraux, ils sont supposés ne servir que lorsqu'on connait la localisation exacte d'une ressource, de façon à pouvoir la récupérer, ou la mettre à jour (section 2). En pratique, la distinction n'est pas évidente. Certains URL ne donnent pas de moyen de récupérer une ressouce (comme news: que spécifie notre RFC ou bien mailto:, désormais dans le RFC 6068). Et même des URL de plan http: peuvent être utilisés uniquement pour identifier, pas pour récupérer une ressource (c'est notamment courant dans le monde XML).

Notre RFC décrit donc la syntaxe des URL (sections 2.1 et 5), bien connue désormais qu'on voit des URL même sur le flanc des autobus, et leur encodage (section 2.2, où est documentée la très mauvaise décision d'encoder les octets et pas les caractères Unicode).

La section 3 décrit ensuite les éléments communs à tous les URL (comme la syntaxe host:port), puis des plans (scheme) pour plusieurs catégories d'URL. Ces plans ont presque tous été mis à jour dans des RFC ultérieurs mais certains restent normalisés uniquement ici comme ftp:. On trouve des plans très utilisés comme le célébrissime http:, section 3.3 (désormais dans la section 3.2 du RFC 2616), mais aussi d'autres désormais dépassés comme son défunt concurrent gopher: (section 3.4, désormais dans le RFC 4266) ou comme l'ancêtre wais: (section 3.9, officiellement abandonné par le RFC 4156).

Le plan news:, section 3.6, permet de récupérer un article d'Usenet sans indiquer de nom de serveur NNTP.

L'IANA maintient le registre de ces plans.

Le plan file: est désormais normalisé dans le RFC 8089.

On notera que notre RFC 1738 normalisait également un mécanisme pour décrire un URL au milieu de texte brut, en utilisant un préfixe défini dans l'annexe A, <URL:http://www.bortzmeyer.org/1738.html>. Ce mécanisme n'a pas eu de succès et a officiellement été abandonné par le RFC 3986, annexe C.


Téléchargez le RFC 1738


L'article seul

RFC 1737: Functional Requirements for Uniform Resource Names

Date de publication du RFC : Décembre 1994
Auteur(s) du RFC : Karen Sollins (MIT Laboratory for Computer Science), Larry Masinter (Xerox Palo Alto Research Center)
Pour information
Première rédaction de cet article le 18 mars 2007


À une époque où le Web était récent, où le navigateur Mosaic venait de sortir et où les experts expliquaient doctement que ce truc, cet Internet n'avait aucun avenir, ce RFC est le premier à avoir mentionné les URN, dans la quête de l'identificateur parfait.

Le Web avait commencé avec les URL mais, pour diverses raisons, ils ne donnaient pas totale satisfaction. De chaudes discussions agitaient la liste uri@bunyip.com. Plusieurs personnes ayant dit « Il faudrait qu'on aie des URN à la place des URL », ce travail a mené à ce RFC.

L'optique est nettement de remplacer les URL, pas seulement de les compléter, puisque dès l'introduction, un URN est défini comme un identificateur unique au niveau mondial,permanent, et fournissant l'accès à une ressource (contrairement à des identificateurs comme les tags du RFC 4151 qui sont juste des identificateurs et ne prétendent pas fournir d'accès).

Il exprime donc le cahier des charges pour les URN, qui ne seront normalisés que plus tard. Idéalement, dit notre RFC, les URN devraient être :

  • uniques dans l'espace et dans le temps,
  • allouables en quantité,
  • utilisables avec les systèmes de nommages existants come les ISBN (cela sera fait dans le RFC 3187),
  • résolvable, de manière à permettre l'accès à une ressource. Notre RFC va jusqu'à dire dans sa section 3 que tout schéma d'URN devrait prévoir un mécanisme de résolution. C'est clairement le point où le cahier des charges a été le moins respecté. Aujourd'hui, rares sont les schémas d'URN où il existe un mécanisme de résolution standard.

À noter que ce RFC était plutôt en retard en matière d'internationalisation : les URN sont envisagés comme étant uniquement en ASCII, au nom de la facilité de l'échange, ce qui est paradoxal, et en mentionnant le transport par courrier électronique, alors que MIME existait déjà depuis deux ans. (Le RFC 3987 normalisera finalement les IRI, identificateurs en Unicode.)

Une curiosité : la mention des URC, un identificateur pour les métadonnées, qui ne prendront jamais.


Téléchargez le RFC 1737


L'article seul

RFC 1661: The Point-to-Point Protocol (PPP)

Date de publication du RFC : Juillet 1994
Auteur(s) du RFC : William Allen Simpson (Daydreamer)
Chemin des normes
Première rédaction de cet article le 25 avril 2007


L'increvable protocole PPP assure toujours une grande partie des connexions Internet dans le monde. Ce RFC relativement court décrit le fonctionnement de PPP.

PPP, comme son nom l'indique, sert aux liaisons point-à-point, par opposition aux réseaux partagés comme Ethernet. Initialement conçu pour remplacer SLIP sur les liaisons modem ou les liaisons série à très courte distance, ainsi que pour remplacer différents protocoles privés entre routeurs sur les WAN, il continue aujourd'hui sa carrière même sur ADSL avec PPPoE (décrit dans le RFC 2516).

PPP est dérivé de HDLC mais est considérablement plus simple. Il comprend trois parties :

  • Une méthode d'encapsulation des trames, dans la section 2 de notre RFC, proche de celle de HDLC,
  • Un sous-protocole, LCP (Link Control Protocol), de contrôle de la liaison, décrit dans le reste du RFC,
  • Et plusieurs protocoles de contrôle des protocoles réseaux situés plus haut, les NCP (Network Control Protocol). PPP travaille à la couche 2 et il est donc indépendant du protocole utilisé en couche 3, à part chaque NCP, qui, lui, dépend du protocole de couche 3. Il existe donc un NCP pour IPv4, IPCP, décrit dans le RFC 1332, un NCP pour IPv6, IPv6CP, décrit dans le RFC 5072, etc.

Dans les exemples de configuration PPP suivants, je prendrai comme référence le programme pppd, utilisé sur beaucoup de systèmes Unix, notamment Linux (les utilisateurs de FreeBSD préfèrent en général Userland PPP). Les messages affichés sont extraits du journal de pppd.

Voici par exemple la négociation LCP qui permet aux deux pairs de se mettre d'accord sur les options de la ligne (un gros avantage de PPP par rapport à SLIP) :


Apr 22 09:30:01 ludwigVI pppd[3055]: rcvd [LCP ConfReq id=0x3e <mru 1492> <auth chap MD5> <magic 0x7de8a7c3>]                                                              
Apr 22 09:30:01 ludwigVI pppd[3055]: sent [LCP ConfReq id=0x1 <mru 1400> <asyncmap 0x0> <magic 0x6a0c5efc> <pcomp> <accomp>]                                              
Apr 22 09:30:01 ludwigVI pppd[3055]: sent [LCP ConfAck id=0x3e <mru 1492> <auth chap MD5> <magic 0x7de8a7c3>]                                                              
Apr 22 09:30:01 ludwigVI pppd[3055]: rcvd [LCP ConfRej id=0x1 <asyncmap 0x0> <pcomp> <accomp>]
Apr 22 09:30:01 ludwigVI pppd[3055]: sent [LCP ConfReq id=0x2 <mru 1400> <magic 0x6a0c5efc>]
Apr 22 09:30:01 ludwigVI pppd[3055]: rcvd [LCP ConfAck id=0x2 <mru 1400> <magic 0x6a0c5efc>]

On notera que certaines options ont été rejetées par un des pairs (par exemple la compression pcomp).

PPP permet d'avoir une seule authentification pour tous les protocoles réseaux, gérée par LCP, et reposant en général sur les protocoles PAP ou CHAP.

On voit ici le dialogue CHAP. La machine a reçu un défi CHAP envoyé par le BAS et répond avec un NAI (RFC 7542) configuré par l'option name :


Apr 22 09:30:01 ludwigVI pppd[3055]: rcvd [CHAP Challenge id=0x1 <35de4b970986e23fc4447ee4416beada>, name = "BAS-CBV3-1"]
Apr 22 09:30:01 ludwigVI pppd[3055]: sent [CHAP Response id=0x1 <c43b7ad1c1cdc8aaa74273efdebb3af0>, name = "bortzmeyer@net2.nerim.nerim"]

LCP permet de définir des tests de la ligne (section 5.8 du RFC). On les active avec les options :

lcp-echo-interval 120
lcp-echo-failure 3

et on peut voir qu'ils sont régulièrement effectués :


Apr 22 09:30:02 ludwigVI pppd[3055]: sent [LCP EchoReq id=0x0 magic=0xa1ce4573]
Apr 22 09:30:02 ludwigVI pppd[3055]: rcvd [LCP EchoRep id=0x0 magic=0xe8d1ffb5]

PPP permet de configurer la MRU (Maximum Receive Unit) de la ligne, souvent une source d'ennuis importante (voir par exemple le RFC 4638). Avec pppd, c'est :

mtu 1492
mru 1400

et cela donne, dans la négociation :


Apr 22 09:30:01 ludwigVI pppd[3055]: sent [LCP ConfReq id=0x1 <mru 1400> <asyncmap 0x0> <magic 0x6a0c5efc> <pcomp> <accomp>]                                              

pppd et, bien sûr, le protocole PPP lui-même dispose de nombreuses autres options.


Téléchargez le RFC 1661


L'article seul

RFC 1644: T/TCP -- TCP Extensions for Transactions Functional Specification

Date de publication du RFC : Juillet 1994
Auteur(s) du RFC : Bob Braden (University of Southern California, Information Sciences Institute)
Intérêt historique uniquement
Première rédaction de cet article le 5 décembre 2007


Il n'y a pas que des normes qui réussissent, à l'IETF. Il y a aussi des échecs, comme cette amélioration du protocole TCP, T/TCP, qui portait de nombreux espoirs à une époque et est pourtant aujourd'hui abandonnée.

T/TCP, normalisé dans ce RFC, visait à résoudre un problème de TCP : le temps d'établissement de la connexion est souvent supérieur au temps passé à transmettre des données, dès que les données sont peu nombreuses. C'est le cas des protocoles de type requête/réponse comme HTTP (beaucoup de pages Web font moins d'un ou un et demi kilo-octet, soit moins qu'un seul paquet IP) mais aussi du DNS ou de SNMP, que notre RFC cite dans sa section 1. Pour ces protocoles, on souhaiterait typiquement n'envoyer que deux paquets, un pour la question et un pour la réponse, laissant le mécanisme normal de TCP aux transferts de gros fichiers, pour lesquels le temps d'établissement de la connexion est négligeable. Le DNS ou SNMP ont choisi d'utiliser UDP et, comme celui-ci n'offre aucune fiabilité, doivent donc gérer les paquets perdus, les retransmissions, etc. HTTP a choisi d'utiliser TCP, ce qui simplifie la tâche des développeurs d'applications Web mais augmente nettement la durée d'une requête Web typique.

Pourquoi ? À cause d'une fonction essentielle de TCP, le 3-way handshake. TCP ne peut pas envoyer ne serait-ce qu'un octet de données avant d'avoir terminé l'ouverture de la connexion et cette ouverture nécessite trois paquets, le paquet de demande d'ouverture d'une connexion, SYN, le paquet d'acceptation et d'accusé de réception, SYN+ACK et le paquet d'accusé de réception ACK. Si le RTT du réseau est important (par exemple sur les liaisons satellite), la durée du 3-way handshake pourra être l'essentiel de la durée de la requête. On peut voir cet effet avec echoping, sur un site Web (http://www.kame.net/) dont la page d'accueil est très légère :

% echoping -v -h / www.kame.net

This is echoping, version 5.2.0.

Trying to connect to internet address 2001:200:0:8002:203:47ff:fea5:3085 80 to transmit 88 bytes...
Trying to send 256 bytes to internet address 2001:200:0:8002:203:47ff:fea5:3085...
Connected...
TCP Latency: 0.331326 seconds
Sent (88 bytes)...
Application Latency: 0.357898 seconds
3241 bytes read from server.
Elapsed time: 0.711559 seconds

Le temps d'établissement de la connexion (TCP latency) est la moitié du temps total. Voici le 3-way handshake correspondant, vu avec tcpdump (le grand S après les adresses IP indique un paquet SYN) :


21:43:15.110842 2001:7a8:7509::1.35261 > 2001:200:0:8002:203:47ff:fea5:3085.80: S 845465777:845465777(0) win 5728 <mss 1432,sackOK,timestamp 10604938 0,nop,wscale 0>

21:43:15.425956 2001:200:0:8002:203:47ff:fea5:3085.80 > 2001:7a8:7509::1.35261: S 3136927327:3136927327(0) ack 845465778 win 65535 <mss 1440,nop,wscale 1,nop,nop,timestamp 476839171 10604938,[|tcp]> [class 0x3] [flowlabel 0x71d12]

21:43:15.426014 2001:7a8:7509::1.35261 > 2001:200:0:8002:203:47ff:fea5:3085.80: . ack 1 win 5728 <nop,nop,timestamp 10605253 476839171>

À la fin de cette échange d'un tiers de seconde, aucune donnée « utile » n'a encore été envoyée.

(Un autre problème de TCP pour ce genre de liens est le délai d'attente à la fin d'une connexion, où chaque machine doit garder un état pour pouvoir traiter correctement les paquets arrivant en retard. Pour un serveur très chargé, gérant beaucoup de requêtes, c'est une vraie contrainte.)

L'idée de base de T/TCP est de transporter dès le premier paquet les données, de façon à ce que l'acceptation de la connexion puisse également porter la réponse. Cela se fait en utilisant une option de TCP, CC (Connection Count) qui indique la présence de données dans le paquet SYN. Le Connection Count sert également de cookie pour garantir qu'on parle bien à la même machine. Un certain nombre de détails doivent être pris en compte pour que cela marche, en conservant la fiabilité de TCP, même si des paquets sont perdus. Ce qui explique que le protocole soit plus complexe que résumé ici (les sections 2 et 3 le détaillent).

Par exemple, comme la connexion ne dure pas longtemps, la mesure du RTT que fait normalement TCP pour optimiser l'utilisation du réseau ne peut avoir lieu. La section 4.3 demande donc qu'une machine T/TCP garde un cache des RTT des différentes machines à laquelle elle parle, pour obtenir approximativement le même effet.

L'idée était donc très tentante et a été promue par plusieurs experts comme W. Richard Stevens, qui s'en est fait l'ardent défenseur. Mais peu de systèmes d'exploitation l'ont implémenté (FreeBSD est la principale exception mais Linux a eu aussi sa version), peu de machines l'ont activé et peu de logiciels s'en servaient (echoping avait une option -r pour T/TCP mais elle a été retirée pour les raisons exposées plus loin, cf. bogue #1350714).

Outre la simple inertie face à la nouveauté, T/TCP a en effet été rapidement victime d'une sécurité plus faible que celle de TCP. Il n'y a pas de miracle : si on va plus vite, on vérifie moins. Alors que les adresses IP d'une connexion TCP sont relativement authentifiées (car le numéro de séquence TCP doit être renvoyé, ce qui impose de donner sa vraie adresse IP pour recevoir les messages), T/TCP n'est guère plus fiable qu'UDP face à l'usurpation d'adresses IP. Comme les réponses sont souvent plus grandes que les requêtes, cela permet en outre une amplification de l'attaque.

Ces failles ont été documentées dans plusieurs articles :

Sur une machine FreeBSD, T/TCP semble coupé par défaut, désormais (sysctl -a | grep -E 'rfc1644|dropsyn' pour voir les variables pertinentes).

Finalement, c'est le RFC 4614 qui a marqué l'abandon officiel de T/TCP. Le RFC 6247 entérinera cet abandon en reclassifiant notre RFC 1644 comme « intérêt historique seulement ».


Téléchargez le RFC 1644


L'article seul

RFC 1630: Universal Resource Identifiers in WWW: A Unifying Syntax for the Expression of Names and Addresses of Objects on the Network as used in the World-Wide Web

Date de publication du RFC : Juin 1994
Auteur(s) du RFC : Tim Berners-Lee (CERN, World-Wide Web project)
Pour information
Première rédaction de cet article le 26 février 2007


Premier RFC à avoir normalisé les URI du Web. C'était bien avant la fondation du W3C.

Les relations des créateurs du Web avec l'IETF n'ont pas toujours été simples et amicales et ce RFC s'est donc vu gratifier d'un avertissement comme quoi l'IETF travaillait à son propre système.

Ce RFC n'en a pas moins été le premier à mentionner les URL (qui ne seront normalisés que plus tard, dans le RFC 1738) et les URN. Aujourd'hui, la norme qui décrit les URI est le RFC 3986 et leurs successeurs internationaux, les IRI sont normalisés dans le RFC 3987.

À propos d'IRI, notons que le jeu de caractères de notre RFC était encore Latin-1 (Unicode n'était pas encore visible sur l'écran radar) et que l'échappement des caractères Latin-1 passait par le %HH où H était un nombre hexadécimal, se limitant ainsi à un seul octet...


Téléchargez le RFC 1630


L'article seul

RFC 1612: DNS Resolver MIB Extensions

Date de publication du RFC : Mai 1994
Auteur(s) du RFC : Rob Austein (Epilogue Technology Corporation), Jon Saperia (Digital Equipment Corporation)
Intérêt historique uniquement
Première rédaction de cet article le 14 février 2007


Dédié au cas des résolveurs DNS, ce RFC, lancé en même temps que son compagnon, le RFC 1611, connaitra le même sort.

Il sera rabaissé au statut de Historic par le RFC 3197.


Téléchargez le RFC 1612


L'article seul

RFC 1611: DNS Server MIB Extensions

Date de publication du RFC : Mai 1994
Auteur(s) du RFC : Rob Austein (Epilogue Technology Corporation), Jon Saperia (Digital Equipment Corporation)
Intérêt historique uniquement
Première rédaction de cet article le 14 février 2007


Ce RFC, qui n'a jamais connu de déploiement significatif, visait un problème toujours non résolu : un moyen standard de gérer un serveur DNS distant.

Vue la dépendance de l'Internet vis-àvis du DNS, il est curieux de constater qu'il n'existe pas de moyen standard de gérer un serveur DNS à distance, ni pour récupérer de l'information (par exemple les compteurs d'activité), ni pour modifier la configuration du serveur (par exemple pour lui demander d'être secondaire pour une nouvelle zone).

BIND a son programme rndc, qui permet de piloter certaines fonctions du serveur à distance, mais elle est complètement spécifique à ce logiciel. Idem pour des services comme le protocole Supermaster de PowerDNS.

Il y a fort longtemps, le protocole SNMP a suscité beaucoup d'espoir et il était un peu mis « à toutes les sauces ». D'où ce RFC et son compagnon, le RFC 1612, qui normalisaient une MIB pour les serveurs DNS. Notre RFC se chargeai plus spécialement de la MIB pour un serveur, l'autre s'occupant des résolveurs.

Cette MIB était très riche : elle comptait d'innombrables compteurs, mais aussi la liste des zones DNS servies. SNMP permettant l'écriture et pas seulement la lecture, cela rendait apparemment possible de modifier cette liste en vol, de manière standard.

Voici un exemple des compteurs qu'on pouvait y trouver :

   dnsServCounterErrors OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "Number of requests the server has processed that were
               answered with errors (RCODE values other than 0 and 3)."
       REFERENCE
               "RFC-1035 section 4.1.1."
       ::= { dnsServCounter 8 }

À ma connaissance, aucun logiciel n'a jamais mis en œuvre ce RFC. Des années, plus tard, le RFC 3197 a officiellement enterré SNMP pour la gestion des serveurs DNS.


Téléchargez le RFC 1611


L'article seul

RFC 1498: On the Naming and Binding of Network Destinations

Date de publication du RFC : Août 1993
Auteur(s) du RFC : Jerome H. Saltzer (MIT, Laboratory for Computer Science)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 2 juillet 2009


Les discussions d'architecture des réseaux à l'IETF ou dans d'autres communautés techniques achoppent souvent sur le vocabulaire. Qu'est-ce que le nom d'une machine ? Qu'identifie t-il réellement ? La clé publique SSH d'une machine est-elle un nom ? D'ailleurs, faut-il identifier les machines ? Pourquoi pas les processus ? Ou les utilisateurs ? Et l'adresse ? Quel est son statut ? http://www.foo.example:8080/toto est-il une adresse bien qu'il inclus un nom ? Il ne s'agit pas uniquement de pinaillage philosophique. C'est en partie à cause du flou sur les concepts que les discussions d'architecture tournent en rond et s'éternisent.

D'innombrables documents, dont ce RFC, ont été produits pour tenter de clarifier la situation. Mais aucune terminologie cohérente n'a été adoptée. Notre RFC 1498 est donc une étape, une des plus souvent citées, dans cette longue liste. Quels sont ses points essentiels ? (Attention si vous distribuez ce document, c'est un des rares RFC qui a une licence qui n'autorise pas une distribution libre.)

Le RFC essaie d'appliquer les principes des systèmes d'exploitation aux réseaux. Les systèmes d'exploitation, eux aussi, doivent identifier les fichiers, les utilisateurs, les disques, les partitions, les parties de la mémoire, etc. Le RFC reprend la terminologie classique (mais très peu appliquée en pratique) de John Shoch, que tous les étudiants des années 1980 et 1990 ont apprise par cœur (Shoch, « A note on Inter-Network Naming, Addressing, and Routing », une copie est disponible sous le nom d'IEN 19 ) :

  • Un nom identifie ce qu'on veut,
  • Une adresse identifie où cela se trouve,
  • Une route identifie comment y aller.

À noter que cette terminologie, dans notre RFC, ne ne fait pas référence à la forme des identificateurs. Ainsi, un nom peut aussi bien être une suite de lettres ayant un sens qu'une série de chiffres opaques (contrairement à une vision trop simpliste selon laquelle les noms sont juste une forme conviviale des adresses). La terminologie de ce RFC ne sépare donc pas les identificateurs qu'un humain peut traiter et ceux qu'une machine peut traiter.

On peut voir tout de suite (ce point ne figure pas dans le RFC) que cette terminologie ne s'applique pas du tout à l'Internet. Une adresse IP, par exemple, n'identifie pas une position dans la topologie de l'Internet, puisqu'il existe des adresses PI, il y a l'anycast, etc. Un URL est un mélange de nom (la ressource que je veux) et d'adresse (puisqu'il indique où trouver la ressource, avec pas mal de détails de bas niveau comme le numéro de port).

J. Saltzer, donc, procède autrement. Il distingue quatre types d'objets qu'on peut avoir envie d'identifier :

  • Les services et les utilisateurs. Les services sont, par exemple, un service de synchronisation d'horloge.
  • Les nœuds du réseau (en gros, les machines).
  • Les points d'attachement au réseau. Ce sont les endroits où une machine se connecte et, dans la terminologie de Shoch, ce sont les adresses. Une machine IP multihomée aura ainsi plusieurs points d'attachement au réseau.
  • Les chemins (ou routes) entre points d'attachement.

Et Saltzer insiste sur le fait qu'un nom peut prendre plusieurs formes (par exemple une binaire sur le câble et une lisible pour les documentations et les fichiers de configuration), sa nature ne dépend pas de sa forme.

Là encore, même si ce point n'est pas abordé dans le RFC, on peut s'amuser à chercher une correspondance entre ces types et les identificateurs utilisés sur l'Internet :

  • Les services ou utilisateurs sont typiquement identifiés par un URI (ou parfois par une forme dégénérée, uniquement le nom de domaine, comme lorsqu'on dit fr.wikipedia.org au lieu de http://fr.wikipedia.org/),
  • Les nœuds n'ont pas vraiment d'identificateurs, à part dans certains protocoles comme SSH et HIP,
  • Les points d'attachement sont vaguement identifiés par les adresses IP mais des techniques comme l'anycast ou des mécanismes d'allocation comme les adresses PI brouillent sérieusement les choses (avec l'anycast, l'adresse IP est plutôt un identificateur de service),
  • Les chemins sont la liste des adresses IP des routeurs traversés, celle qu'affiche traceroute.

Pour notre RFC, les quatre types d'objets cités ci-dessus ont chacun une identité. Cette identité se maintient même si l'objet change ses liaisons avec les autres objets. Ainsi, un service ne devrait pas changer de nom lorsqu'il migre d'une machine à une autre, une machine (un nœud) ne devrait pas changer de nom lorsqu'il migre d'un point d'attachement à un autre, etc.

L'essentiel, donc, dit le RFC, est la liaison (binding) qui est faite entre un type d'objets et un autre. Ainsi, il doit exister un mécanisme de découverte qui permet de faire la liaison entre un service et la machine sur laquelle il opère. Un autre mécanisme de liaison permet de passer de la machine au point d'attachement. Un dernier fait passer du point d'attachement au chemin. Chacun de ces mécanismes doit également effectuer un choix, car il existe souvent plusieurs réponses.

Dans l'Internet actuel, en l'absence de vrai identificateur de machine, il y a plutôt un mécanisme unique, le DNS, qui sert aux deux premiers rôles. BGP, lui, prend en charge le dernier. (Ils ne sont pas cités dans le RFC.)

Il existe aussi parfois un autre mécanisme préalable aux autres, celui qui permet de trouver l'identificateur du service, c'est par exemple un moteur de recherche. La question est discutée dans le RFC, qui note qu'il n'y a pas toujours une liaison explicite, dans une table, entre l'idée humaine d'un service et son nom formel. Ainsi, changer un nom formel est très difficile (voir l'excellent article Cool URIs don't change).

Le RFC discute ensuite quelques cas de réseaux réels, en tenant de les mettre en correspondance avec les notions de types d'objets et de liaisons. Dans le cas d'Ethernet, l'adresse MAC est très mal nommée puisqu'elle est constante et ne dépend pas de la localisation. C'est en fait plutôt un nom et elle est utilisée comme telle par certains logiciels, par exemple pour le contrôle de la licence d'utilisation. Le cas est en fait plus complexe, par exemple parce qu'une machine a deux cartes Ethernet et peut se connecter à un réseau Ethernet en deux points. Les réseaux réels n'ont pas été conçus selon une architecture propre...

Un autre exemple est le vieux NCP où l'identificateur appelé « nom » était en fait dépendant de la position de la machine. En l'absence de mécanisme de résolution commun, la liaison entre un nom et un point d'attachement était câblée en dur dans toutes les machines du réseau. Changer une machine de place imposait donc de changer son nom... ou de mettre à jour toutes les machines du réseau, ce qui n'est pas mieux. Saltzer argumente donc que la nature d'un identificateur dépend de l'existence ou nom d'un mécanisme de résolution, et donc de l'existence d'une vraie liaison avec les identificateurs des autres types d'objet (Un autre exemple aurait pu être Fidonet.)

Donc, pour résumer ce brillant document :

  • Il existe plusieurs types d'objet à identifier,
  • Un mécanisme de liaison est nécessaire pour passer des identificateurs d'un type aux identificateurs d'un autre type,
  • Les réseaux réels comme l'Internet ne collent jamais parfaitement aux modèles.

Téléchargez le RFC 1498


L'article seul

RFC 1383: An Experiment in DNS Based IP Routing

Date de publication du RFC : Décembre 1992
Auteur(s) du RFC : Christian Huitema (INRIA)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 16 juillet 2007


Ce RFC décrit une expérience (apparemment sans suite) d'utilisation du DNS pour aider au routage IP. Cette expérience éclaire certains débats actuels sur la séparation de l'identificateur et du localisateur.

Notre RFC s'attaque à un problème récurrent de l'Internet : la croissance des tables de routage, due notamment au multihoming. Si les chiffres donnés dans le RFC font sourire aujourd'hui (« there are already more than 5000 networks announced in the NSFNET routing tables », alors qu'ils sont plus de 200 000 désormais), la question reste la même. Si un site, pour des bonnes raisons, veut se connecter à plusieurs FAI (être multihomé), il doit annoncer une route dans la table de routage globale et celle-ci croît, aux frais des opérateurs Internet.

La solution proposée par Christian Huitema dans ce RFC est de ne pas annoncer la route vers le réseau du site multihomé mais de compter sur le DNS pour la trouver. Le principe est le suivant : le site multihomé utilise le préfixe réseau 192.0.2.0/24. Le site ne fait pas de BGP et ne l'annonce pas dans la table de routage globale. Il est connecté par deux fournisseurs, dont les routeurs ont les adresses IP 10.123.6.1 et 172.18.1.3, qui ne sont pas dans ce préfixe et sont, elles, annoncées en BGP. Le site publie des enregistrements DNS de type RX qui pointent vers les routeurs des FAI :

2.0.192.in-addr.arpa.     IN    RX   10.123.6.1
                          IN    RX   172.18.1.3

Le premier routeur qui veut parler à une adresse en 192.0.2.0/24 peut alors utiliser le DNS pour trouver le routeur de bord de site.

On a donc une vraie séparation de l'identificateur et du localisateur, l'adresse non-BGPisée (192.0.2.0/24) étant un identificateur et l'adresse des routeurs de bord de site étant un localisateur.

Les enregistrements RX ont été nommés par analogie aux MX. En fait, en raison de la difficulté à déployer de nouveaux types d'enregistrement, notre RFC a utilisé des enregistrements de type TXT.

La première idée est de faire faire ce travail de client DNS à chaque routeur du trajet. Mais cela imposerait des délais et un gros trafic DNS. Le RFC spécifie donc en fait que seul le premier routeur fera une requête DNS, puis utiliser la source routing pour que les routeurs suivants n'aient pas ce travail. (On notera que le source routing ne fonctionne plus sur l'Internet d'aujourd'hui, pour des raisons de sécurité.)

L'expérience ne semble pas avoir connu de suite.


Téléchargez le RFC 1383


L'article seul

RFC 1345: Character Mnemonics and Character Sets

Date de publication du RFC : Juin 1992
Auteur(s) du RFC : Keld Simonsen (Rationel Almen Planlaegning)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 4 octobre 2007


Un ancien RFC, qui représentait une des premières incursions de l'IETF dans le monde complexe des jeux de caractères.

Ce RFC tentait d'énumérer tous les jeux de caractères en usage à l'époque (la bibliographie cite le manuel de VMS, pour le jeu de caractères de ce système !). Les préoccupations d'internationalisation sont anciennes à l'IETF et ce RFC reflète une époque très reculée, où la version 1.0 d'Unicode venait tout juste d'être publié.

Ce RFC est donc essentiellement constitué d'un format pour décrire un jeu de caractères et d'une longue liste de jeux de caractères utilisés à l'époque, en utilisant les noms d'une version préliminaire d'ISO 10646. C'était donc un concurrent direct de la norme Unicode. Cette démarche n'a pas eu un succès fracassant et MIME, par exemple, se contentera d'attribuer un identificateur unique à chaque jeu, sans essayer de le décrire complètement (mais en citant notre RFC). Comparons par exemple l'entrée de notre RFC pour US-ASCII :

  &charset ANSI_X3.4-1968
  &rem source: ECMA registry
  &alias iso-ir-6
  &alias ANSI_X3.4-1986
  &alias ISO_646.irv:1991
  &g0esc x2842 &g1esc x2942 &g2esc x2a42 &g3esc x2b42
  &alias ASCII
  &alias ISO646-US
  &alias US-ASCII
  &alias us
  &alias IBM367
  &alias cp367
  &code 0
  NU SH SX EX ET EQ AK BL BS HT LF VT FF CR SO SI
  DL D1 D2 D3 D4 NK SY EB CN EM SB EC FS GS RS US
  SP ! " Nb DO % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
  At A B C D E F G H I J K L M N O P Q R S T U V W X Y Z <( // )> '> _
  '! a b c d e f g h i j k l m n o p q r s t u v w x y z (! !! !) '? DT

avec celle d'aujourd'hui, tirée du registre IANA, géré selon le RFC 2978 :

Name: ANSI_X3.4-1968                                   [RFC1345,KXS2]
MIBenum: 3
Source: ECMA registry
Alias: iso-ir-6
Alias: ANSI_X3.4-1986
Alias: ISO_646.irv:1991
Alias: ASCII
Alias: ISO646-US
Alias: US-ASCII (preferred MIME name)
Alias: us
Alias: IBM367
Alias: cp367
Alias: csASCII

On notera que, pour faire rentrer les jeux de caractères dans un RFC écrit en ASCII, ce RFC développe un codage se voulant « intuitif » (la section 2.3 dit The two characters are chosen so the graphical appearance in the reference set resembles as much as possible (within the possibilities available) the graphical appearance of the character.). C'est ainsi que le é, le « e accent aigü » s'écrit e' et le è, l'« e accent grave » e!. Voici la seconde moitié de la table ISO 8859-1, ainsi exprimée :

  A! A' A> A? A: AA AE C, E! E' E> E: I! I' I> I:
  D- N? O! O' O> O? O: *X O/ U! U' U> U: Y' TH ss
  a! a' a> a? a: aa ae c, e! e' e> e: i! i' i> i:
  d- n? o! o' o> o? o: -: o/ u! u' u> u: y' th y:

Téléchargez le RFC 1345


L'article seul

RFC 1323: TCP Extensions for High Performance

Date de publication du RFC : Mai 1992
Auteur(s) du RFC : Van Jacobson (University of California Berkeley, Lawrence Berkeley Laboratory), Bob Braden (University of Southern California, Information Sciences Institute), Dave Borman (Cray Research)
Chemin des normes
Première rédaction de cet article le 20 décembre 2013


L'algorithme originel de TCP rendait ce protocole de transport trop prudent et n'utilisant pas assez les réseaux, notamment ceux à forte latence. Après quelques essais, ce RFC 1323, publié en 1992, a permis à TCP de fonctionner correctement sur une bien plus grande variété de réseaux, et jusqu'à aujourd'hui. Ce RFC est ancien et a été remplacé depuis par le RFC 7323. Mais certaines discussions n'ont pas été reprises dans le nouveau RFC et ce RFC 1323 représente donc toujours une lecture indispensable pour les fans de TCP ou tout simplement pour ceux qui veulent comprendre en détail ce protocole.

Avant ce RFC 1323, TCP (normalisé dans le RFC 793 en 1981) se comportait très bien sur les réseaux locaux, ainsi que sur les réseaux distants à faible débit, comme ce qu'on avait sur un modem. Mais il était beaucoup moins satisfaisant sur les réseaux à forte latence et forte capacité, les réseaux à fort BDP où BDP signifie Bandwitdh-Delay Product. Si la capacité est faible ou la latence faible, pas de problèmes. Si leur produit dépasse une certaine valeur, TCP n'était pas capable de remplir la fenêtre et ses performances restaient en deça du maximum théorique du réseau.

La section 1 décrit ce problème. TCP avait été conçu (et avec succès) pour tourner sur des réseaux très disparates, et pour s'adapter automatiquement à leurs caractéristiques (taux de perte, latence, taux de duplication...) À l'époque du RFC 1323, TCP tournait en production sur des réseaux dont les capacités allaient de 100 b/s à 10 Mb/s et cette plage s'est plutôt élargie depuis. La transmission par fibre optique venait juste d'apparaître, poussant à explorer le comportement de TCP à de plus grands débits. Existe-t-il une limite au débit de TCP, au-delà de laquelle il ne servirait à rien d'accélérer encore les réseaux ? La question n'a pas de réponse simple.

La caractéristique importante du réseau n'est en effet pas la capacité mais le produit de la capacité et de la latence, le BDP cité plus haut. C'est cette caractéristique qui indique la taille du tuyau que TCP doit remplir, la capacité étant le « diamètre » du tuyau et la latence sa « longueur ». Si la capacité croît beaucoup, au rythme des progrès techniques, la latence est bloquée par la finitude de la vitesse de la lumière et la seule façon de l'améliorer est de raccourcir les câbles. Donc, un gros BDP oblige TCP à avoir davantage de données « en transit », envoyées, mais n'ayant pas encore fait l'objet d'un accusé de réception, ce qui implique des tampons d'entrée/sortie de grande taille mais qui implique aussi la possibilité de garder trace de grands nombres (par exemple le nombre d'octets en transit), donc d'avoir des compteurs de taille suffisante. Ces liaisons Internet avec un fort BDP sont parfois surnommées les « éléphants » de l'anglais LFN (Long Fat Network).

Un exemple typique d'éléphant est une liaison satellite, avec sa capacité souvent respectable mais sa latence terrible, due à la nécessite d'un aller-retour avec l'orbite géostationnaire. À l'époque de notre RFC, le BDP de ces liaisons était d'environ 1 Mbit soit 100 segments TCP de 1 200 octets chacun. Si une mise en œuvre de TCP se limitait à 50 segments envoyés avant de recevoir un accusé de réception, elle n'utiliserait que la moitié de la capacité disponible. Et les liaisons terrestres peuvent être des éléphants aussi. Un lien transcontinental aux États-Unis a une latence de 30 ms, ce qui, à 45 Mb/s, fait également un BDP de 1 Mbit.

Qu'est-ce qui empêchait TCP de tirer profit de ces éléphants ? Trois points :

  • La taille de la fenêtre n'est stockée par défaut que sur 16 bits, ne permettant pas de fenêtre plus grande que 65 535 octets. Ce problème est résolu par notre RFC 1323 avec l'introduction du window scaling.
  • TCP n'avait pas une connaissance assez précise du RTT, valeur pourtant essentielle au calcul du délai d'attente maximum avant la réémission d'un segment pour lequel il n'y a pas eu d'accusé de réception. Notre RFC 1323 s'attaque au problème avec une nouvelle option TCP permettant d'estampiller temporellement un segment.
  • La récupération était trop longue en cas de perte de paquets. Les premiers TCP, dès qu'un paquet était perdu, attendaient de vider complètement le pipeline, puis repartaient de zéro, comme pour une connexion TCP neuve. En 1990, l'algorithme de TCP avait été modifié pour permettre un redémarrage plus rapide, tant qu'on ne perdait qu'un seul paquet par fenêtre TCP. Mais, avec des fenêtres plus grandes, cette probabilité de perte augmente. Les accusés de réception de TCP étant cumulatifs, une perte de paquet survenant au début de la fenêtre peut faire tout perdre. La solution a été une option d'accusés de réception sélectifs (SACK pour Selective ACKnowledgment). Contrairement aux deux points précédents, celui-ci n'a pas été traité dans ce RFC 1323 mais dans un RFC ultérieur, le RFC 2018.

Un autre problème à considérer est la fiabilité. Si on utilise TCP, c'est pour avoir certaines garanties : que tous les octets émis seront reçus, dans le même ordre, etc. Est-ce que le passage à de plus hautes performances menace ces garanties ? Par exemple, avec des fenêtres plus grandes, la probabilité qu'un paquet ancien, appartenant à une précédente connexion, lorsqu'il finit par arriver, tombe dans la fenêtre courante, cette probabilité est plus élevée. Dans ces conditions, les données seraient corrompues. La principale protection de TCP contre cet accident est la notion de MSL (Maximum Segment Lifetime), le temps qu'un segment peut traîner sur l'Internet. Il ne faut pas réutiliser des numéros de séquence avant qu'une durée supérieure ou égale à la MSL se soit écoulée. Ce numéro ne faisant que 32 bits, cela peut être délicat, surtout aux débits élevés (même sans fenêtres agrandies). La MSL est généralement prise à deux minutes or, à seulement 1 Gb/s, les numéros de séquence ne durent que dix-sept secondes. Or, aucun mécanisme sur l'Internet ne garantit le respect de la MSL. Un vieux paquet ne sera pas jeté. D'où l'utilisation par notre RFC 1323 de la nouvelle option Timestamps pour détecter les segments trop anciens et se protéger donc contre la réutilisation des numéros de séquence TCP.

Reste que les solutions proposées dans ce RFC dépendent des options TCP. Pour certains protocoles, par exemple IP, certaines options ont du mal à passer à travers le réseau. TCP semble mieux placé de ce point de vue (il est mentionné à la fin de mon article sur les options IP).

La section 2 de notre RFC présente la première option qui avait été normalisée pour améliorer les performances de TCP sur les liens à fort BDP (Bandwidth-Delay Product), le window scaling. L'idée de base est très simple : 16 bits pour indiquer la taille de la fenêtre, c'est trop peu, on va donc appliquer un facteur (indiqué dans une option TCP) au nombre décrit par ces 16 bits. À noter que, comme les options ne sont envoyées qu'au début de la connexion TCP, le facteur est constant (la fenêtre elle-même étant dynamique).

La nouvelle (à l'époque de ce RFC) option Window Scale comprend trois champs : Type, Longueur et Valeur. Le type vaut 3 et est enregistré dans le registre des options, la longueur est forcément de 3 (trois octets en tout) et la valeur est un octet qui indique de combien de bits on va décaler la taille de la fenêtre. Une valeur de 0 indique pas de décalage, donc un facteur de 1 (une telle valeur n'est pas inutile car elle sert à indiquer au pair TCP qu'on sait gérer le window scaling). Une valeur de 1 indique qu'on double la taille de la fenêtre pour connaître la vraie valeur, etc. Voici un exemple vu par Wireshark :

Transmission Control Protocol, Src Port: 51336 (51336), Dst Port: 4332 (4332), Seq: 0, Len: 0
...
   Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
...
        Window scale: 5 (multiply by 32)
            Kind: Window Scale (3)
            Length: 3
            Shift count: 5

Et, quelques paquets plus loin, on voit bien le facteur d'échelle appliqué (32, soit 2^5). Le champ indiquant la longueur de la fenêtre vaut 728 octets mais il faut en fait lire 23 296 octets :

    Window size value: 728
    [Calculated window size: 23296]
    [Window size scaling factor: 32]

(À noter que je parlais aussi de cette option à la fin de l'article sur le RFC 793.) Sur Linux, cette option peut s'activer ou se désactiver avec le paramètre sysctl net.ipv4.tcp_window_scaling (c'est parfois nécessaire de la désactiver dans certains réseaux bogués qui bloquent les paquets TCP contenant des options inconnues d'eux).

Autre option normalisée ici, la meilleure mesure du RTT par l'option Timestamps, en section 3. La mesure du RTT est cruciale pour TCP, pour éviter des accidents comme la congestion brutale décrite dans le RFC 896. Si TCP ne mesure qu'un seul paquet par fenêtre, les résultats seront mauvais pour les grandes fenêtres, par simple problème d'échantillonage (critère de Nyquist).

L'option Timestamps a le type 8, une longueur de 10, et deux champs de quatre octets, l'heure qu'il était au moment de l'envoi et l'heure lue dans le paquet pour lequel on accuse réception (cette valeur n'a donc de sens que si le paquet a le bit ACK). L'« heure » n'est pas forcément celle de l'horloge au mur (puisque, de toute façon, on n'utilisera que des différences), l'important est qu'elle avance à peu près au même rythme. Attention, il n'y a aucune raison qu'on ait le même nombre de paquets dans les deux sens. On peut voir un pair TCP envoyer deux paquets et le récepteur ne faire qu'un seul paquet d'accusé de réception. Dans ce cas, ledit récepteur devra renvoyer le temps du paquet le plus ancien. Toujours avec Wireshark, cela donne :

Transmission Control Protocol, Src Port: 4332 (4332), Dst Port: 51336 (51336), Seq: 0, Ack: 1, Len: 0
...
   Options: (20 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale
...
        Timestamps: TSval 2830995292, TSecr 27654541
            Kind: Timestamp (8)
            Length: 10
            Timestamp value: 2830995292
            Timestamp echo reply: 27654541

Et, dans le paquet suivant de la même direction, les compteurs ont augmenté :

        Timestamps: TSval 2830995566, TSecr 27654569
            Kind: Timestamp (8)
            Length: 10
            Timestamp value: 2830995566
            Timestamp echo reply: 27654569

Ici, il s'agissait d'une communication entre deux machines Linux. La génération des estampilles temporelles dans les options TCP est contrôlée par la variable sysctl net.ipv4.tcp_timestamps (documentée, comme les autres, dans le fichier Documentation/networking/ip-sysctl.txt des sources du noyau). Par exemple :

% sysctl net.ipv4.tcp_timestamps
net.ipv4.tcp_timestamps = 1

Cela signifie que cette option est activée sur cette machine (0 = désactivée).

La section 4 présente le mécanisme PAWS (Protect Against Wrapped Sequence numbers), qui sert à lutter contre les vieux segments TCP qui arriveraient tard et avec, par malchance, un numéro de séquence qui a été réutilisé depuis et est donc considéré comme valide. Les numéros de séquence étant stockés sur 32 bits seulement, la probabilité d'un tel accident augmente avec la capacité des réseaux. PAWS se sert de la même option Timestamps qui a été présentée plus haut. L'idée est que si un segment TCP arrive avec une estampille temporelle trop ancienne, par rapport à celles reçues récemment, on peut le jeter sans remords. Comme pour tous les usages de l'option Timestamps, il ne nécessite pas de synchronisation d'horloges entre les deux pairs TCP car les comparaisons se font toujours entre les estampilles mises par une même machine.

L'annexe C résume les changements depuis les prédécesseurs, les RFC 1072 et RFC 1185 et ils sont assez profonds. Notamment :

  • L'option SACK (Selective ACKnowledgment), trop contestée à cette époque, a été migrée vers un futur RFC (ce fut le RFC 2018).
  • Les règles précises d'envoi des estampilles temporelles ont été sérieusement refondues.
  • L'ancêtre de l'option Timestamps, les options Echo et Echo reply du RFC 1072 ont été supprimées.

Téléchargez le RFC 1323


L'article seul

RFC 1305: Network Time Protocol (Version 3) Specification, Implementation

Date de publication du RFC : Mars 1992
Auteur(s) du RFC : David L. Mills (University of Delaware, Electrical Engineering Department)
Chemin des normes
Première rédaction de cet article le 10 avril 2009


Dans tout système technique complexe, comme l'Internet, on a besoin d'horloges correctes. À tout moment, on lit l'heure et on en tient compte. Par exemple, l'ingénieur système qui lit les journaux d'un serveur a besoin d'être sûr de l'heure qu'ils indiquent. De même, le chercheur qui mesure le temps de propogation d'un paquet IP entre deux machines en soustrayant le temps de départ de celui d'arrivée (cf. RFC 7679) doit être sûr des horloges des deux machines, sinon la mesure sera fausse. Pour synchroniser des horloges, on pourrait munir chaque ordinateur connecté à Internet d'un récepteur GPS ou équivalent. Mais de tels récepteurs sont relativement chers (surtout pour les engins les moins puissants comme les PC bas de gamme ou les téléphones portables) et ne marchent pas dans toutes les circonstances (le GPS ne fonctionne bien qu'en plein air). Le mécanisme privilégié sur l'Internet est donc que seules certaines machines sont connectées à une horloge physique correcte et que les autres d'ajustent sur celles-ci, par le biais du protocole NTP, objet de ce RFC.

A priori, synchroniser une machine C sur une autre, nommée S, est simple : C demande l'heure à S et S lui donne. C'est ainsi que fonctionnait le protocole Time du RFC 868. Mais ce mécanisme a un gros défaut : il ne tient pas compte du temps de propagation dans le réseau. Lorsque C reçoit la réponse, elle n'est déjà plus correcte... La résolution d'horloge qu'on peut obtenir est donc limitée par ce temps de propagation. En outre, les algorithmes tels que celui du RFC 868 ne permettent pas de tirer profit de multiples serveurs de temps puisqu'ils ne fournissent aucun moyen de décider quel est le « meilleur » serveur.

Pour expliquer la synchronisation d'horloge, tout un vocabulaire spécifique est nécessaire. Il n'y a pas de glossaire dans le RFC mais des mots come delay et offset sont définis en section 2 : pour résumer, une horloge peut avoir un écart (offset) avec le « vrai » temps, UTC (ou bien avec une autre horloge, si on s'intéresse juste au fait qu'elles soient synchronisées, ce qui n'est pas le cas de NTP). Si cet écart est inférieur à une certaine valeur, on dit que l'horloge est correcte (accurate). Et l'horloge peut avoir un décalage (skew), elle peut avancer plus ou moins vite qu'une autre (ce qui entrainera l'apparition ou l'aggravation d'un écart). Pire, la dérive peut être variable, auquel cas on mesure la dérivée seconde du décalage sous le nom de dérive (drift, mais NTP ignore ce facteur). Enfin, l'horloge a une certaine résolution (precision), la plus petite unité de temps qu'elle peut mesurer. Des problèmes de mesure de temps analogues sont présents dans bien d'autres RFC notamment le RFC 2330 mais aussi les RFC 4656 ou RFC 5481. Pour obtenir le temps d'un autre serveur, alors que le délai de propagation est non-nul, NTP utilise des estampilles temporelles, des valeurs de la mesure de l'horloge, mises dans le paquet. Après plusieurs paquets échangés, chaque serveur NTP connait le délai de propagation avec un autre serveur (ainsi que, au bout d'un temps un peu plus long, la gigue, la variation de ce délai, suite aux hoquets du réseau) et peut donc déduire ce délai des temps mesurés par son pair. Sur une machine Unix, voyons ce que cela donne avec la commande ntpq -c peers :

% ntpq -c peers                                   
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+relay1.nic.fr   192.134.4.11     3 u  998 1024  377    0.297   -1.554   0.163
 gw.prod-ext.pri .INIT.          16 u    - 1024    0    0.000    0.000   0.000
+obelix.gegeweb. 145.238.203.10   3 u  695 1024  377    5.226    0.586   1.768
-ntp.univ-poitie 224.22.30.230    3 u  498 1024  377    6.885   -4.565   0.267
*ns1.azuria.net  193.67.79.202    2 u   56 1024  377    2.739   -1.411   0.305
-rps.samk.be     193.190.198.10   3 u  984 1024  377    5.293    5.930   0.317

Lorsque plusieurs serveurs NTP sont accessibles, NTP sélectionne le meilleur (en tenant compte de divers paramètres comme justement la gigue). Il n'y a pas de vote entre serveurs, NTP est une dictature où le meilleur serveur a toujours raison.

Comme norme, NTP est très stable, et n'avait pas bougé entre cette version 3 et la version 4, apparue dix-huit ans plus tard dans le RFC 5905. La version 2 était décrite dans le RFC 1119 et les différences (aucune n'est essentielle) entre les deux versions sont décrites dans l'annexe D. La version 3 a surtout amélioré les divers algorithmes de traitement des données, sans changer le modèle, et en changeant à peine le protocole. (La première version de NTP était dans le RFC 958.) NTP n'était pas le premier protocole de synchronisation d'horloge, loin de là. Il a été précédé par daytime (RFC 867) ou time (RFC 868), ainsi que par des options d'ICMP comme celle du RFC 781. Il y a également eu des mises en œuvre non normalisées comme le démon timed sur Berkeley Unix. NTP a aussi été inspiré par le protocole DTS, partie du système DCE mais, contrairement à DTS, il n'impose pas que toutes les machines participantes dépendent du même administrateur. Enfin, il y a eu d'innombrables projets de recherche sur des thèmes bien plus ambitieux comme la détermination de la justesse ou de la fausseté d'une horloge, problèmes que NTP n'essaie pas de traiter. Voir la section 1.1 pour plus de détails sur ces autres techniques. Enfin, la version 4 de NTP, on l'a dit, a été publiée en juin 2010 dans le RFC 5905, sans qu'elle change fondamentalement les principes du protocole.

Le problème de la synchronisation d'horloges est très complexe et plein de détails difficiles. Le RFC 1305 est donc un des plus gros RFC qui soit (plus de cent pages). En outre, l'abondance des formules mathématiques, rares dans les RFC mais nécessaires ici à cause des calculs d'erreur, fait que notre RFC n'est pas uniquement disponible en texte brut. S'il y a bien une version dans ce format, l'auteur prévient qu'il est recommandé de lire la version PDF, disponible au même endroit. Elle est la seule à disposer des équations mais aussi de la pagination. Enfin, le caractère plus « scientifique » de ce RFC fait que la section 7, les références, est spécialement longue et évoque plus un article de physique qu'une norme TCP/IP. Le lecteur pressé a sans doute intérêt à lire plutôt l'article de David Mills (l'auteur du RFC), Internet Time Synchronization: the Network Time Protocol qui reprend le plan du RFC mais en omettant les détails (attention, cet article ne décrit que la version 2 de NTP mais les différences ne sont pas vitales). Autrement, la page Web dudit auteur, propose plein d'informations sur NTP.

La section 2 décrit le modèle utilisé. NTP considère que certaines machines ont l'information correcte (par exemple parce qu'elles l'ont obtenu d'une horloge sûre) et que le seul problème est de transmettre cette information aux autres machines. NTP ne s'essaie pas à déterminer si les serveurs ont raison ou tort, il leur fait confiance, il n'existe pas de système de vote, NTP n'est pas une démocratie. Certaines machines ont raison et les autres s'alignent.

Communiquant avec un serveur, un client NTP détermine l'écart (clock offset) avec ce serveur, le RTT (roundtrip delay) et la dispersion, qui est l'écart maximal avec l'autre horloge.

Pour cette communication, il existe plusieurs mécanismes (section 2.1), le plus courant étant un mécanisme client/serveur où le client NTP demande au serveur le temps. Celui-ci répond et l'information contenue dans le paquet permettra au client de déterminer les valeurs ci-dessus, notamment l'écart. En fait, NTP est plus compliqué que cela car il existe plusieurs niveaux de serveurs et chaque client utilise plusieurs serveurs, pour se prémunir contre une panne. La proximité d'un serveur avec une « vraie » horloge est mesurée par un nombre, la strate (section 2.2), qui vaut 1 lorsque le serveur est directement connecté à l'horloge et N+1 lorsque le serveur est coordonné avec un serveur de strate N.

Le serveur calcule ensuite (par une variante de l'algorithme de Bellman-Ford), le chemin le plus court (en utilisant comme métrique le nombre d'étapes et la strate), et c'est par celui-ci que sera transmise la valeur correcte de l'horloge (je le répète, NTP ne fait pas de pondération entre les serveurs possibles, sauf dans le cas particulier décrit dans l'annexe F, une nouveauté de la version 3 de NTP).

La section 3 décrit le protocole. La plus importante information transportée par NTP est évidemment le temps, exprimé sous forme d'un doublet. La première partie du doublet est un nombre sur 32 bits qui indique le nombre entier de secondes depuis le 1er janvier 1900 (section 3.1). La seconde est la partie fractionnaire de cette même valeur. Cela assure donc une précision d'environ 200 picosecondes. Comme tout le fonctionnement de NTP dépend de la précision de ces estampilles temporelles, le RFC recommande que leur écriture dans les paquets soit, autant que possible, fait dans les couches les plus basses, par exemple juste au dessus du pilote de la carte réseau.

32 bits n'est pas énorme et la valeur maximale sera atteinte en 2036. Les programmes devront donc s'adapter et faire preuve d'intelligence en considérant qu'un nombre de secondes très faible signifie « un peu après 2036 » et pas « un peu après 1900 ». Plus drôle, comme la valeur zéro est spéciale (elle signifie que le temps n'est pas connu), pendant 200 picosecondes, au moment de la transition, NTP ne marchera plus.

Pour son bon fonctionnement, NTP dépend de certaines variables, décrites en section 3.2. Il y par exemple l'adresse IP du pair mais aussi :

  • leap indicator qui indique si une seconde intercalaire est imminente,
  • la strate (1 si le serveur a une horloge, de 2 à 255 autrement),
  • la précision de son horloge,
  • un identifiant sur quatre octets, typiquement une chaîne de caractères pour un serveur de strate un, par exemple GPS pour le GPS, ATOM pour une horloge atomique ou LORC pour le bon vieux LORAN,
  • temps d'aller-retour lors de la communication avec le pair,
  • etc.

L'identifiant du type d'horloge est indiqué dans la sortie de ntpq -c peers si le pair est de strate 1, ou bien par la commande ntptrace sous le nom de refid. Par exemple, ici, clock.xmission.com est synchronisé au GPS :

% ntptrace 
localhost: stratum 3, offset 0.000175, synch distance 0.072555
tock.slicehost.net: stratum 2, offset 0.000658, synch distance 0.057252
clock.xmission.com: stratum 1, offset 0.000010, synch distance 0.000274, refid 'GPS'

NTP peut fonctionner selon plusieurs modes (section 3.3), en client ou en serveur mais aussi en mode diffusion (un serveur qui envoie ses données que quelqu'un écoute ou pas). Ainsi, avec le programme ntpd (voir http://support.ntp.org/) d'Unix, si on configure dans /etc/ntp.conf :

broadcast 224.0.0.1

(où l'adresse est celle de diffusion) ntpd va diffuser ses informations à tout le réseau local. Si on met :

broadcastclient

il écoutera passivement les annonces des serveurs qui diffusent. Si enfin, on écrit :

server ntp1.example.net
server ntp2.example.net

il cherchera activement à se connecter aux serveurs ntp1.example.net et ntp2.example.net pour obtenir d'eux des informations sur l'heure qu'il est. Les deux serveurs établiront alors une association entre eux.

NTP peut se défendre contre un pair qui enverrait des informations aberrantes mais il ne contient pas de système de vote qui pourrait protéger contre des pairs malveillants. Même avec un tel système, si tous les pairs participaient d'un commun accord à l'attaque, NTP serait alors trompé. Il faut donc s'assurer que les pairs sont bien ceux qu'on croit. La section 3.6 (et l'annexe C) décrit les contrôles d'accès qu'on peu utiliser. En pratique, cette sécurité est peu pratiquée ; bien que fausser l'horloge d'une machine puisse avoir de sérieuses conséquences pour la sécurité (journaux avec une heure fausse, par exemple), les attaques sur NTP semblent rares. La principale protection reste le filtrage au niveau du pare-feu.

La section 4 décrit les algorithmes de correction qui permettent de réparer dans une certaine mesure les erreurs des horloges, ou bien celles introduites par la propagation dans le réseau. NTP peut aussi bien filtrer les mesures d'une horloge donnée (en ne gardant que les meilleures) que garder les bonnes horloges parmi l'ensemble des pairs accessibles. C'est une des parties les plus mathématiques du RFC, et qui justifie de lire la version PDF.

La précision obtenue avec NTP dépend évidemment de la précision de l'horloge locale. La section 5 décrit la conception d'une horloge telle qu'utilisée dans le système Fuzzball et permettant d'atteindre les objectifs de NTP.

Le format effectif des paquets apparait dans l'annexe A. Les paquets NTP sont transportés sur UDP, port 123. Chaque message indique le mode de l'émetteur (par exemple client, serveur ou autre), les différentes estampilles temporelles (heure de réception du paquet précédent Receive Timestamp, heure d'émission de celui-ci Transmit Timestamp, etc), précision de l'horloge locale, etc. Les estampilles temporelles sont indiquées dans le format à 64 bits décrit plus haut. Leur usage est décrit en section 3.4. Du fait que chaque paquet contienne toutes les estampilles nécessaires, les paquets sont auto-suffisants. Il n'est pas nécessaire qu'ils arrivent dans l'ordre, ni qu'ils soient tous délivrés (d'où le choix d'UDP comme protocole de transport).

Pour observer NTP en action, on peut utiliser tcpdump :

# tcpdump -vvv udp and port 123
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
17:11:46.950459 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 76) munzer.bortzmeyer.org.ntp > tock.slicehost.net.ntp: [udp sum ok] NTPv4, length 48
        Client, Leap indicator:  (0), Stratum 3, poll 10s, precision -20
        Root Delay: 0.037567, Root dispersion: 0.082321, Reference-ID: tock.slicehost.net
          Reference Timestamp:  3448017458.952901899 (2009/04/06 16:37:38)
          Originator Timestamp: 3448018483.951783001 (2009/04/06 16:54:43)
          Receive Timestamp:    3448018483.951863646 (2009/04/06 16:54:43)
          Transmit Timestamp:   3448019506.950407564 (2009/04/06 17:11:46)
            Originator - Receive Timestamp:  +0.000080633
            Originator - Transmit Timestamp: +1022.998624563
17:11:46.950946 IP (tos 0x10, ttl 63, id 0, offset 0, flags [DF], proto UDP (17), length 76) tock.slicehost.net.ntp > munzer.bortzmeyer.org.ntp: [udp sum ok] NTPv4, length 48
        Server, Leap indicator:  (0), Stratum 2, poll 10s, precision -20
        Root Delay: 0.036941, Root dispersion: 0.012893, Reference-ID: clock.xmission.com
          Reference Timestamp:  3448019415.234667003 (2009/04/06 17:10:15)
          Originator Timestamp: 3448019506.950407564 (2009/04/06 17:11:46)
          Receive Timestamp:    3448019506.951188027 (2009/04/06 17:11:46)
          Transmit Timestamp:   3448019506.951214015 (2009/04/06 17:11:46)
            Originator - Receive Timestamp:  +0.000780425
            Originator - Transmit Timestamp: +0.000806425

On voit ici que munzer.bortzmeyer.org, machine chez Slicehost a contacté le serveur de temps, tock.slicehost.net (le second serveur NTP de cet hébergeur se nomme tick.slicehost.net) en indiquant que le paquet était émis (Transmit Timestamp à 3448019506.950407564 (soit le six avril 2009 vers 17:11:46). tock.slicehost.net répond, renvoie cette estampille dans le champ Originator Timestamp, indique qu'il l'a reçue à 3448019506.951188027, soit 780 microsecondes plus tard et qu'il a répondu à 3448019506.951214015, 26 microsecondes après la réception. munzer.bortzmeyer.org, en regardant à quelle heure il a reçu le paquet, peut en déduire le délai d'acheminement et le décalage des deux horloges. Si le serveur venait de démarrer, toutes les estampilles sont à zéro, sauf celle de transmission :

22:39:26.203121 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 76) munzer.bortzmeyer.org.ntp > tick.slicehost.net.ntp: [udp sum ok] NTPv4, length 48
        Client, Leap indicator: clock unsynchronized (192), Stratum 0, poll 6s, precision -20
        Root Delay: 0.000000, Root dispersion: 0.000000, Reference-ID: (unspec)
          Reference Timestamp:  0.000000000
          Originator Timestamp: 0.000000000
          Receive Timestamp:    0.000000000
          Transmit Timestamp:   3448384766.203066617 (2009/04/10 22:39:26)
            Originator - Receive Timestamp:  0.000000000
            Originator - Transmit Timestamp: 3448384766.203066617 (2009/04/10 22:39:26)

L'annexe E contient des passionnants détails sur les calculs de temps. Par exemple, l'annexe E.3 est consacrée à un exposé plus détaillé des divers services de synchronisation d'horloges publics, par exemples ceux du NIST, le LORAN ou le DCF77 allemand. Notez que, à l'époque de la publication du RFC, le GPS était encore en cours de déploiement.

L'annexe E.4 parle de l'organisation du temps, les calculs calendaires. (Je me permets de placer ici une petite publicité pour le livre de Reingold & Dershowitz Calendrical calculations.)

L'annexe G, chargée en mathématiques et en physique, décrit la modélisation des horloges. En G.1.2, l'informaticien intéressé par Unix trouvera un exposé très détaillé de l'application de ce modèle aux horloges Unix. Les appels système settimeofday() et adjtime() permettent de modifier l'horloge système, brutalement dans le premier cas et progressivement dans le second (celui utilisé par NTP). adjtime() prend bien soit que l'horloge ne recule jamais (si elle est en avance, on la ralentit, mais on ne la fait pas aller en arrière).

L'annexe H est une analyse fouillée des causes d'erreurs dans la synchronisation d'horloges, aussi bien celles dues à l'horloge elle-même que celles dues à la propagation des messages dans le réseau. Ces dernières erreurs sont difficiles à caractériser car elles sont tout sauf aléatoires. (En effet, elles dépendent surtout de la taille des files d'attente dans les routeurs, puisque le temps de propagation, lui, est peu variable, cf. H.4. Les variations de taille de ces files sont assez chaotiques.)

L'annexe I plaira aux programmeurs car elle est la seule qui contient du code source, en C, mettant en œuvre certains des algorithmes décrits dans le RFC.

La mise en œuvre la plus courante de NTP, sur Unix, est celle du serveur ntpd. Il se configure dans le fichier /etc/ntp.conf et la documentation complète figure en ligne sur http://doc.ntp.org/. La commande ntpdate permet une mise à jour sommaire, sans faire tourner de serveur :

# ntpdate pool.ntp.org
 23 Feb 01:34:10 ntpdate[3335]: step time server 192.83.249.31 offset 2.155783 sec 

Mais pour une meilleure précision, il faut un serveur tournant en permanence (autrement, il existe une version simplifiée de NTP, SNTP, décrite dans le RFC 4330). Voici par exemple une station de travail ordinaire, synchronisée au serveur NTP de son réseau, ntp.example.org :

server ntp.example.org
server 127.127.1.0
fudge 127.127.1.0 stratum 13

Les deux dernières lignes sont là pour dire à ntpd que l'horloge locale est raisonnablement stable et qu'on peut la considérer comme de strate 13. Comme on ne veut pas forcément que tout l'Internet aille ensuite noyer cette machine sous le trafic NTP et, pire, changer son horloge, on restreint souvent les possibilités de NTP à certaines actions. Par exemple :

# Exchange time with everybody, but don't allow configuration.
restrict default kod notrap nomodify nopeer noquery
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1 nomodify

Une fois cette machine synchronisée, les commandes ntpq et ntptrace permettront de regarder l'état de NTP :

% ntptrace 
localhost: stratum 3, offset 0.000116, synch distance 0.015000
fuzzer.example.org: stratum 2, offset 0.000149, synch distance 0.009868
192.0.2.77: timed out, nothing received
***Request timed out

Ici, le serveur de strate 1, 192.0.2.77 n'accepte pas des interrogation directes de la part des stations, il ne répond donc pas à ntptrace. On peut avoir plus de détails sur les pairs avec ntpq, par exemple :

ntpq> peers
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*fuzzer.ex       192.0.2.176      2 u   50   64  377    0.304    0.107   0.064
 LOCAL(0)        .LOCL.          13 l    1   64  377    0.000    0.000   0.001

ntpq> clocklist
assID=0 status=0000 clk_okay, last_clk_okay,
device="Undisciplined local clock", timecode=, poll=33834, noreply=0,
badformat=0, baddata=0, fudgetime1=0.000, stratum=13, refid=76.79.67.76,
flags=0

qui permet de voir le délai de la communication avec le serveur de strate 2 (ce délai est logiquement de zéro avec l'horloge locale, de strate 13). On peut aussi voir qu'il y a eu association :

ntpq> associations

ind assID status  conf reach auth condition  last_event cnt
===========================================================
  1 16199  9614   yes   yes  none  sys.peer   reachable  1
  2 16200  9014   yes   yes  none    reject   reachable  1

ntpq> pstatus 16199
assID=16199 status=9614 reach, conf, sel_sys.peer, 1 event, event_reach,
srcadr=fuzzer.example.org, srcport=123, dstadr=192.0.2.1, dstport=123,
leap=00, stratum=2, precision=-20, rootdelay=1.999,
rootdispersion=7.858, refid=192.0.2.176, reach=377, unreach=0,
hmode=3, pmode=4, hpoll=6, ppoll=6, flash=00 ok, keyid=0, ttl=0,
offset=0.116, delay=0.305, dispersion=3.077, jitter=0.015,
reftime=cd848978.4d74dea3  Mon, Apr  6 2009 16:00:24.302,
org=cd848a03.2ce4faea  Mon, Apr  6 2009 16:02:43.175,
rec=cd848a03.2ce6b9ee  Mon, Apr  6 2009 16:02:43.175,
xmt=cd848a03.2cd129e9  Mon, Apr  6 2009 16:02:43.175,
filtdelay=     0.31    0.32    0.32    0.32    0.32    0.31    0.37    0.34,
filtoffset=    0.13    0.13    0.13    0.13    0.13    0.12    0.15    0.12,
filtdisp=      0.00    0.99    1.94    2.93    3.90    4.88    5.85    6.80

Ici, il n'y avait qu'une seule vraie association, de numéro 16199, avec le serveur NTP de strate 2.

Et sur un routeur Cisco ? Configurer NTP en client est simplement :

Router#config terminal
Enter configuration commands, one per line.  End with CNTL/Z.
Router(config)#ntp server 129.237.32.2
Router(config)#^Z

Le configurer en serveur pour d'autres machines, ici en strate 10 par défaut :

Router#config terminal
Enter configuration commands, one per line.  End with CNTL/Z.
Router(config)#ntp master 10
Router(config)#^Z

On peut alors vérifier l'état de NTP :

Router#show ntp status
Clock is synchronized, stratum 3, reference is 128.249.2.2
nominal freq is 250.0000 Hz, actual freq is 249.9961 Hz, precision is 2**16
reference time is BF454660.7CCA9683 (22:37:36.487 EDT Sat Sep 8 2001)
clock offset is 4.3323 msec, root delay is 136.28 msec
root dispersion is 37.69 msec, peer dispersion is 1.14 msec

Router#show ntp associations
 
      address         ref clock     st  when  poll reach  delay  offset    disp
  *~128.249.2.2      192.5.41.40     2    4    64   377    76.9    5.49     0.4
  -~130.218.100.5    198.72.72.10    3   33   128   377     7.1   13.13     0.6
  +~129.237.32.2     192.43.244.18   2   16    64   377    44.8    3.05     0.9
  +~128.118.25.3     128.118.25.12   2   48    64   377    39.7    5.50     1.4
 * master (synced), # master (unsynced), + selected, - candidate, ~ configured

Tout le monde n'a pas forcément un serveur NTP chez lui, ni un fournisseur qui lui en procure un de qualité. Il est donc pratique de faire appel à des serveurs publics. Pour cela, le projet pool.ntp.org enregistre dans le DNS l'adresse IP des volontaires qui participent au service ntp.pool.org. Il suffit au client de mettre dans sa configuration :

server pool.ntp.org
server pool.ntp.org
server pool.ntp.org
server pool.ntp.org

pour se synchroniser à quatre serveurs, pris au hasard parmi les volontaires. Notez bien que le fait de répéter la même ligne quatre fois n'est pas une erreur. Chacune de ces lignes va déclencher une requête DNS qui donnera à chaque fois une liste d'adresses IP dans un ordre différent :

% dig +short A  pool.ntp.org   
91.208.102.2
195.83.66.158
81.19.16.225
87.98.147.31
88.191.77.246

% dig +short A  pool.ntp.org
88.191.77.246
91.208.102.2
195.83.66.158
81.19.16.225
87.98.147.31

% dig +short A  pool.ntp.org
87.98.147.31
88.191.77.246
91.208.102.2
195.83.66.158
81.19.16.225

Pour être sûr d'avoir des adresses différentes, il suffit de préfixer les noms par un chiffre :

server 1.pool.ntp.org
server 2.pool.ntp.org
server 3.pool.ntp.org
server 4.pool.ntp.org

Vu avec ntpq, on pourra avoir, par exemple :

% ntpq 
ntpq> peers
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ks34176.kimsufi 193.52.184.106   2 u  25d 1024    0    1.116   -4.039   0.000
*ns1.azuria.net  193.67.79.202    2 u  116  256  377    1.412   -1.931   0.647
+mail1.vetienne. 129.240.64.3     3 u  208  256  377    1.657  -18.063   3.348
+ntp1.adviseo.ne 209.81.9.7       2 u  114  256  377    1.001   -3.440   1.622
ntpq> 

où des machines d'hébergeurs très différents sont utilisées, NTP choisissant le meilleur (atteignable, proche, faible gigue, etc). Bien sûr, pool.ntp.org n'offre aucune sécurité, puisque rien ne dit qu'un méchant ne s'est pas glissé dans le lot dans le but de perturber vos horloges. Mais c'est un service gratuit, fourni par la communauté et globalement de très bonne qualité. À noter que ceux qui réalisent un système d'xploitation peuvent demander un sous-domaine, pour y mettre par défaut leur machine. C'est ce que fait, par exemple, Debian et une machine Debian sera configurée par défaut avec quelque chose du genre :

server 0.debian.pool.ntp.org
server 1.debian.pool.ntp.org
server 2.debian.pool.ntp.org
server 3.debian.pool.ntp.org

Téléchargez le RFC 1305


L'article seul

RFC 1288: The Finger User Information Protocol

Date de publication du RFC : Décembre 1991
Auteur(s) du RFC : David Paul Zimmerman (Rutgers University, Center for Discrete Mathematics and Theoretical Computer Science (DIMACS))
Chemin des normes
Première rédaction de cet article le 24 septembre 2013


Il y a bien longtemps, dans l'Internet, toutes les machines Unix connectées au réseau avaient un serveur finger. Ce protocole permettait d'obtenir des informations sur les utilisateurs de cette machine, à la fois de l'information statique (leur numéro de téléphone, le numéro de leur bureau à l'université...) mais aussi de l'information dynamique (est-ce qu'ils sont connectés ou pas, actifs ou pas, quand ont-il lu leur courrier pour la dernière fois, ...) Aujourd'hui, on utiliserait Facebook pour cela mais, dans les années 80 et 90, pour se renseigner sur un collègue ou un confrère, on se servait de finger. L'importance croissante donnée à la vie privée a petit à petit conduit au démantelement de cet utile service (remplacé, on l'a vu, par de gros silos de données qui sont bien pires, notamment parce que l'information n'est pas sous le contrôle de l'utilisateur). Finger, normalisé dans ce RFC, n'a plus aujourd'hui qu'un intérêt historique.

Je ne connais pas aujourd'hui beaucoup de serveurs finger encore en activité (mais je suis sûr que les lecteurs de mon blog vont m'en trouver plusieurs). Alors, j'en ai créé un, par nostalgie, blog@www.bortzmeyer.org. Vous pouvez utiliser un client finger comme l'outil Unix du même nom pour l'interroger. Il ne donne pas de renseignements sur une personne mais sur un service, comme le faisaient un certain nombre de serveurs finger. Ainsi, il existait un quake@geophys.washington.edu qui donnait de l'information sur les derniers tremblements de terre détectés, et un nasanews@space.mit.edu qui servait les informations de la NASA sur ses vols spatiaux. Ces deux-là ont disparu, mais les toilettes du MIT diffusent toujours des informations :

% finger @bathroom.mit.edu
Random Hall Bathroom Server v2.1

                         Bonfire Kitchen: vacant for 28 min
                         Bonfire  Lounge: vacant for 3 min
                          Pecker  Lounge: vacant for 2 hr
                          Pecker Kitchen: *IN*USE* for 16 min
   K 282  L  290 K          Clam Kitchen: vacant for 43 min
   ... ... ... ...          Clam  Lounge: *IN*USE* for 33 min
  | o : o | o : x |          BMF  Lounge: vacant for 3 min
  | o : x | o : o |          BMF Kitchen: vacant for 52 min
  | o : o | o : o |         Loop Kitchen: vacant for 75 min
  | o : x | - : o |         Loop  Lounge: vacant for 3 min
 ~~~~~~~~~~~~~~~~~~~  Black Hole  Lounge: vacant for 42 min
                      Black Hole Kitchen: vacant for 33 min
      o = vacant!        Destiny Kitchen: vacant for 2 min
      x = in use          Destiny Lounge: *IN*USE* for 33 min
                                     Foo: vacant for 17 min

For more information finger help@bathroom.mit.edu

(2146055)

Plus sérieux, le projet FreeBSD a toujours un serveur finger actif @freebsd.org donc vous pouvez vous informer sur n'importe quel commiter :


%  finger roberto@freebsd.org 
Login: roberto        			Name: Ollivier Robert
Directory: /home/roberto            	Shell: /usr/local/bin/zsh
Office: Bretigny s/Orge FRANCE		Office Phone: +33-1-69887290
No Mail.
Plan:
Home address: <roberto@keltia.net>
Work address: <ollivier.robert@eurocontrol.int>

Twitter: @Keltounet

pub  1024D/7DCAE9D3 1997-08-21 Ollivier Robert <roberto@keltia.net>
uid                            Ollivier Robert <roberto@keltia.freenix.fr>

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.2.1 (FreeBSD)

mQGiBDP8ElkRBADQrtDGMaOawsdVCxQTrtCoa+VFeSebgBgIdfrgduTTOteV+bqz
RYa94GBx3Df/LCxEtb8bgcL6DlD/B5nCjzMfwzW+JkqXDz7g96oVWW48jUIeNrYL
qBZruvcopUEmH3iBZU8ig3lpJ5/XbN+IYGP474E2rnTNfaY26E0iWkWqtQCg/wIY
...

Autre serveur finger utile, celui de météorologie qui permet d'obtenir un rapport sur n'importe quelle ville du monde (ici, Budva) :

% date
Tue Feb 16 08:31:00 CET 2016

% finger budva@graph.no
               -= Meteogram for montenegro/budva/budva~3203106 =-               
 'C                                                                   Rain (mm) 
 23                                                                   
 21   ---                                               |             9 mm 
 19                                                     |             8 mm 
 17---   ^^^      ^^^^^^                                |             7 mm 
 15         ======         =====|                       |             6 mm 
 13                     ^^^     |^^^===   ^^^         ==|             5 mm 
 11                             |      =--   ---=--===  |         ^^^ 4 mm 
  9                             |     |                 |=-----       3 mm 
  7              |           |  |     |                 |      ^^^    2 mm 
  5           |  |           |  |     |              |  |             1 mm 
   _10_13 19 01_07_13 19 01_07_13 19 01_07_13 19 01_07_13 19 01_07_13 Hour
 
    NE SE NE  S  S SW NW  N NE  E NE NW NW  W NW NE NE SW NW NW NW SW Wind dir.
     2  2  2  4  2  0  1  2  2  1  2  1  2  3  2  1  1  2  2  2  1  2 Wind(mps)

Legend left axis:   - Sunny   ^ Scattered   = Clouded   =V= Thunder   # Fog
Legend right axis:  | Rain    ! Sleet       * Snow
Mail a "thank you" to finger@falkp.no if you like the service.  

Si vous voulez installer, vous aussi, un serveur finger, je vous mets en garde : c'est un service sensible et qui peut ouvrir des failles de sécurité. Après tout, son rôle est de distribuer de l'information. Et l'information peut être utile à un méchant.

Comment fonctionne ce protocole ? Difficile de faire plus simple (section 2.1). À l'époque, le moyen le plus courant de faire un protocole d'accès à l'information était de réserver un port TCP (ici, 79), de dire au client de se connecter à ce port et d'envoyer sa question sous forme d'une simple chaîne de caractères, et de dire au serveur d'écouter sur ce port, et de répondre à question par... ce qu'il veut. De nombreux protocoles avaient été conçus ainsi, comme whois (port 43, RFC 3912) ou comme daytime (port 13, RFC 867) qui était encore plus simple (même pas de question, de la part du client). Écrire un logiciel client pour ces protocoles est trivial (exercice de première heure de la première année en réseaux) et on peut même se contenter d'un simple telnet :


% telnet www.bortzmeyer.org finger
Trying 2605:4500:2:245b::42...
Connected to www.bortzmeyer.org.
Escape character is '^]'.
blog
Debian GNU/Linux      Copyright (C) 1993-1999 Software in the Public Interest
...
Connection closed by foreign host.

Notez bien (section 2.2) que la fin de la ligne « question » doit être composée de deux caractères, CR et LF. Certains serveurs finger sont plus tolérants que d'autres si vous violez cette règle. Si on utilise netcat comme client, on va préciser ces deux caractères :

% echo -n -e "blog\r\n" | nc www.bortzmeyer.org finger

On peut aussi utiliser un client whois puisque les deux protocoles sont très proches :

% whois -h www.bortzmeyer.org -p finger blog

Et le format de la réponse ? Il n'est pas du tout défini par ce RFC (section 2.5) qui dit juste que c'est du texte libre, conçu pour être analysé par un humain et pas par un programme. (C'est exactement la même chose avec whois.)

Le RFC donne des indications sur les informations utiles à distribuer. Mais il précise aussi que la liste effective est entièrement sous le contrôle de l'administrateur système. Dans le reste de cet article, je donnerai des exemples de configuration empruntés à deux serveurs finger distribués en logiciel libre, efingerd et cfingerd. Par exemple, le RFC cite le numéro de téléphone, l'adresse, le nombre de minutes depuis la dernière activité sur cet ordinateur. Avec cfingerd, on peut décider d'afficher (signe plus) ou au contraire de ne pas activer (signe moins) l'envoi de ces informations, et on peut le faire pour les utilisateurs locaux à la machine (le second booléen) ou distants (le premier booléen). Un exemple dans le cfingerd.conf est :

CONFIG finger_display  = {
...
        +REAL_NAME              = [FALSE, TRUE],
        +DIRECTORY              = [FALSE, TRUE],
        +SHELL                  = [FALSE, TRUE],
        +ROOM_NUMBER            = [FALSE, TRUE],
        +WORK_NUMBER            = [FALSE, TRUE],
        +HOME_NUMBER            = [FALSE, TRUE],
        +LAST_TIME_ON           = [FALSE, TRUE],
        +IF_ONLINE              = [FALSE, TRUE],
        +TIME_MAIL_READ         = [FALSE, TRUE],
        +DAY_MAIL_READ          = [FALSE, TRUE],
        +ORIGINATION            = [FALSE, TRUE],
        +PLAN                   = [TRUE, TRUE],
        +PROJECT                = [TRUE, TRUE],
        +PGP                    = [TRUE, TRUE],
...

Avec efingerd, cela se configure en éditant le script shell luser qui, par défaut, utilise la commande locale finger qui peut être très bavarde (certains serveurs finger affichaient même l'expéditeur du dernier courrier reçu !). Voici un exemple :

Login: stephane       			Name: 
Directory: /home/stephane           	Shell: /usr/bin/zsh
On since Tue Sep 24 06:39 (UTC) on pts/0 from central.example.net
   1 minute 54 seconds idle
Last login Tue Sep 24 06:39 (UTC) on pts/2 from central.example.net
Mail forwarded to "| procmail -d"
New mail received Tue Sep 24 05:41 2013 (UTC)
     Unread since Tue Sep 24 13:28 2013 (UTC)
No Plan.

Notez que ces deux logiciels serveurs permettent de ne pas envoyer d'information sur un utilisateur particulier (bien que le RFC se demande à quoi cela sert de faire tourner un serveur finger dans ces conditions). Avec efingerd, c'est en éditant le script luser.

Parfois, le nom passé au serveur finger n'est pas celui d'un utilisateur humain mais celui d'un service (comme blog plus haut). La section 2.5.5 discute du cas où le service est un distributeur automatique et demande que finger renvoie la liste des produits actuellement disponibles dans la machine...

Une technique courante était de permettre aux utilisateurs de mettre un fichier nommé .plan dans leur répertoire maison. Ce fichier était alors envoyé après la réponse finger et contenait des informations supplémentaires comme une clé PGP. Les serveurs modernes permettent également aux utilisateurs de mettre un programme (et pas un simple fichier texte) dont le résultat sera envoyé au client finger. Inutile de décrire les risques de sécurité que cela entraine (section 3.2.5)...

finger offrait une autre possibilité : avoir la liste de tous les utilisateurs actuellement connectés, en indiquant une question vide. Donc, la commande finger @machine-distante (sans nom devant le @) donnait la liste de qui était branché. Particulièrement indiscrète, cette possibilité (qui n'avait en outre de sens que pour les grosses machines multi-utilisateurs) a été la première à disparaître (éditer le script nouser pour efingerd et option SYSTEM_LIST pour cfingerd).

À noter qu'il existe d'autres serveurs finger que ceux cités, par exemple IcculusFinger qui en prime est disponible sur le site de l'auteur :

% finger ryan@icculus.org 
IcculusFinger v2.1.24


                              /Nothing to report./

--------------------------------------------------------------------
.plan archives for this user: finger ryan?listarchives=1@icculus.org
Powered by IcculusFinger v2.1.24 (http://icculus.org/IcculusFinger/)
Stick it in the camel and go.

Et la sécurité ? Absente du premier RFC, le RFC 742, elle est au contraire très présente dans ce RFC 1288, notamment en section 3. Il y a plusieurs aspects. D'abord, la sécurité de la mise en œuvre du serveur finger, qui fut illustrée par le ver de Morris. Notons que ce n'était pas un problème spécifique au protocole finger : tout serveur réseau devrait être programmé de manière défensive, de façon à ne pas être vulnérable lorsque le client envoie des données inattendues (très longues, par exemple). Ne pas avoir de serveur finger aujourd'hui, à cause d'une faille de sécurité d'un logiciel qui n'est plus utilisé depuis longtemps, est donc idiot.

Mais finger a évidemment un autre problème, déjà cité, vis-à-vis de la vie privée. On n'a pas forcément envie que n'importe qui sur l'Internet soit au courant de ses heures de présence au bureau ou du rythme auquel on reçoit du courrier. C'est pourquoi le RFC exige qu'on puisse ajuster l'information présentée (cfingerd fournit un contrôle très fin dans son fichier de configuration, efingerd vous laisse programmer ce que vous voulez dans les scripts qu'il exécute).

Si vous avez un serveur finger et que vous voulez le superviser depuis Icinga, cela peut se faire avec la configuration :

define service{
        use   generic-service
        host_name            MonServeur
        service_description       Finger
        check_command             check_finger!utilisateur!chaîne à chercher
}

Elle lèvera une alarme si le texte chaîne à chercher n'apparait pas dans la réponse du serveur. La commande check_finger est définie ainsi :

define command {
        command_name    check_finger
        command_line    /usr/local/share/nagios/libexec/check_finger $HOSTADDRESS$ $ARG1$ $ARG2$ $ARG3$
        }

Et le script check_finger (inspiré d'un équivalent pour whois) est disponible ici.

Notre RFC succède au RFC 1196 et le premier RFC sur finger était le RFC 742. Comme beaucoup de protocoles Internet, finger a d'abord été mis en œuvre (parfois sous le nom de « Name » et pas « Finger »), puis normalisé. La section 1.2 du RFC résume une longue et glorieuse histoire. Le RFC note que la norme actuelle est fondée avant tout sur le comportement du serveur finger d'Unix BSD. Par rapport à son prédécesseur, le RFC 1196, on note surtout une définition plus rigoureuse : le RFC 1196 était souvent très vague. Aujourd'hui, on l'a vu, finger est une survivance du passé, mais le standard IETF de récupération d'information sur une entité, WebFinger (RFC 7033), lui rend hommage par son nom. Autre idée inspirée de finger (et l'utilisant), le réseau social expérimental Thimbl. Comme le dit un contributeur d'Une contre-histoire des Internets, « Je me souviens de finger, seul service interrogeable qui indiquait les services accessibles sur un host »...


Téléchargez le RFC 1288


L'article seul

RFC 1213: Management Information Base for Network Management of TCP/IP-based internets:MIB-II

Date de publication du RFC : Mars 1991
Auteur(s) du RFC : Keith McCloghrie (Hughes, LAN Systems), Marshall T. Rose (Performance Systems International)
Chemin des normes
Première rédaction de cet article le 29 novembre 2007


Un des RFC les plus anciens encore en service, la normalisation de la célèbre MIB-II, la base des données qui peuvent être récoltées avec le protocole de gestion de réseaux SNMP.

La MIB-II est la plus connue et la base de toutes les autres MIB (elle succède à la MIB-I, décrite dans le RFC 1156). Elle décrit un modèle de données, pas un protocole. Ces données sont accessibles par les différentes versions du protocole SNMP, elle donne accès à sept groupes d'informations, comme System ou IP. Ce RFC est donc surtout composé d'une longue liste de variables (objets), selon les principes communs à toutes les MIB, décrits dans le RFC 1155.

Physiquement, une MIB est (section 4) une description en langage ASN.1 des données présentes, avec leur syntaxe, une indication de leur identificateur (l'OID), une description en langue naturelle, etc. Les commandes comme snmpget affichent par défaut les noms des variables mais on peut afficher les OID avec l'option -On. Les OID de MIB-II démarrent à 1.3.6.1.2.1. Par exemple, la définition de la variable ifNumber (nombre d'interfaces réseaux de la machine) est :

          ifNumber OBJECT-TYPE
              SYNTAX  INTEGER
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                      "The number of network interfaces (regardless of
                      their current state) present on this system."
              ::= { interfaces 1 }

Son OID étant { interfaces 1 } et celui de interfaces, défini un peu plus haut, étant { mib-2 2 }, on voit que l'OID de ifNumber est 1.3.6.1.2.1.2.1.0 (le zéro final est une valeur nécessaire pour les scalaires, avec SNMP). snmpget peut donc la récupérer :

% snmpget [options] myrouter 1.3.6.1.2.1.2.1.0
IF-MIB::ifNumber.0 = INTEGER: 2

Si la variable est un tableau, c'est un peu plus compliqué, il faut ajouter à l'OID un index. Par exemple, les interfaces ont une variable ifOperStatus qui indique si elles fonctionnent ou pas (ifAdminStatus indique l'état désiré de l'interface, ifOperStatus son état réel ; la comparaison des deux est donc un bon moyen de savoir si toutes les interfaces fonctionnent comme prévu). Cete variable est définie dans notre RFC ainsi :

          ifOperStatus OBJECT-TYPE
              SYNTAX  INTEGER {
                          up(1),       -- ready to pass packets
                          down(2),
                          testing(3)   -- in some test mode
                      }
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                      "The current operational state of the interface.
                      The testing(3) state indicates that no operational
                      packets can be passed."
              ::= { ifEntry 8 }
% snmpget [options] myrouter 1.3.6.1.2.1.2.2.1.8.1
IF-MIB::ifOperStatus.1 = INTEGER: up(1)                                      

Voici enfin, affichée par snmpwalk, une partie de la MIB-II d'un commutateur réseau de bas de gamme. D'abord, le groupe System (section 3.4), qui décrit l'engin lui-même, par exemple sa description :

SNMPv2-MIB::sysDescr.0 = STRING: 24-Port Managed 10/100 Switch w/WebView
SNMPv2-MIB::sysLocation.0 = STRING: UVA
...

puis le groupe Interfaces qui décrit les interfaces de l'engin :

IF-MIB::ifNumber.0 = INTEGER: 37
...
IF-MIB::ifDescr.1 = STRING: Ethernet Interface
...
IF-MIB::ifType.1 = INTEGER: ethernetCsmacd(6)
...
IF-MIB::ifMtu.1 = INTEGER: 1500
...
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
...
IF-MIB::ifInOctets.1 = Counter32: 188864

Ce dernier compteur, ifInOctets est un exemple des variables que récoltent les programmes de surveillance de réseau comme le célèbre MRTG ou comme le plus récent Munin.

Les groupes ultérieurs comme IP, ou TCP sont moins pertinents pour un commutateur, car ils ne comptent que les paquets qui lui sont directement adressés.


Téléchargez le RFC 1213


L'article seul

RFC 1191: Path MTU discovery

Date de publication du RFC : Novembre 1990
Auteur(s) du RFC : Jeffrey Mogul (Digital Equipment Corporation (DEC) , Western Research Laboratory), Steve Deering (Xerox Palo Alto Research Center)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 20 mai 2007


Ce RFC fut le premier à proposer une méthode pour déterminer la MTU disponible entre deux nœuds de l'Internet.

Une telle détermination sert à beaucoup de choses mais notamment à éviter la fragmentation en envoyant des paquets qui pourront arriver à destination « tels quels ». La fragmentation réduisant le débit, il est souhaitable de l'éviter dès le début. On peut lire à ce sujet Raising the Internet MTU qui décrit en détail pourquoi il serait bon d'augmenter les MTU. (Et, pour un point de vue plus sceptique, l'excellent article de Simon Leinen).

En attendant, qu'elle que soit la MTU, il est préférable de la déterminer dès la source des paquets, plutôt que de compter sur les routeurs ultérieurs pour fragmenter (en IPv6, c'est même obligatoire, les routeurs n'ayant pas le droit de fragmenter).

L'algorithme proposé par notre RFC est le suivant : envoyer des paquets avec le bit DF (Don't fragment) mis et voir si on reçoit des paquets ICMP Datagram too big qui contiennent en général la MTU maximale du lien suivant. Voici, vu par tcpdump, un de ces paquets ICMP, indiquant que le lien suivant ne peut faire passer que 1492 octets d'un coup :

11:10:23.474673 IP 172.19.1.1 > 172.19.1.2: icmp 556: 192.134.4.69 unreachable - need to frag (mtu 1492)

On recommence avec la nouvelle taille jusqu'à ce que le paquet atteigne sa destination. On apprend ainsi la MTU maximale du lien (c'est la plus petite MTU de tous les liens intermédiaires) et on peut ensuite utiliser des paquets de la taille optimale.

Sur le papier, la méthode est imparable. Mais, en pratique, il est fréquent qu'elle ne marche pas. Beaucoup de sites, en effet, filtrent stupidement tous les paquets ICMP et la machine qui tente de faire de la Path MTU discovery n'aura jamais de réponse.

Aujourd'hui, on doit donc plutôt utiliser des bricolages comme le MSS clamping qui consiste à modifier sauvagement la MSS des paquets TCP. Le clamping est décrit par exemple en http://www.netbsd.org/Documentation/network/pppoe/#clamping, pour NetBSD. Avec Linux, on peut utiliser la technique décrite en http://www.linux.com/howtos/Adv-Routing-HOWTO/lartc.cookbook.mtu-mss.shtml ou bien l'option -m du programme pppoe. Par exemple, pour ma connexion ADSL, mon fichier /etc/ppp/peers/monFAI contient pppoe -I eth1 -T 80 -m 1412 pour « clamper » le MSS de TCP à 1412 octets.

Le MSS clamping ne fonctionne qu'avec TCP. Une autre solution, sur un réseau local qui ne peut pas faire sortir des paquets de 1500 octets (par exemple car il est connecté à Internet avec PPPoE) est de changer la MTU sur toutes les machines du réseau (commande ifconfig sur Unix).

Mais une autre approche est possible depuis peu : le RFC 4821 décrit un moyen de découvrir la MTU maximale sans dépendre des paquets ICMP. Il reste donc à voir s'il sera largement déployé.


Téléchargez le RFC 1191


L'article seul

RFC 1155: Structure and identification of management information for TCP/IP-based internets

Date de publication du RFC : Mai 1990
Auteur(s) du RFC : Marshall T. Rose (Performance Systems International, Inc.), Keith McCloghrie (Hughes LAN Systems, The Wollongong Group)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 18 février 2010


Ce RFC a été pendant longtemps la référence pour la description d'informations gérées sur un réseau. Le SMI est le cadre général, dans ce cadre on écrit des MIB, on les interroge avec SNMP (RFC 1157) et voilà la gestion de l'Internet. Aujourd'hui, la dernière norme sur le SMI est la version 2, décrite dans le RFC 2578 mais notre RFC 1155 est toujours en statut standard (numéro 16) et toujours d'actualité puisque toutes les MIB n'ont pas été mises à jour (c'est le cas de la MIB-II, la MIB de base, normalisée dans le RFC 1213, même si elle a connu des évolutions comme celle du RFC 2863).

Notre RFC décrit donc le SMI, le cadre de base de la description d'informations qu'on gère, typiquement avec SNMP (à l'époque où a été fait notre RFC, il était encore obligatoire de citer CMIP, le concurrent ISO qui n'a jamais connu de déploiement significatif). Il y a longtemps que la ligne officielle de l'IAB est que tout protocole Internet soit gérable, et aie donc une MIB, écrite selon les règles du SMI (section 1).

La section 2 donne les principes du SMI : séparation de la description des objets et du protocole d'accès (c'était nécessaire à l'époque, pour les raisons politiciennes qu'explique bien l'un des auteurs du RFC 1155, Marshall Rose, dans son livre The Simple Book), et utilisation d'un sous-ensemble de ASN.1 pour décrire les classes d'objets gérés.

Un autre principe important, est celui de la simplicité. Bien qu'on puisse se demander s'il est vraiment atteint, il faut se rappeler que les propositions concurrentes, à l'époque, étaient bien pires. Le RFC note avec modestie qu'on ne sait pas encore bien maitriser la gestion des réseaux et qu'il faut donc éviter de tout figer par des normes trop strictes (et, effectivement, en 2010, la question est toujours ouverte, comme le montre le RFC 5706). De même, le SMI se veut extensible, car tout ne peut pas être prévu à l'avance

Et, pour ceux qui s'intéressent à l'histoire, outre l'excellent livre de Rose déjà cité, il y a les RFC 1052 et RFC 1109.

Avec la section 3, on en arrive au concret : qu'est-ce qu'une MIB et qu'est-ce qu'on met dedans ? La MIB, écrite en ASN.1, rassemble des objets qui ont tous un nom, plus exactement un OBJECT IDENTIFIER (OID, section 3.1). Ce nom est une suite de chiffres, alloués hiérarchiquement (ce qui garantit l'unicité). Certains de ces chiffres ont aussi parfois une étiquette en lettres. Ainsi, le nœud 1 est étiquetté iso et géré par l'ISO. Tous les objets Internet sont sous le sous-arbre 1.3.6.1 (3 étant alloué par l'ISO à d'autres organisations et 6 étant le DoD qui financait le projet, 1 revenant à l'IAB). En ASN.1, cela se dit :

internet    OBJECT IDENTIFIER ::= { iso(1) org(3) dod(6) 1 }

et les objets officiels sont sous le sous-arbre 1.3.6.1.2. La MIB-II du RFC 1213 est ainsi 1.3.6.1.2.1. Pour prendre un exemple d'objet, ifOperStatus, l'état effectif d'une interface réseau (par exemple une carte Ethernet) est { ifEntry 8 }, c'est-à-dire 1.3.6.1.2.1.2.2.1.8 puisque ifEntry était 1.3.6.1.2.1.2.2.1 (il faut se rappeler qu'une MIB est arborescente). Chaque interface réseau recevra ensuite un OBJECT IDENTIFIER à elle, 1.3.6.1.2.1.2.2.1.8.1, 1.3.6.1.2.1.2.2.1.8.1, etc. Voici un exemple vu avec snmpwalk (-O n lui dit d'afficher les OID, pas les étiquettes), sur une machine qui a quatre interfaces réseaux dont deux fonctionnent :

% snmpwalk -v 1  -O n -c tressecret 192.0.2.68 1.3.6.1.2.1.2.2.1.8
.1.3.6.1.2.1.2.2.1.8.1 = INTEGER: up(1)
.1.3.6.1.2.1.2.2.1.8.2 = INTEGER: up(1)
.1.3.6.1.2.1.2.2.1.8.3 = INTEGER: down(2)
.1.3.6.1.2.1.2.2.1.8.4 = INTEGER: down(2)

Sans -O n, on aurait eu :

% snmpwalk -v 1   -c tressecret 192.0.2.68 1.3.6.1.2.1.2.2.1.8
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)
IF-MIB::ifOperStatus.3 = INTEGER: down(2)
IF-MIB::ifOperStatus.4 = INTEGER: down(2)

Si 1.3.6.1.2 désigne les objets « officiels », 1.3.6.1.3 (section 3.1.3 du RFC) est pour les expérimentations et 1.3.6.1.4 pour les objets privés et 1.3.6.1.4.1 pour les objets spécifiques à une entreprise (section 3.1.4 du RFC). Par exemple, si Netaktiv a obtenu le numéro 9319, ses objets seront sous 1.3.6.1.4.1.9319.

L'objet a aussi une syntaxe (section 3., par exemple INTEGER, OCTET STRING, OBJECT IDENTIFIER ou NULL. C'est un sous-ensemble d'ASN.1 qui est utilisé pour bâtir des définitions à partir de ces types primitifs, en les organisant en séquences ou en tables (section 3.2.2). Par exemple, l'état d'une interface réseau, ifOperStatus, déjà cité, est défini par le RFC 1213 comme INTEGER. Voici la définition complète :

          ifOperStatus OBJECT-TYPE
              SYNTAX  INTEGER {
                          up(1),       -- ready to pass packets
                          down(2),
                          testing(3)   -- in some test mode
                      }
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                      "The current operational state of the interface.
                      The testing(3) state indicates that no operational
                      packets can be passed."
              ::= { ifEntry 8 }

Notre RFC définit aussi des types à partir de ces types primitifs, types qui pourront être utilisés par toutes les MIB. C'est le cas de :

  • IpAddress (section 3.2.3.2), une OCTET STRING de quatre octets (IPv6 n'était pas encore inventé),
  • Counter (section 3.2.3.3), un entier positif sur 32 bits, croissant de manière monotone modulu sa valeur maximale. Si 32 bits semblaient à l'époque permettre des valeurs énormes, c'est aujourd'hui bien trop petit. Pour une interface Ethernet 10G, le Counter ifInOctets peut atteindre sa valeur maximale en seulement trois secondes !
  • Gauge (section 3.2.3.4) qui, contrairement à Counter, peut monter et descendre.

Un objet a enfin un encodage sur le câble (section 3.3) car ASN.1 ne spécifie pas comment les objets doivent être sérialisés en bits. Le SMI utilise BER.

La section 4 donne les informations qui doivent être indiquées lors de la définition d'une classe d'objets (comme ifOperStatus plus haut) : OID, bien sûr mais aussi accès (lecture seule ou bien aussi écriture), description en langage naturel, etc (la syntaxe formelle est en section 4.3). Cette section est mieux résumée par un exemple, ici tirée d'une expérience avortée, le RFC 1414 :

         identOpSys OBJECT-TYPE
                  SYNTAX  OCTET STRING (SIZE(0..40))
                  ACCESS  read-only
                  STATUS  mandatory
                  DESCRIPTION
                      "Indicates the type of operating system in use.
                      In addition to identifying an operating system,
                      each assignment made for this purpose also
                      (implicitly) identifies the textual format and
                      maximum size of the corresponding identUserid and
                      identMisc objects.

                      The legal values for the `indentOpSys' strings
                      are those listed in the SYSTEM NAMES section of
                      the most recent edition of the ASSIGNED NUMBERS
                      RFC [8]."
                  ::= { identEntry 2 }

Toutes les définitions de ce RFC, en ASN.1, sont rassemblées dans la section 6.

Tiens, Google m'a retrouvé le premier programme significatif que j'avais fait avec SNMP, en 1993 : http://www.cpan.org/scripts/netstuff/addresses.on.the.LAN.info. Ne me demandez pas les sources, ils semblent avoir été perdus.


Téléchargez le RFC 1155


L'article seul

RFC 1144: Compressing TCP/IP headers for low-speed serial links

Date de publication du RFC : Février 1990
Auteur(s) du RFC : Van Jacobson (Lawrence Berkeley Laboratory)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 26 septembre 2010


Ce RFC n'est sans doute plus utilisé nulle part aujourd'hui mais, pendant des années, presque toutes les connexions à l'Internet depuis la maison (et, souvent, depuis le bureau), passaient par un lent modem, ce qui justifiait des efforts important pour comprimer les paquets, notamment (et c'était le but de de ce RFC), les en-têtes IP et TCP en profitant des diverses redondances qu'ils contiennent. La « compression Van Jacobson » (on voyait parfois dans les documentations « VJ compression »), documentée dans ce RFC, était un outil indispensable si on voulait pouvoir utiliser son modem de manière satisfaisante.

Contrairement à beaucoup de RFC de la grande époque, il est long (49 pages) car il y a beaucoup de détails techniques à spécifier (et il y a du code C à la fin). Comme plusieurs RFC de ce temps, il existe également en version PostScript, en http://www.rfc-editor.org/rfc/rfc1144.ps. Cette version est plus jolie et est donc recommandée pour la lecture de ce document difficile. Elle a en outre l'avantage de permettre l'inclusion de graphiques, comme la figure 8 qui indique le débit réel en fonction de la MTU.

La section 1 du RFC rappelle le contexte... de l'époque (1990). Des ordinateurs chez les particuliers (enfin, chez les plus riches), un Internet qui, certes, ne figurait pas sur l'écran radar des décideurs et des journalistes (surtout en France où l'Internet était mal vu et où il n'y en avait que pour le Minitel qui, contrairement aux techniques comme SLIP (RFC 1055) utilisées pour l'Internet sur modems, avait un débit asymétrique), des modems allant de 300 b/s (modems acoustiques) à 19 200 b/s (le record - non normalisé - de la norme V.32). Il existait avant ce RFC d'autres techniques de compression d'en-têtes (RFC 914) mais celle-ci était plus performante. À noter que le protocole « Van Jacobson » est spécifique à TCP, car il dépend du format d'en-tête de TCP, et de plusieurs fonctions de TCP, comme la réémission des paquets perdus, qui a permis de mettre aucune fonction de correction d'erreur. (Le RFC 2508 a proposé une méthode pour les autres protocoles de transport.)

Quel était le problème lorsqu'on se connectait à l'Internet via un modem, en utilisant des protocoles comme SLIP ? (PPP sera normalisé quelques mois plus tard, dans le RFC 1172, mais mettra très longtemps à être déployé.) Le problème, expliqué dans la section 2 du RFC, est que des applications interactives (telnet, à l'époque) et des applications transférant des données en bloc (NNTP, SMTP et FTP à l'époque) coexistent sur le câble et que les premières, qui exigent un bon temps de réponse, souffrent de la taille excessive des en-têtes (excessive par rapport au contenu « utile »). Si on se fixe un objectif (raisonnable pour une application interactive) de 100 à 200 ms de délai, on voit qu'un paquet TCP complet, avec ses en-têtes, est trop gros (sur le format des en-têtes, cf. RFC 791, section 3.1, pour IP et RFC 793, section 3.1, pour TCP). Le paquet fait 41 octets pour un seul caractère transmis (et autant pour l'écho effectué par le shell distant), ce qui nécessiterait 4 kb/s pour être transmis en moins de 200 ms. Même pour un modem de ce débit, si un transfert de données est en cours en même temps, les paquets de telnet peuvent avoir besoin d'attendre que la ligne soit libérée. Cela interdit de faire des paquets de données trop gros (ils bloqueraient la ligne pendant plus de 200 ms) et donc la taille relative des en-têtes est aussi un problème pour eux. Le cahier du charge du RFC était donc de permettre de faire du telnet sur des modems à 300 b/s. Un humain tapant environ cinq caractères par seconde impose au maximum cinq octets d'en-tête, ce qui permettrait de réduire la taille des paquets de transfert de données et donc de résoudre deux problèmes d'un coup.

Le protocole lui-même figure en section 3. Il n'est pas évident de comprimer les en-têtes IP et TCP. Contrairement aux protocoles OSI, chaque champ a une utilité et ne peut pas être simplement omis. En revanche, certains de ces champs sont constants au cours d'une même connexion TCP et certains évoluent de manière prédictible. Si les deux parties de la connexion gardent en mémoire l'état de celle-ci, il leur suffit de transmettre avec chaque paquet l'identificateur de la connexion et les champs qui ont changé de façon imprévue. Tout le reste peut être reconstitué localement. C'est sur cette observation que repose l'algorithme Van Jacobson. Après, il ne reste plus qu'à identifier un par un, pour chaque champ, s'il est constant, s'il change de manière prévisible, ou bien s'il peut être déduit de l'information données par d'autres couches (par exemple, le champ Total Length de l'en-tête IP est souvent doublé par une fonction de la couche 2 qui indique la même information). Comme exemple de champ qui change de manière prédictible, on peut citer les numéros de séquence TCP, qui s'incrémentent avec le nombre d'octets envoyés. À noter que toutes les informations vont du compresseur vers le décompresseur : il n'y a pas de rétroaction dans le protocole VJ.

Les détails pratiques figurent en section 3.2. Par exemple, 3.2.2 indique le format du paquet comprimé, 3.2.3 les actions du compresseur et 3.2.4 le mécanisme que doit suivre le décompresseur. Ce dernier doit appliquer aveuglément son algorithme, il ne peut pas demander confirmation ou éclaircissements au compresseur. Il existe quatre types de paquets :

  • TYPE_ERROR : la couche 2 indique que le paquet a été mal reçu. Le décompresseur le jette et compte sur le TCP à l'autre bout pour réémettre.
  • TYPE_IP : un paquet IP non-TCP, non modifié. L'algorithme VJ ne les comprime pas et le décompresseur n'a donc rien à faire.
  • UNCOMPRESSED_TCP (identifié par le champ « Protocole » de IP, normalement à 6 - pour TCP - et qui est ici l'index d'une connexion) : la connexion TCP en question vient juste de commencer ou bien un problème s'est produit, nécessitant une remise à zéro de l'état du compresseur. En recevant ce paquet, le décompresseur doit mettre à jour son état, enregistrer l'index de la connexion et les valeurs des en-têtes.
  • Autrement, le paquet est de type COMPRESSED_TCP et le décompresseur a alors le plus de travail à faire, puisqu'il doit reconstituer le paquet TCP complet (en regardant les valeurs qui avait été stockées pour cet index) qu'il passera au TCP local.

Tout cela, c'est très joli, si tout se passe bien. Mais s'il y a une erreur ? C'est fréquent avec les modems... La section 4 couvre ce problème. D'abord, il faut détecter l'erreur. Le principe de la compression étant de supprimer la redondance, la détection d'erreur, typiquement basée sur une information redondante, devient difficile. N'importe quel bruit aléatoire sur la ligne peut être « décompressé » en un paquet TCP/IP valide. La somme de contrôle, trop courte, n'est pas une protection suffisante : sur une ligne à 9 600 b/s, un parasite de 400 µs (ce qui est très court) va corrompre 16 bits, ce que la somme de contrôle va probablement rater. Le protocole VJ dépend donc essentiellement de la détection d'erreur de la couche 2. Un autre cas où un protocole fondé sur une rétroaction du décompresseur vers le compresseur ne marcherait pas est le cas où le paquet serait totalement détruit : le décompresseur ne peut alors même pas savoir qu'il y a eu un problème. Dans ce cas, c'est TCP qui détectera l'erreur, en ne recevant pas d'accusé de réception.

Une fois l'erreur détectée par le décompresseur, comment la rattraper (section 4.2) ? Le compresseur a la responsabilité d'envoyer un paquet UNCOMPRESSED_TCP pour signaler au décompresseur qu'il doit se resynchroniser. Comment le compresseur sait-il, lui, qu'un paquet est mal arrivé, ou pas arrivé du tout ? Il observe simplement les paquets TCP : si le numéro de séquence n'augmente pas (à part quelques cas spéciaux que le compresseur doit reconnaitre), c'est qu'il y a retransmission, et que des paquets ont été perdus. Le compresseur sait alors qu'il doit envoyer un paquet non comprimé. Le recevant, le décompresseur saura qu'il y a eu un problème et commencera un contexte neuf.

Le protocole VJ permet-il de configurer certains de ses paramètres ? Comme l'explique la section 5, il n'y en a pas beaucoup, car il n'y a pas de moyen de les transmettre entre les deux parties. Les deux paramètres possibles sont « compression activée ou pas » et nombre de contextes (de flux TCP simultanés) à conserver. Le premier paramètre (activer ou pas la compression VJ) ne se négocie pas, il doit donc être configuré de manière identique des deux côtés. À l'époque, c'était une source d'ennuis fréquents, qui se terminait souvent par « on va essayer avec et sans VJ et on verra bien lequel marche ». Le second paramètre est fixé à 16, avec juste une exception pour le changer si le protocole de couche 2,5 fournit un moyen pour cela (SLIP n'en fournit pas).

Quels sont les résultats obtenus effectivement par la compression VJ ? La section 5.3, très détaillée, fait la comparaison entre la compression VJ et une compression générique (Lempel-Ziv) appliquée à tout le paquet. Pour du trafic interactif (telnet), VJ l'emporte d'un facteur 3. Pour du trafic de données (FTP), c'est le contraire. La section 6 revient sur les performances du compresseur et mesure le temps pris sur les machines typiques de l'époque (Sun 3/60 ou DECstation 3100). La plupart des machines récentes (pour l'époque !) arrivaient à comprimer et à décomprimer à 64 kb/s (ce qui permettait même d'utiliser la compression VJ pour le RNIS).

Pour les programmeurs en C, l'annexe A fournit une mise en œuvre complète de l'algorithme, documentée très en détail (avec même un petit réglement de compte contre les machines qui osaient être petit-boutiennes comme le Vax). Elle était distribuée à l'époque dans CSLIP (mise en œuvre de SLIP avec compression). Une copie complète du code se trouve en ftp://ftp.ee.lbl.gov/cslip.tar.Z, à l'endroit exact indiqué par le RFC il y a vingt ans ! Bel existence de persistence d'URL ! (Par contre, l'adresse IP, indiquée dans le RFC, a changé, bon exemple du fait que les noms de domaine fournissent de la permanence et pas de la convivialité.)

Avec PPP, la compression VJ peut être négociée en toute sécurité (cf. RFC 1332, section 4). En revanche, SLIP n'ayant pas de mécanisme de négociation. L'annexe B suggère donc une méthode pour détecter automatiquement, à l'une des extrémités d'une liaison SLIP, si l'autre extrémité est en train de comprimer avec l'algorithme VJ. Cela permet, par exemple, d'avoir un « serveur » SLIP qui s'adapte automatiquement à des clients différents.

Aujourd'hui, l'algorithme VJ n'est plus utilisé. Des techniques plus perfectionnées l'ont remplacé, notamment ROHC (RFC 5795). Mais, pendant de nombreuses années, la plupart des connexions à la maison, ou dans des sites éloignées qui n'avaient pas d'autre liaison que le vieux réseau téléphonique, passaient par cet algorithme.

Et merci à Ludovic Rousseau, Pierre-Yves Lochou et Laurent Chemla pour m'avoir aidé lors de mes débuts avec la compression VJ !


Téléchargez le RFC 1144


L'article seul

RFC 1123: Requirements for Internet Hosts - Application and Support

Date de publication du RFC : Octobre 1989
Auteur(s) du RFC : Robert Braden (University of Southern California (USC), Information Sciences Institute)
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 5 décembre 2007


À une époque, il semblait encore possible de résumer dans un RFC tout ce que devait savoir le développeur de services réseaux. Ce n'est évidemment plus le cas, néanmoins, ce RFC, qui synthétise les règles que doivent respecter les machines non-routeuses reste utile, certaines des règles qu'il pose étant toujours d'actualité.

Un problème classique de l'implémenteur est le nombre de RFC à lire, et le risque de ne plus pouvoir distinguer les choses importantes des détails, au milieu de toutes ces normes. D'où l'idée de résumer les « choses importantes » dans des RFC de synthèse comme le RFC 1812 pour les routeurs ou comme deux RFC, le RFC 1122 et le nôtre, qui couvrent les machines non-routeuses (host en anglais, parfois traduit par terminal, qui est un terme que je trouve trop marqué par l'époque des mainframes et du Minitel). Le RFC 1122 couvre les couches basses et le 1123 les couches hautes. C'est un des plus vieux RFC encore en service. À l'époque (1989), les médias et les experts officiels n'avaient pas encore découvert l'Internet mais celui-ci était déjà suffisamment complexe pour que la section 1.2.1 s'inquiète de l'« énorme croissance de l'Internet » et des problèmes qu'elle pose.

Comme le note la section 1, de tels RFC de synthèse sont normalement inutiles. « Une mise en œuvre de bonne foi, faite en lisant soigneusement les RFC, ainsi qu'en suivant les activités de la communauté technique et des bons principes d'ingéniérie, ne devrait se différencier des demandes de ce RFC que de manière mineure. » Mais la pratique ne suivant pas toujours la théorie, et des mises en œuvre des protocoles Internet s'étant avérées très boguées, la réalisation d'un RFC de rappel a semblé une bonne idée. En revanche, la mise à jour régulière de ce RFC, promise en section 1, ne s'est jamais concrétisée, même s'il y a eu des mises à jour partielles, comme les RFC 1349 ou RFC 2181.

La partie la plus souvent citée de notre RFC est certainement la section 2.1 Host names and numbers, qui normalise la syntaxe pour les noms de machines sur Internet. Cette syntaxe est limitée à LDH (Letters - Digits - Hyphen) c'est-à-dire un sous-ensemble d'ASCII limité aux lettres de A à Z, aux chiffres et au tiret. Contrairement à ce qu'on lit souvent sous la plume d'ignorants, cette limite n'a rien à voir avec le DNS, qui était une invention récente à l'époque de notre RFC. Cette limite plonge au contraire ses racines dans des normes plus anciennes, comme le RFC 952 qui était même encore plus strict (le nom ne pouvait pas commencer par un chiffre). Ainsi, les règles pour les noms de machines ne sont pas les mêmes que pour un nom de domaine. C'est pour cela qu'il a fallu développer IDN (RFC 3490), pas à cause d'une soi-disant limite du DNS.

La section 1.2.2 rappelle un de ces « bons principes d'ingéniérie », la fameuse phrase « Soyez prudents dans ce que vous envoyez et ouverts dans ce que vous recevez » (« Be liberal in what you accept, and conservative in what you send », déjà présente dans le RFC 791).

Voyons maintenant les autres parties, moins célèbres, de ce RFC.

Sur certains points, les changements dans l'Internet ont été positifs. C'est ainsi que la section 1.2.4 déplorait que l'auto-configuration des machines connectés était toujours aussi utopique, alors que depuis, notamment grâce à DHCP (RFC 2131), elle est devenue une réalité.

Par contre, d'autres fonctions, sur lesquelles on fondait beaucoup d'espoirs, n'ont jamais vraiment pris. Ainsi, la section 2.4 mentionne les TOS d'IPv4, que peu d'applications utilisent et que beaucoup de routeurs ou de coupe-feux bloquent. (Petite publicité personnelle : echoping permet de définir ces valeurs TOS, avec l'option -P.)

La section 3 est consacrée au protocole telnet, qui devrait logiquement être abandonné aujourd'hui, remplacé par SSH.

La section 4 concerne le transfert de fichiers, qui à l'époque se faisait uniquement avec FTP. Il est toujours utilisé aujourd'hui, mais HTTP (RFC 2616) et SCP ont diminué son importance.

La section 5 parle du courrier électronique mais on ne recommande pas sa lecture, les normes et, encore plus, la réalité ayant beaucoup évolué depuis (les textes à jour sont les RFC 2821 et RFC 2822).

La section 6.1 détaille les interactions avec les systèmes de résolution de noms. Elle n'est pas limitée au DNS, loin de là, la section 6.1.3.8 expliquant la possibilité d'utiliser également un fichier local (/etc/hosts sur Unix) et de configurer quel mécanisme de résolution est utilisé (/etc/host.conf sur Unix).

La 6.1.4, elle, mentionne les listes de domaines dans lesquels chercher un nom (fonction mise en œuvre avec la directive search dans le /etc/resolv.conf des machines Unix). La publication du RFC en 1989 n'a pas empêché Verisign de déposer un brevet en 2003 (6,560,634) sur cette fonction. Et l'office états-unien des brevets l'a accepté (les offices des brevets acceptent tout et n'importe quoi ; ils n'ont ni la compétence, ni l'envie de chercher des précédents, puisque leurs revenus dépendent des dépôts).

La section 6.2 concerne la gestion des machines, à une époque où le protocole SNMP était très récent.


Téléchargez le RFC 1123


L'article seul

RFC 1122: Requirements for Internet Hosts - Communication Layers

Date de publication du RFC : Octobre 1989
Auteur(s) du RFC : Robert Braden (University of Southern California (USC)/ Information Sciences Institute (ISI))
Chemin des normes
Première rédaction de cet article le 2 juillet 2009


Compagnon du RFC 1123, ce document normalise ce que toute machine terminale (host, par opposition à routeur) connectée à l'Internet devrait savoir. Le RFC 1123 fixait les règles des « couches hautes » (notamment la couche application), notre RFC s'attaque aux « couches basses », notamment réseau et transport). Il a depuis été partiellement mis à jour par le RFC 9293.

Le résultat est un document épais (116 pages), décrivant en détail tout ce qu'IP et TCP doivent faire sur une machine terminale (les routeurs sont, eux, traités dans le RFC 1812). La section 1.4 note que les discussions sur ce RFC avaient duré dix-huit mois et généré trois méga-octets de courrier, ce qui était considérable à l'époque mais est moins qu'un document MS-Word d'une page d'aujourd'hui.

Ce RFC n'avait pas pour but de changer les normes existantes (comme le RFC 791 pour IPv4 ou RFC 793 pour TCP) mais de les résumer et les préciser. Comme le note la section 1, « une mise en œuvre de bonne foi des protocoles TCP/IP, faite en lisant les normes, ne doit différer de ce RFC 1122 que par des détails ».

Aujourd'hui, plusieurs de ses sections sont bien dépassées mais il reste la norme officielle, personne n'a eu le courage de mettre ce travail à jour.

Il n'est donc pas possible de résumer tout le RFC et j'ai donc sélectionné arbitrairement quelques points qui me semblaient intéressants.

La section 1.1 rappelle l'architecture de l'Internet et la section 1.1.1 revient sur la notion de machine terminale (host dans le RFC). La section 1.1.2 note notamment que :

  • L'Internet est un réseau de réseaux. Une machine terminale ne se connecte donc pas réellement à l'Internet, elle se connecte à un réseau connecté à Internet. Cette connexion se fait avec les mêmes protocoles, qu'on communique avec des machines du même réseau ou bien avec des machines lointaines. (La section 1.1.3 en donne une liste partielle, du protocole IPv4 pour les couches basses aux protocoles d'application comme telnet ou SMTP.)
  • Les routeurs (le RFC utilise encore souvent le vieux terme de « passerelle » - gateway - qui n'est plus utilisé aujourd'hui que pour les engins travaillant dans la couche 7) n'ont pas de mémoire, ils routent chaque paquet indépendamment des autres. Les machines terminales ont donc à faire tout le travail d'établissement et de maintien des connexions.
  • Le routage, par contre, ne doit être fait que par les routeurs. Il doit y avoir une stricte séparation entre machines terminales et routeurs. (Certains systèmes d'exploitation comme les Unix BSD routaient autrefois automatiquement dès qu'ils étaient connectés à deux réseaux. La section 1.1.4 explique pourquoi c'est une mauvaise idée. Voir aussi la discussion à la fin de la 3.3.4.2)

La section 1.2 pose les grands principes comme le célébrissime Principe de Robustesse (section 1.2.2), « Soyez tolérant pour ce que vous recevez et exigeant pour ce que vous envoyez », principe qu'on trouve dans plusieurs autres RFC. Ainsi, un programmeur doit résister à la tentation d'exploiter les cas spécifiques d'une norme, pour éviter de perturber les autres implémentations.

La section 1.2.4 détaille la configuration des machines terminales. Elle se faisait entièrement à la main à l'époque. Aujourd'hui, avec la disponibilité fréquente de DHCP (RFC 2131), il vaut mieux oublier cette section et lire le dernier document sur la configuration, le RFC 5505.

Ensuite, le RFC suit le modèle en couches (section 1.3.1), ainsi que le vocabulaire spécifique de chaque couche pour désigner une unité de transmission de données sur le réseau (frame pour la couche 2, packet ou datagram - selon que la fragmentation aie eu lieu ou pas - pour la couche 3, messagesegment pour TCP - pour la couche 4).

La section 2 concerne donc la couche de même rang. C'est ici que se trouve ARP (section 2.3.2, qui insiste que l'expiration des entrées du cache ARP est obligatoire, ce qui n'était pas assez clair dans le RFC 826). C'est aussi dans cette section (en 2.3.3) que l'on rappelle que l'encapsulation normale des paquets IP sur Ethernet est celle du RFC 894, où le troisième champ de l'en-tête Ethernet est le type du protocole de couche 3 (0x800 pour IPv4) pas celle, bien plus complexe, du RFC 1042, où la longueur de la trame se trouve à cet endroit.

Évidemment, la section 3, consacrée à la couche équivalente, est bien plus longue. Elle porte aussi son âge, par exemple en consacrant une section 3.2.1.3 aux classes d'adresse, supprimées depuis.

Parmi les nombreux points abordés, le choix du TTL à mettre dans les paquets (section 3.2.1.7). Une machine terminale ne doit pas émettre un paquet avec un TTL déjà à zéro. La mise en œuvre d'IP doit permettre aux applications de fixer le TTL (sur une machine Posix, cela se fait normalement avec setsockopt(), voir « Tester quels bits de l'en-tête IP on peut changer »).

Mais il y a aussi des exigences du RFC qui ne sont plus du tout suivies aujourd'hui. La section 3.2.1.8 obligeait toute mise en œuvre d'IP à permettre le routage par la source alors que, pour des raisons de sécurité, quasiment plus aucun routeur ne l'accepte.

ICMP (RFC 792) faisant conceptuellement partie de la couche 3, il a droit à une sous-section de la section 3. Elle rappelle par exemple qu'un paquet ICMP d'erreur ne doit jamais être envoyé lorsque le paquet original était lui-même un paquet ICMP d'erreur, pour éviter les boucles. (On lit souvent cette règle énoncée comme « Un paquet ICMP ne doit jamais être envoyé en réponse à un paquet ICMP », ce qui est complètement faux, voir par exemple ping avec les ICMP echo, revus en section 3.2.2.6.)

Parmi les autres sujets abordés, la détection d'un routeur mort, qui ne transmet plus les paquets. Comme les machines terminales n'ont pas (ou plus) de protocole de routage (comme, par exemple, RIP), comment savent-elles que le routeur, en panne, est devenu un trou noir ? La méthode recommandée est, formellement, une violation du modèle en couches, mais c'est la seule qui marche dans tous les cas : les couches hautes doivent informer IP qu'elles ne reçoivent plus rien. (La section 3.3.1.4 est une passionnante discussion des autres options possibles. À lire par tout ingénieur qui s'intéresse aux réseaux.)

Le multihoming, la connexion d'une machine (ou d'un réseau) à plusieurs réseaux, a toujours été un problème difficile pour IP. La section 3.3.4 tente de fixer certaines règles. Par exemple, lors d'une réponse, l'adresse IP source de la réponse doit être l'adresse IP de destination où a été envoyée la question. Ou encore, une application cliente doit avoir la possibilité de choisir son adresse IP source (directive BindAddress de OpenSSH ou bien tcp_outgoing_address de Squid). Et que faire en l'absence de telles directives ? C'est l'objet de la section 3.3.4.3 qui demande de privilégier, si possible, une adresse source située dans le même réseau physique que l'adresse de destination (notez que le RFC 3684 a depuis fourni une solution plus générale à cette question de sélection d'adresse source, pour le protocole IPv6). Par exemple, une machine choisira comme adresse IP source 127.0.0.1 si elle doit contacter localhost et son adresse globale si elle doit contacter une autre machine.

Au sommet de la couche 3 se trouve l'interface avec la couche 4. La section 3.4 détaille les services que doit rendre cette interface. Par exemple, la couche 3 doit fournir un moyen de fixer (pour un paquet émis) et d'interroger (pour un paquet reçu) des paramètres comme le TTL ou le TOS (depuis rebaptisé DSCP par le RFC 2474). Cette section est rédigée sous forme d'une API virtuelle (les API de programmation réseau réelles ont suivi un autre modèle, mais fournissent les mêmes services, cf. le livre de Stevens). Cette API comporte des méthodes comme SEND(src, dst, prot, TOS, TTL, BufPTR, len, Id, DF, opt) (envoi d'un paquet en fixant chaque paramètre).

Finalement, un tableau synthétique, en section 3.5, résume tout ce que doit implémenter le programmeur qui réalise une mise en œuvre d'IP.

La couche 4 est ensuite traitée dans la section 4. Suivant le modèle en sablier, une machine connectée à Internet a un grand choix de couches 2 et de supports physiques, une seule couche 3, IP, et à nouveau un choix en couche 4. À l'époque de notre RFC, il n'y avait qu'UDP (RFC 768) et TCP (RFC 793). Depuis, plusieurs autres ont rejoint ces deux pionniers.

Parmi les exigences pour UDP, le RFC cite une forte recommandation d'activer la somme de contrôle (section 4.1.3.4). Celle-ci est en effet facultative en UDP et plusieurs protocoles ont souffert d'avoir cru qu'ils pouvaient s'en passer (notamment NFS et le DNS pour lequel la version 1 de Zonecheck testait que cette somme de contrôle était bien activée).

TCP est bien plus riche et fait donc l'option d'une section nettement plus longue, la 4.2. À l'époque comme aujourd'hui, il est le protocole de transport le plus utilisé.

Le RFC commence (section 4.2.2) par une discussions sur le rôle des ports, en rappelant que la seule distinction normalisée entre les ports est celle entre ceux inférieurs à 255 (services normalisés) et les autres. La distinction entre les ports privilégiés (inférieurs à 1024) et les autres n'est pas normalisée, en pratique, elle est spécifique à Unix. Le RFC ne s'oppose pas à cette distinction mais note à juste titre qu'elle ne vaut pas grand'chose en matière de sécurité puisque rien ne dit que la machine avec qui on correspond applique les mêmes règles. En outre, depuis la publication du RFC 1122, la vaste diffusion des ordinateurs fait qu'un éventuel attaquant a probablement sa propre machine, sur laquelle il est root. La très relative protection sur laquelle comptaient rlogin (en vérifiant que le port source était 513) et le DNS (qui utilisait à une époque lointaine un port source fixe, 53), ne vaut donc plus rien.

Il y a plein d'autres détails intéressants à couvrir comme l'option PUSH (section 4.2.2.2) dont le RFC rappelle qu'elle ne fournit pas un marquer de fin de message mais qu'elle indique juste un souhait que les données soient transmises « le plus vite possible » (TCP attend normalement un peu pour voir si d'autres données n'arrivent pas, cette optimisation, l'algorithme de Nagle est à nouveau discutée en section 4.2.3.4).

Finalement, un tableau synthétique, en section 4.2.5, résume tout ce que doit implémenter le programmeur qui réalise une mise en œuvre de TCP.


Téléchargez le RFC 1122


L'article seul

RFC 1071: Computing the Internet checksum

Date de publication du RFC : Septembre 1988
Auteur(s) du RFC : R. Braden (USC/Information Sciences Institute), D. Borman (Cray Research), C. Partridge (Bolt Baranek and Newman (BBN) Laboratories), William W. Plummer (Bolt Beranek and Newman, Inc. (BBN))
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 31 mars 2013


Un grand nombre de protocoles de la famille TCP/IP utilisent une somme de contrôle pour détecter les éventuelles corruptions de données pendant le trajet. Chacun de ces protocoles le spécifie comme il veut mais, en pratique, beaucoup utilisent le même algorithme dit « Internet checksum ». Ce RFC donne des conseils sur la mise en œuvre de cette somme de contrôle particulière.

On la trouve à beaucoup d'endroits, IPv4 (RFC 791, section 3.1, « The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header », notez qu'IPv6 n'a pas de somme de contrôle), TCP (RFC 793, section 3.1, « The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header and text »), UDP (RFC 768, « Checksum is the 16-bit one's complement of the one's complement sum of a pseudo header of information from the IP header, the UDP header, and the data [...] ») ou ICMP (RFC 4443, section 2.3, « The checksum is the 16-bit one's complement of the one's complement sum of the entire ICMPv6 message, starting with the ICMPv6 message type field, and prepended with a "pseudo-header" [...] »). Toutes ces définitions sont équivalentes : la « somme de contrôle Internet » est la somme en complément à un des seizets qui forment le pseudo-en-tête et, parfois, le message. Le pseudo-en-tête est une version simplifiée du vrai en-tête (entre autres, il ne contient pas la somme de contrôle). Par exemple, pour UDP sur IPv6, le pseudo en-tête comporte (RFC 2460, section 8.1), les adresses IP source et destination, la longueur des données, le numéro du protocole qui suit, puis l'en-tête UDP.

À l'époque où ce RFC a été écrit (il y a un quart de siècle !) les processeurs étaient bien plus lents, relativement aux réseaux, qu'aujourd'hui. Le calcul de la somme de contrôle, note notre RFC, peut donc être le facteur limitant dans un envoi de données avec TCP. C'est en partie ce qui explique que la somme de contrôle Internet soit une vraie somme, simple à calculer mais peu robuste, et pas un CRC, pourtant plus sûre (a fortiori pas une condensation cryptographique). Aujourd'hui, une mesure faite sur un PC de bureau ordinaire, en fabriquant les paquets en mode utilisateur avant de les envoyer, montre que l'envoi d'un million de courts paquets UDP sur IPv4 prend exactement le même temps avec ou sans la somme de contrôle (elle est optionnelle pour UDP sur IPv4), et time indique que presque tout le temps CPU a été passé dans le noyau, donc pas à calculer la somme de contrôle. (Le résultat pourrait être différent avec des paquets de plus grande taille, puisque la calcul de la somme de contrôle implique d'accéder à tout le paquet.)

Le RFC, écrit à une autre époque, estime qu'il faut chercher à optimiser vigoureusement le calcul de la somme de contrôle. Comme il est fait à chaque paquet, même un gain minime peut être intéressant.

Pour cette optimisation, le RFC note que la somme de contrôle Internet a quelques propriétés utiles (section 2) :

  • Commutativité,
  • Associativité,
  • Indépendance par rapport à la boutianité. Que votre machine soit gros-boutienne ou petit-boutienne ne changera rien,
  • Parallélisation, une conséquence de l'associativité, on peut répartir la tâche de calcul (voir le code pour le Cray plus loin).

(Il parait que ça en fait un groupe abélien.)

Passons à l'implémentation, le cœur de ce RFC. Naturellement, la plupart des programmeurs réseaux n'auront jamais besoin de savoir calculer la somme de contrôle : quelqu'un (typiquement le noyau) le fait pour eux. Aujourd'hui, calculer la somme de contrôle est surtout utile lorsqu'on veut fabriquer soi-même la totalité du paquet, avant de l'envoyer via une prise brute. C'est surtout utile dans le contexte de la sécurité (faire des paquets que le système ne permettrait pas normalement de faire). Quel sont les problèmes à garder en tête ? La plupart des machines font de l'addition en complément à deux. Pour celles-ci, la solution recommandée est de faire une retenue et de l'ajouter à la fin (ce que fait le code C montré plus loin).

En IPv4, chaque routeur doit recalculer la somme de contrôle IP car le TTL change à chaque saut. On peut optimiser cette opération en faisant un recalcul incrémental (RFC 1624).

Ah, et pour vérifier la somme de contrôle ? Mêmes opérations, mais en incluant la somme de contrôle. On doit trouver uniquement des bits à Un (-0 en complément à un).

Le RFC présente en section 4 plusieurs exemples de code mettant en œuvre ces principes. D'abord, un code portable en C :

{
           /* Compute Internet Checksum for "count" bytes
            *         beginning at location "addr".
            */
       register long sum = 0;

        while( count > 1 )  {
           /*  This is the inner loop */
               sum += * (unsigned short) addr++;
               count -= 2;
       }

           /*  Add left-over byte, if any */
       if( count > 0 )
               sum += * (unsigned char *) addr;

           /*  Fold 32-bit sum to 16 bits */
       while (sum>>16)
           sum = (sum & 0xffff) + (sum >> 16);

       checksum = ~sum;
   }

Mais il y a aussi des codes en assembleur, pour les architectures qu'on trouvait à l'époque. Par exemple, le Motorola 68020. Avec ses 20 MHz de fréquence, ce code calculait en 134 μs/ko :

       movl    d1,d2
       lsrl    #6,d1       | count/64 = # loop traversals
       andl    #0x3c,d2    | Then find fractions of a chunk
       negl    d2
       andb    #0xf,cc     | Clear X (extended carry flag)

       jmp     pc@(2$-.-2:b,d2)  | Jump into loop

   1$:     | Begin inner loop...

       movl    a0@+,d2     |  Fetch 32-bit word
       addxl   d2,d0       |    Add word + previous carry
       movl    a0@+,d2     |  Fetch 32-bit word
       addxl   d2,d0       |    Add word + previous carry

           | ... 14 more replications
   2$:
       dbra    d1,1$   | (NB- dbra doesn't affect X)

       movl    d0,d1   | Fold 32 bit sum to 16 bits
       swap    d1      | (NB- swap doesn't affect X)
       addxw   d1,d0
       jcc     3$
       addw    #1,d0
   3$:
       andl    #0xffff,d0

Plus rigolo, du code assembleur pour Cray. Tirant profit des propriétés de la somme de contrôle Internet, et des caractéristiques du Cray, il effectue des calculs sur un vecteur. Même si les ordinateurs vectoriels ne sont plus à la mode, cela illustre aussi comment on peut paralléliser ce calcul :

         EBM
         A0      A1
         VL      64            use full vectors
         S1      <32           form 32-bit mask from the right.
         A2      32
         V1      ,A0,1            load packet into V1
         V2      S1&V1            Form right-hand 32-bits in V2.
         V3      V1>A2            Form left-hand 32-bits in V3.
         V1      V2+V3            Add the two together.
         A2      63            Prepare to collapse into a scalar.
         S1      0
         S4      <16           Form 16-bit mask from the right.
         A4      16
   CK$LOOP S2    V1,A2
         A2      A2-1
         A0      A2
         S1      S1+S2
         JAN     CK$LOOP
         S2      S1&S4           Form right-hand 16-bits in S2
         S1      S1>A4           Form left-hand 16-bits in S1
         S1      S1+S2
         S2      S1&S4           Form right-hand 16-bits in S2
         S1      S1>A4           Form left-hand 16-bits in S1
         S1      S1+S2
         S1      #S1            Take one's complement
         CMR            At this point, S1 contains the checksum.

Ah, et comment je fais, finalement, dans mes programmes ?

static          uint32_t
checksum_finish(uint32_t sum)
{
    /* Fold 32-bit sum to 16 bits */
    while (sum >> 16)
        sum = (sum & 0xffff) + (sum >> 16);
    return ~sum;
}

static          uint32_t
checksum_feed16(const void *p, unsigned int count)
{
    const uint16_t *t = p;
    uint32_t        sum = 0;
    while (count-- > 0)
        /* This is the inner checksum loop */
        sum += *t++;
    return sum;
}

Code qui s'utilise ainsi pour de l'UDP sur IPv6 (buff pointe vers les données) :

uint16_t
checksum6(struct ip6_hdr ip_h, struct udphdr udp_h, uint8_t * buff, uint16_t len_udp)
{
    uint32_t        sum;
    uint8_t         zero_udp_proto[] = { 0, 0, 0, SOL_UDP };
    uint32_t        length = udp_h.len;
    udp_h.check = 0;
    sum = checksum_feed16(ip_h.ip6_src.s6_addr, 8)
        + checksum_feed16(ip_h.ip6_dst.s6_addr, 8)
        + checksum_feed16(&length, 2)
        + checksum_feed16(zero_udp_proto, 2)
        + checksum_feed16(&udp_h, 4)
        + checksum_feed16(buff, len_udp / 2);
    if (len_udp % 2)
        sum += buff[len_udp - 1];
    return checksum_finish(sum);
}

Si vous voulez lire d'autres codes, regarder la fonction in_cksum dans print-ip.c dans le code source de tcpdump pour la vérification. Si vous regardez le code source de Linux (version 3.9), vous verrez que, pour la plupart des plate-formes que gère Linux, le code de la fonction ip_fast_csum est en assembleur, assembleur (en arch/$ARCHITECTURE/include/asm/checksum.h) que vous pouvez comparez avec les codes du RFC.

On notera que la première étude des propriétés de la somme de contrôle de l'Internet a été faite dans le très détaillé document IEN 45, qui est reproduit à la fin de notre RFC. Ceux qui pratiquent la langue de Konrad Zuse liront avec intérêt « Minus Null ». Une bonne explication sur la différence entre complément à un et complément à deux est « Minus Zero ».

Merci à Lutz Donnerhacke pour ses suggestions de lecture. Merci à Kim-Minh Kaplan pour son travail sur le code.


Téléchargez le RFC 1071


L'article seul

RFC 1055: Nonstandard for transmission of IP datagrams over serial lines: SLIP

Date de publication du RFC : Juin 1988
Auteur(s) du RFC : J. Romkey
Statut inconnu, probablement trop ancien
Première rédaction de cet article le 18 mars 2010


Pendant de nombreuses années, le protocole SLIP a été le plus répandu pour l'accès à l'Internet en dehors du réseau local, par exemple via un modem et le RTC. Même si ce RFC se qualifie modestement de « non-norme », il n'en a pas moins été la seule description officielle de SLIP pendant ces années.

Pourtant, SLIP était bien plus ancien que ce RFC. Il a commencé dans les années 1980, dans la mise en œuvre 3com/Unet de TCP/IP. Le terme de « protocole » est d'ailleurs exagéré pour parler de SLIP : c'est uniquement un format de paquet sur une ligne série. Aucune négociation, aucun mécanisme pour distribuer des informations comme les adresses IP. Mais, en contrepartie, la programmation de SLIP est triviale (il y a même un exemple de code en C à la fin du RFC) et il a donc existé un très grand nombre d'implémentations (aujourd'hui, par exemple, celle du noyau Linux est toujours dans drivers/net/slip*).

C'est en 1984, des années avant ce RFC 1055 que Rick Adams a ajouté SLIP à Berkeley Unix et que ce mécanisme a décollé.

Aujourd'hui, l'époque des modems à 1200 b/s, mentionnés par le RFC, semble bien loin et SLIP n'a plus qu'un intérêt historique. Le RFC accuse nettement son âge, notamment lorsqu'il indique (sans donner d'URL, qui n'existaient pas à l'époque) un serveur FTP anonyme pour récupérer le code (ledit serveur n'existe plus), et qu'il ajoute des instructions sur l'utilisation de shar (une horreur en terme de sécurité, inimaginable aujourd'hui).

Donc, en quoi consistait ce « protocole » ? SLIP définissait deux caractères spéciaux, END (valeur 192) et ESC (valeur 219, rien à voir avec le ESC de ASCII). Le END indique la fin du paquet. Si un vrai caractère END (ou ESC) doit être envoyé, on envoie à la place ESC + 220 (ou ESC + 221). Difficile de faire plus simple. Pour copier le noyau Linux :

#define END             0300		/* indicates end of frame	*/
#define ESC             0333		/* indicates byte stuffing	*/
#define ESC_END         0334		/* ESC ESC_END means END 'data'	*/
#define ESC_ESC         0335		/* ESC ESC_ESC means ESC 'data'	*/
...
	while (len-- > 0) {
		switch (c = *s++) {
		case END:
			*ptr++ = ESC;
			*ptr++ = ESC_END;
			break;
		case ESC:
			*ptr++ = ESC;
			*ptr++ = ESC_ESC;
			break;
		default:
			*ptr++ = c;
			break;
		}
	}
	*ptr++ = END;

Il y a quand même quelques petites subtilités. Par exemple, le RFC recommande d'envoyer également un END avant le paquet, pour vider tous les caractères parasites qui seraient en attente (eh oui, les modems n'étaient pas fiables et tout le monde n'avait pas activé V.42). D'autre part, comme SLIP ne définissait pas de MTU, le RFC recommande de se limiter à 1006 octets, taille historique.

Dès le début, les limites de SLIP étaient bien connues et sont listées dans le RFC :

  • Pas de mécanisme d'adressage. À part les adresses IP fixes mises à la main, la solution la plus courante (quoi non citée dans le RFC) était de regarder les paquets IP envoyés et de considérer que l'adresse de destination était l'adresse affectée par l'autre bout.
  • Pas de multi-protocoles : dans un paquet SLIP, rien n'indique le protocole de couche 3 utilisé et SLIP n'était donc utilisable que pour IP.
  • Pas de détection d'erreur. SLIP comptait entièrement sur la ligne ou bien sur IP (dont la somme de contrôle permet de détecter les paquets corrompus).
  • Pas de compression (même si des solutions partielles comme le RFC 1144 sont apparues par la suite).

Bref, SLIP était un vrai protocole Internet : simple, qui marche et qui rend service pendant que les comités sont toujours à discuter d'un protocole meilleur.

Dans le monde Internet, SLIP a été largement remplacé par PPP (qui n'existait pas encore à l'époque du RFC 1055).


Téléchargez le RFC 1055


L'article seul

RFC 1035: Domain names - implementation and specification

Date de publication du RFC : Novembre 1987
Auteur(s) du RFC : P. Mockapetris (USC/ISI)
Chemin des normes
Première rédaction de cet article le 15 octobre 2006


Couturé de cicatrices, ce RFC qui a été amendé par pas moins de vingt-six autres RFC tient toujours. "1035" est toujours la norme du DNS, un protocole sur lequel repose la quasi-totalité des applications de l'Internet. Le DNS est un des plus grands succès de l'Internet (qui se souvient aujourd'hui du ridicule X.500 ?) et notre RFC est donc une lecture indispensable.

Qui osera reprendre ces vingt-huit (avec le RFC 1034 et le 1035) documents et les consolider en un jeu de normes cohérent et à jour ? Sans doute personne, vue l'ampleur de la tâche. En attendant cette très hypothétique synthèse, prévenons tout de suite les lecteurs : lire le 1035 seul peut entrainer des problèmes.

Si son compagnon, le RFC 1034 pose les principes de base du DNS, la structure arborescente des données et le principe client-serveur du protocole, notre RFC descend, lui, dans les détails très concrets et spécifie, dans sa section 3, le format des données (resource records, les enregistrements du DNS) et dans sa section 4 celui des messages échangés entre clients et serveurs. Ces messages sont composés de plusieurs parties (la partie "Question", la partie "Réponse", la partie "Autorité", qui indique les serveurs faisant autorité pour la zone) et le résultat de la commande dig montre ces différentes sections.

Revenant sur le RFC 1034 (la séparation entre les deux RFC n'est pas toujours très logique et on est quasiment toujours obligé de lire les deux), notre RFC revient ensuite sur le format des fichiers de zone et sur l'algorithme utilisé par les logiciels.

En guise de conclusion, rappelons un avertissement : vue l'importance du DNS aujourd'hui, vue la quantité d'expérience accumulée depuis que ce protocole existe, vu le nombre de RFC qui contribuent à décrire le DNS, l'implémenteur de ce protocole ou le simple curieux qui voudrait apprendre ne doivent pas de contenter des deux RFC fondateurs mais doivent être prêts à avaler de nombreux autres textes.


Téléchargez le RFC 1035


L'article seul

RFC 1034: DOMAIN NAMES - CONCEPTS AND FACILITIES

Date de publication du RFC : Novembre 1987
Auteur(s) du RFC : Paul Mockapetris (ISI)
Chemin des normes
Première rédaction de cet article le 30 août 2006


Ce RFC, très ancien, mais jamais remplacé, est toujours la norme officielle du DNS. Modifié, complété, corrigé, par des dizaines de RFC suivants, il reste, avec son compagnon RFC 1035, l'un des plus anciens RFC encore en service.

Il est très intéressant de lire aujourd'hui le RFC qui normalise le DNS. Tout l'Internet dépend fortement du DNS. Mais à l'époque, le DNS n'était qu'une méthode de nommage parmi d'autres. Il l'a finalement emporté et notre RFC ne semble pas ridicule presque vingt ans après. Le DNS a passé le test du temps et le RFC qui le définit reste une excellente source d'information.

Le DNS a été normalisé dans deux RFC : notre 1034 décrit les concepts (mais descend néanmoins beaucoup dans les détails, par exemple sur l'algorithme utilisé) et le RFC 1035 complète avec tout ce que l'implémenteur doit savoir.

Mais, depuis, de très nombreux RFC ont modifié le DNS : supprimant des options (comme IQUERY, les recherches par contenu, jamais réellement déployées et supprimées par le RFC 3425), ajoutant des services comme DNSSEC, ou expliquant tout ce qui n'était pas clair (comme le font les RFC 2181 ou bien le RFC 4592 sur les fameux jokers). Il serait appréciable qu'une âme courageuse s'attache à consolider toutes ces rustines successives en une série de RFC modernes, comme cela a été fait pour le courrier électronique avec les RFC 2821 et RFC 2822. Mais une telle tâche n'a pas encore trouvé de volontaire. Ce serait un véritable travail d'Hercule, vu le nombre de RFC à digérer et le nombre de gens à convaincre, vu aussi le caractère très spécifique d'un service dont dépend presque tout l'Internet.

Parmi les archaïsmes du RFC 1034, notons qu'il spécifie un format de fichiers pour les serveurs de noms, format que lisent des logiciels comme BIND ou NSD, et qu'affiche une commande comme dig :

@ IN  SOA bortzmeyer.netaktiv.com. hostmaster.bortzmeyer.org. (
        2006071901
        7200
        3600
        604800
        43200 )

  IN  NS  ns1.bortzmeyer.org.
  IN  NS  ns1.generic-nic.net.

  IN MX 0 bortzmeyer.netaktiv.com.

. Aujourd'hui, l'IETF évite en général de normaliser les formats de fichiers des clients ou des serveurs, préférant se concentrer sur ce qui passe sur le réseau (on the wire est une expression qui revient souvent à l'IETF). En effet, la normalisation de ce format, quoique utile pour la communication entre humains, ou la rédaction de cours sur le DNS, n'est pas nécessaire à l'interopérabilité des implémentations.


Téléchargez le RFC 1034


L'article seul

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