3. Netzwerkzeitprotokoll
Dieser Abschnitt besteht aus einer formalen Definition des Netzwerkzeitprotokolls, einschließlich seiner Datenformate, Entitäten, Zustandsvariablen, Ereignisse und Ereignisverarbeitungsverfahren. Die Spezifikation basiert auf dem in Abbildung 1 dargestellten Implementierungsmodell, aber es ist nicht beabsichtigt, dass dies das einzige Modell ist, auf dem eine Spezifikation basieren kann. Insbesondere soll die Spezifikation die intrinsischen Operationen von NTP veranschaulichen und klären sowie als Grundlage für eine strengere, umfassendere und überprüfbarere Spezifikation dienen.
3.1. Datenformate
Alle hier ausgedrückten oder impliziten mathematischen Operationen sind in Zweier-Komplement-Festkomma-Arithmetik. Daten werden als ganze Zahlen oder Festkomma-Größen angegeben, wobei Bits in Big-Endian-Weise ab Null beginnend von der linken oder höchstwertigen Position nummeriert sind. Da verschiedene Implementierungen extern abgeleitete Größen für den internen Gebrauch skalieren können, sind weder die Präzision noch die Dezimalpunktplatzierung für Festkomma-Größen spezifiziert. Sofern nicht anders angegeben, sind alle Größen vorzeichenlos und können die volle Feldbreite mit einer impliziten Null vor Bit Null belegen. Hardware- und Softwarepakete, die für die Arbeit mit vorzeichenbehafteten Größen entwickelt wurden, liefern daher überraschende Ergebnisse, wenn das höchstwertige (Vorzeichen-) Bit gesetzt ist. Es wird vorgeschlagen, dass extern abgeleitete, vorzeichenlose Festkomma-Größen wie Zeitstempel für den internen Gebrauch um ein Bit nach rechts verschoben werden, da die durch die volle Feldbreite dargestellte Präzision selten gerechtfertigt ist.
Da NTP-Zeitstempel wertvolle Daten sind und tatsächlich das Hauptprodukt des Protokolls darstellen, wurde ein spezielles Zeitstempelformat etabliert. NTP-Zeitstempel werden als 64-Bit-vorzeichenlose Festkommazahl dargestellt, in Sekunden relativ zu 0h am 1. Januar 1900. Der ganzzahlige Teil befindet sich in den ersten 32 Bits und der Bruchteil in den letzten 32 Bits. Dieses Format ermöglicht bequeme Mehrfachpräzisions-Arithmetik und Konvertierung in Zeitprotokoll-Darstellung (Sekunden), kompliziert jedoch die Konvertierung in ICMP-Zeitstempelnachrichten-Darstellung (Millisekunden). Die Präzision dieser Darstellung beträgt etwa 200 Pikosekunden, was selbst für die exotischsten Anforderungen ausreichend sein sollte.
Zeitstempel werden bestimmt, indem der aktuelle Wert der lokalen Uhr zu einem Zeitstempel kopiert wird, wenn ein bedeutendes Ereignis, wie die Ankunft einer Nachricht, auftritt. Um die höchste Genauigkeit aufrechtzuerhalten, ist es wichtig, dass dies so nah wie möglich am Hardware- oder Softwaretreiber erfolgt, der mit dem Ereignis verbunden ist. Insbesondere sollten Abfahrtszeitstempel für jede Neuübertragung auf Verbindungsebene neu bestimmt werden. In einigen Fällen ist ein bestimmter Zeitstempel möglicherweise nicht verfügbar, z. B. wenn der Host neu gestartet wird oder das Protokoll zum ersten Mal gestartet wird. In diesen Fällen wird das 64-Bit-Feld auf Null gesetzt, was anzeigt, dass der Wert ungültig oder undefiniert ist.
Beachten Sie, dass seit einiger Zeit im Jahr 1968 das höchstwertige Bit (Bit 0 des ganzzahligen Teils) gesetzt wurde und dass das 64-Bit-Feld irgendwann im Jahr 2036 überlaufen wird. Sollte NTP im Jahr 2036 noch verwendet werden, werden externe Mittel erforderlich sein, um die Zeit relativ zu 1900 und die Zeit relativ zu 2036 (und andere Vielfache von 136 Jahren) zu qualifizieren. Mit Zeitstempel versehene Daten, die eine solche Qualifikation erfordern, werden so wertvoll sein, dass geeignete Mittel leicht verfügbar sein sollten. Es wird ein 200-Pikosekunden-Intervall existieren, das hiernach ignoriert wird, alle 136 Jahre, wenn das 64-Bit-Feld Null ist und daher als ungültig betrachtet wird.
3.2. Zustandsvariablen und Parameter
Im Folgenden finden Sie eine Zusammenfassung der verschiedenen Zustandsvariablen und Parameter, die vom Protokoll verwendet werden. Sie sind in Klassen von Systemvariablen unterteilt, die sich auf die Betriebssystemumgebung und den lokalen Uhrenmechanismus beziehen; Peer-Variablen, die den Zustand der protokollspezifischen Maschine für jeden Peer darstellen; Paketvariablen, die den Inhalt der NTP-Nachricht darstellen; und Parameter, die feste Konfigurationskonstanten für alle Implementierungen der aktuellen Version darstellen. Für jede Klasse folgt der Beschreibung der Variablen ihr Name und das Verfahren oder der Wert, der sie steuert. Beachten Sie, dass Variablen in Kleinbuchstaben sind, während Parameter in Großbuchstaben sind. Zusätzliche Details zu Formaten und Verwendung werden in späteren Abschnitten und Anhängen präsentiert.
3.2.1. Gemeinsame Variablen
Die folgenden Variablen sind zwei oder mehreren der System-, Peer- und Paketklassen gemeinsam. Zusätzliche Variablen sind spezifisch für den optionalen Authentifizierungsmechanismus, der in Anhang C beschrieben wird. Wenn es notwendig ist, zwischen gemeinsamen Variablen desselben Namens zu unterscheiden, wird der Variablenbezeichner verwendet.
Peer-Adresse (Peer Address,peer.peeraddr, pkt.peeraddr), Peer-Port (Peer Port,peer.peerport, pkt.peerport): Dies sind die 32-Bit-Internetadresse und die 16-Bit-Portnummer des Peers.
Host-Adresse (Host Address,peer.hostaddr, pkt.hostaddr), Host-Port (Host Port,peer.hostport, pkt.hostport): Dies sind die 32-Bit-Internetadresse und die 16-Bit-Portnummer des Hosts. Sie sind in den Zustandsvariablen enthalten, um Multi-Homing zu unterstützen.
Schaltsekundenindikator (Leap Indicator,sys.leap, peer.leap, pkt.leap): Dies ist ein Zwei-Bit-Code, der vor einer bevorstehenden Schaltsekunde warnt, die in die NTP-Zeitskala eingefügt werden soll. Die Bits werden vor 23:59 am Tag der Einfügung gesetzt und nach 00:00 am folgenden Tag zurückgesetzt. Dies führt dazu, dass die Anzahl der Sekunden (Rollover-Intervall) am Tag der Einfügung um eins erhöht oder verringert wird. Im Falle primärer Server werden die Bits durch Eingreifen des Operators gesetzt, während im Falle sekundärer Server die Bits durch das Protokoll gesetzt werden. Die zwei Bits, Bit 0 und Bit 1, sind wie folgt kodiert:
| Wert | Bedeutung |
|---|---|
| 00 | keine Warnung |
| 01 | letzte Minute hat 61 Sekunden |
| 10 | letzte Minute hat 59 Sekunden |
| 11 | Alarmzustand (Uhr nicht synchronisiert) |
In allen Fällen außer dem Alarmzustand (11₂) macht NTP selbst nichts mit diesen Bits, außer sie an die Zeitkonvertierungsroutinen weiterzugeben, die nicht Teil von NTP sind. Der Alarmzustand tritt auf, wenn aus irgendeinem Grund die lokale Uhr nicht synchronisiert ist, z. B. beim ersten Hochfahren oder nach einer längeren Zeit, in der keine primäre Referenzquelle verfügbar ist.
Modus (Mode,peer.mode, pkt.mode): Dies ist eine ganze Zahl, die den Assoziationsmodus angibt, mit wie folgt kodierten Werten:
| Wert | Modus |
|---|---|
| 0 | nicht spezifiziert |
| 1 | symmetrisch aktiv |
| 2 | symmetrisch passiv |
| 3 | Client |
| 4 | Server |
| 5 | Broadcast |
| 6 | für NTP-Steuerungsnachrichten reserviert |
| 7 | für private Verwendung reserviert |
Schicht (Stratum,sys.stratum, peer.stratum, pkt.stratum): Dies ist eine ganze Zahl, die die Schicht der lokalen Uhr angibt, mit wie folgt definierten Werten:
| Wert | Bedeutung |
|---|---|
| 0 | nicht spezifiziert |
| 1 | primäre Referenz (z.B. kalibrierte Atomuhr, Funkuhr) |
| 2-255 | sekundäre Referenz (über NTP) |
Zu Vergleichszwecken wird ein Wert von Null als größer als jeder andere Wert betrachtet. Beachten Sie, dass der Maximalwert der als Paketvariable kodierten ganzen Zahl durch den Parameter NTP.MAXSTRATUM begrenzt ist.
3.2.2. Systemvariablen
Tabelle 1 zeigt den vollständigen Satz von Systemvariablen. Zusätzlich zu den zuvor beschriebenen gemeinsamen Variablen verwendet das Betriebssystem die folgenden Variablen, um die lokale Uhr zu synchronisieren.
Lokale Uhr (Local Clock,sys.clock): Dies ist die aktuelle lokale Zeit im Zeitstempelformat. Die lokale Zeit wird von der Hardwareuhr der jeweiligen Maschine abgeleitet und inkrementiert in Intervallen, die vom verwendeten Design abhängen. Ein geeignetes Design, einschließlich Anpassungs- und Schiefkompensationsmechanismen, wird in Abschnitt 5 beschrieben.
Uhrenquelle (Clock Source,sys.peer): Dies ist ein Selektor, der die aktuelle Synchronisationsquelle identifiziert. Normalerweise ist dies ein Zeiger auf eine Struktur, die die Peer-Variablen enthält. Der spezielle Wert NULL zeigt an, dass derzeit keine gültige Synchronisationsquelle vorhanden ist.
3.2.3. Peer-Variablen
Tabelle 2 zeigt den vollständigen Satz von Peer-Variablen. Zusätzlich zu den zuvor beschriebenen gemeinsamen Variablen verwenden die Peer-Verwaltungs- und Messfunktionen die folgenden Variablen.
Konfigurationsbit (Configured Bit,peer.config): Dies ist ein Bit, das anzeigt, dass die Assoziation aus Konfigurationsinformationen erstellt wurde und nicht demobilisiert werden sollte, wenn der Peer unerreichbar wird.
Aktualisierungszeitstempel (Update Timestamp,peer.update): Dies ist die lokale Zeit im Zeitstempelformat, wenn die neueste NTP-Nachricht empfangen wurde. Sie wird zur Berechnung der Schiefedispersion verwendet.
Erreichbarkeitsregister (Reachability Register,peer.reach): Dies ist ein Schieberegister mit NTP.WINDOW Bits, das verwendet wird, um den Erreichbarkeitsstatus des Peers zu bestimmen, wobei Bits vom am wenigsten signifikanten (rechten) Ende eintreten. Ein Peer wird als erreichbar betrachtet, wenn mindestens ein Bit in diesem Register auf eins gesetzt ist.
Peer-Timer (Peer Timer,peer.timer): Dies ist ein ganzzahliger Zähler, der verwendet wird, um das Intervall zwischen übertragenen NTP-Nachrichten zu steuern. Sobald er auf einen Wert ungleich Null gesetzt ist, dekrementiert der Zähler in Ein-Sekunden-Intervallen, bis er Null erreicht, wobei zu diesem Zeitpunkt das Übertragungsverfahren aufgerufen wird. Beachten Sie, dass der Betrieb dieses Timers unabhängig von lokalen Uhrenaktualisierungen ist, was impliziert, dass das Zeitmesssystem und die Intervall-Timer-Systemarchitektur unabhängig voneinander sein müssen.
3.3. Betriebsmodi
Außer im Broadcast-Modus wird eine NTP-Assoziation gebildet, wenn zwei Peers Nachrichten austauschen und einer oder beide eine Instanziierung der Protokollmaschine, genannt Assoziation, erstellen und pflegen. Die Assoziation kann in einem von fünf Modi arbeiten, wie durch die Host-Modus-Variable (peer.mode) angezeigt: symmetrisch aktiv, symmetrisch passiv, Client, Server und Broadcast, die wie folgt definiert sind:
Symmetrisch Aktiv (Symmetric Active,1): Ein Host, der in diesem Modus arbeitet, sendet periodische Nachrichten unabhängig vom Erreichbarkeitszustand oder der Schicht seines Peers. Durch den Betrieb in diesem Modus kündigt der Host seine Bereitschaft an, zu synchronisieren und vom Peer synchronisiert zu werden.
Symmetrisch Passiv (Symmetric Passive,2): Dieser Assoziationstyp wird normalerweise beim Eintreffen einer Nachricht von einem Peer erstellt, der im symmetrisch aktiven Modus arbeitet, und besteht nur so lange, wie der Peer erreichbar ist und auf einer Schicht arbeitet, die kleiner oder gleich dem Host ist; andernfalls wird die Assoziation aufgelöst. Die Assoziation wird jedoch immer bestehen bleiben, bis mindestens eine Nachricht als Antwort gesendet wurde. Durch den Betrieb in diesem Modus kündigt der Host seine Bereitschaft an, zu synchronisieren und vom Peer synchronisiert zu werden.
Client (Client,3): Ein Host, der in diesem Modus arbeitet, sendet periodische Nachrichten unabhängig vom Erreichbarkeitszustand oder der Schicht seines Peers. Durch den Betrieb in diesem Modus kündigt der Host, normalerweise eine LAN-Workstation, seine Bereitschaft an, vom Peer synchronisiert zu werden, aber nicht den Peer zu synchronisieren.
Server (Server,4): Dieser Assoziationstyp wird normalerweise beim Eintreffen einer Client-Anforderungsnachricht erstellt und existiert nur, um auf diese Anforderung zu antworten, wonach die Assoziation aufgelöst wird. Durch den Betrieb in diesem Modus kündigt der Host, normalerweise ein LAN-Zeitserver, seine Bereitschaft an, zu synchronisieren, aber nicht vom Peer synchronisiert zu werden.
Broadcast (Broadcast,5): Ein Host, der in diesem Modus arbeitet, sendet periodische Nachrichten unabhängig vom Erreichbarkeitszustand oder der Schicht der Peers. Durch den Betrieb in diesem Modus kündigt der Host, normalerweise ein LAN-Zeitserver, der auf einem Hochgeschwindigkeits-Broadcast-Medium arbeitet, seine Bereitschaft an, alle Peers zu synchronisieren, aber nicht von einem von ihnen synchronisiert zu werden.
3.4. Ereignisverarbeitung
Die wichtigen Ereignisse von Interesse in NTP treten beim Ablauf eines Peer-Timers (peer.timer) auf, von denen einer jedem Peer mit einer aktiven Assoziation gewidmet ist, und beim Eintreffen einer NTP-Nachricht von den verschiedenen Peers. Ein Ereignis kann auch als Ergebnis eines Operatorbefehls oder eines erkannten Systemfehlers auftreten, wie z. B. eines Ausfalls der primären Referenzquelle. Dieser Abschnitt beschreibt die Verfahren, die aufgerufen werden, wenn diese Ereignisse auftreten.
3.5. Synchronisationsabstandsverfahren
Das Abstandsverfahren berechnet die Synchronisationsdistanz aus den Peer-Variablen für den Peer peer.
begin distance(peer) procedure;
DELTA <- peer.rootdelay + |peer.delay|;
EPSILON <- peer.rootdispersion + peer.dispersion + φ(sys.clock - peer.update);
LAMBDA <- EPSILON + |DELTA| / 2;
end distance procedure;
Beachten Sie, dass DELTA in einigen Fällen negativ sein kann, EPSILON und LAMBDA jedoch immer positiv sind.
3.6. Zugriffssteuerungsprobleme
Das NTP-Design ist so, dass versehentliche oder böswillige Datenänderungen (Manipulation, tampering) oder Zerstörung (Störung, jamming) an einem Zeitserver im Allgemeinen nicht zu Zeitmessfehlern an anderer Stelle im Synchronisationssubnetz führen sollten. Der Erfolg dieses Ansatzes hängt jedoch von redundanten Zeitservern und vielfältigen Netzwerkpfaden sowie der Annahme ab, dass Manipulation oder Störung nicht gleichzeitig an vielen Zeitservern im gesamten Synchronisationssubnetz auftreten werden. Im Prinzip kann die Subnetz-Verwundbarkeit durch die Auswahl von als vertrauenswürdig bekannten Zeitservern und das Zulassen nur dieser Zeitserver als Synchronisationsquelle konstruiert werden. Die in Anhang C beschriebenen Authentifizierungsverfahren stellen einen Mechanismus dar, um dies durchzusetzen; die Verschlüsselungsalgorithmen können jedoch sehr CPU-intensiv sein und die Genauigkeit ernsthaft beeinträchtigen, es sei denn, Vorsichtsmaßnahmen wie in der Beschreibung des Übertragungsverfahrens erwähnt werden getroffen.
Obwohl es keine erforderliche Funktion von NTP selbst ist, können einige Implementierungen eine Zugriffssteuerungsfunktion enthalten, die unbefugten Zugriff verhindert und steuert, welche Peers die lokale Uhr aktualisieren dürfen. Zu diesem Zweck ist es nützlich, zwischen drei Kategorien von Zugriff zu unterscheiden: solche, die als vertrauenswürdig vorautorisiert sind, als freundlich vorautorisiert sind und alle anderen (nicht vorautorisierte) Zugriffe. Vermutlich wird die Vorautorisierung durch Einträge in der Konfigurationsdatei oder eine Art Ticket-Verwaltungssystem wie Kerberos [STE88] erreicht. In diesem Modell können nur vertrauenswürdige Zugriffe dazu führen, dass der Peer zur Synchronisationsquelle wird. Während freundliche Zugriffe nicht dazu führen können, dass der Peer zur Synchronisationsquelle wird, werden NTP-Nachrichten und Zeitstempel wie angegeben zurückgegeben.
Es scheint nicht nützlich, eine geheime Uhr zu pflegen, wie sie sich aus der Einschränkung nicht vorautorisierter Zugriffe ergeben würde, es sei denn, die Absicht besteht darin, die Existenz des Zeitservers selbst zu verbergen. Von gut verhaltenen Internet-Hosts wird erwartet, dass sie eine ICMP-Service-nicht-verfügbar-Fehlermeldung zurückgeben, wenn ein Dienst nicht implementiert ist oder Ressourcen nicht verfügbar sind; im Falle von NTP sind jedoch die erforderlichen Ressourcen minimal, sodass kaum Bedarf besteht, Anfragen zu beschränken, die nur dazu dienen, die Uhr zu lesen. Ein einfacher, aber effektiver Zugriffssteuerungsmechanismus besteht dann darin, alle Assoziationen, die in einem symmetrischen Modus oder Client-Modus (Modi 1, 2 und 3) vorkonfiguriert sind, als vertrauenswürdig zu betrachten und alle anderen Assoziationen, vorkonfiguriert oder nicht, als freundlich.
Wenn ein umfassenderes Vertrauensmodell erforderlich ist, kann das Design auf einer Zugriffssteuerungsliste basieren, wobei jeder Eintrag aus einer 32-Bit-Internetadresse, einer 32-Bit-Maske und einem 3-Bit-Modus besteht. Wenn das logische UND der Quelladresse (pkt.peeraddr) und der Maske in einem Eintrag mit der entsprechenden Adresse im Eintrag übereinstimmt und der Modus (pkt.mode) mit dem Modus im Eintrag übereinstimmt, wird der Zugriff zugelassen; andernfalls wird eine ICMP-Fehlermeldung an den Anforderer zurückgegeben. Durch geeignete Wahl der Maske ist es möglich, Anfragen nach Modus auf einzelne Adressen, ein bestimmtes Subnetz oder Netzadressen zu beschränken oder überhaupt keine Einschränkung zu haben. Die Zugriffssteuerungsliste würde dann als Filter dienen, der steuert, welche Peers Assoziationen erstellen können.