Aller au contenu principal

3. Protocole de Temps Réseau

Cette section consiste en une définition formelle du Protocole de Temps Réseau, y compris ses formats de données, entités, variables d'état, événements et procédures de traitement des événements. La spécification est basée sur le modèle d'implémentation illustré dans la Figure 1, mais il n'est pas prévu que ce modèle soit le seul sur lequel une spécification peut être basée. En particulier, la spécification est destinée à illustrer et clarifier les opérations intrinsèques de NTP, ainsi qu'à servir de fondement pour une spécification plus rigoureuse, complète et vérifiable.

3.1. Formats de Données

Toutes les opérations mathématiques exprimées ou implicites ici sont en arithmétique à virgule fixe en complément à deux. Les données sont spécifiées comme des quantités entières ou à virgule fixe, avec des bits numérotés en mode big-endian à partir de zéro en commençant à la position gauche ou de poids fort. Étant donné que diverses implémentations peuvent mettre à l'échelle des quantités dérivées en externe pour un usage interne, ni la précision ni le placement de la virgule décimale pour les quantités à virgule fixe ne sont spécifiés. Sauf indication contraire, toutes les quantités sont non signées et peuvent occuper toute la largeur du champ avec un zéro implicite précédant le bit zéro. Les packages matériels et logiciels conçus pour fonctionner avec des quantités signées donneront ainsi des résultats surprenants lorsque le bit le plus significatif (signe) est défini. Il est suggéré que les quantités à virgule fixe non signées dérivées en externe telles que les horodatages soient décalées d'un bit vers la droite pour un usage interne, car la précision représentée par la largeur complète du champ est rarement justifiée.

Étant donné que les horodatages NTP sont des données précieuses et, en fait, représentent le principal produit du protocole, un format d'horodatage spécial a été établi. Les horodatages NTP sont représentés comme un nombre à virgule fixe non signé de 64 bits, en secondes par rapport à 0h le 1er janvier 1900. La partie entière est dans les 32 premiers bits et la partie fractionnaire dans les 32 derniers bits. Ce format permet une arithmétique de précision multiple pratique et une conversion en représentation de Protocole de Temps (secondes), mais complique la conversion en représentation de message d'horodatage ICMP (millisecondes). La précision de cette représentation est d'environ 200 picosecondes, ce qui devrait être adéquat même pour les exigences les plus exotiques.

Les horodatages sont déterminés en copiant la valeur actuelle de l'horloge locale vers un horodatage lorsqu'un événement significatif, tel que l'arrivée d'un message, se produit. Afin de maintenir la plus haute précision, il est important que cela soit fait aussi près que possible du pilote matériel ou logiciel associé à l'événement. En particulier, les horodatages de départ doivent être redéterminés pour chaque retransmission au niveau de la liaison. Dans certains cas, un horodatage particulier peut ne pas être disponible, par exemple lorsque l'hôte est redémarré ou que le protocole démarre pour la première fois. Dans ces cas, le champ de 64 bits est défini sur zéro, indiquant que la valeur est invalide ou indéfinie.

Notez que depuis un certain temps en 1968, le bit le plus significatif (bit 0 de la partie entière) a été défini et que le champ de 64 bits débordera à un certain moment en 2036. Si NTP est utilisé en 2036, des moyens externes seront nécessaires pour qualifier le temps par rapport à 1900 et le temps par rapport à 2036 (et d'autres multiples de 136 ans). Les données horodatées nécessitant une telle qualification seront si précieuses que des moyens appropriés devraient être facilement disponibles. Il existera un intervalle de 200 picosecondes, désormais ignoré, tous les 136 ans lorsque le champ de 64 bits sera zéro et donc considéré comme invalide.

3.2. Variables d'État et Paramètres

Ce qui suit est un résumé des diverses variables d'état et paramètres utilisés par le protocole. Ils sont séparés en classes de variables système, qui se rapportent à l'environnement du système d'exploitation et au mécanisme d'horloge locale; variables de pair, qui représentent l'état de la machine de protocole spécifique à chaque pair; variables de paquet, qui représentent le contenu du message NTP; et paramètres, qui représentent des constantes de configuration fixes pour toutes les implémentations de la version actuelle. Pour chaque classe, la description de la variable est suivie de son nom et de la procédure ou valeur qui la contrôle. Notez que les variables sont en minuscules, tandis que les paramètres sont en majuscules. Des détails supplémentaires sur les formats et l'utilisation sont présentés dans les sections et annexes ultérieures.

3.2.1. Variables Communes

Les variables suivantes sont communes à deux ou plusieurs des classes système, pair et paquet. Des variables supplémentaires sont spécifiques au mécanisme d'authentification optionnel décrit dans l'Annexe C. Lorsqu'il est nécessaire de distinguer entre les variables communes du même nom, l'identifiant de variable sera utilisé.

Adresse du Pair (Peer Address,peer.peeraddr, pkt.peeraddr), Port du Pair (Peer Port,peer.peerport, pkt.peerport): Ce sont l'adresse Internet 32 bits et le numéro de port 16 bits du pair.

Adresse de l'Hôte (Host Address,peer.hostaddr, pkt.hostaddr), Port de l'Hôte (Host Port,peer.hostport, pkt.hostport): Ce sont l'adresse Internet 32 bits et le numéro de port 16 bits de l'hôte. Ils sont inclus parmi les variables d'état pour prendre en charge le multi-hébergement (multi-homing).

Indicateur de Saut (Leap Indicator,sys.leap, peer.leap, pkt.leap): Il s'agit d'un code de deux bits avertissant d'une seconde intercalaire imminente à insérer dans l'échelle de temps NTP. Les bits sont définis avant 23:59 le jour de l'insertion et réinitialisés après 00:00 le jour suivant. Cela entraîne l'augmentation ou la diminution d'un du nombre de secondes (intervalle de roulement) le jour de l'insertion. Dans le cas des serveurs primaires, les bits sont définis par intervention de l'opérateur, tandis que dans le cas des serveurs secondaires, les bits sont définis par le protocole. Les deux bits, bit 0 et bit 1, respectivement, sont codés comme suit:

ValeurSignification
00pas d'avertissement
01dernière minute a 61 secondes
10dernière minute a 59 secondes
11condition d'alarme (horloge non synchronisée)

Dans tous les cas sauf la condition d'alarme (11₂), NTP lui-même ne fait rien avec ces bits, sauf les transmettre aux routines de conversion de temps qui ne font pas partie de NTP. La condition d'alarme se produit lorsque, pour quelque raison que ce soit, l'horloge locale n'est pas synchronisée, comme lors du premier démarrage ou après une période prolongée où aucune source de référence primaire n'est disponible.

Mode (Mode,peer.mode, pkt.mode): Il s'agit d'un entier indiquant le mode d'association, avec des valeurs codées comme suit:

ValeurMode
0non spécifié
1symétrique actif
2symétrique passif
3client
4serveur
5diffusion
6réservé pour les messages de contrôle NTP
7réservé pour usage privé

Strate (Stratum,sys.stratum, peer.stratum, pkt.stratum): Il s'agit d'un entier indiquant la strate de l'horloge locale, avec des valeurs définies comme suit:

ValeurSignification
0non spécifié
1référence primaire (par ex., horloge atomique calibrée, horloge radio)
2-255référence secondaire (via NTP)

À des fins de comparaison, une valeur de zéro est considérée comme supérieure à toute autre valeur. Notez que la valeur maximale de l'entier encodé comme variable de paquet est limitée par le paramètre NTP.MAXSTRATUM.

3.2.2. Variables Système

Le Tableau 1 montre l'ensemble complet des variables système. En plus des variables communes décrites précédemment, les variables suivantes sont utilisées par le système d'exploitation afin de synchroniser l'horloge locale.

Horloge Locale (Local Clock,sys.clock): Il s'agit de l'heure locale actuelle, en format d'horodatage. L'heure locale est dérivée de l'horloge matérielle de la machine particulière et s'incrémente à des intervalles dépendant de la conception utilisée. Une conception appropriée, y compris les mécanismes d'ajustement et de compensation de biais, est décrite dans la Section 5.

Source d'Horloge (Clock Source,sys.peer): Il s'agit d'un sélecteur identifiant la source de synchronisation actuelle. Habituellement, ce sera un pointeur vers une structure contenant les variables de pair. La valeur spéciale NULL indique qu'il n'y a actuellement aucune source de synchronisation valide.

3.2.3. Variables de Pair

Le Tableau 2 montre l'ensemble complet des variables de pair. En plus des variables communes décrites précédemment, les variables suivantes sont utilisées par les fonctions de gestion et de mesure des pairs.

Bit Configuré (Configured Bit,peer.config): Il s'agit d'un bit indiquant que l'association a été créée à partir d'informations de configuration et ne doit pas être démobilisée si le pair devient inaccessible.

Horodatage de Mise à Jour (Update Timestamp,peer.update): Il s'agit de l'heure locale, en format d'horodatage, lorsque le message NTP le plus récent a été reçu. Il est utilisé pour calculer la dispersion de biais.

Registre de Disponibilité (Reachability Register,peer.reach): Il s'agit d'un registre à décalage de bits NTP.WINDOW utilisé pour déterminer l'état de disponibilité du pair, avec des bits entrant par l'extrémité la moins significative (la plus à droite). Un pair est considéré comme accessible si au moins un bit dans ce registre est défini sur un.

Minuterie de Pair (Peer Timer,peer.timer): Il s'agit d'un compteur entier utilisé pour contrôler l'intervalle entre les messages NTP transmis. Une fois défini sur une valeur non nulle, le compteur décrémente à intervalles d'une seconde jusqu'à atteindre zéro, moment auquel la procédure de transmission est appelée. Notez que le fonctionnement de cette minuterie est indépendant des mises à jour de l'horloge locale, ce qui implique que le système de chronométrage et l'architecture du système de minuterie d'intervalle doivent être indépendants l'un de l'autre.

3.2.4. Variables de Paquet

Le tableau 3 montre l'ensemble complet des variables de paquet. En plus des variables communes décrites précédemment, les variables suivantes sont définies.

Numéro de Version (Version Number,pkt.version): Il s'agit d'un entier indiquant le numéro de version de l'expéditeur. Les messages NTP seront toujours envoyés avec le numéro de version actuel NTP.VERSION et seront toujours acceptés si le numéro de version correspond à NTP.VERSION. Des exceptions peuvent être recommandées au cas par cas lorsque le numéro de version est modifié. Les directives spécifiques pour l'interopération entre cette version et les versions précédentes de NTP sont résumées dans l'annexe D.

3.2.5. Variables de Filtre d'Horloge

Lorsque les algorithmes de filtrage et de sélection suggérés dans la section 4 sont utilisés, les variables d'état suivantes sont définies en plus des variables décrites précédemment.

Registre de Filtre (Filter Register,peer.filter): Il s'agit d'un registre à décalage de NTP.SHIFT étages, où chaque étage stocke un triplet composé du délai mesuré, du décalage mesuré et de la dispersion calculée associés à une seule observation. Ces triplets entrent par l'extrémité la plus significative (la plus à gauche) et sont décalés vers l'extrémité la moins significative (la plus à droite) et finalement écartés à mesure que de nouvelles observations arrivent.

Compteur de Données Valides (Valid Data Counter,peer.valid): Il s'agit d'un compteur entier indiquant les échantillons valides restants dans le registre de filtre. Il est utilisé pour déterminer l'état de disponibilité et le moment où l'intervalle d'interrogation doit être augmenté ou diminué.

Décalage (Offset,peer.offset): Il s'agit d'un nombre signé à virgule fixe indiquant le décalage de l'horloge du pair par rapport à l'horloge locale, en secondes.

Délai (Delay,peer.delay): Il s'agit d'un nombre signé à virgule fixe indiquant le délai aller-retour de l'horloge du pair par rapport à l'horloge locale sur le chemin réseau entre elles, en secondes. Notez que cette variable peut prendre des valeurs à la fois positives et négatives, selon la précision de l'horloge et l'accumulation d'erreurs de dérive.

Dispersion (Dispersion,peer.dispersion): Il s'agit d'un nombre signé à virgule fixe indiquant l'erreur maximale de l'horloge du pair par rapport à l'horloge locale sur le chemin réseau entre elles, en secondes. Seules des valeurs positives supérieures à zéro sont possibles.

3.2.6. Variables d'Authentification

Lorsque le mécanisme d'authentification suggéré dans l'annexe C est utilisé, les variables d'état suivantes sont définies en plus des variables décrites précédemment. Ces variables ne sont utilisées que si le mécanisme d'authentification optionnel décrit dans l'annexe C est implémenté.

Bit d'Activation de l'Authentification (Authentication Enabled Bit,peer.authenable): Il s'agit d'un bit indiquant que l'association doit fonctionner en mode authentifié.

Bit Authentifié (Authenticated Bit,peer.authentic): Il s'agit d'un bit indiquant que le dernier message reçu du pair a été correctement authentifié.

Identifiant de Clé (Key Identifier,peer.hostkeyid,peer.peerkeyid,pkt.keyid): Il s'agit d'un entier identifiant la clé cryptographique utilisée pour générer le code d'authentification de message.

Clés Cryptographiques (Cryptographic Keys,sys.key): Il s'agit d'un ensemble de clés DES 64 bits. Chaque clé est construite comme dans les distributions Berkeley Unix, qui se compose de huit octets, où les sept bits de poids faible de chaque octet correspondent aux bits DES 1-7 et le bit de poids fort correspond au bit de parité impaire DES 8.

Somme de Contrôle Cryptographique (Crypto-Checksum,pkt.check): Il s'agit d'une somme de contrôle cryptographique calculée par la procédure de chiffrement.

3.2.7. Paramètres

Le tableau 4 montre les paramètres supposés pour toutes les implémentations fonctionnant dans le système Internet. Il est nécessaire de s'accorder sur les valeurs de ces paramètres afin d'éviter des surcharges réseau inutiles et de maintenir des associations de pairs stables. Les paramètres suivants sont supposés fixes et applicables à toutes les associations.

Numéro de Version (NTP.VERSION): Il s'agit du numéro de version NTP actuel (3).

Port NTP (NTP.PORT): Il s'agit du numéro de port (123) attribué à NTP par l'Internet Assigned Numbers Authority.

Strate Maximale (NTP.MAXSTRATUM): Il s'agit de la valeur de strate maximale pouvant être encodée comme variable de paquet, également interprétée comme « l'infini » ou inaccessible par l'algorithme de routage du sous-réseau.

Âge Maximal de l'Horloge (NTP.MAXAGE): Il s'agit de l'intervalle maximal pendant lequel une horloge de référence sera considérée comme valide après sa dernière mise à jour, en secondes.

Dérive Maximale (NTP.MAXSKEW): Il s'agit de l'erreur de décalage maximale due à la dérive de l'horloge locale sur l'intervalle déterminé par NTP.MAXAGE, en secondes. Le rapport φ = NTP.MAXSKEW / NTP.MAXAGE est interprété comme le taux de dérive maximal possible dû à toutes les causes.

Distance Maximale (NTP.MAXDISTANCE): Lorsque l'algorithme de sélection suggéré dans la section 4 est utilisé, il s'agit de la distance de synchronisation maximale pour les pairs acceptables pour la synchronisation.

Intervalle d'Interrogation Minimal (NTP.MINPOLL): Il s'agit de l'intervalle d'interrogation minimal autorisé par tout pair du système Internet, en secondes sous forme de puissance de deux.

Intervalle d'Interrogation Maximal (NTP.MAXPOLL): Il s'agit de l'intervalle d'interrogation maximal autorisé par tout pair du système Internet, en secondes sous forme de puissance de deux.

Nombre Minimal d'Horloges Sélectionnées (NTP.MINCLOCK): Lorsque l'algorithme de sélection suggéré dans la section 4 est utilisé, il s'agit du nombre minimal de pairs acceptables pour la synchronisation.

Nombre Maximal d'Horloges Sélectionnées (NTP.MAXCLOCK): Lorsque l'algorithme de sélection suggéré dans la section 4 est utilisé, il s'agit du nombre maximal de pairs considérés pour la sélection.

Dispersion Minimale (NTP.MINDISPERSE): Lorsque l'algorithme de filtrage suggéré dans la section 4 est utilisé, il s'agit de l'incrément de dispersion minimal pour chaque niveau de strate, en secondes.

Dispersion Maximale (NTP.MAXDISPERSE): Lorsque l'algorithme de filtrage suggéré dans la section 4 est utilisé, il s'agit de la dispersion maximale du pair et de la dispersion supposée pour les données manquantes, en secondes.

Taille du Registre de Disponibilité (NTP.WINDOW): Il s'agit de la taille du registre de disponibilité (peer.reach), en bits.

Taille du Filtre (NTP.SHIFT): Lorsque l'algorithme de filtrage suggéré dans la section 4 est utilisé, il s'agit de la taille du registre à décalage du filtre d'horloge (peer.filter), en étages.

Poids du Filtre (NTP.FILTER): Lorsque l'algorithme de filtrage suggéré dans la section 4 est utilisé, il s'agit du poids utilisé pour calculer la dispersion du filtre.

Poids de Sélection (NTP.SELECT): Lorsque l'algorithme de sélection suggéré dans la section 4 est utilisé, il s'agit du poids utilisé pour calculer la dispersion de sélection.

3.3. Modes de Fonctionnement

Sauf en mode diffusion, une association NTP est formée lorsque deux pairs échangent des messages et l'un ou les deux créent et maintiennent une instanciation de la machine de protocole, appelée association. L'association peut fonctionner dans l'un des cinq modes indiqués par la variable de mode hôte (peer.mode): symétrique actif, symétrique passif, client, serveur et diffusion, qui sont définis comme suit:

Symétrique Actif (Symmetric Active,1): Un hôte fonctionnant dans ce mode envoie des messages périodiques indépendamment de l'état de disponibilité ou de la strate de son pair. En fonctionnant dans ce mode, l'hôte annonce sa volonté de synchroniser et d'être synchronisé par le pair.

Symétrique Passif (Symmetric Passive,2): Ce type d'association est normalement créé à l'arrivée d'un message d'un pair fonctionnant en mode symétrique actif et persiste seulement tant que le pair est accessible et fonctionne à un niveau de strate inférieur ou égal à l'hôte; sinon, l'association est dissoute. Cependant, l'association persistera toujours jusqu'à ce qu'au moins un message ait été envoyé en réponse. En fonctionnant dans ce mode, l'hôte annonce sa volonté de synchroniser et d'être synchronisé par le pair.

Client (Client,3): Un hôte fonctionnant dans ce mode envoie des messages périodiques indépendamment de l'état de disponibilité ou de la strate de son pair. En fonctionnant dans ce mode, l'hôte, généralement un poste de travail LAN, annonce sa volonté d'être synchronisé par, mais pas de synchroniser le pair.

Serveur (Server,4): Ce type d'association est normalement créé à l'arrivée d'un message de demande client et existe seulement afin de répondre à cette demande, après quoi l'association est dissoute. En fonctionnant dans ce mode, l'hôte, généralement un serveur de temps LAN, annonce sa volonté de synchroniser, mais pas d'être synchronisé par le pair.

Diffusion (Broadcast,5): Un hôte fonctionnant dans ce mode envoie des messages périodiques indépendamment de l'état de disponibilité ou de la strate des pairs. En fonctionnant dans ce mode, l'hôte, généralement un serveur de temps LAN fonctionnant sur un support de diffusion à haute vitesse, annonce sa volonté de synchroniser tous les pairs, mais pas d'être synchronisé par l'un d'eux.

Un hôte fonctionnant en mode client envoie occasionnellement un message NTP à un hôte fonctionnant en mode serveur, peut-être immédiatement après le redémarrage puis à intervalles périodiques. Le serveur répond simplement en échangeant les adresses et les ports, en remplissant les informations requises et en renvoyant le message au client. Les serveurs n'ont pas besoin de conserver d'informations d'état entre les requêtes des clients, tandis que les clients sont libres de gérer l'intervalle d'envoi des messages NTP pour s'adapter aux conditions locales. Dans ces modes, la machine de protocole décrite dans ce document peut être considérablement simplifiée en un simple mécanisme d'appel de procédure distante, sans perte significative de précision ou de robustesse, en particulier lorsqu'elle fonctionne sur un LAN à haut débit.

Dans les modes symétriques, la distinction client/serveur disparaît (presque). Le mode symétrique passif est destiné à être utilisé par les serveurs de temps fonctionnant près des nœuds racines (strate la plus basse) du sous-réseau de synchronisation et avec un nombre relativement important de pairs de manière intermittente. Dans ce mode, l'identité du pair n'a pas besoin d'être connue à l'avance, car l'association avec ses variables d'état est créée uniquement à l'arrivée d'un message NTP. De plus, le stockage d'état peut être réutilisé lorsque le pair devient inaccessible ou fonctionne à un niveau de strate supérieur et donc inéligible comme source de synchronisation.

Le mode symétrique actif est destiné à être utilisé par les serveurs de temps fonctionnant près des nœuds terminaux (strate la plus élevée) du sous-réseau de synchronisation. Un service de temps fiable peut généralement être maintenu avec deux pairs au niveau de strate immédiatement inférieur et un pair au même niveau de strate, de sorte que le taux d'interrogation continue n'est généralement pas significatif, même lorsque la connectivité est perdue et que chaque interrogation renvoie un message d'erreur.

Normalement, un pair fonctionne en mode actif (mode symétrique actif, client ou diffusion), tel que configuré par un fichier de démarrage, tandis que l'autre fonctionne en mode passif (mode symétrique passif ou serveur), souvent sans configuration préalable. Cependant, les deux pairs peuvent être configurés pour fonctionner en mode symétrique actif. Une condition d'erreur se produit lorsque les deux pairs fonctionnent dans le même mode, mais pas en mode symétrique actif. Dans un tel cas, chaque pair ignorera les messages de l'autre, de sorte que les associations antérieures, le cas échéant, seront démantelées en raison d'un échec d'accessibilité.

Le mode diffusion est destiné aux opérations sur des LAN à haut débit avec de nombreuses stations de travail et où la plus haute précision n'est pas requise. Dans le scénario typique, un ou plusieurs serveurs de temps sur le LAN envoient des diffusions périodiques aux stations de travail, qui déterminent ensuite l'heure sur la base d'un délai préconfiguré de l'ordre de quelques millisecondes. Comme dans les modes client/serveur, la machine de protocole peut être considérablement simplifiée dans ce mode ; cependant, une forme modifiée de l'algorithme de sélection d'horloge peut être utile dans les cas où plusieurs serveurs de temps sont utilisés pour une fiabilité accrue.

3.4. Traitement des Événements

Les événements importants d'intérêt dans NTP se produisent lors de l'expiration d'une minuterie de pair (peer.timer), dont une est dédiée à chaque pair avec une association active, et lors de l'arrivée d'un message NTP des différents pairs. Un événement peut également se produire suite à une commande d'opérateur ou à une panne système détectée, telle qu'une défaillance de source de référence primaire. Cette section décrit les procédures invoquées lorsque ces événements se produisent.

3.4.1. Conventions de Notation

Les algorithmes de filtrage et de sélection NTP opèrent sur un ensemble de variables : le décalage d'horloge (θ, THETA), le délai aller-retour (δ, DELTA) et la dispersion (ε, EPSILON). Lorsqu'il est nécessaire de les distinguer, les lettres grecques minuscules sont utilisées pour les variables relatives à un pair, tandis que les lettres grecques majuscules sont utilisées pour les variables relatives à la source de référence primaire, c'est-à-dire à travers le pair jusqu'à la racine du sous-réseau de synchronisation. Des indices seront utilisés pour identifier un pair particulier lorsque le contexte n'est pas clair. Ces algorithmes sont basés sur une quantité appelée distance de synchronisation (λ, LAMBDA), calculée à partir du délai aller-retour et de la dispersion comme décrit ci-dessous.

Comme décrit dans l'annexe H, la dispersion du pair ε comprend les contributions suivantes : l'erreur de mesure ρ = 1 << sys.precision, l'accumulation d'erreur de dérive φτ (où φ = NTP.MAXSKEW / NTP.MAXAGE est le taux de dérive maximal et τ = sys.clock - peer.update est l'intervalle depuis la dernière mise à jour), et la dispersion de filtre (échantillon) ε_σ calculée par l'algorithme de filtre d'horloge. La dispersion racine EPSILON comprend les contributions de la dispersion du pair sélectionné ε et de l'accumulation d'erreur de dérive φτ, ainsi que la dispersion racine du pair lui-même. La dispersion système comprend la dispersion de sélection (échantillon) ε_ξ calculée par l'algorithme de sélection d'horloge et le décalage d'horloge initial absolu |THETA| fourni à l'algorithme d'horloge locale. Tant ε que EPSILON sont des quantités dynamiques, car elles dépendent du temps τ écoulé depuis la dernière mise à jour, ainsi que des dispersions d'échantillon calculées par les algorithmes.

Chaque fois que les variables de pair pertinentes sont mises à jour, toutes les dispersions associées à ce pair sont mises à jour pour refléter l'accumulation d'erreur de dérive. Les calculs peuvent être résumés comme suit :

  • θ = peer.offset
  • δ = peer.delay
  • ε = peer.dispersion = ρ + φτ + ε_σ
  • λ = ε + |δ| / 2

où τ est l'intervalle entre le moment où l'horodatage d'origine (à partir duquel θ et δ ont été déterminés) a été envoyé et le moment présent, et ε_σ est la dispersion de filtre (voir la procédure de filtre d'horloge ci-dessous). Les variables relatives à la racine du sous-réseau de synchronisation via le pair i sont déterminées comme suit :

  • THETA_i = θ_i
  • DELTA_i = peer.rootdelay + δ_i
  • EPSILON_i = peer.rootdispersion + ε_i + φτ_i
  • LAMBDA_i = EPSILON_i + |DELTA_i| / 2

où toutes les variables sont comprises comme appartenant au i-ème pair. Enfin, en supposant que le i-ème pair est sélectionné pour la synchronisation, les variables système sont déterminées comme suit :

  • THETA = décalage final combiné
  • DELTA = DELTA_i
  • EPSILON = EPSILON_i + ε_ξ + |THETA|
  • LAMBDA = LAMBDA_i

où ε_ξ est la dispersion de sélection (voir la procédure de sélection d'horloge ci-dessous).

Un pseudocode informel qui effectue ces calculs est présenté ci-dessous. Notez que le pseudocode n'est exprimé dans aucun langage particulier, bien qu'il présente de nombreuses similitudes avec le langage C. Les détails spécifiques des algorithmes importants sont davantage illustrés par les routines en langage C de l'annexe I.

3.4.2. Procédure de Transmission

La procédure de transmission est exécutée lorsque la minuterie du pair décrémente jusqu'à zéro pour tous les modes sauf le mode client avec un serveur de diffusion et le mode serveur dans tous les cas. En mode client avec un serveur de diffusion, les messages ne sont jamais envoyés. En mode serveur, les messages ne sont envoyés qu'en réponse aux messages reçus. Cette procédure est également appelée par la procédure de réception lorsqu'un message NTP arrive et qu'il n'en résulte pas une association persistante.

begin transmit procedure

pkt.peeraddr <- peer.hostaddr; /* copy system and peer variables */
pkt.peerport <- peer.hostport;
pkt.hostaddr <- peer.peeraddr;
pkt.hostport <- peer.peerport;
pkt.leap <- sys.leap;
pkt.version <- NTP.VERSION;
pkt.mode <- peer.mode;
pkt.stratum <- sys.stratum;
pkt.poll <- peer.hostpoll;
pkt.precision <- sys.precision;
pkt.rootdelay <- sys.rootdelay;
if (sys.leap = 11₂ or (sys.clock - sys.reftime) > NTP.MAXAGE)
skew <- NTP.MAXSKEW;
else
skew <- φ(sys.clock - sys.reftime);
pkt.rootdispersion <- sys.rootdispersion + (1 << sys.precision) + skew;
pkt.refid <- sys.refid;
pkt.reftime <- sys.reftime;

pkt.org <- peer.org; /* copy timestamps */
pkt.rec <- peer.rec;
pkt.xmt <- sys.clock;
peer.xmt <- pkt.xmt;

#ifdef (authentication implemented) /* see Appendix C */
call encrypt;
#endef
send packet;

peer.reach <- peer.reach << 1; /* update reachability */
if (peer.reach = 0 and peer.config = 0)
begin
demobilize association;
exit;
endif

if (peer.reach & 6 != 0) /* test two low-order bits */
if (peer.valid < NTP.SHIFT) /* valid data received */
peer.valid <- peer.valid + 1;
else peer.hostpoll <- peer.hostpoll + 1;
else begin
peer.valid <- peer.valid - 1; /* nothing heard */
peer.hostpoll <- peer.hostpoll - 1;
call clock-filter(0, 0, NTP.MAXDISPERSE);
call clock-select; /* select clock source */
endif
call poll-update;
end transmit procedure;

3.4.3. Procédure de Réception

La procédure de réception est exécutée à l'arrivée d'un message NTP. Elle valide le message, interprète les différents modes et appelle d'autres procédures pour filtrer les données et sélectionner la source de synchronisation. Si le numéro de version dans le paquet ne correspond pas à la version actuelle, le message peut être rejeté ; cependant, des exceptions recommandées peuvent être données au cas par cas lors des changements de version. Si les messages de contrôle NTP décrits dans l'annexe B sont implémentés et que le mode de paquet est 6 (contrôle), la procédure de message de contrôle est appelée. Les adresses Internet et les ports source et destination dans les en-têtes IP et UDP sont mis en correspondance avec le pair correct. S'il n'y a pas de correspondance, une nouvelle instance de la machine de protocole est créée et l'association est mobilisée.

begin receive procedure
if (pkt.version != NTP.VERSION) exit;
#ifdef (control messages implemented)
if (pkt.mode = 6) call control-message;
#endef
for (all associations) /* access control goes here */
match addresses and ports to associations;
if (no matching association)
call receive-instantiation procedure; /* create association */

#ifdef (authentication implemented) /* see Appendix C */
call decrypt;
#endef

if (pkt.mode = 0) /* for compatibility */
mode <- (see Section 3.3);
else
mode <- pkt.mode;

case (mode, peer.hostmode) /* see Table 5 */

error: if (peer.config = 0) demobilize association;
break;

recv: call packet; /* process packet */
if (valid header) begin
peer.reach <- peer.reach | 1;
if (valid data) call clock-update;
endif
else
if (peer.config = 0) demobilize association;
break;

xmit: call packet; /* process packet */
peer.hostpoll <- peer.peerpoll;
call poll-update;
call transmit;
if (peer.config = 0) demobilize association;
break;

pkt: call packet; /* process packet */
if (valid header) begin
peer.reach <- peer.reach | 1;
if (valid data) call clock-update;
endif
else if (peer.config = 0) begin
peer.hostpoll <- peer.peerpoll;
call poll-update;
call transmit;
demobilize association;
endif
endcase
end receive procedure;

3.4.4. Procédure de Paquet

La procédure de paquet vérifie la validité du message, calcule les échantillons de délai/décalage et appelle d'autres procédures pour filtrer les données et sélectionner la source de synchronisation. Le test 1 exige que l'horodatage de transmission ne corresponde pas au dernier reçu du même pair ; sinon, le message pourrait être un ancien doublon. Le test 2 exige que l'horodatage d'origine corresponde au dernier envoyé au même pair ; sinon, le message pourrait être hors séquence, falsifié ou pire. Dans le cas du mode diffusion (5), le délai aller-retour apparent sera nul et la pleine précision de l'opération de transfert de temps pourrait ne pas être atteinte. Cependant, la précision obtenue peut être suffisante pour la plupart des usages. La procédure de mise à jour d'interrogation est appelée avec l'argument peer.hostpoll (peer.peerpoll peut avoir changé).

begin packet procedure
peer.rec <- sys.clock; /* capture receive timestamp */
if (pkt.mode != 5) begin
test1 <- (pkt.xmt != peer.org); /* test 1 */
test2 <- (pkt.org = peer.xmt); /* test 2 */
endif
else begin
pkt.org <- peer.rec; /* fudge missing timestamps */
pkt.rec <- pkt.xmt;
test1 <- true; /* fake tests */
test2 <- true;
endif
peer.org <- pkt.xmt; /* update originate timestamp */
peer.peerpoll <- pkt.poll; /* adjust poll interval */
call poll-update(peer.hostpoll);

test3 <- (pkt.org != 0 and pkt.rec != 0); /* test 3 */

δ <- (T_i - T_(i-3)) - (T_(i-1) - T_(i-2))
θ <- ((T_(i-2) - T_(i-3)) + (T_(i-1) - T_i)) / 2
ε <- (1 << sys.precision) + φ(T_i - T_(i-3))

test4 <- (|δ| < NTP.MAXDISPERSE and ε < NTP.MAXDISPERSE); /* test 4 */

#ifdef (authentication implemented) /* test 5 */
test5 <- ((peer.config = 1 and peer.authenable = 0) or peer.authentic = 1);
#endef

test6 <- (pkt.leap != 11₂ and /* test 6 */
pkt.reftime <= pkt.xmt < pkt.reftime + NTP.MAXAGE)
test7 <- (pkt.stratum <= sys.stratum and /* test 7 */
pkt.stratum < NTP.MAXSTRATUM);
test8 <- (|pkt.rootdelay| < NTP.MAXDISPERSE and /* test 8 */
pkt.rootdispersion < NTP.MAXDISPERSE);

if (not valid header) exit;
peer.leap <- pkt.leap; /* copy packet variables */
peer.stratum <- pkt.stratum;
peer.precision <- pkt.precision;
peer.rootdelay <- pkt.rootdelay;
peer.rootdispersion <- pkt.rootdispersion;
peer.refid <- pkt.refid;
peer.reftime <- pkt.reftime;
if (valid data) call clock-filter(θ, δ, ε); /* process sample */
end packet procedure;

3.4.5. Procédure de Mise à Jour d'Horloge

La procédure de mise à jour d'horloge est appelée par la procédure de réception lorsque des données valides de décalage d'horloge, de délai et de dispersion ont été déterminées par la procédure de filtre d'horloge pour le pair actuel. Le résultat des procédures de sélection d'horloge et de combinaison d'horloge est la valeur finale de correction d'horloge THETA, qui est utilisée par la procédure d'horloge locale pour mettre à jour l'horloge locale. Si aucun candidat ne survit à ces procédures, la procédure de mise à jour d'horloge se termine sans autre action.

begin clock-update procedure
call clock-select; /* select clock source */
if (sys.peer != peer) exit;

LAMBDA <- distance(peer); /* update system variables */
if (LAMBDA >= NTP.MAXDISTANCE) exit;
sys.leap <- peer.leap;
sys.stratum <- peer.stratum + 1;
sys.refid <- peer.peeraddr;
call local-clock;
if (local clock reset) begin /* if reset, clear state variables */
sys.leap <- 11₂;
for (all peers) call clear;
endif
else begin
sys.peer <- peer; /* if not, adjust local clock */
sys.rootdelay <- DELTA;
sys.rootdispersion <- EPSILON + max(ε_ξ + |THETA|, NTP.MINDISPERSE);
endif
sys.reftime <- sys.clock;
end clock-update procedure;

Dans certaines configurations système, une source d'informations de synchronisation précises est disponible sous la forme d'un train d'impulsions de synchronisation espacées d'une seconde. Habituellement, cela est fourni en plus d'une source d'informations de code temporel, telle qu'une horloge radio ou même NTP lui-même, pour numéroter les secondes, minutes, heures et jours. Dans ces configurations, les variables système sont définies pour faire référence à la source à partir de laquelle les impulsions sont dérivées. Pour les configurations prenant en charge une source de référence primaire, telle qu'une horloge radio ou une horloge atomique calibrée, la strate est définie à 1 tant qu'il s'agit de la source de synchronisation réelle, que la procédure d'horloge primaire soit utilisée ou non.

Les spécifications des algorithmes de sélection d'horloge et d'horloge locale ne font pas partie intégrante de la spécification NTP, car d'autres algorithmes offrant des performances équivalentes peuvent exister. Cependant, un algorithme de sélection d'horloge dont on a constaté qu'il fonctionne bien dans l'environnement Internet est décrit à la section 4 et un algorithme d'horloge locale est décrit à la section 5, et leur utilisation est recommandée. L'algorithme de sélection d'horloge décrit à la section 4 sélectionne généralement le pair de plus basse strate et de distance de synchronisation minimale parmi tous les pairs disponibles, sauf si ce pair semble être un faux indicateur (falseticker). Le résultat est que tous les algorithmes fonctionnent ensemble pour construire un arbre couvrant de poids minimal par rapport aux serveurs de temps de référence primaires, donnant un sous-réseau de synchronisation maître-esclave hiérarchique.

3.4.6. Procédure d'Horloge Primaire

Lorsqu'une source de référence primaire, telle qu'une horloge radio, est connectée à l'hôte, il est commode d'intégrer ses informations dans la base de données comme si l'horloge était représentée comme un pair ordinaire. Dans la procédure d'horloge primaire, l'horloge est interrogée environ une fois par minute et le code temporel retourné est utilisé pour produire une nouvelle mise à jour pour l'horloge locale. Lorsque le peer.timer du pair d'horloge primaire décrémente jusqu'à zéro, la procédure de transmission n'est pas appelée ; au lieu de cela, l'horloge radio est interrogée, généralement à l'aide d'une chaîne ASCII spécifiée à cet effet. Lorsqu'un code temporel valide est reçu de l'horloge radio, il est converti au format d'horodatage NTP et les variables de pair sont mises à jour. La valeur de peer.leap est définie selon l'état des bits d'avertissement de seconde intercalaire dans le code temporel, s'ils sont disponibles, ou manuellement par l'opérateur. La valeur de peer.peeraddr, qui deviendra la valeur de sys.refid lorsque la procédure de mise à jour d'horloge est appelée, est définie à une chaîne ASCII décrivant le type d'horloge (voir l'annexe A).

begin primary-clock-update procedure
peer.leap <- "from" radio or operator; /* copy variables */
peer.peeraddr <- ASCII identifier;
peer.rec <- radio timestamp;
peer.reach <- 1;
call clock-filter(sys.clock - peer.rec, 0, 1 << peer.precision);
call clock-update; /* update local clock */
end primary-clock-update procedure;

3.4.7. Procédures d'Initialisation

Les procédures d'initialisation sont utilisées pour configurer et initialiser le système, ses pairs et ses associations.

3.4.7.1. Procédure d'Initialisation

La procédure d'initialisation est appelée lors du redémarrage ou du réamorçage du démon NTP. L'horloge locale est vraisemblablement indéfinie au redémarrage ; cependant, dans certains équipements, une estimation est disponible à partir de l'environnement de redémarrage, comme une horloge/calendrier à sauvegarde par batterie. La variable de précision est déterminée par l'architecture inhérente de l'horloge matérielle locale. Les variables d'authentification ne sont utilisées que si le mécanisme d'authentification décrit dans l'annexe C est implémenté. Les valeurs de ces variables sont déterminées à l'aide de procédures dépassant le cadre de NTP lui-même.

begin initialization procedure
#ifdef (authentication implemented) /* see Appendix C */
sys.keys <- as required;
#endef;
sys.leap <- 11₂; /* copy variables */
sys.stratum <- 0 (undefined);
sys.precision <- host precision;
sys.rootdelay <- 0 (undefined);
sys.rootdispersion <- 0 (undefined);
sys.refid <- 0 (undefined);
sys.reftime <- 0 (undefined);
sys.clock <- external reference;
sys.peer <- NULL;
sys.poll <- NTP.MINPOLL;
for (all configured peers) /* create configured associations */
call initialization-instantiation procedure;
end initialization procedure;

3.4.7.2. Procédure d'Instanciation d'Initialisation

Cette procédure spécifique à l'implémentation est appelée par la procédure d'initialisation afin de définir une association. L'adresse et le mode du pair sont déterminés à partir des informations lues pendant la procédure de redémarrage ou comme résultat de commandes d'opérateur. Les variables d'authentification ne sont utilisées que si le mécanisme d'authentification décrit dans l'annexe C est implémenté. Les valeurs de ces variables sont déterminées à l'aide de procédures dépassant le cadre de NTP lui-même. Avec le bit d'authentification défini comme suggéré, seuls les pairs correctement authentifiés peuvent devenir la source de synchronisation.

begin initialization-instantiation procedure
peer.config <- 1;
#ifdef (authentication implemented) /* see Appendix C */
peer.authenable <- 1 (suggested);
peer.authentic <- 0;
peer.hostkeyid <- as required;
peer.peerkeyid <- 0;
#endef;
peer.peeraddr <- peer IP address; /* copy variables */
peer.peerport <- NTP.PORT;
peer.hostaddr <- host IP address;
peer.hostport <- NTP.PORT;
peer.mode <- host mode;
peer.peerpoll <- 0 (undefined);
peer.timer <- 0;
peer.delay <- 0 (undefined);
peer.offset <- 0 (undefined);
call clear; /* initialize association */
end initialization-instantiation procedure;

3.4.7.3. Procédure d'Instanciation de Réception

La procédure d'instanciation de réception est appelée par la procédure de réception lorsqu'un nouveau pair est découvert. Elle initialise les variables de pair et mobilise l'association. Si le message provient d'un pair fonctionnant en mode client (3), le mode hôte est défini en mode serveur (4) ; sinon, il est défini en mode symétrique passif (2). Les variables d'authentification ne sont utilisées que si le mécanisme d'authentification décrit dans l'annexe C est implémenté. S'il est implémenté, seuls les pairs non configurés correctement authentifiés peuvent devenir la source de synchronisation.

begin receive-instantiation procedure
#ifdef (authentication implemented) /* see Appendix C */
peer.authenable <- 0;
peer.authentic <- 0;
peer.hostkeyid <- as required;
peer.peerkeyid <- 0;
#endef
peer.config <- 0; /* copy variables */
peer.peeraddr <- pkt.peeraddr;
peer.peerport <- pkt.peerport;
peer.hostaddr <- pkt.hostaddr;
peer.hostport <- pkt.hostport;
if (pkt.mode = 3) /* determine mode */
peer.mode <- 4;
else
peer.mode <- 2;
peer.peerpoll <- 0 (undefined);
peer.timer <- 0;
peer.delay <- 0 (undefined);
peer.offset <- 0 (undefined);
call clear; /* initialize association */
end receive-instantiation procedure;

3.4.7.4. Procédure d'Instanciation d'Horloge Primaire

Cette procédure est appelée par la procédure d'initialisation afin de configurer les variables d'état pour l'horloge primaire. La valeur de peer.precision est déterminée à partir des spécifications de l'horloge radio et de l'interface matérielle. La valeur de peer.rootdispersion est nominalement dix fois l'erreur maximale inhérente à l'horloge radio ; par exemple, 10 μs pour une horloge atomique calibrée, 10 ms pour une horloge radio WWVB ou GOES et 100 ms pour une horloge radio WWV moins précise.

begin clock-instantiation procedure
peer.config <- 1; /* copy variables */
peer.peeraddr <- 0 undefined;
peer.peerport <- 0 (not used);
peer.hostaddr <- 0 (not used);
peer.hostport <- 0 (not used);
peer.leap <- 11₂;
peer.mode <- 0 (not used);
peer.stratum <- 0;
peer.peerpoll <- 0 (undefined);
peer.precision <- clock precision;
peer.rootdelay <- 0;
peer.rootdispersion <- clock dispersion;
peer.refid <- 0 (not used);
peer.reftime <- 0 (undefined);
peer.timer <- 0;
peer.delay <- 0 (undefined);
peer.offset <- 0 (undefined);
call clear; /* initialize association */
end clock-instantiation procedure;

Dans certaines configurations impliquant une horloge atomique calibrée ou un récepteur LORAN-C, la source de référence primaire peut ne fournir que des impulsions de seconde et manquer d'un code temporel complet à partir duquel la numérotation des secondes, etc., peut être dérivée. Dans ces configurations, la numérotation des secondes peut être dérivée d'autres sources, telles qu'une horloge radio ou même d'autres pairs NTP. Dans ces configurations, les variables d'horloge primaire doivent refléter la source de référence primaire, et non la source de numérotation des secondes ; cependant, si la source de numérotation des secondes tombe en panne ou est connue pour fonctionner incorrectement, les mises à jour de la source de référence primaire doivent être supprimées comme si elle-même était tombée en panne.

3.4.8. Procédure d'Effacement

La procédure d'effacement est appelée lorsqu'un événement se produit et qu'il entraîne un changement significatif de l'état d'accessibilité ou une interruption potentielle de l'horloge locale.

begin clear procedure
peer.org <- 0 (undefined); /* mark timestamps undefined */
peer.rec <- 0 (undefined);
peer.xmt <- 0 (undefined);
peer.reach <- 0; /* reset state variables */
peer.filter <- [0, 0, NTP.MAXDISPERSE]; /* all stages */
peer.valid <- 0;
peer.dispersion <- NTP.MAXDISPERSE;
peer.hostpoll <- NTP.MINPOLL; /* reset poll interval */
call poll-update;
call clock-select; /* select clock source */
end clear procedure;

3.4.9. Procédure de Mise à Jour d'Interrogation

La procédure de mise à jour d'interrogation est appelée lorsqu'un événement significatif se produit et qu'il peut entraîner un changement de l'intervalle d'interrogation ou de la minuterie du pair. Elle vérifie les valeurs de l'intervalle d'interrogation hôte (peer.hostpoll) et de l'intervalle d'interrogation du pair (peer.peerpoll) et limite chacun à sa plage valide. Si le pair est sélectionné pour la synchronisation, la valeur est encore limitée en fonction de la conformité calculée (voir la section 5).

begin poll-update procedure
temp <- peer.hostpoll; /* determine host poll interval */
if (peer = sys.peer)
temp <- min(temp, sys.poll, NTP.MAXPOLL);
else
temp <- min(temp, NTP.MAXPOLL);
peer.hostpoll <- max(temp, NTP.MINPOLL);
temp <- 1 << min(peer.hostpoll, max(peer.peerpoll, NTP.MINPOLL));

if (peer.timer = 0) /* reset peer timer */
peer.timer <- temp;
else if (peer.timer > temp)
peer.timer <- (sys.clock & (temp - 1)) + 1;
end poll-update procedure;

3.5. Procédure de Distance de Synchronisation

La procédure de distance calcule la distance de synchronisation à partir des variables de pair pour le pair peer.

begin distance(peer) procedure;
DELTA &lt;- peer.rootdelay + |peer.delay|;
EPSILON &lt;- peer.rootdispersion + peer.dispersion + φ(sys.clock - peer.update);
LAMBDA &lt;- EPSILON + |DELTA| / 2;
end distance procedure;

Notez que, bien que DELTA puisse être négatif dans certains cas, EPSILON et LAMBDA sont toujours positifs.

3.6. Questions de Contrôle d'Accès

La conception NTP est telle que la modification accidentelle ou malveillante de données (falsification, tampering) ou la destruction (brouillage, jamming) sur un serveur de temps ne devrait généralement pas entraîner d'erreurs de chronométrage ailleurs dans le sous-réseau de synchronisation. Cependant, le succès de cette approche dépend de serveurs de temps redondants et de chemins réseau diversifiés, ainsi que de l'hypothèse que la falsification ou le brouillage ne se produira pas sur de nombreux serveurs de temps dans tout le sous-réseau de synchronisation en même temps. En principe, la vulnérabilité du sous-réseau peut être conçue par la sélection de serveurs de temps connus pour être fiables et en permettant uniquement à ces serveurs de temps de devenir la source de synchronisation. Les procédures d'authentification décrites dans l'Annexe C représentent un mécanisme pour appliquer cela; cependant, les algorithmes de chiffrement peuvent être très intensifs en CPU et peuvent sérieusement dégrader la précision, sauf si des précautions telles que mentionnées dans la description de la procédure de transmission sont prises.

Bien qu'il ne s'agisse pas d'une fonctionnalité requise de NTP lui-même, certaines implémentations peuvent inclure une fonctionnalité de contrôle d'accès qui empêche l'accès non autorisé et contrôle quels pairs sont autorisés à mettre à jour l'horloge locale. À cette fin, il est utile de distinguer trois catégories d'accès: ceux qui sont préautorisés comme fiables, préautorisés comme amicaux et tous les autres accès (non préautorisés). Vraisemblablement, la préautorisation est accomplie par des entrées dans le fichier de configuration ou un certain type de système de gestion de tickets tel que Kerberos [STE88]. Dans ce modèle, seuls les accès fiables peuvent entraîner que le pair devienne la source de synchronisation. Bien que les accès amicaux ne puissent pas entraîner que le pair devienne la source de synchronisation, les messages NTP et les horodatages sont renvoyés comme spécifié.

Il ne semble pas utile de maintenir une horloge secrète, comme cela résulterait de la restriction des accès non préautorisés, à moins que l'intention ne soit de cacher l'existence du serveur de temps lui-même. Les hôtes Internet bien comportés sont censés renvoyer un message d'erreur ICMP service-indisponible si un service n'est pas implémenté ou si les ressources ne sont pas disponibles; cependant, dans le cas de NTP, les ressources requises sont minimes, il y a donc peu de besoin de restreindre les demandes destinées uniquement à lire l'horloge. Un mécanisme de contrôle d'accès simple mais efficace consiste alors à considérer toutes les associations préconfigurées en mode symétrique ou en mode client (modes 1, 2 et 3) comme fiables et toutes les autres associations, préconfigurées ou non, comme amicales.

Si un modèle de confiance plus complet est requis, la conception peut être basée sur une liste de contrôle d'accès avec chaque entrée composée d'une adresse Internet 32 bits, d'un masque 32 bits et d'un mode 3 bits. Si le ET logique de l'adresse source (pkt.peeraddr) et du masque dans une entrée correspond à l'adresse correspondante dans l'entrée et que le mode (pkt.mode) correspond au mode dans l'entrée, l'accès est autorisé; sinon, un message d'erreur ICMP est renvoyé au demandeur. Grâce au choix approprié du masque, il est possible de restreindre les demandes par mode à des adresses individuelles, un sous-réseau particulier ou des adresses réseau, ou de n'avoir aucune restriction du tout. La liste de contrôle d'accès servirait alors de filtre contrôlant quels pairs pourraient créer des associations.