Anatomie du paquet NTP#

Pourquoi#

Le chapitre Chrony explique comment un offset est calculé à partir de quatre timestamps, mais jamais à quoi ressemble le paquet qui les transporte réellement sur le réseau. Comprendre la structure de ce paquet, minuscule, 48 octets dans sa forme la plus simple, permet de lire une capture réseau, de comprendre le mode utilisé par ce projet (client-serveur) par opposition aux autres modes que NTP propose, et de découvrir un mécanisme intégré au protocole que ce guide n’avait pas encore montré : le “Kiss-o’-Death”.

Comment : les champs de l’en-tête#

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Root Delay                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Root Dispersion                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Reference ID                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                    Reference Timestamp (64)                   +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Origin Timestamp (64)  [T1]               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Receive Timestamp (64) [T2]               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                  Transmit Timestamp (64) [T3]                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Extensions (NTS, MAC...), longueur variable          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Le quatrième timestamp (T4, réception) n’apparaît jamais dans le paquet lui-même : il est enregistré localement par le destinataire au moment de la réception, jamais transmis sur le fil.

ChampTailleRôle
LI (Leap Indicator)2 bitsAnnonce une seconde intercalaire imminente (cf. section dédiée ci-dessous)
VN (Version)3 bitsVersion du protocole, 4 aujourd’hui
Mode3 bitsRôle de l’émetteur dans l’échange (cf. section Modes)
Stratum8 bitsNiveau hiérarchique (chapitre Vue d’ensemble), 0 a un sens spécial, voir Kiss-o’-Death
Poll8 bitsIntervalle d’interrogation, en log₂ secondes
Precision8 bitsPrécision déclarée de l’horloge locale, en log₂ secondes
Root Delay / Root Dispersion32 bits chacunDélai et incertitude cumulés jusqu’à la référence stratum 0
Reference ID32 bitsIdentifiant de la source (chaîne ASCII sur stratum 0/1, ex. PPS0 ; adresse IP du serveur amont sur stratum ≥ 2)
Origin/Receive/Transmit Timestamps64 bits chacunT1, T2, T3, cf. section Les quatre timestamps ci-dessous

Reference ID : le catalogue des sources d’un stratum 1#

Sur un serveur stratum 1, le Reference ID est une chaîne ASCII de 4 caractères qui annonce le type de référence physique qui discipline l’horloge. La RFC 5905 (§ 7.3) en assigne une liste conventionnelle, dont voici les principaux codes :

CodeSource physique
GPSConstellation GPS (États-Unis), reçue par un récepteur satellite
GALConstellation Galileo (Europe)
PPSImpulsion par seconde générique, fournie par un équipement externe calibré, quel qu’il soit
DCFÉmetteur grandes ondes DCF77 (Mainflingen, Allemagne, 77,5 kHz), l’horloge radio historique de l’Europe, encore reçue par des millions de réveils et d’horloges de gare
MSFÉmetteur grandes ondes MSF (Anthorn, Royaume-Uni, 60 kHz)
WWVBÉmetteur grandes ondes WWVB (Fort Collins, Colorado, 60 kHz)
JJYÉmetteurs grandes ondes japonais (Fukushima 40 kHz, Saga 60 kHz)
TDFÉmetteur d’Allouis (France, 162 kHz), ex-porteuse de France Inter, qui diffuse toujours un code horaire piloté par des horloges atomiques
CHU / WWV / WWVHÉmetteurs radio HF horaires (Ottawa, Colorado, Hawaï), l’heure “parlée” en ondes courtes
IRIGSignal filaire IRIG (Inter-Range Instrumentation Group), distribution d’heure en environnement industriel et militaire
NIST / ACTS / USNO / PTBServices d’heure par modem téléphonique des instituts nationaux (NIST et USNO américains, PTB allemande)
GOESSatellites météo géostationnaires GOES (États-Unis), service horaire historique
LORCStations de radionavigation LORAN-C (100 kHz), réseau aujourd’hui largement éteint

Ces codes racontent l’histoire des références de temps : les émetteurs radio nationaux grandes ondes (DCF, MSF, WWVB, JJY, TDF) et les services par modem téléphonique (NIST, ACTS) ont précédé le GNSS, qui les a presque tous supplantés ; PPS ne désigne pas une source en soi mais l’impulsion électrique de calage qu’une source, quelle qu’elle soit, fournit à la machine.

Le code exact reste déclaratif : c’est la configuration du serveur qui le choisit, et rien ne permet à un client de le vérifier. Sur ce serveur, l’utilisateur a choisi PPS0 (Reference ID : 50505330 (PPS0), soit les codes ASCII de P, P, S, 0). À partir du stratum 2, le même champ change de nature et transporte l’adresse IPv4 de la source amont (cf. Erreurs à éviter).

Les quatre timestamps et le calcul d’offset#

L’échange client-serveur repose sur quatre instants, mesurés en alternance par l’horloge du client et par celle du serveur :

      Client                             Serveur
        │                                   │
   T1   ●─────────── requête ─────────────► ●   T2
        │                                   │  (traitement)
   T4   ● ◄────────── réponse ──────────────●   T3
        │                                   │
  • T1 (Origin Timestamp) : départ de la requête, lu sur l’horloge du client ;
  • T2 (Receive Timestamp) : arrivée de la requête, lu sur l’horloge du serveur ;
  • T3 (Transmit Timestamp) : départ de la réponse, horloge du serveur ;
  • T4 : arrivée de la réponse, horloge du client. Ce quatrième instant n’est jamais transmis dans le paquet : chaque machine le note localement à la réception (cf. Erreurs à éviter).

Chaque différence mélange deux inconnues : le décalage réel entre les deux horloges et le temps de trajet réseau. T2 - T1 contient le décalage plus le trajet aller ; T3 - T4 contient le décalage moins le trajet retour. En moyennant les deux, les trajets s’annulent, à condition d’être égaux :

offset = ((T2 - T1) + (T3 - T4)) / 2
délai  = (T4 - T1) - (T3 - T2)

Le délai aller-retour, lui, retranche du temps total vu par le client (T4 - T1) le temps de traitement du serveur (T3 - T2), qui ne traverse pas le réseau.

Exemple chiffré : un serveur en avance de 100 ms sur le client, 50 ms de trajet dans chaque sens, 20 ms de traitement (en gras, les quatre valeurs réellement mesurées) :

InstantHorloge clientHorloge serveur (+100 ms)
T1 (départ requête)0 ms100 ms
T2 (arrivée serveur)50 ms150 ms
T3 (départ réponse)70 ms170 ms
T4 (retour client)120 ms220 ms
offset = ((150 - 0) + (170 - 120)) / 2 = (150 + 50) / 2 = 100 ms   (l'avance réelle)
délai  = (120 - 0) - (170 - 150)       = 120 - 20       = 100 ms   (2 × 50 ms de trajet)

L’hypothèse implicite, un réseau symétrique dans les deux sens, est la limite fondamentale du protocole : toute asymétrie introduit un biais égal à sa moitié, indétectable depuis les quatre timestamps seuls (chapitre Chrony, Pour aller plus loin). Le déroulé pas à pas de ce calcul est aussi présenté, avec un autre exemple, dans How does NTP work? (sookocheff.com), une des lectures fondatrices de ce chapitre (cf. Sources et remerciements du chapitre Vue d’ensemble).

Les modes NTP#

Le champ Mode (3 bits) indique le rôle joué par le paquet. Ce guide n’en utilise qu’un seul, mais le protocole en définit plusieurs :

ModeUsageUtilisé dans ce guide ?
Client (3) / Serveur (4)Le client interroge, le serveur répond : c’est le mode utilisé pour toutes les requêtes vers ce serveur Stratum 1 et vers les sources amontOui
Symétrique actif/passif (1/2)Deux serveurs s’interrogent mutuellement en pair-à-pair, chacun pouvant discipliner l’autre, typique entre serveurs de même niveau qui se surveillent mutuellementNon
Broadcast/Multicast (5)Un serveur diffuse l’heure sans requête individuelle, boucle ouverte, moins précis (aucun calcul de délai réseau possible sans échange bidirectionnel)Non

Le mode client-serveur est le bon choix pour ce projet : un serveur public qui répond à des millions de clients anonymes n’a pas vocation à entretenir des associations symétriques avec chacun d’eux, et le broadcast sacrifierait la précision pour un gain de bande passante non pertinent ici.

Kiss-o’-Death : le contrôle de débit intégré au protocole#

Le chapitre nftables montre comment limiter le débit au niveau réseau (rejet de paquets au-delà d’un seuil). NTP dispose en plus de son propre mécanisme de rétorsion, au niveau applicatif : quand Stratum = 0, le champ Reference ID ne contient plus un identifiant de source, mais un code Kiss ASCII de 4 caractères, d’où le nom “Kiss-o’-Death” (KoD).

CodeSignification
RATEFréquence d’interrogation trop élevée, l’intervalle de poll doit être augmenté
DENY / RSTRAccès refusé par la politique du serveur
INITLe serveur n’est pas encore synchronisé

C’est un signal coopératif : un client bien élevé (comme chrony) réduit effectivement son taux de requêtes en recevant un RATE. Un client malveillant peut l’ignorer : c’est pourquoi le rate-limiting réseau du chapitre nftables reste nécessaire en complément : le KoD régule les clients de bonne foi, le pare-feu contient ceux qui ne le sont pas.

Le champ Leap Indicator#

Le chapitre Secondes intercalaires explique le fichier leap-seconds.list qui informe chrony à l’avance qu’une seconde intercalaire est programmée. Le champ LI de 2 bits est le mécanisme par lequel cette information est ensuite répercutée en temps réel à chaque client, dans chaque paquet, durant les heures qui précèdent l’événement :

Valeur LISignification
00Pas d’avertissement
01La dernière minute du jour aura 61 secondes
10La dernière minute du jour aura 59 secondes
11Horloge non synchronisée (alarme)

Erreurs à éviter#

  • Confondre le Reference ID d’un stratum 1 et celui d’un stratum supérieur. Sur ce projet (Reference ID : 50505330 (PPS0), chapitre Chrony), c’est une chaîne ASCII de 4 caractères. Sur un client interrogeant ce serveur, le Reference ID qu’il verra dans les réponses de ses propres sources amont de stratum ≥ 2 sera au contraire une adresse IPv4, le même champ change de sens selon le stratum de l’émetteur.
  • Oublier que T4 n’est jamais dans le paquet. Une capture réseau d’un paquet NTP isolé ne contient que 3 des 4 timestamps nécessaires au calcul d’offset ; le quatrième est local à chaque machine, jamais observable depuis l’extérieur.

Vérifier#

# Capturer un échange NTP pour observer les champs réels
tcpdump -i any -n -vv udp port 123 -c 4

# Avec un client NTP capable d'afficher le détail du paquet
ntpdate -d pool.ntp.org 2>&1 | head -30

📚 Pour aller plus loin

  • RFC 5905 définit la structure complète du paquet NTPv4, tous les champs et leur codage exact.
  • Le format des codes Kiss-o’-Death est détaillé au §7.4 de la RFC 5905.
  • Le mécanisme d’authentification historique Autokey (RFC 5906), prédécesseur de NTS, est évoqué au chapitre Chrony.